o mc146818(4):
- Add locking. - Account for if the MC146818_NO_CENT_ADJUST flag is set we don't need to check wheter year < POSIX_BASE_YEAR. - Add some comments about mapping the day of week from the range the generic clock code uses to the range the chip uses and which I meant to add in the initial version. - Minor clean-up, use __func__ instead of hardcoded function names in error strings. o in the rtc(4) front-end additionally: - Don't leak resources in case mc146818_attach() fails. - Account for ebus(4) defaulting to SYS_RES_MEMORY for the memory resources since ebus.c rev. 1.22.
This commit is contained in:
parent
fb596371a9
commit
003daaea5f
@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/clock.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/mutex.h>
|
||||
|
||||
#include <machine/bus.h>
|
||||
|
||||
@ -57,6 +59,11 @@ mc146818_attach(device_t dev)
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
|
||||
if (mtx_initialized(&sc->sc_mtx) == 0) {
|
||||
device_printf(dev, "%s: mutex not initialized\n", __func__);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
if (sc->sc_mcread == NULL)
|
||||
sc->sc_mcread = mc146818_def_read;
|
||||
if (sc->sc_mcwrite == NULL)
|
||||
@ -73,8 +80,10 @@ mc146818_attach(device_t dev)
|
||||
sc->sc_setcent = mc146818_def_setcent;
|
||||
}
|
||||
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
if (!(*sc->sc_mcread)(dev, MC_REGD) & MC_REGD_VRT) {
|
||||
device_printf(dev, "mc146818_attach: battery low\n");
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
device_printf(dev, "%s: battery low\n", __func__);
|
||||
return (ENXIO);
|
||||
}
|
||||
|
||||
@ -85,6 +94,7 @@ mc146818_attach(device_t dev)
|
||||
sc->sc_regb |= (sc->sc_flag & MC146818_BCD) ? 0 : MC_REGB_BINARY;
|
||||
sc->sc_regb |= (sc->sc_flag & MC146818_12HR) ? 0 : MC_REGB_24HR;
|
||||
(*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
|
||||
clock_register(dev, 1000000); /* 1 second resolution. */
|
||||
|
||||
@ -106,12 +116,7 @@ mc146818_gettime(device_t dev, struct timespec *ts)
|
||||
|
||||
timeout = 1000000; /* XXX how long should we wait? */
|
||||
|
||||
/*
|
||||
* XXX: Use a spinlock to mutex register access and increase the
|
||||
* likelihood that all registers are read before an update
|
||||
* occurs.
|
||||
*/
|
||||
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
/*
|
||||
* If MC_REGA_UIP is 0 we have at least 244us before the next
|
||||
* update. If it's 1 an update is imminent.
|
||||
@ -120,7 +125,8 @@ mc146818_gettime(device_t dev, struct timespec *ts)
|
||||
if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP))
|
||||
break;
|
||||
if (--timeout < 0) {
|
||||
device_printf(dev, "mc146818_gettime: timeout\n");
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
device_printf(dev, "%s: timeout\n", __func__);
|
||||
return (EBUSY);
|
||||
}
|
||||
}
|
||||
@ -131,18 +137,19 @@ mc146818_gettime(device_t dev, struct timespec *ts)
|
||||
ct.sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC));
|
||||
ct.min = FROMREG((*sc->sc_mcread)(dev, MC_MIN));
|
||||
ct.hour = FROMREG((*sc->sc_mcread)(dev, MC_HOUR));
|
||||
/* Map dow from 1 - 7 to 0 - 6. */
|
||||
ct.dow = FROMREG((*sc->sc_mcread)(dev, MC_DOW)) - 1;
|
||||
ct.day = FROMREG((*sc->sc_mcread)(dev, MC_DOM));
|
||||
ct.mon = FROMREG((*sc->sc_mcread)(dev, MC_MONTH));
|
||||
year = FROMREG((*sc->sc_mcread)(dev, MC_YEAR));
|
||||
if (sc->sc_getcent) {
|
||||
year += sc->sc_year0;
|
||||
if (sc->sc_flag & MC146818_NO_CENT_ADJUST) {
|
||||
cent = (*sc->sc_getcent)(dev);
|
||||
year += cent * 100;
|
||||
}
|
||||
|
||||
year += sc->sc_year0;
|
||||
if (year < POSIX_BASE_YEAR && !(sc->sc_flag & MC146818_NO_CENT_ADJUST))
|
||||
} else if (year < POSIX_BASE_YEAR)
|
||||
year += 100;
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
|
||||
ct.year = year;
|
||||
|
||||
return (clock_ct_to_ts(&ct, ts));
|
||||
@ -159,16 +166,19 @@ mc146818_getsecs(device_t dev, int *secp)
|
||||
|
||||
timeout = 1000000; /* XXX how long should we wait? */
|
||||
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
for (;;) {
|
||||
if (!((*sc->sc_mcread)(dev, MC_REGA) & MC_REGA_UIP)) {
|
||||
sec = FROMREG((*sc->sc_mcread)(dev, MC_SEC));
|
||||
break;
|
||||
}
|
||||
if (--timeout == 0) {
|
||||
device_printf(dev, "mc146818_getsecs: timeout\n");
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
device_printf(dev, "%s: timeout\n", __func__);
|
||||
return (EBUSY);
|
||||
}
|
||||
}
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
|
||||
#undef FROMREG
|
||||
|
||||
@ -196,6 +206,7 @@ mc146818_settime(device_t dev, struct timespec *ts)
|
||||
ts->tv_nsec = 0;
|
||||
clock_ts_to_ct(ts, &ct);
|
||||
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
/* Disable RTC updates and interrupts (if enabled). */
|
||||
(*sc->sc_mcwrite)(dev, MC_REGB,
|
||||
((sc->sc_regb & (MC_REGB_BINARY | MC_REGB_24HR)) | MC_REGB_SET));
|
||||
@ -205,22 +216,23 @@ mc146818_settime(device_t dev, struct timespec *ts)
|
||||
(*sc->sc_mcwrite)(dev, MC_SEC, TOREG(ct.sec));
|
||||
(*sc->sc_mcwrite)(dev, MC_MIN, TOREG(ct.min));
|
||||
(*sc->sc_mcwrite)(dev, MC_HOUR, TOREG(ct.hour));
|
||||
/* Map dow from 0 - 6 to 1 - 7. */
|
||||
(*sc->sc_mcwrite)(dev, MC_DOW, TOREG(ct.dow + 1));
|
||||
(*sc->sc_mcwrite)(dev, MC_DOM, TOREG(ct.day));
|
||||
(*sc->sc_mcwrite)(dev, MC_MONTH, TOREG(ct.mon));
|
||||
|
||||
year = ct.year - sc->sc_year0;
|
||||
if (sc->sc_setcent) {
|
||||
if (sc->sc_flag & MC146818_NO_CENT_ADJUST) {
|
||||
cent = year / 100;
|
||||
(*sc->sc_setcent)(dev, cent);
|
||||
year -= cent * 100;
|
||||
}
|
||||
if (year > 99 && (sc->sc_flag & MC146818_NO_CENT_ADJUST) == 0)
|
||||
} else if (year > 99)
|
||||
year -= 100;
|
||||
(*sc->sc_mcwrite)(dev, MC_YEAR, TOREG(year));
|
||||
|
||||
/* Reenable RTC updates and interrupts. */
|
||||
(*sc->sc_mcwrite)(dev, MC_REGB, sc->sc_regb);
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
|
||||
#undef TOREG
|
||||
|
||||
|
@ -32,6 +32,8 @@ struct mc146818_softc {
|
||||
bus_space_tag_t sc_bst; /* bus space tag */
|
||||
bus_space_handle_t sc_bsh; /* bus space handle */
|
||||
|
||||
struct mtx sc_mtx; /* hardware mutex */
|
||||
|
||||
u_char sc_rega; /* register A */
|
||||
u_char sc_regb; /* register B */
|
||||
|
||||
|
@ -39,7 +39,9 @@ __FBSDID("$FreeBSD$");
|
||||
#include <sys/systm.h>
|
||||
#include <sys/bus.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/lock.h>
|
||||
#include <sys/module.h>
|
||||
#include <sys/mutex.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#include <dev/ofw/ofw_bus.h>
|
||||
@ -71,9 +73,6 @@ static device_method_t rtc_ebus_methods[] = {
|
||||
/* clock interface */
|
||||
DEVMETHOD(clock_gettime, mc146818_gettime),
|
||||
DEVMETHOD(clock_settime, mc146818_settime),
|
||||
#ifdef notyet
|
||||
DEVMETHOD(clock_getsecs, mc146818_getsecs),
|
||||
#endif
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
@ -95,9 +94,6 @@ static device_method_t rtc_isa_methods[] = {
|
||||
/* clock interface */
|
||||
DEVMETHOD(clock_gettime, mc146818_gettime),
|
||||
DEVMETHOD(clock_settime, mc146818_settime),
|
||||
#ifdef notyet
|
||||
DEVMETHOD(clock_getsecs, mc146818_getsecs),
|
||||
#endif
|
||||
|
||||
{ 0, 0 }
|
||||
};
|
||||
@ -148,16 +144,24 @@ rtc_attach(device_t dev)
|
||||
struct timespec ts;
|
||||
struct mc146818_softc *sc;
|
||||
struct resource *res;
|
||||
int error, rid;
|
||||
int error, rid, rtype;
|
||||
|
||||
sc = device_get_softc(dev);
|
||||
bzero(sc, sizeof(struct mc146818_softc));
|
||||
|
||||
mtx_init(&sc->sc_mtx, "rtc_mtx", NULL, MTX_DEF);
|
||||
|
||||
if (strcmp(device_get_name(device_get_parent(dev)), "isa") == 0)
|
||||
rtype = SYS_RES_IOPORT;
|
||||
else
|
||||
rtype = SYS_RES_MEMORY;
|
||||
|
||||
rid = 0;
|
||||
res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
|
||||
res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE);
|
||||
if (res == NULL) {
|
||||
device_printf(dev, "could not allocate resources\n");
|
||||
return (ENXIO);
|
||||
device_printf(dev, "cannot allocate resources\n");
|
||||
error = ENXIO;
|
||||
goto fail_mtx;
|
||||
}
|
||||
sc->sc_bst = rman_get_bustag(res);
|
||||
sc->sc_bsh = rman_get_bushandle(res);
|
||||
@ -168,7 +172,7 @@ rtc_attach(device_t dev)
|
||||
sc->sc_flag = MC146818_NO_CENT_ADJUST;
|
||||
if ((error = mc146818_attach(dev)) != 0) {
|
||||
device_printf(dev, "cannot attach time of day clock\n");
|
||||
return (error);
|
||||
goto fail_res;
|
||||
}
|
||||
|
||||
if (bootverbose) {
|
||||
@ -178,4 +182,11 @@ rtc_attach(device_t dev)
|
||||
}
|
||||
|
||||
return (0);
|
||||
|
||||
fail_res:
|
||||
bus_release_resource(dev, rtype, rid, res);
|
||||
fail_mtx:
|
||||
mtx_destroy(&sc->sc_mtx);
|
||||
|
||||
return (error);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user