Commit 298e54fa authored by Russell King's avatar Russell King Committed by David S. Miller

net: phy: add core phylib sfp support

Add core phylib help for supporting SFP sockets on PHYs.  This provides
a mechanism to inform the SFP layer about PHY up/down events, and also
unregister the SFP bus when the PHY is going away.
Signed-off-by: default avatarRussell King <rmk+kernel@armlinux.org.uk>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fb3d8bcd
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/phy_led_triggers.h> #include <linux/phy_led_triggers.h>
#include <linux/sfp.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/mdio.h> #include <linux/mdio.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -841,6 +842,9 @@ void phy_stop(struct phy_device *phydev) ...@@ -841,6 +842,9 @@ void phy_stop(struct phy_device *phydev)
mutex_lock(&phydev->lock); mutex_lock(&phydev->lock);
if (phydev->sfp_bus)
sfp_upstream_stop(phydev->sfp_bus);
phydev->state = PHY_HALTED; phydev->state = PHY_HALTED;
mutex_unlock(&phydev->lock); mutex_unlock(&phydev->lock);
...@@ -875,6 +879,9 @@ void phy_start(struct phy_device *phydev) ...@@ -875,6 +879,9 @@ void phy_start(struct phy_device *phydev)
goto out; goto out;
} }
if (phydev->sfp_bus)
sfp_upstream_start(phydev->sfp_bus);
/* if phy was suspended, bring the physical link up again */ /* if phy was suspended, bring the physical link up again */
__phy_resume(phydev); __phy_resume(phydev);
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/bitmap.h> #include <linux/bitmap.h>
#include <linux/phy.h> #include <linux/phy.h>
#include <linux/phy_led_triggers.h> #include <linux/phy_led_triggers.h>
#include <linux/sfp.h>
#include <linux/mdio.h> #include <linux/mdio.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
...@@ -1174,6 +1175,65 @@ phy_standalone_show(struct device *dev, struct device_attribute *attr, ...@@ -1174,6 +1175,65 @@ phy_standalone_show(struct device *dev, struct device_attribute *attr,
} }
static DEVICE_ATTR_RO(phy_standalone); static DEVICE_ATTR_RO(phy_standalone);
/**
* phy_sfp_attach - attach the SFP bus to the PHY upstream network device
* @upstream: pointer to the phy device
* @bus: sfp bus representing cage being attached
*
* This is used to fill in the sfp_upstream_ops .attach member.
*/
void phy_sfp_attach(void *upstream, struct sfp_bus *bus)
{
struct phy_device *phydev = upstream;
if (phydev->attached_dev)
phydev->attached_dev->sfp_bus = bus;
phydev->sfp_bus_attached = true;
}
EXPORT_SYMBOL(phy_sfp_attach);
/**
* phy_sfp_detach - detach the SFP bus from the PHY upstream network device
* @upstream: pointer to the phy device
* @bus: sfp bus representing cage being attached
*
* This is used to fill in the sfp_upstream_ops .detach member.
*/
void phy_sfp_detach(void *upstream, struct sfp_bus *bus)
{
struct phy_device *phydev = upstream;
if (phydev->attached_dev)
phydev->attached_dev->sfp_bus = NULL;
phydev->sfp_bus_attached = false;
}
EXPORT_SYMBOL(phy_sfp_detach);
/**
* phy_sfp_probe - probe for a SFP cage attached to this PHY device
* @phydev: Pointer to phy_device
* @ops: SFP's upstream operations
*/
int phy_sfp_probe(struct phy_device *phydev,
const struct sfp_upstream_ops *ops)
{
struct sfp_bus *bus;
int ret;
if (phydev->mdio.dev.fwnode) {
bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode);
if (IS_ERR(bus))
return PTR_ERR(bus);
phydev->sfp_bus = bus;
ret = sfp_bus_add_upstream(bus, phydev, ops);
sfp_bus_put(bus);
}
return 0;
}
EXPORT_SYMBOL(phy_sfp_probe);
/** /**
* phy_attach_direct - attach a network device to a given PHY device pointer * phy_attach_direct - attach a network device to a given PHY device pointer
* @dev: network device to attach * @dev: network device to attach
...@@ -1249,6 +1309,9 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev, ...@@ -1249,6 +1309,9 @@ int phy_attach_direct(struct net_device *dev, struct phy_device *phydev,
if (dev) { if (dev) {
phydev->attached_dev = dev; phydev->attached_dev = dev;
dev->phydev = phydev; dev->phydev = phydev;
if (phydev->sfp_bus_attached)
dev->sfp_bus = phydev->sfp_bus;
} }
/* Some Ethernet drivers try to connect to a PHY device before /* Some Ethernet drivers try to connect to a PHY device before
...@@ -2418,6 +2481,9 @@ static int phy_remove(struct device *dev) ...@@ -2418,6 +2481,9 @@ static int phy_remove(struct device *dev)
phydev->state = PHY_DOWN; phydev->state = PHY_DOWN;
mutex_unlock(&phydev->lock); mutex_unlock(&phydev->lock);
sfp_bus_del_upstream(phydev->sfp_bus);
phydev->sfp_bus = NULL;
if (phydev->drv && phydev->drv->remove) { if (phydev->drv && phydev->drv->remove) {
phydev->drv->remove(phydev); phydev->drv->remove(phydev);
......
...@@ -203,6 +203,8 @@ static inline const char *phy_modes(phy_interface_t interface) ...@@ -203,6 +203,8 @@ static inline const char *phy_modes(phy_interface_t interface)
struct device; struct device;
struct phylink; struct phylink;
struct sfp_bus;
struct sfp_upstream_ops;
struct sk_buff; struct sk_buff;
/* /*
...@@ -342,6 +344,8 @@ struct phy_c45_device_ids { ...@@ -342,6 +344,8 @@ struct phy_c45_device_ids {
* dev_flags: Device-specific flags used by the PHY driver. * dev_flags: Device-specific flags used by the PHY driver.
* irq: IRQ number of the PHY's interrupt (-1 if none) * irq: IRQ number of the PHY's interrupt (-1 if none)
* phy_timer: The timer for handling the state machine * phy_timer: The timer for handling the state machine
* sfp_bus_attached: flag indicating whether the SFP bus has been attached
* sfp_bus: SFP bus attached to this PHY's fiber port
* attached_dev: The attached enet driver's device instance ptr * attached_dev: The attached enet driver's device instance ptr
* adjust_link: Callback for the enet controller to respond to * adjust_link: Callback for the enet controller to respond to
* changes in the link state. * changes in the link state.
...@@ -432,6 +436,9 @@ struct phy_device { ...@@ -432,6 +436,9 @@ struct phy_device {
struct mutex lock; struct mutex lock;
/* This may be modified under the rtnl lock */
bool sfp_bus_attached;
struct sfp_bus *sfp_bus;
struct phylink *phylink; struct phylink *phylink;
struct net_device *attached_dev; struct net_device *attached_dev;
...@@ -1020,6 +1027,10 @@ int phy_suspend(struct phy_device *phydev); ...@@ -1020,6 +1027,10 @@ int phy_suspend(struct phy_device *phydev);
int phy_resume(struct phy_device *phydev); int phy_resume(struct phy_device *phydev);
int __phy_resume(struct phy_device *phydev); int __phy_resume(struct phy_device *phydev);
int phy_loopback(struct phy_device *phydev, bool enable); int phy_loopback(struct phy_device *phydev, bool enable);
void phy_sfp_attach(void *upstream, struct sfp_bus *bus);
void phy_sfp_detach(void *upstream, struct sfp_bus *bus);
int phy_sfp_probe(struct phy_device *phydev,
const struct sfp_upstream_ops *ops);
struct phy_device *phy_attach(struct net_device *dev, const char *bus_id, struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
phy_interface_t interface); phy_interface_t interface);
struct phy_device *phy_find_first(struct mii_bus *bus); struct phy_device *phy_find_first(struct mii_bus *bus);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment