From: Daejun Park <daejun7.park@samsung.com>
To: Daejun Park <daejun7.park@samsung.com>,
"avri.altman@wdc.com" <avri.altman@wdc.com>,
"jejb@linux.ibm.com" <jejb@linux.ibm.com>,
"martin.petersen@oracle.com" <martin.petersen@oracle.com>,
"asutoshd@codeaurora.org" <asutoshd@codeaurora.org>,
"beanhuo@micron.com" <beanhuo@micron.com>,
"stanley.chu@mediatek.com" <stanley.chu@mediatek.com>,
"cang@codeaurora.org" <cang@codeaurora.org>,
"bvanassche@acm.org" <bvanassche@acm.org>,
"tomas.winkler@intel.com" <tomas.winkler@intel.com>,
ALIM AKHTAR <alim.akhtar@samsung.com>
Cc: "linux-scsi@vger.kernel.org" <linux-scsi@vger.kernel.org>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
Sang-yoon Oh <sangyoon.oh@samsung.com>,
Sung-Jun Park <sungjun07.park@samsung.com>,
yongmyung lee <ymhungry.lee@samsung.com>,
Jinyoung CHOI <j-young.choi@samsung.com>,
Adel Choi <adel.choi@samsung.com>,
BoRam Shin <boram.shin@samsung.com>
Subject: [PATCH v9 4/4] scsi: ufs: Prepare HPB read for cached sub-region
Date: Fri, 28 Aug 2020 16:19:44 +0900 [thread overview]
Message-ID: <717176949.41598601302683.JavaMail.epsvc@epcpadp1> (raw)
In-Reply-To: <963815509.21598598782155.JavaMail.epsvc@epcpadp2>
This patch changes the read I/O to the HPB read I/O.
If the logical address of the read I/O belongs to active sub-region, the
HPB driver modifies the read I/O command to HPB read. It modifies the UPIU
command of UFS instead of modifying the existing SCSI command.
In the HPB version 1.0, the maximum read I/O size that can be converted to
HPB read is 4KB.
The dirty map of the active sub-region prevents an incorrect HPB read that
has stale physical page number which is updated by previous write I/O.
Acked-by: Avri Altman <Avri.Altman@wdc.com>
Tested-by: Bean Huo <beanhuo@micron.com>
Signed-off-by: Daejun Park <daejun7.park@samsung.com>
---
drivers/scsi/ufs/ufshpb.c | 231 ++++++++++++++++++++++++++++++++++++++
1 file changed, 231 insertions(+)
diff --git a/drivers/scsi/ufs/ufshpb.c b/drivers/scsi/ufs/ufshpb.c
index cd1a1a77ced9..9b4f7fc41dc4 100644
--- a/drivers/scsi/ufs/ufshpb.c
+++ b/drivers/scsi/ufs/ufshpb.c
@@ -33,6 +33,29 @@ bool ufshpb_is_allowed(struct ufs_hba *hba)
return !(hba->ufshpb_dev.hpb_disabled);
}
+static int ufshpb_is_valid_srgn(struct ufshpb_region *rgn,
+ struct ufshpb_subregion *srgn)
+{
+ return rgn->rgn_state != HPB_RGN_INACTIVE &&
+ srgn->srgn_state == HPB_SRGN_VALID;
+}
+
+static bool ufshpb_is_read_cmd(struct scsi_cmnd *cmd)
+{
+ return req_op(cmd->request) == REQ_OP_READ;
+}
+
+static bool ufshpb_is_write_discard_cmd(struct scsi_cmnd *cmd)
+{
+ return op_is_write(req_op(cmd->request)) ||
+ op_is_discard(req_op(cmd->request));
+}
+
+static bool ufshpb_is_support_chunk(int transfer_len)
+{
+ return transfer_len <= HPB_MULTI_CHUNK_HIGH;
+}
+
static bool ufshpb_is_general_lun(int lun)
{
return lun < UFS_UPIU_MAX_UNIT_NUM_ID;
@@ -99,8 +122,216 @@ static void ufshpb_set_state(struct ufshpb_lu *hpb, int state)
atomic_set(&hpb->hpb_state, state);
}
+static void ufshpb_set_ppn_dirty(struct ufshpb_lu *hpb, int rgn_idx,
+ int srgn_idx, int srgn_offset, int cnt)
+{
+ struct ufshpb_region *rgn;
+ struct ufshpb_subregion *srgn;
+ int set_bit_len;
+ int bitmap_len = hpb->entries_per_srgn;
+
+next_srgn:
+ rgn = hpb->rgn_tbl + rgn_idx;
+ srgn = rgn->srgn_tbl + srgn_idx;
+
+ if ((srgn_offset + cnt) > bitmap_len)
+ set_bit_len = bitmap_len - srgn_offset;
+ else
+ set_bit_len = cnt;
+
+ if (rgn->rgn_state != HPB_RGN_INACTIVE &&
+ srgn->srgn_state == HPB_SRGN_VALID)
+ bitmap_set(srgn->mctx->ppn_dirty, srgn_offset, set_bit_len);
+
+ srgn_offset = 0;
+ if (++srgn_idx == hpb->srgns_per_rgn) {
+ srgn_idx = 0;
+ rgn_idx++;
+ }
+
+ cnt -= set_bit_len;
+ if (cnt > 0)
+ goto next_srgn;
+
+ WARN_ON(cnt < 0);
+}
+
+static bool ufshpb_test_ppn_dirty(struct ufshpb_lu *hpb, int rgn_idx,
+ int srgn_idx, int srgn_offset, int cnt)
+{
+ struct ufshpb_region *rgn;
+ struct ufshpb_subregion *srgn;
+ int bitmap_len = hpb->entries_per_srgn;
+ int bit_len;
+
+next_srgn:
+ rgn = hpb->rgn_tbl + rgn_idx;
+ srgn = rgn->srgn_tbl + srgn_idx;
+
+ if (!ufshpb_is_valid_srgn(rgn, srgn))
+ return true;
+
+ /*
+ * If the region state is active, mctx must be allocated.
+ * In this case, check whether the region is evicted or
+ * mctx allcation fail.
+ */
+ WARN_ON(!srgn->mctx);
+
+ if ((srgn_offset + cnt) > bitmap_len)
+ bit_len = bitmap_len - srgn_offset;
+ else
+ bit_len = cnt;
+
+ if (find_next_bit(srgn->mctx->ppn_dirty,
+ bit_len, srgn_offset) >= srgn_offset)
+ return true;
+
+ srgn_offset = 0;
+ if (++srgn_idx == hpb->srgns_per_rgn) {
+ srgn_idx = 0;
+ rgn_idx++;
+ }
+
+ cnt -= bit_len;
+ if (cnt > 0)
+ goto next_srgn;
+
+ return false;
+}
+
+static u64 ufshpb_get_ppn(struct ufshpb_lu *hpb,
+ struct ufshpb_map_ctx *mctx, int pos, int *error)
+{
+ u64 *ppn_table;
+ struct page *page;
+ int index, offset;
+
+ index = pos / (PAGE_SIZE / HPB_ENTRY_SIZE);
+ offset = pos % (PAGE_SIZE / HPB_ENTRY_SIZE);
+
+ page = mctx->m_page[index];
+ if (unlikely(!page)) {
+ *error = -ENOMEM;
+ dev_err(&hpb->sdev_ufs_lu->sdev_dev,
+ "error. cannot find page in mctx\n");
+ return 0;
+ }
+
+ ppn_table = page_address(page);
+ if (unlikely(!ppn_table)) {
+ *error = -ENOMEM;
+ dev_err(&hpb->sdev_ufs_lu->sdev_dev,
+ "error. cannot get ppn_table\n");
+ return 0;
+ }
+
+ return ppn_table[offset];
+}
+
+static void
+ufshpb_get_pos_from_lpn(struct ufshpb_lu *hpb, unsigned long lpn, int *rgn_idx,
+ int *srgn_idx, int *offset)
+{
+ int rgn_offset;
+
+ *rgn_idx = lpn >> hpb->entries_per_rgn_shift;
+ rgn_offset = lpn & hpb->entries_per_rgn_mask;
+ *srgn_idx = rgn_offset >> hpb->entries_per_srgn_shift;
+ *offset = rgn_offset & hpb->entries_per_srgn_mask;
+}
+
+static void
+ufshpb_set_hpb_read_to_upiu(struct ufshpb_lu *hpb, struct ufshcd_lrb *lrbp,
+ u32 lpn, u64 ppn, unsigned int transfer_len)
+{
+ unsigned char *cdb = lrbp->ucd_req_ptr->sc.cdb;
+
+ cdb[0] = UFSHPB_READ;
+
+ put_unaligned_be64(ppn, &cdb[6]);
+ cdb[14] = transfer_len;
+}
+
+/*
+ * This function will set up HPB read command using host-side L2P map data.
+ * In HPB v1.0, maximum size of HPB read command is 4KB.
+ */
void ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp)
{
+ struct ufshpb_lu *hpb;
+ struct ufshpb_region *rgn;
+ struct ufshpb_subregion *srgn;
+ struct scsi_cmnd *cmd = lrbp->cmd;
+ u32 lpn;
+ u64 ppn;
+ unsigned long flags;
+ int transfer_len, rgn_idx, srgn_idx, srgn_offset;
+ int err = 0;
+
+ hpb = ufshpb_get_hpb_data(cmd);
+ if (!hpb)
+ return;
+
+ if (ufshpb_get_state(hpb) != HPB_PRESENT) {
+ dev_notice(&hpb->sdev_ufs_lu->sdev_dev,
+ "%s: ufshpb state is not PRESENT", __func__);
+ return;
+ }
+
+ WARN_ON(hpb->lun != cmd->device->lun);
+ if (!ufshpb_is_write_discard_cmd(cmd) &&
+ !ufshpb_is_read_cmd(cmd))
+ return;
+
+ transfer_len = sectors_to_logical(cmd->device, blk_rq_sectors(cmd->request));
+ if (unlikely(!transfer_len))
+ return;
+
+ lpn = sectors_to_logical(cmd->device, blk_rq_pos(cmd->request));
+ ufshpb_get_pos_from_lpn(hpb, lpn, &rgn_idx, &srgn_idx, &srgn_offset);
+ rgn = hpb->rgn_tbl + rgn_idx;
+ srgn = rgn->srgn_tbl + srgn_idx;
+
+ /* If command type is WRITE or DISCARD, set bitmap as drity */
+ if (ufshpb_is_write_discard_cmd(cmd)) {
+ spin_lock_irqsave(&hpb->hpb_state_lock, flags);
+ ufshpb_set_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
+ transfer_len);
+ spin_unlock_irqrestore(&hpb->hpb_state_lock, flags);
+ return;
+ }
+
+ WARN_ON(!ufshpb_is_read_cmd(cmd));
+
+ if (!ufshpb_is_support_chunk(transfer_len))
+ return;
+
+ spin_lock_irqsave(&hpb->hpb_state_lock, flags);
+ if (ufshpb_test_ppn_dirty(hpb, rgn_idx, srgn_idx, srgn_offset,
+ transfer_len)) {
+ atomic_inc(&hpb->stats.miss_cnt);
+ spin_unlock_irqrestore(&hpb->hpb_state_lock, flags);
+ return;
+ }
+
+ ppn = ufshpb_get_ppn(hpb, srgn->mctx, srgn_offset, &err);
+ spin_unlock_irqrestore(&hpb->hpb_state_lock, flags);
+ if (unlikely(err)) {
+ /*
+ * In this case, the region state is active,
+ * but the ppn table is not allocated.
+ * Make sure that ppn table must be allocated on
+ * active state.
+ */
+ WARN_ON(true);
+ dev_err(hba->dev, "ufshpb_get_ppn failed. err %d\n", err);
+ return;
+ }
+
+ ufshpb_set_hpb_read_to_upiu(hpb, lrbp, lpn, ppn, transfer_len);
+
+ atomic_inc(&hpb->stats.hit_cnt);
}
static struct ufshpb_req *ufshpb_get_map_req(struct ufshpb_lu *hpb,
--
2.17.1
next prev parent reply other threads:[~2020-08-28 7:55 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <CGME20200828070950epcms2p5470bd43374be18d184dd802da09e73c8@epcms2p5>
2020-08-28 7:09 ` [PATCH v9 0/4] scsi: ufs: Add Host Performance Booster Support Daejun Park
2020-08-28 7:17 ` [PATCH v9 1/4] scsi: ufs: Add HPB feature related parameters Daejun Park
2020-08-29 23:11 ` Bart Van Assche
2020-08-28 7:18 ` [PATCH v9 2/4] scsi: ufs: Introduce HPB feature Daejun Park
2020-08-29 22:58 ` Bart Van Assche
2020-09-01 0:24 ` Daejun Park
2020-08-28 7:19 ` [PATCH v9 3/4] scsi: ufs: L2P map management for HPB read Daejun Park
2020-08-29 23:48 ` Bart Van Assche
2020-09-01 0:21 ` Daejun Park
2020-08-28 7:19 ` Daejun Park [this message]
2020-08-29 23:54 ` [PATCH v9 4/4] scsi: ufs: Prepare HPB read for cached sub-region Bart Van Assche
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=717176949.41598601302683.JavaMail.epsvc@epcpadp1 \
--to=daejun7.park@samsung.com \
--cc=adel.choi@samsung.com \
--cc=alim.akhtar@samsung.com \
--cc=asutoshd@codeaurora.org \
--cc=avri.altman@wdc.com \
--cc=beanhuo@micron.com \
--cc=boram.shin@samsung.com \
--cc=bvanassche@acm.org \
--cc=cang@codeaurora.org \
--cc=j-young.choi@samsung.com \
--cc=jejb@linux.ibm.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-scsi@vger.kernel.org \
--cc=martin.petersen@oracle.com \
--cc=sangyoon.oh@samsung.com \
--cc=stanley.chu@mediatek.com \
--cc=sungjun07.park@samsung.com \
--cc=tomas.winkler@intel.com \
--cc=ymhungry.lee@samsung.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox