diff options
| -rw-r--r-- | drivers/mmc/host/sdhci-msm.c | 180 | ||||
| -rw-r--r-- | drivers/mmc/host/sdhci-msm.h | 4 |
2 files changed, 184 insertions, 0 deletions
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c index 7b571bd0289d..cbfc473ca76f 100644 --- a/drivers/mmc/host/sdhci-msm.c +++ b/drivers/mmc/host/sdhci-msm.c @@ -3232,11 +3232,69 @@ void sdhci_msm_pm_qos_irq_unvote(struct sdhci_host *host, bool async) msm_host->pm_qos_irq.latency); } +static ssize_t +sdhci_msm_pm_qos_irq_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + struct sdhci_msm_pm_qos_irq *irq = &msm_host->pm_qos_irq; + + return snprintf(buf, PAGE_SIZE, + "IRQ PM QoS: enabled=%d, counter=%d, latency=%d\n", + irq->enabled, atomic_read(&irq->counter), irq->latency); +} + +static ssize_t +sdhci_msm_pm_qos_irq_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + + return snprintf(buf, PAGE_SIZE, "%u\n", msm_host->pm_qos_irq.enabled); +} + +static ssize_t +sdhci_msm_pm_qos_irq_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + uint32_t value; + bool enable; + int ret; + + ret = kstrtou32(buf, 0, &value); + if (ret) + goto out; + enable = !!value; + + if (enable == msm_host->pm_qos_irq.enabled) + goto out; + + msm_host->pm_qos_irq.enabled = enable; + if (!enable) { + cancel_work_sync(&msm_host->pm_qos_irq.unvote_work); + atomic_set(&msm_host->pm_qos_irq.counter, 0); + msm_host->pm_qos_irq.latency = PM_QOS_DEFAULT_VALUE; + pm_qos_update_request(&msm_host->pm_qos_irq.req, + msm_host->pm_qos_irq.latency); + } + +out: + return count; +} + void sdhci_msm_pm_qos_irq_init(struct sdhci_host *host) { struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); struct sdhci_msm_host *msm_host = pltfm_host->priv; struct sdhci_msm_pm_qos_latency *irq_latency; + int ret; if (!msm_host->pdata->pm_qos_data.irq_valid) return; @@ -3263,6 +3321,101 @@ void sdhci_msm_pm_qos_irq_init(struct sdhci_host *host) pm_qos_add_request(&msm_host->pm_qos_irq.req, PM_QOS_CPU_DMA_LATENCY, msm_host->pm_qos_irq.latency); msm_host->pm_qos_irq.enabled = true; + + /* sysfs */ + msm_host->pm_qos_irq.enable_attr.show = + sdhci_msm_pm_qos_irq_enable_show; + msm_host->pm_qos_irq.enable_attr.store = + sdhci_msm_pm_qos_irq_enable_store; + sysfs_attr_init(&msm_host->pm_qos_irq.enable_attr.attr); + msm_host->pm_qos_irq.enable_attr.attr.name = "pm_qos_irq_enable"; + msm_host->pm_qos_irq.enable_attr.attr.mode = S_IRUGO | S_IWUSR; + ret = device_create_file(&msm_host->pdev->dev, + &msm_host->pm_qos_irq.enable_attr); + if (ret) + pr_err("%s: fail to create pm_qos_irq_enable (%d)\n", + __func__, ret); + + msm_host->pm_qos_irq.status_attr.show = sdhci_msm_pm_qos_irq_show; + msm_host->pm_qos_irq.status_attr.store = NULL; + sysfs_attr_init(&msm_host->pm_qos_irq.status_attr.attr); + msm_host->pm_qos_irq.status_attr.attr.name = "pm_qos_irq_status"; + msm_host->pm_qos_irq.status_attr.attr.mode = S_IRUGO; + ret = device_create_file(&msm_host->pdev->dev, + &msm_host->pm_qos_irq.status_attr); + if (ret) + pr_err("%s: fail to create pm_qos_irq_status (%d)\n", + __func__, ret); +} + +static ssize_t sdhci_msm_pm_qos_group_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + struct sdhci_msm_pm_qos_group *group; + int i; + int nr_groups = msm_host->pdata->pm_qos_data.cpu_group_map.nr_groups; + int offset = 0; + + for (i = 0; i < nr_groups; i++) { + group = &msm_host->pm_qos[i]; + offset += snprintf(&buf[offset], PAGE_SIZE, + "Group #%d (mask=0x%lx) PM QoS: enabled=%d, counter=%d, latency=%d\n", + i, group->req.cpus_affine.bits[0], + msm_host->pm_qos_group_enable, + atomic_read(&group->counter), + group->latency); + } + + return offset; +} + +static ssize_t sdhci_msm_pm_qos_group_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + + return snprintf(buf, PAGE_SIZE, "%s\n", + msm_host->pm_qos_group_enable ? "enabled" : "disabled"); +} + +static ssize_t sdhci_msm_pm_qos_group_enable_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct sdhci_host *host = dev_get_drvdata(dev); + struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host); + struct sdhci_msm_host *msm_host = pltfm_host->priv; + int nr_groups = msm_host->pdata->pm_qos_data.cpu_group_map.nr_groups; + uint32_t value; + bool enable; + int ret; + int i; + + ret = kstrtou32(buf, 0, &value); + if (ret) + goto out; + enable = !!value; + + if (enable == msm_host->pm_qos_group_enable) + goto out; + + msm_host->pm_qos_group_enable = enable; + if (!enable) { + for (i = 0; i < nr_groups; i++) { + cancel_work_sync(&msm_host->pm_qos[i].unvote_work); + atomic_set(&msm_host->pm_qos[i].counter, 0); + msm_host->pm_qos[i].latency = PM_QOS_DEFAULT_VALUE; + pm_qos_update_request(&msm_host->pm_qos[i].req, + msm_host->pm_qos[i].latency); + } + } + +out: + return count; } static int sdhci_msm_get_cpu_group(struct sdhci_msm_host *msm_host, int cpu) @@ -3349,6 +3502,7 @@ void sdhci_msm_pm_qos_cpu_init(struct sdhci_host *host, int nr_groups = msm_host->pdata->pm_qos_data.cpu_group_map.nr_groups; struct sdhci_msm_pm_qos_group *group; int i; + int ret; if (msm_host->pm_qos_group_enable) return; @@ -3378,6 +3532,32 @@ void sdhci_msm_pm_qos_cpu_init(struct sdhci_host *host, } msm_host->pm_qos_prev_cpu = -1; msm_host->pm_qos_group_enable = true; + + /* sysfs */ + msm_host->pm_qos_group_status_attr.show = sdhci_msm_pm_qos_group_show; + msm_host->pm_qos_group_status_attr.store = NULL; + sysfs_attr_init(&msm_host->pm_qos_group_status_attr.attr); + msm_host->pm_qos_group_status_attr.attr.name = + "pm_qos_cpu_groups_status"; + msm_host->pm_qos_group_status_attr.attr.mode = S_IRUGO; + ret = device_create_file(&msm_host->pdev->dev, + &msm_host->pm_qos_group_status_attr); + if (ret) + dev_err(&msm_host->pdev->dev, "%s: fail to create pm_qos_group_status_attr (%d)\n", + __func__, ret); + msm_host->pm_qos_group_enable_attr.show = + sdhci_msm_pm_qos_group_enable_show; + msm_host->pm_qos_group_enable_attr.store = + sdhci_msm_pm_qos_group_enable_store; + sysfs_attr_init(&msm_host->pm_qos_group_enable_attr.attr); + msm_host->pm_qos_group_enable_attr.attr.name = + "pm_qos_cpu_groups_enable"; + msm_host->pm_qos_group_enable_attr.attr.mode = S_IRUGO; + ret = device_create_file(&msm_host->pdev->dev, + &msm_host->pm_qos_group_enable_attr); + if (ret) + dev_err(&msm_host->pdev->dev, "%s: fail to create pm_qos_group_enable_attr (%d)\n", + __func__, ret); } static void sdhci_msm_pre_req(struct sdhci_host *host, diff --git a/drivers/mmc/host/sdhci-msm.h b/drivers/mmc/host/sdhci-msm.h index 01ad6d1593a2..0a90409a7409 100644 --- a/drivers/mmc/host/sdhci-msm.h +++ b/drivers/mmc/host/sdhci-msm.h @@ -120,6 +120,8 @@ struct sdhci_msm_pm_qos_group { struct sdhci_msm_pm_qos_irq { struct pm_qos_request req; struct work_struct unvote_work; + struct device_attribute enable_attr; + struct device_attribute status_attr; atomic_t counter; s32 latency; bool enabled; @@ -204,6 +206,8 @@ struct sdhci_msm_host { u32 ice_clk_rate; struct sdhci_msm_pm_qos_group *pm_qos; int pm_qos_prev_cpu; + struct device_attribute pm_qos_group_enable_attr; + struct device_attribute pm_qos_group_status_attr; bool pm_qos_group_enable; struct sdhci_msm_pm_qos_irq pm_qos_irq; }; |
