Merge branch 'linux-linaro-lsk-v4.4-android' of git://git.linaro.org/kernel/linux...
[firefly-linux-kernel-4.4.55.git] / drivers / mmc / core / core.c
index d72977c999adee37c7b9c9fec2719a04cdfcc6d6..31fc5362f99ab358e79dde0d6be02f7102610e89 100644 (file)
@@ -176,6 +176,19 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
                        pr_debug("%s:     %d bytes transferred: %d\n",
                                mmc_hostname(host),
                                mrq->data->bytes_xfered, mrq->data->error);
+#ifdef CONFIG_BLOCK
+                       if (mrq->lat_hist_enabled) {
+                               ktime_t completion;
+                               u_int64_t delta_us;
+
+                               completion = ktime_get();
+                               delta_us = ktime_us_delta(completion,
+                                                         mrq->io_start);
+                               blk_update_latency_hist(&host->io_lat_s,
+                                       (mrq->data->flags & MMC_DATA_READ),
+                                       delta_us);
+                       }
+#endif
                        trace_mmc_blk_rw_end(cmd->opcode, cmd->arg, mrq->data);
                }
 
@@ -620,6 +633,13 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
        }
 
        if (!err && areq) {
+#ifdef CONFIG_BLOCK
+               if (host->latency_hist_enabled) {
+                       areq->mrq->io_start = ktime_get();
+                       areq->mrq->lat_hist_enabled = 1;
+               } else
+                       areq->mrq->lat_hist_enabled = 0;
+#endif
                trace_mmc_blk_rw_start(areq->mrq->cmd->opcode,
                                       areq->mrq->cmd->arg,
                                       areq->mrq->data);
@@ -1962,7 +1982,7 @@ void mmc_init_erase(struct mmc_card *card)
 }
 
 static unsigned int mmc_mmc_erase_timeout(struct mmc_card *card,
-                                         unsigned int arg, unsigned int qty)
+                                         unsigned int arg, unsigned int qty)
 {
        unsigned int erase_timeout;
 
@@ -2918,6 +2938,56 @@ static void __exit mmc_exit(void)
        mmc_unregister_bus();
 }
 
+#ifdef CONFIG_BLOCK
+static ssize_t
+latency_hist_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct mmc_host *host = cls_dev_to_mmc_host(dev);
+
+       return blk_latency_hist_show(&host->io_lat_s, buf);
+}
+
+/*
+ * Values permitted 0, 1, 2.
+ * 0 -> Disable IO latency histograms (default)
+ * 1 -> Enable IO latency histograms
+ * 2 -> Zero out IO latency histograms
+ */
+static ssize_t
+latency_hist_store(struct device *dev, struct device_attribute *attr,
+                  const char *buf, size_t count)
+{
+       struct mmc_host *host = cls_dev_to_mmc_host(dev);
+       long value;
+
+       if (kstrtol(buf, 0, &value))
+               return -EINVAL;
+       if (value == BLK_IO_LAT_HIST_ZERO)
+               blk_zero_latency_hist(&host->io_lat_s);
+       else if (value == BLK_IO_LAT_HIST_ENABLE ||
+                value == BLK_IO_LAT_HIST_DISABLE)
+               host->latency_hist_enabled = value;
+       return count;
+}
+
+static DEVICE_ATTR(latency_hist, S_IRUGO | S_IWUSR,
+                  latency_hist_show, latency_hist_store);
+
+void
+mmc_latency_hist_sysfs_init(struct mmc_host *host)
+{
+       if (device_create_file(&host->class_dev, &dev_attr_latency_hist))
+               dev_err(&host->class_dev,
+                       "Failed to create latency_hist sysfs entry\n");
+}
+
+void
+mmc_latency_hist_sysfs_exit(struct mmc_host *host)
+{
+       device_remove_file(&host->class_dev, &dev_attr_latency_hist);
+}
+#endif
+
 subsys_initcall(mmc_init);
 module_exit(mmc_exit);