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

Reply via email to