diff options
author | ray <ray@FreeBSD.org> | 2012-10-15 12:20:40 +0000 |
---|---|---|
committer | ray <ray@FreeBSD.org> | 2012-10-15 12:20:40 +0000 |
commit | 304e13439b52bec3ac813e787148986209e890f8 (patch) | |
tree | f90f8242e4bcad01cc768a7afb94a17308ac6909 /sys/dev | |
parent | 5b7ad0edc8102b0195e61417799c4a1be6710dfc (diff) | |
download | FreeBSD-src-304e13439b52bec3ac813e787148986209e890f8.zip FreeBSD-src-304e13439b52bec3ac813e787148986209e890f8.tar.gz |
Locking for etherswitch framework:
* add lock/unlock methods;
* add lock/unlock default implementation;
* surround switch IOCTLs with locking;
* add lock/unlock implementation for arswitch;
Submitted by: Luiz Otavio O Souza
Approved by: adrian (mentor)
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/etherswitch/arswitch/arswitch.c | 25 | ||||
-rw-r--r-- | sys/dev/etherswitch/arswitch/arswitch_phy.c | 31 | ||||
-rw-r--r-- | sys/dev/etherswitch/etherswitch.c | 4 | ||||
-rw-r--r-- | sys/dev/etherswitch/etherswitch_if.m | 29 |
4 files changed, 82 insertions, 7 deletions
diff --git a/sys/dev/etherswitch/arswitch/arswitch.c b/sys/dev/etherswitch/arswitch/arswitch.c index 05d4307..07c7d4e 100644 --- a/sys/dev/etherswitch/arswitch/arswitch.c +++ b/sys/dev/etherswitch/arswitch/arswitch.c @@ -263,7 +263,10 @@ arswitch_attach(device_t dev) return (err); callout_init_mtx(&sc->callout_tick, &sc->sc_mtx, 0); + + ARSWITCH_LOCK(sc); arswitch_tick(sc); + ARSWITCH_UNLOCK(sc); return (err); } @@ -371,6 +374,8 @@ arswitch_miipollstat(struct arswitch_softc *sc) struct mii_softc *miisc; int portstatus; + ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); + for (i = 0; i < sc->numphys; i++) { if (sc->miibus[i] == NULL) continue; @@ -404,6 +409,24 @@ arswitch_tick(void *arg) callout_reset(&sc->callout_tick, hz, arswitch_tick, sc); } +static void +arswitch_lock(device_t dev) +{ + struct arswitch_softc *sc = device_get_softc(dev); + + ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); + ARSWITCH_LOCK(sc); +} + +static void +arswitch_unlock(device_t dev) +{ + struct arswitch_softc *sc = device_get_softc(dev); + + ARSWITCH_LOCK_ASSERT(sc, MA_OWNED); + ARSWITCH_UNLOCK(sc); +} + static etherswitch_info_t * arswitch_getinfo(device_t dev) { @@ -552,6 +575,8 @@ static device_method_t arswitch_methods[] = { DEVMETHOD(mdio_writereg, arswitch_writephy), /* etherswitch interface */ + DEVMETHOD(etherswitch_lock, arswitch_lock), + DEVMETHOD(etherswitch_unlock, arswitch_unlock), DEVMETHOD(etherswitch_getinfo, arswitch_getinfo), DEVMETHOD(etherswitch_readreg, arswitch_readreg), DEVMETHOD(etherswitch_writereg, arswitch_writereg), diff --git a/sys/dev/etherswitch/arswitch/arswitch_phy.c b/sys/dev/etherswitch/arswitch/arswitch_phy.c index 283cdb6..f896d42 100644 --- a/sys/dev/etherswitch/arswitch/arswitch_phy.c +++ b/sys/dev/etherswitch/arswitch/arswitch_phy.c @@ -75,13 +75,19 @@ static SYSCTL_NODE(_debug, OID_AUTO, arswitch, CTLFLAG_RD, 0, "arswitch"); int arswitch_readphy(device_t dev, int phy, int reg) { + struct arswitch_softc *sc; uint32_t data = 0, ctrl; int err, timeout; + sc = device_get_softc(dev); + ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); + if (phy < 0 || phy >= 32) return (ENXIO); if (reg < 0 || reg >= 32) return (ENXIO); + + ARSWITCH_LOCK(sc); err = arswitch_writereg_msb(dev, AR8X16_REG_MDIO_CTRL, AR8X16_MDIO_CTRL_BUSY | AR8X16_MDIO_CTRL_MASTER_EN | AR8X16_MDIO_CTRL_CMD_READ | @@ -89,41 +95,50 @@ arswitch_readphy(device_t dev, int phy, int reg) (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT)); DEVERR(dev, err, "arswitch_readphy()=%d: phy=%d.%02x\n", phy, reg); if (err != 0) - return (-1); + goto fail; for (timeout = 100; timeout--; ) { ctrl = arswitch_readreg_msb(dev, AR8X16_REG_MDIO_CTRL); if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0) break; } if (timeout < 0) - err = EIO; + goto fail; data = arswitch_readreg_lsb(dev, AR8X16_REG_MDIO_CTRL) & AR8X16_MDIO_CTRL_DATA_MASK; + ARSWITCH_UNLOCK(sc); return (data); + +fail: + ARSWITCH_UNLOCK(sc); + return (-1); } int arswitch_writephy(device_t dev, int phy, int reg, int data) { + struct arswitch_softc *sc; uint32_t ctrl; int err, timeout; - + + sc = device_get_softc(dev); + ARSWITCH_LOCK_ASSERT(sc, MA_NOTOWNED); + if (reg < 0 || reg >= 32) return (ENXIO); + + ARSWITCH_LOCK(sc); err = arswitch_writereg_lsb(dev, AR8X16_REG_MDIO_CTRL, (data & AR8X16_MDIO_CTRL_DATA_MASK)); - DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg); if (err != 0) - return (err); + goto out; err = arswitch_writereg_msb(dev, AR8X16_REG_MDIO_CTRL, AR8X16_MDIO_CTRL_BUSY | AR8X16_MDIO_CTRL_MASTER_EN | AR8X16_MDIO_CTRL_CMD_WRITE | (phy << AR8X16_MDIO_CTRL_PHY_ADDR_SHIFT) | (reg << AR8X16_MDIO_CTRL_REG_ADDR_SHIFT)); - DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg); if (err != 0) - return (err); + goto out; for (timeout = 100; timeout--; ) { ctrl = arswitch_readreg(dev, AR8X16_REG_MDIO_CTRL); if ((ctrl & AR8X16_MDIO_CTRL_BUSY) == 0) @@ -131,6 +146,8 @@ arswitch_writephy(device_t dev, int phy, int reg, int data) } if (timeout < 0) err = EIO; +out: DEVERR(dev, err, "arswitch_writephy()=%d: phy=%d.%02x\n", phy, reg); + ARSWITCH_UNLOCK(sc); return (err); } diff --git a/sys/dev/etherswitch/etherswitch.c b/sys/dev/etherswitch/etherswitch.c index a216289..01a94af 100644 --- a/sys/dev/etherswitch/etherswitch.c +++ b/sys/dev/etherswitch/etherswitch.c @@ -213,12 +213,16 @@ etherswitchioctl(struct cdev *cdev, u_long cmd, caddr_t data, int flags, struct case IOETHERSWITCHGETREG: reg = (etherswitch_reg_t *)data; + ETHERSWITCH_LOCK(etherswitch); reg->val = ETHERSWITCH_READREG(etherswitch, reg->reg); + ETHERSWITCH_UNLOCK(etherswitch); break; case IOETHERSWITCHSETREG: reg = (etherswitch_reg_t *)data; + ETHERSWITCH_LOCK(etherswitch); error = ETHERSWITCH_WRITEREG(etherswitch, reg->reg, reg->val); + ETHERSWITCH_UNLOCK(etherswitch); break; case IOETHERSWITCHGETPORT: diff --git a/sys/dev/etherswitch/etherswitch_if.m b/sys/dev/etherswitch/etherswitch_if.m index 7429c04..20970d7 100644 --- a/sys/dev/etherswitch/etherswitch_if.m +++ b/sys/dev/etherswitch/etherswitch_if.m @@ -11,6 +11,21 @@ INTERFACE etherswitch; # +# Default implementation +# +CODE { + static void + null_etherswitch_lock(device_t dev) + { + } + + static void + null_etherswitch_unlock(device_t dev) + { + } +}; + +# # Return device info # METHOD etherswitch_info_t* getinfo { @@ -18,6 +33,20 @@ METHOD etherswitch_info_t* getinfo { } # +# Lock access to switch registers +# +METHOD void lock { + device_t dev; +} DEFAULT null_etherswitch_lock; + +# +# Unlock access to switch registers +# +METHOD void unlock { + device_t dev; +} DEFAULT null_etherswitch_unlock; + +# # Read switch register # METHOD int readreg { |