From 54f40eb6c35f44b0ea5fe5f95b0ce7dc80a1317d Mon Sep 17 00:00:00 2001 From: marius Date: Thu, 19 May 2005 21:20:42 +0000 Subject: 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. --- sys/dev/mc146818/mc146818.c | 46 ++++++++++++++++++++++++++---------------- sys/dev/mc146818/mc146818var.h | 2 ++ 2 files changed, 31 insertions(+), 17 deletions(-) (limited to 'sys/dev/mc146818') diff --git a/sys/dev/mc146818/mc146818.c b/sys/dev/mc146818/mc146818.c index 4d09193..6e6d478 100644 --- a/sys/dev/mc146818/mc146818.c +++ b/sys/dev/mc146818/mc146818.c @@ -37,6 +37,8 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include +#include #include @@ -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 diff --git a/sys/dev/mc146818/mc146818var.h b/sys/dev/mc146818/mc146818var.h index 4e8600c..4c6ff09 100644 --- a/sys/dev/mc146818/mc146818var.h +++ b/sys/dev/mc146818/mc146818var.h @@ -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 */ -- cgit v1.1