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:
Marius Strobl 2005-05-19 21:20:42 +00:00
parent fb596371a9
commit 003daaea5f
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=146417
3 changed files with 53 additions and 28 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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);
}