Use genclock for RTC handling. This eliminates the MD versions for

inittodr() and resettodr(). Have nexus double as the clock device,
because it's the firmware that provides RTC services. We could
create a special (pseudo-) device for it, but that wasn't superior
enough to actually do it. Maybe later...

Requested by: phk
This commit is contained in:
Marcel Moolenaar 2008-04-15 17:02:23 +00:00
parent bc225cd686
commit 22cc9ba0f0
3 changed files with 51 additions and 135 deletions

View File

@ -9,6 +9,7 @@ machine ia64
device acpi # ACPI support
# Pseudo devices.
device genclock # Real-time clock
device mem # Memory and kernel memory devices
# UART chips on this platform

View File

@ -44,8 +44,6 @@ __FBSDID("$FreeBSD$");
uint64_t ia64_clock_reload;
static int clock_initialized = 0;
#ifndef SMP
static timecounter_get_t ia64_get_timecount;
@ -110,93 +108,3 @@ cpu_stopprofclock(void)
/* nothing to do */
}
void
inittodr(time_t base)
{
long days;
struct efi_tm tm;
struct timespec ts;
struct clocktime ct;
efi_get_time(&tm);
/*
* This code was written in 2005, so logically EFI cannot return
* a year smaller than that. Assume the EFI clock is out of whack
* in that case and reset the EFI clock.
*/
if (tm.tm_year < 2005) {
printf("WARNING: CHECK AND RESET THE DATE!\n");
memset(&tm, 0, sizeof(tm));
tm.tm_year = 2005;
tm.tm_mon = tm.tm_mday = 1;
if (efi_set_time(&tm))
printf("ERROR: COULD NOT RESET EFI CLOCK!\n");
}
ct.nsec = tm.tm_nsec;
ct.sec = tm.tm_sec;
ct.min = tm.tm_min;
ct.hour = tm.tm_hour;
ct.day = tm.tm_mday;
ct.mon = tm.tm_mon;
ct.year = tm.tm_year;
ct.dow = -1;
if (clock_ct_to_ts(&ct, &ts))
printf("Invalid time in clock: check and reset the date!\n");
ts.tv_sec += utc_offset();
/*
* The EFI clock is supposed to be a real-time clock, whereas the
* base argument is coming from a saved (as on disk) time. It's
* impossible for a saved time to represent a time in the future,
* so we expect the EFI clock to be larger. If not, the EFI clock
* may not be reliable and we trust the base.
* Warn if the EFI clock was off by 2 or more days.
*/
if (ts.tv_sec < base) {
days = (base - ts.tv_sec) / (60L * 60L * 24L);
if (days >= 2)
printf("WARNING: EFI clock lost %ld days!\n", days);
ts.tv_sec = base;
ts.tv_nsec = 0;
}
tc_setclock(&ts);
clock_initialized = 1;
}
/*
* 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()
{
struct timespec ts;
struct clocktime ct;
struct efi_tm tm;
if (!clock_initialized || disable_rtc_set)
return;
efi_get_time(&tm);
getnanotime(&ts);
ts.tv_sec -= utc_offset();
clock_ts_to_ct(&ts, &ct);
tm.tm_nsec = ts.tv_nsec;
tm.tm_sec = ct.sec;
tm.tm_min = ct.min;
tm.tm_hour = ct.hour;
tm.tm_year = ct.year;
tm.tm_mon = ct.mon;
tm.tm_mday = ct.day;
if (efi_set_time(&tm))
printf("ERROR: COULD NOT RESET EFI CLOCK!\n");
}

View File

@ -43,6 +43,7 @@
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/clock.h>
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
@ -53,6 +54,7 @@
#include <vm/vm.h>
#include <vm/pmap.h>
#include <machine/efi.h>
#include <machine/intr.h>
#include <machine/nexusvar.h>
#include <machine/pmap.h>
@ -66,6 +68,8 @@
#include <isa/isareg.h>
#include <sys/rtprio.h>
#include "clock_if.h"
static MALLOC_DEFINE(M_NEXUSDEV, "nexusdev", "Nexus device");
struct nexus_device {
struct resource_list nx_resources;
@ -104,6 +108,9 @@ static void nexus_delete_resource(device_t, device_t, int, int);
static int nexus_config_intr(device_t, int, enum intr_trigger,
enum intr_polarity);
static int nexus_gettime(device_t, struct timespec *);
static int nexus_settime(device_t, struct timespec *);
static device_method_t nexus_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, nexus_probe),
@ -130,6 +137,10 @@ static device_method_t nexus_methods[] = {
DEVMETHOD(bus_delete_resource, nexus_delete_resource),
DEVMETHOD(bus_config_intr, nexus_config_intr),
/* Clock interface */
DEVMETHOD(clock_gettime, nexus_gettime),
DEVMETHOD(clock_settime, nexus_settime),
{ 0, 0 }
};
@ -229,6 +240,7 @@ nexus_attach(device_t dev)
if (acpi_identify() == 0)
BUS_ADD_CHILD(dev, 10, "acpi", 0);
clock_register(dev, 1000);
bus_generic_attach(dev);
return 0;
}
@ -521,54 +533,49 @@ nexus_config_intr(device_t dev, int irq, enum intr_trigger trig,
return (sapic_config_intr(irq, trig, pol));
}
#if 0
/*
* Placeholder which claims PnP 'devices' which describe system
* resources.
*/
static struct isa_pnp_id sysresource_ids[] = {
{ 0x010cd041 /* PNP0c01 */, "System Memory" },
{ 0x020cd041 /* PNP0c02 */, "System Resource" },
{ 0 }
};
static int
sysresource_probe(device_t dev)
nexus_gettime(device_t dev, struct timespec *ts)
{
int result;
if ((result = ISA_PNP_PROBE(device_get_parent(dev), dev, sysresource_ids)) <= 0) {
device_quiet(dev);
}
return(result);
struct clocktime ct;
struct efi_tm tm;
efi_get_time(&tm);
/*
* This code was written in 2005, so logically EFI cannot return
* a year smaller than that. Assume the EFI clock is out of whack
* in that case and reset the EFI clock.
*/
if (tm.tm_year < 2005)
return (EINVAL);
ct.nsec = tm.tm_nsec;
ct.sec = tm.tm_sec;
ct.min = tm.tm_min;
ct.hour = tm.tm_hour;
ct.day = tm.tm_mday;
ct.mon = tm.tm_mon;
ct.year = tm.tm_year;
ct.dow = -1;
return (clock_ct_to_ts(&ct, ts));
}
static int
sysresource_attach(device_t dev)
nexus_settime(device_t dev, struct timespec *ts)
{
return(0);
struct clocktime ct;
struct efi_tm tm;
efi_get_time(&tm);
clock_ts_to_ct(ts, &ct);
tm.tm_nsec = ts->tv_nsec;
tm.tm_sec = ct.sec;
tm.tm_min = ct.min;
tm.tm_hour = ct.hour;
tm.tm_year = ct.year;
tm.tm_mon = ct.mon;
tm.tm_mday = ct.day;
return (efi_set_time(&tm));
}
static device_method_t sysresource_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, sysresource_probe),
DEVMETHOD(device_attach, sysresource_attach),
DEVMETHOD(device_detach, bus_generic_detach),
DEVMETHOD(device_shutdown, bus_generic_shutdown),
DEVMETHOD(device_suspend, bus_generic_suspend),
DEVMETHOD(device_resume, bus_generic_resume),
{ 0, 0 }
};
static driver_t sysresource_driver = {
"sysresource",
sysresource_methods,
1, /* no softc */
};
static devclass_t sysresource_devclass;
DRIVER_MODULE(sysresource, isa, sysresource_driver, sysresource_devclass, 0, 0);
#endif