summaryrefslogtreecommitdiffstats
path: root/sys/i386
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2014-11-20 20:24:30 +0000
committerjhb <jhb@FreeBSD.org>2014-11-20 20:24:30 +0000
commit86ac03a3f79123d99c1bbb40a40c6fffeaf777af (patch)
tree0738959ddf885dfc313b4771009539d9f7509622 /sys/i386
parentedc612fe8cb2a265effaa015f98dd72db3e8d56b (diff)
downloadFreeBSD-src-86ac03a3f79123d99c1bbb40a40c6fffeaf777af.zip
FreeBSD-src-86ac03a3f79123d99c1bbb40a40c6fffeaf777af.tar.gz
Lock spic(4) and mark it MPSAFE:
- Add a per-softc mutex as a driver lock. - Use callout(9) instead of timeout(9). - Set softc pointer in si_drv1 of cdev instead of looking softc up via devclass in cdev methods. Tested by: no one
Diffstat (limited to 'sys/i386')
-rw-r--r--sys/i386/isa/spic.c70
1 files changed, 39 insertions, 31 deletions
diff --git a/sys/i386/isa/spic.c b/sys/i386/isa/spic.c
index 70c1cc1..89ebb57 100644
--- a/sys/i386/isa/spic.c
+++ b/sys/i386/isa/spic.c
@@ -87,7 +87,6 @@ static d_poll_t spicpoll;
static struct cdevsw spic_cdevsw = {
.d_version = D_VERSION,
- .d_flags = D_NEEDGIANT,
.d_open = spicopen,
.d_close = spicclose,
.d_read = spicread,
@@ -106,8 +105,10 @@ struct spic_softc {
int sc_opened;
int sc_sleeping;
int sc_buttonlast;
- struct callout_handle sc_timeout_ch;
+ struct callout sc_timeout;
+ struct mtx sc_lock;
device_t sc_dev;
+ struct cdev *sc_cdev;
struct selinfo sc_rsel;
u_char sc_buf[SCBUFLEN];
int sc_count;
@@ -337,6 +338,8 @@ spic_attach(device_t dev)
sc = device_get_softc(dev);
sc->sc_dev = dev;
+ mtx_init(&sc->sc_lock, "spic", NULL, MTX_DEF);
+ callout_init_mtx(&sc->sc_timeout, &sc->sc_lock, 0);
spic_pollrate = (hz/50); /* Every 50th of a second */
@@ -345,7 +348,8 @@ spic_attach(device_t dev)
spic_call1(sc, 0x92);
/* There can be only one */
- make_dev(&spic_cdevsw, 0, 0, 0, 0600, "jogdial");
+ sc->sc_cdev = make_dev(&spic_cdevsw, 0, 0, 0, 0600, "jogdial");
+ sc->sc_cdev->si_drv1 = sc;
return 0;
}
@@ -357,6 +361,7 @@ spictimeout(void *arg)
u_char b, event, param;
int j;
+ mtx_assert(&sc->sc_lock, MA_OWNED);
if (!sc->sc_opened) {
device_printf(sc->sc_dev, "timeout called while closed!\n");
return;
@@ -426,7 +431,7 @@ spictimeout(void *arg)
}
else {
/* No event. Wait some more */
- sc->sc_timeout_ch = timeout(spictimeout, sc, spic_pollrate);
+ callout_reset(&sc->sc_timeout, spic_pollrate, spictimeout, sc);
return;
}
@@ -439,7 +444,7 @@ spictimeout(void *arg)
}
spic_call2(sc, 0x81, 0xff); /* Clear event */
- sc->sc_timeout_ch = timeout(spictimeout, sc, spic_pollrate);
+ callout_reset(&sc->sc_timeout, spic_pollrate, spictimeout, sc);
}
static int
@@ -447,17 +452,21 @@ spicopen(struct cdev *dev, int flag, int fmt, struct thread *td)
{
struct spic_softc *sc;
- sc = devclass_get_softc(spic_devclass, 0);
+ sc = dev->si_drv1;
- if (sc->sc_opened)
- return EBUSY;
+ mtx_lock(&sc->sc_lock);
+ if (sc->sc_opened) {
+ mtx_unlock(&sc->sc_lock);
+ return (EBUSY);
+ }
sc->sc_opened++;
sc->sc_count=0;
/* Start the polling */
- timeout(spictimeout, sc, spic_pollrate);
- return 0;
+ callout_reset(&sc->sc_timeout, spic_pollrate, spictimeout, sc);
+ mtx_unlock(&sc->sc_lock);
+ return (0);
}
static int
@@ -465,11 +474,13 @@ spicclose(struct cdev *dev, int flag, int fmt, struct thread *td)
{
struct spic_softc *sc;
- sc = devclass_get_softc(spic_devclass, 0);
+ sc = dev->si_drv1;
+ mtx_lock(&sc->sc_lock);
/* Stop polling */
- untimeout(spictimeout, sc, sc->sc_timeout_ch);
+ callout_stop(&sc->sc_timeout);
sc->sc_opened = 0;
+ mtx_unlock(&sc->sc_lock);
return 0;
}
@@ -477,34 +488,31 @@ static int
spicread(struct cdev *dev, struct uio *uio, int flag)
{
struct spic_softc *sc;
- int l, s, error;
+ int l, error;
u_char buf[SCBUFLEN];
- sc = devclass_get_softc(spic_devclass, 0);
+ sc = dev->si_drv1;
if (uio->uio_resid <= 0) /* What kind of a read is this?! */
- return 0;
+ return (0);
- s = spltty();
+ mtx_lock(&sc->sc_lock);
while (!(sc->sc_count)) {
sc->sc_sleeping=1;
- error = tsleep( sc, PZERO | PCATCH, "jogrea", 0);
+ error = mtx_sleep(sc, &sc->sc_lock, PZERO | PCATCH, "jogrea", 0);
sc->sc_sleeping=0;
if (error) {
- splx(s);
- return error;
+ mtx_unlock(&sc->sc_lock);
+ return (error);
}
}
- splx(s);
- s = spltty();
l = min(uio->uio_resid, sc->sc_count);
bcopy(sc->sc_buf, buf, l);
sc->sc_count -= l;
bcopy(sc->sc_buf + l, sc->sc_buf, l);
- splx(s);
- return uiomove(buf, l, uio);
-
+ mtx_unlock(&sc->sc_lock);
+ return (uiomove(buf, l, uio));
}
static int
@@ -512,28 +520,28 @@ spicioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *t
{
struct spic_softc *sc;
- sc = devclass_get_softc(spic_devclass, 0);
+ sc = dev->si_drv1;
- return EIO;
+ return (EIO);
}
static int
spicpoll(struct cdev *dev, int events, struct thread *td)
{
struct spic_softc *sc;
- int revents = 0, s;
+ int revents = 0;
- sc = devclass_get_softc(spic_devclass, 0);
- s = spltty();
+ sc = dev->si_drv1;
+ mtx_lock(&sc->sc_lock);
if (events & (POLLIN | POLLRDNORM)) {
if (sc->sc_count)
revents |= events & (POLLIN | POLLRDNORM);
else
selrecord(td, &sc->sc_rsel); /* Who shall we wake? */
}
- splx(s);
+ mtx_unlock(&sc->sc_lock);
- return revents;
+ return (revents);
}
OpenPOWER on IntegriCloud