[PATCH 4/8] scsi: ufshpb: Make eviction depends on region's reads

Avri Altman
2021-01-27T15:15:37Z

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 | 44 ++++++++++++++++++++++++++++++++++++---
1 file changed, 41 insertions(+), 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index 51c3607166bc..a16c0f2d5fac 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -18,6 +18,7 @@

#define WORK_PENDING 0
#define ACTIVATION_THRSHLD 4 /* 4 IOs */
+#define EVICTION_THRSHLD (ACTIVATION_THRSHLD << 6) /* 256 IOs */

/* memory management */
static struct kmem_cache *ufshpb_mctx_cache;
@@ -639,6 +640,14 @@ 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 (ufshpb_mode == HPB_HOST_CONTROL &&
+ atomic64_read(&rgn->reads) > (EVICTION_THRSHLD >> 1))
+ continue;
+
victim_rgn = rgn;
break;
}
@@ -789,7 +798,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;
@@ -817,6 +826,17 @@ 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 (ufshpb_mode == HPB_HOST_CONTROL &&
+ atomic64_read(&rgn->reads) < EVICTION_THRSHLD) {
+ ret = -EACCES;
+ goto out;
+ }
+
victim_rgn = ufshpb_victim_lru_info(hpb);
if (!victim_rgn) {
dev_warn(&hpb->sdev_ufs_lu->sdev_dev,
@@ -1024,8 +1044,13 @@ static void ufshpb_run_active_subregion_list(struct ufshpb_lu *hpb)

rgn = hpb->rgn_tbl + srgn->rgn_idx;
ret = ufshpb_add_region(hpb, rgn);
- if (ret)
- goto active_failed;
+ if (ret) {
+ if (ret == -EACCES) {
+ spin_lock_irqsave(&hpb->rsp_list_lock, flags);
+ continue;
+ }
+ goto add_region_failed;
+ }

ret = ufshpb_issue_map_req(hpb, rgn, srgn);
if (ret) {
@@ -1039,9 +1064,22 @@ static void ufshpb_run_active_subregion_list(struct ufshpb_lu *hpb)
spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
return;

+add_region_failed:
+ if (ufshpb_mode == HPB_HOST_CONTROL) {
+ /*
+ * In host control mode, it is common that eviction trials
+ * fail, either because the entering region didn't have enough
+ * reads, or a poor-performing exiting region wasn't found.
+ * No need to re-insert those regions to the "to-be-activated"
+ * list.
+ */
+ return;
+ }
+
active_failed:
dev_err(&hpb->sdev_ufs_lu->sdev_dev, "failed to activate region %d - %d, will retry\n",
rgn->rgn_idx, srgn->srgn_idx);
+
spin_lock_irqsave(&hpb->rsp_list_lock, flags);
ufshpb_add_active_list(hpb, rgn, srgn);
spin_unlock_irqrestore(&hpb->rsp_list_lock, flags);
--
2.25.1