summaryrefslogtreecommitdiff
path: root/drivers/net
diff options
context:
space:
mode:
authorGrygorii Strashko <grygorii.strashko@ti.com>2016-06-24 18:23:44 (GMT)
committerDavid S. Miller <davem@davemloft.net>2016-06-28 12:57:18 (GMT)
commit7898b1daf055537a8f661828272defecdee49f27 (patch)
tree0a1a0d39fb3383e817560985d753e7bb287804c3 /drivers/net
parent74556f516702331444b3c2d900a6a1d1fc9fc4cd (diff)
downloadlinux-7898b1daf055537a8f661828272defecdee49f27.tar.xz
drivers: net: cpsw: ethtool: fix accessing to suspended device
The CPSW might be suspended by RPM if all ethX interfaces are down, but it still could be accesible through ethtool interfce. In this case ethtool operations, requiring registers access, will cause L3 errors and CPSW crash. ethtool callbcaks which need to access CPSW registers now: .set_coalesce(), .get_ethtool_stats(), .set_pauseparam(), .get_regs() Hence, fix it by adding .begin()/.complete() ethtool callbacks, which will be called before/after each ethtool operation runs, and do CPSW RPM handling in these callbacks. That way CPSW will be active while handling ethtool requests. Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ethernet/ti/cpsw.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index b6c508e..2b21cad 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -1905,10 +1905,33 @@ static int cpsw_set_pauseparam(struct net_device *ndev,
priv->tx_pause = pause->tx_pause ? true : false;
for_each_slave(priv, _cpsw_adjust_link, priv, &link);
-
return 0;
}
+static int cpsw_ethtool_op_begin(struct net_device *ndev)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = pm_runtime_get_sync(&priv->pdev->dev);
+ if (ret < 0) {
+ cpsw_err(priv, drv, "ethtool begin failed %d\n", ret);
+ pm_runtime_put_noidle(&priv->pdev->dev);
+ }
+
+ return ret;
+}
+
+static void cpsw_ethtool_op_complete(struct net_device *ndev)
+{
+ struct cpsw_priv *priv = netdev_priv(ndev);
+ int ret;
+
+ ret = pm_runtime_put(&priv->pdev->dev);
+ if (ret < 0)
+ cpsw_err(priv, drv, "ethtool complete failed %d\n", ret);
+}
+
static const struct ethtool_ops cpsw_ethtool_ops = {
.get_drvinfo = cpsw_get_drvinfo,
.get_msglevel = cpsw_get_msglevel,
@@ -1928,6 +1951,8 @@ static const struct ethtool_ops cpsw_ethtool_ops = {
.set_wol = cpsw_set_wol,
.get_regs_len = cpsw_get_regs_len,
.get_regs = cpsw_get_regs,
+ .begin = cpsw_ethtool_op_begin,
+ .complete = cpsw_ethtool_op_complete,
};
static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,