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

Commit a645a761 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: emac: Add Wake-on-LAN support"

parents d5989a19 fd060e92
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -760,5 +760,6 @@ int emac_clk_set_rate(struct emac_adapter *adpt, enum emac_clk_id id,
		      enum emac_clk_rate rate);
void emac_task_schedule(struct emac_adapter *adpt);
void emac_check_lsc(struct emac_adapter *adpt);
void emac_wol_gpio_irq(struct emac_adapter *adpt, bool enable);

#endif /* _QCOM_EMAC_H_ */
+15 −3
Original line number Diff line number Diff line
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -322,6 +322,8 @@ static void emac_get_wol(struct net_device *netdev,
static int emac_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
	struct emac_adapter *adpt = netdev_priv(netdev);
	struct phy_device *phydev = netdev->phydev;
	u32 ret = 0;

	if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE |
			    WAKE_UCAST | WAKE_BCAST | WAKE_MCAST))
@@ -330,13 +332,23 @@ static int emac_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
	if (emac_wol_exclusion(adpt, wol))
		return wol->wolopts ? -EOPNOTSUPP : 0;

	/* Enable WOL interrupt */
	ret = phy_ethtool_set_wol(phydev, wol);
	if (ret)
		return ret;

	adpt->wol = 0;
	if (wol->wolopts & WAKE_MAGIC)
	if (wol->wolopts & WAKE_MAGIC) {
		adpt->wol |= EMAC_WOL_MAGIC;
		emac_wol_gpio_irq(adpt, true);
		/* Release wakelock */
		__pm_relax(&adpt->link_wlock);
	}

	if (wol->wolopts & WAKE_PHY)
		adpt->wol |= EMAC_WOL_PHY;

	return 0;
	return ret;
}

static int emac_get_intr_coalesce(struct net_device *netdev,
+1 −0
Original line number Diff line number Diff line
@@ -149,4 +149,5 @@ bool emac_hw_read_tx_tstamp(struct emac_hw *hw, struct emac_hwtxtstamp *ts);
/* MII_INT_ENABLE/MII_INT_STATUS */
#define LINK_SUCCESS_INTERRUPT			BIT(10)
#define LINK_SUCCESS_BX			BIT(7)
#define WOL_INT				BIT(0)
#endif /*_EMAC_HW_H_*/
+17 −6
Original line number Diff line number Diff line
@@ -1132,7 +1132,7 @@ static int emac_start_xmit(struct sk_buff *skb,
}

/* This funciton aquire spin-lock so should not call from sleeping context */
static void emac_wol_gpio_irq(struct emac_adapter *adpt, bool enable)
void emac_wol_gpio_irq(struct emac_adapter *adpt, bool enable)
{
	struct emac_irq_per_dev *wol_irq = &adpt->irq[EMAC_WOL_IRQ];
	struct emac_phy *phy = &adpt->phy;
@@ -1174,6 +1174,8 @@ static irqreturn_t emac_wol_isr(int irq, void *data)
	if (!pm_runtime_status_suspended(adpt->netdev->dev.parent)) {
		if (val)
			emac_wol_gpio_irq(adpt, false);
		if (val & WOL_INT)
			__pm_stay_awake(&adpt->link_wlock);
	}
	return IRQ_HANDLED;
}
@@ -2035,9 +2037,10 @@ static int emac_open(struct net_device *netdev)
	if (irq->irq) {
		/* Register for EMAC WOL ISR */
		retval = request_threaded_irq(irq->irq, NULL, irq_cmn->handler,
					      IRQF_TRIGGER_FALLING
					      IRQF_TRIGGER_LOW
					      | IRQF_ONESHOT,
					      irq_cmn->name, irq);
		enable_irq_wake(irq->irq);
		if (retval) {
			emac_err(adpt,
				 "error:%d on request_irq(%d:%s flags:0x%lx)\n",
@@ -2076,6 +2079,7 @@ static int emac_close(struct net_device *netdev)
		phy->is_wol_enabled = false;
		free_irq(adpt->irq[EMAC_WOL_IRQ].irq, &adpt->irq[EMAC_WOL_IRQ]);
		phy->is_wol_irq_reg = 0;
		disable_irq_wake(adpt->irq[EMAC_WOL_IRQ].irq);
	}

	if (!TEST_FLAG(adpt, ADPT_STATE_DOWN))
@@ -2452,7 +2456,7 @@ static void emac_init_adapter(struct emac_adapter *adpt)

	/* others */
	hw->preamble = EMAC_PREAMBLE_DEF;
	adpt->wol = EMAC_WOL_MAGIC | EMAC_WOL_PHY;
	adpt->wol = EMAC_WOL_PHY;

	adpt->phy.is_ext_phy_connect = 0;
}
@@ -2812,7 +2816,7 @@ static int emac_pm_suspend(struct device *device, bool wol_enable)
	u32 wufc = adpt->wol;

	/* Check link state. Don't suspend if link is up */
	if (netif_carrier_ok(adpt->netdev))
	if (netif_carrier_ok(adpt->netdev) && !(adpt->wol & EMAC_WOL_MAGIC))
		return -EPERM;

	/* cannot suspend if WOL interrupt is not enabled */
@@ -2834,7 +2838,7 @@ static int emac_pm_suspend(struct device *device, bool wol_enable)
	flush_delayed_work(&adpt->phydev->state_queue);
	if (QCA8337_PHY_ID != adpt->phydev->phy_id)
		emac_hw_config_pow_save(hw, adpt->phydev->speed, !!wufc,
					!!(wufc & EMAC_WOL_MAGIC));
					!!(wufc & EMAC_WOL_PHY));

	if (!adpt->phydev->link && phy->is_wol_irq_reg) {
		int value, i;
@@ -2936,17 +2940,24 @@ static int emac_pm_sys_suspend(struct device *device)

	if (!pm_runtime_enabled(device) || !pm_runtime_suspended(device)) {
		emac_pm_suspend(device, false);

		/* Synchronize runtime-pm and system-pm states:
		 * at this point we are already suspended. However, the
		 * runtime-PM framework still thinks that we are active.
		 * The three calls below let the runtime-PM know that we are
		 * suspended already without re-invoking the suspend callback
		 */
		if (adpt->wol & EMAC_WOL_MAGIC) {
			pm_runtime_mark_last_busy(netdev->dev.parent);
			pm_runtime_put_autosuspend(netdev->dev.parent);
		}
		pm_runtime_disable(netdev->dev.parent);
		pm_runtime_set_suspended(netdev->dev.parent);
		pm_runtime_enable(netdev->dev.parent);
	}

		/* Clear the Magic packet flag */
		adpt->wol &= ~EMAC_WOL_MAGIC;
	}
	netif_device_detach(netdev);
	emac_disable_clks(adpt);
	emac_disable_regulator(adpt, EMAC_VREG1, EMAC_VREG2);