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

Commit b3512051 authored by Vladimir Kondratiev's avatar Vladimir Kondratiev Committed by Ian Maund
Browse files

wil6210: system power management



Support for the system suspend/resume.
In preparation for the run-time PM, implementation made
run-time PM friendly: common for system and run-time PM
code factored out as generic functions, albeit is_runtime
parameter value is always false currently.

For debug purposes, "PM" debug category introduced.

Policy: AP-like interface can't be suspended; otherwise
suspend is allowed. Hardware brought down if interface
was up. Connection, if existed, get lost.
Interface will be brought up upon resume if it was up
before suspend.

Change-Id: Ia9e320960912b848dfc9caab52767cb9f6183a00
Signed-off-by: default avatarVladimir Kondratiev <qca_vkondrat@qca.qualcomm.com>
Signed-off-by: default avatarKalle Valo <kvalo@qca.qualcomm.com>
Git-commit: 93cb679a768bb526a60a9c4ce30beb45465334be
Git-repo: https://github.com/kvalo/ath.git


Signed-off-by: default avatarHamad Kadmany <hkadmany@codeaurora.org>
parent ee1466e0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@ wil6210-y += debug.o
wil6210-y += rx_reorder.o
wil6210-y += ioctl.o
wil6210-y += fw.o
wil6210-y += pm.o
wil6210-y += pmc.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
wil6210-y += wil_platform.o
+69 −0
Original line number Diff line number Diff line
@@ -259,11 +259,80 @@ static const struct pci_device_id wil6210_pcie_ids[] = {
};
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);

#ifdef CONFIG_PM

static int wil6210_suspend(struct device *dev, bool is_runtime)
{
	int rc = 0;
	struct pci_dev *pdev = to_pci_dev(dev);
	struct wil6210_priv *wil = pci_get_drvdata(pdev);

	wil_dbg_pm(wil, "%s(%s)\n", __func__,
		   is_runtime ? "runtime" : "system");

	rc = wil_can_suspend(wil, is_runtime);
	if (rc)
		goto out;

	rc = wil_suspend(wil, is_runtime);
	if (rc)
		goto out;

	/* TODO: how do I bring card in low power state? */

	/* disable bus mastering */
	pci_clear_master(pdev);
	/* PCI will call pci_save_state(pdev) and pci_prepare_to_sleep(pdev) */

out:
	return rc;
}

static int wil6210_resume(struct device *dev, bool is_runtime)
{
	int rc = 0;
	struct pci_dev *pdev = to_pci_dev(dev);
	struct wil6210_priv *wil = pci_get_drvdata(pdev);

	wil_dbg_pm(wil, "%s(%s)\n", __func__,
		   is_runtime ? "runtime" : "system");

	/* allow master */
	pci_set_master(pdev);

	rc = wil_resume(wil, is_runtime);
	if (rc)
		pci_clear_master(pdev);

	return rc;
}

#ifdef CONFIG_PM_SLEEP
static int wil6210_pm_suspend(struct device *dev)
{
	return wil6210_suspend(dev, false);
}

static int wil6210_pm_resume(struct device *dev)
{
	return wil6210_resume(dev, false);
}
#endif /* CONFIG_PM_SLEEP */

#endif /* CONFIG_PM */

static const struct dev_pm_ops wil6210_pm_ops = {
	SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume)
};

static struct pci_driver wil6210_driver = {
	.probe		= wil_pcie_probe,
	.remove		= wil_pcie_remove,
	.id_table	= wil6210_pcie_ids,
	.name		= WIL_NAME,
	.driver		= {
		.pm = &wil6210_pm_ops,
	},
};

static int __init wil6210_driver_init(void)
+98 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2014 Qualcomm Atheros, Inc.
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include "wil6210.h"

int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime)
{
	int rc = 0;
	struct wireless_dev *wdev = wil->wdev;

	wil_dbg_pm(wil, "%s(%s)\n", __func__,
		   is_runtime ? "runtime" : "system");

	switch (wdev->iftype) {
	case NL80211_IFTYPE_MONITOR:
	case NL80211_IFTYPE_STATION:
	case NL80211_IFTYPE_P2P_CLIENT:
		break;
	/* AP-like interface - can't suspend */
	default:
		wil_dbg_pm(wil, "AP-like interface\n");
		rc = -EBUSY;
		break;
	}

	wil_dbg_pm(wil, "%s(%s) => %s (%d)\n", __func__,
		   is_runtime ? "runtime" : "system", rc ? "No" : "Yes", rc);

	return rc;
}

int wil_suspend(struct wil6210_priv *wil, bool is_runtime)
{
	int rc = 0;
	struct net_device *ndev = wil_to_ndev(wil);

	wil_dbg_pm(wil, "%s(%s)\n", __func__,
		   is_runtime ? "runtime" : "system");

	/* if netif up, hardware is alive, shut it down */
	if (ndev->flags & IFF_UP) {
		rc = wil_down(wil);
		if (rc) {
			wil_err(wil, "wil_down : %d\n", rc);
			goto out;
		}
	}

	if (wil->platform_ops.suspend)
		rc = wil->platform_ops.suspend(wil->platform_handle);

out:
	wil_dbg_pm(wil, "%s(%s) => %d\n", __func__,
		   is_runtime ? "runtime" : "system", rc);
	return rc;
}

int wil_resume(struct wil6210_priv *wil, bool is_runtime)
{
	int rc = 0;
	struct net_device *ndev = wil_to_ndev(wil);

	wil_dbg_pm(wil, "%s(%s)\n", __func__,
		   is_runtime ? "runtime" : "system");

	if (wil->platform_ops.resume) {
		rc = wil->platform_ops.resume(wil->platform_handle);
		if (rc) {
			wil_err(wil, "platform_ops.resume : %d\n", rc);
			goto out;
		}
	}

	/* if netif up, bring hardware up
	 * During open(), IFF_UP set after actual device method
	 * invocation. This prevent recursive call to wil_up()
	 */
	if (ndev->flags & IFF_UP)
		rc = wil_up(wil);

out:
	wil_dbg_pm(wil, "%s(%s) => %d\n", __func__,
		   is_runtime ? "runtime" : "system", rc);
	return rc;
}
+5 −0
Original line number Diff line number Diff line
@@ -643,6 +643,7 @@ void wil_info(struct wil6210_priv *wil, const char *fmt, ...);
#define wil_dbg_txrx(wil, fmt, arg...) wil_dbg(wil, "DBG[TXRX]" fmt, ##arg)
#define wil_dbg_wmi(wil, fmt, arg...) wil_dbg(wil, "DBG[ WMI]" fmt, ##arg)
#define wil_dbg_misc(wil, fmt, arg...) wil_dbg(wil, "DBG[MISC]" fmt, ##arg)
#define wil_dbg_pm(wil, fmt, arg...) wil_dbg(wil, "DBG[ PM ]" fmt, ##arg)

/* target operations */
/* register read */
@@ -811,4 +812,8 @@ int wil_iftype_nl2wmi(enum nl80211_iftype type);
int wil_ioctl(struct wil6210_priv *wil, void __user *data, int cmd);
int wil_request_firmware(struct wil6210_priv *wil, const char *name);

int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime);
int wil_suspend(struct wil6210_priv *wil, bool is_runtime);
int wil_resume(struct wil6210_priv *wil, bool is_runtime);

#endif /* __WIL6210_H__ */