Files
Arquivotheca.AIX-4.1.3/bos/kernel/proc/POWER/m_clock.c
seta75D d6fe8fe829 Init
2021-10-11 22:19:34 -03:00

492 lines
13 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
static char sccsid[] = "@(#)55 1.11.4.2 src/bos/kernel/proc/POWER/m_clock.c, sysproc, bos41J, bai15 4/11/95 11:38:37";
/*
* COMPONENT_NAME: SYSPROC
*
* FUNCTIONS: set_alarm
* set_time
* update_rtc
* update_system_time_pwr
* write_clock
* write_dp8570
* write_ds1285
* write_rtc
*
* ORIGINS: 27,83
*
* This module contains IBM CONFIDENTIAL code. -- (IBM
* Confidential Restricted when combined with the aggregated
* modules for this product)
* SOURCE MATERIALS
*
* (C) COPYRIGHT International Business Machines Corp. 1988,1995
* All Rights Reserved
* US Government Users Restricted Rights - Use, duplication or
* disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
*/
/*
* LEVEL 1, 5 Years Bull Confidential Information
*/
#include <sys/types.h> /* always needed */
#include <sys/adspace.h> /* for the WRITE_CLOCK macro to work */
#include <sys/time.h> /* for the timeval structure */
#include <sys/param.h> /* to define the HZ label */
#include <sys/mstsave.h> /* mstsave area def. for asserting */
#include <sys/user.h> /* the u structure to return errnos */
#include <sys/errno.h> /* define the errno's to be returned */
#include <sys/syspest.h> /* for the ASSERT and assert macros */
#include <sys/intr.h> /* for the serialization stuff */
#include <sys/rtc.h> /* for real time clock related defines */
#include <sys/low.h> /* access the csa for asserts */
#include <sys/machine.h> /* for machine model macros */
#include <sys/systemcfg.h> /* for system config structure */
#include <sys/sys_resource.h> /* for system resource structure */
#include <sys/inline.h> /* for eieio() */
#ifdef _RSPC
#include <sys/ioacc.h> /* for io_map structure */
#include <sys/system_rspc.h> /* for IO addresses */
#endif
#ifdef _RS6K_SMP_MCA
extern int fd_mutex;
extern int pgs_SSGA_lvl;
extern void d_abort_fd();
#endif /* _RS6K_SMP_MCA */
extern void reset_decr(), write_clock();
extern struct io_map nio_map;
/*
* NAME: set_time
*
* FUNCTION: Set the time: processor clock, memory mapped variables, nvram chip.
*
* EXECUTION ENVIRONMENT:
*
* It is assumed that interrupts were disabled by the caller.
* This routine does not page fault.
*
* EXTERNAL PROCEDURES CALLED: None
*
* NOTE: A RSC deviation prevents setting rtcl in the range:
* 3b9a4a00 <= rtcl < 3b9aca00
* this is 32.768 uS from rapping. If rtcl is set to this value a check
* stop could result. To work around this rtcl values that are within
* 34 uS of rapping are rounded up or down. Also the minimium clock
* resolutionis set to 17 uS.
*/
void
set_time(struct timestruc_t new_time)
{
struct timestruc_t ct;
cpu_t my_cpu=CPUID;
ASSERT(csa->intpri == INTMAX);
#ifdef _POWER_MP
ASSERT(lock_mine(&tod_lock));
#endif
if (__power_rsc())
{
if ((new_time).tv_nsec >= NS_PER_SEC-17*NS_PER_uS)
{
(new_time).tv_sec++;
(new_time).tv_nsec = 0;
}
else if ((new_time).tv_nsec >= NS_PER_SEC-34*NS_PER_uS)
{
(new_time).tv_nsec = NS_PER_SEC-34*NS_PER_uS;
}
}
/*
* Set reference time for next time out. It is assumed that
* ref_time is greater than the current time, however, the
* RTCU and RTCL registers are implemented internally as a
* continuous 64 bit register that cannot be disabled.
*/
curtime(&ct);
while (ntimercmp(TIMER(my_cpu)->ref_time, ct, <))
ntimeradd(TIMER(my_cpu)->ref_time, ref_const,
TIMER(my_cpu)->ref_time);
ntimersub(TIMER(my_cpu)->ref_time, ct, ct);
ntimeradd(new_time, ct, TIMER(my_cpu)->ref_time);
/*
* Adjust the timer request blocks.
*/
adj_trbs(new_time);
/*
* write_clock() gets the current time from the real time
* clock with curtime(). It then copies this value to the
* tm.secs and tm.msecs fields. These values are then
* translated to MMddyyhhmmss and the time of day chip is
* updated. We must update the time in the real time clock
* before calling write_clock(). Therefore, order is
* important.
*/
UPDATE_RTC(new_time);
if (my_cpu == MP_MASTER){
write_clock();
/*
* Update memory copy of time.
*/
tod.tv_sec = tm.secs = time = (new_time).tv_sec;
tod.tv_nsec = (new_time).tv_nsec;
}
/*
* Reset the decrementer for the next timer interrupt.
*/
(void)reset_decr();
}
/*
* NAME: write_dp8570
*
* FUNCTION: Sets the time of day clock to the time and date contained
* in tm.
*
* EXECUTION ENVIRONMENT:
*
* It is assumed that interrupts were disabled by the caller.
* This routine does not page fault.
*
* EXTERNAL PROCEDURES CALLED: None
*/
static void
write_dp8570()
{
volatile register struct rtc *rtc;
#ifdef _POWER_RS
if (__power_rs())
rtc = (struct rtc *)io_att(SYSREG_SEGVAL, RTC_OFFSET);
#endif
#ifdef _RS6K
if (__rs6k())
rtc = (struct rtc *)&sys_resource_ptr->sys_regs.time_of_day[0];
#endif
#ifdef _RS6K_SMP_MCA
/* If diskette is working, kill the ongoing DMA before */
/* writing the tod */
if (pgs_SSGA_lvl == 2 && fd_mutex)
d_abort_fd();
#endif /* _RS6K_SMP_MCA */
/*
* Turn off page select.
* Select the appropriate control registers.
* Disable clock.
*/
rtc->msr &= ~MSR_PS; IOSPACE_EIEIO();
rtc->msr |= MSR_RS; IOSPACE_EIEIO();
rtc->rtm &= ~RTM_CSS; IOSPACE_EIEIO();
switch((tm.yrs+2) % 4) { /* +2 -> yrs is yrs since 1970 */
case 0:
rtc->rtm &= (~(RTM_LY0 | RTM_LY1));
break;
case 1:
rtc->rtm = (rtc->rtm & ~RTM_LY1) | RTM_LY0;
break;
case 2:
rtc->rtm = (rtc->rtm & ~RTM_LY0) | RTM_LY1;
break;
case 3:
rtc->rtm |= RTM_LY1 | RTM_LY0;
break;
} IOSPACE_EIEIO();
rtc->c_millisecs = tm.ms;
rtc->c_seconds = tm.no_secs;
rtc->c_minutes = tm.mins;
rtc->c_hours = tm.hrs;
rtc->c_date_month = tm.dom;
rtc->c_months = tm.mths;
rtc->c_years = tm.yrs;
rtc->c_julian_digits = tm.jul_dig;
rtc->c_julian_100 = tm.jul_100;
rtc->rtm |= RTM_CSS; /* start clock */ IOSPACE_EIEIO();
IO_DET((ulong)rtc);
}
/*
* NAME: write_rtc
*
* FUNCTION: write a byte to DS1285 real time clock chip
*
* EXECUTION ENVIORNMENT:
* called by init_ds1285 and write_ds1285
*
* caller should be disabled
*
* RETURNS: None
*/
void
write_rtc(reg, value)
int reg;
char value;
{
volatile char *io_addr;
#ifdef _POWER_RS
if (__power_rs()) {
io_addr = io_att(SYSREG_SEGVAL, 0);
*(io_addr + TOD_INDX_OFF) = reg;
*(io_addr + TOD_DATA_OFF) = value;
io_det(io_addr);
}
#endif /* _POWER_RS */
#ifdef _RS6K
if (__rs6k()) {
io_addr = (volatile char *)
&sys_resource_ptr->sys_regs.time_of_day[TOD_INDX_PPC];
*(io_addr) = reg;
eieio();
io_addr = (volatile char *)
&sys_resource_ptr->sys_regs.time_of_day[TOD_DATA_PPC];
*(io_addr) = value;
__iospace_sync(); /* make sure seen */
}
#endif /* _RS6K */
#ifdef _RSPC
if (__rspc()) {
volatile struct rspcsio *siop;
siop = iomem_att(&nio_map);
/*
* check that high bit (NMI_OK) is off
*/
ASSERT(!(RSPC_RTC_NMI & reg));
siop->rtc_index = reg;
eieio();
siop->rtc_data = value;
__iospace_sync();
iomem_det((void *)siop);
}
#endif /* _RSPC */
}
/*
* NAME update_rtc
*
* FUNCTION: update time in DS1285
*
* EXECUTION ENVIORNMENT:
* called by write_ds1285 and init_ds1285. must not be
* called to update the DP8570.
*
* RETURNS:
* None
*/
void
update_rtc()
{
/* write new time. RTC_YEAR is the actual year of the century.
* When the value is greater than 0x30, overflow would occur, so
* we check for that here and wrap the year 2000 back to 0.
*/
if (tm.yrs + 0x70 < 0xa0)
write_rtc(RTC_YEAR, tm.yrs + 0x70);
else
write_rtc(RTC_YEAR, tm.yrs - 0x30);
write_rtc(RTC_MONTH, tm.mths);
write_rtc(RTC_DOM, tm.dom);
write_rtc(RTC_HRS, tm.hrs);
write_rtc(RTC_MIN, tm.mins);
write_rtc(RTC_SEC, tm.no_secs);
}
/*
* NAME write_ds1285
*
* FUNCTION: Update time in DS1285 real time clock chip
*
* EXECUTION ENVIORNMENT:
* only called by write_clock
*
* RETURNS: None
*/
static void
write_ds1285()
{
/* disable update of clock
*/
write_rtc(RTC_REGB, CRB_SET|CRB_24HR);
update_rtc();
/* enable update of clock
*/
write_rtc(RTC_REGB, CRB_24HR);
}
/*
* NAME: write_clock
*
* FUNCTION: Update time in real time clock
*
* EXECUTION ENVIORNMENT:
* Caller should be disabled, or non-premptable. This routine
* is not re-entrant
*
* RETURNS: None
*/
void
write_clock()
{
struct timestruc_t ct;
/*
* Get the current time to set the clock. Need to convert
* nanoseconds to hundred seconds.
*/
curtime(&ct);
tm.secs = ct.tv_sec;
tm.ms = ct.tv_nsec / (NS_PER_SEC/100); /* nano secs to 100th secs */
secs_to_date(&tm);
if (__power_rsc() | __rs6k_up_mca() | __rspc_up_pci())
{
write_ds1285();
}
else
{
write_dp8570();
}
}
/*
* NAME: set_alarm
*
* FUNCTION: Sets an alarm in the real time clock. The alarm function
* is only supported by lampasas.
*
* EXECUTION ENVIRONMENT:
*
* It is assumed that interrupts were disabled by the caller.
* This routine does not page fault.
*
* EXTERNAL PROCEDURES CALLED: None
*/
void
set_alarm(time_t nsecs)
{
volatile register struct rtc *rtc;
struct tms ntm;
/* Only Power RS1 Power RS2 and SMP models implement this
*/
if (!__power_set(POWER_RS1|POWER_RS2) && !__rs6k_smp_mca())
return;
/*
* Convert the global field tm into time of day structure.
* The seconds field is update every 10 millisecs by the
* system timer, but the date fields are not.
*/
secs_to_date(&tm);
ntm.secs = tm.secs + (ulong)nsecs;
secs_to_date(&ntm);
if (__rs6k_smp_mca())
rtc = (struct rtc *)&sys_resource_ptr->sys_regs.time_of_day[0];
else
rtc = (struct rtc *)io_att(SYSREG_SEGVAL, RTC_OFFSET);
/*
* Turn off page select.
* Select the appropriate control registers.
* Disable clock.
*/
rtc->msr &= ~MSR_PS; IOSPACE_EIEIO();
rtc->msr |= MSR_RS; IOSPACE_EIEIO();
rtc->rtm &= ~RTM_CSS; IOSPACE_EIEIO();
/* timer enable is being set somewhere */
rtc->intr_r0 = 0;
/*
* Set alarm enable bit - IC1_ALE
* Also indicate the valid comparison fields.
*/
rtc->intr_r1 = ( IC1_ALE | /* enable alarm */
IC1_DOM_COM | /* day of the month */
IC1_MO_COM | /* month */
IC1_HR_COM | /* hour */
IC1_MN_COM | /* minutes */
IC1_SC_COM ); /* seconds */
/*
* Reset the current time because the oscillators in the two clocks
* are different, and the ntm field is based off of the processor
* clock.
*/
rtc->c_seconds = tm.no_secs;
rtc->c_minutes = tm.mins;
rtc->c_hours = tm.hrs;
rtc->c_date_month = tm.dom;
rtc->c_months = tm.mths;
rtc->c_years = tm.yrs;
rtc->c_julian_digits = tm.jul_dig;
rtc->c_julian_100 = tm.jul_100;
/* fill in time to alarm */
rtc->comp_month = ntm.mths;
rtc->comp_dom = ntm.dom;
rtc->comp_hour = ntm.hrs;
rtc->comp_min = ntm.mins;
rtc->comp_secs = ntm.no_secs;
/* load faster counters with zero */
rtc->c_millisecs = 0; IOSPACE_EIEIO();
rtc->rtm |= RTM_CSS; /* start clock */ IOSPACE_EIEIO();
IO_DET((ulong)rtc);
}
/*
* Update the processor clock on POWER & Power_PC 601.
*
* NOTE: This should only be called from tinit.
* An architectual deviation was granted to require 7F80 to be
* placed in rtcl before setting time
*/
void
update_system_time_pwr(struct timestruc_t new_time)
{
mtrtcl(0x7F80);
mtrtcu((new_time).tv_sec);
mtrtcl((new_time).tv_nsec);
}