summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authorray <ray@FreeBSD.org>2012-10-15 12:20:40 +0000
committerray <ray@FreeBSD.org>2012-10-15 12:20:40 +0000
commit304e13439b52bec3ac813e787148986209e890f8 (patch)
treef90f8242e4bcad01cc768a7afb94a17308ac6909 /sys/dev
parent5b7ad0edc8102b0195e61417799c4a1be6710dfc (diff)
downloadFreeBSD-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.c25
-rw-r--r--sys/dev/etherswitch/arswitch/arswitch_phy.c31
-rw-r--r--sys/dev/etherswitch/etherswitch.c4
-rw-r--r--sys/dev/etherswitch/etherswitch_if.m29
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 {
OpenPOWER on IntegriCloud