add fixed_phy_update_state() - update state of fixed_phy
authorStas Sergeev <stsp@list.ru>
Wed, 1 Apr 2015 17:30:31 +0000 (20:30 +0300)
committerDavid S. Miller <davem@davemloft.net>
Fri, 3 Apr 2015 19:08:20 +0000 (15:08 -0400)
Currently fixed_phy uses a callback to periodically poll the link state.
This patch adds the fixed_phy_update_state() API.
It solves the following problems:
- On link state interrupt, MAC driver can't update status.
Instead it needs to provide the callback to periodically query
the HW about the link state. It is more efficient to update status
after interrupt.
- The callback needs to be unregistered before phy_disconnect(),
or otherwise it will be called with net_dev==NULL. phy_disconnect()
does not have enough info to unregister the callback automatically.
- The callback needs to be registered before of_phy_connect() to
avoid running with outdated state, but of_phy_connect() returns the
phy_device pointer, which is needed to register the callback. Registering
it before of_phy_connect() will therefore require a hack to get the
pointer earlier.

Overall, this addition makes the subsequent patch that implements
SGMII link status for mvneta, much cleaner.

CC: Florian Fainelli <f.fainelli@gmail.com>
CC: netdev@vger.kernel.org
CC: linux-kernel@vger.kernel.org
Signed-off-by: Stas Sergeev <stsp@users.sourceforge.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/phy/fixed_phy.c
include/linux/phy_fixed.h

index a08a3c78ba97b08fb503bace451a3d177fc04053..1960b46add65b3b89f122cc401c872050cebdbe4 100644 (file)
@@ -183,6 +183,35 @@ int fixed_phy_set_link_update(struct phy_device *phydev,
 }
 EXPORT_SYMBOL_GPL(fixed_phy_set_link_update);
 
+int fixed_phy_update_state(struct phy_device *phydev,
+                          const struct fixed_phy_status *status,
+                          const struct fixed_phy_status *changed)
+{
+       struct fixed_mdio_bus *fmb = &platform_fmb;
+       struct fixed_phy *fp;
+
+       if (!phydev || !phydev->bus)
+               return -EINVAL;
+
+       list_for_each_entry(fp, &fmb->phys, node) {
+               if (fp->addr == phydev->addr) {
+#define _UPD(x) if (changed->x) \
+       fp->status.x = status->x
+                       _UPD(link);
+                       _UPD(speed);
+                       _UPD(duplex);
+                       _UPD(pause);
+                       _UPD(asym_pause);
+#undef _UPD
+                       fixed_phy_update_regs(fp);
+                       return 0;
+               }
+       }
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL(fixed_phy_update_state);
+
 int fixed_phy_add(unsigned int irq, int phy_addr,
                  struct fixed_phy_status *status)
 {
index 7e75bfe37cc7cd72d5db63cd094b5110984b066b..fe5732d53edacd17af2e259e191f60e595721345 100644 (file)
@@ -21,6 +21,9 @@ extern void fixed_phy_del(int phy_addr);
 extern int fixed_phy_set_link_update(struct phy_device *phydev,
                        int (*link_update)(struct net_device *,
                                           struct fixed_phy_status *));
+extern int fixed_phy_update_state(struct phy_device *phydev,
+                          const struct fixed_phy_status *status,
+                          const struct fixed_phy_status *changed);
 #else
 static inline int fixed_phy_add(unsigned int irq, int phy_id,
                                struct fixed_phy_status *status)
@@ -43,6 +46,12 @@ static inline int fixed_phy_set_link_update(struct phy_device *phydev,
 {
        return -ENODEV;
 }
+static inline int fixed_phy_update_state(struct phy_device *phydev,
+                          const struct fixed_phy_status *status,
+                          const struct fixed_phy_status *changed)
+{
+       return -ENODEV;
+}
 #endif /* CONFIG_FIXED_PHY */
 
 #endif /* __PHY_FIXED_H */
This page took 0.026556 seconds and 5 git commands to generate.