mirror of https://github.com/OpenIPC/firmware.git
148 lines
4.2 KiB
Diff
148 lines
4.2 KiB
Diff
diff -drupN a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
|
|
--- a/drivers/scsi/ufs/ufshcd.c 2018-08-06 17:23:04.000000000 +0300
|
|
+++ b/drivers/scsi/ufs/ufshcd.c 2022-06-12 05:28:14.000000000 +0300
|
|
@@ -41,6 +41,7 @@
|
|
#include <linux/devfreq.h>
|
|
#include <linux/nls.h>
|
|
#include <linux/of.h>
|
|
+#include <linux/blkdev.h>
|
|
#include "ufshcd.h"
|
|
#include "ufs_quirks.h"
|
|
#include "unipro.h"
|
|
@@ -1469,6 +1470,17 @@ static int ufshcd_queuecommand(struct Sc
|
|
clear_bit_unlock(tag, &hba->lrb_in_use);
|
|
goto out;
|
|
}
|
|
+
|
|
+ /* IO svc time latency histogram */
|
|
+ if (hba != NULL && cmd->request != NULL) {
|
|
+ if (hba->latency_hist_enabled &&
|
|
+ (cmd->request->cmd_type == REQ_TYPE_FS)) {
|
|
+ cmd->request->lat_hist_io_start = ktime_get();
|
|
+ cmd->request->lat_hist_enabled = 1;
|
|
+ } else
|
|
+ cmd->request->lat_hist_enabled = 0;
|
|
+ }
|
|
+
|
|
WARN_ON(hba->clk_gating.state != CLKS_ON);
|
|
|
|
lrbp = &hba->lrb[tag];
|
|
@@ -3677,6 +3689,7 @@ static void __ufshcd_transfer_req_compl(
|
|
struct scsi_cmnd *cmd;
|
|
int result;
|
|
int index;
|
|
+ struct request *req;
|
|
|
|
for_each_set_bit(index, &completed_reqs, hba->nutrs) {
|
|
lrbp = &hba->lrb[index];
|
|
@@ -3688,6 +3701,22 @@ static void __ufshcd_transfer_req_compl(
|
|
/* Mark completed command as NULL in LRB */
|
|
lrbp->cmd = NULL;
|
|
clear_bit_unlock(index, &hba->lrb_in_use);
|
|
+ req = cmd->request;
|
|
+ if (req) {
|
|
+ /* Update IO svc time latency histogram */
|
|
+ if (req->lat_hist_enabled) {
|
|
+ ktime_t completion;
|
|
+ u_int64_t delta_us;
|
|
+
|
|
+ completion = ktime_get();
|
|
+ delta_us = ktime_us_delta(completion,
|
|
+ req->lat_hist_io_start);
|
|
+ blk_update_latency_hist(
|
|
+ (rq_data_dir(req) == READ) ?
|
|
+ &hba->io_lat_read :
|
|
+ &hba->io_lat_write, delta_us);
|
|
+ }
|
|
+ }
|
|
/* Do not touch lrbp after scsi done */
|
|
cmd->scsi_done(cmd);
|
|
__ufshcd_release(hba);
|
|
@@ -6467,6 +6496,61 @@ out:
|
|
}
|
|
EXPORT_SYMBOL(ufshcd_shutdown);
|
|
|
|
+/*
|
|
+ * 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 ufs_hba *hba = dev_get_drvdata(dev);
|
|
+ long value;
|
|
+
|
|
+ if (kstrtol(buf, 0, &value))
|
|
+ return -EINVAL;
|
|
+ if (value == BLK_IO_LAT_HIST_ZERO) {
|
|
+ memset(&hba->io_lat_read, 0, sizeof(hba->io_lat_read));
|
|
+ memset(&hba->io_lat_write, 0, sizeof(hba->io_lat_write));
|
|
+ } else if (value == BLK_IO_LAT_HIST_ENABLE ||
|
|
+ value == BLK_IO_LAT_HIST_DISABLE)
|
|
+ hba->latency_hist_enabled = value;
|
|
+ return count;
|
|
+}
|
|
+
|
|
+ssize_t
|
|
+latency_hist_show(struct device *dev, struct device_attribute *attr,
|
|
+ char *buf)
|
|
+{
|
|
+ struct ufs_hba *hba = dev_get_drvdata(dev);
|
|
+ size_t written_bytes;
|
|
+
|
|
+ written_bytes = blk_latency_hist_show("Read", &hba->io_lat_read,
|
|
+ buf, PAGE_SIZE);
|
|
+ written_bytes += blk_latency_hist_show("Write", &hba->io_lat_write,
|
|
+ buf + written_bytes, PAGE_SIZE - written_bytes);
|
|
+
|
|
+ return written_bytes;
|
|
+}
|
|
+
|
|
+static DEVICE_ATTR(latency_hist, S_IRUGO | S_IWUSR,
|
|
+ latency_hist_show, latency_hist_store);
|
|
+
|
|
+static void
|
|
+ufshcd_init_latency_hist(struct ufs_hba *hba)
|
|
+{
|
|
+ if (device_create_file(hba->dev, &dev_attr_latency_hist))
|
|
+ dev_err(hba->dev, "Failed to create latency_hist sysfs entry\n");
|
|
+}
|
|
+
|
|
+static void
|
|
+ufshcd_exit_latency_hist(struct ufs_hba *hba)
|
|
+{
|
|
+ device_create_file(hba->dev, &dev_attr_latency_hist);
|
|
+}
|
|
+
|
|
/**
|
|
* ufshcd_remove - de-allocate SCSI host and host memory space
|
|
* data structure memory
|
|
@@ -6482,6 +6566,7 @@ void ufshcd_remove(struct ufs_hba *hba)
|
|
scsi_host_put(hba->host);
|
|
|
|
ufshcd_exit_clk_gating(hba);
|
|
+ ufshcd_exit_latency_hist(hba);
|
|
if (ufshcd_is_clkscaling_enabled(hba))
|
|
devfreq_remove_device(hba->devfreq);
|
|
ufshcd_hba_exit(hba);
|
|
@@ -6798,6 +6883,8 @@ int ufshcd_init(struct ufs_hba *hba, voi
|
|
/* Hold auto suspend until async scan completes */
|
|
pm_runtime_get_sync(dev);
|
|
|
|
+ ufshcd_init_latency_hist(hba);
|
|
+
|
|
/*
|
|
* We are assuming that device wasn't put in sleep/power-down
|
|
* state exclusively during the boot stage before kernel.
|
|
@@ -6814,6 +6901,7 @@ out_remove_scsi_host:
|
|
scsi_remove_host(hba->host);
|
|
exit_gating:
|
|
ufshcd_exit_clk_gating(hba);
|
|
+ ufshcd_exit_latency_hist(hba);
|
|
out_disable:
|
|
hba->is_irq_enabled = false;
|
|
scsi_host_put(host);
|