|
@@ -298,6 +298,48 @@ static ssize_t pblk_sysfs_get_sec_per_write(struct pblk *pblk, char *page)
|
|
return snprintf(page, PAGE_SIZE, "%d\n", pblk->sec_per_write);
|
|
return snprintf(page, PAGE_SIZE, "%d\n", pblk->sec_per_write);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static ssize_t pblk_get_write_amp(u64 user, u64 gc, u64 pad,
|
|
|
|
+ char *page)
|
|
|
|
+{
|
|
|
|
+ int sz;
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ sz = snprintf(page, PAGE_SIZE,
|
|
|
|
+ "user:%lld gc:%lld pad:%lld WA:",
|
|
|
|
+ user, gc, pad);
|
|
|
|
+
|
|
|
|
+ if (!user) {
|
|
|
|
+ sz += snprintf(page + sz, PAGE_SIZE - sz, "NaN\n");
|
|
|
|
+ } else {
|
|
|
|
+ u64 wa_int;
|
|
|
|
+ u32 wa_frac;
|
|
|
|
+
|
|
|
|
+ wa_int = (user + gc + pad) * 100000;
|
|
|
|
+ wa_int = div_u64(wa_int, user);
|
|
|
|
+ wa_int = div_u64_rem(wa_int, 100000, &wa_frac);
|
|
|
|
+
|
|
|
|
+ sz += snprintf(page + sz, PAGE_SIZE - sz, "%llu.%05u\n",
|
|
|
|
+ wa_int, wa_frac);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return sz;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static ssize_t pblk_sysfs_get_write_amp_mileage(struct pblk *pblk, char *page)
|
|
|
|
+{
|
|
|
|
+ return pblk_get_write_amp(atomic64_read(&pblk->user_wa),
|
|
|
|
+ atomic64_read(&pblk->gc_wa), atomic64_read(&pblk->pad_wa),
|
|
|
|
+ page);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static ssize_t pblk_sysfs_get_write_amp_trip(struct pblk *pblk, char *page)
|
|
|
|
+{
|
|
|
|
+ return pblk_get_write_amp(
|
|
|
|
+ atomic64_read(&pblk->user_wa) - pblk->user_rst_wa,
|
|
|
|
+ atomic64_read(&pblk->gc_wa) - pblk->gc_rst_wa,
|
|
|
|
+ atomic64_read(&pblk->pad_wa) - pblk->pad_rst_wa, page);
|
|
|
|
+}
|
|
|
|
+
|
|
#ifdef CONFIG_NVM_DEBUG
|
|
#ifdef CONFIG_NVM_DEBUG
|
|
static ssize_t pblk_sysfs_stats_debug(struct pblk *pblk, char *page)
|
|
static ssize_t pblk_sysfs_stats_debug(struct pblk *pblk, char *page)
|
|
{
|
|
{
|
|
@@ -360,6 +402,30 @@ static ssize_t pblk_sysfs_set_sec_per_write(struct pblk *pblk,
|
|
return len;
|
|
return len;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static ssize_t pblk_sysfs_set_write_amp_trip(struct pblk *pblk,
|
|
|
|
+ const char *page, size_t len)
|
|
|
|
+{
|
|
|
|
+ size_t c_len;
|
|
|
|
+ int reset_value;
|
|
|
|
+
|
|
|
|
+ c_len = strcspn(page, "\n");
|
|
|
|
+ if (c_len >= len)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ if (kstrtouint(page, 0, &reset_value))
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ if (reset_value != 0)
|
|
|
|
+ return -EINVAL;
|
|
|
|
+
|
|
|
|
+ pblk->user_rst_wa = atomic64_read(&pblk->user_wa);
|
|
|
|
+ pblk->pad_rst_wa = atomic64_read(&pblk->pad_wa);
|
|
|
|
+ pblk->gc_rst_wa = atomic64_read(&pblk->gc_wa);
|
|
|
|
+
|
|
|
|
+ return len;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
static struct attribute sys_write_luns = {
|
|
static struct attribute sys_write_luns = {
|
|
.name = "write_luns",
|
|
.name = "write_luns",
|
|
.mode = 0444,
|
|
.mode = 0444,
|
|
@@ -410,6 +476,16 @@ static struct attribute sys_max_sec_per_write = {
|
|
.mode = 0644,
|
|
.mode = 0644,
|
|
};
|
|
};
|
|
|
|
|
|
|
|
+static struct attribute sys_write_amp_mileage = {
|
|
|
|
+ .name = "write_amp_mileage",
|
|
|
|
+ .mode = 0444,
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct attribute sys_write_amp_trip = {
|
|
|
|
+ .name = "write_amp_trip",
|
|
|
|
+ .mode = 0644,
|
|
|
|
+};
|
|
|
|
+
|
|
#ifdef CONFIG_NVM_DEBUG
|
|
#ifdef CONFIG_NVM_DEBUG
|
|
static struct attribute sys_stats_debug_attr = {
|
|
static struct attribute sys_stats_debug_attr = {
|
|
.name = "stats",
|
|
.name = "stats",
|
|
@@ -428,6 +504,8 @@ static struct attribute *pblk_attrs[] = {
|
|
&sys_stats_ppaf_attr,
|
|
&sys_stats_ppaf_attr,
|
|
&sys_lines_attr,
|
|
&sys_lines_attr,
|
|
&sys_lines_info_attr,
|
|
&sys_lines_info_attr,
|
|
|
|
+ &sys_write_amp_mileage,
|
|
|
|
+ &sys_write_amp_trip,
|
|
#ifdef CONFIG_NVM_DEBUG
|
|
#ifdef CONFIG_NVM_DEBUG
|
|
&sys_stats_debug_attr,
|
|
&sys_stats_debug_attr,
|
|
#endif
|
|
#endif
|
|
@@ -457,6 +535,10 @@ static ssize_t pblk_sysfs_show(struct kobject *kobj, struct attribute *attr,
|
|
return pblk_sysfs_lines_info(pblk, buf);
|
|
return pblk_sysfs_lines_info(pblk, buf);
|
|
else if (strcmp(attr->name, "max_sec_per_write") == 0)
|
|
else if (strcmp(attr->name, "max_sec_per_write") == 0)
|
|
return pblk_sysfs_get_sec_per_write(pblk, buf);
|
|
return pblk_sysfs_get_sec_per_write(pblk, buf);
|
|
|
|
+ else if (strcmp(attr->name, "write_amp_mileage") == 0)
|
|
|
|
+ return pblk_sysfs_get_write_amp_mileage(pblk, buf);
|
|
|
|
+ else if (strcmp(attr->name, "write_amp_trip") == 0)
|
|
|
|
+ return pblk_sysfs_get_write_amp_trip(pblk, buf);
|
|
#ifdef CONFIG_NVM_DEBUG
|
|
#ifdef CONFIG_NVM_DEBUG
|
|
else if (strcmp(attr->name, "stats") == 0)
|
|
else if (strcmp(attr->name, "stats") == 0)
|
|
return pblk_sysfs_stats_debug(pblk, buf);
|
|
return pblk_sysfs_stats_debug(pblk, buf);
|
|
@@ -473,7 +555,8 @@ static ssize_t pblk_sysfs_store(struct kobject *kobj, struct attribute *attr,
|
|
return pblk_sysfs_gc_force(pblk, buf, len);
|
|
return pblk_sysfs_gc_force(pblk, buf, len);
|
|
else if (strcmp(attr->name, "max_sec_per_write") == 0)
|
|
else if (strcmp(attr->name, "max_sec_per_write") == 0)
|
|
return pblk_sysfs_set_sec_per_write(pblk, buf, len);
|
|
return pblk_sysfs_set_sec_per_write(pblk, buf, len);
|
|
-
|
|
|
|
|
|
+ else if (strcmp(attr->name, "write_amp_trip") == 0)
|
|
|
|
+ return pblk_sysfs_set_write_amp_trip(pblk, buf, len);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|