FROMLIST: scsi: ufs: L2P map management for HPB read

This is a patch for managing L2P map in HPB module.

The HPB divides logical addresses into several regions. A region consists
of several sub-regions. The sub-region is a basic unit where L2P mapping is
managed. The driver loads L2P mapping data of each sub-region. The loaded
sub-region is called active-state. The HPB driver unloads L2P mapping data
as region unit. The unloaded region is called inactive-state.

Sub-region/region candidates to be loaded and unloaded are delivered from
the UFS device. The UFS device delivers the recommended active sub-region
and inactivate region to the driver using sensedata.
The HPB module performs L2P mapping management on the host through the
delivered information.

A pinned region is a pre-set regions on the UFS device that is always
activate-state.

The data structure for map data request and L2P map uses mempool API,
minimizing allocation overhead while avoiding static allocation.

The mininum size of the memory pool used in the HPB is implemented
as a module parameter, so that it can be configurable by the user.

To gurantee a minimum memory pool size of 4MB: ufshpb_host_map_kbytes=4096

The map_work manages active/inactive by 2 "to-do" lists.
Each hpb lun maintains 2 "to-do" lists:
  hpb->lh_inact_rgn - regions to be inactivated, and
  hpb->lh_act_srgn - subregions to be activated
Those lists are maintained on IO completion.

Bug: 183467926
Bug: 170940265
Bug: 183454255

Link: https://lore.kernel.org/linux-scsi/20210616070848epcms2p2819a1f0bf96cdcc357842fe8500af633@epcms2p2/

Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Can Guo <cang@codeaurora.org>
Reviewed-by: Bean Huo <beanhuo@micron.com>
Reviewed-by: Stanley Chu <stanley.chu@mediatek.com>
Acked-by: Avri Altman <Avri.Altman@wdc.com>
Tested-by: Bean Huo <beanhuo@micron.com>
Tested-by: Can Guo <cang@codeaurora.org>
Tested-by: Stanley Chu <stanley.chu@mediatek.com>
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
Change-Id: I1284f326332e2d6f2c1221e2d64160939614ad2d
This commit is contained in:
Daejun Park
2021-06-16 17:37:07 +09:00
committed by Todd Kjos
parent 791e1c6968
commit 466f620a31
4 changed files with 1178 additions and 15 deletions

View File

@@ -472,6 +472,41 @@ struct utp_cmd_rsp {
u8 sense_data[UFS_SENSE_SIZE];
};
struct ufshpb_active_field {
__be16 active_rgn;
__be16 active_srgn;
};
#define HPB_ACT_FIELD_SIZE 4
/**
* struct utp_hpb_rsp - Response UPIU structure
* @residual_transfer_count: Residual transfer count DW-3
* @reserved1: Reserved double words DW-4 to DW-7
* @sense_data_len: Sense data length DW-8 U16
* @desc_type: Descriptor type of sense data
* @additional_len: Additional length of sense data
* @hpb_op: HPB operation type
* @lun: LUN of response UPIU
* @active_rgn_cnt: Active region count
* @inactive_rgn_cnt: Inactive region count
* @hpb_active_field: Recommended to read HPB region and subregion
* @hpb_inactive_field: To be inactivated HPB region and subregion
*/
struct utp_hpb_rsp {
__be32 residual_transfer_count;
__be32 reserved1[4];
__be16 sense_data_len;
u8 desc_type;
u8 additional_len;
u8 hpb_op;
u8 lun;
u8 active_rgn_cnt;
u8 inactive_rgn_cnt;
struct ufshpb_active_field hpb_active_field[2];
__be16 hpb_inactive_field[2];
};
#define UTP_HPB_RSP_SIZE 40
/**
* struct utp_upiu_rsp - general upiu response structure
* @header: UPIU header structure DW-0 to DW-2
@@ -482,6 +517,7 @@ struct utp_upiu_rsp {
struct utp_upiu_header header;
union {
struct utp_cmd_rsp sr;
struct utp_hpb_rsp hr;
struct utp_upiu_query qr;
};
};

View File

@@ -5075,6 +5075,9 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
*/
pm_runtime_get_noresume(hba->dev);
}
if (scsi_status == SAM_STAT_GOOD)
ufshpb_rsp_upiu(hba, lrbp);
break;
case UPIU_TRANSACTION_REJECT_UPIU:
/* TODO: handle Reject UPIU Response */
@@ -9244,6 +9247,7 @@ EXPORT_SYMBOL(ufshcd_shutdown);
void ufshcd_remove(struct ufs_hba *hba)
{
ufs_bsg_remove(hba);
ufshpb_remove(hba);
ufs_sysfs_remove_nodes(hba->dev);
blk_cleanup_queue(hba->tmf_queue);
blk_mq_free_tag_set(&hba->tmf_tag_set);

File diff suppressed because it is too large Load Diff

View File

@@ -40,6 +40,7 @@
#define LU_ENABLED_HPB_FUNC 0x02
#define HPB_RESET_REQ_RETRIES 10
#define HPB_MAP_REQ_RETRIES 5
#define HPB_SUPPORT_VERSION 0x100
@@ -84,11 +85,19 @@ struct ufshpb_lu_info {
int max_active_rgns;
};
struct ufshpb_map_ctx {
struct page **m_page;
unsigned long *ppn_dirty;
};
struct ufshpb_subregion {
struct ufshpb_map_ctx *mctx;
enum HPB_SRGN_STATE srgn_state;
int rgn_idx;
int srgn_idx;
bool is_last;
/* below information is used by rsp_list */
struct list_head list_act_srgn;
};
struct ufshpb_region {
@@ -96,6 +105,43 @@ struct ufshpb_region {
enum HPB_RGN_STATE rgn_state;
int rgn_idx;
int srgn_cnt;
/* below information is used by rsp_list */
struct list_head list_inact_rgn;
/* below information is used by lru */
struct list_head list_lru_rgn;
};
#define for_each_sub_region(rgn, i, srgn) \
for ((i) = 0; \
((i) < (rgn)->srgn_cnt) && ((srgn) = &(rgn)->srgn_tbl[i]); \
(i)++)
/**
* struct ufshpb_req - UFSHPB READ BUFFER (for caching map) request structure
* @req: block layer request for READ BUFFER
* @bio: bio for holding map page
* @hpb: ufshpb_lu structure that related to the L2P map
* @mctx: L2P map information
* @rgn_idx: target region index
* @srgn_idx: target sub-region index
* @lun: target logical unit number
*/
struct ufshpb_req {
struct request *req;
struct bio *bio;
struct ufshpb_lu *hpb;
struct ufshpb_map_ctx *mctx;
unsigned int rgn_idx;
unsigned int srgn_idx;
};
struct victim_select_info {
struct list_head lh_lru_rgn; /* LRU list of regions */
int max_lru_active_cnt; /* supported hpb #region - pinned #region */
atomic_t active_cnt;
};
struct ufshpb_stats {
@@ -110,10 +156,22 @@ struct ufshpb_stats {
struct ufshpb_lu {
int lun;
struct scsi_device *sdev_ufs_lu;
spinlock_t rgn_state_lock; /* for protect rgn/srgn state */
struct ufshpb_region *rgn_tbl;
atomic_t hpb_state;
spinlock_t rsp_list_lock;
struct list_head lh_act_srgn; /* hold rsp_list_lock */
struct list_head lh_inact_rgn; /* hold rsp_list_lock */
/* cached L2P map management worker */
struct work_struct map_work;
/* for selecting victim */
struct victim_select_info lru_info;
/* pinned region information */
u32 lu_pinned_start;
u32 lu_pinned_end;
@@ -133,6 +191,9 @@ struct ufshpb_lu {
struct ufshpb_stats stats;
struct kmem_cache *map_req_cache;
struct kmem_cache *m_page_cache;
struct list_head list_hpb_lu;
};
@@ -140,6 +201,7 @@ struct ufs_hba;
struct ufshcd_lrb;
#ifndef CONFIG_SCSI_UFS_HPB
static void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) {}
static void ufshpb_resume(struct ufs_hba *hba) {}
static void ufshpb_suspend(struct ufs_hba *hba) {}
static void ufshpb_reset(struct ufs_hba *hba) {}
@@ -147,10 +209,12 @@ static void ufshpb_reset_host(struct ufs_hba *hba) {}
static void ufshpb_init(struct ufs_hba *hba) {}
static void ufshpb_init_hpb_lu(struct ufs_hba *hba, struct scsi_device *sdev) {}
static void ufshpb_destroy_lu(struct ufs_hba *hba, struct scsi_device *sdev) {}
static void ufshpb_remove(struct ufs_hba *hba) {}
static bool ufshpb_is_allowed(struct ufs_hba *hba) { return false; }
static void ufshpb_get_geo_info(struct ufs_hba *hba, u8 *geo_buf) {}
static void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf) {}
#else
void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp);
void ufshpb_resume(struct ufs_hba *hba);
void ufshpb_suspend(struct ufs_hba *hba);
void ufshpb_reset(struct ufs_hba *hba);
@@ -158,6 +222,7 @@ void ufshpb_reset_host(struct ufs_hba *hba);
void ufshpb_init(struct ufs_hba *hba);
void ufshpb_init_hpb_lu(struct ufs_hba *hba, struct scsi_device *sdev);
void ufshpb_destroy_lu(struct ufs_hba *hba, struct scsi_device *sdev);
void ufshpb_remove(struct ufs_hba *hba);
bool ufshpb_is_allowed(struct ufs_hba *hba);
void ufshpb_get_geo_info(struct ufs_hba *hba, u8 *geo_buf);
void ufshpb_get_dev_info(struct ufs_hba *hba, u8 *desc_buf);