In order to support hardware time stamping from a PHY, it is necessary to read from the PHY while running in_interrupt(). This patch allows a mii bus to operate in an atomic context. An mii_bus driver may declare itself capable for this mode. Drivers which do not do this will remain with the default that bus operations may sleep.
Signed-off-by: Richard Cochran <richard.coch...@omicron.at> --- drivers/net/phy/mdio_bus.c | 35 ++++++++++++++++++++++++++++------- include/linux/phy.h | 13 +++++++++++-- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 6a6b819..441be7d 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -36,6 +36,22 @@ #include <asm/irq.h> #include <asm/uaccess.h> +static inline void mdiobus_lock(struct mii_bus *bus) +{ + if (MDIOBUS_SLEEPS_RW == bus->locktype) + mutex_lock(&bus->mdio_lock.m); + else + spin_lock(&bus->mdio_lock.s); +} + +static inline void mdiobus_unlock(struct mii_bus *bus) +{ + if (MDIOBUS_SLEEPS_RW == bus->locktype) + mutex_unlock(&bus->mdio_lock.m); + else + spin_unlock(&bus->mdio_lock.s); +} + /** * mdiobus_alloc - allocate a mii_bus structure * @@ -107,7 +123,10 @@ int mdiobus_register(struct mii_bus *bus) return -EINVAL; } - mutex_init(&bus->mdio_lock); + if (MDIOBUS_SLEEPS_RW == bus->locktype) + mutex_init(&bus->mdio_lock.m); + else + spin_lock_init(&bus->mdio_lock.s); if (bus->reset) bus->reset(bus); @@ -212,11 +231,12 @@ int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) { int retval; - BUG_ON(in_interrupt()); + if (MDIOBUS_SLEEPS_RW == bus->locktype) + BUG_ON(in_interrupt()); - mutex_lock(&bus->mdio_lock); + mdiobus_lock(bus); retval = bus->read(bus, addr, regnum); - mutex_unlock(&bus->mdio_lock); + mdiobus_unlock(bus); return retval; } @@ -237,11 +257,12 @@ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) { int err; - BUG_ON(in_interrupt()); + if (MDIOBUS_SLEEPS_RW == bus->locktype) + BUG_ON(in_interrupt()); - mutex_lock(&bus->mdio_lock); + mdiobus_lock(bus); err = bus->write(bus, addr, regnum, val); - mutex_unlock(&bus->mdio_lock); + mdiobus_unlock(bus); return err; } diff --git a/include/linux/phy.h b/include/linux/phy.h index 7a8caac..352b030 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -98,11 +98,20 @@ struct mii_bus { int (*write)(struct mii_bus *bus, int phy_id, int regnum, u16 val); int (*reset)(struct mii_bus *bus); + /* Indicates whether bus may be used from an atomic context. */ + enum { + MDIOBUS_SLEEPS_RW, + MDIOBUS_ATOMIC_RW + } locktype; + /* - * A lock to ensure that only one thing can read/write + * A lock or mutex to ensure that only one thing can read/write * the MDIO bus at a time */ - struct mutex mdio_lock; + union { + struct mutex m; + spinlock_t s; + } mdio_lock; struct device *parent; enum { -- 1.6.3.3 _______________________________________________ Linuxppc-dev mailing list Linuxppc-dev@lists.ozlabs.org https://lists.ozlabs.org/listinfo/linuxppc-dev