linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v5 00/10] Add Host control mode to HPB
@ 2021-03-02 13:24 Avri Altman
  2021-03-02 13:24 ` [PATCH v5 01/10] scsi: ufshpb: Cache HPB Control mode on init Avri Altman
                   ` (9 more replies)
  0 siblings, 10 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-02 13:24 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen, linux-scsi, linux-kernel
  Cc: gregkh, Bart Van Assche, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, cang,
	stanley.chu, Avri Altman

v4 -> v5:
 - attend Daejun's comments
 - Control the number of inflight map requests

v3 -> v4:
 - rebase on Daejun's v25

v2 -> v3:
 - Attend Greg's and Can's comments
 - rebase on Daejun's v21

v1 -> v2:
 - attend Greg's and Daejun's comments
 - add patch 9 making host mode parameters configurable
 - rebase on Daejun's v19


The HPB spec defines 2 control modes - device control mode and host
control mode. In oppose to device control mode, in which the host obey
to whatever recommendation received from the device - In host control
mode, the host uses its own algorithms to decide which regions should
be activated or inactivated.

We kept the host managed heuristic simple and concise.

Aside from adding a by-spec functionality, host control mode entails
some further potential benefits: makes the hpb logic transparent and
readable, while allow tuning / scaling its various parameters, and
utilize system-wide info to optimize HPB potential.

This series is based on Samsung's V25 device-control HPB2.0 driver, see
msg-id: 20210226073233epcms2p80fca2dffabea03143a9414838f757633@epcms2p8
in lore.kernel.org.

This version was tested on Galaxy S20, and Xiaomi Mi10 pro.
Your meticulous review and testing is mostly welcome and appreciated.

Thanks,
Avri

Avri Altman (10):
  scsi: ufshpb: Cache HPB Control mode on init
  scsi: ufshpb: Add host control mode support to rsp_upiu
  scsi: ufshpb: Add region's reads counter
  scsi: ufshpb: Make eviction depends on region's reads
  scsi: ufshpb: Region inactivation in host mode
  scsi: ufshpb: Add hpb dev reset response
  scsi: ufshpb: Add "Cold" regions timer
  scsi: ufshpb: Limit the number of inflight map requests
  scsi: ufshpb: Add support for host control mode
  scsi: ufshpb: Make host mode parameters configurable

 Documentation/ABI/testing/sysfs-driver-ufs |  74 +++
 drivers/scsi/ufs/ufshcd.h                  |   2 +
 drivers/scsi/ufs/ufshpb.c                  | 555 ++++++++++++++++++++-
 drivers/scsi/ufs/ufshpb.h                  |  39 ++
 4 files changed, 646 insertions(+), 24 deletions(-)

-- 
2.25.1


^ permalink raw reply	[flat|nested] 58+ messages in thread

* [PATCH v5 01/10] scsi: ufshpb: Cache HPB Control mode on init
  2021-03-02 13:24 [PATCH v5 00/10] Add Host control mode to HPB Avri Altman
@ 2021-03-02 13:24 ` Avri Altman
  2021-03-02 13:24 ` [PATCH v5 02/10] scsi: ufshpb: Add host control mode support to rsp_upiu Avri Altman
                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-02 13:24 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen, linux-scsi, linux-kernel
  Cc: gregkh, Bart Van Assche, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, cang,
	stanley.chu, Avri Altman

We will use it later, when we'll need to differentiate between device
and host control modes.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/scsi/ufs/ufshcd.h | 2 ++
 drivers/scsi/ufs/ufshpb.c | 8 +++++---
 drivers/scsi/ufs/ufshpb.h | 2 ++
 3 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 3ea7e88f5bff..2d589ee18875 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -656,6 +656,7 @@ struct ufs_hba_variant_params {
  * @hpb_disabled: flag to check if HPB is disabled
  * @max_hpb_single_cmd: maximum size of single HPB command
  * @is_legacy: flag to check HPB 1.0
+ * @control_mode: either host or device
  */
 struct ufshpb_dev_info {
 	int num_lu;
@@ -665,6 +666,7 @@ struct ufshpb_dev_info {
 	bool hpb_disabled;
 	int max_hpb_single_cmd;
 	bool is_legacy;
+	u8 control_mode;
 };
 #endif
 
diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index f89714a9785c..d9ea0cddc3c4 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -1624,6 +1624,9 @@ static void ufshpb_lu_parameter_init(struct ufs_hba *hba,
 				 % (hpb->srgn_mem_size / HPB_ENTRY_SIZE);
 
 	hpb->pages_per_srgn = DIV_ROUND_UP(hpb->srgn_mem_size, PAGE_SIZE);
+
+	if (hpb_dev_info->control_mode == HPB_HOST_CONTROL)
+		hpb->is_hcm = true;
 }
 
 static int ufshpb_alloc_region_tbl(struct ufs_hba *hba, struct ufshpb_lu *hpb)
@@ -2308,11 +2311,10 @@ void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf)
 {
 	struct ufshpb_dev_info *hpb_dev_info = &hba->ufshpb_dev;
 	int version, ret;
-	u8 hpb_mode;
 	u32 max_hpb_sigle_cmd = 0;
 
-	hpb_mode = desc_buf[DEVICE_DESC_PARAM_HPB_CONTROL];
-	if (hpb_mode == HPB_HOST_CONTROL) {
+	hpb_dev_info->control_mode = desc_buf[DEVICE_DESC_PARAM_HPB_CONTROL];
+	if (hpb_dev_info->control_mode == HPB_HOST_CONTROL) {
 		dev_err(hba->dev, "%s: host control mode is not supported.\n",
 			__func__);
 		hpb_dev_info->hpb_disabled = true;
diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
index 88f424250dd9..14b7ba9bda3a 100644
--- a/drivers/scsi/ufs/ufshpb.h
+++ b/drivers/scsi/ufs/ufshpb.h
@@ -227,6 +227,8 @@ struct ufshpb_lu {
 	u32 entries_per_srgn_shift;
 	u32 pages_per_srgn;
 
+	bool is_hcm;
+
 	struct ufshpb_stats stats;
 	struct ufshpb_params params;
 
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v5 02/10] scsi: ufshpb: Add host control mode support to rsp_upiu
  2021-03-02 13:24 [PATCH v5 00/10] Add Host control mode to HPB Avri Altman
  2021-03-02 13:24 ` [PATCH v5 01/10] scsi: ufshpb: Cache HPB Control mode on init Avri Altman
@ 2021-03-02 13:24 ` Avri Altman
  2021-03-02 13:24 ` [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter Avri Altman
                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-02 13:24 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen, linux-scsi, linux-kernel
  Cc: gregkh, Bart Van Assche, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, cang,
	stanley.chu, Avri Altman

In device control mode, the device may recommend the host to either
activate or inactivate a region, and the host should follow. Meaning
those are not actually recommendations, but more of instructions.

On the contrary, in host control mode, the recommendation protocol is
slightly changed:
a) The device may only recommend the host to update a subregion of an
   already-active region. And,
b) The device may *not* recommend to inactivate a region.

Furthermore, in host control mode, the host may choose not to follow any
of the device's recommendations. However, in case of a recommendation to
update an active and clean subregion, it is better to follow those
recommendation because otherwise the host has no other way to know that
some internal relocation took place.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/scsi/ufs/ufshpb.c | 34 +++++++++++++++++++++++++++++++++-
 drivers/scsi/ufs/ufshpb.h |  2 ++
 2 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index d9ea0cddc3c4..044fec9854a0 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -166,6 +166,8 @@ static void ufshpb_set_ppn_dirty(struct ufshpb_lu *hpb, int rgn_idx,
 	else
 		set_bit_len = cnt;
 
+	set_bit(RGN_FLAG_DIRTY, &rgn->rgn_flags);
+
 	if (rgn->rgn_state != HPB_RGN_INACTIVE &&
 	    srgn->srgn_state == HPB_SRGN_VALID)
 		bitmap_set(srgn->mctx->ppn_dirty, srgn_offset, set_bit_len);
@@ -235,6 +237,11 @@ static bool ufshpb_test_ppn_dirty(struct ufshpb_lu *hpb, int rgn_idx,
 	return false;
 }
 
+static inline bool is_rgn_dirty(struct ufshpb_region *rgn)
+{
+	return test_bit(RGN_FLAG_DIRTY, &rgn->rgn_flags);
+}
+
 static int ufshpb_fill_ppn_from_page(struct ufshpb_lu *hpb,
 				     struct ufshpb_map_ctx *mctx, int pos,
 				     int len, u64 *ppn_buf)
@@ -717,6 +724,7 @@ static void ufshpb_put_map_req(struct ufshpb_lu *hpb,
 static int ufshpb_clear_dirty_bitmap(struct ufshpb_lu *hpb,
 				     struct ufshpb_subregion *srgn)
 {
+	struct ufshpb_region *rgn;
 	u32 num_entries = hpb->entries_per_srgn;
 
 	if (!srgn->mctx) {
@@ -730,6 +738,10 @@ static int ufshpb_clear_dirty_bitmap(struct ufshpb_lu *hpb,
 		num_entries = hpb->last_srgn_entries;
 
 	bitmap_zero(srgn->mctx->ppn_dirty, num_entries);
+
+	rgn = hpb->rgn_tbl + srgn->rgn_idx;
+	clear_bit(RGN_FLAG_DIRTY, &rgn->rgn_flags);
+
 	return 0;
 }
 
@@ -1257,6 +1269,18 @@ static void ufshpb_rsp_req_region_update(struct ufshpb_lu *hpb,
 		srgn_i =
 			be16_to_cpu(rsp_field->hpb_active_field[i].active_srgn);
 
+		rgn = hpb->rgn_tbl + rgn_i;
+		if (hpb->is_hcm &&
+		    (rgn->rgn_state != HPB_RGN_ACTIVE || is_rgn_dirty(rgn))) {
+			/*
+			 * in host control mode, subregion activation
+			 * recommendations are only allowed to active regions.
+			 * Also, ignore recommendations for dirty regions - the
+			 * host will make decisions concerning those by himself
+			 */
+			continue;
+		}
+
 		dev_dbg(&hpb->sdev_ufs_lu->sdev_dev,
 			"activate(%d) region %d - %d\n", i, rgn_i, srgn_i);
 
@@ -1264,7 +1288,6 @@ static void ufshpb_rsp_req_region_update(struct ufshpb_lu *hpb,
 		ufshpb_update_active_info(hpb, rgn_i, srgn_i);
 		spin_unlock(&hpb->rsp_list_lock);
 
-		rgn = hpb->rgn_tbl + rgn_i;
 		srgn = rgn->srgn_tbl + srgn_i;
 
 		/* blocking HPB_READ */
@@ -1275,6 +1298,14 @@ static void ufshpb_rsp_req_region_update(struct ufshpb_lu *hpb,
 		hpb->stats.rb_active_cnt++;
 	}
 
+	if (hpb->is_hcm) {
+		/*
+		 * in host control mode the device is not allowed to inactivate
+		 * regions
+		 */
+		goto out;
+	}
+
 	for (i = 0; i < rsp_field->inactive_rgn_cnt; i++) {
 		rgn_i = be16_to_cpu(rsp_field->hpb_inactive_field[i]);
 		dev_dbg(&hpb->sdev_ufs_lu->sdev_dev,
@@ -1299,6 +1330,7 @@ static void ufshpb_rsp_req_region_update(struct ufshpb_lu *hpb,
 		hpb->stats.rb_inactive_cnt++;
 	}
 
+out:
 	dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "Noti: #ACT %u #INACT %u\n",
 		rsp_field->active_rgn_cnt, rsp_field->inactive_rgn_cnt);
 
diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
index 14b7ba9bda3a..8119b1a3d1e5 100644
--- a/drivers/scsi/ufs/ufshpb.h
+++ b/drivers/scsi/ufs/ufshpb.h
@@ -119,6 +119,8 @@ struct ufshpb_region {
 
 	/* below information is used by lru */
 	struct list_head list_lru_rgn;
+	unsigned long rgn_flags;
+#define RGN_FLAG_DIRTY 0
 };
 
 #define for_each_sub_region(rgn, i, srgn)				\
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter
  2021-03-02 13:24 [PATCH v5 00/10] Add Host control mode to HPB Avri Altman
  2021-03-02 13:24 ` [PATCH v5 01/10] scsi: ufshpb: Cache HPB Control mode on init Avri Altman
  2021-03-02 13:24 ` [PATCH v5 02/10] scsi: ufshpb: Add host control mode support to rsp_upiu Avri Altman
@ 2021-03-02 13:24 ` Avri Altman
  2021-03-11  7:52   ` Can Guo
                     ` (2 more replies)
  2021-03-02 13:24 ` [PATCH v5 04/10] scsi: ufshpb: Make eviction depends on region's reads Avri Altman
                   ` (6 subsequent siblings)
  9 siblings, 3 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-02 13:24 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen, linux-scsi, linux-kernel
  Cc: gregkh, Bart Van Assche, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, cang,
	stanley.chu, Avri Altman

In host control mode, reads are the major source of activation trials.
Keep track of those reads counters, for both active as well inactive
regions.

We reset the read counter upon write - we are only interested in "clean"
reads.  less intuitive however, is that we also reset it upon region's
deactivation.  Region deactivation is often due to the fact that
eviction took place: a region become active on the expense of another.
This is happening when the max-active-regions limit has crossed. If we
don’t reset the counter, we will trigger a lot of trashing of the HPB
database, since few reads (or even one) to the region that was
deactivated, will trigger a re-activation trial.

Keep those counters normalized, as we are using those reads as a
comparative score, to make various decisions.
If during consecutive normalizations an active region has exhaust its
reads - inactivate it.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/scsi/ufs/ufshpb.c | 102 ++++++++++++++++++++++++++++++++------
 drivers/scsi/ufs/ufshpb.h |   5 ++
 2 files changed, 92 insertions(+), 15 deletions(-)

diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index 044fec9854a0..a8f8d13af21a 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -16,6 +16,8 @@
 #include "ufshpb.h"
 #include "../sd.h"
 
+#define ACTIVATION_THRESHOLD 4 /* 4 IOs */
+
 /* memory management */
 static struct kmem_cache *ufshpb_mctx_cache;
 static mempool_t *ufshpb_mctx_pool;
@@ -554,6 +556,21 @@ static int ufshpb_issue_pre_req(struct ufshpb_lu *hpb, struct scsi_cmnd *cmd,
 	return ret;
 }
 
+static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int rgn_idx,
+				      int srgn_idx)
+{
+	struct ufshpb_region *rgn;
+	struct ufshpb_subregion *srgn;
+
+	rgn = hpb->rgn_tbl + rgn_idx;
+	srgn = rgn->srgn_tbl + srgn_idx;
+
+	list_del_init(&rgn->list_inact_rgn);
+
+	if (list_empty(&srgn->list_act_srgn))
+		list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn);
+}
+
 /*
  * This function will set up HPB read command using host-side L2P map data.
  */
@@ -600,12 +617,44 @@ int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 		ufshpb_set_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
 				 transfer_len);
 		spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
+
+		if (hpb->is_hcm) {
+			spin_lock_irqsave(&rgn->rgn_lock, flags);
+			rgn->reads = 0;
+			spin_unlock_irqrestore(&rgn->rgn_lock, flags);
+		}
+
 		return 0;
 	}
 
 	if (!ufshpb_is_support_chunk(hpb, transfer_len))
 		return 0;
 
+	if (hpb->is_hcm) {
+		bool activate = false;
+		/*
+		 * in host control mode, reads are the main source for
+		 * activation trials.
+		 */
+		spin_lock_irqsave(&rgn->rgn_lock, flags);
+		rgn->reads++;
+		if (rgn->reads == ACTIVATION_THRESHOLD)
+			activate = true;
+		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
+		if (activate) {
+			spin_lock_irqsave(&hpb->rsp_list_lock, flags);
+			ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
+			hpb->stats.rb_active_cnt++;
+			spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
+			dev_dbg(&hpb->sdev_ufs_lu->sdev_dev,
+				"activate region %d-%d\n", rgn_idx, srgn_idx);
+		}
+
+		/* keep those counters normalized */
+		if (rgn->reads > hpb->entries_per_srgn)
+			schedule_work(&hpb->ufshpb_normalization_work);
+	}
+
 	spin_lock_irqsave(&hpb->rgn_state_lock, flags);
 	if (ufshpb_test_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
 				   transfer_len)) {
@@ -745,21 +794,6 @@ static int ufshpb_clear_dirty_bitmap(struct ufshpb_lu *hpb,
 	return 0;
 }
 
-static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int rgn_idx,
-				      int srgn_idx)
-{
-	struct ufshpb_region *rgn;
-	struct ufshpb_subregion *srgn;
-
-	rgn = hpb->rgn_tbl + rgn_idx;
-	srgn = rgn->srgn_tbl + srgn_idx;
-
-	list_del_init(&rgn->list_inact_rgn);
-
-	if (list_empty(&srgn->list_act_srgn))
-		list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn);
-}
-
 static void ufshpb_update_inactive_info(struct ufshpb_lu *hpb, int rgn_idx)
 {
 	struct ufshpb_region *rgn;
@@ -1079,6 +1113,14 @@ static void __ufshpb_evict_region(struct ufshpb_lu *hpb,
 
 	ufshpb_cleanup_lru_info(lru_info, rgn);
 
+	if (hpb->is_hcm) {
+		unsigned long flags;
+
+		spin_lock_irqsave(&rgn->rgn_lock, flags);
+		rgn->reads = 0;
+		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
+	}
+
 	for_each_sub_region(rgn, srgn_idx, srgn)
 		ufshpb_purge_active_subregion(hpb, srgn);
 }
@@ -1523,6 +1565,31 @@ static void ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
 	spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
 }
 
+static void ufshpb_normalization_work_handler(struct work_struct *work)
+{
+	struct ufshpb_lu *hpb;
+	int rgn_idx;
+	unsigned long flags;
+
+	hpb = container_of(work, struct ufshpb_lu, ufshpb_normalization_work);
+
+	for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) {
+		struct ufshpb_region *rgn = hpb->rgn_tbl + rgn_idx;
+
+		spin_lock_irqsave(&rgn->rgn_lock, flags);
+		rgn->reads = (rgn->reads >> 1);
+		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
+
+		if (rgn->rgn_state != HPB_RGN_ACTIVE || rgn->reads)
+			continue;
+
+		/* if region is active but has no reads - inactivate it */
+		spin_lock(&hpb->rsp_list_lock);
+		ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
+		spin_unlock(&hpb->rsp_list_lock);
+	}
+}
+
 static void ufshpb_map_work_handler(struct work_struct *work)
 {
 	struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu, map_work);
@@ -1913,6 +1980,9 @@ static int ufshpb_lu_hpb_init(struct ufs_hba *hba, struct ufshpb_lu *hpb)
 	INIT_LIST_HEAD(&hpb->list_hpb_lu);
 
 	INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
+	if (hpb->is_hcm)
+		INIT_WORK(&hpb->ufshpb_normalization_work,
+			  ufshpb_normalization_work_handler);
 
 	hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
 			  sizeof(struct ufshpb_req), 0, 0, NULL);
@@ -2012,6 +2082,8 @@ static void ufshpb_discard_rsp_lists(struct ufshpb_lu *hpb)
 
 static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
 {
+	if (hpb->is_hcm)
+		cancel_work_sync(&hpb->ufshpb_normalization_work);
 	cancel_work_sync(&hpb->map_work);
 }
 
diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
index 8119b1a3d1e5..bd4308010466 100644
--- a/drivers/scsi/ufs/ufshpb.h
+++ b/drivers/scsi/ufs/ufshpb.h
@@ -121,6 +121,10 @@ struct ufshpb_region {
 	struct list_head list_lru_rgn;
 	unsigned long rgn_flags;
 #define RGN_FLAG_DIRTY 0
+
+	/* region reads - for host mode */
+	spinlock_t rgn_lock;
+	unsigned int reads;
 };
 
 #define for_each_sub_region(rgn, i, srgn)				\
@@ -211,6 +215,7 @@ struct ufshpb_lu {
 
 	/* for selecting victim */
 	struct victim_select_info lru_info;
+	struct work_struct ufshpb_normalization_work;
 
 	/* pinned region information */
 	u32 lu_pinned_start;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v5 04/10] scsi: ufshpb: Make eviction depends on region's reads
  2021-03-02 13:24 [PATCH v5 00/10] Add Host control mode to HPB Avri Altman
                   ` (2 preceding siblings ...)
  2021-03-02 13:24 ` [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter Avri Altman
@ 2021-03-02 13:24 ` Avri Altman
  2021-03-11  7:53   ` Can Guo
  2021-03-15  8:30   ` Can Guo
  2021-03-02 13:24 ` [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode Avri Altman
                   ` (5 subsequent siblings)
  9 siblings, 2 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-02 13:24 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen, linux-scsi, linux-kernel
  Cc: gregkh, Bart Van Assche, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, cang,
	stanley.chu, Avri Altman

In host mode, eviction is considered an extreme measure.
verify that the entering region has enough reads, and the exiting
region has much less reads.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/scsi/ufs/ufshpb.c | 20 +++++++++++++++++++-
 1 file changed, 19 insertions(+), 1 deletion(-)

diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index a8f8d13af21a..6f4fd22eaf2f 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -17,6 +17,7 @@
 #include "../sd.h"
 
 #define ACTIVATION_THRESHOLD 4 /* 4 IOs */
+#define EVICTION_THRESHOLD (ACTIVATION_THRESHOLD << 6) /* 256 IOs */
 
 /* memory management */
 static struct kmem_cache *ufshpb_mctx_cache;
@@ -1050,6 +1051,13 @@ static struct ufshpb_region *ufshpb_victim_lru_info(struct ufshpb_lu *hpb)
 		if (ufshpb_check_srgns_issue_state(hpb, rgn))
 			continue;
 
+		/*
+		 * in host control mode, verify that the exiting region
+		 * has less reads
+		 */
+		if (hpb->is_hcm && rgn->reads > (EVICTION_THRESHOLD >> 1))
+			continue;
+
 		victim_rgn = rgn;
 		break;
 	}
@@ -1235,7 +1243,7 @@ static int ufshpb_issue_map_req(struct ufshpb_lu *hpb,
 
 static int ufshpb_add_region(struct ufshpb_lu *hpb, struct ufshpb_region *rgn)
 {
-	struct ufshpb_region *victim_rgn;
+	struct ufshpb_region *victim_rgn = NULL;
 	struct victim_select_info *lru_info = &hpb->lru_info;
 	unsigned long flags;
 	int ret = 0;
@@ -1263,6 +1271,16 @@ static int ufshpb_add_region(struct ufshpb_lu *hpb, struct ufshpb_region *rgn)
 			 * because the device could detect this region
 			 * by not issuing HPB_READ
 			 */
+
+			/*
+			 * in host control mode, verify that the entering
+			 * region has enough reads
+			 */
+			if (hpb->is_hcm && rgn->reads < EVICTION_THRESHOLD) {
+				ret = -EACCES;
+				goto out;
+			}
+
 			victim_rgn = ufshpb_victim_lru_info(hpb);
 			if (!victim_rgn) {
 				dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
  2021-03-02 13:24 [PATCH v5 00/10] Add Host control mode to HPB Avri Altman
                   ` (3 preceding siblings ...)
  2021-03-02 13:24 ` [PATCH v5 04/10] scsi: ufshpb: Make eviction depends on region's reads Avri Altman
@ 2021-03-02 13:24 ` Avri Altman
  2021-03-11  8:20   ` Can Guo
  2021-03-15  4:02   ` Can Guo
  2021-03-02 13:24 ` [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response Avri Altman
                   ` (4 subsequent siblings)
  9 siblings, 2 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-02 13:24 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen, linux-scsi, linux-kernel
  Cc: gregkh, Bart Van Assche, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, cang,
	stanley.chu, Avri Altman

I host mode, the host is expected to send HPB-WRITE-BUFFER with
buffer-id = 0x1 when it inactivates a region.

Use the map-requests pool as there is no point in assigning a
designated cache for umap-requests.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
 drivers/scsi/ufs/ufshpb.h |  1 +
 2 files changed, 15 insertions(+)

diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index 6f4fd22eaf2f..0744feb4d484 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct ufshpb_lu *hpb,
 
 	blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_umap_req_compl_fn);
 
+	hpb->stats.umap_req_cnt++;
 	return 0;
 }
 
@@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct ufshpb_lu *hpb,
 	return -EAGAIN;
 }
 
+static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
+					struct ufshpb_region *rgn)
+{
+	return ufshpb_issue_umap_req(hpb, rgn);
+}
+
 static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
 {
 	return ufshpb_issue_umap_req(hpb, NULL);
@@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct ufshpb_lu *hpb,
 	struct ufshpb_subregion *srgn;
 	int srgn_idx;
 
+
+	if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))
+		return;
+
 	lru_info = &hpb->lru_info;
 
 	dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n", rgn->rgn_idx);
@@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
 ufshpb_sysfs_attr_show_func(rb_active_cnt);
 ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
 ufshpb_sysfs_attr_show_func(map_req_cnt);
+ufshpb_sysfs_attr_show_func(umap_req_cnt);
 
 static struct attribute *hpb_dev_stat_attrs[] = {
 	&dev_attr_hit_cnt.attr,
@@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[] = {
 	&dev_attr_rb_active_cnt.attr,
 	&dev_attr_rb_inactive_cnt.attr,
 	&dev_attr_map_req_cnt.attr,
+	&dev_attr_umap_req_cnt.attr,
 	NULL,
 };
 
@@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu *hpb)
 	hpb->stats.rb_active_cnt = 0;
 	hpb->stats.rb_inactive_cnt = 0;
 	hpb->stats.map_req_cnt = 0;
+	hpb->stats.umap_req_cnt = 0;
 }
 
 static void ufshpb_param_init(struct ufshpb_lu *hpb)
diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
index bd4308010466..84598a317897 100644
--- a/drivers/scsi/ufs/ufshpb.h
+++ b/drivers/scsi/ufs/ufshpb.h
@@ -186,6 +186,7 @@ struct ufshpb_stats {
 	u64 rb_inactive_cnt;
 	u64 map_req_cnt;
 	u64 pre_req_cnt;
+	u64 umap_req_cnt;
 };
 
 struct ufshpb_lu {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-02 13:24 [PATCH v5 00/10] Add Host control mode to HPB Avri Altman
                   ` (4 preceding siblings ...)
  2021-03-02 13:24 ` [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode Avri Altman
@ 2021-03-02 13:24 ` Avri Altman
  2021-03-15  1:34   ` Can Guo
  2021-03-17 10:56   ` Can Guo
  2021-03-02 13:25 ` [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer Avri Altman
                   ` (3 subsequent siblings)
  9 siblings, 2 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-02 13:24 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen, linux-scsi, linux-kernel
  Cc: gregkh, Bart Van Assche, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, cang,
	stanley.chu, Avri Altman

The spec does not define what is the host's recommended response when
the device send hpb dev reset response (oper 0x2).

We will update all active hpb regions: mark them and do that on the next
read.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/scsi/ufs/ufshpb.c | 47 ++++++++++++++++++++++++++++++++++++---
 drivers/scsi/ufs/ufshpb.h |  2 ++
 2 files changed, 46 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index 0744feb4d484..0034fa03fdc6 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -642,7 +642,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 		if (rgn->reads == ACTIVATION_THRESHOLD)
 			activate = true;
 		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
-		if (activate) {
+		if (activate ||
+		    test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) {
 			spin_lock_irqsave(&hpb->rsp_list_lock, flags);
 			ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
 			hpb->stats.rb_active_cnt++;
@@ -1480,6 +1481,20 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 	case HPB_RSP_DEV_RESET:
 		dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
 			 "UFS device lost HPB information during PM.\n");
+
+		if (hpb->is_hcm) {
+			struct scsi_device *sdev;
+
+			__shost_for_each_device(sdev, hba->host) {
+				struct ufshpb_lu *h = sdev->hostdata;
+
+				if (!h)
+					continue;
+
+				schedule_work(&hpb->ufshpb_lun_reset_work);
+			}
+		}
+
 		break;
 	default:
 		dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
@@ -1594,6 +1609,25 @@ static void ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
 	spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
 }
 
+static void ufshpb_reset_work_handler(struct work_struct *work)
+{
+	struct ufshpb_lu *hpb;
+	struct victim_select_info *lru_info;
+	struct ufshpb_region *rgn;
+	unsigned long flags;
+
+	hpb = container_of(work, struct ufshpb_lu, ufshpb_lun_reset_work);
+
+	lru_info = &hpb->lru_info;
+
+	spin_lock_irqsave(&hpb->rgn_state_lock, flags);
+
+	list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
+		set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
+
+	spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
+}
+
 static void ufshpb_normalization_work_handler(struct work_struct *work)
 {
 	struct ufshpb_lu *hpb;
@@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct ufs_hba *hba, struct ufshpb_lu *hpb)
 		} else {
 			rgn->rgn_state = HPB_RGN_INACTIVE;
 		}
+
+		rgn->rgn_flags = 0;
 	}
 
 	return 0;
@@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct ufs_hba *hba, struct ufshpb_lu *hpb)
 	INIT_LIST_HEAD(&hpb->list_hpb_lu);
 
 	INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
-	if (hpb->is_hcm)
+	if (hpb->is_hcm) {
 		INIT_WORK(&hpb->ufshpb_normalization_work,
 			  ufshpb_normalization_work_handler);
+		INIT_WORK(&hpb->ufshpb_lun_reset_work,
+			  ufshpb_reset_work_handler);
+	}
 
 	hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
 			  sizeof(struct ufshpb_req), 0, 0, NULL);
@@ -2114,8 +2153,10 @@ static void ufshpb_discard_rsp_lists(struct ufshpb_lu *hpb)
 
 static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
 {
-	if (hpb->is_hcm)
+	if (hpb->is_hcm) {
+		cancel_work_sync(&hpb->ufshpb_lun_reset_work);
 		cancel_work_sync(&hpb->ufshpb_normalization_work);
+	}
 	cancel_work_sync(&hpb->map_work);
 }
 
diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
index 84598a317897..37c1b0ea0c0a 100644
--- a/drivers/scsi/ufs/ufshpb.h
+++ b/drivers/scsi/ufs/ufshpb.h
@@ -121,6 +121,7 @@ struct ufshpb_region {
 	struct list_head list_lru_rgn;
 	unsigned long rgn_flags;
 #define RGN_FLAG_DIRTY 0
+#define RGN_FLAG_UPDATE 1
 
 	/* region reads - for host mode */
 	spinlock_t rgn_lock;
@@ -217,6 +218,7 @@ struct ufshpb_lu {
 	/* for selecting victim */
 	struct victim_select_info lru_info;
 	struct work_struct ufshpb_normalization_work;
+	struct work_struct ufshpb_lun_reset_work;
 
 	/* pinned region information */
 	u32 lu_pinned_start;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer
  2021-03-02 13:24 [PATCH v5 00/10] Add Host control mode to HPB Avri Altman
                   ` (5 preceding siblings ...)
  2021-03-02 13:24 ` [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response Avri Altman
@ 2021-03-02 13:25 ` Avri Altman
  2021-03-15  1:37   ` Can Guo
  2021-03-15  9:36   ` Can Guo
  2021-03-02 13:25 ` [PATCH v5 08/10] scsi: ufshpb: Limit the number of inflight map requests Avri Altman
                   ` (2 subsequent siblings)
  9 siblings, 2 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-02 13:25 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen, linux-scsi, linux-kernel
  Cc: gregkh, Bart Van Assche, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, cang,
	stanley.chu, Avri Altman

In order not to hang on to “cold” regions, we shall inactivate a
region that has no READ access for a predefined amount of time -
READ_TO_MS. For that purpose we shall monitor the active regions list,
polling it on every POLLING_INTERVAL_MS. On timeout expiry we shall add
the region to the "to-be-inactivated" list, unless it is clean and did
not exhaust its READ_TO_EXPIRIES - another parameter.

All this does not apply to pinned regions.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/scsi/ufs/ufshpb.c | 65 +++++++++++++++++++++++++++++++++++++++
 drivers/scsi/ufs/ufshpb.h |  6 ++++
 2 files changed, 71 insertions(+)

diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index 0034fa03fdc6..89a930e72cff 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -18,6 +18,9 @@
 
 #define ACTIVATION_THRESHOLD 4 /* 4 IOs */
 #define EVICTION_THRESHOLD (ACTIVATION_THRESHOLD << 6) /* 256 IOs */
+#define READ_TO_MS 1000
+#define READ_TO_EXPIRIES 100
+#define POLLING_INTERVAL_MS 200
 
 /* memory management */
 static struct kmem_cache *ufshpb_mctx_cache;
@@ -1024,12 +1027,61 @@ static int ufshpb_check_srgns_issue_state(struct ufshpb_lu *hpb,
 	return 0;
 }
 
+static void ufshpb_read_to_handler(struct work_struct *work)
+{
+	struct delayed_work *dwork = to_delayed_work(work);
+	struct ufshpb_lu *hpb;
+	struct victim_select_info *lru_info;
+	struct ufshpb_region *rgn;
+	unsigned long flags;
+	LIST_HEAD(expired_list);
+
+	hpb = container_of(dwork, struct ufshpb_lu, ufshpb_read_to_work);
+
+	spin_lock_irqsave(&hpb->rgn_state_lock, flags);
+
+	lru_info = &hpb->lru_info;
+
+	list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) {
+		bool timedout = ktime_after(ktime_get(), rgn->read_timeout);
+
+		if (timedout) {
+			rgn->read_timeout_expiries--;
+			if (is_rgn_dirty(rgn) ||
+			    rgn->read_timeout_expiries == 0)
+				list_add(&rgn->list_expired_rgn, &expired_list);
+			else
+				rgn->read_timeout = ktime_add_ms(ktime_get(),
+							 READ_TO_MS);
+		}
+	}
+
+	spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
+
+	list_for_each_entry(rgn, &expired_list, list_expired_rgn) {
+		list_del_init(&rgn->list_expired_rgn);
+		spin_lock_irqsave(&hpb->rsp_list_lock, flags);
+		ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
+		hpb->stats.rb_inactive_cnt++;
+		spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
+	}
+
+	ufshpb_kick_map_work(hpb);
+
+	schedule_delayed_work(&hpb->ufshpb_read_to_work,
+			      msecs_to_jiffies(POLLING_INTERVAL_MS));
+}
+
 static void ufshpb_add_lru_info(struct victim_select_info *lru_info,
 				struct ufshpb_region *rgn)
 {
 	rgn->rgn_state = HPB_RGN_ACTIVE;
 	list_add_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn);
 	atomic_inc(&lru_info->active_cnt);
+	if (rgn->hpb->is_hcm) {
+		rgn->read_timeout = ktime_add_ms(ktime_get(), READ_TO_MS);
+		rgn->read_timeout_expiries = READ_TO_EXPIRIES;
+	}
 }
 
 static void ufshpb_hit_lru_info(struct victim_select_info *lru_info,
@@ -1813,6 +1865,7 @@ static int ufshpb_alloc_region_tbl(struct ufs_hba *hba, struct ufshpb_lu *hpb)
 
 		INIT_LIST_HEAD(&rgn->list_inact_rgn);
 		INIT_LIST_HEAD(&rgn->list_lru_rgn);
+		INIT_LIST_HEAD(&rgn->list_expired_rgn);
 
 		if (rgn_idx == hpb->rgns_per_lu - 1) {
 			srgn_cnt = ((hpb->srgns_per_lu - 1) %
@@ -1834,6 +1887,7 @@ static int ufshpb_alloc_region_tbl(struct ufs_hba *hba, struct ufshpb_lu *hpb)
 		}
 
 		rgn->rgn_flags = 0;
+		rgn->hpb = hpb;
 	}
 
 	return 0;
@@ -2053,6 +2107,8 @@ static int ufshpb_lu_hpb_init(struct ufs_hba *hba, struct ufshpb_lu *hpb)
 			  ufshpb_normalization_work_handler);
 		INIT_WORK(&hpb->ufshpb_lun_reset_work,
 			  ufshpb_reset_work_handler);
+		INIT_DELAYED_WORK(&hpb->ufshpb_read_to_work,
+				  ufshpb_read_to_handler);
 	}
 
 	hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
@@ -2087,6 +2143,10 @@ static int ufshpb_lu_hpb_init(struct ufs_hba *hba, struct ufshpb_lu *hpb)
 	ufshpb_stat_init(hpb);
 	ufshpb_param_init(hpb);
 
+	if (hpb->is_hcm)
+		schedule_delayed_work(&hpb->ufshpb_read_to_work,
+				      msecs_to_jiffies(POLLING_INTERVAL_MS));
+
 	return 0;
 
 release_pre_req_mempool:
@@ -2154,6 +2214,7 @@ static void ufshpb_discard_rsp_lists(struct ufshpb_lu *hpb)
 static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
 {
 	if (hpb->is_hcm) {
+		cancel_delayed_work_sync(&hpb->ufshpb_read_to_work);
 		cancel_work_sync(&hpb->ufshpb_lun_reset_work);
 		cancel_work_sync(&hpb->ufshpb_normalization_work);
 	}
@@ -2264,6 +2325,10 @@ void ufshpb_resume(struct ufs_hba *hba)
 			continue;
 		ufshpb_set_state(hpb, HPB_PRESENT);
 		ufshpb_kick_map_work(hpb);
+		if (hpb->is_hcm)
+			schedule_delayed_work(&hpb->ufshpb_read_to_work,
+				msecs_to_jiffies(POLLING_INTERVAL_MS));
+
 	}
 }
 
diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
index 37c1b0ea0c0a..b49e9a34267f 100644
--- a/drivers/scsi/ufs/ufshpb.h
+++ b/drivers/scsi/ufs/ufshpb.h
@@ -109,6 +109,7 @@ struct ufshpb_subregion {
 };
 
 struct ufshpb_region {
+	struct ufshpb_lu *hpb;
 	struct ufshpb_subregion *srgn_tbl;
 	enum HPB_RGN_STATE rgn_state;
 	int rgn_idx;
@@ -126,6 +127,10 @@ struct ufshpb_region {
 	/* region reads - for host mode */
 	spinlock_t rgn_lock;
 	unsigned int reads;
+	/* region "cold" timer - for host mode */
+	ktime_t read_timeout;
+	unsigned int read_timeout_expiries;
+	struct list_head list_expired_rgn;
 };
 
 #define for_each_sub_region(rgn, i, srgn)				\
@@ -219,6 +224,7 @@ struct ufshpb_lu {
 	struct victim_select_info lru_info;
 	struct work_struct ufshpb_normalization_work;
 	struct work_struct ufshpb_lun_reset_work;
+	struct delayed_work ufshpb_read_to_work;
 
 	/* pinned region information */
 	u32 lu_pinned_start;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v5 08/10] scsi: ufshpb: Limit the number of inflight map requests
  2021-03-02 13:24 [PATCH v5 00/10] Add Host control mode to HPB Avri Altman
                   ` (6 preceding siblings ...)
  2021-03-02 13:25 ` [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer Avri Altman
@ 2021-03-02 13:25 ` Avri Altman
  2021-03-15  8:31   ` Can Guo
  2021-03-02 13:25 ` [PATCH v5 09/10] scsi: ufshpb: Add support for host control mode Avri Altman
  2021-03-02 13:25 ` [PATCH v5 10/10] scsi: ufshpb: Make host mode parameters configurable Avri Altman
  9 siblings, 1 reply; 58+ messages in thread
From: Avri Altman @ 2021-03-02 13:25 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen, linux-scsi, linux-kernel
  Cc: gregkh, Bart Van Assche, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, cang,
	stanley.chu, Avri Altman

in host control mode the host is the originator of map requests. To not
flood the device with map requests, use a simple throttling mechanism
that limits the number of inflight map requests.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/scsi/ufs/ufshpb.c | 11 +++++++++++
 drivers/scsi/ufs/ufshpb.h |  1 +
 2 files changed, 12 insertions(+)

diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index 89a930e72cff..74da69727340 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -21,6 +21,7 @@
 #define READ_TO_MS 1000
 #define READ_TO_EXPIRIES 100
 #define POLLING_INTERVAL_MS 200
+#define THROTTLE_MAP_REQ_DEFAULT 1
 
 /* memory management */
 static struct kmem_cache *ufshpb_mctx_cache;
@@ -750,6 +751,14 @@ static struct ufshpb_req *ufshpb_get_map_req(struct ufshpb_lu *hpb,
 	struct ufshpb_req *map_req;
 	struct bio *bio;
 
+	if (hpb->is_hcm &&
+	    hpb->num_inflight_map_req >= THROTTLE_MAP_REQ_DEFAULT) {
+		dev_info(&hpb->sdev_ufs_lu->sdev_dev,
+			 "map_req throttle. inflight %d throttle %d",
+			 hpb->num_inflight_map_req, THROTTLE_MAP_REQ_DEFAULT);
+		return NULL;
+	}
+
 	map_req = ufshpb_get_req(hpb, srgn->rgn_idx, REQ_OP_SCSI_IN);
 	if (!map_req)
 		return NULL;
@@ -764,6 +773,7 @@ static struct ufshpb_req *ufshpb_get_map_req(struct ufshpb_lu *hpb,
 
 	map_req->rb.srgn_idx = srgn->srgn_idx;
 	map_req->rb.mctx = srgn->mctx;
+	hpb->num_inflight_map_req++;
 
 	return map_req;
 }
@@ -773,6 +783,7 @@ static void ufshpb_put_map_req(struct ufshpb_lu *hpb,
 {
 	bio_put(map_req->bio);
 	ufshpb_put_req(hpb, map_req);
+	hpb->num_inflight_map_req--;
 }
 
 static int ufshpb_clear_dirty_bitmap(struct ufshpb_lu *hpb,
diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
index b49e9a34267f..d83ab488688a 100644
--- a/drivers/scsi/ufs/ufshpb.h
+++ b/drivers/scsi/ufs/ufshpb.h
@@ -212,6 +212,7 @@ struct ufshpb_lu {
 	struct ufshpb_req *pre_req;
 	int num_inflight_pre_req;
 	int throttle_pre_req;
+	int num_inflight_map_req;
 	struct list_head lh_pre_req_free;
 	int cur_read_id;
 	int pre_req_min_tr_len;
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v5 09/10] scsi: ufshpb: Add support for host control mode
  2021-03-02 13:24 [PATCH v5 00/10] Add Host control mode to HPB Avri Altman
                   ` (7 preceding siblings ...)
  2021-03-02 13:25 ` [PATCH v5 08/10] scsi: ufshpb: Limit the number of inflight map requests Avri Altman
@ 2021-03-02 13:25 ` Avri Altman
  2021-03-02 13:25 ` [PATCH v5 10/10] scsi: ufshpb: Make host mode parameters configurable Avri Altman
  9 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-02 13:25 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen, linux-scsi, linux-kernel
  Cc: gregkh, Bart Van Assche, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, cang,
	stanley.chu, Avri Altman

Support devices that report they are using host control mode.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 drivers/scsi/ufs/ufshpb.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index 74da69727340..7b749b95accb 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -2567,12 +2567,6 @@ void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf)
 	u32 max_hpb_sigle_cmd = 0;
 
 	hpb_dev_info->control_mode = desc_buf[DEVICE_DESC_PARAM_HPB_CONTROL];
-	if (hpb_dev_info->control_mode == HPB_HOST_CONTROL) {
-		dev_err(hba->dev, "%s: host control mode is not supported.\n",
-			__func__);
-		hpb_dev_info->hpb_disabled = true;
-		return;
-	}
 
 	version = get_unaligned_be16(desc_buf + DEVICE_DESC_PARAM_HPB_VER);
 	if ((version != HPB_SUPPORT_VERSION) &&
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* [PATCH v5 10/10] scsi: ufshpb: Make host mode parameters configurable
  2021-03-02 13:24 [PATCH v5 00/10] Add Host control mode to HPB Avri Altman
                   ` (8 preceding siblings ...)
  2021-03-02 13:25 ` [PATCH v5 09/10] scsi: ufshpb: Add support for host control mode Avri Altman
@ 2021-03-02 13:25 ` Avri Altman
  9 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-02 13:25 UTC (permalink / raw)
  To: James E . J . Bottomley, Martin K . Petersen, linux-scsi, linux-kernel
  Cc: gregkh, Bart Van Assche, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, cang,
	stanley.chu, Avri Altman

We can make use of this commit, to elaborate some more of the host
control mode logic, explaining what role play each and every variable.

While at it, allow those parameters to be configurable.

Signed-off-by: Avri Altman <avri.altman@wdc.com>
---
 Documentation/ABI/testing/sysfs-driver-ufs |  74 ++++++
 drivers/scsi/ufs/ufshpb.c                  | 290 +++++++++++++++++++--
 drivers/scsi/ufs/ufshpb.h                  |  20 ++
 3 files changed, 368 insertions(+), 16 deletions(-)

diff --git a/Documentation/ABI/testing/sysfs-driver-ufs b/Documentation/ABI/testing/sysfs-driver-ufs
index 0017eaf89cbe..b91a4d018b3e 100644
--- a/Documentation/ABI/testing/sysfs-driver-ufs
+++ b/Documentation/ABI/testing/sysfs-driver-ufs
@@ -1322,3 +1322,77 @@ Description:	This entry shows the maximum HPB data size for using single HPB
 		===  ========
 
 		The file is read only.
+
+What:		/sys/class/scsi_device/*/device/hpb_param_sysfs/activation_thld
+Date:		February 2021
+Contact:	Avri Altman <avri.altman@wdc.com>
+Description:	In host control mode, reads are the major source of activation
+		trials.  once this threshold hs met, the region is added to the
+		"to-be-activated" list.  Since we reset the read counter upon
+		write, this include sending a rb command updating the region
+		ppn as well.
+
+What:		/sys/class/scsi_device/*/device/hpb_param_sysfs/normalization_factor
+Date:		February 2021
+Contact:	Avri Altman <avri.altman@wdc.com>
+Description:	In host control mode, We think of the regions as "buckets".
+		Those buckets are being filled with reads, and emptied on write.
+		We use entries_per_srgn - the amount of blocks in a subregion as
+		our bucket size.  This applies because HPB1.0 only concern a
+		single-block reads.  Once the bucket size is crossed, we trigger
+		a normalization work - not only to avoid overflow, but mainly
+		because we want to keep those counters normalized, as we are
+		using those reads as a comparative score, to make various decisions.
+		The normalization is dividing (shift right) the read counter by
+		the normalization_factor. If during consecutive normalizations
+		an active region has exhaust its reads - inactivate it.
+
+What:		/sys/class/scsi_device/*/device/hpb_param_sysfs/eviction_thld_enter
+Date:		February 2021
+Contact:	Avri Altman <avri.altman@wdc.com>
+Description:	Region deactivation is often due to the fact that eviction took
+		place: a region become active on the expense of another. This is
+		happening when the max-active-regions limit has crossed.
+		In host mode, eviction is considered an extreme measure. We
+		want to verify that the entering region has enough reads, and
+		the exiting region has much less reads.  eviction_thld_enter is
+		the min reads that a region must have in order to be considered
+		as a candidate to evict other region.
+
+What:		/sys/class/scsi_device/*/device/hpb_param_sysfs/eviction_thld_exit
+Date:		February 2021
+Contact:	Avri Altman <avri.altman@wdc.com>
+Description:	same as above for the exiting region. A region is consider to
+		be a candidate to be evicted, only if it has less reads than
+		eviction_thld_exit.
+
+What:		/sys/class/scsi_device/*/device/hpb_param_sysfs/read_timeout_ms
+Date:		February 2021
+Contact:	Avri Altman <avri.altman@wdc.com>
+Description:	In order not to hang on to “cold” regions, we shall inactivate
+		a region that has no READ access for a predefined amount of
+		time - read_timeout_ms. If read_timeout_ms has expired, and the
+		region is dirty - it is less likely that we can make any use of
+		HPB-READing it.  So we inactivate it.  Still, deactivation has
+		its overhead, and we may still benefit from HPB-READing this
+		region if it is clean - see read_timeout_expiries.
+
+What:		/sys/class/scsi_device/*/device/hpb_param_sysfs/read_timeout_expiries
+Date:		February 2021
+Contact:	Avri Altman <avri.altman@wdc.com>
+Description:	if the region read timeout has expired, but the region is clean,
+		just re-wind its timer for another spin.  Do that as long as it
+		is clean and did not exhaust its read_timeout_expiries threshold.
+
+What:		/sys/class/scsi_device/*/device/hpb_param_sysfs/timeout_polling_interval_ms
+Date:		February 2021
+Contact:	Avri Altman <avri.altman@wdc.com>
+Description:	the frequency in which the delayed worker that checks the
+		read_timeouts is awaken.
+
+What:		/sys/class/scsi_device/*/device/hpb_param_sysfs/inflight_map_req
+Date:		February 2021
+Contact:	Avri Altman <avri.altman@wdc.com>
+Description:	in host control mode the host is the originator of map requests.
+		To not flood the device with map requests, use a simple throttling
+		mechanism that limits the number of inflight map requests.
diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index 7b749b95accb..dce94a069c85 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -17,7 +17,6 @@
 #include "../sd.h"
 
 #define ACTIVATION_THRESHOLD 4 /* 4 IOs */
-#define EVICTION_THRESHOLD (ACTIVATION_THRESHOLD << 6) /* 256 IOs */
 #define READ_TO_MS 1000
 #define READ_TO_EXPIRIES 100
 #define POLLING_INTERVAL_MS 200
@@ -643,7 +642,7 @@ int ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
 		 */
 		spin_lock_irqsave(&rgn->rgn_lock, flags);
 		rgn->reads++;
-		if (rgn->reads == ACTIVATION_THRESHOLD)
+		if (rgn->reads == hpb->params.activation_thld)
 			activate = true;
 		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
 		if (activate ||
@@ -752,10 +751,11 @@ static struct ufshpb_req *ufshpb_get_map_req(struct ufshpb_lu *hpb,
 	struct bio *bio;
 
 	if (hpb->is_hcm &&
-	    hpb->num_inflight_map_req >= THROTTLE_MAP_REQ_DEFAULT) {
+	    hpb->num_inflight_map_req >= hpb->params.inflight_map_req) {
 		dev_info(&hpb->sdev_ufs_lu->sdev_dev,
 			 "map_req throttle. inflight %d throttle %d",
-			 hpb->num_inflight_map_req, THROTTLE_MAP_REQ_DEFAULT);
+			 hpb->num_inflight_map_req,
+			 hpb->params.inflight_map_req);
 		return NULL;
 	}
 
@@ -1045,6 +1045,7 @@ static void ufshpb_read_to_handler(struct work_struct *work)
 	struct victim_select_info *lru_info;
 	struct ufshpb_region *rgn;
 	unsigned long flags;
+	unsigned int poll;
 	LIST_HEAD(expired_list);
 
 	hpb = container_of(dwork, struct ufshpb_lu, ufshpb_read_to_work);
@@ -1063,7 +1064,7 @@ static void ufshpb_read_to_handler(struct work_struct *work)
 				list_add(&rgn->list_expired_rgn, &expired_list);
 			else
 				rgn->read_timeout = ktime_add_ms(ktime_get(),
-							 READ_TO_MS);
+						hpb->params.read_timeout_ms);
 		}
 	}
 
@@ -1079,8 +1080,9 @@ static void ufshpb_read_to_handler(struct work_struct *work)
 
 	ufshpb_kick_map_work(hpb);
 
+	poll = hpb->params.timeout_polling_interval_ms;
 	schedule_delayed_work(&hpb->ufshpb_read_to_work,
-			      msecs_to_jiffies(POLLING_INTERVAL_MS));
+			      msecs_to_jiffies(poll));
 }
 
 static void ufshpb_add_lru_info(struct victim_select_info *lru_info,
@@ -1090,8 +1092,11 @@ static void ufshpb_add_lru_info(struct victim_select_info *lru_info,
 	list_add_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn);
 	atomic_inc(&lru_info->active_cnt);
 	if (rgn->hpb->is_hcm) {
-		rgn->read_timeout = ktime_add_ms(ktime_get(), READ_TO_MS);
-		rgn->read_timeout_expiries = READ_TO_EXPIRIES;
+		rgn->read_timeout =
+			ktime_add_ms(ktime_get(),
+				     rgn->hpb->params.read_timeout_ms);
+		rgn->read_timeout_expiries =
+			rgn->hpb->params.read_timeout_expiries;
 	}
 }
 
@@ -1120,7 +1125,8 @@ static struct ufshpb_region *ufshpb_victim_lru_info(struct ufshpb_lu *hpb)
 		 * in host control mode, verify that the exiting region
 		 * has less reads
 		 */
-		if (hpb->is_hcm && rgn->reads > (EVICTION_THRESHOLD >> 1))
+		if (hpb->is_hcm &&
+		    rgn->reads > hpb->params.eviction_thld_exit)
 			continue;
 
 		victim_rgn = rgn;
@@ -1351,7 +1357,8 @@ static int ufshpb_add_region(struct ufshpb_lu *hpb, struct ufshpb_region *rgn)
 			 * in host control mode, verify that the entering
 			 * region has enough reads
 			 */
-			if (hpb->is_hcm && rgn->reads < EVICTION_THRESHOLD) {
+			if (hpb->is_hcm &&
+			    rgn->reads < hpb->params.eviction_thld_enter) {
 				ret = -EACCES;
 				goto out;
 			}
@@ -1696,14 +1703,16 @@ static void ufshpb_normalization_work_handler(struct work_struct *work)
 	struct ufshpb_lu *hpb;
 	int rgn_idx;
 	unsigned long flags;
+	u8 factor;
 
 	hpb = container_of(work, struct ufshpb_lu, ufshpb_normalization_work);
+	factor = hpb->params.normalization_factor;
 
 	for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) {
 		struct ufshpb_region *rgn = hpb->rgn_tbl + rgn_idx;
 
 		spin_lock_irqsave(&rgn->rgn_lock, flags);
-		rgn->reads = (rgn->reads >> 1);
+		rgn->reads = (rgn->reads >> factor);
 		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
 
 		if (rgn->rgn_state != HPB_RGN_ACTIVE || rgn->reads)
@@ -2022,8 +2031,248 @@ requeue_timeout_ms_store(struct device *dev, struct device_attribute *attr,
 }
 static DEVICE_ATTR_RW(requeue_timeout_ms);
 
+ufshpb_sysfs_param_show_func(activation_thld);
+static ssize_t
+activation_thld_store(struct device *dev, struct device_attribute *attr,
+		      const char *buf, size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev);
+	int val;
+
+	if (!hpb)
+		return -ENODEV;
+
+	if (!hpb->is_hcm)
+		return -EOPNOTSUPP;
+
+	if (kstrtouint(buf, 0, &val))
+		return -EINVAL;
+
+	if (val <= 0)
+		return -EINVAL;
+
+	hpb->params.activation_thld = val;
+
+	return count;
+}
+static DEVICE_ATTR_RW(activation_thld);
+
+ufshpb_sysfs_param_show_func(normalization_factor);
+static ssize_t
+normalization_factor_store(struct device *dev, struct device_attribute *attr,
+			   const char *buf, size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev);
+	int val;
+
+	if (!hpb)
+		return -ENODEV;
+
+	if (!hpb->is_hcm)
+		return -EOPNOTSUPP;
+
+	if (kstrtouint(buf, 0, &val))
+		return -EINVAL;
+
+	if (val <= 0 || val > ilog2(hpb->entries_per_srgn))
+		return -EINVAL;
+
+	hpb->params.normalization_factor = val;
+
+	return count;
+}
+static DEVICE_ATTR_RW(normalization_factor);
+
+ufshpb_sysfs_param_show_func(eviction_thld_enter);
+static ssize_t
+eviction_thld_enter_store(struct device *dev, struct device_attribute *attr,
+			  const char *buf, size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev);
+	int val;
+
+	if (!hpb)
+		return -ENODEV;
+
+	if (!hpb->is_hcm)
+		return -EOPNOTSUPP;
+
+	if (kstrtouint(buf, 0, &val))
+		return -EINVAL;
+
+	if (val <= hpb->params.eviction_thld_exit)
+		return -EINVAL;
+
+	hpb->params.eviction_thld_enter = val;
+
+	return count;
+}
+static DEVICE_ATTR_RW(eviction_thld_enter);
+
+ufshpb_sysfs_param_show_func(eviction_thld_exit);
+static ssize_t
+eviction_thld_exit_store(struct device *dev, struct device_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev);
+	int val;
+
+	if (!hpb)
+		return -ENODEV;
+
+	if (!hpb->is_hcm)
+		return -EOPNOTSUPP;
+
+	if (kstrtouint(buf, 0, &val))
+		return -EINVAL;
+
+	if (val <= hpb->params.activation_thld)
+		return -EINVAL;
+
+	hpb->params.eviction_thld_exit = val;
+
+	return count;
+}
+static DEVICE_ATTR_RW(eviction_thld_exit);
+
+ufshpb_sysfs_param_show_func(read_timeout_ms);
+static ssize_t
+read_timeout_ms_store(struct device *dev, struct device_attribute *attr,
+		      const char *buf, size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev);
+	int val;
+
+	if (!hpb)
+		return -ENODEV;
+
+	if (!hpb->is_hcm)
+		return -EOPNOTSUPP;
+
+	if (kstrtouint(buf, 0, &val))
+		return -EINVAL;
+
+	/* read_timeout >> timeout_polling_interval */
+	if (val < hpb->params.timeout_polling_interval_ms * 2)
+		return -EINVAL;
+
+	hpb->params.read_timeout_ms = val;
+
+	return count;
+}
+static DEVICE_ATTR_RW(read_timeout_ms);
+
+ufshpb_sysfs_param_show_func(read_timeout_expiries);
+static ssize_t
+read_timeout_expiries_store(struct device *dev, struct device_attribute *attr,
+			    const char *buf, size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev);
+	int val;
+
+	if (!hpb)
+		return -ENODEV;
+
+	if (!hpb->is_hcm)
+		return -EOPNOTSUPP;
+
+	if (kstrtouint(buf, 0, &val))
+		return -EINVAL;
+
+	if (val <= 0)
+		return -EINVAL;
+
+	hpb->params.read_timeout_expiries = val;
+
+	return count;
+}
+static DEVICE_ATTR_RW(read_timeout_expiries);
+
+ufshpb_sysfs_param_show_func(timeout_polling_interval_ms);
+static ssize_t
+timeout_polling_interval_ms_store(struct device *dev,
+				  struct device_attribute *attr,
+				  const char *buf, size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev);
+	int val;
+
+	if (!hpb)
+		return -ENODEV;
+
+	if (!hpb->is_hcm)
+		return -EOPNOTSUPP;
+
+	if (kstrtouint(buf, 0, &val))
+		return -EINVAL;
+
+	/* timeout_polling_interval << read_timeout */
+	if (val <= 0 || val > hpb->params.read_timeout_ms / 2)
+		return -EINVAL;
+
+	hpb->params.timeout_polling_interval_ms = val;
+
+	return count;
+}
+static DEVICE_ATTR_RW(timeout_polling_interval_ms);
+
+ufshpb_sysfs_param_show_func(inflight_map_req);
+static ssize_t inflight_map_req_store(struct device *dev,
+				      struct device_attribute *attr,
+				      const char *buf, size_t count)
+{
+	struct scsi_device *sdev = to_scsi_device(dev);
+	struct ufshpb_lu *hpb = ufshpb_get_hpb_data(sdev);
+	int val;
+
+	if (!hpb)
+		return -ENODEV;
+
+	if (!hpb->is_hcm)
+		return -EOPNOTSUPP;
+
+	if (kstrtouint(buf, 0, &val))
+		return -EINVAL;
+
+	if (val <= 0 || val > hpb->sdev_ufs_lu->queue_depth - 1)
+		return -EINVAL;
+
+	hpb->params.inflight_map_req = val;
+
+	return count;
+}
+static DEVICE_ATTR_RW(inflight_map_req);
+
+
+static void ufshpb_hcm_param_init(struct ufshpb_lu *hpb)
+{
+	hpb->params.activation_thld = ACTIVATION_THRESHOLD;
+	hpb->params.normalization_factor = 1;
+	hpb->params.eviction_thld_enter = (ACTIVATION_THRESHOLD << 6);
+	hpb->params.eviction_thld_exit = (ACTIVATION_THRESHOLD << 5);
+	hpb->params.read_timeout_ms = READ_TO_MS;
+	hpb->params.read_timeout_expiries = READ_TO_EXPIRIES;
+	hpb->params.timeout_polling_interval_ms = POLLING_INTERVAL_MS;
+	hpb->params.inflight_map_req = THROTTLE_MAP_REQ_DEFAULT;
+}
+
 static struct attribute *hpb_dev_param_attrs[] = {
 	&dev_attr_requeue_timeout_ms.attr,
+	&dev_attr_activation_thld.attr,
+	&dev_attr_normalization_factor.attr,
+	&dev_attr_eviction_thld_enter.attr,
+	&dev_attr_eviction_thld_exit.attr,
+	&dev_attr_read_timeout_ms.attr,
+	&dev_attr_read_timeout_expiries.attr,
+	&dev_attr_timeout_polling_interval_ms.attr,
+	&dev_attr_inflight_map_req.attr,
 	NULL,
 };
 
@@ -2098,6 +2347,8 @@ static void ufshpb_stat_init(struct ufshpb_lu *hpb)
 static void ufshpb_param_init(struct ufshpb_lu *hpb)
 {
 	hpb->params.requeue_timeout_ms = HPB_REQUEUE_TIME_MS;
+	if (hpb->is_hcm)
+		ufshpb_hcm_param_init(hpb);
 }
 
 static int ufshpb_lu_hpb_init(struct ufs_hba *hba, struct ufshpb_lu *hpb)
@@ -2154,9 +2405,13 @@ static int ufshpb_lu_hpb_init(struct ufs_hba *hba, struct ufshpb_lu *hpb)
 	ufshpb_stat_init(hpb);
 	ufshpb_param_init(hpb);
 
-	if (hpb->is_hcm)
+	if (hpb->is_hcm) {
+		unsigned int poll;
+
+		poll = hpb->params.timeout_polling_interval_ms;
 		schedule_delayed_work(&hpb->ufshpb_read_to_work,
-				      msecs_to_jiffies(POLLING_INTERVAL_MS));
+				      msecs_to_jiffies(poll));
+	}
 
 	return 0;
 
@@ -2336,10 +2591,13 @@ void ufshpb_resume(struct ufs_hba *hba)
 			continue;
 		ufshpb_set_state(hpb, HPB_PRESENT);
 		ufshpb_kick_map_work(hpb);
-		if (hpb->is_hcm)
-			schedule_delayed_work(&hpb->ufshpb_read_to_work,
-				msecs_to_jiffies(POLLING_INTERVAL_MS));
+		if (hpb->is_hcm) {
+			unsigned int poll =
+				hpb->params.timeout_polling_interval_ms;
 
+			schedule_delayed_work(&hpb->ufshpb_read_to_work,
+				msecs_to_jiffies(poll));
+		}
 	}
 }
 
diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
index d83ab488688a..91151593faad 100644
--- a/drivers/scsi/ufs/ufshpb.h
+++ b/drivers/scsi/ufs/ufshpb.h
@@ -180,8 +180,28 @@ struct victim_select_info {
 	atomic_t active_cnt;
 };
 
+/**
+ * ufshpb_params - ufs hpb parameters
+ * @requeue_timeout_ms - requeue threshold of wb command (0x2)
+ * @activation_thld - min reads [IOs] to activate/update a region
+ * @normalization_factor - shift right the region's reads
+ * @eviction_thld_enter - min reads [IOs] for the entering region in eviction
+ * @eviction_thld_exit - max reads [IOs] for the exiting region in eviction
+ * @read_timeout_ms - timeout [ms] from the last read IO to the region
+ * @read_timeout_expiries - amount of allowable timeout expireis
+ * @timeout_polling_interval_ms - frequency in which timeouts are checked
+ * @inflight_map_req - number of inflight map requests
+ */
 struct ufshpb_params {
 	unsigned int requeue_timeout_ms;
+	unsigned int activation_thld;
+	unsigned int normalization_factor;
+	unsigned int eviction_thld_enter;
+	unsigned int eviction_thld_exit;
+	unsigned int read_timeout_ms;
+	unsigned int read_timeout_expiries;
+	unsigned int timeout_polling_interval_ms;
+	unsigned int inflight_map_req;
 };
 
 struct ufshpb_stats {
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter
  2021-03-02 13:24 ` [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter Avri Altman
@ 2021-03-11  7:52   ` Can Guo
  2021-03-11  8:04     ` Avri Altman
  2021-03-15  3:16   ` Can Guo
  2021-03-15  8:40   ` Can Guo
  2 siblings, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-11  7:52 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

Hi Avri,

On 2021-03-02 21:24, Avri Altman wrote:
> In host control mode, reads are the major source of activation trials.
> Keep track of those reads counters, for both active as well inactive
> regions.
> 
> We reset the read counter upon write - we are only interested in 
> "clean"
> reads.  less intuitive however, is that we also reset it upon region's
> deactivation.  Region deactivation is often due to the fact that
> eviction took place: a region become active on the expense of another.
> This is happening when the max-active-regions limit has crossed. If we
> don’t reset the counter, we will trigger a lot of trashing of the HPB
> database, since few reads (or even one) to the region that was
> deactivated, will trigger a re-activation trial.
> 
> Keep those counters normalized, as we are using those reads as a
> comparative score, to make various decisions.
> If during consecutive normalizations an active region has exhaust its
> reads - inactivate it.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 102 ++++++++++++++++++++++++++++++++------
>  drivers/scsi/ufs/ufshpb.h |   5 ++
>  2 files changed, 92 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index 044fec9854a0..a8f8d13af21a 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -16,6 +16,8 @@
>  #include "ufshpb.h"
>  #include "../sd.h"
> 
> +#define ACTIVATION_THRESHOLD 4 /* 4 IOs */

Can this param be added as a sysfs entry?

Thanks,
Can Guo

> +
>  /* memory management */
>  static struct kmem_cache *ufshpb_mctx_cache;
>  static mempool_t *ufshpb_mctx_pool;
> @@ -554,6 +556,21 @@ static int ufshpb_issue_pre_req(struct ufshpb_lu
> *hpb, struct scsi_cmnd *cmd,
>  	return ret;
>  }
> 
> +static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int 
> rgn_idx,
> +				      int srgn_idx)
> +{
> +	struct ufshpb_region *rgn;
> +	struct ufshpb_subregion *srgn;
> +
> +	rgn = hpb->rgn_tbl + rgn_idx;
> +	srgn = rgn->srgn_tbl + srgn_idx;
> +
> +	list_del_init(&rgn->list_inact_rgn);
> +
> +	if (list_empty(&srgn->list_act_srgn))
> +		list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn);
> +}
> +
>  /*
>   * This function will set up HPB read command using host-side L2P map 
> data.
>   */
> @@ -600,12 +617,44 @@ int ufshpb_prep(struct ufs_hba *hba, struct
> ufshcd_lrb *lrbp)
>  		ufshpb_set_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
>  				 transfer_len);
>  		spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> +
> +		if (hpb->is_hcm) {
> +			spin_lock_irqsave(&rgn->rgn_lock, flags);
> +			rgn->reads = 0;
> +			spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +		}
> +
>  		return 0;
>  	}
> 
>  	if (!ufshpb_is_support_chunk(hpb, transfer_len))
>  		return 0;
> 
> +	if (hpb->is_hcm) {
> +		bool activate = false;
> +		/*
> +		 * in host control mode, reads are the main source for
> +		 * activation trials.
> +		 */
> +		spin_lock_irqsave(&rgn->rgn_lock, flags);
> +		rgn->reads++;
> +		if (rgn->reads == ACTIVATION_THRESHOLD)
> +			activate = true;
> +		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +		if (activate) {
> +			spin_lock_irqsave(&hpb->rsp_list_lock, flags);
> +			ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
> +			hpb->stats.rb_active_cnt++;
> +			spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> +			dev_dbg(&hpb->sdev_ufs_lu->sdev_dev,
> +				"activate region %d-%d\n", rgn_idx, srgn_idx);
> +		}
> +
> +		/* keep those counters normalized */
> +		if (rgn->reads > hpb->entries_per_srgn)
> +			schedule_work(&hpb->ufshpb_normalization_work);
> +	}
> +
>  	spin_lock_irqsave(&hpb->rgn_state_lock, flags);
>  	if (ufshpb_test_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
>  				   transfer_len)) {
> @@ -745,21 +794,6 @@ static int ufshpb_clear_dirty_bitmap(struct 
> ufshpb_lu *hpb,
>  	return 0;
>  }
> 
> -static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int 
> rgn_idx,
> -				      int srgn_idx)
> -{
> -	struct ufshpb_region *rgn;
> -	struct ufshpb_subregion *srgn;
> -
> -	rgn = hpb->rgn_tbl + rgn_idx;
> -	srgn = rgn->srgn_tbl + srgn_idx;
> -
> -	list_del_init(&rgn->list_inact_rgn);
> -
> -	if (list_empty(&srgn->list_act_srgn))
> -		list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn);
> -}
> -
>  static void ufshpb_update_inactive_info(struct ufshpb_lu *hpb, int 
> rgn_idx)
>  {
>  	struct ufshpb_region *rgn;
> @@ -1079,6 +1113,14 @@ static void __ufshpb_evict_region(struct 
> ufshpb_lu *hpb,
> 
>  	ufshpb_cleanup_lru_info(lru_info, rgn);
> 
> +	if (hpb->is_hcm) {
> +		unsigned long flags;
> +
> +		spin_lock_irqsave(&rgn->rgn_lock, flags);
> +		rgn->reads = 0;
> +		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +	}
> +
>  	for_each_sub_region(rgn, srgn_idx, srgn)
>  		ufshpb_purge_active_subregion(hpb, srgn);
>  }
> @@ -1523,6 +1565,31 @@ static void
> ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
>  	spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>  }
> 
> +static void ufshpb_normalization_work_handler(struct work_struct 
> *work)
> +{
> +	struct ufshpb_lu *hpb;
> +	int rgn_idx;
> +	unsigned long flags;
> +
> +	hpb = container_of(work, struct ufshpb_lu, 
> ufshpb_normalization_work);
> +
> +	for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) {
> +		struct ufshpb_region *rgn = hpb->rgn_tbl + rgn_idx;
> +
> +		spin_lock_irqsave(&rgn->rgn_lock, flags);
> +		rgn->reads = (rgn->reads >> 1);
> +		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +
> +		if (rgn->rgn_state != HPB_RGN_ACTIVE || rgn->reads)
> +			continue;
> +
> +		/* if region is active but has no reads - inactivate it */
> +		spin_lock(&hpb->rsp_list_lock);
> +		ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
> +		spin_unlock(&hpb->rsp_list_lock);
> +	}
> +}
> +
>  static void ufshpb_map_work_handler(struct work_struct *work)
>  {
>  	struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu, 
> map_work);
> @@ -1913,6 +1980,9 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> *hba, struct ufshpb_lu *hpb)
>  	INIT_LIST_HEAD(&hpb->list_hpb_lu);
> 
>  	INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> +	if (hpb->is_hcm)
> +		INIT_WORK(&hpb->ufshpb_normalization_work,
> +			  ufshpb_normalization_work_handler);
> 
>  	hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
>  			  sizeof(struct ufshpb_req), 0, 0, NULL);
> @@ -2012,6 +2082,8 @@ static void ufshpb_discard_rsp_lists(struct
> ufshpb_lu *hpb)
> 
>  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>  {
> +	if (hpb->is_hcm)
> +		cancel_work_sync(&hpb->ufshpb_normalization_work);
>  	cancel_work_sync(&hpb->map_work);
>  }
> 
> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> index 8119b1a3d1e5..bd4308010466 100644
> --- a/drivers/scsi/ufs/ufshpb.h
> +++ b/drivers/scsi/ufs/ufshpb.h
> @@ -121,6 +121,10 @@ struct ufshpb_region {
>  	struct list_head list_lru_rgn;
>  	unsigned long rgn_flags;
>  #define RGN_FLAG_DIRTY 0
> +
> +	/* region reads - for host mode */
> +	spinlock_t rgn_lock;
> +	unsigned int reads;
>  };
> 
>  #define for_each_sub_region(rgn, i, srgn)				\
> @@ -211,6 +215,7 @@ struct ufshpb_lu {
> 
>  	/* for selecting victim */
>  	struct victim_select_info lru_info;
> +	struct work_struct ufshpb_normalization_work;
> 
>  	/* pinned region information */
>  	u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 04/10] scsi: ufshpb: Make eviction depends on region's reads
  2021-03-02 13:24 ` [PATCH v5 04/10] scsi: ufshpb: Make eviction depends on region's reads Avri Altman
@ 2021-03-11  7:53   ` Can Guo
  2021-03-11  8:06     ` Avri Altman
  2021-03-15  8:30   ` Can Guo
  1 sibling, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-11  7:53 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

Hi Avri,

On 2021-03-02 21:24, Avri Altman wrote:
> In host mode, eviction is considered an extreme measure.
> verify that the entering region has enough reads, and the exiting
> region has much less reads.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 20 +++++++++++++++++++-
>  1 file changed, 19 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index a8f8d13af21a..6f4fd22eaf2f 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -17,6 +17,7 @@
>  #include "../sd.h"
> 
>  #define ACTIVATION_THRESHOLD 4 /* 4 IOs */
> +#define EVICTION_THRESHOLD (ACTIVATION_THRESHOLD << 6) /* 256 IOs */

Same here, can this be added as a sysfs entry?

Thanks,
Can Guo.

> 
>  /* memory management */
>  static struct kmem_cache *ufshpb_mctx_cache;
> @@ -1050,6 +1051,13 @@ static struct ufshpb_region
> *ufshpb_victim_lru_info(struct ufshpb_lu *hpb)
>  		if (ufshpb_check_srgns_issue_state(hpb, rgn))
>  			continue;
> 
> +		/*
> +		 * in host control mode, verify that the exiting region
> +		 * has less reads
> +		 */
> +		if (hpb->is_hcm && rgn->reads > (EVICTION_THRESHOLD >> 1))
> +			continue;
> +
>  		victim_rgn = rgn;
>  		break;
>  	}
> @@ -1235,7 +1243,7 @@ static int ufshpb_issue_map_req(struct ufshpb_lu 
> *hpb,
> 
>  static int ufshpb_add_region(struct ufshpb_lu *hpb, struct 
> ufshpb_region *rgn)
>  {
> -	struct ufshpb_region *victim_rgn;
> +	struct ufshpb_region *victim_rgn = NULL;
>  	struct victim_select_info *lru_info = &hpb->lru_info;
>  	unsigned long flags;
>  	int ret = 0;
> @@ -1263,6 +1271,16 @@ static int ufshpb_add_region(struct ufshpb_lu
> *hpb, struct ufshpb_region *rgn)
>  			 * because the device could detect this region
>  			 * by not issuing HPB_READ
>  			 */
> +
> +			/*
> +			 * in host control mode, verify that the entering
> +			 * region has enough reads
> +			 */
> +			if (hpb->is_hcm && rgn->reads < EVICTION_THRESHOLD) {
> +				ret = -EACCES;
> +				goto out;
> +			}
> +
>  			victim_rgn = ufshpb_victim_lru_info(hpb);
>  			if (!victim_rgn) {
>  				dev_warn(&hpb->sdev_ufs_lu->sdev_dev,

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter
  2021-03-11  7:52   ` Can Guo
@ 2021-03-11  8:04     ` Avri Altman
  2021-03-11  8:07       ` Can Guo
  0 siblings, 1 reply; 58+ messages in thread
From: Avri Altman @ 2021-03-11  8:04 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> > diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> > index 044fec9854a0..a8f8d13af21a 100644
> > --- a/drivers/scsi/ufs/ufshpb.c
> > +++ b/drivers/scsi/ufs/ufshpb.c
> > @@ -16,6 +16,8 @@
> >  #include "ufshpb.h"
> >  #include "../sd.h"
> >
> > +#define ACTIVATION_THRESHOLD 4 /* 4 IOs */
> 
> Can this param be added as a sysfs entry?
Yes.
Daejun asked me that as well, so the last patch makes all logic parameter configurable.

Thanks,
Avri

> 
> Thanks,
> Can Guo

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 04/10] scsi: ufshpb: Make eviction depends on region's reads
  2021-03-11  7:53   ` Can Guo
@ 2021-03-11  8:06     ` Avri Altman
  0 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-11  8:06 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> > diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> > index a8f8d13af21a..6f4fd22eaf2f 100644
> > --- a/drivers/scsi/ufs/ufshpb.c
> > +++ b/drivers/scsi/ufs/ufshpb.c
> > @@ -17,6 +17,7 @@
> >  #include "../sd.h"
> >
> >  #define ACTIVATION_THRESHOLD 4 /* 4 IOs */
> > +#define EVICTION_THRESHOLD (ACTIVATION_THRESHOLD << 6) /* 256 IOs
> */
> 
> Same here, can this be added as a sysfs entry?
Yes.  Please see last patch.

Thanks,
Avri

> 
> Thanks,
> Can Guo.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter
  2021-03-11  8:04     ` Avri Altman
@ 2021-03-11  8:07       ` Can Guo
  0 siblings, 0 replies; 58+ messages in thread
From: Can Guo @ 2021-03-11  8:07 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-11 16:04, Avri Altman wrote:
>> > diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>> > index 044fec9854a0..a8f8d13af21a 100644
>> > --- a/drivers/scsi/ufs/ufshpb.c
>> > +++ b/drivers/scsi/ufs/ufshpb.c
>> > @@ -16,6 +16,8 @@
>> >  #include "ufshpb.h"
>> >  #include "../sd.h"
>> >
>> > +#define ACTIVATION_THRESHOLD 4 /* 4 IOs */
>> 
>> Can this param be added as a sysfs entry?
> Yes.
> Daejun asked me that as well, so the last patch makes all logic
> parameter configurable.
> 
> Thanks,
> Avri
> 

Ok, thanks. I haven't reach the last one, absorbing them one by one.

Can Guo.

>> 
>> Thanks,
>> Can Guo

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
  2021-03-02 13:24 ` [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode Avri Altman
@ 2021-03-11  8:20   ` Can Guo
  2021-03-11  9:03     ` Avri Altman
  2021-03-15  4:02   ` Can Guo
  1 sibling, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-11  8:20 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-02 21:24, Avri Altman wrote:
> I host mode, the host is expected to send HPB-WRITE-BUFFER with

In host mode,

> buffer-id = 0x1 when it inactivates a region.
> 
> Use the map-requests pool as there is no point in assigning a
> designated cache for umap-requests.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
>  drivers/scsi/ufs/ufshpb.h |  1 +
>  2 files changed, 15 insertions(+)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index 6f4fd22eaf2f..0744feb4d484 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct ufshpb_lu 
> *hpb,
> 
>  	blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_umap_req_compl_fn);
> 
> +	hpb->stats.umap_req_cnt++;
>  	return 0;
>  }
> 
> @@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct 
> ufshpb_lu *hpb,
>  	return -EAGAIN;
>  }
> 
> +static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
> +					struct ufshpb_region *rgn)
> +{
> +	return ufshpb_issue_umap_req(hpb, rgn);
> +}
> +
>  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
>  {
>  	return ufshpb_issue_umap_req(hpb, NULL);
> @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct 
> ufshpb_lu *hpb,
>  	struct ufshpb_subregion *srgn;
>  	int srgn_idx;
> 
> +

No need of this blank line.

Regards,
Can Guo.

> +	if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))
> +		return;
> +
>  	lru_info = &hpb->lru_info;
> 
>  	dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n", 
> rgn->rgn_idx);
> @@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
>  ufshpb_sysfs_attr_show_func(rb_active_cnt);
>  ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
>  ufshpb_sysfs_attr_show_func(map_req_cnt);
> +ufshpb_sysfs_attr_show_func(umap_req_cnt);
> 
>  static struct attribute *hpb_dev_stat_attrs[] = {
>  	&dev_attr_hit_cnt.attr,
> @@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[] = {
>  	&dev_attr_rb_active_cnt.attr,
>  	&dev_attr_rb_inactive_cnt.attr,
>  	&dev_attr_map_req_cnt.attr,
> +	&dev_attr_umap_req_cnt.attr,
>  	NULL,
>  };
> 
> @@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu 
> *hpb)
>  	hpb->stats.rb_active_cnt = 0;
>  	hpb->stats.rb_inactive_cnt = 0;
>  	hpb->stats.map_req_cnt = 0;
> +	hpb->stats.umap_req_cnt = 0;
>  }
> 
>  static void ufshpb_param_init(struct ufshpb_lu *hpb)
> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> index bd4308010466..84598a317897 100644
> --- a/drivers/scsi/ufs/ufshpb.h
> +++ b/drivers/scsi/ufs/ufshpb.h
> @@ -186,6 +186,7 @@ struct ufshpb_stats {
>  	u64 rb_inactive_cnt;
>  	u64 map_req_cnt;
>  	u64 pre_req_cnt;
> +	u64 umap_req_cnt;
>  };
> 
>  struct ufshpb_lu {

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
  2021-03-11  8:20   ` Can Guo
@ 2021-03-11  9:03     ` Avri Altman
  0 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-11  9:03 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> 
> On 2021-03-02 21:24, Avri Altman wrote:
> > I host mode, the host is expected to send HPB-WRITE-BUFFER with
> 
> In host mode,
Done.

> >  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
> >  {
> >       return ufshpb_issue_umap_req(hpb, NULL);
> > @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct
> > ufshpb_lu *hpb,
> >       struct ufshpb_subregion *srgn;
> >       int srgn_idx;
> >
> > +
> 
> No need of this blank line.
Done.

Thanks,
Avri

> 
> Regards,
> Can Guo.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-02 13:24 ` [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response Avri Altman
@ 2021-03-15  1:34   ` Can Guo
  2021-03-15  6:40     ` Can Guo
  2021-03-15  7:42     ` Avri Altman
  2021-03-17 10:56   ` Can Guo
  1 sibling, 2 replies; 58+ messages in thread
From: Can Guo @ 2021-03-15  1:34 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-02 21:24, Avri Altman wrote:
> The spec does not define what is the host's recommended response when
> the device send hpb dev reset response (oper 0x2).
> 
> We will update all active hpb regions: mark them and do that on the 
> next
> read.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 47 ++++++++++++++++++++++++++++++++++++---
>  drivers/scsi/ufs/ufshpb.h |  2 ++
>  2 files changed, 46 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index 0744feb4d484..0034fa03fdc6 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -642,7 +642,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct
> ufshcd_lrb *lrbp)
>  		if (rgn->reads == ACTIVATION_THRESHOLD)
>  			activate = true;
>  		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> -		if (activate) {
> +		if (activate ||
> +		    test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) {
>  			spin_lock_irqsave(&hpb->rsp_list_lock, flags);
>  			ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
>  			hpb->stats.rb_active_cnt++;
> @@ -1480,6 +1481,20 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba,
> struct ufshcd_lrb *lrbp)
>  	case HPB_RSP_DEV_RESET:
>  		dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
>  			 "UFS device lost HPB information during PM.\n");
> +
> +		if (hpb->is_hcm) {
> +			struct scsi_device *sdev;
                         bool need_reset = false;
> +
> +			__shost_for_each_device(sdev, hba->host) {
> +				struct ufshpb_lu *h = sdev->hostdata;
> +
> +				if (!h)
> +					continue;
> +
> +				need_reset = true;
> +			}

                         if (need_reset)
                             schedule_work(&hpb->ufshpb_lun_reset_work);

At last, scheduling only one reset work shall be enough, otherwise 
multiple
reset work can be flying in parallel, so maybe above changes?

> +		}
> +
>  		break;
>  	default:
>  		dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
> @@ -1594,6 +1609,25 @@ static void
> ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
>  	spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>  }
> 
> +static void ufshpb_reset_work_handler(struct work_struct *work)
> +{
> +	struct ufshpb_lu *hpb;

         struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu, 
ufshpb_lun_reset_work);

> +	struct victim_select_info *lru_info;

         struct victim_select_info *lru_info = &hpb->lru_info;

This can save some lines.

Thanks,
Can Guo.

> +	struct ufshpb_region *rgn;
> +	unsigned long flags;
> +
> +	spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> +
> +	list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
> +		set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
> +
> +	spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> +}
> +
>  static void ufshpb_normalization_work_handler(struct work_struct 
> *work)
>  {
>  	struct ufshpb_lu *hpb;
> @@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct
> ufs_hba *hba, struct ufshpb_lu *hpb)
>  		} else {
>  			rgn->rgn_state = HPB_RGN_INACTIVE;
>  		}
> +
> +		rgn->rgn_flags = 0;
>  	}
> 
>  	return 0;
> @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> *hba, struct ufshpb_lu *hpb)
>  	INIT_LIST_HEAD(&hpb->list_hpb_lu);
> 
>  	INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> -	if (hpb->is_hcm)
> +	if (hpb->is_hcm) {
>  		INIT_WORK(&hpb->ufshpb_normalization_work,
>  			  ufshpb_normalization_work_handler);
> +		INIT_WORK(&hpb->ufshpb_lun_reset_work,
> +			  ufshpb_reset_work_handler);
> +	}
> 
>  	hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
>  			  sizeof(struct ufshpb_req), 0, 0, NULL);
> @@ -2114,8 +2153,10 @@ static void ufshpb_discard_rsp_lists(struct
> ufshpb_lu *hpb)
> 
>  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>  {
> -	if (hpb->is_hcm)
> +	if (hpb->is_hcm) {
> +		cancel_work_sync(&hpb->ufshpb_lun_reset_work);
>  		cancel_work_sync(&hpb->ufshpb_normalization_work);
> +	}
>  	cancel_work_sync(&hpb->map_work);
>  }
> 
> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> index 84598a317897..37c1b0ea0c0a 100644
> --- a/drivers/scsi/ufs/ufshpb.h
> +++ b/drivers/scsi/ufs/ufshpb.h
> @@ -121,6 +121,7 @@ struct ufshpb_region {
>  	struct list_head list_lru_rgn;
>  	unsigned long rgn_flags;
>  #define RGN_FLAG_DIRTY 0
> +#define RGN_FLAG_UPDATE 1
> 
>  	/* region reads - for host mode */
>  	spinlock_t rgn_lock;
> @@ -217,6 +218,7 @@ struct ufshpb_lu {
>  	/* for selecting victim */
>  	struct victim_select_info lru_info;
>  	struct work_struct ufshpb_normalization_work;
> +	struct work_struct ufshpb_lun_reset_work;
> 
>  	/* pinned region information */
>  	u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer
  2021-03-02 13:25 ` [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer Avri Altman
@ 2021-03-15  1:37   ` Can Guo
  2021-03-15  7:54     ` Avri Altman
  2021-03-15  9:36   ` Can Guo
  1 sibling, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-15  1:37 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-02 21:25, Avri Altman wrote:
> In order not to hang on to “cold” regions, we shall inactivate a
> region that has no READ access for a predefined amount of time -
> READ_TO_MS. For that purpose we shall monitor the active regions list,
> polling it on every POLLING_INTERVAL_MS. On timeout expiry we shall add
> the region to the "to-be-inactivated" list, unless it is clean and did
> not exhaust its READ_TO_EXPIRIES - another parameter.
> 
> All this does not apply to pinned regions.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 65 +++++++++++++++++++++++++++++++++++++++
>  drivers/scsi/ufs/ufshpb.h |  6 ++++
>  2 files changed, 71 insertions(+)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index 0034fa03fdc6..89a930e72cff 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -18,6 +18,9 @@
> 
>  #define ACTIVATION_THRESHOLD 4 /* 4 IOs */
>  #define EVICTION_THRESHOLD (ACTIVATION_THRESHOLD << 6) /* 256 IOs */
> +#define READ_TO_MS 1000
> +#define READ_TO_EXPIRIES 100
> +#define POLLING_INTERVAL_MS 200
> 
>  /* memory management */
>  static struct kmem_cache *ufshpb_mctx_cache;
> @@ -1024,12 +1027,61 @@ static int
> ufshpb_check_srgns_issue_state(struct ufshpb_lu *hpb,
>  	return 0;
>  }
> 
> +static void ufshpb_read_to_handler(struct work_struct *work)
> +{
> +	struct delayed_work *dwork = to_delayed_work(work);
> +	struct ufshpb_lu *hpb;

         struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu, 
ufshpb_read_to_work.work);

usually we use this to get data of a delayed work.

> +	struct victim_select_info *lru_info;

         struct victim_select_info *lru_info = &hpb->lru_info;

This can save some lines.

Thanks,
Can Guo.

> +	struct ufshpb_region *rgn;
> +	unsigned long flags;
> +	LIST_HEAD(expired_list);
> +
> +	spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> +
> +	list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) {
> +		bool timedout = ktime_after(ktime_get(), rgn->read_timeout);
> +
> +		if (timedout) {
> +			rgn->read_timeout_expiries--;
> +			if (is_rgn_dirty(rgn) ||
> +			    rgn->read_timeout_expiries == 0)
> +				list_add(&rgn->list_expired_rgn, &expired_list);
> +			else
> +				rgn->read_timeout = ktime_add_ms(ktime_get(),
> +							 READ_TO_MS);
> +		}
> +	}
> +
> +	spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> +
> +	list_for_each_entry(rgn, &expired_list, list_expired_rgn) {
> +		list_del_init(&rgn->list_expired_rgn);
> +		spin_lock_irqsave(&hpb->rsp_list_lock, flags);
> +		ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
> +		hpb->stats.rb_inactive_cnt++;
> +		spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> +	}
> +
> +	ufshpb_kick_map_work(hpb);
> +
> +	schedule_delayed_work(&hpb->ufshpb_read_to_work,
> +			      msecs_to_jiffies(POLLING_INTERVAL_MS));
> +}
> +
>  static void ufshpb_add_lru_info(struct victim_select_info *lru_info,
>  				struct ufshpb_region *rgn)
>  {
>  	rgn->rgn_state = HPB_RGN_ACTIVE;
>  	list_add_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn);
>  	atomic_inc(&lru_info->active_cnt);
> +	if (rgn->hpb->is_hcm) {
> +		rgn->read_timeout = ktime_add_ms(ktime_get(), READ_TO_MS);
> +		rgn->read_timeout_expiries = READ_TO_EXPIRIES;
> +	}
>  }
> 
>  static void ufshpb_hit_lru_info(struct victim_select_info *lru_info,
> @@ -1813,6 +1865,7 @@ static int ufshpb_alloc_region_tbl(struct
> ufs_hba *hba, struct ufshpb_lu *hpb)
> 
>  		INIT_LIST_HEAD(&rgn->list_inact_rgn);
>  		INIT_LIST_HEAD(&rgn->list_lru_rgn);
> +		INIT_LIST_HEAD(&rgn->list_expired_rgn);
> 
>  		if (rgn_idx == hpb->rgns_per_lu - 1) {
>  			srgn_cnt = ((hpb->srgns_per_lu - 1) %
> @@ -1834,6 +1887,7 @@ static int ufshpb_alloc_region_tbl(struct
> ufs_hba *hba, struct ufshpb_lu *hpb)
>  		}
> 
>  		rgn->rgn_flags = 0;
> +		rgn->hpb = hpb;
>  	}
> 
>  	return 0;
> @@ -2053,6 +2107,8 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> *hba, struct ufshpb_lu *hpb)
>  			  ufshpb_normalization_work_handler);
>  		INIT_WORK(&hpb->ufshpb_lun_reset_work,
>  			  ufshpb_reset_work_handler);
> +		INIT_DELAYED_WORK(&hpb->ufshpb_read_to_work,
> +				  ufshpb_read_to_handler);
>  	}
> 
>  	hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
> @@ -2087,6 +2143,10 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> *hba, struct ufshpb_lu *hpb)
>  	ufshpb_stat_init(hpb);
>  	ufshpb_param_init(hpb);
> 
> +	if (hpb->is_hcm)
> +		schedule_delayed_work(&hpb->ufshpb_read_to_work,
> +				      msecs_to_jiffies(POLLING_INTERVAL_MS));
> +
>  	return 0;
> 
>  release_pre_req_mempool:
> @@ -2154,6 +2214,7 @@ static void ufshpb_discard_rsp_lists(struct
> ufshpb_lu *hpb)
>  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>  {
>  	if (hpb->is_hcm) {
> +		cancel_delayed_work_sync(&hpb->ufshpb_read_to_work);
>  		cancel_work_sync(&hpb->ufshpb_lun_reset_work);
>  		cancel_work_sync(&hpb->ufshpb_normalization_work);
>  	}
> @@ -2264,6 +2325,10 @@ void ufshpb_resume(struct ufs_hba *hba)
>  			continue;
>  		ufshpb_set_state(hpb, HPB_PRESENT);
>  		ufshpb_kick_map_work(hpb);
> +		if (hpb->is_hcm)
> +			schedule_delayed_work(&hpb->ufshpb_read_to_work,
> +				msecs_to_jiffies(POLLING_INTERVAL_MS));
> +
>  	}
>  }
> 
> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> index 37c1b0ea0c0a..b49e9a34267f 100644
> --- a/drivers/scsi/ufs/ufshpb.h
> +++ b/drivers/scsi/ufs/ufshpb.h
> @@ -109,6 +109,7 @@ struct ufshpb_subregion {
>  };
> 
>  struct ufshpb_region {
> +	struct ufshpb_lu *hpb;
>  	struct ufshpb_subregion *srgn_tbl;
>  	enum HPB_RGN_STATE rgn_state;
>  	int rgn_idx;
> @@ -126,6 +127,10 @@ struct ufshpb_region {
>  	/* region reads - for host mode */
>  	spinlock_t rgn_lock;
>  	unsigned int reads;
> +	/* region "cold" timer - for host mode */
> +	ktime_t read_timeout;
> +	unsigned int read_timeout_expiries;
> +	struct list_head list_expired_rgn;
>  };
> 
>  #define for_each_sub_region(rgn, i, srgn)				\
> @@ -219,6 +224,7 @@ struct ufshpb_lu {
>  	struct victim_select_info lru_info;
>  	struct work_struct ufshpb_normalization_work;
>  	struct work_struct ufshpb_lun_reset_work;
> +	struct delayed_work ufshpb_read_to_work;
> 
>  	/* pinned region information */
>  	u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter
  2021-03-02 13:24 ` [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter Avri Altman
  2021-03-11  7:52   ` Can Guo
@ 2021-03-15  3:16   ` Can Guo
  2021-03-15  9:20     ` Avri Altman
  2021-03-15  8:40   ` Can Guo
  2 siblings, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-15  3:16 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

Hi Avri,

On 2021-03-02 21:24, Avri Altman wrote:
> In host control mode, reads are the major source of activation trials.
> Keep track of those reads counters, for both active as well inactive
> regions.
> 
> We reset the read counter upon write - we are only interested in 
> "clean"
> reads.  less intuitive however, is that we also reset it upon region's
> deactivation.  Region deactivation is often due to the fact that
> eviction took place: a region become active on the expense of another.
> This is happening when the max-active-regions limit has crossed. If we
> don’t reset the counter, we will trigger a lot of trashing of the HPB
> database, since few reads (or even one) to the region that was
> deactivated, will trigger a re-activation trial.
> 
> Keep those counters normalized, as we are using those reads as a
> comparative score, to make various decisions.
> If during consecutive normalizations an active region has exhaust its
> reads - inactivate it.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 102 ++++++++++++++++++++++++++++++++------
>  drivers/scsi/ufs/ufshpb.h |   5 ++
>  2 files changed, 92 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index 044fec9854a0..a8f8d13af21a 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -16,6 +16,8 @@
>  #include "ufshpb.h"
>  #include "../sd.h"
> 
> +#define ACTIVATION_THRESHOLD 4 /* 4 IOs */
> +
>  /* memory management */
>  static struct kmem_cache *ufshpb_mctx_cache;
>  static mempool_t *ufshpb_mctx_pool;
> @@ -554,6 +556,21 @@ static int ufshpb_issue_pre_req(struct ufshpb_lu
> *hpb, struct scsi_cmnd *cmd,
>  	return ret;
>  }
> 
> +static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int 
> rgn_idx,
> +				      int srgn_idx)
> +{
> +	struct ufshpb_region *rgn;
> +	struct ufshpb_subregion *srgn;
> +
> +	rgn = hpb->rgn_tbl + rgn_idx;
> +	srgn = rgn->srgn_tbl + srgn_idx;
> +
> +	list_del_init(&rgn->list_inact_rgn);
> +
> +	if (list_empty(&srgn->list_act_srgn))
> +		list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn);
> +}
> +
>  /*
>   * This function will set up HPB read command using host-side L2P map 
> data.
>   */
> @@ -600,12 +617,44 @@ int ufshpb_prep(struct ufs_hba *hba, struct
> ufshcd_lrb *lrbp)
>  		ufshpb_set_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
>  				 transfer_len);
>  		spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> +
> +		if (hpb->is_hcm) {
> +			spin_lock_irqsave(&rgn->rgn_lock, flags);

rgn_lock is never used in IRQ contexts, so no need of irqsave and
irqrestore everywhere, which can impact performance. Please correct
me if I am wrong.

Meanwhile, have you ever initialized the rgn_lock before use it???

Thanks,
Can Guo.

> +			rgn->reads = 0;
> +			spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +		}
> +
>  		return 0;
>  	}
> 
>  	if (!ufshpb_is_support_chunk(hpb, transfer_len))
>  		return 0;
> 
> +	if (hpb->is_hcm) {
> +		bool activate = false;
> +		/*
> +		 * in host control mode, reads are the main source for
> +		 * activation trials.
> +		 */
> +		spin_lock_irqsave(&rgn->rgn_lock, flags);
> +		rgn->reads++;
> +		if (rgn->reads == ACTIVATION_THRESHOLD)
> +			activate = true;
> +		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +		if (activate) {
> +			spin_lock_irqsave(&hpb->rsp_list_lock, flags);
> +			ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
> +			hpb->stats.rb_active_cnt++;
> +			spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> +			dev_dbg(&hpb->sdev_ufs_lu->sdev_dev,
> +				"activate region %d-%d\n", rgn_idx, srgn_idx);
> +		}
> +
> +		/* keep those counters normalized */
> +		if (rgn->reads > hpb->entries_per_srgn)
> +			schedule_work(&hpb->ufshpb_normalization_work);
> +	}
> +
>  	spin_lock_irqsave(&hpb->rgn_state_lock, flags);
>  	if (ufshpb_test_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
>  				   transfer_len)) {
> @@ -745,21 +794,6 @@ static int ufshpb_clear_dirty_bitmap(struct 
> ufshpb_lu *hpb,
>  	return 0;
>  }
> 
> -static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int 
> rgn_idx,
> -				      int srgn_idx)
> -{
> -	struct ufshpb_region *rgn;
> -	struct ufshpb_subregion *srgn;
> -
> -	rgn = hpb->rgn_tbl + rgn_idx;
> -	srgn = rgn->srgn_tbl + srgn_idx;
> -
> -	list_del_init(&rgn->list_inact_rgn);
> -
> -	if (list_empty(&srgn->list_act_srgn))
> -		list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn);
> -}
> -
>  static void ufshpb_update_inactive_info(struct ufshpb_lu *hpb, int 
> rgn_idx)
>  {
>  	struct ufshpb_region *rgn;
> @@ -1079,6 +1113,14 @@ static void __ufshpb_evict_region(struct 
> ufshpb_lu *hpb,
> 
>  	ufshpb_cleanup_lru_info(lru_info, rgn);
> 
> +	if (hpb->is_hcm) {
> +		unsigned long flags;
> +
> +		spin_lock_irqsave(&rgn->rgn_lock, flags);
> +		rgn->reads = 0;
> +		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +	}
> +
>  	for_each_sub_region(rgn, srgn_idx, srgn)
>  		ufshpb_purge_active_subregion(hpb, srgn);
>  }
> @@ -1523,6 +1565,31 @@ static void
> ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
>  	spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>  }
> 
> +static void ufshpb_normalization_work_handler(struct work_struct 
> *work)
> +{
> +	struct ufshpb_lu *hpb;
> +	int rgn_idx;
> +	unsigned long flags;
> +
> +	hpb = container_of(work, struct ufshpb_lu, 
> ufshpb_normalization_work);
> +
> +	for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) {
> +		struct ufshpb_region *rgn = hpb->rgn_tbl + rgn_idx;
> +
> +		spin_lock_irqsave(&rgn->rgn_lock, flags);
> +		rgn->reads = (rgn->reads >> 1);
> +		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +
> +		if (rgn->rgn_state != HPB_RGN_ACTIVE || rgn->reads)
> +			continue;
> +
> +		/* if region is active but has no reads - inactivate it */
> +		spin_lock(&hpb->rsp_list_lock);
> +		ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
> +		spin_unlock(&hpb->rsp_list_lock);
> +	}
> +}
> +
>  static void ufshpb_map_work_handler(struct work_struct *work)
>  {
>  	struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu, 
> map_work);
> @@ -1913,6 +1980,9 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> *hba, struct ufshpb_lu *hpb)
>  	INIT_LIST_HEAD(&hpb->list_hpb_lu);
> 
>  	INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> +	if (hpb->is_hcm)
> +		INIT_WORK(&hpb->ufshpb_normalization_work,
> +			  ufshpb_normalization_work_handler);
> 
>  	hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
>  			  sizeof(struct ufshpb_req), 0, 0, NULL);
> @@ -2012,6 +2082,8 @@ static void ufshpb_discard_rsp_lists(struct
> ufshpb_lu *hpb)
> 
>  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>  {
> +	if (hpb->is_hcm)
> +		cancel_work_sync(&hpb->ufshpb_normalization_work);
>  	cancel_work_sync(&hpb->map_work);
>  }
> 
> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> index 8119b1a3d1e5..bd4308010466 100644
> --- a/drivers/scsi/ufs/ufshpb.h
> +++ b/drivers/scsi/ufs/ufshpb.h
> @@ -121,6 +121,10 @@ struct ufshpb_region {
>  	struct list_head list_lru_rgn;
>  	unsigned long rgn_flags;
>  #define RGN_FLAG_DIRTY 0
> +
> +	/* region reads - for host mode */
> +	spinlock_t rgn_lock;
> +	unsigned int reads;
>  };
> 
>  #define for_each_sub_region(rgn, i, srgn)				\
> @@ -211,6 +215,7 @@ struct ufshpb_lu {
> 
>  	/* for selecting victim */
>  	struct victim_select_info lru_info;
> +	struct work_struct ufshpb_normalization_work;
> 
>  	/* pinned region information */
>  	u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
  2021-03-02 13:24 ` [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode Avri Altman
  2021-03-11  8:20   ` Can Guo
@ 2021-03-15  4:02   ` Can Guo
  2021-03-15  7:33     ` Can Guo
  1 sibling, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-15  4:02 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-02 21:24, Avri Altman wrote:
> I host mode, the host is expected to send HPB-WRITE-BUFFER with
> buffer-id = 0x1 when it inactivates a region.
> 
> Use the map-requests pool as there is no point in assigning a
> designated cache for umap-requests.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
>  drivers/scsi/ufs/ufshpb.h |  1 +
>  2 files changed, 15 insertions(+)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index 6f4fd22eaf2f..0744feb4d484 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct ufshpb_lu 
> *hpb,
> 
>  	blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_umap_req_compl_fn);
> 
> +	hpb->stats.umap_req_cnt++;
>  	return 0;
>  }
> 
> @@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct 
> ufshpb_lu *hpb,
>  	return -EAGAIN;
>  }
> 
> +static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
> +					struct ufshpb_region *rgn)
> +{
> +	return ufshpb_issue_umap_req(hpb, rgn);
> +}
> +
>  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
>  {
>  	return ufshpb_issue_umap_req(hpb, NULL);
> @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct 
> ufshpb_lu *hpb,
>  	struct ufshpb_subregion *srgn;
>  	int srgn_idx;
> 
> +
> +	if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))

__ufshpb_evict_region() is called with rgn_state_lock held and IRQ 
disabled,
when ufshpb_issue_umap_single_req() invokes blk_execute_rq_nowait(), 
below
warning shall pop up every time, fix it?

void blk_execute_rq_nowait(struct request_queue *q, struct gendisk 
*bd_disk,
		   struct request *rq, int at_head,
			   rq_end_io_fn *done)
{
	WARN_ON(irqs_disabled());
...

Thanks.
Can Guo.

> +		return;
> +
>  	lru_info = &hpb->lru_info;
> 
>  	dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n", 
> rgn->rgn_idx);
> @@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
>  ufshpb_sysfs_attr_show_func(rb_active_cnt);
>  ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
>  ufshpb_sysfs_attr_show_func(map_req_cnt);
> +ufshpb_sysfs_attr_show_func(umap_req_cnt);
> 
>  static struct attribute *hpb_dev_stat_attrs[] = {
>  	&dev_attr_hit_cnt.attr,
> @@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[] = {
>  	&dev_attr_rb_active_cnt.attr,
>  	&dev_attr_rb_inactive_cnt.attr,
>  	&dev_attr_map_req_cnt.attr,
> +	&dev_attr_umap_req_cnt.attr,
>  	NULL,
>  };
> 
> @@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu 
> *hpb)
>  	hpb->stats.rb_active_cnt = 0;
>  	hpb->stats.rb_inactive_cnt = 0;
>  	hpb->stats.map_req_cnt = 0;
> +	hpb->stats.umap_req_cnt = 0;
>  }
> 
>  static void ufshpb_param_init(struct ufshpb_lu *hpb)
> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> index bd4308010466..84598a317897 100644
> --- a/drivers/scsi/ufs/ufshpb.h
> +++ b/drivers/scsi/ufs/ufshpb.h
> @@ -186,6 +186,7 @@ struct ufshpb_stats {
>  	u64 rb_inactive_cnt;
>  	u64 map_req_cnt;
>  	u64 pre_req_cnt;
> +	u64 umap_req_cnt;
>  };
> 
>  struct ufshpb_lu {

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-15  1:34   ` Can Guo
@ 2021-03-15  6:40     ` Can Guo
  2021-03-15  7:42     ` Avri Altman
  1 sibling, 0 replies; 58+ messages in thread
From: Can Guo @ 2021-03-15  6:40 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-15 09:34, Can Guo wrote:
> On 2021-03-02 21:24, Avri Altman wrote:
>> The spec does not define what is the host's recommended response when
>> the device send hpb dev reset response (oper 0x2).
>> 
>> We will update all active hpb regions: mark them and do that on the 
>> next
>> read.
>> 
>> Signed-off-by: Avri Altman <avri.altman@wdc.com>
>> ---
>>  drivers/scsi/ufs/ufshpb.c | 47 
>> ++++++++++++++++++++++++++++++++++++---
>>  drivers/scsi/ufs/ufshpb.h |  2 ++
>>  2 files changed, 46 insertions(+), 3 deletions(-)
>> 
>> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>> index 0744feb4d484..0034fa03fdc6 100644
>> --- a/drivers/scsi/ufs/ufshpb.c
>> +++ b/drivers/scsi/ufs/ufshpb.c
>> @@ -642,7 +642,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct
>> ufshcd_lrb *lrbp)
>>  		if (rgn->reads == ACTIVATION_THRESHOLD)
>>  			activate = true;
>>  		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
>> -		if (activate) {
>> +		if (activate ||
>> +		    test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) {
>>  			spin_lock_irqsave(&hpb->rsp_list_lock, flags);
>>  			ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
>>  			hpb->stats.rb_active_cnt++;
>> @@ -1480,6 +1481,20 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba,
>> struct ufshcd_lrb *lrbp)
>>  	case HPB_RSP_DEV_RESET:
>>  		dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
>>  			 "UFS device lost HPB information during PM.\n");
>> +
>> +		if (hpb->is_hcm) {
>> +			struct scsi_device *sdev;
>                         bool need_reset = false;
>> +
>> +			__shost_for_each_device(sdev, hba->host) {
>> +				struct ufshpb_lu *h = sdev->hostdata;
>> +
>> +				if (!h)
>> +					continue;
>> +
>> +				need_reset = true;
>> +			}
> 
>                         if (need_reset)
>                             schedule_work(&hpb->ufshpb_lun_reset_work);
> 
> At last, scheduling only one reset work shall be enough, otherwise 
> multiple
> reset work can be flying in parallel, so maybe above changes?

Forget about this one, I misunderstood it - reset work is for each 
ufshpb_lu...

Regards,
Can Guo.

> 
>> +		}
>> +
>>  		break;
>>  	default:
>>  		dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
>> @@ -1594,6 +1609,25 @@ static void
>> ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
>>  	spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>>  }
>> 
>> +static void ufshpb_reset_work_handler(struct work_struct *work)
>> +{
>> +	struct ufshpb_lu *hpb;
> 
>         struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu,
> ufshpb_lun_reset_work);
> 
>> +	struct victim_select_info *lru_info;
> 
>         struct victim_select_info *lru_info = &hpb->lru_info;
> 
> This can save some lines.
> 
> Thanks,
> Can Guo.
> 
>> +	struct ufshpb_region *rgn;
>> +	unsigned long flags;
>> +
>> +	spin_lock_irqsave(&hpb->rgn_state_lock, flags);
>> +
>> +	list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
>> +		set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
>> +
>> +	spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
>> +}
>> +
>>  static void ufshpb_normalization_work_handler(struct work_struct 
>> *work)
>>  {
>>  	struct ufshpb_lu *hpb;
>> @@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct
>> ufs_hba *hba, struct ufshpb_lu *hpb)
>>  		} else {
>>  			rgn->rgn_state = HPB_RGN_INACTIVE;
>>  		}
>> +
>> +		rgn->rgn_flags = 0;
>>  	}
>> 
>>  	return 0;
>> @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
>> *hba, struct ufshpb_lu *hpb)
>>  	INIT_LIST_HEAD(&hpb->list_hpb_lu);
>> 
>>  	INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
>> -	if (hpb->is_hcm)
>> +	if (hpb->is_hcm) {
>>  		INIT_WORK(&hpb->ufshpb_normalization_work,
>>  			  ufshpb_normalization_work_handler);
>> +		INIT_WORK(&hpb->ufshpb_lun_reset_work,
>> +			  ufshpb_reset_work_handler);
>> +	}
>> 
>>  	hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
>>  			  sizeof(struct ufshpb_req), 0, 0, NULL);
>> @@ -2114,8 +2153,10 @@ static void ufshpb_discard_rsp_lists(struct
>> ufshpb_lu *hpb)
>> 
>>  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>>  {
>> -	if (hpb->is_hcm)
>> +	if (hpb->is_hcm) {
>> +		cancel_work_sync(&hpb->ufshpb_lun_reset_work);
>>  		cancel_work_sync(&hpb->ufshpb_normalization_work);
>> +	}
>>  	cancel_work_sync(&hpb->map_work);
>>  }
>> 
>> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>> index 84598a317897..37c1b0ea0c0a 100644
>> --- a/drivers/scsi/ufs/ufshpb.h
>> +++ b/drivers/scsi/ufs/ufshpb.h
>> @@ -121,6 +121,7 @@ struct ufshpb_region {
>>  	struct list_head list_lru_rgn;
>>  	unsigned long rgn_flags;
>>  #define RGN_FLAG_DIRTY 0
>> +#define RGN_FLAG_UPDATE 1
>> 
>>  	/* region reads - for host mode */
>>  	spinlock_t rgn_lock;
>> @@ -217,6 +218,7 @@ struct ufshpb_lu {
>>  	/* for selecting victim */
>>  	struct victim_select_info lru_info;
>>  	struct work_struct ufshpb_normalization_work;
>> +	struct work_struct ufshpb_lun_reset_work;
>> 
>>  	/* pinned region information */
>>  	u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
  2021-03-15  4:02   ` Can Guo
@ 2021-03-15  7:33     ` Can Guo
  2021-03-16  8:30       ` Avri Altman
       [not found]       ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p3>
  0 siblings, 2 replies; 58+ messages in thread
From: Can Guo @ 2021-03-15  7:33 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-15 12:02, Can Guo wrote:
> On 2021-03-02 21:24, Avri Altman wrote:
>> I host mode, the host is expected to send HPB-WRITE-BUFFER with
>> buffer-id = 0x1 when it inactivates a region.
>> 
>> Use the map-requests pool as there is no point in assigning a
>> designated cache for umap-requests.
>> 
>> Signed-off-by: Avri Altman <avri.altman@wdc.com>
>> ---
>>  drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
>>  drivers/scsi/ufs/ufshpb.h |  1 +
>>  2 files changed, 15 insertions(+)
>> 
>> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>> index 6f4fd22eaf2f..0744feb4d484 100644
>> --- a/drivers/scsi/ufs/ufshpb.c
>> +++ b/drivers/scsi/ufs/ufshpb.c
>> @@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct 
>> ufshpb_lu *hpb,
>> 
>>  	blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_umap_req_compl_fn);
>> 
>> +	hpb->stats.umap_req_cnt++;
>>  	return 0;
>>  }
>> 
>> @@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct 
>> ufshpb_lu *hpb,
>>  	return -EAGAIN;
>>  }
>> 
>> +static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
>> +					struct ufshpb_region *rgn)
>> +{
>> +	return ufshpb_issue_umap_req(hpb, rgn);
>> +}
>> +
>>  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
>>  {
>>  	return ufshpb_issue_umap_req(hpb, NULL);
>> @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct 
>> ufshpb_lu *hpb,
>>  	struct ufshpb_subregion *srgn;
>>  	int srgn_idx;
>> 
>> +
>> +	if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))
> 
> __ufshpb_evict_region() is called with rgn_state_lock held and IRQ 
> disabled,
> when ufshpb_issue_umap_single_req() invokes blk_execute_rq_nowait(), 
> below
> warning shall pop up every time, fix it?
> 
> void blk_execute_rq_nowait(struct request_queue *q, struct gendisk 
> *bd_disk,
> 		   struct request *rq, int at_head,
> 			   rq_end_io_fn *done)
> {
> 	WARN_ON(irqs_disabled());
> ...
> 

Moreover, since we are here with rgn_state_lock held and IRQ disabled,
in ufshpb_get_req(), rq = kmem_cache_alloc(hpb->map_req_cache, 
GFP_KERNEL)
has the GFP_KERNEL flag, scheduling while atomic???

Can Guo.

> Thanks.
> Can Guo.
> 
>> +		return;
>> +
>>  	lru_info = &hpb->lru_info;
>> 
>>  	dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n", 
>> rgn->rgn_idx);
>> @@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
>>  ufshpb_sysfs_attr_show_func(rb_active_cnt);
>>  ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
>>  ufshpb_sysfs_attr_show_func(map_req_cnt);
>> +ufshpb_sysfs_attr_show_func(umap_req_cnt);
>> 
>>  static struct attribute *hpb_dev_stat_attrs[] = {
>>  	&dev_attr_hit_cnt.attr,
>> @@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[] = 
>> {
>>  	&dev_attr_rb_active_cnt.attr,
>>  	&dev_attr_rb_inactive_cnt.attr,
>>  	&dev_attr_map_req_cnt.attr,
>> +	&dev_attr_umap_req_cnt.attr,
>>  	NULL,
>>  };
>> 
>> @@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu 
>> *hpb)
>>  	hpb->stats.rb_active_cnt = 0;
>>  	hpb->stats.rb_inactive_cnt = 0;
>>  	hpb->stats.map_req_cnt = 0;
>> +	hpb->stats.umap_req_cnt = 0;
>>  }
>> 
>>  static void ufshpb_param_init(struct ufshpb_lu *hpb)
>> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>> index bd4308010466..84598a317897 100644
>> --- a/drivers/scsi/ufs/ufshpb.h
>> +++ b/drivers/scsi/ufs/ufshpb.h
>> @@ -186,6 +186,7 @@ struct ufshpb_stats {
>>  	u64 rb_inactive_cnt;
>>  	u64 map_req_cnt;
>>  	u64 pre_req_cnt;
>> +	u64 umap_req_cnt;
>>  };
>> 
>>  struct ufshpb_lu {

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-15  1:34   ` Can Guo
  2021-03-15  6:40     ` Can Guo
@ 2021-03-15  7:42     ` Avri Altman
  1 sibling, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-15  7:42 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> > +static void ufshpb_reset_work_handler(struct work_struct *work)
> > +{
> > +     struct ufshpb_lu *hpb;
> 
>          struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu,
> ufshpb_lun_reset_work);
> 
> > +     struct victim_select_info *lru_info;
> 
>          struct victim_select_info *lru_info = &hpb->lru_info;
> 
> This can save some lines.
Done.

Thanks,
Avri
> 
> Thanks,
> Can Guo.
> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer
  2021-03-15  1:37   ` Can Guo
@ 2021-03-15  7:54     ` Avri Altman
  0 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-15  7:54 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> >
> > +static void ufshpb_read_to_handler(struct work_struct *work)
> > +{
> > +     struct delayed_work *dwork = to_delayed_work(work);
> > +     struct ufshpb_lu *hpb;
> 
>          struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu,
> ufshpb_read_to_work.work);
> 
> usually we use this to get data of a delayed work.
> 
> > +     struct victim_select_info *lru_info;
> 
>          struct victim_select_info *lru_info = &hpb->lru_info;
> 
> This can save some lines.
Done.

Thanks,
Avri

> Thanks,
> Can Guo.
> 
> > +     struct ufshpb_region *rgn;
> > +     unsigned long flags;
> > +     LIST_HEAD(expired_list);

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 04/10] scsi: ufshpb: Make eviction depends on region's reads
  2021-03-02 13:24 ` [PATCH v5 04/10] scsi: ufshpb: Make eviction depends on region's reads Avri Altman
  2021-03-11  7:53   ` Can Guo
@ 2021-03-15  8:30   ` Can Guo
  2021-03-16  8:34     ` Avri Altman
  1 sibling, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-15  8:30 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-02 21:24, Avri Altman wrote:
> In host mode, eviction is considered an extreme measure.
> verify that the entering region has enough reads, and the exiting
> region has much less reads.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 20 +++++++++++++++++++-
>  1 file changed, 19 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index a8f8d13af21a..6f4fd22eaf2f 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -17,6 +17,7 @@
>  #include "../sd.h"
> 
>  #define ACTIVATION_THRESHOLD 4 /* 4 IOs */
> +#define EVICTION_THRESHOLD (ACTIVATION_THRESHOLD << 6) /* 256 IOs */
> 
>  /* memory management */
>  static struct kmem_cache *ufshpb_mctx_cache;
> @@ -1050,6 +1051,13 @@ static struct ufshpb_region
> *ufshpb_victim_lru_info(struct ufshpb_lu *hpb)
>  		if (ufshpb_check_srgns_issue_state(hpb, rgn))
>  			continue;
> 
> +		/*
> +		 * in host control mode, verify that the exiting region
> +		 * has less reads
> +		 */
> +		if (hpb->is_hcm && rgn->reads > (EVICTION_THRESHOLD >> 1))
> +			continue;
> +
>  		victim_rgn = rgn;
>  		break;
>  	}
> @@ -1235,7 +1243,7 @@ static int ufshpb_issue_map_req(struct ufshpb_lu 
> *hpb,
> 
>  static int ufshpb_add_region(struct ufshpb_lu *hpb, struct 
> ufshpb_region *rgn)
>  {
> -	struct ufshpb_region *victim_rgn;
> +	struct ufshpb_region *victim_rgn = NULL;
>  	struct victim_select_info *lru_info = &hpb->lru_info;
>  	unsigned long flags;
>  	int ret = 0;
> @@ -1263,6 +1271,16 @@ static int ufshpb_add_region(struct ufshpb_lu
> *hpb, struct ufshpb_region *rgn)
>  			 * because the device could detect this region
>  			 * by not issuing HPB_READ
>  			 */
> +
> +			/*
> +			 * in host control mode, verify that the entering
> +			 * region has enough reads
> +			 */

Maybe merge the new comments with the original comments above?

Thanks,
Can Guo.

> +			if (hpb->is_hcm && rgn->reads < EVICTION_THRESHOLD) {
> +				ret = -EACCES;
> +				goto out;
> +			}
> +
>  			victim_rgn = ufshpb_victim_lru_info(hpb);
>  			if (!victim_rgn) {
>  				dev_warn(&hpb->sdev_ufs_lu->sdev_dev,

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 08/10] scsi: ufshpb: Limit the number of inflight map requests
  2021-03-02 13:25 ` [PATCH v5 08/10] scsi: ufshpb: Limit the number of inflight map requests Avri Altman
@ 2021-03-15  8:31   ` Can Guo
  2021-03-16  8:32     ` Avri Altman
  0 siblings, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-15  8:31 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-02 21:25, Avri Altman wrote:
> in host control mode the host is the originator of map requests. To not

in -> In

Thanks,
Can Guo.

> flood the device with map requests, use a simple throttling mechanism
> that limits the number of inflight map requests.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 11 +++++++++++
>  drivers/scsi/ufs/ufshpb.h |  1 +
>  2 files changed, 12 insertions(+)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index 89a930e72cff..74da69727340 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -21,6 +21,7 @@
>  #define READ_TO_MS 1000
>  #define READ_TO_EXPIRIES 100
>  #define POLLING_INTERVAL_MS 200
> +#define THROTTLE_MAP_REQ_DEFAULT 1
> 
>  /* memory management */
>  static struct kmem_cache *ufshpb_mctx_cache;
> @@ -750,6 +751,14 @@ static struct ufshpb_req
> *ufshpb_get_map_req(struct ufshpb_lu *hpb,
>  	struct ufshpb_req *map_req;
>  	struct bio *bio;
> 
> +	if (hpb->is_hcm &&
> +	    hpb->num_inflight_map_req >= THROTTLE_MAP_REQ_DEFAULT) {
> +		dev_info(&hpb->sdev_ufs_lu->sdev_dev,
> +			 "map_req throttle. inflight %d throttle %d",
> +			 hpb->num_inflight_map_req, THROTTLE_MAP_REQ_DEFAULT);
> +		return NULL;
> +	}
> +
>  	map_req = ufshpb_get_req(hpb, srgn->rgn_idx, REQ_OP_SCSI_IN);
>  	if (!map_req)
>  		return NULL;
> @@ -764,6 +773,7 @@ static struct ufshpb_req
> *ufshpb_get_map_req(struct ufshpb_lu *hpb,
> 
>  	map_req->rb.srgn_idx = srgn->srgn_idx;
>  	map_req->rb.mctx = srgn->mctx;
> +	hpb->num_inflight_map_req++;
> 
>  	return map_req;
>  }
> @@ -773,6 +783,7 @@ static void ufshpb_put_map_req(struct ufshpb_lu 
> *hpb,
>  {
>  	bio_put(map_req->bio);
>  	ufshpb_put_req(hpb, map_req);
> +	hpb->num_inflight_map_req--;
>  }
> 
>  static int ufshpb_clear_dirty_bitmap(struct ufshpb_lu *hpb,
> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> index b49e9a34267f..d83ab488688a 100644
> --- a/drivers/scsi/ufs/ufshpb.h
> +++ b/drivers/scsi/ufs/ufshpb.h
> @@ -212,6 +212,7 @@ struct ufshpb_lu {
>  	struct ufshpb_req *pre_req;
>  	int num_inflight_pre_req;
>  	int throttle_pre_req;
> +	int num_inflight_map_req;
>  	struct list_head lh_pre_req_free;
>  	int cur_read_id;
>  	int pre_req_min_tr_len;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter
  2021-03-02 13:24 ` [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter Avri Altman
  2021-03-11  7:52   ` Can Guo
  2021-03-15  3:16   ` Can Guo
@ 2021-03-15  8:40   ` Can Guo
  2021-03-15  9:22     ` Avri Altman
  2 siblings, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-15  8:40 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-02 21:24, Avri Altman wrote:
> In host control mode, reads are the major source of activation trials.
> Keep track of those reads counters, for both active as well inactive
> regions.
> 
> We reset the read counter upon write - we are only interested in 
> "clean"
> reads.  less intuitive however, is that we also reset it upon region's
> deactivation.  Region deactivation is often due to the fact that
> eviction took place: a region become active on the expense of another.
> This is happening when the max-active-regions limit has crossed. If we
> don’t reset the counter, we will trigger a lot of trashing of the HPB
> database, since few reads (or even one) to the region that was
> deactivated, will trigger a re-activation trial.
> 
> Keep those counters normalized, as we are using those reads as a
> comparative score, to make various decisions.
> If during consecutive normalizations an active region has exhaust its
> reads - inactivate it.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 102 ++++++++++++++++++++++++++++++++------
>  drivers/scsi/ufs/ufshpb.h |   5 ++
>  2 files changed, 92 insertions(+), 15 deletions(-)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index 044fec9854a0..a8f8d13af21a 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -16,6 +16,8 @@
>  #include "ufshpb.h"
>  #include "../sd.h"
> 
> +#define ACTIVATION_THRESHOLD 4 /* 4 IOs */
> +
>  /* memory management */
>  static struct kmem_cache *ufshpb_mctx_cache;
>  static mempool_t *ufshpb_mctx_pool;
> @@ -554,6 +556,21 @@ static int ufshpb_issue_pre_req(struct ufshpb_lu
> *hpb, struct scsi_cmnd *cmd,
>  	return ret;
>  }
> 
> +static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int 
> rgn_idx,
> +				      int srgn_idx)
> +{
> +	struct ufshpb_region *rgn;
> +	struct ufshpb_subregion *srgn;
> +
> +	rgn = hpb->rgn_tbl + rgn_idx;
> +	srgn = rgn->srgn_tbl + srgn_idx;
> +
> +	list_del_init(&rgn->list_inact_rgn);
> +
> +	if (list_empty(&srgn->list_act_srgn))
> +		list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn);
> +}
> +
>  /*
>   * This function will set up HPB read command using host-side L2P map 
> data.
>   */
> @@ -600,12 +617,44 @@ int ufshpb_prep(struct ufs_hba *hba, struct
> ufshcd_lrb *lrbp)
>  		ufshpb_set_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
>  				 transfer_len);
>  		spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> +
> +		if (hpb->is_hcm) {
> +			spin_lock_irqsave(&rgn->rgn_lock, flags);
> +			rgn->reads = 0;
> +			spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +		}
> +
>  		return 0;
>  	}
> 
>  	if (!ufshpb_is_support_chunk(hpb, transfer_len))
>  		return 0;
> 
> +	if (hpb->is_hcm) {
> +		bool activate = false;
> +		/*
> +		 * in host control mode, reads are the main source for
> +		 * activation trials.
> +		 */
> +		spin_lock_irqsave(&rgn->rgn_lock, flags);
> +		rgn->reads++;
> +		if (rgn->reads == ACTIVATION_THRESHOLD)
> +			activate = true;
> +		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +		if (activate) {
> +			spin_lock_irqsave(&hpb->rsp_list_lock, flags);
> +			ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
> +			hpb->stats.rb_active_cnt++;
> +			spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> +			dev_dbg(&hpb->sdev_ufs_lu->sdev_dev,
> +				"activate region %d-%d\n", rgn_idx, srgn_idx);
> +		}
> +
> +		/* keep those counters normalized */
> +		if (rgn->reads > hpb->entries_per_srgn)
> +			schedule_work(&hpb->ufshpb_normalization_work);
> +	}
> +
>  	spin_lock_irqsave(&hpb->rgn_state_lock, flags);
>  	if (ufshpb_test_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
>  				   transfer_len)) {
> @@ -745,21 +794,6 @@ static int ufshpb_clear_dirty_bitmap(struct 
> ufshpb_lu *hpb,
>  	return 0;
>  }
> 
> -static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int 
> rgn_idx,
> -				      int srgn_idx)
> -{
> -	struct ufshpb_region *rgn;
> -	struct ufshpb_subregion *srgn;
> -
> -	rgn = hpb->rgn_tbl + rgn_idx;
> -	srgn = rgn->srgn_tbl + srgn_idx;
> -
> -	list_del_init(&rgn->list_inact_rgn);
> -
> -	if (list_empty(&srgn->list_act_srgn))
> -		list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn);
> -}
> -
>  static void ufshpb_update_inactive_info(struct ufshpb_lu *hpb, int 
> rgn_idx)
>  {
>  	struct ufshpb_region *rgn;
> @@ -1079,6 +1113,14 @@ static void __ufshpb_evict_region(struct 
> ufshpb_lu *hpb,
> 
>  	ufshpb_cleanup_lru_info(lru_info, rgn);
> 
> +	if (hpb->is_hcm) {
> +		unsigned long flags;
> +
> +		spin_lock_irqsave(&rgn->rgn_lock, flags);
> +		rgn->reads = 0;
> +		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +	}
> +
>  	for_each_sub_region(rgn, srgn_idx, srgn)
>  		ufshpb_purge_active_subregion(hpb, srgn);
>  }
> @@ -1523,6 +1565,31 @@ static void
> ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
>  	spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>  }
> 
> +static void ufshpb_normalization_work_handler(struct work_struct 
> *work)
> +{
> +	struct ufshpb_lu *hpb;
> +	int rgn_idx;
> +	unsigned long flags;
> +
> +	hpb = container_of(work, struct ufshpb_lu, 
> ufshpb_normalization_work);
> +
> +	for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) {
> +		struct ufshpb_region *rgn = hpb->rgn_tbl + rgn_idx;
> +
> +		spin_lock_irqsave(&rgn->rgn_lock, flags);
> +		rgn->reads = (rgn->reads >> 1);
> +		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> +
> +		if (rgn->rgn_state != HPB_RGN_ACTIVE || rgn->reads)
> +			continue;
> +
> +		/* if region is active but has no reads - inactivate it */
> +		spin_lock(&hpb->rsp_list_lock);
> +		ufshpb_update_inactive_info(hpb, rgn->rgn_idx);

Miss a hpb->stats.rb_inactive_cnt++ here?

Thanks,
Can Guo.

> +		spin_unlock(&hpb->rsp_list_lock);
> +	}
> +}
> +
>  static void ufshpb_map_work_handler(struct work_struct *work)
>  {
>  	struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu, 
> map_work);
> @@ -1913,6 +1980,9 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> *hba, struct ufshpb_lu *hpb)
>  	INIT_LIST_HEAD(&hpb->list_hpb_lu);
> 
>  	INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> +	if (hpb->is_hcm)
> +		INIT_WORK(&hpb->ufshpb_normalization_work,
> +			  ufshpb_normalization_work_handler);
> 
>  	hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
>  			  sizeof(struct ufshpb_req), 0, 0, NULL);
> @@ -2012,6 +2082,8 @@ static void ufshpb_discard_rsp_lists(struct
> ufshpb_lu *hpb)
> 
>  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>  {
> +	if (hpb->is_hcm)
> +		cancel_work_sync(&hpb->ufshpb_normalization_work);
>  	cancel_work_sync(&hpb->map_work);
>  }
> 
> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> index 8119b1a3d1e5..bd4308010466 100644
> --- a/drivers/scsi/ufs/ufshpb.h
> +++ b/drivers/scsi/ufs/ufshpb.h
> @@ -121,6 +121,10 @@ struct ufshpb_region {
>  	struct list_head list_lru_rgn;
>  	unsigned long rgn_flags;
>  #define RGN_FLAG_DIRTY 0
> +
> +	/* region reads - for host mode */
> +	spinlock_t rgn_lock;
> +	unsigned int reads;
>  };
> 
>  #define for_each_sub_region(rgn, i, srgn)				\
> @@ -211,6 +215,7 @@ struct ufshpb_lu {
> 
>  	/* for selecting victim */
>  	struct victim_select_info lru_info;
> +	struct work_struct ufshpb_normalization_work;
> 
>  	/* pinned region information */
>  	u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter
  2021-03-15  3:16   ` Can Guo
@ 2021-03-15  9:20     ` Avri Altman
  2021-03-15  9:31       ` Can Guo
  0 siblings, 1 reply; 58+ messages in thread
From: Avri Altman @ 2021-03-15  9:20 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> > +
> > +             if (hpb->is_hcm) {
> > +                     spin_lock_irqsave(&rgn->rgn_lock, flags);
> 
> rgn_lock is never used in IRQ contexts, so no need of irqsave and
> irqrestore everywhere, which can impact performance. Please correct
> me if I am wrong.
Thanks.  Will do.

> 
> Meanwhile, have you ever initialized the rgn_lock before use it???
Yep - forgot to do that here (but not in gs20 and mi10).  Thanks.

Thanks,
Avri

> 
> Thanks,
> Can Guo.
> 
> > +                     rgn->reads = 0;
> > +                     spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> > +             }
> > +
> >               return 0;
> >       }
> >
> >       if (!ufshpb_is_support_chunk(hpb, transfer_len))
> >               return 0;
> >
> > +     if (hpb->is_hcm) {
> > +             bool activate = false;
> > +             /*
> > +              * in host control mode, reads are the main source for
> > +              * activation trials.
> > +              */
> > +             spin_lock_irqsave(&rgn->rgn_lock, flags);
> > +             rgn->reads++;
> > +             if (rgn->reads == ACTIVATION_THRESHOLD)
> > +                     activate = true;
> > +             spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> > +             if (activate) {
> > +                     spin_lock_irqsave(&hpb->rsp_list_lock, flags);
> > +                     ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
> > +                     hpb->stats.rb_active_cnt++;
> > +                     spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> > +                     dev_dbg(&hpb->sdev_ufs_lu->sdev_dev,
> > +                             "activate region %d-%d\n", rgn_idx, srgn_idx);
> > +             }
> > +
> > +             /* keep those counters normalized */
> > +             if (rgn->reads > hpb->entries_per_srgn)
> > +                     schedule_work(&hpb->ufshpb_normalization_work);
> > +     }
> > +
> >       spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> >       if (ufshpb_test_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
> >                                  transfer_len)) {
> > @@ -745,21 +794,6 @@ static int ufshpb_clear_dirty_bitmap(struct
> > ufshpb_lu *hpb,
> >       return 0;
> >  }
> >
> > -static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int
> > rgn_idx,
> > -                                   int srgn_idx)
> > -{
> > -     struct ufshpb_region *rgn;
> > -     struct ufshpb_subregion *srgn;
> > -
> > -     rgn = hpb->rgn_tbl + rgn_idx;
> > -     srgn = rgn->srgn_tbl + srgn_idx;
> > -
> > -     list_del_init(&rgn->list_inact_rgn);
> > -
> > -     if (list_empty(&srgn->list_act_srgn))
> > -             list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn);
> > -}
> > -
> >  static void ufshpb_update_inactive_info(struct ufshpb_lu *hpb, int
> > rgn_idx)
> >  {
> >       struct ufshpb_region *rgn;
> > @@ -1079,6 +1113,14 @@ static void __ufshpb_evict_region(struct
> > ufshpb_lu *hpb,
> >
> >       ufshpb_cleanup_lru_info(lru_info, rgn);
> >
> > +     if (hpb->is_hcm) {
> > +             unsigned long flags;
> > +
> > +             spin_lock_irqsave(&rgn->rgn_lock, flags);
> > +             rgn->reads = 0;
> > +             spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> > +     }
> > +
> >       for_each_sub_region(rgn, srgn_idx, srgn)
> >               ufshpb_purge_active_subregion(hpb, srgn);
> >  }
> > @@ -1523,6 +1565,31 @@ static void
> > ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
> >       spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> >  }
> >
> > +static void ufshpb_normalization_work_handler(struct work_struct
> > *work)
> > +{
> > +     struct ufshpb_lu *hpb;
> > +     int rgn_idx;
> > +     unsigned long flags;
> > +
> > +     hpb = container_of(work, struct ufshpb_lu,
> > ufshpb_normalization_work);
> > +
> > +     for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) {
> > +             struct ufshpb_region *rgn = hpb->rgn_tbl + rgn_idx;
> > +
> > +             spin_lock_irqsave(&rgn->rgn_lock, flags);
> > +             rgn->reads = (rgn->reads >> 1);
> > +             spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> > +
> > +             if (rgn->rgn_state != HPB_RGN_ACTIVE || rgn->reads)
> > +                     continue;
> > +
> > +             /* if region is active but has no reads - inactivate it */
> > +             spin_lock(&hpb->rsp_list_lock);
> > +             ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
> > +             spin_unlock(&hpb->rsp_list_lock);
> > +     }
> > +}
> > +
> >  static void ufshpb_map_work_handler(struct work_struct *work)
> >  {
> >       struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu,
> > map_work);
> > @@ -1913,6 +1980,9 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> > *hba, struct ufshpb_lu *hpb)
> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
> >
> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> > +     if (hpb->is_hcm)
> > +             INIT_WORK(&hpb->ufshpb_normalization_work,
> > +                       ufshpb_normalization_work_handler);
> >
> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
> > @@ -2012,6 +2082,8 @@ static void ufshpb_discard_rsp_lists(struct
> > ufshpb_lu *hpb)
> >
> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
> >  {
> > +     if (hpb->is_hcm)
> > +             cancel_work_sync(&hpb->ufshpb_normalization_work);
> >       cancel_work_sync(&hpb->map_work);
> >  }
> >
> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> > index 8119b1a3d1e5..bd4308010466 100644
> > --- a/drivers/scsi/ufs/ufshpb.h
> > +++ b/drivers/scsi/ufs/ufshpb.h
> > @@ -121,6 +121,10 @@ struct ufshpb_region {
> >       struct list_head list_lru_rgn;
> >       unsigned long rgn_flags;
> >  #define RGN_FLAG_DIRTY 0
> > +
> > +     /* region reads - for host mode */
> > +     spinlock_t rgn_lock;
> > +     unsigned int reads;
> >  };
> >
> >  #define for_each_sub_region(rgn, i, srgn)                            \
> > @@ -211,6 +215,7 @@ struct ufshpb_lu {
> >
> >       /* for selecting victim */
> >       struct victim_select_info lru_info;
> > +     struct work_struct ufshpb_normalization_work;
> >
> >       /* pinned region information */
> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter
  2021-03-15  8:40   ` Can Guo
@ 2021-03-15  9:22     ` Avri Altman
  0 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-15  9:22 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> > +             /* if region is active but has no reads - inactivate it */
> > +             spin_lock(&hpb->rsp_list_lock);
> > +             ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
> 
> Miss a hpb->stats.rb_inactive_cnt++ here?
Thanks.
Also noticed that since rb_inactive_cnt and rb_active_cnt are incremented now in more than one place - 
Need to protect that.

Thanks,
Avri

> 
> Thanks,
> Can Guo.
> 
> > +             spin_unlock(&hpb->rsp_list_lock);
> > +     }
> > +}
> > +
> >  static void ufshpb_map_work_handler(struct work_struct *work)
> >  {
> >       struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu,
> > map_work);
> > @@ -1913,6 +1980,9 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> > *hba, struct ufshpb_lu *hpb)
> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
> >
> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> > +     if (hpb->is_hcm)
> > +             INIT_WORK(&hpb->ufshpb_normalization_work,
> > +                       ufshpb_normalization_work_handler);
> >
> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
> > @@ -2012,6 +2082,8 @@ static void ufshpb_discard_rsp_lists(struct
> > ufshpb_lu *hpb)
> >
> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
> >  {
> > +     if (hpb->is_hcm)
> > +             cancel_work_sync(&hpb->ufshpb_normalization_work);
> >       cancel_work_sync(&hpb->map_work);
> >  }
> >
> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> > index 8119b1a3d1e5..bd4308010466 100644
> > --- a/drivers/scsi/ufs/ufshpb.h
> > +++ b/drivers/scsi/ufs/ufshpb.h
> > @@ -121,6 +121,10 @@ struct ufshpb_region {
> >       struct list_head list_lru_rgn;
> >       unsigned long rgn_flags;
> >  #define RGN_FLAG_DIRTY 0
> > +
> > +     /* region reads - for host mode */
> > +     spinlock_t rgn_lock;
> > +     unsigned int reads;
> >  };
> >
> >  #define for_each_sub_region(rgn, i, srgn)                            \
> > @@ -211,6 +215,7 @@ struct ufshpb_lu {
> >
> >       /* for selecting victim */
> >       struct victim_select_info lru_info;
> > +     struct work_struct ufshpb_normalization_work;
> >
> >       /* pinned region information */
> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter
  2021-03-15  9:20     ` Avri Altman
@ 2021-03-15  9:31       ` Can Guo
  2021-03-17  9:19         ` Avri Altman
  0 siblings, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-15  9:31 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-15 17:20, Avri Altman wrote:
>> > +
>> > +             if (hpb->is_hcm) {
>> > +                     spin_lock_irqsave(&rgn->rgn_lock, flags);
>> 
>> rgn_lock is never used in IRQ contexts, so no need of irqsave and
>> irqrestore everywhere, which can impact performance. Please correct
>> me if I am wrong.
> Thanks.  Will do.
> 
>> 
>> Meanwhile, have you ever initialized the rgn_lock before use it???
> Yep - forgot to do that here (but not in gs20 and mi10).  Thanks.

You mean you didn't test this specific series before upload?
I haven't moved to the test stage, but this will definitely
cause you error...

Can Guo.

> 
> Thanks,
> Avri
> 
>> 
>> Thanks,
>> Can Guo.
>> 
>> > +                     rgn->reads = 0;
>> > +                     spin_unlock_irqrestore(&rgn->rgn_lock, flags);
>> > +             }
>> > +
>> >               return 0;
>> >       }
>> >
>> >       if (!ufshpb_is_support_chunk(hpb, transfer_len))
>> >               return 0;
>> >
>> > +     if (hpb->is_hcm) {
>> > +             bool activate = false;
>> > +             /*
>> > +              * in host control mode, reads are the main source for
>> > +              * activation trials.
>> > +              */
>> > +             spin_lock_irqsave(&rgn->rgn_lock, flags);
>> > +             rgn->reads++;
>> > +             if (rgn->reads == ACTIVATION_THRESHOLD)
>> > +                     activate = true;
>> > +             spin_unlock_irqrestore(&rgn->rgn_lock, flags);
>> > +             if (activate) {
>> > +                     spin_lock_irqsave(&hpb->rsp_list_lock, flags);
>> > +                     ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
>> > +                     hpb->stats.rb_active_cnt++;
>> > +                     spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>> > +                     dev_dbg(&hpb->sdev_ufs_lu->sdev_dev,
>> > +                             "activate region %d-%d\n", rgn_idx, srgn_idx);
>> > +             }
>> > +
>> > +             /* keep those counters normalized */
>> > +             if (rgn->reads > hpb->entries_per_srgn)
>> > +                     schedule_work(&hpb->ufshpb_normalization_work);
>> > +     }
>> > +
>> >       spin_lock_irqsave(&hpb->rgn_state_lock, flags);
>> >       if (ufshpb_test_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
>> >                                  transfer_len)) {
>> > @@ -745,21 +794,6 @@ static int ufshpb_clear_dirty_bitmap(struct
>> > ufshpb_lu *hpb,
>> >       return 0;
>> >  }
>> >
>> > -static void ufshpb_update_active_info(struct ufshpb_lu *hpb, int
>> > rgn_idx,
>> > -                                   int srgn_idx)
>> > -{
>> > -     struct ufshpb_region *rgn;
>> > -     struct ufshpb_subregion *srgn;
>> > -
>> > -     rgn = hpb->rgn_tbl + rgn_idx;
>> > -     srgn = rgn->srgn_tbl + srgn_idx;
>> > -
>> > -     list_del_init(&rgn->list_inact_rgn);
>> > -
>> > -     if (list_empty(&srgn->list_act_srgn))
>> > -             list_add_tail(&srgn->list_act_srgn, &hpb->lh_act_srgn);
>> > -}
>> > -
>> >  static void ufshpb_update_inactive_info(struct ufshpb_lu *hpb, int
>> > rgn_idx)
>> >  {
>> >       struct ufshpb_region *rgn;
>> > @@ -1079,6 +1113,14 @@ static void __ufshpb_evict_region(struct
>> > ufshpb_lu *hpb,
>> >
>> >       ufshpb_cleanup_lru_info(lru_info, rgn);
>> >
>> > +     if (hpb->is_hcm) {
>> > +             unsigned long flags;
>> > +
>> > +             spin_lock_irqsave(&rgn->rgn_lock, flags);
>> > +             rgn->reads = 0;
>> > +             spin_unlock_irqrestore(&rgn->rgn_lock, flags);
>> > +     }
>> > +
>> >       for_each_sub_region(rgn, srgn_idx, srgn)
>> >               ufshpb_purge_active_subregion(hpb, srgn);
>> >  }
>> > @@ -1523,6 +1565,31 @@ static void
>> > ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
>> >       spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>> >  }
>> >
>> > +static void ufshpb_normalization_work_handler(struct work_struct
>> > *work)
>> > +{
>> > +     struct ufshpb_lu *hpb;
>> > +     int rgn_idx;
>> > +     unsigned long flags;
>> > +
>> > +     hpb = container_of(work, struct ufshpb_lu,
>> > ufshpb_normalization_work);
>> > +
>> > +     for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) {
>> > +             struct ufshpb_region *rgn = hpb->rgn_tbl + rgn_idx;
>> > +
>> > +             spin_lock_irqsave(&rgn->rgn_lock, flags);
>> > +             rgn->reads = (rgn->reads >> 1);
>> > +             spin_unlock_irqrestore(&rgn->rgn_lock, flags);
>> > +
>> > +             if (rgn->rgn_state != HPB_RGN_ACTIVE || rgn->reads)
>> > +                     continue;
>> > +
>> > +             /* if region is active but has no reads - inactivate it */
>> > +             spin_lock(&hpb->rsp_list_lock);
>> > +             ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
>> > +             spin_unlock(&hpb->rsp_list_lock);
>> > +     }
>> > +}
>> > +
>> >  static void ufshpb_map_work_handler(struct work_struct *work)
>> >  {
>> >       struct ufshpb_lu *hpb = container_of(work, struct ufshpb_lu,
>> > map_work);
>> > @@ -1913,6 +1980,9 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
>> > *hba, struct ufshpb_lu *hpb)
>> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
>> >
>> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
>> > +     if (hpb->is_hcm)
>> > +             INIT_WORK(&hpb->ufshpb_normalization_work,
>> > +                       ufshpb_normalization_work_handler);
>> >
>> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
>> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
>> > @@ -2012,6 +2082,8 @@ static void ufshpb_discard_rsp_lists(struct
>> > ufshpb_lu *hpb)
>> >
>> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>> >  {
>> > +     if (hpb->is_hcm)
>> > +             cancel_work_sync(&hpb->ufshpb_normalization_work);
>> >       cancel_work_sync(&hpb->map_work);
>> >  }
>> >
>> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>> > index 8119b1a3d1e5..bd4308010466 100644
>> > --- a/drivers/scsi/ufs/ufshpb.h
>> > +++ b/drivers/scsi/ufs/ufshpb.h
>> > @@ -121,6 +121,10 @@ struct ufshpb_region {
>> >       struct list_head list_lru_rgn;
>> >       unsigned long rgn_flags;
>> >  #define RGN_FLAG_DIRTY 0
>> > +
>> > +     /* region reads - for host mode */
>> > +     spinlock_t rgn_lock;
>> > +     unsigned int reads;
>> >  };
>> >
>> >  #define for_each_sub_region(rgn, i, srgn)                            \
>> > @@ -211,6 +215,7 @@ struct ufshpb_lu {
>> >
>> >       /* for selecting victim */
>> >       struct victim_select_info lru_info;
>> > +     struct work_struct ufshpb_normalization_work;
>> >
>> >       /* pinned region information */
>> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer
  2021-03-02 13:25 ` [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer Avri Altman
  2021-03-15  1:37   ` Can Guo
@ 2021-03-15  9:36   ` Can Guo
  2021-03-16  9:21     ` Avri Altman
  1 sibling, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-15  9:36 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-02 21:25, Avri Altman wrote:
> In order not to hang on to “cold” regions, we shall inactivate a
> region that has no READ access for a predefined amount of time -
> READ_TO_MS. For that purpose we shall monitor the active regions list,
> polling it on every POLLING_INTERVAL_MS. On timeout expiry we shall add
> the region to the "to-be-inactivated" list, unless it is clean and did
> not exhaust its READ_TO_EXPIRIES - another parameter.
> 
> All this does not apply to pinned regions.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 65 +++++++++++++++++++++++++++++++++++++++
>  drivers/scsi/ufs/ufshpb.h |  6 ++++
>  2 files changed, 71 insertions(+)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index 0034fa03fdc6..89a930e72cff 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -18,6 +18,9 @@
> 
>  #define ACTIVATION_THRESHOLD 4 /* 4 IOs */
>  #define EVICTION_THRESHOLD (ACTIVATION_THRESHOLD << 6) /* 256 IOs */
> +#define READ_TO_MS 1000
> +#define READ_TO_EXPIRIES 100
> +#define POLLING_INTERVAL_MS 200
> 
>  /* memory management */
>  static struct kmem_cache *ufshpb_mctx_cache;
> @@ -1024,12 +1027,61 @@ static int
> ufshpb_check_srgns_issue_state(struct ufshpb_lu *hpb,
>  	return 0;
>  }
> 
> +static void ufshpb_read_to_handler(struct work_struct *work)
> +{
> +	struct delayed_work *dwork = to_delayed_work(work);
> +	struct ufshpb_lu *hpb;
> +	struct victim_select_info *lru_info;
> +	struct ufshpb_region *rgn;
> +	unsigned long flags;
> +	LIST_HEAD(expired_list);
> +
> +	hpb = container_of(dwork, struct ufshpb_lu, ufshpb_read_to_work);
> +
> +	spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> +
> +	lru_info = &hpb->lru_info;
> +
> +	list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) {
> +		bool timedout = ktime_after(ktime_get(), rgn->read_timeout);
> +
> +		if (timedout) {
> +			rgn->read_timeout_expiries--;
> +			if (is_rgn_dirty(rgn) ||
> +			    rgn->read_timeout_expiries == 0)
> +				list_add(&rgn->list_expired_rgn, &expired_list);
> +			else
> +				rgn->read_timeout = ktime_add_ms(ktime_get(),
> +							 READ_TO_MS);
> +		}
> +	}
> +
> +	spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> +
> +	list_for_each_entry(rgn, &expired_list, list_expired_rgn) {

Here can be problematic - since you don't have the native expired_list 
initialized
before use, if above loop did not insert anything to expired_list, it 
shall become
a dead loop here.

And, which lock is protecting rgn->list_expired_rgn? If two 
read_to_handler works
are running in parallel, one can be inserting it to its expired_list 
while another
can be deleting it.

Can Guo.

> +		list_del_init(&rgn->list_expired_rgn);
> +		spin_lock_irqsave(&hpb->rsp_list_lock, flags);
> +		ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
> +		hpb->stats.rb_inactive_cnt++;
> +		spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> +	}
> +
> +	ufshpb_kick_map_work(hpb);
> +
> +	schedule_delayed_work(&hpb->ufshpb_read_to_work,
> +			      msecs_to_jiffies(POLLING_INTERVAL_MS));
> +}
> +
>  static void ufshpb_add_lru_info(struct victim_select_info *lru_info,
>  				struct ufshpb_region *rgn)
>  {
>  	rgn->rgn_state = HPB_RGN_ACTIVE;
>  	list_add_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn);
>  	atomic_inc(&lru_info->active_cnt);
> +	if (rgn->hpb->is_hcm) {
> +		rgn->read_timeout = ktime_add_ms(ktime_get(), READ_TO_MS);
> +		rgn->read_timeout_expiries = READ_TO_EXPIRIES;
> +	}
>  }
> 
>  static void ufshpb_hit_lru_info(struct victim_select_info *lru_info,
> @@ -1813,6 +1865,7 @@ static int ufshpb_alloc_region_tbl(struct
> ufs_hba *hba, struct ufshpb_lu *hpb)
> 
>  		INIT_LIST_HEAD(&rgn->list_inact_rgn);
>  		INIT_LIST_HEAD(&rgn->list_lru_rgn);
> +		INIT_LIST_HEAD(&rgn->list_expired_rgn);
> 
>  		if (rgn_idx == hpb->rgns_per_lu - 1) {
>  			srgn_cnt = ((hpb->srgns_per_lu - 1) %
> @@ -1834,6 +1887,7 @@ static int ufshpb_alloc_region_tbl(struct
> ufs_hba *hba, struct ufshpb_lu *hpb)
>  		}
> 
>  		rgn->rgn_flags = 0;
> +		rgn->hpb = hpb;
>  	}
> 
>  	return 0;
> @@ -2053,6 +2107,8 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> *hba, struct ufshpb_lu *hpb)
>  			  ufshpb_normalization_work_handler);
>  		INIT_WORK(&hpb->ufshpb_lun_reset_work,
>  			  ufshpb_reset_work_handler);
> +		INIT_DELAYED_WORK(&hpb->ufshpb_read_to_work,
> +				  ufshpb_read_to_handler);
>  	}
> 
>  	hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
> @@ -2087,6 +2143,10 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> *hba, struct ufshpb_lu *hpb)
>  	ufshpb_stat_init(hpb);
>  	ufshpb_param_init(hpb);
> 
> +	if (hpb->is_hcm)
> +		schedule_delayed_work(&hpb->ufshpb_read_to_work,
> +				      msecs_to_jiffies(POLLING_INTERVAL_MS));
> +
>  	return 0;
> 
>  release_pre_req_mempool:
> @@ -2154,6 +2214,7 @@ static void ufshpb_discard_rsp_lists(struct
> ufshpb_lu *hpb)
>  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>  {
>  	if (hpb->is_hcm) {
> +		cancel_delayed_work_sync(&hpb->ufshpb_read_to_work);
>  		cancel_work_sync(&hpb->ufshpb_lun_reset_work);
>  		cancel_work_sync(&hpb->ufshpb_normalization_work);
>  	}
> @@ -2264,6 +2325,10 @@ void ufshpb_resume(struct ufs_hba *hba)
>  			continue;
>  		ufshpb_set_state(hpb, HPB_PRESENT);
>  		ufshpb_kick_map_work(hpb);
> +		if (hpb->is_hcm)
> +			schedule_delayed_work(&hpb->ufshpb_read_to_work,
> +				msecs_to_jiffies(POLLING_INTERVAL_MS));
> +
>  	}
>  }
> 
> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> index 37c1b0ea0c0a..b49e9a34267f 100644
> --- a/drivers/scsi/ufs/ufshpb.h
> +++ b/drivers/scsi/ufs/ufshpb.h
> @@ -109,6 +109,7 @@ struct ufshpb_subregion {
>  };
> 
>  struct ufshpb_region {
> +	struct ufshpb_lu *hpb;
>  	struct ufshpb_subregion *srgn_tbl;
>  	enum HPB_RGN_STATE rgn_state;
>  	int rgn_idx;
> @@ -126,6 +127,10 @@ struct ufshpb_region {
>  	/* region reads - for host mode */
>  	spinlock_t rgn_lock;
>  	unsigned int reads;
> +	/* region "cold" timer - for host mode */
> +	ktime_t read_timeout;
> +	unsigned int read_timeout_expiries;
> +	struct list_head list_expired_rgn;
>  };
> 
>  #define for_each_sub_region(rgn, i, srgn)				\
> @@ -219,6 +224,7 @@ struct ufshpb_lu {
>  	struct victim_select_info lru_info;
>  	struct work_struct ufshpb_normalization_work;
>  	struct work_struct ufshpb_lun_reset_work;
> +	struct delayed_work ufshpb_read_to_work;
> 
>  	/* pinned region information */
>  	u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
  2021-03-15  7:33     ` Can Guo
@ 2021-03-16  8:30       ` Avri Altman
  2021-03-17  1:23         ` Can Guo
       [not found]       ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p3>
  1 sibling, 1 reply; 58+ messages in thread
From: Avri Altman @ 2021-03-16  8:30 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> >> ---
> >>  drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
> >>  drivers/scsi/ufs/ufshpb.h |  1 +
> >>  2 files changed, 15 insertions(+)
> >>
> >> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> >> index 6f4fd22eaf2f..0744feb4d484 100644
> >> --- a/drivers/scsi/ufs/ufshpb.c
> >> +++ b/drivers/scsi/ufs/ufshpb.c
> >> @@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct
> >> ufshpb_lu *hpb,
> >>
> >>      blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_umap_req_compl_fn);
> >>
> >> +    hpb->stats.umap_req_cnt++;
> >>      return 0;
> >>  }
> >>
> >> @@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct
> >> ufshpb_lu *hpb,
> >>      return -EAGAIN;
> >>  }
> >>
> >> +static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
> >> +                                    struct ufshpb_region *rgn)
> >> +{
> >> +    return ufshpb_issue_umap_req(hpb, rgn);
> >> +}
> >> +
> >>  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
> >>  {
> >>      return ufshpb_issue_umap_req(hpb, NULL);
> >> @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct
> >> ufshpb_lu *hpb,
> >>      struct ufshpb_subregion *srgn;
> >>      int srgn_idx;
> >>
> >> +
> >> +    if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))
> >
> > __ufshpb_evict_region() is called with rgn_state_lock held and IRQ
> > disabled,
> > when ufshpb_issue_umap_single_req() invokes blk_execute_rq_nowait(),
> > below
> > warning shall pop up every time, fix it?
> >
> > void blk_execute_rq_nowait(struct request_queue *q, struct gendisk
> > *bd_disk,
> >                  struct request *rq, int at_head,
> >                          rq_end_io_fn *done)
> > {
> >       WARN_ON(irqs_disabled());
> > ...
> >
> 
> Moreover, since we are here with rgn_state_lock held and IRQ disabled,
> in ufshpb_get_req(), rq = kmem_cache_alloc(hpb->map_req_cache,
> GFP_KERNEL)
> has the GFP_KERNEL flag, scheduling while atomic???
I think your comment applies to  ufshpb_issue_umap_all_req as well,
Which is called from slave_configure/scsi_add_lun.

Since the host-mode series is utilizing the framework laid by the device-mode,
Maybe you can add this comment to  Daejun's last version?

Thanks,
Avri

> 
> Can Guo.
> 
> > Thanks.
> > Can Guo.
> >
> >> +            return;
> >> +
> >>      lru_info = &hpb->lru_info;
> >>
> >>      dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n",
> >> rgn->rgn_idx);
> >> @@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
> >>  ufshpb_sysfs_attr_show_func(rb_active_cnt);
> >>  ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
> >>  ufshpb_sysfs_attr_show_func(map_req_cnt);
> >> +ufshpb_sysfs_attr_show_func(umap_req_cnt);
> >>
> >>  static struct attribute *hpb_dev_stat_attrs[] = {
> >>      &dev_attr_hit_cnt.attr,
> >> @@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[] =
> >> {
> >>      &dev_attr_rb_active_cnt.attr,
> >>      &dev_attr_rb_inactive_cnt.attr,
> >>      &dev_attr_map_req_cnt.attr,
> >> +    &dev_attr_umap_req_cnt.attr,
> >>      NULL,
> >>  };
> >>
> >> @@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu
> >> *hpb)
> >>      hpb->stats.rb_active_cnt = 0;
> >>      hpb->stats.rb_inactive_cnt = 0;
> >>      hpb->stats.map_req_cnt = 0;
> >> +    hpb->stats.umap_req_cnt = 0;
> >>  }
> >>
> >>  static void ufshpb_param_init(struct ufshpb_lu *hpb)
> >> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> >> index bd4308010466..84598a317897 100644
> >> --- a/drivers/scsi/ufs/ufshpb.h
> >> +++ b/drivers/scsi/ufs/ufshpb.h
> >> @@ -186,6 +186,7 @@ struct ufshpb_stats {
> >>      u64 rb_inactive_cnt;
> >>      u64 map_req_cnt;
> >>      u64 pre_req_cnt;
> >> +    u64 umap_req_cnt;
> >>  };
> >>
> >>  struct ufshpb_lu {

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 08/10] scsi: ufshpb: Limit the number of inflight map requests
  2021-03-15  8:31   ` Can Guo
@ 2021-03-16  8:32     ` Avri Altman
  0 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-16  8:32 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> 
> 
> On 2021-03-02 21:25, Avri Altman wrote:
> > in host control mode the host is the originator of map requests. To not
> 
> in -> In
Done.

> 
> Thanks,
> Can Guo.
> 
> > flood the device with map requests, use a simple throttling mechanism
> > that limits the number of inflight map requests.
> >
> > Signed-off-by: Avri Altman <avri.altman@wdc.com>
> > ---
> >  drivers/scsi/ufs/ufshpb.c | 11 +++++++++++
> >  drivers/scsi/ufs/ufshpb.h |  1 +
> >  2 files changed, 12 insertions(+)
> >
> > diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> > index 89a930e72cff..74da69727340 100644
> > --- a/drivers/scsi/ufs/ufshpb.c
> > +++ b/drivers/scsi/ufs/ufshpb.c
> > @@ -21,6 +21,7 @@
> >  #define READ_TO_MS 1000
> >  #define READ_TO_EXPIRIES 100
> >  #define POLLING_INTERVAL_MS 200
> > +#define THROTTLE_MAP_REQ_DEFAULT 1
> >
> >  /* memory management */
> >  static struct kmem_cache *ufshpb_mctx_cache;
> > @@ -750,6 +751,14 @@ static struct ufshpb_req
> > *ufshpb_get_map_req(struct ufshpb_lu *hpb,
> >       struct ufshpb_req *map_req;
> >       struct bio *bio;
> >
> > +     if (hpb->is_hcm &&
> > +         hpb->num_inflight_map_req >= THROTTLE_MAP_REQ_DEFAULT) {
> > +             dev_info(&hpb->sdev_ufs_lu->sdev_dev,
> > +                      "map_req throttle. inflight %d throttle %d",
> > +                      hpb->num_inflight_map_req, THROTTLE_MAP_REQ_DEFAULT);
> > +             return NULL;
> > +     }
> > +
> >       map_req = ufshpb_get_req(hpb, srgn->rgn_idx, REQ_OP_SCSI_IN);
> >       if (!map_req)
> >               return NULL;
> > @@ -764,6 +773,7 @@ static struct ufshpb_req
> > *ufshpb_get_map_req(struct ufshpb_lu *hpb,
> >
> >       map_req->rb.srgn_idx = srgn->srgn_idx;
> >       map_req->rb.mctx = srgn->mctx;
> > +     hpb->num_inflight_map_req++;
> >
> >       return map_req;
> >  }
> > @@ -773,6 +783,7 @@ static void ufshpb_put_map_req(struct ufshpb_lu
> > *hpb,
> >  {
> >       bio_put(map_req->bio);
> >       ufshpb_put_req(hpb, map_req);
> > +     hpb->num_inflight_map_req--;
> >  }
> >
> >  static int ufshpb_clear_dirty_bitmap(struct ufshpb_lu *hpb,
> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> > index b49e9a34267f..d83ab488688a 100644
> > --- a/drivers/scsi/ufs/ufshpb.h
> > +++ b/drivers/scsi/ufs/ufshpb.h
> > @@ -212,6 +212,7 @@ struct ufshpb_lu {
> >       struct ufshpb_req *pre_req;
> >       int num_inflight_pre_req;
> >       int throttle_pre_req;
> > +     int num_inflight_map_req;
> >       struct list_head lh_pre_req_free;
> >       int cur_read_id;
> >       int pre_req_min_tr_len;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 04/10] scsi: ufshpb: Make eviction depends on region's reads
  2021-03-15  8:30   ` Can Guo
@ 2021-03-16  8:34     ` Avri Altman
  0 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-16  8:34 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> >       int ret = 0;
> > @@ -1263,6 +1271,16 @@ static int ufshpb_add_region(struct ufshpb_lu
> > *hpb, struct ufshpb_region *rgn)
> >                        * because the device could detect this region
> >                        * by not issuing HPB_READ
> >                        */
> > +
> > +                     /*
> > +                      * in host control mode, verify that the entering
> > +                      * region has enough reads
> > +                      */
> 
> Maybe merge the new comments with the original comments above?
Done.

Thanks,
Avri

> Thanks,
> Can Guo.

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer
  2021-03-15  9:36   ` Can Guo
@ 2021-03-16  9:21     ` Avri Altman
  2021-03-17  2:45       ` Can Guo
  0 siblings, 1 reply; 58+ messages in thread
From: Avri Altman @ 2021-03-16  9:21 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> > +static void ufshpb_read_to_handler(struct work_struct *work)
> > +{
> > +     struct delayed_work *dwork = to_delayed_work(work);
> > +     struct ufshpb_lu *hpb;
> > +     struct victim_select_info *lru_info;
> > +     struct ufshpb_region *rgn;
> > +     unsigned long flags;
> > +     LIST_HEAD(expired_list);
> > +
> > +     hpb = container_of(dwork, struct ufshpb_lu, ufshpb_read_to_work);
> > +
> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> > +
> > +     lru_info = &hpb->lru_info;
> > +
> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) {
> > +             bool timedout = ktime_after(ktime_get(), rgn->read_timeout);
> > +
> > +             if (timedout) {
> > +                     rgn->read_timeout_expiries--;
> > +                     if (is_rgn_dirty(rgn) ||
> > +                         rgn->read_timeout_expiries == 0)
> > +                             list_add(&rgn->list_expired_rgn, &expired_list);
> > +                     else
> > +                             rgn->read_timeout = ktime_add_ms(ktime_get(),
> > +                                                      READ_TO_MS);
> > +             }
> > +     }
> > +
> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> > +
> > +     list_for_each_entry(rgn, &expired_list, list_expired_rgn) {
> 
> Here can be problematic - since you don't have the native expired_list
> initialized
> before use, if above loop did not insert anything to expired_list, it
> shall become
> a dead loop here.
Not sure what you meant by native initialization.
LIST_HEAD is statically initializing an empty list, resulting the same outcome as INIT_LIST_HEAD.

> 
> And, which lock is protecting rgn->list_expired_rgn? If two
> read_to_handler works
> are running in parallel, one can be inserting it to its expired_list
> while another
> can be deleting it.
The timeout handler, being a delayed work, is meant to run every polling period.
Originally, I had it protected from 2 handlers running concurrently,
But I removed it following Daejun's comment, which I accepted,
Since it is always scheduled using the same polling period.

Thanks,
Avri

> 
> Can Guo.
> 
> > +             list_del_init(&rgn->list_expired_rgn);
> > +             spin_lock_irqsave(&hpb->rsp_list_lock, flags);
> > +             ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
> > +             hpb->stats.rb_inactive_cnt++;
> > +             spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> > +     }
> > +
> > +     ufshpb_kick_map_work(hpb);
> > +
> > +     schedule_delayed_work(&hpb->ufshpb_read_to_work,
> > +                           msecs_to_jiffies(POLLING_INTERVAL_MS));
> > +}
> > +
> >  static void ufshpb_add_lru_info(struct victim_select_info *lru_info,
> >                               struct ufshpb_region *rgn)
> >  {
> >       rgn->rgn_state = HPB_RGN_ACTIVE;
> >       list_add_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn);
> >       atomic_inc(&lru_info->active_cnt);
> > +     if (rgn->hpb->is_hcm) {
> > +             rgn->read_timeout = ktime_add_ms(ktime_get(), READ_TO_MS);
> > +             rgn->read_timeout_expiries = READ_TO_EXPIRIES;
> > +     }
> >  }
> >
> >  static void ufshpb_hit_lru_info(struct victim_select_info *lru_info,
> > @@ -1813,6 +1865,7 @@ static int ufshpb_alloc_region_tbl(struct
> > ufs_hba *hba, struct ufshpb_lu *hpb)
> >
> >               INIT_LIST_HEAD(&rgn->list_inact_rgn);
> >               INIT_LIST_HEAD(&rgn->list_lru_rgn);
> > +             INIT_LIST_HEAD(&rgn->list_expired_rgn);
> >
> >               if (rgn_idx == hpb->rgns_per_lu - 1) {
> >                       srgn_cnt = ((hpb->srgns_per_lu - 1) %
> > @@ -1834,6 +1887,7 @@ static int ufshpb_alloc_region_tbl(struct
> > ufs_hba *hba, struct ufshpb_lu *hpb)
> >               }
> >
> >               rgn->rgn_flags = 0;
> > +             rgn->hpb = hpb;
> >       }
> >
> >       return 0;
> > @@ -2053,6 +2107,8 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> > *hba, struct ufshpb_lu *hpb)
> >                         ufshpb_normalization_work_handler);
> >               INIT_WORK(&hpb->ufshpb_lun_reset_work,
> >                         ufshpb_reset_work_handler);
> > +             INIT_DELAYED_WORK(&hpb->ufshpb_read_to_work,
> > +                               ufshpb_read_to_handler);
> >       }
> >
> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
> > @@ -2087,6 +2143,10 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> > *hba, struct ufshpb_lu *hpb)
> >       ufshpb_stat_init(hpb);
> >       ufshpb_param_init(hpb);
> >
> > +     if (hpb->is_hcm)
> > +             schedule_delayed_work(&hpb->ufshpb_read_to_work,
> > +                                   msecs_to_jiffies(POLLING_INTERVAL_MS));
> > +
> >       return 0;
> >
> >  release_pre_req_mempool:
> > @@ -2154,6 +2214,7 @@ static void ufshpb_discard_rsp_lists(struct
> > ufshpb_lu *hpb)
> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
> >  {
> >       if (hpb->is_hcm) {
> > +             cancel_delayed_work_sync(&hpb->ufshpb_read_to_work);
> >               cancel_work_sync(&hpb->ufshpb_lun_reset_work);
> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
> >       }
> > @@ -2264,6 +2325,10 @@ void ufshpb_resume(struct ufs_hba *hba)
> >                       continue;
> >               ufshpb_set_state(hpb, HPB_PRESENT);
> >               ufshpb_kick_map_work(hpb);
> > +             if (hpb->is_hcm)
> > +                     schedule_delayed_work(&hpb->ufshpb_read_to_work,
> > +                             msecs_to_jiffies(POLLING_INTERVAL_MS));
> > +
> >       }
> >  }
> >
> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> > index 37c1b0ea0c0a..b49e9a34267f 100644
> > --- a/drivers/scsi/ufs/ufshpb.h
> > +++ b/drivers/scsi/ufs/ufshpb.h
> > @@ -109,6 +109,7 @@ struct ufshpb_subregion {
> >  };
> >
> >  struct ufshpb_region {
> > +     struct ufshpb_lu *hpb;
> >       struct ufshpb_subregion *srgn_tbl;
> >       enum HPB_RGN_STATE rgn_state;
> >       int rgn_idx;
> > @@ -126,6 +127,10 @@ struct ufshpb_region {
> >       /* region reads - for host mode */
> >       spinlock_t rgn_lock;
> >       unsigned int reads;
> > +     /* region "cold" timer - for host mode */
> > +     ktime_t read_timeout;
> > +     unsigned int read_timeout_expiries;
> > +     struct list_head list_expired_rgn;
> >  };
> >
> >  #define for_each_sub_region(rgn, i, srgn)                            \
> > @@ -219,6 +224,7 @@ struct ufshpb_lu {
> >       struct victim_select_info lru_info;
> >       struct work_struct ufshpb_normalization_work;
> >       struct work_struct ufshpb_lun_reset_work;
> > +     struct delayed_work ufshpb_read_to_work;
> >
> >       /* pinned region information */
> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
  2021-03-16  8:30       ` Avri Altman
@ 2021-03-17  1:23         ` Can Guo
  0 siblings, 0 replies; 58+ messages in thread
From: Can Guo @ 2021-03-17  1:23 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-16 16:30, Avri Altman wrote:
>> >> ---
>> >>  drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
>> >>  drivers/scsi/ufs/ufshpb.h |  1 +
>> >>  2 files changed, 15 insertions(+)
>> >>
>> >> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>> >> index 6f4fd22eaf2f..0744feb4d484 100644
>> >> --- a/drivers/scsi/ufs/ufshpb.c
>> >> +++ b/drivers/scsi/ufs/ufshpb.c
>> >> @@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct
>> >> ufshpb_lu *hpb,
>> >>
>> >>      blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_umap_req_compl_fn);
>> >>
>> >> +    hpb->stats.umap_req_cnt++;
>> >>      return 0;
>> >>  }
>> >>
>> >> @@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct
>> >> ufshpb_lu *hpb,
>> >>      return -EAGAIN;
>> >>  }
>> >>
>> >> +static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
>> >> +                                    struct ufshpb_region *rgn)
>> >> +{
>> >> +    return ufshpb_issue_umap_req(hpb, rgn);
>> >> +}
>> >> +
>> >>  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
>> >>  {
>> >>      return ufshpb_issue_umap_req(hpb, NULL);
>> >> @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct
>> >> ufshpb_lu *hpb,
>> >>      struct ufshpb_subregion *srgn;
>> >>      int srgn_idx;
>> >>
>> >> +
>> >> +    if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))
>> >
>> > __ufshpb_evict_region() is called with rgn_state_lock held and IRQ
>> > disabled,
>> > when ufshpb_issue_umap_single_req() invokes blk_execute_rq_nowait(),
>> > below
>> > warning shall pop up every time, fix it?
>> >
>> > void blk_execute_rq_nowait(struct request_queue *q, struct gendisk
>> > *bd_disk,
>> >                  struct request *rq, int at_head,
>> >                          rq_end_io_fn *done)
>> > {
>> >       WARN_ON(irqs_disabled());
>> > ...
>> >
>> 
>> Moreover, since we are here with rgn_state_lock held and IRQ disabled,
>> in ufshpb_get_req(), rq = kmem_cache_alloc(hpb->map_req_cache,
>> GFP_KERNEL)
>> has the GFP_KERNEL flag, scheduling while atomic???
> I think your comment applies to  ufshpb_issue_umap_all_req as well,
> Which is called from slave_configure/scsi_add_lun.

ufshpb_issue_umap_all_req() is not called from atomic contexts,
so ufshpb_issue_umap_all_req() is fine.

Thanks,
Can Guo.

> 
> Since the host-mode series is utilizing the framework laid by the 
> device-mode,
> Maybe you can add this comment to  Daejun's last version?
> 
> Thanks,
> Avri
> 
>> 
>> Can Guo.
>> 
>> > Thanks.
>> > Can Guo.
>> >
>> >> +            return;
>> >> +
>> >>      lru_info = &hpb->lru_info;
>> >>
>> >>      dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n",
>> >> rgn->rgn_idx);
>> >> @@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
>> >>  ufshpb_sysfs_attr_show_func(rb_active_cnt);
>> >>  ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
>> >>  ufshpb_sysfs_attr_show_func(map_req_cnt);
>> >> +ufshpb_sysfs_attr_show_func(umap_req_cnt);
>> >>
>> >>  static struct attribute *hpb_dev_stat_attrs[] = {
>> >>      &dev_attr_hit_cnt.attr,
>> >> @@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[] =
>> >> {
>> >>      &dev_attr_rb_active_cnt.attr,
>> >>      &dev_attr_rb_inactive_cnt.attr,
>> >>      &dev_attr_map_req_cnt.attr,
>> >> +    &dev_attr_umap_req_cnt.attr,
>> >>      NULL,
>> >>  };
>> >>
>> >> @@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu
>> >> *hpb)
>> >>      hpb->stats.rb_active_cnt = 0;
>> >>      hpb->stats.rb_inactive_cnt = 0;
>> >>      hpb->stats.map_req_cnt = 0;
>> >> +    hpb->stats.umap_req_cnt = 0;
>> >>  }
>> >>
>> >>  static void ufshpb_param_init(struct ufshpb_lu *hpb)
>> >> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>> >> index bd4308010466..84598a317897 100644
>> >> --- a/drivers/scsi/ufs/ufshpb.h
>> >> +++ b/drivers/scsi/ufs/ufshpb.h
>> >> @@ -186,6 +186,7 @@ struct ufshpb_stats {
>> >>      u64 rb_inactive_cnt;
>> >>      u64 map_req_cnt;
>> >>      u64 pre_req_cnt;
>> >> +    u64 umap_req_cnt;
>> >>  };
>> >>
>> >>  struct ufshpb_lu {

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: RE: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
       [not found]       ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p3>
@ 2021-03-17  2:28         ` Daejun Park
  2021-03-17  4:41           ` Can Guo
       [not found]           ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p4>
  0 siblings, 2 replies; 58+ messages in thread
From: Daejun Park @ 2021-03-17  2:28 UTC (permalink / raw)
  To: Avri Altman, Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, ALIM AKHTAR, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

>> >> ---
>> >>  drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
>> >>  drivers/scsi/ufs/ufshpb.h |  1 +
>> >>  2 files changed, 15 insertions(+)
>> >>
>> >> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>> >> index 6f4fd22eaf2f..0744feb4d484 100644
>> >> --- a/drivers/scsi/ufs/ufshpb.c
>> >> +++ b/drivers/scsi/ufs/ufshpb.c
>> >> @@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct
>> >> ufshpb_lu *hpb,
>> >>
>> >>      blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_umap_req_compl_fn);
>> >>
>> >> +    hpb->stats.umap_req_cnt++;
>> >>      return 0;
>> >>  }
>> >>
>> >> @@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct
>> >> ufshpb_lu *hpb,
>> >>      return -EAGAIN;
>> >>  }
>> >>
>> >> +static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
>> >> +                                    struct ufshpb_region *rgn)
>> >> +{
>> >> +    return ufshpb_issue_umap_req(hpb, rgn);
>> >> +}
>> >> +
>> >>  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
>> >>  {
>> >>      return ufshpb_issue_umap_req(hpb, NULL);
>> >> @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct
>> >> ufshpb_lu *hpb,
>> >>      struct ufshpb_subregion *srgn;
>> >>      int srgn_idx;
>> >>
>> >> +
>> >> +    if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))
>> >
>> > __ufshpb_evict_region() is called with rgn_state_lock held and IRQ
>> > disabled,
>> > when ufshpb_issue_umap_single_req() invokes blk_execute_rq_nowait(),
>> > below
>> > warning shall pop up every time, fix it?
>> >
>> > void blk_execute_rq_nowait(struct request_queue *q, struct gendisk
>> > *bd_disk,
>> >                  struct request *rq, int at_head,
>> >                          rq_end_io_fn *done)
>> > {
>> >       WARN_ON(irqs_disabled());
>> > ...
>> >
>> 
>> Moreover, since we are here with rgn_state_lock held and IRQ disabled,
>> in ufshpb_get_req(), rq = kmem_cache_alloc(hpb->map_req_cache,
>> GFP_KERNEL)
>> has the GFP_KERNEL flag, scheduling while atomic???
>I think your comment applies to  ufshpb_issue_umap_all_req as well,
>Which is called from slave_configure/scsi_add_lun.
> 
>Since the host-mode series is utilizing the framework laid by the device-mode,
>Maybe you can add this comment to  Daejun's last version?

Hi Avri, Can Guo

I think ufshpb_issue_umap_single_req() can be moved to end of ufshpb_evict_region().
Then we can avoid rgn_state_lock when it sends unmap command.

Thanks,
Daejun


>Thanks,
>Avri
> 
>> 
>> Can Guo.
>> 
>> > Thanks.
>> > Can Guo.
>> >
>> >> +            return;
>> >> +
>> >>      lru_info = &hpb->lru_info;
>> >>
>> >>      dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n",
>> >> rgn->rgn_idx);
>> >> @@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
>> >>  ufshpb_sysfs_attr_show_func(rb_active_cnt);
>> >>  ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
>> >>  ufshpb_sysfs_attr_show_func(map_req_cnt);
>> >> +ufshpb_sysfs_attr_show_func(umap_req_cnt);
>> >>
>> >>  static struct attribute *hpb_dev_stat_attrs[] = {
>> >>      &dev_attr_hit_cnt.attr,
>> >> @@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[] =
>> >> {
>> >>      &dev_attr_rb_active_cnt.attr,
>> >>      &dev_attr_rb_inactive_cnt.attr,
>> >>      &dev_attr_map_req_cnt.attr,
>> >> +    &dev_attr_umap_req_cnt.attr,
>> >>      NULL,
>> >>  };
>> >>
>> >> @@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu
>> >> *hpb)
>> >>      hpb->stats.rb_active_cnt = 0;
>> >>      hpb->stats.rb_inactive_cnt = 0;
>> >>      hpb->stats.map_req_cnt = 0;
>> >> +    hpb->stats.umap_req_cnt = 0;
>> >>  }
>> >>
>> >>  static void ufshpb_param_init(struct ufshpb_lu *hpb)
>> >> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>> >> index bd4308010466..84598a317897 100644
>> >> --- a/drivers/scsi/ufs/ufshpb.h
>> >> +++ b/drivers/scsi/ufs/ufshpb.h
>> >> @@ -186,6 +186,7 @@ struct ufshpb_stats {
>> >>      u64 rb_inactive_cnt;
>> >>      u64 map_req_cnt;
>> >>      u64 pre_req_cnt;
>> >> +    u64 umap_req_cnt;
>> >>  };
>> >>
>> >>  struct ufshpb_lu {
> 
> 
>  

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer
  2021-03-16  9:21     ` Avri Altman
@ 2021-03-17  2:45       ` Can Guo
  2021-03-17  7:55         ` Avri Altman
  0 siblings, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-17  2:45 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-16 17:21, Avri Altman wrote:
>> > +static void ufshpb_read_to_handler(struct work_struct *work)
>> > +{
>> > +     struct delayed_work *dwork = to_delayed_work(work);
>> > +     struct ufshpb_lu *hpb;
>> > +     struct victim_select_info *lru_info;
>> > +     struct ufshpb_region *rgn;
>> > +     unsigned long flags;
>> > +     LIST_HEAD(expired_list);
>> > +
>> > +     hpb = container_of(dwork, struct ufshpb_lu, ufshpb_read_to_work);
>> > +
>> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
>> > +
>> > +     lru_info = &hpb->lru_info;
>> > +
>> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) {
>> > +             bool timedout = ktime_after(ktime_get(), rgn->read_timeout);
>> > +
>> > +             if (timedout) {
>> > +                     rgn->read_timeout_expiries--;
>> > +                     if (is_rgn_dirty(rgn) ||
>> > +                         rgn->read_timeout_expiries == 0)
>> > +                             list_add(&rgn->list_expired_rgn, &expired_list);
>> > +                     else
>> > +                             rgn->read_timeout = ktime_add_ms(ktime_get(),
>> > +                                                      READ_TO_MS);
>> > +             }
>> > +     }
>> > +
>> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
>> > +
>> > +     list_for_each_entry(rgn, &expired_list, list_expired_rgn) {
>> 
>> Here can be problematic - since you don't have the native expired_list
>> initialized
>> before use, if above loop did not insert anything to expired_list, it
>> shall become
>> a dead loop here.
> Not sure what you meant by native initialization.
> LIST_HEAD is statically initializing an empty list, resulting the same
> outcome as INIT_LIST_HEAD.
> 

Sorry for making you confused, you should use list_for_each_entry_safe()
instead of list_for_each_entry() as you are deleting entries within the 
loop,
otherwise, this can become an infinite loop. Again, have you tested this 
patch
before upload? I am sure this is problematic - when it becomes an 
inifinite
loop, below path will hang...

ufshcd_suspend()->ufshpb_suspend()->cancel_jobs()->cancel_delayed_work()

>> 
>> And, which lock is protecting rgn->list_expired_rgn? If two
>> read_to_handler works
>> are running in parallel, one can be inserting it to its expired_list
>> while another
>> can be deleting it.
> The timeout handler, being a delayed work, is meant to run every 
> polling period.
> Originally, I had it protected from 2 handlers running concurrently,
> But I removed it following Daejun's comment, which I accepted,
> Since it is always scheduled using the same polling period.

But one can set the delay to 0 through sysfs, right?

Thanks,
Can Guo.

> 
> Thanks,
> Avri
> 
>> 
>> Can Guo.
>> 
>> > +             list_del_init(&rgn->list_expired_rgn);
>> > +             spin_lock_irqsave(&hpb->rsp_list_lock, flags);
>> > +             ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
>> > +             hpb->stats.rb_inactive_cnt++;
>> > +             spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>> > +     }
>> > +
>> > +     ufshpb_kick_map_work(hpb);
>> > +
>> > +     schedule_delayed_work(&hpb->ufshpb_read_to_work,
>> > +                           msecs_to_jiffies(POLLING_INTERVAL_MS));
>> > +}
>> > +
>> >  static void ufshpb_add_lru_info(struct victim_select_info *lru_info,
>> >                               struct ufshpb_region *rgn)
>> >  {
>> >       rgn->rgn_state = HPB_RGN_ACTIVE;
>> >       list_add_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn);
>> >       atomic_inc(&lru_info->active_cnt);
>> > +     if (rgn->hpb->is_hcm) {
>> > +             rgn->read_timeout = ktime_add_ms(ktime_get(), READ_TO_MS);
>> > +             rgn->read_timeout_expiries = READ_TO_EXPIRIES;
>> > +     }
>> >  }
>> >
>> >  static void ufshpb_hit_lru_info(struct victim_select_info *lru_info,
>> > @@ -1813,6 +1865,7 @@ static int ufshpb_alloc_region_tbl(struct
>> > ufs_hba *hba, struct ufshpb_lu *hpb)
>> >
>> >               INIT_LIST_HEAD(&rgn->list_inact_rgn);
>> >               INIT_LIST_HEAD(&rgn->list_lru_rgn);
>> > +             INIT_LIST_HEAD(&rgn->list_expired_rgn);
>> >
>> >               if (rgn_idx == hpb->rgns_per_lu - 1) {
>> >                       srgn_cnt = ((hpb->srgns_per_lu - 1) %
>> > @@ -1834,6 +1887,7 @@ static int ufshpb_alloc_region_tbl(struct
>> > ufs_hba *hba, struct ufshpb_lu *hpb)
>> >               }
>> >
>> >               rgn->rgn_flags = 0;
>> > +             rgn->hpb = hpb;
>> >       }
>> >
>> >       return 0;
>> > @@ -2053,6 +2107,8 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
>> > *hba, struct ufshpb_lu *hpb)
>> >                         ufshpb_normalization_work_handler);
>> >               INIT_WORK(&hpb->ufshpb_lun_reset_work,
>> >                         ufshpb_reset_work_handler);
>> > +             INIT_DELAYED_WORK(&hpb->ufshpb_read_to_work,
>> > +                               ufshpb_read_to_handler);
>> >       }
>> >
>> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
>> > @@ -2087,6 +2143,10 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
>> > *hba, struct ufshpb_lu *hpb)
>> >       ufshpb_stat_init(hpb);
>> >       ufshpb_param_init(hpb);
>> >
>> > +     if (hpb->is_hcm)
>> > +             schedule_delayed_work(&hpb->ufshpb_read_to_work,
>> > +                                   msecs_to_jiffies(POLLING_INTERVAL_MS));
>> > +
>> >       return 0;
>> >
>> >  release_pre_req_mempool:
>> > @@ -2154,6 +2214,7 @@ static void ufshpb_discard_rsp_lists(struct
>> > ufshpb_lu *hpb)
>> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>> >  {
>> >       if (hpb->is_hcm) {
>> > +             cancel_delayed_work_sync(&hpb->ufshpb_read_to_work);
>> >               cancel_work_sync(&hpb->ufshpb_lun_reset_work);
>> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
>> >       }
>> > @@ -2264,6 +2325,10 @@ void ufshpb_resume(struct ufs_hba *hba)
>> >                       continue;
>> >               ufshpb_set_state(hpb, HPB_PRESENT);
>> >               ufshpb_kick_map_work(hpb);
>> > +             if (hpb->is_hcm)
>> > +                     schedule_delayed_work(&hpb->ufshpb_read_to_work,
>> > +                             msecs_to_jiffies(POLLING_INTERVAL_MS));
>> > +
>> >       }
>> >  }
>> >
>> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>> > index 37c1b0ea0c0a..b49e9a34267f 100644
>> > --- a/drivers/scsi/ufs/ufshpb.h
>> > +++ b/drivers/scsi/ufs/ufshpb.h
>> > @@ -109,6 +109,7 @@ struct ufshpb_subregion {
>> >  };
>> >
>> >  struct ufshpb_region {
>> > +     struct ufshpb_lu *hpb;
>> >       struct ufshpb_subregion *srgn_tbl;
>> >       enum HPB_RGN_STATE rgn_state;
>> >       int rgn_idx;
>> > @@ -126,6 +127,10 @@ struct ufshpb_region {
>> >       /* region reads - for host mode */
>> >       spinlock_t rgn_lock;
>> >       unsigned int reads;
>> > +     /* region "cold" timer - for host mode */
>> > +     ktime_t read_timeout;
>> > +     unsigned int read_timeout_expiries;
>> > +     struct list_head list_expired_rgn;
>> >  };
>> >
>> >  #define for_each_sub_region(rgn, i, srgn)                            \
>> > @@ -219,6 +224,7 @@ struct ufshpb_lu {
>> >       struct victim_select_info lru_info;
>> >       struct work_struct ufshpb_normalization_work;
>> >       struct work_struct ufshpb_lun_reset_work;
>> > +     struct delayed_work ufshpb_read_to_work;
>> >
>> >       /* pinned region information */
>> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
  2021-03-17  2:28         ` Daejun Park
@ 2021-03-17  4:41           ` Can Guo
  2021-03-17  7:59             ` Avri Altman
       [not found]           ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p4>
  1 sibling, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-17  4:41 UTC (permalink / raw)
  To: daejun7.park
  Cc: Avri Altman, James E . J . Bottomley, Martin K . Petersen,
	linux-scsi, linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	ALIM AKHTAR, asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo,
	stanley.chu

On 2021-03-17 10:28, Daejun Park wrote:
>>> >> ---
>>> >>  drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
>>> >>  drivers/scsi/ufs/ufshpb.h |  1 +
>>> >>  2 files changed, 15 insertions(+)
>>> >>
>>> >> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>>> >> index 6f4fd22eaf2f..0744feb4d484 100644
>>> >> --- a/drivers/scsi/ufs/ufshpb.c
>>> >> +++ b/drivers/scsi/ufs/ufshpb.c
>>> >> @@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct
>>> >> ufshpb_lu *hpb,
>>> >>
>>> >>      blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_umap_req_compl_fn);
>>> >>
>>> >> +    hpb->stats.umap_req_cnt++;
>>> >>      return 0;
>>> >>  }
>>> >>
>>> >> @@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct
>>> >> ufshpb_lu *hpb,
>>> >>      return -EAGAIN;
>>> >>  }
>>> >>
>>> >> +static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
>>> >> +                                    struct ufshpb_region *rgn)
>>> >> +{
>>> >> +    return ufshpb_issue_umap_req(hpb, rgn);
>>> >> +}
>>> >> +
>>> >>  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
>>> >>  {
>>> >>      return ufshpb_issue_umap_req(hpb, NULL);
>>> >> @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct
>>> >> ufshpb_lu *hpb,
>>> >>      struct ufshpb_subregion *srgn;
>>> >>      int srgn_idx;
>>> >>
>>> >> +
>>> >> +    if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))
>>> >
>>> > __ufshpb_evict_region() is called with rgn_state_lock held and IRQ
>>> > disabled,
>>> > when ufshpb_issue_umap_single_req() invokes blk_execute_rq_nowait(),
>>> > below
>>> > warning shall pop up every time, fix it?
>>> >
>>> > void blk_execute_rq_nowait(struct request_queue *q, struct gendisk
>>> > *bd_disk,
>>> >                  struct request *rq, int at_head,
>>> >                          rq_end_io_fn *done)
>>> > {
>>> >       WARN_ON(irqs_disabled());
>>> > ...
>>> >
>>> 
>>> Moreover, since we are here with rgn_state_lock held and IRQ 
>>> disabled,
>>> in ufshpb_get_req(), rq = kmem_cache_alloc(hpb->map_req_cache,
>>> GFP_KERNEL)
>>> has the GFP_KERNEL flag, scheduling while atomic???
>> I think your comment applies to  ufshpb_issue_umap_all_req as well,
>> Which is called from slave_configure/scsi_add_lun.
>> 
>> Since the host-mode series is utilizing the framework laid by the 
>> device-mode,
>> Maybe you can add this comment to  Daejun's last version?
> 
> Hi Avri, Can Guo
> 
> I think ufshpb_issue_umap_single_req() can be moved to end of
> ufshpb_evict_region().
> Then we can avoid rgn_state_lock when it sends unmap command.

I am not the expert here, please you two fix it. I am just reporting
what can be wrong. Anyways, ufshpb_issue_umap_single_req() should not
be called with rgn_state_lock held - think about below (another deadly)
scenario.

lock(rgn_state_lock)
   ufshpb_issue_umap_single_req()
     ufshpb_prep()
        lock(rgn_state_lock)   <---------- recursive spin_lock

BTW, @Daejun shouldn't we stop passthrough cmds from stepping
into ufshpb_prep()? In current code, you are trying to use below
check to block cmds other than write/discard/read, but a passthrough
cmd can not be blocked by the check.

          if (!ufshpb_is_write_or_discard_cmd(cmd) &&
              !ufshpb_is_read_cmd(cmd))
                  return 0;

Thanks,
Can Guo.

> 
> Thanks,
> Daejun
> 
> 
>> Thanks,
>> Avri
>> 
>>> 
>>> Can Guo.
>>> 
>>> > Thanks.
>>> > Can Guo.
>>> >
>>> >> +            return;
>>> >> +
>>> >>      lru_info = &hpb->lru_info;
>>> >>
>>> >>      dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n",
>>> >> rgn->rgn_idx);
>>> >> @@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
>>> >>  ufshpb_sysfs_attr_show_func(rb_active_cnt);
>>> >>  ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
>>> >>  ufshpb_sysfs_attr_show_func(map_req_cnt);
>>> >> +ufshpb_sysfs_attr_show_func(umap_req_cnt);
>>> >>
>>> >>  static struct attribute *hpb_dev_stat_attrs[] = {
>>> >>      &dev_attr_hit_cnt.attr,
>>> >> @@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[] =
>>> >> {
>>> >>      &dev_attr_rb_active_cnt.attr,
>>> >>      &dev_attr_rb_inactive_cnt.attr,
>>> >>      &dev_attr_map_req_cnt.attr,
>>> >> +    &dev_attr_umap_req_cnt.attr,
>>> >>      NULL,
>>> >>  };
>>> >>
>>> >> @@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu
>>> >> *hpb)
>>> >>      hpb->stats.rb_active_cnt = 0;
>>> >>      hpb->stats.rb_inactive_cnt = 0;
>>> >>      hpb->stats.map_req_cnt = 0;
>>> >> +    hpb->stats.umap_req_cnt = 0;
>>> >>  }
>>> >>
>>> >>  static void ufshpb_param_init(struct ufshpb_lu *hpb)
>>> >> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>>> >> index bd4308010466..84598a317897 100644
>>> >> --- a/drivers/scsi/ufs/ufshpb.h
>>> >> +++ b/drivers/scsi/ufs/ufshpb.h
>>> >> @@ -186,6 +186,7 @@ struct ufshpb_stats {
>>> >>      u64 rb_inactive_cnt;
>>> >>      u64 map_req_cnt;
>>> >>      u64 pre_req_cnt;
>>> >> +    u64 umap_req_cnt;
>>> >>  };
>>> >>
>>> >>  struct ufshpb_lu {
>> 
>> 
>> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: Re: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
       [not found]           ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p4>
@ 2021-03-17  5:19             ` Daejun Park
  2021-03-17  5:34               ` Can Guo
       [not found]               ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p6>
  0 siblings, 2 replies; 58+ messages in thread
From: Daejun Park @ 2021-03-17  5:19 UTC (permalink / raw)
  To: Can Guo, Daejun Park
  Cc: Avri Altman, James E . J . Bottomley, Martin K . Petersen,
	linux-scsi, linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	ALIM AKHTAR, asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo,
	stanley.chu

>>>> >> ---
>>>> >>  drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
>>>> >>  drivers/scsi/ufs/ufshpb.h |  1 +
>>>> >>  2 files changed, 15 insertions(+)
>>>> >>
>>>> >> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>>>> >> index 6f4fd22eaf2f..0744feb4d484 100644
>>>> >> --- a/drivers/scsi/ufs/ufshpb.c
>>>> >> +++ b/drivers/scsi/ufs/ufshpb.c
>>>> >> @@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct
>>>> >> ufshpb_lu *hpb,
>>>> >>
>>>> >>      blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_umap_req_compl_fn);
>>>> >>
>>>> >> +    hpb->stats.umap_req_cnt++;
>>>> >>      return 0;
>>>> >>  }
>>>> >>
>>>> >> @@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct
>>>> >> ufshpb_lu *hpb,
>>>> >>      return -EAGAIN;
>>>> >>  }
>>>> >>
>>>> >> +static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
>>>> >> +                                    struct ufshpb_region *rgn)
>>>> >> +{
>>>> >> +    return ufshpb_issue_umap_req(hpb, rgn);
>>>> >> +}
>>>> >> +
>>>> >>  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
>>>> >>  {
>>>> >>      return ufshpb_issue_umap_req(hpb, NULL);
>>>> >> @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct
>>>> >> ufshpb_lu *hpb,
>>>> >>      struct ufshpb_subregion *srgn;
>>>> >>      int srgn_idx;
>>>> >>
>>>> >> +
>>>> >> +    if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))
>>>> >
>>>> > __ufshpb_evict_region() is called with rgn_state_lock held and IRQ
>>>> > disabled,
>>>> > when ufshpb_issue_umap_single_req() invokes blk_execute_rq_nowait(),
>>>> > below
>>>> > warning shall pop up every time, fix it?
>>>> >
>>>> > void blk_execute_rq_nowait(struct request_queue *q, struct gendisk
>>>> > *bd_disk,
>>>> >                  struct request *rq, int at_head,
>>>> >                          rq_end_io_fn *done)
>>>> > {
>>>> >       WARN_ON(irqs_disabled());
>>>> > ...
>>>> >
>>>> 
>>>> Moreover, since we are here with rgn_state_lock held and IRQ 
>>>> disabled,
>>>> in ufshpb_get_req(), rq = kmem_cache_alloc(hpb->map_req_cache,
>>>> GFP_KERNEL)
>>>> has the GFP_KERNEL flag, scheduling while atomic???
>>> I think your comment applies to  ufshpb_issue_umap_all_req as well,
>>> Which is called from slave_configure/scsi_add_lun.
>>> 
>>> Since the host-mode series is utilizing the framework laid by the 
>>> device-mode,
>>> Maybe you can add this comment to  Daejun's last version?
>> 
>> Hi Avri, Can Guo
>> 
>> I think ufshpb_issue_umap_single_req() can be moved to end of
>> ufshpb_evict_region().
>> Then we can avoid rgn_state_lock when it sends unmap command.
> 
>I am not the expert here, please you two fix it. I am just reporting
>what can be wrong. Anyways, ufshpb_issue_umap_single_req() should not
>be called with rgn_state_lock held - think about below (another deadly)
>scenario.
> 
>lock(rgn_state_lock)
>   ufshpb_issue_umap_single_req()
>     ufshpb_prep()
>        lock(rgn_state_lock)   <---------- recursive spin_lock
> 
>BTW, @Daejun shouldn't we stop passthrough cmds from stepping
>into ufshpb_prep()? In current code, you are trying to use below
>check to block cmds other than write/discard/read, but a passthrough
>cmd can not be blocked by the check.
> 
>          if (!ufshpb_is_write_or_discard_cmd(cmd) &&
>              !ufshpb_is_read_cmd(cmd) )
>                  return 0;

I found this problem too. I fixed it and submit next patch.

if (blk_rq_is_scsi(cmd->request) ||
	    (!ufshpb_is_write_or_discard_cmd(cmd) &&
	    !ufshpb_is_read_cmd(cmd)))
		return 0;


Thanks,
Daejun

>Thanks,
>Can Guo.
> 
>> 
>> Thanks,
>> Daejun
>> 
>> 
>>> Thanks,
>>> Avri
>>> 
>>>> 
>>>> Can Guo.
>>>> 
>>>> > Thanks.
>>>> > Can Guo.
>>>> >
>>>> >> +            return;
>>>> >> +
>>>> >>      lru_info = &hpb->lru_info;
>>>> >>
>>>> >>      dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n",
>>>> >> rgn->rgn_idx);
>>>> >> @@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
>>>> >>  ufshpb_sysfs_attr_show_func(rb_active_cnt);
>>>> >>  ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
>>>> >>  ufshpb_sysfs_attr_show_func(map_req_cnt);
>>>> >> +ufshpb_sysfs_attr_show_func(umap_req_cnt);
>>>> >>
>>>> >>  static struct attribute *hpb_dev_stat_attrs[] = {
>>>> >>      &dev_attr_hit_cnt.attr,
>>>> >> @@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[] =
>>>> >> {
>>>> >>      &dev_attr_rb_active_cnt.attr,
>>>> >>      &dev_attr_rb_inactive_cnt.attr,
>>>> >>      &dev_attr_map_req_cnt.attr,
>>>> >> +    &dev_attr_umap_req_cnt.attr,
>>>> >>      NULL,
>>>> >>  };
>>>> >>
>>>> >> @@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu
>>>> >> *hpb)
>>>> >>      hpb->stats.rb_active_cnt = 0;
>>>> >>      hpb->stats.rb_inactive_cnt = 0;
>>>> >>      hpb->stats.map_req_cnt = 0;
>>>> >> +    hpb->stats.umap_req_cnt = 0;
>>>> >>  }
>>>> >>
>>>> >>  static void ufshpb_param_init(struct ufshpb_lu *hpb)
>>>> >> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>>>> >> index bd4308010466..84598a317897 100644
>>>> >> --- a/drivers/scsi/ufs/ufshpb.h
>>>> >> +++ b/drivers/scsi/ufs/ufshpb.h
>>>> >> @@ -186,6 +186,7 @@ struct ufshpb_stats {
>>>> >>      u64 rb_inactive_cnt;
>>>> >>      u64 map_req_cnt;
>>>> >>      u64 pre_req_cnt;
>>>> >> +    u64 umap_req_cnt;
>>>> >>  };
>>>> >>
>>>> >>  struct ufshpb_lu {
>>> 
>>> 
>>> 
> 
> 
>  

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
  2021-03-17  5:19             ` Daejun Park
@ 2021-03-17  5:34               ` Can Guo
       [not found]               ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p6>
  1 sibling, 0 replies; 58+ messages in thread
From: Can Guo @ 2021-03-17  5:34 UTC (permalink / raw)
  To: daejun7.park
  Cc: Avri Altman, James E . J . Bottomley, Martin K . Petersen,
	linux-scsi, linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	ALIM AKHTAR, asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo,
	stanley.chu

On 2021-03-17 13:19, Daejun Park wrote:
>>>>> >> ---
>>>>> >>  drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
>>>>> >>  drivers/scsi/ufs/ufshpb.h |  1 +
>>>>> >>  2 files changed, 15 insertions(+)
>>>>> >>
>>>>> >> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>>>>> >> index 6f4fd22eaf2f..0744feb4d484 100644
>>>>> >> --- a/drivers/scsi/ufs/ufshpb.c
>>>>> >> +++ b/drivers/scsi/ufs/ufshpb.c
>>>>> >> @@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct
>>>>> >> ufshpb_lu *hpb,
>>>>> >>
>>>>> >>      blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_umap_req_compl_fn);
>>>>> >>
>>>>> >> +    hpb->stats.umap_req_cnt++;
>>>>> >>      return 0;
>>>>> >>  }
>>>>> >>
>>>>> >> @@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct
>>>>> >> ufshpb_lu *hpb,
>>>>> >>      return -EAGAIN;
>>>>> >>  }
>>>>> >>
>>>>> >> +static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
>>>>> >> +                                    struct ufshpb_region *rgn)
>>>>> >> +{
>>>>> >> +    return ufshpb_issue_umap_req(hpb, rgn);
>>>>> >> +}
>>>>> >> +
>>>>> >>  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
>>>>> >>  {
>>>>> >>      return ufshpb_issue_umap_req(hpb, NULL);
>>>>> >> @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct
>>>>> >> ufshpb_lu *hpb,
>>>>> >>      struct ufshpb_subregion *srgn;
>>>>> >>      int srgn_idx;
>>>>> >>
>>>>> >> +
>>>>> >> +    if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))
>>>>> >
>>>>> > __ufshpb_evict_region() is called with rgn_state_lock held and IRQ
>>>>> > disabled,
>>>>> > when ufshpb_issue_umap_single_req() invokes blk_execute_rq_nowait(),
>>>>> > below
>>>>> > warning shall pop up every time, fix it?
>>>>> >
>>>>> > void blk_execute_rq_nowait(struct request_queue *q, struct gendisk
>>>>> > *bd_disk,
>>>>> >                  struct request *rq, int at_head,
>>>>> >                          rq_end_io_fn *done)
>>>>> > {
>>>>> >       WARN_ON(irqs_disabled());
>>>>> > ...
>>>>> >
>>>>> 
>>>>> Moreover, since we are here with rgn_state_lock held and IRQ
>>>>> disabled,
>>>>> in ufshpb_get_req(), rq = kmem_cache_alloc(hpb->map_req_cache,
>>>>> GFP_KERNEL)
>>>>> has the GFP_KERNEL flag, scheduling while atomic???
>>>> I think your comment applies to  ufshpb_issue_umap_all_req as well,
>>>> Which is called from slave_configure/scsi_add_lun.
>>>> 
>>>> Since the host-mode series is utilizing the framework laid by the
>>>> device-mode,
>>>> Maybe you can add this comment to  Daejun's last version?
>>> 
>>> Hi Avri, Can Guo
>>> 
>>> I think ufshpb_issue_umap_single_req() can be moved to end of
>>> ufshpb_evict_region().
>>> Then we can avoid rgn_state_lock when it sends unmap command.
>> 
>> I am not the expert here, please you two fix it. I am just reporting
>> what can be wrong. Anyways, ufshpb_issue_umap_single_req() should not
>> be called with rgn_state_lock held - think about below (another 
>> deadly)
>> scenario.
>> 
>> lock(rgn_state_lock)
>>   ufshpb_issue_umap_single_req()
>>     ufshpb_prep()
>>        lock(rgn_state_lock)   <---------- recursive spin_lock
>> 
>> BTW, @Daejun shouldn't we stop passthrough cmds from stepping
>> into ufshpb_prep()? In current code, you are trying to use below
>> check to block cmds other than write/discard/read, but a passthrough
>> cmd can not be blocked by the check.
>> 
>>          if (!ufshpb_is_write_or_discard_cmd(cmd) &&
>>              !ufshpb_is_read_cmd(cmd) )
>>                  return 0;
> 
> I found this problem too. I fixed it and submit next patch.

You mean in V30, which has not been uploaded yet, right?

Thanks,
Can Guo.

> 
> if (blk_rq_is_scsi(cmd->request) ||
> 	    (!ufshpb_is_write_or_discard_cmd(cmd) &&
> 	    !ufshpb_is_read_cmd(cmd)))
> 		return 0;
> 
> 
> Thanks,
> Daejun
> 
>> Thanks,
>> Can Guo.
>> 
>>> 
>>> Thanks,
>>> Daejun
>>> 
>>> 
>>>> Thanks,
>>>> Avri
>>>> 
>>>>> 
>>>>> Can Guo.
>>>>> 
>>>>> > Thanks.
>>>>> > Can Guo.
>>>>> >
>>>>> >> +            return;
>>>>> >> +
>>>>> >>      lru_info = &hpb->lru_info;
>>>>> >>
>>>>> >>      dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n",
>>>>> >> rgn->rgn_idx);
>>>>> >> @@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
>>>>> >>  ufshpb_sysfs_attr_show_func(rb_active_cnt);
>>>>> >>  ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
>>>>> >>  ufshpb_sysfs_attr_show_func(map_req_cnt);
>>>>> >> +ufshpb_sysfs_attr_show_func(umap_req_cnt);
>>>>> >>
>>>>> >>  static struct attribute *hpb_dev_stat_attrs[] = {
>>>>> >>      &dev_attr_hit_cnt.attr,
>>>>> >> @@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[] =
>>>>> >> {
>>>>> >>      &dev_attr_rb_active_cnt.attr,
>>>>> >>      &dev_attr_rb_inactive_cnt.attr,
>>>>> >>      &dev_attr_map_req_cnt.attr,
>>>>> >> +    &dev_attr_umap_req_cnt.attr,
>>>>> >>      NULL,
>>>>> >>  };
>>>>> >>
>>>>> >> @@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu
>>>>> >> *hpb)
>>>>> >>      hpb->stats.rb_active_cnt = 0;
>>>>> >>      hpb->stats.rb_inactive_cnt = 0;
>>>>> >>      hpb->stats.map_req_cnt = 0;
>>>>> >> +    hpb->stats.umap_req_cnt = 0;
>>>>> >>  }
>>>>> >>
>>>>> >>  static void ufshpb_param_init(struct ufshpb_lu *hpb)
>>>>> >> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>>>>> >> index bd4308010466..84598a317897 100644
>>>>> >> --- a/drivers/scsi/ufs/ufshpb.h
>>>>> >> +++ b/drivers/scsi/ufs/ufshpb.h
>>>>> >> @@ -186,6 +186,7 @@ struct ufshpb_stats {
>>>>> >>      u64 rb_inactive_cnt;
>>>>> >>      u64 map_req_cnt;
>>>>> >>      u64 pre_req_cnt;
>>>>> >> +    u64 umap_req_cnt;
>>>>> >>  };
>>>>> >>
>>>>> >>  struct ufshpb_lu {
>>>> 
>>>> 
>>>> 
>> 
>> 
>> 

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: Re: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
       [not found]               ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p6>
@ 2021-03-17  5:42                 ` Daejun Park
  0 siblings, 0 replies; 58+ messages in thread
From: Daejun Park @ 2021-03-17  5:42 UTC (permalink / raw)
  To: Can Guo, Daejun Park
  Cc: Avri Altman, James E . J . Bottomley, Martin K . Petersen,
	linux-scsi, linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	ALIM AKHTAR, asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo,
	stanley.chu

>>>>>> >> ---
>>>>>> >>  drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
>>>>>> >>  drivers/scsi/ufs/ufshpb.h |  1 +
>>>>>> >>  2 files changed, 15 insertions(+)
>>>>>> >>
>>>>>> >> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>>>>>> >> index 6f4fd22eaf2f..0744feb4d484 100644
>>>>>> >> --- a/drivers/scsi/ufs/ufshpb.c
>>>>>> >> +++ b/drivers/scsi/ufs/ufshpb.c
>>>>>> >> @@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct
>>>>>> >> ufshpb_lu *hpb,
>>>>>> >>
>>>>>> >>      blk_execute_rq_nowait(q, NULL, req, 1, ufshpb_umap_req_compl_fn);
>>>>>> >>
>>>>>> >> +    hpb->stats.umap_req_cnt++;
>>>>>> >>      return 0;
>>>>>> >>  }
>>>>>> >>
>>>>>> >> @@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct
>>>>>> >> ufshpb_lu *hpb,
>>>>>> >>      return -EAGAIN;
>>>>>> >>  }
>>>>>> >>
>>>>>> >> +static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
>>>>>> >> +                                    struct ufshpb_region *rgn)
>>>>>> >> +{
>>>>>> >> +    return ufshpb_issue_umap_req(hpb, rgn);
>>>>>> >> +}
>>>>>> >> +
>>>>>> >>  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
>>>>>> >>  {
>>>>>> >>      return ufshpb_issue_umap_req(hpb, NULL);
>>>>>> >> @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct
>>>>>> >> ufshpb_lu *hpb,
>>>>>> >>      struct ufshpb_subregion *srgn;
>>>>>> >>      int srgn_idx;
>>>>>> >>
>>>>>> >> +
>>>>>> >> +    if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))
>>>>>> >
>>>>>> > __ufshpb_evict_region() is called with rgn_state_lock held and IRQ
>>>>>> > disabled,
>>>>>> > when ufshpb_issue_umap_single_req() invokes blk_execute_rq_nowait(),
>>>>>> > below
>>>>>> > warning shall pop up every time, fix it?
>>>>>> >
>>>>>> > void blk_execute_rq_nowait(struct request_queue *q, struct gendisk
>>>>>> > *bd_disk,
>>>>>> >                  struct request *rq, int at_head,
>>>>>> >                          rq_end_io_fn *done)
>>>>>> > {
>>>>>> >       WARN_ON(irqs_disabled());
>>>>>> > ...
>>>>>> >
>>>>>> 
>>>>>> Moreover, since we are here with rgn_state_lock held and IRQ
>>>>>> disabled,
>>>>>> in ufshpb_get_req(), rq = kmem_cache_alloc(hpb->map_req_cache,
>>>>>> GFP_KERNEL)
>>>>>> has the GFP_KERNEL flag, scheduling while atomic???
>>>>> I think your comment applies to  ufshpb_issue_umap_all_req as well,
>>>>> Which is called from slave_configure/scsi_add_lun.
>>>>> 
>>>>> Since the host-mode series is utilizing the framework laid by the
>>>>> device-mode,
>>>>> Maybe you can add this comment to  Daejun's last version?
>>>> 
>>>> Hi Avri, Can Guo
>>>> 
>>>> I think ufshpb_issue_umap_single_req() can be moved to end of
>>>> ufshpb_evict_region().
>>>> Then we can avoid rgn_state_lock when it sends unmap command.
>>> 
>>> I am not the expert here, please you two fix it. I am just reporting
>>> what can be wrong. Anyways, ufshpb_issue_umap_single_req() should not
>>> be called with rgn_state_lock held - think about below (another 
>>> deadly)
>>> scenario.
>>> 
>>> lock(rgn_state_lock)
>>>   ufshpb_issue_umap_single_req()
>>>     ufshpb_prep()
>>>        lock(rgn_state_lock)   <---------- recursive spin_lock
>>> 
>>> BTW, @Daejun shouldn't we stop passthrough cmds from stepping
>>> into ufshpb_prep()? In current code, you are trying to use below
>>> check to block cmds other than write/discard/read, but a passthrough
>>> cmd can not be blocked by the check.
>>> 
>>>          if (!ufshpb_is_write_or_discard_cmd(cmd) &&
>>>              !ufshpb_is_read_cmd(cmd) )
>>>                  return 0;
>> 
>> I found this problem too. I fixed it and submit next patch.
> 
>You mean in V30, which has not been uploaded yet, right?

Yes, it is about v30.

Thanks,
Daejun

>Thanks,
>Can Guo.
> 
>> 
>> if (blk_rq_is_scsi(cmd->request) ||
>>             (!ufshpb_is_write_or_discard_cmd(cmd) &&
>>             !ufshpb_is_read_cmd(cmd)))
>>                 return 0;
>> 
>> 
>> Thanks,
>> Daejun
>> 
>>> Thanks,
>>> Can Guo.
>>> 
>>>> 
>>>> Thanks,
>>>> Daejun
>>>> 
>>>> 
>>>>> Thanks,
>>>>> Avri
>>>>> 
>>>>>> 
>>>>>> Can Guo.
>>>>>> 
>>>>>> > Thanks.
>>>>>> > Can Guo.
>>>>>> >
>>>>>> >> +            return;
>>>>>> >> +
>>>>>> >>      lru_info = &hpb->lru_info;
>>>>>> >>
>>>>>> >>      dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n",
>>>>>> >> rgn->rgn_idx);
>>>>>> >> @@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
>>>>>> >>  ufshpb_sysfs_attr_show_func(rb_active_cnt);
>>>>>> >>  ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
>>>>>> >>  ufshpb_sysfs_attr_show_func(map_req_cnt);
>>>>>> >> +ufshpb_sysfs_attr_show_func(umap_req_cnt);
>>>>>> >>
>>>>>> >>  static struct attribute *hpb_dev_stat_attrs[] = {
>>>>>> >>      &dev_attr_hit_cnt.attr,
>>>>>> >> @@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[] =
>>>>>> >> {
>>>>>> >>      &dev_attr_rb_active_cnt.attr,
>>>>>> >>      &dev_attr_rb_inactive_cnt.attr,
>>>>>> >>      &dev_attr_map_req_cnt.attr,
>>>>>> >> +    &dev_attr_umap_req_cnt.attr,
>>>>>> >>      NULL,
>>>>>> >>  };
>>>>>> >>
>>>>>> >> @@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu
>>>>>> >> *hpb)
>>>>>> >>      hpb->stats.rb_active_cnt = 0;
>>>>>> >>      hpb->stats.rb_inactive_cnt = 0;
>>>>>> >>      hpb->stats.map_req_cnt = 0;
>>>>>> >> +    hpb->stats.umap_req_cnt = 0;
>>>>>> >>  }
>>>>>> >>
>>>>>> >>  static void ufshpb_param_init(struct ufshpb_lu *hpb)
>>>>>> >> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>>>>>> >> index bd4308010466..84598a317897 100644
>>>>>> >> --- a/drivers/scsi/ufs/ufshpb.h
>>>>>> >> +++ b/drivers/scsi/ufs/ufshpb.h
>>>>>> >> @@ -186,6 +186,7 @@ struct ufshpb_stats {
>>>>>> >>      u64 rb_inactive_cnt;
>>>>>> >>      u64 map_req_cnt;
>>>>>> >>      u64 pre_req_cnt;
>>>>>> >> +    u64 umap_req_cnt;
>>>>>> >>  };
>>>>>> >>
>>>>>> >>  struct ufshpb_lu {
>>>>> 
>>>>> 
>>>>> 
>>> 
>>> 
>>> 
> 
> 
>  

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer
  2021-03-17  2:45       ` Can Guo
@ 2021-03-17  7:55         ` Avri Altman
  2021-06-01 16:22           ` Bart Van Assche
  0 siblings, 1 reply; 58+ messages in thread
From: Avri Altman @ 2021-03-17  7:55 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> On 2021-03-16 17:21, Avri Altman wrote:
> >> > +static void ufshpb_read_to_handler(struct work_struct *work)
> >> > +{
> >> > +     struct delayed_work *dwork = to_delayed_work(work);
> >> > +     struct ufshpb_lu *hpb;
> >> > +     struct victim_select_info *lru_info;
> >> > +     struct ufshpb_region *rgn;
> >> > +     unsigned long flags;
> >> > +     LIST_HEAD(expired_list);
> >> > +
> >> > +     hpb = container_of(dwork, struct ufshpb_lu, ufshpb_read_to_work);
> >> > +
> >> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> >> > +
> >> > +     lru_info = &hpb->lru_info;
> >> > +
> >> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn) {
> >> > +             bool timedout = ktime_after(ktime_get(), rgn->read_timeout);
> >> > +
> >> > +             if (timedout) {
> >> > +                     rgn->read_timeout_expiries--;
> >> > +                     if (is_rgn_dirty(rgn) ||
> >> > +                         rgn->read_timeout_expiries == 0)
> >> > +                             list_add(&rgn->list_expired_rgn, &expired_list);
> >> > +                     else
> >> > +                             rgn->read_timeout = ktime_add_ms(ktime_get(),
> >> > +                                                      READ_TO_MS);
> >> > +             }
> >> > +     }
> >> > +
> >> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> >> > +
> >> > +     list_for_each_entry(rgn, &expired_list, list_expired_rgn) {
> >>
> >> Here can be problematic - since you don't have the native expired_list
> >> initialized
> >> before use, if above loop did not insert anything to expired_list, it
> >> shall become
> >> a dead loop here.
> > Not sure what you meant by native initialization.
> > LIST_HEAD is statically initializing an empty list, resulting the same
> > outcome as INIT_LIST_HEAD.
> >
> 
> Sorry for making you confused, you should use list_for_each_entry_safe()
> instead of list_for_each_entry() as you are deleting entries within the
> loop,
> otherwise, this can become an infinite loop. Again, have you tested this
> patch
> before upload? I am sure this is problematic - when it becomes an
> inifinite
> loop, below path will hang...
> 
> ufshcd_suspend()->ufshpb_suspend()->cancel_jobs()->cancel_delayed_work()
Ahh  - yes.  You are right.  Originally I used list_for_each_entry_safe.
Not sure why I changed it here.  Will fix it.

I openly disclosed that I am testing the code on gs20 and mi10.
Those are v4.19 platforms, and I am using a driver adopted from the original public hpb driver
Published by Samsung with the gs20 code.
I am also concern as those drivers are drifted apart as the review process commences.
Will try to bring-up a more advanced platform (gs21) and apply the mainline hpb driver.


> 
> >>
> >> And, which lock is protecting rgn->list_expired_rgn? If two
> >> read_to_handler works
> >> are running in parallel, one can be inserting it to its expired_list
> >> while another
> >> can be deleting it.
> > The timeout handler, being a delayed work, is meant to run every
> > polling period.
> > Originally, I had it protected from 2 handlers running concurrently,
> > But I removed it following Daejun's comment, which I accepted,
> > Since it is always scheduled using the same polling period.
> 
> But one can set the delay to 0 through sysfs, right?
Will restore the protection.  Thanks.

Thanks,
Avri

> 
> Thanks,
> Can Guo.
> 
> >
> > Thanks,
> > Avri
> >
> >>
> >> Can Guo.
> >>
> >> > +             list_del_init(&rgn->list_expired_rgn);
> >> > +             spin_lock_irqsave(&hpb->rsp_list_lock, flags);
> >> > +             ufshpb_update_inactive_info(hpb, rgn->rgn_idx);
> >> > +             hpb->stats.rb_inactive_cnt++;
> >> > +             spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> >> > +     }
> >> > +
> >> > +     ufshpb_kick_map_work(hpb);
> >> > +
> >> > +     schedule_delayed_work(&hpb->ufshpb_read_to_work,
> >> > +                           msecs_to_jiffies(POLLING_INTERVAL_MS));
> >> > +}
> >> > +
> >> >  static void ufshpb_add_lru_info(struct victim_select_info *lru_info,
> >> >                               struct ufshpb_region *rgn)
> >> >  {
> >> >       rgn->rgn_state = HPB_RGN_ACTIVE;
> >> >       list_add_tail(&rgn->list_lru_rgn, &lru_info->lh_lru_rgn);
> >> >       atomic_inc(&lru_info->active_cnt);
> >> > +     if (rgn->hpb->is_hcm) {
> >> > +             rgn->read_timeout = ktime_add_ms(ktime_get(), READ_TO_MS);
> >> > +             rgn->read_timeout_expiries = READ_TO_EXPIRIES;
> >> > +     }
> >> >  }
> >> >
> >> >  static void ufshpb_hit_lru_info(struct victim_select_info *lru_info,
> >> > @@ -1813,6 +1865,7 @@ static int ufshpb_alloc_region_tbl(struct
> >> > ufs_hba *hba, struct ufshpb_lu *hpb)
> >> >
> >> >               INIT_LIST_HEAD(&rgn->list_inact_rgn);
> >> >               INIT_LIST_HEAD(&rgn->list_lru_rgn);
> >> > +             INIT_LIST_HEAD(&rgn->list_expired_rgn);
> >> >
> >> >               if (rgn_idx == hpb->rgns_per_lu - 1) {
> >> >                       srgn_cnt = ((hpb->srgns_per_lu - 1) %
> >> > @@ -1834,6 +1887,7 @@ static int ufshpb_alloc_region_tbl(struct
> >> > ufs_hba *hba, struct ufshpb_lu *hpb)
> >> >               }
> >> >
> >> >               rgn->rgn_flags = 0;
> >> > +             rgn->hpb = hpb;
> >> >       }
> >> >
> >> >       return 0;
> >> > @@ -2053,6 +2107,8 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> >> > *hba, struct ufshpb_lu *hpb)
> >> >                         ufshpb_normalization_work_handler);
> >> >               INIT_WORK(&hpb->ufshpb_lun_reset_work,
> >> >                         ufshpb_reset_work_handler);
> >> > +             INIT_DELAYED_WORK(&hpb->ufshpb_read_to_work,
> >> > +                               ufshpb_read_to_handler);
> >> >       }
> >> >
> >> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
> >> > @@ -2087,6 +2143,10 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> >> > *hba, struct ufshpb_lu *hpb)
> >> >       ufshpb_stat_init(hpb);
> >> >       ufshpb_param_init(hpb);
> >> >
> >> > +     if (hpb->is_hcm)
> >> > +             schedule_delayed_work(&hpb->ufshpb_read_to_work,
> >> > +                                   msecs_to_jiffies(POLLING_INTERVAL_MS));
> >> > +
> >> >       return 0;
> >> >
> >> >  release_pre_req_mempool:
> >> > @@ -2154,6 +2214,7 @@ static void ufshpb_discard_rsp_lists(struct
> >> > ufshpb_lu *hpb)
> >> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
> >> >  {
> >> >       if (hpb->is_hcm) {
> >> > +             cancel_delayed_work_sync(&hpb->ufshpb_read_to_work);
> >> >               cancel_work_sync(&hpb->ufshpb_lun_reset_work);
> >> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
> >> >       }
> >> > @@ -2264,6 +2325,10 @@ void ufshpb_resume(struct ufs_hba *hba)
> >> >                       continue;
> >> >               ufshpb_set_state(hpb, HPB_PRESENT);
> >> >               ufshpb_kick_map_work(hpb);
> >> > +             if (hpb->is_hcm)
> >> > +                     schedule_delayed_work(&hpb->ufshpb_read_to_work,
> >> > +                             msecs_to_jiffies(POLLING_INTERVAL_MS));
> >> > +
> >> >       }
> >> >  }
> >> >
> >> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> >> > index 37c1b0ea0c0a..b49e9a34267f 100644
> >> > --- a/drivers/scsi/ufs/ufshpb.h
> >> > +++ b/drivers/scsi/ufs/ufshpb.h
> >> > @@ -109,6 +109,7 @@ struct ufshpb_subregion {
> >> >  };
> >> >
> >> >  struct ufshpb_region {
> >> > +     struct ufshpb_lu *hpb;
> >> >       struct ufshpb_subregion *srgn_tbl;
> >> >       enum HPB_RGN_STATE rgn_state;
> >> >       int rgn_idx;
> >> > @@ -126,6 +127,10 @@ struct ufshpb_region {
> >> >       /* region reads - for host mode */
> >> >       spinlock_t rgn_lock;
> >> >       unsigned int reads;
> >> > +     /* region "cold" timer - for host mode */
> >> > +     ktime_t read_timeout;
> >> > +     unsigned int read_timeout_expiries;
> >> > +     struct list_head list_expired_rgn;
> >> >  };
> >> >
> >> >  #define for_each_sub_region(rgn, i, srgn)                            \
> >> > @@ -219,6 +224,7 @@ struct ufshpb_lu {
> >> >       struct victim_select_info lru_info;
> >> >       struct work_struct ufshpb_normalization_work;
> >> >       struct work_struct ufshpb_lun_reset_work;
> >> > +     struct delayed_work ufshpb_read_to_work;
> >> >
> >> >       /* pinned region information */
> >> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode
  2021-03-17  4:41           ` Can Guo
@ 2021-03-17  7:59             ` Avri Altman
  0 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-17  7:59 UTC (permalink / raw)
  To: Can Guo, daejun7.park
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	ALIM AKHTAR, asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo,
	stanley.chu

> On 2021-03-17 10:28, Daejun Park wrote:
> >>> >> ---
> >>> >>  drivers/scsi/ufs/ufshpb.c | 14 ++++++++++++++
> >>> >>  drivers/scsi/ufs/ufshpb.h |  1 +
> >>> >>  2 files changed, 15 insertions(+)
> >>> >>
> >>> >> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> >>> >> index 6f4fd22eaf2f..0744feb4d484 100644
> >>> >> --- a/drivers/scsi/ufs/ufshpb.c
> >>> >> +++ b/drivers/scsi/ufs/ufshpb.c
> >>> >> @@ -907,6 +907,7 @@ static int ufshpb_execute_umap_req(struct
> >>> >> ufshpb_lu *hpb,
> >>> >>
> >>> >>      blk_execute_rq_nowait(q, NULL, req, 1,
> ufshpb_umap_req_compl_fn);
> >>> >>
> >>> >> +    hpb->stats.umap_req_cnt++;
> >>> >>      return 0;
> >>> >>  }
> >>> >>
> >>> >> @@ -1103,6 +1104,12 @@ static int ufshpb_issue_umap_req(struct
> >>> >> ufshpb_lu *hpb,
> >>> >>      return -EAGAIN;
> >>> >>  }
> >>> >>
> >>> >> +static int ufshpb_issue_umap_single_req(struct ufshpb_lu *hpb,
> >>> >> +                                    struct ufshpb_region *rgn)
> >>> >> +{
> >>> >> +    return ufshpb_issue_umap_req(hpb, rgn);
> >>> >> +}
> >>> >> +
> >>> >>  static int ufshpb_issue_umap_all_req(struct ufshpb_lu *hpb)
> >>> >>  {
> >>> >>      return ufshpb_issue_umap_req(hpb, NULL);
> >>> >> @@ -1115,6 +1122,10 @@ static void __ufshpb_evict_region(struct
> >>> >> ufshpb_lu *hpb,
> >>> >>      struct ufshpb_subregion *srgn;
> >>> >>      int srgn_idx;
> >>> >>
> >>> >> +
> >>> >> +    if (hpb->is_hcm && ufshpb_issue_umap_single_req(hpb, rgn))
> >>> >
> >>> > __ufshpb_evict_region() is called with rgn_state_lock held and IRQ
> >>> > disabled,
> >>> > when ufshpb_issue_umap_single_req() invokes
> blk_execute_rq_nowait(),
> >>> > below
> >>> > warning shall pop up every time, fix it?
> >>> >
> >>> > void blk_execute_rq_nowait(struct request_queue *q, struct gendisk
> >>> > *bd_disk,
> >>> >                  struct request *rq, int at_head,
> >>> >                          rq_end_io_fn *done)
> >>> > {
> >>> >       WARN_ON(irqs_disabled());
> >>> > ...
> >>> >
> >>>
> >>> Moreover, since we are here with rgn_state_lock held and IRQ
> >>> disabled,
> >>> in ufshpb_get_req(), rq = kmem_cache_alloc(hpb->map_req_cache,
> >>> GFP_KERNEL)
> >>> has the GFP_KERNEL flag, scheduling while atomic???
> >> I think your comment applies to  ufshpb_issue_umap_all_req as well,
> >> Which is called from slave_configure/scsi_add_lun.
> >>
> >> Since the host-mode series is utilizing the framework laid by the
> >> device-mode,
> >> Maybe you can add this comment to  Daejun's last version?
> >
> > Hi Avri, Can Guo
> >
> > I think ufshpb_issue_umap_single_req() can be moved to end of
> > ufshpb_evict_region().
> > Then we can avoid rgn_state_lock when it sends unmap command.
> 
> I am not the expert here, please you two fix it. I am just reporting
> what can be wrong. Anyways, ufshpb_issue_umap_single_req() should not
> be called with rgn_state_lock held - think about below (another deadly)
> scenario.
> 
> lock(rgn_state_lock)
>    ufshpb_issue_umap_single_req()
>      ufshpb_prep()
>         lock(rgn_state_lock)   <---------- recursive spin_lock
Will fix.   Will wait for Daejun's v30 to see if anything applies to unmap_single.

Thanks,
Avri 

> 
> BTW, @Daejun shouldn't we stop passthrough cmds from stepping
> into ufshpb_prep()? In current code, you are trying to use below
> check to block cmds other than write/discard/read, but a passthrough
> cmd can not be blocked by the check.
> 
>           if (!ufshpb_is_write_or_discard_cmd(cmd) &&
>               !ufshpb_is_read_cmd(cmd))
>                   return 0;
> 
> Thanks,
> Can Guo.
> 
> >
> > Thanks,
> > Daejun
> >
> >
> >> Thanks,
> >> Avri
> >>
> >>>
> >>> Can Guo.
> >>>
> >>> > Thanks.
> >>> > Can Guo.
> >>> >
> >>> >> +            return;
> >>> >> +
> >>> >>      lru_info = &hpb->lru_info;
> >>> >>
> >>> >>      dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "evict region %d\n",
> >>> >> rgn->rgn_idx);
> >>> >> @@ -1855,6 +1866,7 @@ ufshpb_sysfs_attr_show_func(rb_noti_cnt);
> >>> >>  ufshpb_sysfs_attr_show_func(rb_active_cnt);
> >>> >>  ufshpb_sysfs_attr_show_func(rb_inactive_cnt);
> >>> >>  ufshpb_sysfs_attr_show_func(map_req_cnt);
> >>> >> +ufshpb_sysfs_attr_show_func(umap_req_cnt);
> >>> >>
> >>> >>  static struct attribute *hpb_dev_stat_attrs[] = {
> >>> >>      &dev_attr_hit_cnt.attr,
> >>> >> @@ -1863,6 +1875,7 @@ static struct attribute *hpb_dev_stat_attrs[]
> =
> >>> >> {
> >>> >>      &dev_attr_rb_active_cnt.attr,
> >>> >>      &dev_attr_rb_inactive_cnt.attr,
> >>> >>      &dev_attr_map_req_cnt.attr,
> >>> >> +    &dev_attr_umap_req_cnt.attr,
> >>> >>      NULL,
> >>> >>  };
> >>> >>
> >>> >> @@ -1978,6 +1991,7 @@ static void ufshpb_stat_init(struct ufshpb_lu
> >>> >> *hpb)
> >>> >>      hpb->stats.rb_active_cnt = 0;
> >>> >>      hpb->stats.rb_inactive_cnt = 0;
> >>> >>      hpb->stats.map_req_cnt = 0;
> >>> >> +    hpb->stats.umap_req_cnt = 0;
> >>> >>  }
> >>> >>
> >>> >>  static void ufshpb_param_init(struct ufshpb_lu *hpb)
> >>> >> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> >>> >> index bd4308010466..84598a317897 100644
> >>> >> --- a/drivers/scsi/ufs/ufshpb.h
> >>> >> +++ b/drivers/scsi/ufs/ufshpb.h
> >>> >> @@ -186,6 +186,7 @@ struct ufshpb_stats {
> >>> >>      u64 rb_inactive_cnt;
> >>> >>      u64 map_req_cnt;
> >>> >>      u64 pre_req_cnt;
> >>> >> +    u64 umap_req_cnt;
> >>> >>  };
> >>> >>
> >>> >>  struct ufshpb_lu {
> >>
> >>
> >>

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter
  2021-03-15  9:31       ` Can Guo
@ 2021-03-17  9:19         ` Avri Altman
  0 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-17  9:19 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> >> > @@ -1079,6 +1113,14 @@ static void __ufshpb_evict_region(struct
> >> > ufshpb_lu *hpb,
> >> >
> >> >       ufshpb_cleanup_lru_info(lru_info, rgn);
> >> >
> >> > +     if (hpb->is_hcm) {
> >> > +             unsigned long flags;
> >> > +
> >> > +             spin_lock_irqsave(&rgn->rgn_lock, flags);
> >> > +             rgn->reads = 0;
> >> > +             spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> >> > +     }
> >> > +
While at it, Following your comments concerning the unmap request,
Better move this as well outside of __ufshpb_evict_region while rgn_state_lock is not held.

Thanks,
Avri

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-02 13:24 ` [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response Avri Altman
  2021-03-15  1:34   ` Can Guo
@ 2021-03-17 10:56   ` Can Guo
  2021-03-17 11:23     ` Avri Altman
  1 sibling, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-17 10:56 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-02 21:24, Avri Altman wrote:
> The spec does not define what is the host's recommended response when
> the device send hpb dev reset response (oper 0x2).
> 
> We will update all active hpb regions: mark them and do that on the 
> next
> read.
> 
> Signed-off-by: Avri Altman <avri.altman@wdc.com>
> ---
>  drivers/scsi/ufs/ufshpb.c | 47 ++++++++++++++++++++++++++++++++++++---
>  drivers/scsi/ufs/ufshpb.h |  2 ++
>  2 files changed, 46 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> index 0744feb4d484..0034fa03fdc6 100644
> --- a/drivers/scsi/ufs/ufshpb.c
> +++ b/drivers/scsi/ufs/ufshpb.c
> @@ -642,7 +642,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct
> ufshcd_lrb *lrbp)
>  		if (rgn->reads == ACTIVATION_THRESHOLD)
>  			activate = true;
>  		spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> -		if (activate) {
> +		if (activate ||
> +		    test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) {
>  			spin_lock_irqsave(&hpb->rsp_list_lock, flags);
>  			ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
>  			hpb->stats.rb_active_cnt++;
> @@ -1480,6 +1481,20 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba,
> struct ufshcd_lrb *lrbp)
>  	case HPB_RSP_DEV_RESET:
>  		dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
>  			 "UFS device lost HPB information during PM.\n");
> +
> +		if (hpb->is_hcm) {
> +			struct scsi_device *sdev;
> +
> +			__shost_for_each_device(sdev, hba->host) {
> +				struct ufshpb_lu *h = sdev->hostdata;
> +
> +				if (!h)
> +					continue;
> +
> +				schedule_work(&hpb->ufshpb_lun_reset_work);
> +			}
> +		}
> +
>  		break;
>  	default:
>  		dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
> @@ -1594,6 +1609,25 @@ static void
> ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
>  	spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>  }
> 
> +static void ufshpb_reset_work_handler(struct work_struct *work)

Just curious, directly doing below things inside ufshpb_rsp_upiu() does 
not
seem a problem to me, does this really deserve a separate work?

Thanks,
Can Guo.

> +{
> +	struct ufshpb_lu *hpb;
> +	struct victim_select_info *lru_info;
> +	struct ufshpb_region *rgn;
> +	unsigned long flags;
> +
> +	hpb = container_of(work, struct ufshpb_lu, ufshpb_lun_reset_work);
> +
> +	lru_info = &hpb->lru_info;
> +
> +	spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> +
> +	list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
> +		set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
> +
> +	spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> +}
> +
>  static void ufshpb_normalization_work_handler(struct work_struct 
> *work)
>  {
>  	struct ufshpb_lu *hpb;
> @@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct
> ufs_hba *hba, struct ufshpb_lu *hpb)
>  		} else {
>  			rgn->rgn_state = HPB_RGN_INACTIVE;
>  		}
> +
> +		rgn->rgn_flags = 0;
>  	}
> 
>  	return 0;
> @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> *hba, struct ufshpb_lu *hpb)
>  	INIT_LIST_HEAD(&hpb->list_hpb_lu);
> 
>  	INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> -	if (hpb->is_hcm)
> +	if (hpb->is_hcm) {
>  		INIT_WORK(&hpb->ufshpb_normalization_work,
>  			  ufshpb_normalization_work_handler);
> +		INIT_WORK(&hpb->ufshpb_lun_reset_work,
> +			  ufshpb_reset_work_handler);
> +	}
> 
>  	hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
>  			  sizeof(struct ufshpb_req), 0, 0, NULL);
> @@ -2114,8 +2153,10 @@ static void ufshpb_discard_rsp_lists(struct
> ufshpb_lu *hpb)
> 
>  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>  {
> -	if (hpb->is_hcm)
> +	if (hpb->is_hcm) {
> +		cancel_work_sync(&hpb->ufshpb_lun_reset_work);
>  		cancel_work_sync(&hpb->ufshpb_normalization_work);
> +	}
>  	cancel_work_sync(&hpb->map_work);
>  }
> 
> diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> index 84598a317897..37c1b0ea0c0a 100644
> --- a/drivers/scsi/ufs/ufshpb.h
> +++ b/drivers/scsi/ufs/ufshpb.h
> @@ -121,6 +121,7 @@ struct ufshpb_region {
>  	struct list_head list_lru_rgn;
>  	unsigned long rgn_flags;
>  #define RGN_FLAG_DIRTY 0
> +#define RGN_FLAG_UPDATE 1
> 
>  	/* region reads - for host mode */
>  	spinlock_t rgn_lock;
> @@ -217,6 +218,7 @@ struct ufshpb_lu {
>  	/* for selecting victim */
>  	struct victim_select_info lru_info;
>  	struct work_struct ufshpb_normalization_work;
> +	struct work_struct ufshpb_lun_reset_work;
> 
>  	/* pinned region information */
>  	u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-17 10:56   ` Can Guo
@ 2021-03-17 11:23     ` Avri Altman
  2021-03-17 12:12       ` Can Guo
  0 siblings, 1 reply; 58+ messages in thread
From: Avri Altman @ 2021-03-17 11:23 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> 
> On 2021-03-02 21:24, Avri Altman wrote:
> > The spec does not define what is the host's recommended response when
> > the device send hpb dev reset response (oper 0x2).
> >
> > We will update all active hpb regions: mark them and do that on the
> > next
> > read.
> >
> > Signed-off-by: Avri Altman <avri.altman@wdc.com>
> > ---
> >  drivers/scsi/ufs/ufshpb.c | 47
> ++++++++++++++++++++++++++++++++++++---
> >  drivers/scsi/ufs/ufshpb.h |  2 ++
> >  2 files changed, 46 insertions(+), 3 deletions(-)
> >
> > diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> > index 0744feb4d484..0034fa03fdc6 100644
> > --- a/drivers/scsi/ufs/ufshpb.c
> > +++ b/drivers/scsi/ufs/ufshpb.c
> > @@ -642,7 +642,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct
> > ufshcd_lrb *lrbp)
> >               if (rgn->reads == ACTIVATION_THRESHOLD)
> >                       activate = true;
> >               spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> > -             if (activate) {
> > +             if (activate ||
> > +                 test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) {
> >                       spin_lock_irqsave(&hpb->rsp_list_lock, flags);
> >                       ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
> >                       hpb->stats.rb_active_cnt++;
> > @@ -1480,6 +1481,20 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba,
> > struct ufshcd_lrb *lrbp)
> >       case HPB_RSP_DEV_RESET:
> >               dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
> >                        "UFS device lost HPB information during PM.\n");
> > +
> > +             if (hpb->is_hcm) {
> > +                     struct scsi_device *sdev;
> > +
> > +                     __shost_for_each_device(sdev, hba->host) {
> > +                             struct ufshpb_lu *h = sdev->hostdata;
> > +
> > +                             if (!h)
> > +                                     continue;
> > +
> > +                             schedule_work(&hpb->ufshpb_lun_reset_work);
> > +                     }
> > +             }
> > +
> >               break;
> >       default:
> >               dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
> > @@ -1594,6 +1609,25 @@ static void
> > ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
> >       spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> >  }
> >
> > +static void ufshpb_reset_work_handler(struct work_struct *work)
> 
> Just curious, directly doing below things inside ufshpb_rsp_upiu() does
> not
> seem a problem to me, does this really deserve a separate work?
I don't know, I never even consider of doing this.
The active region list may contain up to few thousands of regions - 
It is not rare to see configurations that covers the entire device.

But yes, I can do that.
Better to get ack from Daejun first.

Thanks,
Avri

> 
> Thanks,
> Can Guo.
> 
> > +{
> > +     struct ufshpb_lu *hpb;
> > +     struct victim_select_info *lru_info;
> > +     struct ufshpb_region *rgn;
> > +     unsigned long flags;
> > +
> > +     hpb = container_of(work, struct ufshpb_lu, ufshpb_lun_reset_work);
> > +
> > +     lru_info = &hpb->lru_info;
> > +
> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> > +
> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
> > +             set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
> > +
> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> > +}
> > +
> >  static void ufshpb_normalization_work_handler(struct work_struct
> > *work)
> >  {
> >       struct ufshpb_lu *hpb;
> > @@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct
> > ufs_hba *hba, struct ufshpb_lu *hpb)
> >               } else {
> >                       rgn->rgn_state = HPB_RGN_INACTIVE;
> >               }
> > +
> > +             rgn->rgn_flags = 0;
> >       }
> >
> >       return 0;
> > @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> > *hba, struct ufshpb_lu *hpb)
> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
> >
> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> > -     if (hpb->is_hcm)
> > +     if (hpb->is_hcm) {
> >               INIT_WORK(&hpb->ufshpb_normalization_work,
> >                         ufshpb_normalization_work_handler);
> > +             INIT_WORK(&hpb->ufshpb_lun_reset_work,
> > +                       ufshpb_reset_work_handler);
> > +     }
> >
> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
> > @@ -2114,8 +2153,10 @@ static void ufshpb_discard_rsp_lists(struct
> > ufshpb_lu *hpb)
> >
> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
> >  {
> > -     if (hpb->is_hcm)
> > +     if (hpb->is_hcm) {
> > +             cancel_work_sync(&hpb->ufshpb_lun_reset_work);
> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
> > +     }
> >       cancel_work_sync(&hpb->map_work);
> >  }
> >
> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> > index 84598a317897..37c1b0ea0c0a 100644
> > --- a/drivers/scsi/ufs/ufshpb.h
> > +++ b/drivers/scsi/ufs/ufshpb.h
> > @@ -121,6 +121,7 @@ struct ufshpb_region {
> >       struct list_head list_lru_rgn;
> >       unsigned long rgn_flags;
> >  #define RGN_FLAG_DIRTY 0
> > +#define RGN_FLAG_UPDATE 1
> >
> >       /* region reads - for host mode */
> >       spinlock_t rgn_lock;
> > @@ -217,6 +218,7 @@ struct ufshpb_lu {
> >       /* for selecting victim */
> >       struct victim_select_info lru_info;
> >       struct work_struct ufshpb_normalization_work;
> > +     struct work_struct ufshpb_lun_reset_work;
> >
> >       /* pinned region information */
> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-17 11:23     ` Avri Altman
@ 2021-03-17 12:12       ` Can Guo
  2021-03-17 12:22         ` Avri Altman
  0 siblings, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-17 12:12 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-17 19:23, Avri Altman wrote:
>> 
>> On 2021-03-02 21:24, Avri Altman wrote:
>> > The spec does not define what is the host's recommended response when
>> > the device send hpb dev reset response (oper 0x2).
>> >
>> > We will update all active hpb regions: mark them and do that on the
>> > next
>> > read.
>> >
>> > Signed-off-by: Avri Altman <avri.altman@wdc.com>
>> > ---
>> >  drivers/scsi/ufs/ufshpb.c | 47
>> ++++++++++++++++++++++++++++++++++++---
>> >  drivers/scsi/ufs/ufshpb.h |  2 ++
>> >  2 files changed, 46 insertions(+), 3 deletions(-)
>> >
>> > diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>> > index 0744feb4d484..0034fa03fdc6 100644
>> > --- a/drivers/scsi/ufs/ufshpb.c
>> > +++ b/drivers/scsi/ufs/ufshpb.c
>> > @@ -642,7 +642,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct
>> > ufshcd_lrb *lrbp)
>> >               if (rgn->reads == ACTIVATION_THRESHOLD)
>> >                       activate = true;
>> >               spin_unlock_irqrestore(&rgn->rgn_lock, flags);
>> > -             if (activate) {
>> > +             if (activate ||
>> > +                 test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) {
>> >                       spin_lock_irqsave(&hpb->rsp_list_lock, flags);
>> >                       ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
>> >                       hpb->stats.rb_active_cnt++;
>> > @@ -1480,6 +1481,20 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba,
>> > struct ufshcd_lrb *lrbp)
>> >       case HPB_RSP_DEV_RESET:
>> >               dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
>> >                        "UFS device lost HPB information during PM.\n");
>> > +
>> > +             if (hpb->is_hcm) {
>> > +                     struct scsi_device *sdev;
>> > +
>> > +                     __shost_for_each_device(sdev, hba->host) {
>> > +                             struct ufshpb_lu *h = sdev->hostdata;
>> > +
>> > +                             if (!h)
>> > +                                     continue;
>> > +
>> > +                             schedule_work(&hpb->ufshpb_lun_reset_work);
>> > +                     }
>> > +             }
>> > +
>> >               break;
>> >       default:
>> >               dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
>> > @@ -1594,6 +1609,25 @@ static void
>> > ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
>> >       spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>> >  }
>> >
>> > +static void ufshpb_reset_work_handler(struct work_struct *work)
>> 
>> Just curious, directly doing below things inside ufshpb_rsp_upiu() 
>> does
>> not
>> seem a problem to me, does this really deserve a separate work?
> I don't know, I never even consider of doing this.
> The active region list may contain up to few thousands of regions -
> It is not rare to see configurations that covers the entire device.
> 

Yes, true, it can be a huge list. But what does the ops 
"HPB_RSP_DEV_RESET"
really mean? The specs says "Device reset HPB Regions information", but 
I
don't know what is really happening. Could you please elaborate?

Thanks,
Can Guo.

> But yes, I can do that.
> Better to get ack from Daejun first.
> 
> Thanks,
> Avri
> 
>> 
>> Thanks,
>> Can Guo.
>> 
>> > +{
>> > +     struct ufshpb_lu *hpb;
>> > +     struct victim_select_info *lru_info;
>> > +     struct ufshpb_region *rgn;
>> > +     unsigned long flags;
>> > +
>> > +     hpb = container_of(work, struct ufshpb_lu, ufshpb_lun_reset_work);
>> > +
>> > +     lru_info = &hpb->lru_info;
>> > +
>> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
>> > +
>> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
>> > +             set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
>> > +
>> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
>> > +}
>> > +
>> >  static void ufshpb_normalization_work_handler(struct work_struct
>> > *work)
>> >  {
>> >       struct ufshpb_lu *hpb;
>> > @@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct
>> > ufs_hba *hba, struct ufshpb_lu *hpb)
>> >               } else {
>> >                       rgn->rgn_state = HPB_RGN_INACTIVE;
>> >               }
>> > +
>> > +             rgn->rgn_flags = 0;
>> >       }
>> >
>> >       return 0;
>> > @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
>> > *hba, struct ufshpb_lu *hpb)
>> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
>> >
>> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
>> > -     if (hpb->is_hcm)
>> > +     if (hpb->is_hcm) {
>> >               INIT_WORK(&hpb->ufshpb_normalization_work,
>> >                         ufshpb_normalization_work_handler);
>> > +             INIT_WORK(&hpb->ufshpb_lun_reset_work,
>> > +                       ufshpb_reset_work_handler);
>> > +     }
>> >
>> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
>> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
>> > @@ -2114,8 +2153,10 @@ static void ufshpb_discard_rsp_lists(struct
>> > ufshpb_lu *hpb)
>> >
>> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>> >  {
>> > -     if (hpb->is_hcm)
>> > +     if (hpb->is_hcm) {
>> > +             cancel_work_sync(&hpb->ufshpb_lun_reset_work);
>> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
>> > +     }
>> >       cancel_work_sync(&hpb->map_work);
>> >  }
>> >
>> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>> > index 84598a317897..37c1b0ea0c0a 100644
>> > --- a/drivers/scsi/ufs/ufshpb.h
>> > +++ b/drivers/scsi/ufs/ufshpb.h
>> > @@ -121,6 +121,7 @@ struct ufshpb_region {
>> >       struct list_head list_lru_rgn;
>> >       unsigned long rgn_flags;
>> >  #define RGN_FLAG_DIRTY 0
>> > +#define RGN_FLAG_UPDATE 1
>> >
>> >       /* region reads - for host mode */
>> >       spinlock_t rgn_lock;
>> > @@ -217,6 +218,7 @@ struct ufshpb_lu {
>> >       /* for selecting victim */
>> >       struct victim_select_info lru_info;
>> >       struct work_struct ufshpb_normalization_work;
>> > +     struct work_struct ufshpb_lun_reset_work;
>> >
>> >       /* pinned region information */
>> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-17 12:12       ` Can Guo
@ 2021-03-17 12:22         ` Avri Altman
  2021-03-17 13:50           ` Can Guo
  0 siblings, 1 reply; 58+ messages in thread
From: Avri Altman @ 2021-03-17 12:22 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> 
> On 2021-03-17 19:23, Avri Altman wrote:
> >>
> >> On 2021-03-02 21:24, Avri Altman wrote:
> >> > The spec does not define what is the host's recommended response when
> >> > the device send hpb dev reset response (oper 0x2).
> >> >
> >> > We will update all active hpb regions: mark them and do that on the
> >> > next
> >> > read.
> >> >
> >> > Signed-off-by: Avri Altman <avri.altman@wdc.com>
> >> > ---
> >> >  drivers/scsi/ufs/ufshpb.c | 47
> >> ++++++++++++++++++++++++++++++++++++---
> >> >  drivers/scsi/ufs/ufshpb.h |  2 ++
> >> >  2 files changed, 46 insertions(+), 3 deletions(-)
> >> >
> >> > diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> >> > index 0744feb4d484..0034fa03fdc6 100644
> >> > --- a/drivers/scsi/ufs/ufshpb.c
> >> > +++ b/drivers/scsi/ufs/ufshpb.c
> >> > @@ -642,7 +642,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct
> >> > ufshcd_lrb *lrbp)
> >> >               if (rgn->reads == ACTIVATION_THRESHOLD)
> >> >                       activate = true;
> >> >               spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> >> > -             if (activate) {
> >> > +             if (activate ||
> >> > +                 test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) {
> >> >                       spin_lock_irqsave(&hpb->rsp_list_lock, flags);
> >> >                       ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
> >> >                       hpb->stats.rb_active_cnt++;
> >> > @@ -1480,6 +1481,20 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba,
> >> > struct ufshcd_lrb *lrbp)
> >> >       case HPB_RSP_DEV_RESET:
> >> >               dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
> >> >                        "UFS device lost HPB information during PM.\n");
> >> > +
> >> > +             if (hpb->is_hcm) {
> >> > +                     struct scsi_device *sdev;
> >> > +
> >> > +                     __shost_for_each_device(sdev, hba->host) {
> >> > +                             struct ufshpb_lu *h = sdev->hostdata;
> >> > +
> >> > +                             if (!h)
> >> > +                                     continue;
> >> > +
> >> > +                             schedule_work(&hpb->ufshpb_lun_reset_work);
> >> > +                     }
> >> > +             }
> >> > +
> >> >               break;
> >> >       default:
> >> >               dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
> >> > @@ -1594,6 +1609,25 @@ static void
> >> > ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
> >> >       spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> >> >  }
> >> >
> >> > +static void ufshpb_reset_work_handler(struct work_struct *work)
> >>
> >> Just curious, directly doing below things inside ufshpb_rsp_upiu()
> >> does
> >> not
> >> seem a problem to me, does this really deserve a separate work?
> > I don't know, I never even consider of doing this.
> > The active region list may contain up to few thousands of regions -
> > It is not rare to see configurations that covers the entire device.
> >
> 
> Yes, true, it can be a huge list. But what does the ops
> "HPB_RSP_DEV_RESET"
> really mean? The specs says "Device reset HPB Regions information", but
> I
> don't know what is really happening. Could you please elaborate?
It means that the device informs the host that the L2P cache is no longer valid.
The spec doesn't say what to do in that case.
We thought that in host mode, it make sense to update all the active regions.

I think I will go with your suggestion.
Effectively, in host mode, since it is deactivating "cold" regions,
the lru list is kept relatively small, and contains only "hot" regions.

Thanks,
Avri

> 
> Thanks,
> Can Guo.
> 
> > But yes, I can do that.
> > Better to get ack from Daejun first.
> >
> > Thanks,
> > Avri
> >
> >>
> >> Thanks,
> >> Can Guo.
> >>
> >> > +{
> >> > +     struct ufshpb_lu *hpb;
> >> > +     struct victim_select_info *lru_info;
> >> > +     struct ufshpb_region *rgn;
> >> > +     unsigned long flags;
> >> > +
> >> > +     hpb = container_of(work, struct ufshpb_lu, ufshpb_lun_reset_work);
> >> > +
> >> > +     lru_info = &hpb->lru_info;
> >> > +
> >> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> >> > +
> >> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
> >> > +             set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
> >> > +
> >> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> >> > +}
> >> > +
> >> >  static void ufshpb_normalization_work_handler(struct work_struct
> >> > *work)
> >> >  {
> >> >       struct ufshpb_lu *hpb;
> >> > @@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct
> >> > ufs_hba *hba, struct ufshpb_lu *hpb)
> >> >               } else {
> >> >                       rgn->rgn_state = HPB_RGN_INACTIVE;
> >> >               }
> >> > +
> >> > +             rgn->rgn_flags = 0;
> >> >       }
> >> >
> >> >       return 0;
> >> > @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
> >> > *hba, struct ufshpb_lu *hpb)
> >> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
> >> >
> >> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> >> > -     if (hpb->is_hcm)
> >> > +     if (hpb->is_hcm) {
> >> >               INIT_WORK(&hpb->ufshpb_normalization_work,
> >> >                         ufshpb_normalization_work_handler);
> >> > +             INIT_WORK(&hpb->ufshpb_lun_reset_work,
> >> > +                       ufshpb_reset_work_handler);
> >> > +     }
> >> >
> >> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
> >> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
> >> > @@ -2114,8 +2153,10 @@ static void ufshpb_discard_rsp_lists(struct
> >> > ufshpb_lu *hpb)
> >> >
> >> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
> >> >  {
> >> > -     if (hpb->is_hcm)
> >> > +     if (hpb->is_hcm) {
> >> > +             cancel_work_sync(&hpb->ufshpb_lun_reset_work);
> >> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
> >> > +     }
> >> >       cancel_work_sync(&hpb->map_work);
> >> >  }
> >> >
> >> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> >> > index 84598a317897..37c1b0ea0c0a 100644
> >> > --- a/drivers/scsi/ufs/ufshpb.h
> >> > +++ b/drivers/scsi/ufs/ufshpb.h
> >> > @@ -121,6 +121,7 @@ struct ufshpb_region {
> >> >       struct list_head list_lru_rgn;
> >> >       unsigned long rgn_flags;
> >> >  #define RGN_FLAG_DIRTY 0
> >> > +#define RGN_FLAG_UPDATE 1
> >> >
> >> >       /* region reads - for host mode */
> >> >       spinlock_t rgn_lock;
> >> > @@ -217,6 +218,7 @@ struct ufshpb_lu {
> >> >       /* for selecting victim */
> >> >       struct victim_select_info lru_info;
> >> >       struct work_struct ufshpb_normalization_work;
> >> > +     struct work_struct ufshpb_lun_reset_work;
> >> >
> >> >       /* pinned region information */
> >> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-17 12:22         ` Avri Altman
@ 2021-03-17 13:50           ` Can Guo
  2021-03-17 14:22             ` Avri Altman
  0 siblings, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-17 13:50 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-17 20:22, Avri Altman wrote:
>> 
>> On 2021-03-17 19:23, Avri Altman wrote:
>> >>
>> >> On 2021-03-02 21:24, Avri Altman wrote:
>> >> > The spec does not define what is the host's recommended response when
>> >> > the device send hpb dev reset response (oper 0x2).
>> >> >
>> >> > We will update all active hpb regions: mark them and do that on the
>> >> > next
>> >> > read.
>> >> >
>> >> > Signed-off-by: Avri Altman <avri.altman@wdc.com>
>> >> > ---
>> >> >  drivers/scsi/ufs/ufshpb.c | 47
>> >> ++++++++++++++++++++++++++++++++++++---
>> >> >  drivers/scsi/ufs/ufshpb.h |  2 ++
>> >> >  2 files changed, 46 insertions(+), 3 deletions(-)
>> >> >
>> >> > diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>> >> > index 0744feb4d484..0034fa03fdc6 100644
>> >> > --- a/drivers/scsi/ufs/ufshpb.c
>> >> > +++ b/drivers/scsi/ufs/ufshpb.c
>> >> > @@ -642,7 +642,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct
>> >> > ufshcd_lrb *lrbp)
>> >> >               if (rgn->reads == ACTIVATION_THRESHOLD)
>> >> >                       activate = true;
>> >> >               spin_unlock_irqrestore(&rgn->rgn_lock, flags);
>> >> > -             if (activate) {
>> >> > +             if (activate ||
>> >> > +                 test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) {

Other than this place, do we also need to clear this bit in places like
ufshpb_map_req_compl_fn() and/or ufshpb_cleanup_lru_info()? Otherwise,
this flag may be left there even after the rgn is inactivated.

>> >> >                       spin_lock_irqsave(&hpb->rsp_list_lock, flags);
>> >> >                       ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
>> >> >                       hpb->stats.rb_active_cnt++;
>> >> > @@ -1480,6 +1481,20 @@ void ufshpb_rsp_upiu(struct ufs_hba *hba,
>> >> > struct ufshcd_lrb *lrbp)
>> >> >       case HPB_RSP_DEV_RESET:
>> >> >               dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
>> >> >                        "UFS device lost HPB information during PM.\n");
>> >> > +
>> >> > +             if (hpb->is_hcm) {
>> >> > +                     struct scsi_device *sdev;
>> >> > +
>> >> > +                     __shost_for_each_device(sdev, hba->host) {
>> >> > +                             struct ufshpb_lu *h = sdev->hostdata;
>> >> > +
>> >> > +                             if (!h)
>> >> > +                                     continue;
>> >> > +
>> >> > +                             schedule_work(&hpb->ufshpb_lun_reset_work);
>> >> > +                     }
>> >> > +             }
>> >> > +
>> >> >               break;
>> >> >       default:
>> >> >               dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
>> >> > @@ -1594,6 +1609,25 @@ static void
>> >> > ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
>> >> >       spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>> >> >  }
>> >> >
>> >> > +static void ufshpb_reset_work_handler(struct work_struct *work)
>> >>
>> >> Just curious, directly doing below things inside ufshpb_rsp_upiu()
>> >> does
>> >> not
>> >> seem a problem to me, does this really deserve a separate work?
>> > I don't know, I never even consider of doing this.
>> > The active region list may contain up to few thousands of regions -
>> > It is not rare to see configurations that covers the entire device.
>> >
>> 
>> Yes, true, it can be a huge list. But what does the ops
>> "HPB_RSP_DEV_RESET"
>> really mean? The specs says "Device reset HPB Regions information", 
>> but
>> I
>> don't know what is really happening. Could you please elaborate?
> It means that the device informs the host that the L2P cache is no 
> longer valid.
> The spec doesn't say what to do in that case.

Then it means that all the clean (without DIRTY flag set) HPB entries 
(ppns)
in active rgns in host memory side may not be valid to the device 
anymore.
Please correct me if I am wrong.

> We thought that in host mode, it make sense to update all the active 
> regions.

But current logic does not set the state of the sub-regions (in active 
regions) to
INVALID, it only marks all active regions as UPDATE.

Although one of subsequent read cmds shall put the sub-region back to 
activate_list,
ufshpb_test_ppn_dirty() can still return false, thus these read cmds 
still think the
ppns are valid and they shall move forward to send HPB Write Buffer 
(buffer id = 0x2,
in case of HPB2.0) and HPB Read cmds.

HPB Read cmds with invalid ppns will be treated as normal Read cmds by 
device as the
specs says, but what would happen to HPB Write Buffer cmds (buffer id = 
0x2, in case
of HPB2.0) with invalid ppns? Can this be a real problem?

> 
> I think I will go with your suggestion.
> Effectively, in host mode, since it is deactivating "cold" regions,
> the lru list is kept relatively small, and contains only "hot" regions.

hmm... I don't really have a idea on this, please go with whatever you 
and Daejun think is fine here.

Thanks,
Can Guo.

> 
> Thanks,
> Avri
> 
>> 
>> Thanks,
>> Can Guo.
>> 
>> > But yes, I can do that.
>> > Better to get ack from Daejun first.
>> >
>> > Thanks,
>> > Avri
>> >
>> >>
>> >> Thanks,
>> >> Can Guo.
>> >>
>> >> > +{
>> >> > +     struct ufshpb_lu *hpb;
>> >> > +     struct victim_select_info *lru_info;
>> >> > +     struct ufshpb_region *rgn;
>> >> > +     unsigned long flags;
>> >> > +
>> >> > +     hpb = container_of(work, struct ufshpb_lu, ufshpb_lun_reset_work);
>> >> > +
>> >> > +     lru_info = &hpb->lru_info;
>> >> > +
>> >> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
>> >> > +
>> >> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
>> >> > +             set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
>> >> > +
>> >> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
>> >> > +}
>> >> > +
>> >> >  static void ufshpb_normalization_work_handler(struct work_struct
>> >> > *work)
>> >> >  {
>> >> >       struct ufshpb_lu *hpb;
>> >> > @@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct
>> >> > ufs_hba *hba, struct ufshpb_lu *hpb)
>> >> >               } else {
>> >> >                       rgn->rgn_state = HPB_RGN_INACTIVE;
>> >> >               }
>> >> > +
>> >> > +             rgn->rgn_flags = 0;
>> >> >       }
>> >> >
>> >> >       return 0;
>> >> > @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct ufs_hba
>> >> > *hba, struct ufshpb_lu *hpb)
>> >> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
>> >> >
>> >> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
>> >> > -     if (hpb->is_hcm)
>> >> > +     if (hpb->is_hcm) {
>> >> >               INIT_WORK(&hpb->ufshpb_normalization_work,
>> >> >                         ufshpb_normalization_work_handler);
>> >> > +             INIT_WORK(&hpb->ufshpb_lun_reset_work,
>> >> > +                       ufshpb_reset_work_handler);
>> >> > +     }
>> >> >
>> >> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
>> >> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
>> >> > @@ -2114,8 +2153,10 @@ static void ufshpb_discard_rsp_lists(struct
>> >> > ufshpb_lu *hpb)
>> >> >
>> >> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>> >> >  {
>> >> > -     if (hpb->is_hcm)
>> >> > +     if (hpb->is_hcm) {
>> >> > +             cancel_work_sync(&hpb->ufshpb_lun_reset_work);
>> >> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
>> >> > +     }
>> >> >       cancel_work_sync(&hpb->map_work);
>> >> >  }
>> >> >
>> >> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>> >> > index 84598a317897..37c1b0ea0c0a 100644
>> >> > --- a/drivers/scsi/ufs/ufshpb.h
>> >> > +++ b/drivers/scsi/ufs/ufshpb.h
>> >> > @@ -121,6 +121,7 @@ struct ufshpb_region {
>> >> >       struct list_head list_lru_rgn;
>> >> >       unsigned long rgn_flags;
>> >> >  #define RGN_FLAG_DIRTY 0
>> >> > +#define RGN_FLAG_UPDATE 1
>> >> >
>> >> >       /* region reads - for host mode */
>> >> >       spinlock_t rgn_lock;
>> >> > @@ -217,6 +218,7 @@ struct ufshpb_lu {
>> >> >       /* for selecting victim */
>> >> >       struct victim_select_info lru_info;
>> >> >       struct work_struct ufshpb_normalization_work;
>> >> > +     struct work_struct ufshpb_lun_reset_work;
>> >> >
>> >> >       /* pinned region information */
>> >> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-17 13:50           ` Can Guo
@ 2021-03-17 14:22             ` Avri Altman
  2021-03-17 14:36               ` Can Guo
  0 siblings, 1 reply; 58+ messages in thread
From: Avri Altman @ 2021-03-17 14:22 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

 
> 
> On 2021-03-17 20:22, Avri Altman wrote:
> >>
> >> On 2021-03-17 19:23, Avri Altman wrote:
> >> >>
> >> >> On 2021-03-02 21:24, Avri Altman wrote:
> >> >> > The spec does not define what is the host's recommended response
> when
> >> >> > the device send hpb dev reset response (oper 0x2).
> >> >> >
> >> >> > We will update all active hpb regions: mark them and do that on the
> >> >> > next
> >> >> > read.
> >> >> >
> >> >> > Signed-off-by: Avri Altman <avri.altman@wdc.com>
> >> >> > ---
> >> >> >  drivers/scsi/ufs/ufshpb.c | 47
> >> >> ++++++++++++++++++++++++++++++++++++---
> >> >> >  drivers/scsi/ufs/ufshpb.h |  2 ++
> >> >> >  2 files changed, 46 insertions(+), 3 deletions(-)
> >> >> >
> >> >> > diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
> >> >> > index 0744feb4d484..0034fa03fdc6 100644
> >> >> > --- a/drivers/scsi/ufs/ufshpb.c
> >> >> > +++ b/drivers/scsi/ufs/ufshpb.c
> >> >> > @@ -642,7 +642,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct
> >> >> > ufshcd_lrb *lrbp)
> >> >> >               if (rgn->reads == ACTIVATION_THRESHOLD)
> >> >> >                       activate = true;
> >> >> >               spin_unlock_irqrestore(&rgn->rgn_lock, flags);
> >> >> > -             if (activate) {
> >> >> > +             if (activate ||
> >> >> > +                 test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) {
> 
> Other than this place, do we also need to clear this bit in places like
> ufshpb_map_req_compl_fn() and/or ufshpb_cleanup_lru_info()? Otherwise,
> this flag may be left there even after the rgn is inactivated.
I don't think so - may cause a race if device reset arrives when map request just finished.
Better to be in one place.

> 
> >> >> >                       spin_lock_irqsave(&hpb->rsp_list_lock, flags);
> >> >> >                       ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
> >> >> >                       hpb->stats.rb_active_cnt++;
> >> >> > @@ -1480,6 +1481,20 @@ void ufshpb_rsp_upiu(struct ufs_hba
> *hba,
> >> >> > struct ufshcd_lrb *lrbp)
> >> >> >       case HPB_RSP_DEV_RESET:
> >> >> >               dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
> >> >> >                        "UFS device lost HPB information during PM.\n");
> >> >> > +
> >> >> > +             if (hpb->is_hcm) {
> >> >> > +                     struct scsi_device *sdev;
> >> >> > +
> >> >> > +                     __shost_for_each_device(sdev, hba->host) {
> >> >> > +                             struct ufshpb_lu *h = sdev->hostdata;
> >> >> > +
> >> >> > +                             if (!h)
> >> >> > +                                     continue;
> >> >> > +
> >> >> > +                             schedule_work(&hpb->ufshpb_lun_reset_work);
> >> >> > +                     }
> >> >> > +             }
> >> >> > +
> >> >> >               break;
> >> >> >       default:
> >> >> >               dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
> >> >> > @@ -1594,6 +1609,25 @@ static void
> >> >> > ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
> >> >> >       spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
> >> >> >  }
> >> >> >
> >> >> > +static void ufshpb_reset_work_handler(struct work_struct *work)
> >> >>
> >> >> Just curious, directly doing below things inside ufshpb_rsp_upiu()
> >> >> does
> >> >> not
> >> >> seem a problem to me, does this really deserve a separate work?
> >> > I don't know, I never even consider of doing this.
> >> > The active region list may contain up to few thousands of regions -
> >> > It is not rare to see configurations that covers the entire device.
> >> >
> >>
> >> Yes, true, it can be a huge list. But what does the ops
> >> "HPB_RSP_DEV_RESET"
> >> really mean? The specs says "Device reset HPB Regions information",
> >> but
> >> I
> >> don't know what is really happening. Could you please elaborate?
> > It means that the device informs the host that the L2P cache is no
> > longer valid.
> > The spec doesn't say what to do in that case.
> 
> Then it means that all the clean (without DIRTY flag set) HPB entries
> (ppns)
> in active rgns in host memory side may not be valid to the device
> anymore.
> Please correct me if I am wrong.
> 
> > We thought that in host mode, it make sense to update all the active
> > regions.
> 
> But current logic does not set the state of the sub-regions (in active
> regions) to
> INVALID, it only marks all active regions as UPDATE.
> 
> Although one of subsequent read cmds shall put the sub-region back to
> activate_list,
> ufshpb_test_ppn_dirty() can still return false, thus these read cmds
> still think the
> ppns are valid and they shall move forward to send HPB Write Buffer
> (buffer id = 0x2,
> in case of HPB2.0) and HPB Read cmds.
> 
> HPB Read cmds with invalid ppns will be treated as normal Read cmds by
> device as the
> specs says, but what would happen to HPB Write Buffer cmds (buffer id =
> 0x2, in case
> of HPB2.0) with invalid ppns? Can this be a real problem?
No need to control the ppn dirty / invalid state for this case.
The device send device reset so it is aware that all the L2P cache is invalid.
Any HPB_READ is treated like normal READ10.

Only once HPB-READ-BUFFER is completed,
the device will relate back to the physical address.

> 
> >
> > I think I will go with your suggestion.
> > Effectively, in host mode, since it is deactivating "cold" regions,
> > the lru list is kept relatively small, and contains only "hot" regions.
> 
> hmm... I don't really have a idea on this, please go with whatever you
> and Daejun think is fine here.
I will take your advice and remove the worker.


Thanks,
Avri

> 
> Thanks,
> Can Guo.
> 
> >
> > Thanks,
> > Avri
> >
> >>
> >> Thanks,
> >> Can Guo.
> >>
> >> > But yes, I can do that.
> >> > Better to get ack from Daejun first.
> >> >
> >> > Thanks,
> >> > Avri
> >> >
> >> >>
> >> >> Thanks,
> >> >> Can Guo.
> >> >>
> >> >> > +{
> >> >> > +     struct ufshpb_lu *hpb;
> >> >> > +     struct victim_select_info *lru_info;
> >> >> > +     struct ufshpb_region *rgn;
> >> >> > +     unsigned long flags;
> >> >> > +
> >> >> > +     hpb = container_of(work, struct ufshpb_lu,
> ufshpb_lun_reset_work);
> >> >> > +
> >> >> > +     lru_info = &hpb->lru_info;
> >> >> > +
> >> >> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> >> >> > +
> >> >> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
> >> >> > +             set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
> >> >> > +
> >> >> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> >> >> > +}
> >> >> > +
> >> >> >  static void ufshpb_normalization_work_handler(struct work_struct
> >> >> > *work)
> >> >> >  {
> >> >> >       struct ufshpb_lu *hpb;
> >> >> > @@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct
> >> >> > ufs_hba *hba, struct ufshpb_lu *hpb)
> >> >> >               } else {
> >> >> >                       rgn->rgn_state = HPB_RGN_INACTIVE;
> >> >> >               }
> >> >> > +
> >> >> > +             rgn->rgn_flags = 0;
> >> >> >       }
> >> >> >
> >> >> >       return 0;
> >> >> > @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct
> ufs_hba
> >> >> > *hba, struct ufshpb_lu *hpb)
> >> >> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
> >> >> >
> >> >> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> >> >> > -     if (hpb->is_hcm)
> >> >> > +     if (hpb->is_hcm) {
> >> >> >               INIT_WORK(&hpb->ufshpb_normalization_work,
> >> >> >                         ufshpb_normalization_work_handler);
> >> >> > +             INIT_WORK(&hpb->ufshpb_lun_reset_work,
> >> >> > +                       ufshpb_reset_work_handler);
> >> >> > +     }
> >> >> >
> >> >> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
> >> >> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
> >> >> > @@ -2114,8 +2153,10 @@ static void ufshpb_discard_rsp_lists(struct
> >> >> > ufshpb_lu *hpb)
> >> >> >
> >> >> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
> >> >> >  {
> >> >> > -     if (hpb->is_hcm)
> >> >> > +     if (hpb->is_hcm) {
> >> >> > +             cancel_work_sync(&hpb->ufshpb_lun_reset_work);
> >> >> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
> >> >> > +     }
> >> >> >       cancel_work_sync(&hpb->map_work);
> >> >> >  }
> >> >> >
> >> >> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> >> >> > index 84598a317897..37c1b0ea0c0a 100644
> >> >> > --- a/drivers/scsi/ufs/ufshpb.h
> >> >> > +++ b/drivers/scsi/ufs/ufshpb.h
> >> >> > @@ -121,6 +121,7 @@ struct ufshpb_region {
> >> >> >       struct list_head list_lru_rgn;
> >> >> >       unsigned long rgn_flags;
> >> >> >  #define RGN_FLAG_DIRTY 0
> >> >> > +#define RGN_FLAG_UPDATE 1
> >> >> >
> >> >> >       /* region reads - for host mode */
> >> >> >       spinlock_t rgn_lock;
> >> >> > @@ -217,6 +218,7 @@ struct ufshpb_lu {
> >> >> >       /* for selecting victim */
> >> >> >       struct victim_select_info lru_info;
> >> >> >       struct work_struct ufshpb_normalization_work;
> >> >> > +     struct work_struct ufshpb_lun_reset_work;
> >> >> >
> >> >> >       /* pinned region information */
> >> >> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-17 14:22             ` Avri Altman
@ 2021-03-17 14:36               ` Can Guo
  2021-03-17 15:46                 ` Avri Altman
  0 siblings, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-17 14:36 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-17 22:22, Avri Altman wrote:
>> 
>> On 2021-03-17 20:22, Avri Altman wrote:
>> >>
>> >> On 2021-03-17 19:23, Avri Altman wrote:
>> >> >>
>> >> >> On 2021-03-02 21:24, Avri Altman wrote:
>> >> >> > The spec does not define what is the host's recommended response
>> when
>> >> >> > the device send hpb dev reset response (oper 0x2).
>> >> >> >
>> >> >> > We will update all active hpb regions: mark them and do that on the
>> >> >> > next
>> >> >> > read.
>> >> >> >
>> >> >> > Signed-off-by: Avri Altman <avri.altman@wdc.com>
>> >> >> > ---
>> >> >> >  drivers/scsi/ufs/ufshpb.c | 47
>> >> >> ++++++++++++++++++++++++++++++++++++---
>> >> >> >  drivers/scsi/ufs/ufshpb.h |  2 ++
>> >> >> >  2 files changed, 46 insertions(+), 3 deletions(-)
>> >> >> >
>> >> >> > diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
>> >> >> > index 0744feb4d484..0034fa03fdc6 100644
>> >> >> > --- a/drivers/scsi/ufs/ufshpb.c
>> >> >> > +++ b/drivers/scsi/ufs/ufshpb.c
>> >> >> > @@ -642,7 +642,8 @@ int ufshpb_prep(struct ufs_hba *hba, struct
>> >> >> > ufshcd_lrb *lrbp)
>> >> >> >               if (rgn->reads == ACTIVATION_THRESHOLD)
>> >> >> >                       activate = true;
>> >> >> >               spin_unlock_irqrestore(&rgn->rgn_lock, flags);
>> >> >> > -             if (activate) {
>> >> >> > +             if (activate ||
>> >> >> > +                 test_and_clear_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags)) {
>> 
>> Other than this place, do we also need to clear this bit in places 
>> like
>> ufshpb_map_req_compl_fn() and/or ufshpb_cleanup_lru_info()? Otherwise,
>> this flag may be left there even after the rgn is inactivated.
> I don't think so - may cause a race if device reset arrives when map
> request just finished.

hmm.. that does not look racy to me, in that case the bit is either
set or not set, which does not hurt anything. Anyways, it is up to you.

> Better to be in one place.
> 
>> 
>> >> >> >                       spin_lock_irqsave(&hpb->rsp_list_lock, flags);
>> >> >> >                       ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
>> >> >> >                       hpb->stats.rb_active_cnt++;
>> >> >> > @@ -1480,6 +1481,20 @@ void ufshpb_rsp_upiu(struct ufs_hba
>> *hba,
>> >> >> > struct ufshcd_lrb *lrbp)
>> >> >> >       case HPB_RSP_DEV_RESET:
>> >> >> >               dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
>> >> >> >                        "UFS device lost HPB information during PM.\n");
>> >> >> > +
>> >> >> > +             if (hpb->is_hcm) {
>> >> >> > +                     struct scsi_device *sdev;
>> >> >> > +
>> >> >> > +                     __shost_for_each_device(sdev, hba->host) {
>> >> >> > +                             struct ufshpb_lu *h = sdev->hostdata;
>> >> >> > +
>> >> >> > +                             if (!h)
>> >> >> > +                                     continue;
>> >> >> > +
>> >> >> > +                             schedule_work(&hpb->ufshpb_lun_reset_work);
>> >> >> > +                     }
>> >> >> > +             }
>> >> >> > +
>> >> >> >               break;
>> >> >> >       default:
>> >> >> >               dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
>> >> >> > @@ -1594,6 +1609,25 @@ static void
>> >> >> > ufshpb_run_inactive_region_list(struct ufshpb_lu *hpb)
>> >> >> >       spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
>> >> >> >  }
>> >> >> >
>> >> >> > +static void ufshpb_reset_work_handler(struct work_struct *work)
>> >> >>
>> >> >> Just curious, directly doing below things inside ufshpb_rsp_upiu()
>> >> >> does
>> >> >> not
>> >> >> seem a problem to me, does this really deserve a separate work?
>> >> > I don't know, I never even consider of doing this.
>> >> > The active region list may contain up to few thousands of regions -
>> >> > It is not rare to see configurations that covers the entire device.
>> >> >
>> >>
>> >> Yes, true, it can be a huge list. But what does the ops
>> >> "HPB_RSP_DEV_RESET"
>> >> really mean? The specs says "Device reset HPB Regions information",
>> >> but
>> >> I
>> >> don't know what is really happening. Could you please elaborate?
>> > It means that the device informs the host that the L2P cache is no
>> > longer valid.
>> > The spec doesn't say what to do in that case.
>> 
>> Then it means that all the clean (without DIRTY flag set) HPB entries
>> (ppns)
>> in active rgns in host memory side may not be valid to the device
>> anymore.
>> Please correct me if I am wrong.
>> 
>> > We thought that in host mode, it make sense to update all the active
>> > regions.
>> 
>> But current logic does not set the state of the sub-regions (in active
>> regions) to
>> INVALID, it only marks all active regions as UPDATE.
>> 
>> Although one of subsequent read cmds shall put the sub-region back to
>> activate_list,
>> ufshpb_test_ppn_dirty() can still return false, thus these read cmds
>> still think the
>> ppns are valid and they shall move forward to send HPB Write Buffer
>> (buffer id = 0x2,
>> in case of HPB2.0) and HPB Read cmds.
>> 
>> HPB Read cmds with invalid ppns will be treated as normal Read cmds by
>> device as the
>> specs says, but what would happen to HPB Write Buffer cmds (buffer id 
>> =
>> 0x2, in case
>> of HPB2.0) with invalid ppns? Can this be a real problem?
> No need to control the ppn dirty / invalid state for this case.
> The device send device reset so it is aware that all the L2P cache is 
> invalid.
> Any HPB_READ is treated like normal READ10.
> 
> Only once HPB-READ-BUFFER is completed,
> the device will relate back to the physical address.

What about HPB-WRITE-BUFFER (buffer id = 0x2) cmds?

Thanks,
Can Guo.

> 
>> 
>> >
>> > I think I will go with your suggestion.
>> > Effectively, in host mode, since it is deactivating "cold" regions,
>> > the lru list is kept relatively small, and contains only "hot" regions.
>> 
>> hmm... I don't really have a idea on this, please go with whatever you
>> and Daejun think is fine here.
> I will take your advice and remove the worker.
> 
> 
> Thanks,
> Avri
> 
>> 
>> Thanks,
>> Can Guo.
>> 
>> >
>> > Thanks,
>> > Avri
>> >
>> >>
>> >> Thanks,
>> >> Can Guo.
>> >>
>> >> > But yes, I can do that.
>> >> > Better to get ack from Daejun first.
>> >> >
>> >> > Thanks,
>> >> > Avri
>> >> >
>> >> >>
>> >> >> Thanks,
>> >> >> Can Guo.
>> >> >>
>> >> >> > +{
>> >> >> > +     struct ufshpb_lu *hpb;
>> >> >> > +     struct victim_select_info *lru_info;
>> >> >> > +     struct ufshpb_region *rgn;
>> >> >> > +     unsigned long flags;
>> >> >> > +
>> >> >> > +     hpb = container_of(work, struct ufshpb_lu,
>> ufshpb_lun_reset_work);
>> >> >> > +
>> >> >> > +     lru_info = &hpb->lru_info;
>> >> >> > +
>> >> >> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
>> >> >> > +
>> >> >> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
>> >> >> > +             set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
>> >> >> > +
>> >> >> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
>> >> >> > +}
>> >> >> > +
>> >> >> >  static void ufshpb_normalization_work_handler(struct work_struct
>> >> >> > *work)
>> >> >> >  {
>> >> >> >       struct ufshpb_lu *hpb;
>> >> >> > @@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct
>> >> >> > ufs_hba *hba, struct ufshpb_lu *hpb)
>> >> >> >               } else {
>> >> >> >                       rgn->rgn_state = HPB_RGN_INACTIVE;
>> >> >> >               }
>> >> >> > +
>> >> >> > +             rgn->rgn_flags = 0;
>> >> >> >       }
>> >> >> >
>> >> >> >       return 0;
>> >> >> > @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct
>> ufs_hba
>> >> >> > *hba, struct ufshpb_lu *hpb)
>> >> >> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
>> >> >> >
>> >> >> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
>> >> >> > -     if (hpb->is_hcm)
>> >> >> > +     if (hpb->is_hcm) {
>> >> >> >               INIT_WORK(&hpb->ufshpb_normalization_work,
>> >> >> >                         ufshpb_normalization_work_handler);
>> >> >> > +             INIT_WORK(&hpb->ufshpb_lun_reset_work,
>> >> >> > +                       ufshpb_reset_work_handler);
>> >> >> > +     }
>> >> >> >
>> >> >> >       hpb->map_req_cache = kmem_cache_create("ufshpb_req_cache",
>> >> >> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
>> >> >> > @@ -2114,8 +2153,10 @@ static void ufshpb_discard_rsp_lists(struct
>> >> >> > ufshpb_lu *hpb)
>> >> >> >
>> >> >> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>> >> >> >  {
>> >> >> > -     if (hpb->is_hcm)
>> >> >> > +     if (hpb->is_hcm) {
>> >> >> > +             cancel_work_sync(&hpb->ufshpb_lun_reset_work);
>> >> >> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
>> >> >> > +     }
>> >> >> >       cancel_work_sync(&hpb->map_work);
>> >> >> >  }
>> >> >> >
>> >> >> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>> >> >> > index 84598a317897..37c1b0ea0c0a 100644
>> >> >> > --- a/drivers/scsi/ufs/ufshpb.h
>> >> >> > +++ b/drivers/scsi/ufs/ufshpb.h
>> >> >> > @@ -121,6 +121,7 @@ struct ufshpb_region {
>> >> >> >       struct list_head list_lru_rgn;
>> >> >> >       unsigned long rgn_flags;
>> >> >> >  #define RGN_FLAG_DIRTY 0
>> >> >> > +#define RGN_FLAG_UPDATE 1
>> >> >> >
>> >> >> >       /* region reads - for host mode */
>> >> >> >       spinlock_t rgn_lock;
>> >> >> > @@ -217,6 +218,7 @@ struct ufshpb_lu {
>> >> >> >       /* for selecting victim */
>> >> >> >       struct victim_select_info lru_info;
>> >> >> >       struct work_struct ufshpb_normalization_work;
>> >> >> > +     struct work_struct ufshpb_lun_reset_work;
>> >> >> >
>> >> >> >       /* pinned region information */
>> >> >> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-17 14:36               ` Can Guo
@ 2021-03-17 15:46                 ` Avri Altman
  2021-03-18  1:00                   ` Can Guo
  0 siblings, 1 reply; 58+ messages in thread
From: Avri Altman @ 2021-03-17 15:46 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> >> >> >>
> >> >> >> Just curious, directly doing below things inside ufshpb_rsp_upiu()
> >> >> >> does
> >> >> >> not
> >> >> >> seem a problem to me, does this really deserve a separate work?
> >> >> > I don't know, I never even consider of doing this.
> >> >> > The active region list may contain up to few thousands of regions -
> >> >> > It is not rare to see configurations that covers the entire device.
> >> >> >
> >> >>
> >> >> Yes, true, it can be a huge list. But what does the ops
> >> >> "HPB_RSP_DEV_RESET"
> >> >> really mean? The specs says "Device reset HPB Regions information",
> >> >> but
> >> >> I
> >> >> don't know what is really happening. Could you please elaborate?
> >> > It means that the device informs the host that the L2P cache is no
> >> > longer valid.
> >> > The spec doesn't say what to do in that case.
> >>
> >> Then it means that all the clean (without DIRTY flag set) HPB entries
> >> (ppns)
> >> in active rgns in host memory side may not be valid to the device
> >> anymore.
> >> Please correct me if I am wrong.
> >>
> >> > We thought that in host mode, it make sense to update all the active
> >> > regions.
> >>
> >> But current logic does not set the state of the sub-regions (in active
> >> regions) to
> >> INVALID, it only marks all active regions as UPDATE.
> >>
> >> Although one of subsequent read cmds shall put the sub-region back to
> >> activate_list,
> >> ufshpb_test_ppn_dirty() can still return false, thus these read cmds
> >> still think the
> >> ppns are valid and they shall move forward to send HPB Write Buffer
> >> (buffer id = 0x2,
> >> in case of HPB2.0) and HPB Read cmds.
> >>
> >> HPB Read cmds with invalid ppns will be treated as normal Read cmds by
> >> device as the
> >> specs says, but what would happen to HPB Write Buffer cmds (buffer id
> >> =
> >> 0x2, in case
> >> of HPB2.0) with invalid ppns? Can this be a real problem?
> > No need to control the ppn dirty / invalid state for this case.
> > The device send device reset so it is aware that all the L2P cache is
> > invalid.
> > Any HPB_READ is treated like normal READ10.
> >
> > Only once HPB-READ-BUFFER is completed,
> > the device will relate back to the physical address.
> 
> What about HPB-WRITE-BUFFER (buffer id = 0x2) cmds?
Same.
Oper 0x2 is a relative simple case.
The device is expected to manage some versioning framework not to be "fooled" by erroneous ppn.
There are some more challenging races that the device should meet.

Thanks,
Avri
> 
> Thanks,
> Can Guo.
> 
> >
> >>
> >> >
> >> > I think I will go with your suggestion.
> >> > Effectively, in host mode, since it is deactivating "cold" regions,
> >> > the lru list is kept relatively small, and contains only "hot" regions.
> >>
> >> hmm... I don't really have a idea on this, please go with whatever you
> >> and Daejun think is fine here.
> > I will take your advice and remove the worker.
> >
> >
> > Thanks,
> > Avri
> >
> >>
> >> Thanks,
> >> Can Guo.
> >>
> >> >
> >> > Thanks,
> >> > Avri
> >> >
> >> >>
> >> >> Thanks,
> >> >> Can Guo.
> >> >>
> >> >> > But yes, I can do that.
> >> >> > Better to get ack from Daejun first.
> >> >> >
> >> >> > Thanks,
> >> >> > Avri
> >> >> >
> >> >> >>
> >> >> >> Thanks,
> >> >> >> Can Guo.
> >> >> >>
> >> >> >> > +{
> >> >> >> > +     struct ufshpb_lu *hpb;
> >> >> >> > +     struct victim_select_info *lru_info;
> >> >> >> > +     struct ufshpb_region *rgn;
> >> >> >> > +     unsigned long flags;
> >> >> >> > +
> >> >> >> > +     hpb = container_of(work, struct ufshpb_lu,
> >> ufshpb_lun_reset_work);
> >> >> >> > +
> >> >> >> > +     lru_info = &hpb->lru_info;
> >> >> >> > +
> >> >> >> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> >> >> >> > +
> >> >> >> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
> >> >> >> > +             set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
> >> >> >> > +
> >> >> >> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> >> >> >> > +}
> >> >> >> > +
> >> >> >> >  static void ufshpb_normalization_work_handler(struct work_struct
> >> >> >> > *work)
> >> >> >> >  {
> >> >> >> >       struct ufshpb_lu *hpb;
> >> >> >> > @@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct
> >> >> >> > ufs_hba *hba, struct ufshpb_lu *hpb)
> >> >> >> >               } else {
> >> >> >> >                       rgn->rgn_state = HPB_RGN_INACTIVE;
> >> >> >> >               }
> >> >> >> > +
> >> >> >> > +             rgn->rgn_flags = 0;
> >> >> >> >       }
> >> >> >> >
> >> >> >> >       return 0;
> >> >> >> > @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct
> >> ufs_hba
> >> >> >> > *hba, struct ufshpb_lu *hpb)
> >> >> >> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
> >> >> >> >
> >> >> >> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> >> >> >> > -     if (hpb->is_hcm)
> >> >> >> > +     if (hpb->is_hcm) {
> >> >> >> >               INIT_WORK(&hpb->ufshpb_normalization_work,
> >> >> >> >                         ufshpb_normalization_work_handler);
> >> >> >> > +             INIT_WORK(&hpb->ufshpb_lun_reset_work,
> >> >> >> > +                       ufshpb_reset_work_handler);
> >> >> >> > +     }
> >> >> >> >
> >> >> >> >       hpb->map_req_cache =
> kmem_cache_create("ufshpb_req_cache",
> >> >> >> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
> >> >> >> > @@ -2114,8 +2153,10 @@ static void
> ufshpb_discard_rsp_lists(struct
> >> >> >> > ufshpb_lu *hpb)
> >> >> >> >
> >> >> >> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
> >> >> >> >  {
> >> >> >> > -     if (hpb->is_hcm)
> >> >> >> > +     if (hpb->is_hcm) {
> >> >> >> > +             cancel_work_sync(&hpb->ufshpb_lun_reset_work);
> >> >> >> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
> >> >> >> > +     }
> >> >> >> >       cancel_work_sync(&hpb->map_work);
> >> >> >> >  }
> >> >> >> >
> >> >> >> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> >> >> >> > index 84598a317897..37c1b0ea0c0a 100644
> >> >> >> > --- a/drivers/scsi/ufs/ufshpb.h
> >> >> >> > +++ b/drivers/scsi/ufs/ufshpb.h
> >> >> >> > @@ -121,6 +121,7 @@ struct ufshpb_region {
> >> >> >> >       struct list_head list_lru_rgn;
> >> >> >> >       unsigned long rgn_flags;
> >> >> >> >  #define RGN_FLAG_DIRTY 0
> >> >> >> > +#define RGN_FLAG_UPDATE 1
> >> >> >> >
> >> >> >> >       /* region reads - for host mode */
> >> >> >> >       spinlock_t rgn_lock;
> >> >> >> > @@ -217,6 +218,7 @@ struct ufshpb_lu {
> >> >> >> >       /* for selecting victim */
> >> >> >> >       struct victim_select_info lru_info;
> >> >> >> >       struct work_struct ufshpb_normalization_work;
> >> >> >> > +     struct work_struct ufshpb_lun_reset_work;
> >> >> >> >
> >> >> >> >       /* pinned region information */
> >> >> >> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-17 15:46                 ` Avri Altman
@ 2021-03-18  1:00                   ` Can Guo
  2021-03-18  8:04                     ` Avri Altman
  0 siblings, 1 reply; 58+ messages in thread
From: Can Guo @ 2021-03-18  1:00 UTC (permalink / raw)
  To: Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

On 2021-03-17 23:46, Avri Altman wrote:
>> >> >> >>
>> >> >> >> Just curious, directly doing below things inside ufshpb_rsp_upiu()
>> >> >> >> does
>> >> >> >> not
>> >> >> >> seem a problem to me, does this really deserve a separate work?
>> >> >> > I don't know, I never even consider of doing this.
>> >> >> > The active region list may contain up to few thousands of regions -
>> >> >> > It is not rare to see configurations that covers the entire device.
>> >> >> >
>> >> >>
>> >> >> Yes, true, it can be a huge list. But what does the ops
>> >> >> "HPB_RSP_DEV_RESET"
>> >> >> really mean? The specs says "Device reset HPB Regions information",
>> >> >> but
>> >> >> I
>> >> >> don't know what is really happening. Could you please elaborate?
>> >> > It means that the device informs the host that the L2P cache is no
>> >> > longer valid.
>> >> > The spec doesn't say what to do in that case.
>> >>
>> >> Then it means that all the clean (without DIRTY flag set) HPB entries
>> >> (ppns)
>> >> in active rgns in host memory side may not be valid to the device
>> >> anymore.
>> >> Please correct me if I am wrong.
>> >>
>> >> > We thought that in host mode, it make sense to update all the active
>> >> > regions.
>> >>
>> >> But current logic does not set the state of the sub-regions (in active
>> >> regions) to
>> >> INVALID, it only marks all active regions as UPDATE.
>> >>
>> >> Although one of subsequent read cmds shall put the sub-region back to
>> >> activate_list,
>> >> ufshpb_test_ppn_dirty() can still return false, thus these read cmds
>> >> still think the
>> >> ppns are valid and they shall move forward to send HPB Write Buffer
>> >> (buffer id = 0x2,
>> >> in case of HPB2.0) and HPB Read cmds.
>> >>
>> >> HPB Read cmds with invalid ppns will be treated as normal Read cmds by
>> >> device as the
>> >> specs says, but what would happen to HPB Write Buffer cmds (buffer id
>> >> =
>> >> 0x2, in case
>> >> of HPB2.0) with invalid ppns? Can this be a real problem?
>> > No need to control the ppn dirty / invalid state for this case.
>> > The device send device reset so it is aware that all the L2P cache is
>> > invalid.
>> > Any HPB_READ is treated like normal READ10.
>> >
>> > Only once HPB-READ-BUFFER is completed,
>> > the device will relate back to the physical address.
>> 
>> What about HPB-WRITE-BUFFER (buffer id = 0x2) cmds?
> Same.
> Oper 0x2 is a relative simple case.
> The device is expected to manage some versioning framework not to be
> "fooled" by erroneous ppn.
> There are some more challenging races that the device should meet.
> 

But I don't find the handling w.r.t this scenario on HPB2.0 specs -
how would the device re-act/respond to HPB-WRITE-BUFFER cmds with
invalid HPB entries? Could you please point me to relevant 
section/paragraph?

Thanks,
Can Guo.

> Thanks,
> Avri
>> 
>> Thanks,
>> Can Guo.
>> 
>> >
>> >>
>> >> >
>> >> > I think I will go with your suggestion.
>> >> > Effectively, in host mode, since it is deactivating "cold" regions,
>> >> > the lru list is kept relatively small, and contains only "hot" regions.
>> >>
>> >> hmm... I don't really have a idea on this, please go with whatever you
>> >> and Daejun think is fine here.
>> > I will take your advice and remove the worker.
>> >
>> >
>> > Thanks,
>> > Avri
>> >
>> >>
>> >> Thanks,
>> >> Can Guo.
>> >>
>> >> >
>> >> > Thanks,
>> >> > Avri
>> >> >
>> >> >>
>> >> >> Thanks,
>> >> >> Can Guo.
>> >> >>
>> >> >> > But yes, I can do that.
>> >> >> > Better to get ack from Daejun first.
>> >> >> >
>> >> >> > Thanks,
>> >> >> > Avri
>> >> >> >
>> >> >> >>
>> >> >> >> Thanks,
>> >> >> >> Can Guo.
>> >> >> >>
>> >> >> >> > +{
>> >> >> >> > +     struct ufshpb_lu *hpb;
>> >> >> >> > +     struct victim_select_info *lru_info;
>> >> >> >> > +     struct ufshpb_region *rgn;
>> >> >> >> > +     unsigned long flags;
>> >> >> >> > +
>> >> >> >> > +     hpb = container_of(work, struct ufshpb_lu,
>> >> ufshpb_lun_reset_work);
>> >> >> >> > +
>> >> >> >> > +     lru_info = &hpb->lru_info;
>> >> >> >> > +
>> >> >> >> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
>> >> >> >> > +
>> >> >> >> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
>> >> >> >> > +             set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
>> >> >> >> > +
>> >> >> >> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
>> >> >> >> > +}
>> >> >> >> > +
>> >> >> >> >  static void ufshpb_normalization_work_handler(struct work_struct
>> >> >> >> > *work)
>> >> >> >> >  {
>> >> >> >> >       struct ufshpb_lu *hpb;
>> >> >> >> > @@ -1798,6 +1832,8 @@ static int ufshpb_alloc_region_tbl(struct
>> >> >> >> > ufs_hba *hba, struct ufshpb_lu *hpb)
>> >> >> >> >               } else {
>> >> >> >> >                       rgn->rgn_state = HPB_RGN_INACTIVE;
>> >> >> >> >               }
>> >> >> >> > +
>> >> >> >> > +             rgn->rgn_flags = 0;
>> >> >> >> >       }
>> >> >> >> >
>> >> >> >> >       return 0;
>> >> >> >> > @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct
>> >> ufs_hba
>> >> >> >> > *hba, struct ufshpb_lu *hpb)
>> >> >> >> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
>> >> >> >> >
>> >> >> >> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
>> >> >> >> > -     if (hpb->is_hcm)
>> >> >> >> > +     if (hpb->is_hcm) {
>> >> >> >> >               INIT_WORK(&hpb->ufshpb_normalization_work,
>> >> >> >> >                         ufshpb_normalization_work_handler);
>> >> >> >> > +             INIT_WORK(&hpb->ufshpb_lun_reset_work,
>> >> >> >> > +                       ufshpb_reset_work_handler);
>> >> >> >> > +     }
>> >> >> >> >
>> >> >> >> >       hpb->map_req_cache =
>> kmem_cache_create("ufshpb_req_cache",
>> >> >> >> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
>> >> >> >> > @@ -2114,8 +2153,10 @@ static void
>> ufshpb_discard_rsp_lists(struct
>> >> >> >> > ufshpb_lu *hpb)
>> >> >> >> >
>> >> >> >> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
>> >> >> >> >  {
>> >> >> >> > -     if (hpb->is_hcm)
>> >> >> >> > +     if (hpb->is_hcm) {
>> >> >> >> > +             cancel_work_sync(&hpb->ufshpb_lun_reset_work);
>> >> >> >> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
>> >> >> >> > +     }
>> >> >> >> >       cancel_work_sync(&hpb->map_work);
>> >> >> >> >  }
>> >> >> >> >
>> >> >> >> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
>> >> >> >> > index 84598a317897..37c1b0ea0c0a 100644
>> >> >> >> > --- a/drivers/scsi/ufs/ufshpb.h
>> >> >> >> > +++ b/drivers/scsi/ufs/ufshpb.h
>> >> >> >> > @@ -121,6 +121,7 @@ struct ufshpb_region {
>> >> >> >> >       struct list_head list_lru_rgn;
>> >> >> >> >       unsigned long rgn_flags;
>> >> >> >> >  #define RGN_FLAG_DIRTY 0
>> >> >> >> > +#define RGN_FLAG_UPDATE 1
>> >> >> >> >
>> >> >> >> >       /* region reads - for host mode */
>> >> >> >> >       spinlock_t rgn_lock;
>> >> >> >> > @@ -217,6 +218,7 @@ struct ufshpb_lu {
>> >> >> >> >       /* for selecting victim */
>> >> >> >> >       struct victim_select_info lru_info;
>> >> >> >> >       struct work_struct ufshpb_normalization_work;
>> >> >> >> > +     struct work_struct ufshpb_lun_reset_work;
>> >> >> >> >
>> >> >> >> >       /* pinned region information */
>> >> >> >> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* RE: [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response
  2021-03-18  1:00                   ` Can Guo
@ 2021-03-18  8:04                     ` Avri Altman
  0 siblings, 0 replies; 58+ messages in thread
From: Avri Altman @ 2021-03-18  8:04 UTC (permalink / raw)
  To: Can Guo
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, Bart Van Assche, yongmyung lee,
	Daejun Park, alim.akhtar, asutoshd, Zang Leigang,
	Avi Shchislowski, Bean Huo, stanley.chu

> On 2021-03-17 23:46, Avri Altman wrote:
> >> >> >> >>
> >> >> >> >> Just curious, directly doing below things inside ufshpb_rsp_upiu()
> >> >> >> >> does
> >> >> >> >> not
> >> >> >> >> seem a problem to me, does this really deserve a separate work?
> >> >> >> > I don't know, I never even consider of doing this.
> >> >> >> > The active region list may contain up to few thousands of regions -
> >> >> >> > It is not rare to see configurations that covers the entire device.
> >> >> >> >
> >> >> >>
> >> >> >> Yes, true, it can be a huge list. But what does the ops
> >> >> >> "HPB_RSP_DEV_RESET"
> >> >> >> really mean? The specs says "Device reset HPB Regions information",
> >> >> >> but
> >> >> >> I
> >> >> >> don't know what is really happening. Could you please elaborate?
> >> >> > It means that the device informs the host that the L2P cache is no
> >> >> > longer valid.
> >> >> > The spec doesn't say what to do in that case.
> >> >>
> >> >> Then it means that all the clean (without DIRTY flag set) HPB entries
> >> >> (ppns)
> >> >> in active rgns in host memory side may not be valid to the device
> >> >> anymore.
> >> >> Please correct me if I am wrong.
> >> >>
> >> >> > We thought that in host mode, it make sense to update all the active
> >> >> > regions.
> >> >>
> >> >> But current logic does not set the state of the sub-regions (in active
> >> >> regions) to
> >> >> INVALID, it only marks all active regions as UPDATE.
> >> >>
> >> >> Although one of subsequent read cmds shall put the sub-region back to
> >> >> activate_list,
> >> >> ufshpb_test_ppn_dirty() can still return false, thus these read cmds
> >> >> still think the
> >> >> ppns are valid and they shall move forward to send HPB Write Buffer
> >> >> (buffer id = 0x2,
> >> >> in case of HPB2.0) and HPB Read cmds.
> >> >>
> >> >> HPB Read cmds with invalid ppns will be treated as normal Read cmds by
> >> >> device as the
> >> >> specs says, but what would happen to HPB Write Buffer cmds (buffer id
> >> >> =
> >> >> 0x2, in case
> >> >> of HPB2.0) with invalid ppns? Can this be a real problem?
> >> > No need to control the ppn dirty / invalid state for this case.
> >> > The device send device reset so it is aware that all the L2P cache is
> >> > invalid.
> >> > Any HPB_READ is treated like normal READ10.
> >> >
> >> > Only once HPB-READ-BUFFER is completed,
> >> > the device will relate back to the physical address.
> >>
> >> What about HPB-WRITE-BUFFER (buffer id = 0x2) cmds?
> > Same.
> > Oper 0x2 is a relative simple case.
> > The device is expected to manage some versioning framework not to be
> > "fooled" by erroneous ppn.
> > There are some more challenging races that the device should meet.
> >
> 
> But I don't find the handling w.r.t this scenario on HPB2.0 specs -
> how would the device re-act/respond to HPB-WRITE-BUFFER cmds with
> invalid HPB entries? Could you please point me to relevant
> section/paragraph?
The spec does not handle that.
HPB-WRITE-BUFFER 0x2 is not a stand-alone command, it always tagged to a HPB-READ command.
It is up to the device to handle invalid ppn and always return the correct data.
The expected performance in that case is like a regular READ10.

Thanks,
Avri 

> 
> Thanks,
> Can Guo.
> 
> > Thanks,
> > Avri
> >>
> >> Thanks,
> >> Can Guo.
> >>
> >> >
> >> >>
> >> >> >
> >> >> > I think I will go with your suggestion.
> >> >> > Effectively, in host mode, since it is deactivating "cold" regions,
> >> >> > the lru list is kept relatively small, and contains only "hot" regions.
> >> >>
> >> >> hmm... I don't really have a idea on this, please go with whatever you
> >> >> and Daejun think is fine here.
> >> > I will take your advice and remove the worker.
> >> >
> >> >
> >> > Thanks,
> >> > Avri
> >> >
> >> >>
> >> >> Thanks,
> >> >> Can Guo.
> >> >>
> >> >> >
> >> >> > Thanks,
> >> >> > Avri
> >> >> >
> >> >> >>
> >> >> >> Thanks,
> >> >> >> Can Guo.
> >> >> >>
> >> >> >> > But yes, I can do that.
> >> >> >> > Better to get ack from Daejun first.
> >> >> >> >
> >> >> >> > Thanks,
> >> >> >> > Avri
> >> >> >> >
> >> >> >> >>
> >> >> >> >> Thanks,
> >> >> >> >> Can Guo.
> >> >> >> >>
> >> >> >> >> > +{
> >> >> >> >> > +     struct ufshpb_lu *hpb;
> >> >> >> >> > +     struct victim_select_info *lru_info;
> >> >> >> >> > +     struct ufshpb_region *rgn;
> >> >> >> >> > +     unsigned long flags;
> >> >> >> >> > +
> >> >> >> >> > +     hpb = container_of(work, struct ufshpb_lu,
> >> >> ufshpb_lun_reset_work);
> >> >> >> >> > +
> >> >> >> >> > +     lru_info = &hpb->lru_info;
> >> >> >> >> > +
> >> >> >> >> > +     spin_lock_irqsave(&hpb->rgn_state_lock, flags);
> >> >> >> >> > +
> >> >> >> >> > +     list_for_each_entry(rgn, &lru_info->lh_lru_rgn, list_lru_rgn)
> >> >> >> >> > +             set_bit(RGN_FLAG_UPDATE, &rgn->rgn_flags);
> >> >> >> >> > +
> >> >> >> >> > +     spin_unlock_irqrestore(&hpb->rgn_state_lock, flags);
> >> >> >> >> > +}
> >> >> >> >> > +
> >> >> >> >> >  static void ufshpb_normalization_work_handler(struct
> work_struct
> >> >> >> >> > *work)
> >> >> >> >> >  {
> >> >> >> >> >       struct ufshpb_lu *hpb;
> >> >> >> >> > @@ -1798,6 +1832,8 @@ static int
> ufshpb_alloc_region_tbl(struct
> >> >> >> >> > ufs_hba *hba, struct ufshpb_lu *hpb)
> >> >> >> >> >               } else {
> >> >> >> >> >                       rgn->rgn_state = HPB_RGN_INACTIVE;
> >> >> >> >> >               }
> >> >> >> >> > +
> >> >> >> >> > +             rgn->rgn_flags = 0;
> >> >> >> >> >       }
> >> >> >> >> >
> >> >> >> >> >       return 0;
> >> >> >> >> > @@ -2012,9 +2048,12 @@ static int ufshpb_lu_hpb_init(struct
> >> >> ufs_hba
> >> >> >> >> > *hba, struct ufshpb_lu *hpb)
> >> >> >> >> >       INIT_LIST_HEAD(&hpb->list_hpb_lu);
> >> >> >> >> >
> >> >> >> >> >       INIT_WORK(&hpb->map_work, ufshpb_map_work_handler);
> >> >> >> >> > -     if (hpb->is_hcm)
> >> >> >> >> > +     if (hpb->is_hcm) {
> >> >> >> >> >               INIT_WORK(&hpb->ufshpb_normalization_work,
> >> >> >> >> >                         ufshpb_normalization_work_handler);
> >> >> >> >> > +             INIT_WORK(&hpb->ufshpb_lun_reset_work,
> >> >> >> >> > +                       ufshpb_reset_work_handler);
> >> >> >> >> > +     }
> >> >> >> >> >
> >> >> >> >> >       hpb->map_req_cache =
> >> kmem_cache_create("ufshpb_req_cache",
> >> >> >> >> >                         sizeof(struct ufshpb_req), 0, 0, NULL);
> >> >> >> >> > @@ -2114,8 +2153,10 @@ static void
> >> ufshpb_discard_rsp_lists(struct
> >> >> >> >> > ufshpb_lu *hpb)
> >> >> >> >> >
> >> >> >> >> >  static void ufshpb_cancel_jobs(struct ufshpb_lu *hpb)
> >> >> >> >> >  {
> >> >> >> >> > -     if (hpb->is_hcm)
> >> >> >> >> > +     if (hpb->is_hcm) {
> >> >> >> >> > +             cancel_work_sync(&hpb->ufshpb_lun_reset_work);
> >> >> >> >> >               cancel_work_sync(&hpb->ufshpb_normalization_work);
> >> >> >> >> > +     }
> >> >> >> >> >       cancel_work_sync(&hpb->map_work);
> >> >> >> >> >  }
> >> >> >> >> >
> >> >> >> >> > diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
> >> >> >> >> > index 84598a317897..37c1b0ea0c0a 100644
> >> >> >> >> > --- a/drivers/scsi/ufs/ufshpb.h
> >> >> >> >> > +++ b/drivers/scsi/ufs/ufshpb.h
> >> >> >> >> > @@ -121,6 +121,7 @@ struct ufshpb_region {
> >> >> >> >> >       struct list_head list_lru_rgn;
> >> >> >> >> >       unsigned long rgn_flags;
> >> >> >> >> >  #define RGN_FLAG_DIRTY 0
> >> >> >> >> > +#define RGN_FLAG_UPDATE 1
> >> >> >> >> >
> >> >> >> >> >       /* region reads - for host mode */
> >> >> >> >> >       spinlock_t rgn_lock;
> >> >> >> >> > @@ -217,6 +218,7 @@ struct ufshpb_lu {
> >> >> >> >> >       /* for selecting victim */
> >> >> >> >> >       struct victim_select_info lru_info;
> >> >> >> >> >       struct work_struct ufshpb_normalization_work;
> >> >> >> >> > +     struct work_struct ufshpb_lun_reset_work;
> >> >> >> >> >
> >> >> >> >> >       /* pinned region information */
> >> >> >> >> >       u32 lu_pinned_start;

^ permalink raw reply	[flat|nested] 58+ messages in thread

* Re: [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer
  2021-03-17  7:55         ` Avri Altman
@ 2021-06-01 16:22           ` Bart Van Assche
  0 siblings, 0 replies; 58+ messages in thread
From: Bart Van Assche @ 2021-06-01 16:22 UTC (permalink / raw)
  To: Can Guo, Avri Altman
  Cc: James E . J . Bottomley, Martin K . Petersen, linux-scsi,
	linux-kernel, gregkh, yongmyung lee, Daejun Park, alim.akhtar,
	asutoshd, Zang Leigang, Avi Shchislowski, Bean Huo, stanley.chu

On 3/17/21 12:55 AM, Avri Altman wrote:
>> On 2021-03-16 17:21, Avri Altman wrote:
[ ... ]
>>>> And, which lock is protecting rgn->list_expired_rgn? If two
>>>> read_to_handler works
>>>> are running in parallel, one can be inserting it to its expired_list
>>>> while another
>>>> can be deleting it.
>>> The timeout handler, being a delayed work, is meant to run every
>>> polling period.
>>> Originally, I had it protected from 2 handlers running concurrently,
>>> But I removed it following Daejun's comment, which I accepted,
>>> Since it is always scheduled using the same polling period.
>>
>> But one can set the delay to 0 through sysfs, right?
>
> Will restore the protection.  Thanks.

(replying to an email from 2.5 months ago)

Hi Can,

How can two read_to_handler works run in parallel? How can it make a
difference whether or not the delay can be set to zero? Are you aware
that since kernel v3.7 (released in 2012) all workqueues are
non-reentrant? See also commit dbf2576e37da ("workqueue: make all
workqueues non-reentrant"). From the description of that commit:

    This patch makes all workqueues non-reentrant.  If a work item is
    executing on a different CPU when queueing is requested, it is
    always queued to that CPU.  This guarantees that any given work item
    can be executing on one CPU at maximum and if a work item is queued
    and executing, both are on the same CPU.

Thanks,

Bart.

^ permalink raw reply	[flat|nested] 58+ messages in thread

end of thread, other threads:[~2021-06-01 16:22 UTC | newest]

Thread overview: 58+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-03-02 13:24 [PATCH v5 00/10] Add Host control mode to HPB Avri Altman
2021-03-02 13:24 ` [PATCH v5 01/10] scsi: ufshpb: Cache HPB Control mode on init Avri Altman
2021-03-02 13:24 ` [PATCH v5 02/10] scsi: ufshpb: Add host control mode support to rsp_upiu Avri Altman
2021-03-02 13:24 ` [PATCH v5 03/10] scsi: ufshpb: Add region's reads counter Avri Altman
2021-03-11  7:52   ` Can Guo
2021-03-11  8:04     ` Avri Altman
2021-03-11  8:07       ` Can Guo
2021-03-15  3:16   ` Can Guo
2021-03-15  9:20     ` Avri Altman
2021-03-15  9:31       ` Can Guo
2021-03-17  9:19         ` Avri Altman
2021-03-15  8:40   ` Can Guo
2021-03-15  9:22     ` Avri Altman
2021-03-02 13:24 ` [PATCH v5 04/10] scsi: ufshpb: Make eviction depends on region's reads Avri Altman
2021-03-11  7:53   ` Can Guo
2021-03-11  8:06     ` Avri Altman
2021-03-15  8:30   ` Can Guo
2021-03-16  8:34     ` Avri Altman
2021-03-02 13:24 ` [PATCH v5 05/10] scsi: ufshpb: Region inactivation in host mode Avri Altman
2021-03-11  8:20   ` Can Guo
2021-03-11  9:03     ` Avri Altman
2021-03-15  4:02   ` Can Guo
2021-03-15  7:33     ` Can Guo
2021-03-16  8:30       ` Avri Altman
2021-03-17  1:23         ` Can Guo
     [not found]       ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p3>
2021-03-17  2:28         ` Daejun Park
2021-03-17  4:41           ` Can Guo
2021-03-17  7:59             ` Avri Altman
     [not found]           ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p4>
2021-03-17  5:19             ` Daejun Park
2021-03-17  5:34               ` Can Guo
     [not found]               ` <CGME20210316083014epcas2p32d6b84e689cdbe06ee065c870b236d65@epcms2p6>
2021-03-17  5:42                 ` Daejun Park
2021-03-02 13:24 ` [PATCH v5 06/10] scsi: ufshpb: Add hpb dev reset response Avri Altman
2021-03-15  1:34   ` Can Guo
2021-03-15  6:40     ` Can Guo
2021-03-15  7:42     ` Avri Altman
2021-03-17 10:56   ` Can Guo
2021-03-17 11:23     ` Avri Altman
2021-03-17 12:12       ` Can Guo
2021-03-17 12:22         ` Avri Altman
2021-03-17 13:50           ` Can Guo
2021-03-17 14:22             ` Avri Altman
2021-03-17 14:36               ` Can Guo
2021-03-17 15:46                 ` Avri Altman
2021-03-18  1:00                   ` Can Guo
2021-03-18  8:04                     ` Avri Altman
2021-03-02 13:25 ` [PATCH v5 07/10] scsi: ufshpb: Add "Cold" regions timer Avri Altman
2021-03-15  1:37   ` Can Guo
2021-03-15  7:54     ` Avri Altman
2021-03-15  9:36   ` Can Guo
2021-03-16  9:21     ` Avri Altman
2021-03-17  2:45       ` Can Guo
2021-03-17  7:55         ` Avri Altman
2021-06-01 16:22           ` Bart Van Assche
2021-03-02 13:25 ` [PATCH v5 08/10] scsi: ufshpb: Limit the number of inflight map requests Avri Altman
2021-03-15  8:31   ` Can Guo
2021-03-16  8:32     ` Avri Altman
2021-03-02 13:25 ` [PATCH v5 09/10] scsi: ufshpb: Add support for host control mode Avri Altman
2021-03-02 13:25 ` [PATCH v5 10/10] scsi: ufshpb: Make host mode parameters configurable Avri Altman

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).