summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2005-05-19 21:20:42 +0000
committermarius <marius@FreeBSD.org>2005-05-19 21:20:42 +0000
commit54f40eb6c35f44b0ea5fe5f95b0ce7dc80a1317d (patch)
tree64e3bcc3a3097c9a888798d39f552f3bc44a05a9 /sys
parentbedc4e05717f5dabf8d7fab67cee6819f1b93358 (diff)
downloadFreeBSD-src-54f40eb6c35f44b0ea5fe5f95b0ce7dc80a1317d.zip
FreeBSD-src-54f40eb6c35f44b0ea5fe5f95b0ce7dc80a1317d.tar.gz
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.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/mc146818/mc146818.c46
-rw-r--r--sys/dev/mc146818/mc146818var.h2
-rw-r--r--sys/sparc64/sparc64/rtc.c33
3 files changed, 53 insertions, 28 deletions
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 <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
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 */
diff --git a/sys/sparc64/sparc64/rtc.c b/sys/sparc64/sparc64/rtc.c
index fde3a0f..234d1b7 100644
--- a/sys/sparc64/sparc64/rtc.c
+++ b/sys/sparc64/sparc64/rtc.c
@@ -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);
}
OpenPOWER on IntegriCloud