qcacld-3.0: Add runtime pm initialization
Add runtime pm initialization, including the creation of a debugfs entry. Change-Id: Ib057feaf36a04bb525a731e236187c134449c5f2 CRs-Fixed: 935300
This commit is contained in:

committed by
Akash Patel

parent
5be9bac028
commit
8eb73ed3ad
@@ -247,6 +247,7 @@ static int wlan_hdd_probe(struct device *dev, void *bdev, const hif_bus_id *bid,
|
||||
if (ret)
|
||||
goto err_hif_close;
|
||||
|
||||
hif_enable_power_management(hif_ctx);
|
||||
|
||||
if (reinit) {
|
||||
cds_set_recovery_in_progress(false);
|
||||
|
@@ -642,6 +642,7 @@ CDF_STATUS hif_enable(void *hif_ctx, struct device *dev, void *bdev,
|
||||
enum hif_enable_type type);
|
||||
void hif_disable(void *hif_ctx, enum hif_disable_type type);
|
||||
void hif_enable_power_gating(void *hif_ctx);
|
||||
void hif_enable_power_management(void *hif_ctx);
|
||||
int hif_bus_resume(void);
|
||||
int hif_bus_suspend(void);
|
||||
void hif_vote_link_down(void);
|
||||
|
@@ -43,6 +43,8 @@
|
||||
#include "bmi_msg.h" /* TARGET_TYPE_ */
|
||||
#include "regtable.h"
|
||||
#include "ol_fw.h"
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <osapi_linux.h>
|
||||
#include "cds_api.h"
|
||||
#include "cdf_status.h"
|
||||
@@ -804,6 +806,326 @@ end:
|
||||
cdf_atomic_dec(&scn->active_tasklet_cnt);
|
||||
}
|
||||
|
||||
#ifdef FEATURE_RUNTIME_PM
|
||||
#define HIF_PCI_RUNTIME_PM_STATS(_s, _sc, _name) \
|
||||
seq_printf(_s, "%30s: %u\n", #_name, _sc->pm_stats._name)
|
||||
|
||||
/**
|
||||
* hif_pci_runtime_pm_warn() - Runtime PM Debugging API
|
||||
* @sc: hif_pci_softc context
|
||||
* @msg: log message
|
||||
*
|
||||
* log runtime pm stats when something seems off.
|
||||
*
|
||||
* Return: void
|
||||
*/
|
||||
void hif_pci_runtime_pm_warn(struct hif_pci_softc *sc, const char *msg)
|
||||
{
|
||||
struct hif_pm_runtime_lock *ctx;
|
||||
|
||||
HIF_ERROR("%s: usage_count: %d, pm_state: %d, prevent_suspend_cnt: %d",
|
||||
msg, atomic_read(&sc->dev->power.usage_count),
|
||||
atomic_read(&sc->pm_state),
|
||||
sc->prevent_suspend_cnt);
|
||||
|
||||
HIF_ERROR("runtime_status: %d, runtime_error: %d, disable_depth: %d autosuspend_delay: %d",
|
||||
sc->dev->power.runtime_status,
|
||||
sc->dev->power.runtime_error,
|
||||
sc->dev->power.disable_depth,
|
||||
sc->dev->power.autosuspend_delay);
|
||||
|
||||
HIF_ERROR("runtime_get: %u, runtime_put: %u, request_resume: %u",
|
||||
sc->pm_stats.runtime_get, sc->pm_stats.runtime_put,
|
||||
sc->pm_stats.request_resume);
|
||||
|
||||
HIF_ERROR("allow_suspend: %u, prevent_suspend: %u",
|
||||
sc->pm_stats.allow_suspend,
|
||||
sc->pm_stats.prevent_suspend);
|
||||
|
||||
HIF_ERROR("prevent_suspend_timeout: %u, allow_suspend_timeout: %u",
|
||||
sc->pm_stats.prevent_suspend_timeout,
|
||||
sc->pm_stats.allow_suspend_timeout);
|
||||
|
||||
HIF_ERROR("Suspended: %u, resumed: %u count",
|
||||
sc->pm_stats.suspended,
|
||||
sc->pm_stats.resumed);
|
||||
|
||||
HIF_ERROR("suspend_err: %u, runtime_get_err: %u",
|
||||
sc->pm_stats.suspend_err,
|
||||
sc->pm_stats.runtime_get_err);
|
||||
|
||||
HIF_ERROR("Active Wakeup Sources preventing Runtime Suspend: ");
|
||||
|
||||
list_for_each_entry(ctx, &sc->prevent_suspend_list, list) {
|
||||
HIF_ERROR("source %s; timeout %d ms", ctx->name, ctx->timeout);
|
||||
}
|
||||
|
||||
WARN_ON(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* hif_pci_pm_runtime_debugfs_show(): show debug stats for runtimepm
|
||||
* @s: file to print to
|
||||
* @data: unused
|
||||
*
|
||||
* debugging tool added to the debug fs for displaying runtimepm stats
|
||||
*
|
||||
* Return: 0
|
||||
*/
|
||||
static int hif_pci_pm_runtime_debugfs_show(struct seq_file *s, void *data)
|
||||
{
|
||||
struct hif_pci_softc *sc = s->private;
|
||||
static const char * const autopm_state[] = {"NONE", "ON", "INPROGRESS",
|
||||
"SUSPENDED"};
|
||||
unsigned int msecs_age;
|
||||
int pm_state = atomic_read(&sc->pm_state);
|
||||
unsigned long timer_expires, flags;
|
||||
struct hif_pm_runtime_lock *ctx;
|
||||
|
||||
seq_printf(s, "%30s: %s\n", "Runtime PM state",
|
||||
autopm_state[pm_state]);
|
||||
seq_printf(s, "%30s: %pf\n", "Last Resume Caller",
|
||||
sc->pm_stats.last_resume_caller);
|
||||
|
||||
if (pm_state == HIF_PM_RUNTIME_STATE_SUSPENDED) {
|
||||
msecs_age = jiffies_to_msecs(
|
||||
jiffies - sc->pm_stats.suspend_jiffies);
|
||||
seq_printf(s, "%30s: %d.%03ds\n", "Suspended Since",
|
||||
msecs_age / 1000, msecs_age % 1000);
|
||||
}
|
||||
|
||||
seq_printf(s, "%30s: %d\n", "PM Usage count",
|
||||
atomic_read(&sc->dev->power.usage_count));
|
||||
|
||||
seq_printf(s, "%30s: %u\n", "prevent_suspend_cnt",
|
||||
sc->prevent_suspend_cnt);
|
||||
|
||||
HIF_PCI_RUNTIME_PM_STATS(s, sc, suspended);
|
||||
HIF_PCI_RUNTIME_PM_STATS(s, sc, suspend_err);
|
||||
HIF_PCI_RUNTIME_PM_STATS(s, sc, resumed);
|
||||
HIF_PCI_RUNTIME_PM_STATS(s, sc, runtime_get);
|
||||
HIF_PCI_RUNTIME_PM_STATS(s, sc, runtime_put);
|
||||
HIF_PCI_RUNTIME_PM_STATS(s, sc, request_resume);
|
||||
HIF_PCI_RUNTIME_PM_STATS(s, sc, prevent_suspend);
|
||||
HIF_PCI_RUNTIME_PM_STATS(s, sc, allow_suspend);
|
||||
HIF_PCI_RUNTIME_PM_STATS(s, sc, prevent_suspend_timeout);
|
||||
HIF_PCI_RUNTIME_PM_STATS(s, sc, allow_suspend_timeout);
|
||||
HIF_PCI_RUNTIME_PM_STATS(s, sc, runtime_get_err);
|
||||
|
||||
timer_expires = sc->runtime_timer_expires;
|
||||
if (timer_expires > 0) {
|
||||
msecs_age = jiffies_to_msecs(timer_expires - jiffies);
|
||||
seq_printf(s, "%30s: %d.%03ds\n", "Prevent suspend timeout",
|
||||
msecs_age / 1000, msecs_age % 1000);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&sc->runtime_lock, flags);
|
||||
if (list_empty(&sc->prevent_suspend_list)) {
|
||||
spin_unlock_irqrestore(&sc->runtime_lock, flags);
|
||||
return 0;
|
||||
}
|
||||
|
||||
seq_printf(s, "%30s: ", "Active Wakeup_Sources");
|
||||
list_for_each_entry(ctx, &sc->prevent_suspend_list, list) {
|
||||
seq_printf(s, "%s", ctx->name);
|
||||
if (ctx->timeout)
|
||||
seq_printf(s, "(%d ms)", ctx->timeout);
|
||||
seq_puts(s, " ");
|
||||
}
|
||||
seq_puts(s, "\n");
|
||||
spin_unlock_irqrestore(&sc->runtime_lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#undef HIF_PCI_RUNTIME_PM_STATS
|
||||
|
||||
/**
|
||||
* hif_pci_autopm_open() - open a debug fs file to access the runtime pm stats
|
||||
* @inode
|
||||
* @file
|
||||
*
|
||||
* Return: linux error code of single_open.
|
||||
*/
|
||||
static int hif_pci_runtime_pm_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, hif_pci_pm_runtime_debugfs_show,
|
||||
inode->i_private);
|
||||
}
|
||||
|
||||
#ifdef WLAN_OPEN_SOURCE
|
||||
static const struct file_operations hif_pci_runtime_pm_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = hif_pci_runtime_pm_open,
|
||||
.release = single_release,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
};
|
||||
|
||||
/**
|
||||
* hif_runtime_pm_debugfs_create() - creates runtimepm debugfs entry
|
||||
* @sc: pci context
|
||||
*
|
||||
* creates a debugfs entry to debug the runtime pm feature.
|
||||
*/
|
||||
static void hif_runtime_pm_debugfs_create(struct hif_pci_softc *sc)
|
||||
{
|
||||
sc->pm_dentry = debugfs_create_file("cnss_runtime_pm",
|
||||
S_IRUSR, NULL, sc,
|
||||
&hif_pci_runtime_pm_fops);
|
||||
}
|
||||
/**
|
||||
* hif_runtime_pm_debugfs_remove() - removes runtimepm debugfs entry
|
||||
* @sc: pci context
|
||||
*
|
||||
* removes the debugfs entry to debug the runtime pm feature.
|
||||
*/
|
||||
static void hif_runtime_pm_debugfs_remove(struct hif_pci_softc *sc)
|
||||
{
|
||||
debugfs_remove(sc->pm_dentry);
|
||||
}
|
||||
#else
|
||||
static inline void hif_runtime_pm_debugfs_create(struct hif_pci_softc *sc)
|
||||
{
|
||||
}
|
||||
static inline void hif_runtime_pm_debugfs_remove(struct hif_pci_softc *sc)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hif_pm_runtime_lock_timeout_fn() - callback the runtime lock timeout
|
||||
* @data: calback data that is the pci context
|
||||
*
|
||||
* if runtime locks are aquired with a timeout, this function releases
|
||||
* the locks when the latest runtime lock expires.
|
||||
*
|
||||
* dummy implementation until lock acquisition is implemented.
|
||||
*/
|
||||
void hif_pm_runtime_lock_timeout_fn(unsigned long data) {}
|
||||
|
||||
/**
|
||||
* hif_pm_runtime_start(): start the runtime pm
|
||||
* @sc: pci context
|
||||
*
|
||||
* After this call, runtime pm will be active.
|
||||
*/
|
||||
static void hif_pm_runtime_start(struct hif_pci_softc *sc)
|
||||
{
|
||||
struct ol_softc *ol_sc;
|
||||
|
||||
ol_sc = sc->ol_sc;
|
||||
|
||||
if (!ol_sc->enable_runtime_pm) {
|
||||
HIF_INFO("%s: RUNTIME PM is disabled in ini\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (cds_get_conparam() == CDF_FTM_MODE ||
|
||||
WLAN_IS_EPPING_ENABLED(cds_get_conparam())) {
|
||||
HIF_INFO("%s: RUNTIME PM is disabled for FTM/EPPING mode\n",
|
||||
__func__);
|
||||
return;
|
||||
}
|
||||
|
||||
setup_timer(&sc->runtime_timer, hif_pm_runtime_lock_timeout_fn,
|
||||
(unsigned long)sc);
|
||||
|
||||
HIF_INFO("%s: Enabling RUNTIME PM, Delay: %d ms", __func__,
|
||||
ol_sc->runtime_pm_delay);
|
||||
|
||||
cnss_runtime_init(sc->dev, ol_sc->runtime_pm_delay);
|
||||
cdf_atomic_set(&sc->pm_state, HIF_PM_RUNTIME_STATE_ON);
|
||||
hif_runtime_pm_debugfs_create(sc);
|
||||
}
|
||||
|
||||
/**
|
||||
* hif_pm_runtime_stop(): stop runtime pm
|
||||
* @sc: pci context
|
||||
*
|
||||
* Turns off runtime pm and frees corresponding resources
|
||||
* that were acquired by hif_runtime_pm_start().
|
||||
*/
|
||||
static void hif_pm_runtime_stop(struct hif_pci_softc *sc)
|
||||
{
|
||||
struct ol_softc *ol_sc = sc->ol_sc;
|
||||
|
||||
if (!ol_sc->enable_runtime_pm)
|
||||
return;
|
||||
|
||||
if (cds_get_conparam() == CDF_FTM_MODE ||
|
||||
WLAN_IS_EPPING_ENABLED(cds_get_conparam()))
|
||||
return;
|
||||
|
||||
cnss_runtime_exit(sc->dev);
|
||||
cnss_pm_runtime_request(sc->dev, CNSS_PM_RUNTIME_RESUME);
|
||||
|
||||
cdf_atomic_set(&sc->pm_state, HIF_PM_RUNTIME_STATE_NONE);
|
||||
|
||||
hif_runtime_pm_debugfs_remove(sc);
|
||||
del_timer_sync(&sc->runtime_timer);
|
||||
/* doesn't wait for penting trafic unlike cld-2.0 */
|
||||
}
|
||||
|
||||
/**
|
||||
* hif_pm_runtime_open(): initialize runtime pm
|
||||
* @sc: pci data structure
|
||||
*
|
||||
* Early initialization
|
||||
*/
|
||||
static void hif_pm_runtime_open(struct hif_pci_softc *sc)
|
||||
{
|
||||
spin_lock_init(&sc->runtime_lock);
|
||||
|
||||
cdf_atomic_init(&sc->pm_state);
|
||||
cdf_atomic_set(&sc->pm_state, HIF_PM_RUNTIME_STATE_NONE);
|
||||
INIT_LIST_HEAD(&sc->prevent_suspend_list);
|
||||
}
|
||||
|
||||
/**
|
||||
* hif_pm_runtime_close(): close runtime pm
|
||||
* @sc: pci bus handle
|
||||
*
|
||||
* ensure runtime_pm is stopped before closing the driver
|
||||
*/
|
||||
static void hif_pm_runtime_close(struct hif_pci_softc *sc)
|
||||
{
|
||||
if (cdf_atomic_read(&sc->pm_state) == HIF_PM_RUNTIME_STATE_NONE)
|
||||
return;
|
||||
else
|
||||
hif_pm_runtime_stop(sc);
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
static void hif_pm_runtime_close(struct hif_pci_softc *sc) {}
|
||||
static void hif_pm_runtime_open(struct hif_pci_softc *sc) {}
|
||||
static void hif_pm_runtime_start(struct hif_pci_softc *sc) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* hif_enable_power_management(): enable power management
|
||||
* @hif_ctx: hif context
|
||||
*
|
||||
* Currently only does runtime pm. Eventually this function could
|
||||
* consolidate other power state features such as only letting
|
||||
* the soc sleep after the driver finishes loading and re-enabling
|
||||
* aspm (hif_enable_power_gating).
|
||||
*/
|
||||
void hif_enable_power_management(void *hif_ctx)
|
||||
{
|
||||
struct hif_pci_softc *pci_ctx;
|
||||
|
||||
if (hif_ctx == NULL) {
|
||||
HIF_ERROR("%s, hif_ctx null", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
pci_ctx = ((struct ol_softc *)hif_ctx)->hif_sc;
|
||||
|
||||
hif_pm_runtime_start(pci_ctx);
|
||||
}
|
||||
|
||||
#define ATH_PCI_PROBE_RETRY_MAX 3
|
||||
/**
|
||||
* hif_bus_open(): hif_bus_open
|
||||
@@ -824,6 +1146,7 @@ CDF_STATUS hif_bus_open(struct ol_softc *ol_sc, enum ath_hal_bus_type bus_type)
|
||||
ol_sc->hif_sc = (void *)sc;
|
||||
sc->ol_sc = ol_sc;
|
||||
ol_sc->bus_type = bus_type;
|
||||
hif_pm_runtime_open(sc);
|
||||
|
||||
cdf_spinlock_init(&ol_sc->irq_lock);
|
||||
|
||||
@@ -846,6 +1169,8 @@ void hif_bus_close(struct ol_softc *ol_sc)
|
||||
sc = ol_sc->hif_sc;
|
||||
if (sc == NULL)
|
||||
return;
|
||||
|
||||
hif_pm_runtime_close(sc);
|
||||
cdf_mem_free(sc);
|
||||
ol_sc->hif_sc = NULL;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2015 The Linux Foundation. All rights reserved.
|
||||
* Copyright (c) 2013-2016 The Linux Foundation. All rights reserved.
|
||||
*
|
||||
* Previously licensed under the ISC license by Qualcomm Atheros, Inc.
|
||||
*
|
||||
@@ -50,6 +50,54 @@ struct hif_tasklet_entry {
|
||||
uint8_t id; /* 0 - 9: maps to CE, 10: fw */
|
||||
void *hif_handler; /* struct hif_pci_softc */
|
||||
};
|
||||
|
||||
/**
|
||||
* enum hif_pm_runtime_state - Driver States for Runtime Power Management
|
||||
* HIF_PM_RUNTIME_STATE_NONE: runtime pm is off
|
||||
* HIF_PM_RUNTIME_STATE_ON: runtime pm is active and link is active
|
||||
* HIF_PM_RUNTIME_STATE_INPROGRESS: a runtime suspend or resume is in progress
|
||||
* HIF_PM_RUNTIME_STATE_SUSPENDED: the driver is runtime suspended
|
||||
*/
|
||||
enum hif_pm_runtime_state {
|
||||
HIF_PM_RUNTIME_STATE_NONE,
|
||||
HIF_PM_RUNTIME_STATE_ON,
|
||||
HIF_PM_RUNTIME_STATE_INPROGRESS,
|
||||
HIF_PM_RUNTIME_STATE_SUSPENDED,
|
||||
};
|
||||
|
||||
#ifdef FEATURE_RUNTIME_PM
|
||||
|
||||
/**
|
||||
* struct hif_pm_runtime_lock - data structure for preventing runtime suspend
|
||||
* @list - global list of runtime locks
|
||||
* @active - true if this lock is preventing suspend
|
||||
* @name - character string for tracking this lock
|
||||
*/
|
||||
struct hif_pm_runtime_lock {
|
||||
struct list_head list;
|
||||
bool active;
|
||||
uint32_t timeout;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
/* Debugging stats for Runtime PM */
|
||||
struct hif_pci_pm_stats {
|
||||
u32 suspended;
|
||||
u32 suspend_err;
|
||||
u32 resumed;
|
||||
u32 runtime_get;
|
||||
u32 runtime_put;
|
||||
u32 request_resume;
|
||||
u32 allow_suspend;
|
||||
u32 prevent_suspend;
|
||||
u32 prevent_suspend_timeout;
|
||||
u32 allow_suspend_timeout;
|
||||
u32 runtime_get_err;
|
||||
void *last_resume_caller;
|
||||
unsigned long suspend_jiffies;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct hif_pci_softc {
|
||||
void __iomem *mem; /* PCI address. */
|
||||
/* For efficiency, should be first in struct */
|
||||
@@ -69,6 +117,19 @@ struct hif_pci_softc {
|
||||
cdf_dma_addr_t soc_pcie_bar0;
|
||||
struct hif_tasklet_entry tasklet_entries[HIF_MAX_TASKLET_NUM];
|
||||
bool pci_enabled;
|
||||
#ifdef FEATURE_RUNTIME_PM
|
||||
atomic_t pm_state;
|
||||
uint32_t prevent_suspend_cnt;
|
||||
struct hif_pci_pm_stats pm_stats;
|
||||
struct work_struct pm_work;
|
||||
spinlock_t runtime_lock;
|
||||
struct timer_list runtime_timer;
|
||||
struct list_head prevent_suspend_list;
|
||||
unsigned long runtime_timer_expires;
|
||||
#ifdef WLAN_OPEN_SOURCE
|
||||
struct dentry *pm_dentry;
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
|
||||
bool hif_pci_targ_is_present(struct ol_softc *scn, void *__iomem *mem);
|
||||
|
Reference in New Issue
Block a user