From patchwork Mon Jul 31 16:32:28 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Maya Erez X-Patchwork-Id: 9872455 X-Patchwork-Delegate: kvalo@adurom.com Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 4A90B60365 for ; Mon, 31 Jul 2017 16:32:50 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 32B6A285D1 for ; Mon, 31 Jul 2017 16:32:50 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2459D2856D; Mon, 31 Jul 2017 16:32:50 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 26D7D28470 for ; Mon, 31 Jul 2017 16:32:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752573AbdGaQcs (ORCPT ); Mon, 31 Jul 2017 12:32:48 -0400 Received: from sabertooth02.qualcomm.com ([65.197.215.38]:37826 "EHLO sabertooth02.qualcomm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752566AbdGaQcq (ORCPT ); Mon, 31 Jul 2017 12:32:46 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=qca.qualcomm.com; i=@qca.qualcomm.com; q=dns/txt; s=qcdkim; t=1501518766; x=1533054766; h=cc:from:to:subject:date:message-id:in-reply-to: references; bh=VSCHo5yegQfkJih1NQtgKIpoczh28TJpB5zmZjRUe4I=; b=XtVKnq0ULl02eS+HjCn28dApMIwtXUGZRD4zX2TE8ovZXZB2JkWW9jY2 HrnDlxzcpW27wexiHXC/UmxzNggU/ckSefgmBhe9qvqqNHH0d4xvtTBfz oMhGqCuRYZWrCpCRtZfwyET8JGVIGvL3lsSAq1YW01pExurcR/lda12oO E=; X-IronPort-AV: E=Sophos;i="5.41,304,1498546800"; d="scan'208";a="112898155" Received: from unknown (HELO ironmsg02-L.qualcomm.com) ([10.53.140.109]) by sabertooth02.qualcomm.com with ESMTP; 31 Jul 2017 09:32:46 -0700 Cc: Lazar Alexei , linux-wireless@vger.kernel.org, wil6210@qca.qualcomm.com, Maya Erez X-IronPort-AV: E=McAfee;i="5900,7806,8608"; a="974365109" X-MGA-submission: =?us-ascii?q?MDHv2HbMVOSETjWqNLjEss+6ZdSkN80pan/X7l?= =?us-ascii?q?aF9VMO5PKqOjME0qngzImAqw0Yc9XvRARfr4AliW8aGN28xPqs6bUIxh?= =?us-ascii?q?85FUxDPdjg2M7O78ytR0JKBZM9wqy3/Gljv0KseOadZYmHmL2v214XAN?= =?us-ascii?q?WG?= Received: from lx-merez1.mea.qualcomm.com ([10.18.173.103]) by ironmsg02-L.qualcomm.com with ESMTP; 31 Jul 2017 09:32:44 -0700 From: Maya Erez To: Kalle Valo Subject: [PATCH 05/10] wil6210: run-time PM when interface down Date: Mon, 31 Jul 2017 19:32:28 +0300 Message-Id: <1501518753-6339-6-git-send-email-qca_merez@qca.qualcomm.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1501518753-6339-1-git-send-email-qca_merez@qca.qualcomm.com> References: <1501518753-6339-1-git-send-email-qca_merez@qca.qualcomm.com> Sender: linux-wireless-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-wireless@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Lazar Alexei Allow run-time suspend when interface is down, keep card alive when interface is up. If driver is in wmi only or debug_fw mode run-time PM won't suspend. Signed-off-by: Lazar Alexei Signed-off-by: Maya Erez --- drivers/net/wireless/ath/wil6210/debugfs.c | 85 ++++++++++++++++++++++++++--- drivers/net/wireless/ath/wil6210/ethtool.c | 15 +++++ drivers/net/wireless/ath/wil6210/netdev.c | 18 +++++- drivers/net/wireless/ath/wil6210/pcie_bus.c | 35 ++++++++++++ drivers/net/wireless/ath/wil6210/pm.c | 62 +++++++++++++++++++++ drivers/net/wireless/ath/wil6210/wil6210.h | 16 ++++++ 6 files changed, 222 insertions(+), 9 deletions(-) diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c index 21b6611..8a0e64c 100644 --- a/drivers/net/wireless/ath/wil6210/debugfs.c +++ b/drivers/net/wireless/ath/wil6210/debugfs.c @@ -244,12 +244,19 @@ static void wil_print_ring(struct seq_file *s, const char *prefix, static int wil_mbox_debugfs_show(struct seq_file *s, void *data) { struct wil6210_priv *wil = s->private; + int ret; + + ret = wil_pm_runtime_get(wil); + if (ret < 0) + return ret; wil_print_ring(s, "tx", wil->csr + HOST_MBOX + offsetof(struct wil6210_mbox_ctl, tx)); wil_print_ring(s, "rx", wil->csr + HOST_MBOX + offsetof(struct wil6210_mbox_ctl, rx)); + wil_pm_runtime_put(wil); + return 0; } @@ -267,15 +274,37 @@ static int wil_mbox_seq_open(struct inode *inode, struct file *file) static int wil_debugfs_iomem_x32_set(void *data, u64 val) { - writel(val, (void __iomem *)data); + struct wil_debugfs_iomem_data *d = (struct + wil_debugfs_iomem_data *)data; + struct wil6210_priv *wil = d->wil; + int ret; + + ret = wil_pm_runtime_get(wil); + if (ret < 0) + return ret; + + writel(val, (void __iomem *)d->offset); wmb(); /* make sure write propagated to HW */ + wil_pm_runtime_put(wil); + return 0; } static int wil_debugfs_iomem_x32_get(void *data, u64 *val) { - *val = readl((void __iomem *)data); + struct wil_debugfs_iomem_data *d = (struct + wil_debugfs_iomem_data *)data; + struct wil6210_priv *wil = d->wil; + int ret; + + ret = wil_pm_runtime_get(wil); + if (ret < 0) + return ret; + + *val = readl((void __iomem *)d->offset); + + wil_pm_runtime_put(wil); return 0; } @@ -286,10 +315,21 @@ static int wil_debugfs_iomem_x32_get(void *data, u64 *val) static struct dentry *wil_debugfs_create_iomem_x32(const char *name, umode_t mode, struct dentry *parent, - void *value) + void *value, + struct wil6210_priv *wil) { - return debugfs_create_file(name, mode, parent, value, - &fops_iomem_x32); + struct dentry *file; + struct wil_debugfs_iomem_data *data = &wil->dbg_data.data_arr[ + wil->dbg_data.iomem_data_count]; + + data->wil = wil; + data->offset = value; + + file = debugfs_create_file(name, mode, parent, data, &fops_iomem_x32); + if (!IS_ERR_OR_NULL(file)) + wil->dbg_data.iomem_data_count++; + + return file; } static int wil_debugfs_ulong_set(void *data, u64 val) @@ -348,7 +388,8 @@ static void wil6210_debugfs_init_offset(struct wil6210_priv *wil, case doff_io32: f = wil_debugfs_create_iomem_x32(tbl[i].name, tbl[i].mode, dbg, - base + tbl[i].off); + base + tbl[i].off, + wil); break; case doff_u8: f = debugfs_create_u8(tbl[i].name, tbl[i].mode, dbg, @@ -504,10 +545,12 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, { enum { max_count = 4096 }; struct wil_blob_wrapper *wil_blob = file->private_data; + struct wil6210_priv *wil = wil_blob->wil; loff_t pos = *ppos; size_t available = wil_blob->blob.size; void *buf; size_t ret; + int rc; if (test_bit(wil_status_suspending, wil_blob->wil->status) || test_bit(wil_status_suspended, wil_blob->wil->status)) @@ -528,10 +571,19 @@ static ssize_t wil_read_file_ioblob(struct file *file, char __user *user_buf, if (!buf) return -ENOMEM; + rc = wil_pm_runtime_get(wil); + if (rc < 0) { + kfree(buf); + return rc; + } + wil_memcpy_fromio_32(buf, (const void __iomem *) wil_blob->blob.data + pos, count); ret = copy_to_user(user_buf, buf, count); + + wil_pm_runtime_put(wil); + kfree(buf); if (ret == count) return -EFAULT; @@ -1773,14 +1825,31 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil, {}, }; +static const int dbg_off_count = 4 * (ARRAY_SIZE(isr_off) - 1) + + ARRAY_SIZE(dbg_wil_regs) - 1 + + ARRAY_SIZE(pseudo_isr_off) - 1 + + ARRAY_SIZE(lgc_itr_cnt_off) - 1 + + ARRAY_SIZE(tx_itr_cnt_off) - 1 + + ARRAY_SIZE(rx_itr_cnt_off) - 1; + int wil6210_debugfs_init(struct wil6210_priv *wil) { struct dentry *dbg = wil->debug = debugfs_create_dir(WIL_NAME, wil_to_wiphy(wil)->debugfsdir); - if (IS_ERR_OR_NULL(dbg)) return -ENODEV; + wil->dbg_data.data_arr = kcalloc(dbg_off_count, + sizeof(struct wil_debugfs_iomem_data), + GFP_KERNEL); + if (!wil->dbg_data.data_arr) { + debugfs_remove_recursive(dbg); + wil->debug = NULL; + return -ENOMEM; + } + + wil->dbg_data.iomem_data_count = 0; + wil_pmc_init(wil); wil6210_debugfs_init_files(wil, dbg); @@ -1803,6 +1872,8 @@ void wil6210_debugfs_remove(struct wil6210_priv *wil) debugfs_remove_recursive(wil->debug); wil->debug = NULL; + kfree(wil->dbg_data.data_arr); + /* free pmc memory without sending command to fw, as it will * be reset on the way down anyway */ diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c index adcfef4..66200f6 100644 --- a/drivers/net/wireless/ath/wil6210/ethtool.c +++ b/drivers/net/wireless/ath/wil6210/ethtool.c @@ -47,9 +47,14 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev, struct wil6210_priv *wil = ndev_to_wil(ndev); u32 tx_itr_en, tx_itr_val = 0; u32 rx_itr_en, rx_itr_val = 0; + int ret; wil_dbg_misc(wil, "ethtoolops_get_coalesce\n"); + ret = wil_pm_runtime_get(wil); + if (ret < 0) + return ret; + tx_itr_en = wil_r(wil, RGF_DMA_ITR_TX_CNT_CTL); if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN) tx_itr_val = wil_r(wil, RGF_DMA_ITR_TX_CNT_TRSH); @@ -58,6 +63,8 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev, if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN) rx_itr_val = wil_r(wil, RGF_DMA_ITR_RX_CNT_TRSH); + wil_pm_runtime_put(wil); + cp->tx_coalesce_usecs = tx_itr_val; cp->rx_coalesce_usecs = rx_itr_val; return 0; @@ -67,6 +74,7 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev, struct ethtool_coalesce *cp) { struct wil6210_priv *wil = ndev_to_wil(ndev); + int ret; wil_dbg_misc(wil, "ethtoolops_set_coalesce: rx %d usec, tx %d usec\n", cp->rx_coalesce_usecs, cp->tx_coalesce_usecs); @@ -86,8 +94,15 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev, wil->tx_max_burst_duration = cp->tx_coalesce_usecs; wil->rx_max_burst_duration = cp->rx_coalesce_usecs; + + ret = wil_pm_runtime_get(wil); + if (ret < 0) + return ret; + wil_configure_interrupt_moderation(wil); + wil_pm_runtime_put(wil); + return 0; out_bad: diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c index 4a6ab2d..b641ac1 100644 --- a/drivers/net/wireless/ath/wil6210/netdev.c +++ b/drivers/net/wireless/ath/wil6210/netdev.c @@ -21,6 +21,7 @@ static int wil_open(struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); + int rc; wil_dbg_misc(wil, "open\n"); @@ -30,16 +31,29 @@ static int wil_open(struct net_device *ndev) return -EINVAL; } - return wil_up(wil); + rc = wil_pm_runtime_get(wil); + if (rc < 0) + return rc; + + rc = wil_up(wil); + if (rc) + wil_pm_runtime_put(wil); + + return rc; } static int wil_stop(struct net_device *ndev) { struct wil6210_priv *wil = ndev_to_wil(ndev); + int rc; wil_dbg_misc(wil, "stop\n"); - return wil_down(wil); + rc = wil_down(wil); + if (!rc) + wil_pm_runtime_put(wil); + + return rc; } static const struct net_device_ops wil_netdev_ops = { diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c index 6a3ab4b..560a737 100644 --- a/drivers/net/wireless/ath/wil6210/pcie_bus.c +++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c @@ -21,6 +21,7 @@ #include #include "wil6210.h" #include +#include static bool use_msi = true; module_param(use_msi, bool, 0444); @@ -334,6 +335,8 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) wil6210_debugfs_init(wil); + wil_pm_runtime_allow(wil); + return 0; bus_disable: @@ -365,6 +368,8 @@ static void wil_pcie_remove(struct pci_dev *pdev) #endif /* CONFIG_PM_SLEEP */ #endif /* CONFIG_PM */ + wil_pm_runtime_forbid(wil); + wil6210_debugfs_remove(wil); rtnl_lock(); wil_p2p_wdev_free(wil); @@ -492,10 +497,40 @@ static int wil6210_pm_resume(struct device *dev) } #endif /* CONFIG_PM_SLEEP */ +static int wil6210_pm_runtime_idle(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct wil6210_priv *wil = pci_get_drvdata(pdev); + + wil_dbg_pm(wil, "Runtime idle\n"); + + return wil_can_suspend(wil, true); +} + +static int wil6210_pm_runtime_resume(struct device *dev) +{ + return wil6210_resume(dev, true); +} + +static int wil6210_pm_runtime_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct wil6210_priv *wil = pci_get_drvdata(pdev); + + if (test_bit(wil_status_suspended, wil->status)) { + wil_dbg_pm(wil, "trying to suspend while suspended\n"); + return 1; + } + + return wil6210_suspend(dev, true); +} #endif /* CONFIG_PM */ static const struct dev_pm_ops wil6210_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(wil6210_pm_suspend, wil6210_pm_resume) + SET_RUNTIME_PM_OPS(wil6210_pm_runtime_suspend, + wil6210_pm_runtime_resume, + wil6210_pm_runtime_idle) }; static struct pci_driver wil6210_driver = { diff --git a/drivers/net/wireless/ath/wil6210/pm.c b/drivers/net/wireless/ath/wil6210/pm.c index 4548829..976c9aa 100644 --- a/drivers/net/wireless/ath/wil6210/pm.c +++ b/drivers/net/wireless/ath/wil6210/pm.c @@ -16,14 +16,25 @@ #include "wil6210.h" #include +#include + +#define WIL6210_AUTOSUSPEND_DELAY_MS (1000) int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) { int rc = 0; struct wireless_dev *wdev = wil->wdev; + bool wmi_only = test_bit(WMI_FW_CAPABILITY_WMI_ONLY, + wil->fw_capabilities); wil_dbg_pm(wil, "can_suspend: %s\n", is_runtime ? "runtime" : "system"); + if (wmi_only || debug_fw) { + wil_dbg_pm(wil, "Deny any suspend - %s mode\n", + wmi_only ? "wmi_only" : "debug_fw"); + rc = -EPERM; + goto out; + } if (!netif_running(wil_to_ndev(wil))) { /* can always sleep when down */ wil_dbg_pm(wil, "Interface is down\n"); @@ -43,6 +54,10 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) /* interface is running */ switch (wdev->iftype) { case NL80211_IFTYPE_MONITOR: + wil_dbg_pm(wil, "Sniffer\n"); + rc = -EBUSY; + goto out; + /* for STA-like interface, don't runtime suspend */ case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_P2P_CLIENT: if (test_bit(wil_status_fwconnecting, wil->status)) { @@ -50,6 +65,12 @@ int wil_can_suspend(struct wil6210_priv *wil, bool is_runtime) rc = -EBUSY; goto out; } + /* Runtime pm not supported in case the interface is up */ + if (is_runtime) { + wil_dbg_pm(wil, "STA-like interface\n"); + rc = -EBUSY; + goto out; + } break; /* AP-like interface - can't suspend */ default: @@ -331,3 +352,44 @@ int wil_resume(struct wil6210_priv *wil, bool is_runtime) is_runtime ? "runtime" : "system", rc); return rc; } + +void wil_pm_runtime_allow(struct wil6210_priv *wil) +{ + struct device *dev = wil_to_dev(wil); + + pm_runtime_put_noidle(dev); + pm_runtime_set_autosuspend_delay(dev, WIL6210_AUTOSUSPEND_DELAY_MS); + pm_runtime_use_autosuspend(dev); + pm_runtime_allow(dev); +} + +void wil_pm_runtime_forbid(struct wil6210_priv *wil) +{ + struct device *dev = wil_to_dev(wil); + + pm_runtime_forbid(dev); + pm_runtime_get_noresume(dev); +} + +int wil_pm_runtime_get(struct wil6210_priv *wil) +{ + int rc; + struct device *dev = wil_to_dev(wil); + + rc = pm_runtime_get_sync(dev); + if (rc < 0) { + wil_err(wil, "pm_runtime_get_sync() failed, rc = %d\n", rc); + pm_runtime_put_noidle(dev); + return rc; + } + + return 0; +} + +void wil_pm_runtime_put(struct wil6210_priv *wil) +{ + struct device *dev = wil_to_dev(wil); + + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); +} diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h index ac32284..69103b0 100644 --- a/drivers/net/wireless/ath/wil6210/wil6210.h +++ b/drivers/net/wireless/ath/wil6210/wil6210.h @@ -607,6 +607,16 @@ struct blink_on_off_time { u32 off_ms; }; +struct wil_debugfs_iomem_data { + void *offset; + struct wil6210_priv *wil; +}; + +struct wil_debugfs_data { + struct wil_debugfs_iomem_data *data_arr; + int iomem_data_count; +}; + extern struct blink_on_off_time led_blink_time[WIL_LED_TIME_LAST]; extern u8 led_id; extern u8 led_polarity; @@ -698,6 +708,7 @@ struct wil6210_priv { u8 abft_len; u8 wakeup_trigger; struct wil_suspend_stats suspend_stats; + struct wil_debugfs_data dbg_data; void *platform_handle; struct wil_platform_ops platform_ops; @@ -981,6 +992,11 @@ int wil_request_firmware(struct wil6210_priv *wil, const char *name, bool load); bool wil_fw_verify_file_exists(struct wil6210_priv *wil, const char *name); +void wil_pm_runtime_allow(struct wil6210_priv *wil); +void wil_pm_runtime_forbid(struct wil6210_priv *wil); +int wil_pm_runtime_get(struct wil6210_priv *wil); +void wil_pm_runtime_put(struct wil6210_priv *wil); + 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);