Merge "icnss: Add support of suspend_noirq/resume_noirq"

This commit is contained in:
Linux Build Service Account 2016-09-12 14:42:29 -07:00 committed by Gerrit - the friendly Code Review server
commit b7bf6d2b63
2 changed files with 160 additions and 0 deletions

View file

@ -49,6 +49,7 @@
#define MAX_PROP_SIZE 32
#define NUM_LOG_PAGES 10
#define NUM_REG_LOG_PAGES 4
#define ICNSS_MAGIC 0x5abc5abc
/*
* Registers: MPM2_PSHOLD
@ -269,6 +270,8 @@ enum icnss_driver_state {
ICNSS_DRIVER_PROBED,
ICNSS_FW_TEST_MODE,
ICNSS_SUSPEND,
ICNSS_PM_SUSPEND,
ICNSS_PM_SUSPEND_NOIRQ,
ICNSS_SSR_ENABLED,
ICNSS_PDR_ENABLED,
ICNSS_PD_RESTART,
@ -324,6 +327,15 @@ struct icnss_stats {
uint32_t disable;
} ce_irqs[ICNSS_MAX_IRQ_REGISTRATIONS];
uint32_t pm_suspend;
uint32_t pm_suspend_err;
uint32_t pm_resume;
uint32_t pm_resume_err;
uint32_t pm_suspend_noirq;
uint32_t pm_suspend_noirq_err;
uint32_t pm_resume_noirq;
uint32_t pm_resume_noirq_err;
uint32_t ind_register_req;
uint32_t ind_register_resp;
uint32_t ind_register_err;
@ -350,6 +362,7 @@ struct icnss_stats {
};
static struct icnss_priv {
uint32_t magic;
struct platform_device *pdev;
struct icnss_driver_ops *ops;
struct ce_irq_list ce_irq_list[ICNSS_MAX_IRQ_REGISTRATIONS];
@ -3302,6 +3315,12 @@ static int icnss_stats_show_state(struct seq_file *s, struct icnss_priv *priv)
case ICNSS_FW_TEST_MODE:
seq_puts(s, "FW TEST MODE");
continue;
case ICNSS_PM_SUSPEND:
seq_puts(s, "PM SUSPEND");
continue;
case ICNSS_PM_SUSPEND_NOIRQ:
seq_puts(s, "PM SUSPEND_NOIRQ");
continue;
case ICNSS_SSR_ENABLED:
seq_puts(s, "SSR ENABLED");
continue;
@ -3402,6 +3421,16 @@ static int icnss_stats_show(struct seq_file *s, void *data)
ICNSS_STATS_DUMP(s, priv, ini_resp);
ICNSS_STATS_DUMP(s, priv, ini_req_err);
seq_puts(s, "\n<------------------ PM stats ------------------->\n");
ICNSS_STATS_DUMP(s, priv, pm_suspend);
ICNSS_STATS_DUMP(s, priv, pm_suspend_err);
ICNSS_STATS_DUMP(s, priv, pm_resume);
ICNSS_STATS_DUMP(s, priv, pm_resume_err);
ICNSS_STATS_DUMP(s, priv, pm_suspend_noirq);
ICNSS_STATS_DUMP(s, priv, pm_suspend_noirq_err);
ICNSS_STATS_DUMP(s, priv, pm_resume_noirq);
ICNSS_STATS_DUMP(s, priv, pm_resume_noirq_err);
icnss_stats_show_irqs(s, priv);
icnss_stats_show_capability(s, priv);
@ -3477,6 +3506,7 @@ static int icnss_probe(struct platform_device *pdev)
if (!priv)
return -ENOMEM;
priv->magic = ICNSS_MAGIC;
dev_set_drvdata(dev, priv);
priv->pdev = pdev;
@ -3725,6 +3755,131 @@ out:
return ret;
}
#ifdef CONFIG_PM_SLEEP
static int icnss_pm_suspend(struct device *dev)
{
struct icnss_priv *priv = dev_get_drvdata(dev);
int ret = 0;
if (priv->magic != ICNSS_MAGIC) {
icnss_pr_err("Invalid drvdata for pm suspend: dev %p, data %p, magic 0x%x\n",
dev, priv, priv->magic);
return -EINVAL;
}
icnss_pr_dbg("PM Suspend, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->pm_suspend ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
goto out;
ret = priv->ops->pm_suspend(dev);
out:
if (ret == 0) {
priv->stats.pm_suspend++;
set_bit(ICNSS_PM_SUSPEND, &priv->state);
} else {
priv->stats.pm_suspend_err++;
}
return ret;
}
static int icnss_pm_resume(struct device *dev)
{
struct icnss_priv *priv = dev_get_drvdata(dev);
int ret = 0;
if (priv->magic != ICNSS_MAGIC) {
icnss_pr_err("Invalid drvdata for pm resume: dev %p, data %p, magic 0x%x\n",
dev, priv, priv->magic);
return -EINVAL;
}
icnss_pr_dbg("PM resume, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->pm_resume ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
goto out;
ret = priv->ops->pm_resume(dev);
out:
if (ret == 0) {
priv->stats.pm_resume++;
clear_bit(ICNSS_PM_SUSPEND, &priv->state);
} else {
priv->stats.pm_resume_err++;
}
return ret;
}
static int icnss_pm_suspend_noirq(struct device *dev)
{
struct icnss_priv *priv = dev_get_drvdata(dev);
int ret = 0;
if (priv->magic != ICNSS_MAGIC) {
icnss_pr_err("Invalid drvdata for pm suspend_noirq: dev %p, data %p, magic 0x%x\n",
dev, priv, priv->magic);
return -EINVAL;
}
icnss_pr_dbg("PM suspend_noirq, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->suspend_noirq ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
goto out;
ret = priv->ops->suspend_noirq(dev);
out:
if (ret == 0) {
priv->stats.pm_suspend_noirq++;
set_bit(ICNSS_PM_SUSPEND_NOIRQ, &priv->state);
} else {
priv->stats.pm_suspend_noirq_err++;
}
return ret;
}
static int icnss_pm_resume_noirq(struct device *dev)
{
struct icnss_priv *priv = dev_get_drvdata(dev);
int ret = 0;
if (priv->magic != ICNSS_MAGIC) {
icnss_pr_err("Invalid drvdata for pm resume_noirq: dev %p, data %p, magic 0x%x\n",
dev, priv, priv->magic);
return -EINVAL;
}
icnss_pr_dbg("PM resume_noirq, state: 0x%lx\n", priv->state);
if (!priv->ops || !priv->ops->resume_noirq ||
!test_bit(ICNSS_DRIVER_PROBED, &priv->state))
goto out;
ret = priv->ops->resume_noirq(dev);
out:
if (ret == 0) {
priv->stats.pm_resume_noirq++;
clear_bit(ICNSS_PM_SUSPEND_NOIRQ, &priv->state);
} else {
priv->stats.pm_resume_noirq_err++;
}
return ret;
}
#endif
static const struct dev_pm_ops icnss_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(icnss_pm_suspend,
icnss_pm_resume)
SET_NOIRQ_SYSTEM_SLEEP_PM_OPS(icnss_pm_suspend_noirq,
icnss_pm_resume_noirq)
};
static const struct of_device_id icnss_dt_match[] = {
{.compatible = "qcom,icnss"},
{}
@ -3739,6 +3894,7 @@ static struct platform_driver icnss_driver = {
.resume = icnss_resume,
.driver = {
.name = "icnss",
.pm = &icnss_pm_ops,
.owner = THIS_MODULE,
.of_match_table = icnss_dt_match,
},

View file

@ -26,6 +26,10 @@ struct icnss_driver_ops {
void (*crash_shutdown)(void *pdev);
int (*suspend)(struct device *dev, pm_message_t state);
int (*resume)(struct device *dev);
int (*pm_suspend)(struct device *dev);
int (*pm_resume)(struct device *dev);
int (*suspend_noirq)(struct device *dev);
int (*resume_noirq)(struct device *dev);
};