Skip to content

Commit

Permalink
drivers: net: cpsw: ndev: fix accessing to suspended device
Browse files Browse the repository at this point in the history
The CPSW might be suspended by RPM if all ethX interfaces are down,
but it still could be accesible through net_device_ops interfce. In
this case net_device_ops operations requiring registers access will
cause L3 errors and CPSW crash.

Hence, fix it by adding RPM get/put calls in net_device_ops callbacks
which need to access CPSW registers: .ndo_set_mac_address(),
.ndo_vlan_rx_add_vid(), .ndo_vlan_rx_kill_vid().

Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Grygorii Strashko authored and David S. Miller committed Jun 28, 2016
1 parent 7898b1d commit a6c5d14
Showing 1 changed file with 30 additions and 3 deletions.
33 changes: 30 additions & 3 deletions drivers/net/ethernet/ti/cpsw.c
Original file line number Diff line number Diff line change
Expand Up @@ -1614,10 +1614,17 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p)
struct sockaddr *addr = (struct sockaddr *)p;
int flags = 0;
u16 vid = 0;
int ret;

if (!is_valid_ether_addr(addr->sa_data))
return -EADDRNOTAVAIL;

ret = pm_runtime_get_sync(&priv->pdev->dev);
if (ret < 0) {
pm_runtime_put_noidle(&priv->pdev->dev);
return ret;
}

if (priv->data.dual_emac) {
vid = priv->slaves[priv->emac_port].port_vlan;
flags = ALE_VLAN;
Expand All @@ -1632,6 +1639,8 @@ static int cpsw_ndo_set_mac_address(struct net_device *ndev, void *p)
memcpy(ndev->dev_addr, priv->mac_addr, ETH_ALEN);
for_each_slave(priv, cpsw_set_slave_mac, priv);

pm_runtime_put(&priv->pdev->dev);

return 0;
}

Expand Down Expand Up @@ -1696,10 +1705,17 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
__be16 proto, u16 vid)
{
struct cpsw_priv *priv = netdev_priv(ndev);
int ret;

if (vid == priv->data.default_vlan)
return 0;

ret = pm_runtime_get_sync(&priv->pdev->dev);
if (ret < 0) {
pm_runtime_put_noidle(&priv->pdev->dev);
return ret;
}

if (priv->data.dual_emac) {
/* In dual EMAC, reserved VLAN id should not be used for
* creating VLAN interfaces as this can break the dual
Expand All @@ -1714,7 +1730,10 @@ static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev,
}

dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid);
return cpsw_add_vlan_ale_entry(priv, vid);
ret = cpsw_add_vlan_ale_entry(priv, vid);

pm_runtime_put(&priv->pdev->dev);
return ret;
}

static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
Expand All @@ -1726,6 +1745,12 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
if (vid == priv->data.default_vlan)
return 0;

ret = pm_runtime_get_sync(&priv->pdev->dev);
if (ret < 0) {
pm_runtime_put_noidle(&priv->pdev->dev);
return ret;
}

if (priv->data.dual_emac) {
int i;

Expand All @@ -1745,8 +1770,10 @@ static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev,
if (ret != 0)
return ret;

return cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast,
0, ALE_VLAN, vid);
ret = cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast,
0, ALE_VLAN, vid);
pm_runtime_put(&priv->pdev->dev);
return ret;
}

static const struct net_device_ops cpsw_netdev_ops = {
Expand Down

0 comments on commit a6c5d14

Please sign in to comment.