Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 644afe23 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'cpsw-runtime-pm'

Grygorii Strashko says:

====================
drivers: net: cpsw: improve runtime pm

This series intended to improve runtime PM and allow CPSW to be
RPM suspended when all ethX netdevices are down.

To achieve above goal it is required to relax runtime PM constraints for
Davinci MDIO which blocks CPSW runtime PM now, because Davinci MDIO is always
powered on during probe and powered off only when it's going to be removed.
- Patches 6-11 implement PM runtime autosuspend for Davinci MDIO, but keep it
disabled by default, because Davinci MDIO is integrated in big set of TI devices
and not all of them verified to work correctly with RPM autosuspend enabled:
 expected to work on SoCs where MDIO is defined as part of CPSW in DT
 (cpsw.c DRA7/am57x, am437x, am335x)
The CPSW need to be fixed before RPM suspended can be allowed:
 - Patches 1-5 ensure that CPSW will not cause L3 errors while it is in RPM
   suspended state.

Davinci MDIO RPM autosuspend can be enabled through sysfs:
 echo 100 > /sys/devices/../48484000.ethernet/48485000.mdio/power/autosuspend_delay_ms

Patches 12 - 15: introduce new compatible string "ti,cpsw-mdio" which is used
then to enable RPM for am335x/am437x/dra7 SoCs.

Tested on am335x, am437x, am572x and k2g (on k2g with RPM disabled for Davinci MDIO)
These changes should not affect on errata i877 implementation on DRA7.

Power measurement on am335x GP EVM:
 Without this series:  547.60 mW total SoC power
 With this series + "ifconfig eth0 down": 477.32 mW Total Soc Power

Changes in v2:
- CPSW ethtool interface updated to use .begin()/.complete() callbacks
- kbuild failure fixed
- davinci_mdio DT updated with proper description of allowed compatible strings
  combinations

Link on v1:
 https://lkml.org/lkml/2016/6/15/362


====================

Reviewed-by: default avatarMugunthan V N <mugunthanvnm@ti.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 8f659aee 9efd1a6f
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -2,7 +2,10 @@ TI SoC Davinci/Keystone2 MDIO Controller Device Tree Bindings
---------------------------------------------------

Required properties:
- compatible		: Should be "ti,davinci_mdio" or "ti,keystone_mdio"
- compatible		: Should be "ti,davinci_mdio"
			  and "ti,keystone_mdio" for Keystone 2 SoCs
			  and "ti,cpsw-mdio" for am335x, am472x, am57xx/dra7, dm814x SoCs
			  and "ti,am4372-mdio" for am472x SoC
- reg			: physical base address and size of the davinci mdio
			  registers map
- bus_freq		: Mdio Bus frequency
+1 −1
Original line number Diff line number Diff line
@@ -788,7 +788,7 @@
			status = "disabled";

			davinci_mdio: mdio@4a101000 {
				compatible = "ti,davinci_mdio";
				compatible = "ti,cpsw-mdio","ti,davinci_mdio";
				#address-cells = <1>;
				#size-cells = <0>;
				ti,hwmods = "davinci_mdio";
+1 −1
Original line number Diff line number Diff line
@@ -635,7 +635,7 @@
			syscon = <&scm_conf>;

			davinci_mdio: mdio@4a101000 {
				compatible = "ti,am4372-mdio","ti,davinci_mdio";
				compatible = "ti,am4372-mdio","ti,cpsw-mdio","ti,davinci_mdio";
				reg = <0x4a101000 0x100>;
				#address-cells = <1>;
				#size-cells = <0>;
+1 −1
Original line number Diff line number Diff line
@@ -1660,7 +1660,7 @@
			status = "disabled";

			davinci_mdio: mdio@48485000 {
				compatible = "ti,davinci_mdio";
				compatible = "ti,cpsw-mdio","ti,davinci_mdio";
				#address-cells = <1>;
				#size-cells = <0>;
				ti,hwmods = "davinci_mdio";
+67 −12
Original line number Diff line number Diff line
@@ -1243,6 +1243,7 @@ static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv)
	slave->phy = NULL;
	cpsw_ale_control_set(priv->ale, slave_port,
			     ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
	soft_reset_slave(slave);
}

static int cpsw_ndo_open(struct net_device *ndev)
@@ -1251,7 +1252,11 @@ static int cpsw_ndo_open(struct net_device *ndev)
	int i, ret;
	u32 reg;

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

	if (!cpsw_common_res_usage_state(priv))
		cpsw_intr_disable(priv);
@@ -1609,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;
@@ -1627,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;
}

@@ -1691,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
@@ -1709,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,
@@ -1721,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;

@@ -1740,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,
	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 = {
@@ -1900,10 +1932,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,
@@ -1923,6 +1978,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,
@@ -2311,7 +2368,11 @@ static int cpsw_probe(struct platform_device *pdev)
	/* Need to enable clocks with runtime PM api to access module
	 * registers
	 */
	pm_runtime_get_sync(&pdev->dev);
	ret = pm_runtime_get_sync(&pdev->dev);
	if (ret < 0) {
		pm_runtime_put_noidle(&pdev->dev);
		goto clean_runtime_disable_ret;
	}
	priv->version = readl(&priv->regs->id_ver);
	pm_runtime_put_sync(&pdev->dev);

@@ -2548,16 +2609,12 @@ static int cpsw_suspend(struct device *dev)
		for (i = 0; i < priv->data.slaves; i++) {
			if (netif_running(priv->slaves[i].ndev))
				cpsw_ndo_stop(priv->slaves[i].ndev);
			soft_reset_slave(priv->slaves + i);
		}
	} else {
		if (netif_running(ndev))
			cpsw_ndo_stop(ndev);
		for_each_slave(priv, soft_reset_slave);
	}

	pm_runtime_put_sync(&pdev->dev);

	/* Select sleep pin state */
	pinctrl_pm_select_sleep_state(&pdev->dev);

@@ -2570,8 +2627,6 @@ static int cpsw_resume(struct device *dev)
	struct net_device	*ndev = platform_get_drvdata(pdev);
	struct cpsw_priv	*priv = netdev_priv(ndev);

	pm_runtime_get_sync(&pdev->dev);

	/* Select default pin state */
	pinctrl_pm_select_default_state(&pdev->dev);

Loading