There are some limitations to activations / inactivations in host
control mode - Add those.

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

diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index 183bdf35f2d0..5fa1f5bc08e6 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -140,6 +140,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);
@@ -201,6 +203,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 u64 ufshpb_get_ppn(struct ufshpb_lu *hpb,
                          struct ufshpb_map_ctx *mctx, int pos, int *error)
 {
@@ -380,8 +387,12 @@ 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;
+
        WARN_ON(!srgn->mctx);
        bitmap_zero(srgn->mctx->ppn_dirty, hpb->entries_per_srgn);
+       rgn = hpb->rgn_tbl + srgn->rgn_idx;
+       clear_bit(RGN_FLAG_DIRTY, &rgn->rgn_flags);
        return 0;
 }
 
@@ -814,17 +825,39 @@ static void ufshpb_rsp_req_region_update(struct ufshpb_lu 
*hpb,
         */
        spin_lock(&hpb->rsp_list_lock);
        for (i = 0; i < rsp_field->active_rgn_cnt; i++) {
+               struct ufshpb_region *rgn;
+
                rgn_idx =
                        be16_to_cpu(rsp_field->hpb_active_field[i].active_rgn);
                srgn_idx =
                        be16_to_cpu(rsp_field->hpb_active_field[i].active_srgn);
 
+               rgn = hpb->rgn_tbl + rgn_idx;
+               if (ufshpb_mode == HPB_HOST_CONTROL &&
+                   (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_idx, srgn_idx);
                ufshpb_update_active_info(hpb, rgn_idx, srgn_idx);
                hpb->stats.rb_active_cnt++;
        }
 
+       if (ufshpb_mode == HPB_HOST_CONTROL) {
+               /*
+                * in host control mode the device is not allowed to inactivate
+                * regions
+                */
+               goto out_unlock;
+       }
+
        for (i = 0; i < rsp_field->inactive_rgn_cnt; i++) {
                rgn_idx = be16_to_cpu(rsp_field->hpb_inactive_field[i]);
                dev_dbg(&hpb->sdev_ufs_lu->sdev_dev,
@@ -832,6 +865,8 @@ static void ufshpb_rsp_req_region_update(struct ufshpb_lu 
*hpb,
                ufshpb_update_inactive_info(hpb, rgn_idx);
                hpb->stats.rb_inactive_cnt++;
        }
+
+out_unlock:
        spin_unlock(&hpb->rsp_list_lock);
 
        dev_dbg(&hpb->sdev_ufs_lu->sdev_dev, "Noti: #ACT %u #INACT %u\n",
diff --git a/drivers/scsi/ufs/ufshpb.h b/drivers/scsi/ufs/ufshpb.h
index 2c43a03b66b6..8a34b0f42754 100644
--- a/drivers/scsi/ufs/ufshpb.h
+++ b/drivers/scsi/ufs/ufshpb.h
@@ -48,6 +48,11 @@ enum UFSHPB_MODE {
        HPB_DEVICE_CONTROL,
 };
 
+enum HPB_RGN_FLAGS {
+       RGN_FLAG_UPDATE = 0,
+       RGN_FLAG_DIRTY,
+};
+
 enum UFSHPB_STATE {
        HPB_PRESENT = 1,
        HPB_SUSPEND,
@@ -109,6 +114,7 @@ struct ufshpb_region {
 
        /* below information is used by lru */
        struct list_head list_lru_rgn;
+       unsigned long rgn_flags;
 };
 
 #define for_each_sub_region(rgn, i, srgn)                              \
-- 
2.25.1

Reply via email to