Commit b2f2af21 authored by Florian Fainelli's avatar Florian Fainelli Committed by David S. Miller

net: dsa: allow enabling and disable switch ports

Whenever a per-port network device is used/unused, invoke the switch
driver port_enable/port_disable callbacks to allow saving as much power
as possible by disabling unused parts of the switch (RX/TX logic, memory
arrays, PHYs...). We supply a PHY device argument to make sure the
switch driver can act on the PHY device if needed (like putting/taking
the PHY out of deep low power mode).
Signed-off-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent f7f1de51
...@@ -224,6 +224,14 @@ struct dsa_switch_driver { ...@@ -224,6 +224,14 @@ struct dsa_switch_driver {
*/ */
int (*suspend)(struct dsa_switch *ds); int (*suspend)(struct dsa_switch *ds);
int (*resume)(struct dsa_switch *ds); int (*resume)(struct dsa_switch *ds);
/*
* Port enable/disable
*/
int (*port_enable)(struct dsa_switch *ds, int port,
struct phy_device *phy);
void (*port_disable)(struct dsa_switch *ds, int port,
struct phy_device *phy);
}; };
void register_switch_driver(struct dsa_switch_driver *type); void register_switch_driver(struct dsa_switch_driver *type);
......
...@@ -62,6 +62,7 @@ static int dsa_slave_open(struct net_device *dev) ...@@ -62,6 +62,7 @@ static int dsa_slave_open(struct net_device *dev)
{ {
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_slave_priv *p = netdev_priv(dev);
struct net_device *master = p->parent->dst->master_netdev; struct net_device *master = p->parent->dst->master_netdev;
struct dsa_switch *ds = p->parent;
int err; int err;
if (!(master->flags & IFF_UP)) if (!(master->flags & IFF_UP))
...@@ -84,11 +85,20 @@ static int dsa_slave_open(struct net_device *dev) ...@@ -84,11 +85,20 @@ static int dsa_slave_open(struct net_device *dev)
goto clear_allmulti; goto clear_allmulti;
} }
if (ds->drv->port_enable) {
err = ds->drv->port_enable(ds, p->port, p->phy);
if (err)
goto clear_promisc;
}
if (p->phy) if (p->phy)
phy_start(p->phy); phy_start(p->phy);
return 0; return 0;
clear_promisc:
if (dev->flags & IFF_PROMISC)
dev_set_promiscuity(master, 0);
clear_allmulti: clear_allmulti:
if (dev->flags & IFF_ALLMULTI) if (dev->flags & IFF_ALLMULTI)
dev_set_allmulti(master, -1); dev_set_allmulti(master, -1);
...@@ -103,6 +113,7 @@ static int dsa_slave_close(struct net_device *dev) ...@@ -103,6 +113,7 @@ static int dsa_slave_close(struct net_device *dev)
{ {
struct dsa_slave_priv *p = netdev_priv(dev); struct dsa_slave_priv *p = netdev_priv(dev);
struct net_device *master = p->parent->dst->master_netdev; struct net_device *master = p->parent->dst->master_netdev;
struct dsa_switch *ds = p->parent;
if (p->phy) if (p->phy)
phy_stop(p->phy); phy_stop(p->phy);
...@@ -117,6 +128,9 @@ static int dsa_slave_close(struct net_device *dev) ...@@ -117,6 +128,9 @@ static int dsa_slave_close(struct net_device *dev)
if (!ether_addr_equal(dev->dev_addr, master->dev_addr)) if (!ether_addr_equal(dev->dev_addr, master->dev_addr))
dev_uc_del(master, dev->dev_addr); dev_uc_del(master, dev->dev_addr);
if (ds->drv->port_disable)
ds->drv->port_disable(ds, p->port, p->phy);
return 0; return 0;
} }
......
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