[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <2154d9c6-4b29-7d24-0261-26d2aa05caef@acm.org>
Date: Sat, 8 Aug 2020 17:07:41 -0700
From: Bart Van Assche <bvanassche@....org>
To: daejun7.park@...sung.com,
"avri.altman@....com" <avri.altman@....com>,
"jejb@...ux.ibm.com" <jejb@...ux.ibm.com>,
"martin.petersen@...cle.com" <martin.petersen@...cle.com>,
"asutoshd@...eaurora.org" <asutoshd@...eaurora.org>,
"beanhuo@...ron.com" <beanhuo@...ron.com>,
"stanley.chu@...iatek.com" <stanley.chu@...iatek.com>,
"cang@...eaurora.org" <cang@...eaurora.org>,
"tomas.winkler@...el.com" <tomas.winkler@...el.com>,
ALIM AKHTAR <alim.akhtar@...sung.com>
Cc: "linux-scsi@...r.kernel.org" <linux-scsi@...r.kernel.org>,
"linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
Sang-yoon Oh <sangyoon.oh@...sung.com>,
Sung-Jun Park <sungjun07.park@...sung.com>,
yongmyung lee <ymhungry.lee@...sung.com>,
Jinyoung CHOI <j-young.choi@...sung.com>,
Adel Choi <adel.choi@...sung.com>,
BoRam Shin <boram.shin@...sung.com>
Subject: Re: [PATCH v8 2/4] scsi: ufs: Introduce HPB feature
On 2020-08-06 02:11, Daejun Park wrote:
> This is a patch for the HPB feature.
> This patch adds HPB function calls to UFS core driver.
>
> The mininum size of the memory pool used in the HPB is implemented as a
^^^^^^^
minimum?
> Kconfig parameter (SCSI_UFS_HPB_HOST_MEM), so that it can be configurable.
> +config SCSI_UFS_HPB
> + bool "Support UFS Host Performance Booster"
> + depends on SCSI_UFSHCD
> + help
> + A UFS HPB Feature improves random read performance. It caches
^ ^^^^^^^
The? feature?
> + L2P map of UFS to host DRAM. The driver uses HPB read command
> + by piggybacking physical page number for bypassing FTL's L2P address
> + translation.
Please explain what L2P and FTL mean. Not everyone is familiar with SSD
internals.
> +config SCSI_UFS_HPB_HOST_MEM
> + int "Host-side cached memory size (KB) for HPB support"
> + default 32
> + depends on SCSI_UFS_HPB
> + help
> + The mininum size of the memory pool used in the HPB module. It can
> + be configurable by the user. If this value is larger than required
> + memory size, kernel resizes cached memory size.
^^^^^^^ ^^^^^^^^^^^^^^^^^^
reduces? cache size?
Please make this a kernel module parameter instead of a compile-time constant.
> +#ifndef CONFIG_SCSI_UFS_HPB
> +static void ufshpb_resume(struct ufs_hba *hba) {}
> +static void ufshpb_suspend(struct ufs_hba *hba) {}
> +static void ufshpb_reset(struct ufs_hba *hba) {}
> +static void ufshpb_reset_host(struct ufs_hba *hba) {}
> +static void ufshpb_rsp_upiu(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) {}
> +static void ufshpb_prep(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) {}
> +static void ufshpb_remove(struct ufs_hba *hba) {}
> +static void ufshpb_scan_feature(struct ufs_hba *hba) {}
> +#endif
Please move these definitions into ufshpb.h since that is the
recommended Linux kernel coding style.
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index b2ef18f1b746..904c19796e09 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -47,6 +47,9 @@
> #include "ufs.h"
> #include "ufs_quirks.h"
> #include "ufshci.h"
> +#ifdef CONFIG_SCSI_UFS_HPB
> +#include "ufshpb.h"
> +#endif
Please move #ifdef CONFIG_SCSI_UFS_HPB / #endif into ufshpb.h. From
Documentation/process/4.Coding.rst: "As a general rule, #ifdef use
should be confined to header files whenever possible."
> +struct ufsf_feature_info {
> + atomic_t slave_conf_cnt;
> + wait_queue_head_t sdev_wait;
> +};
Please add a comment above this data structure that explains the role
of this data structure and also what "ufsf" stands for.
> +static int ufshpb_create_sysfs(struct ufs_hba *hba, struct ufshpb_lu *hpb);
I don't think that this forward declaration is necessary so please leave it
out.
> +static inline 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;
> +}
Please do not declare functions inside .c files inline but instead let
the compiler decide which functions to inline. Modern compilers are really
good at this.
> +static struct kobj_type ufshpb_ktype = {
> + .sysfs_ops = &ufshpb_sysfs_ops,
> + .release = NULL,
> +};
If the release method of a kobj_type is NULL that is a strong sign that
there is something wrong ...
> +static int ufshpb_create_sysfs(struct ufs_hba *hba, struct ufshpb_lu *hpb)
> +{
> + int ret;
> +
> + ufshpb_stat_init(hpb);
> +
> + kobject_init(&hpb->kobj, &ufshpb_ktype);
> + mutex_init(&hpb->sysfs_lock);
> +
> + ret = kobject_add(&hpb->kobj, kobject_get(&hba->dev->kobj),
> + "ufshpb_lu%d", hpb->lun);
> +
> + if (ret)
> + return ret;
> +
> + ret = sysfs_create_group(&hpb->kobj, &ufshpb_sysfs_group);
> +
> + if (ret) {
> + dev_err(hba->dev, "ufshpb_lu%d create file error\n", hpb->lun);
> + return ret;
> + }
> +
> + dev_info(hba->dev, "ufshpb_lu%d sysfs adds uevent", hpb->lun);
> + kobject_uevent(&hpb->kobj, KOBJ_ADD);
> +
> + return 0;
> +}
Please attach these sysfs attributes to /sys/class/scsi_device/*/device
instead of creating a new kobject. Consider using the following
scsi_host_template member to define LUN sysfs attributes:
/*
* Pointer to the SCSI device attribute groups for this host,
* NULL terminated.
*/
const struct attribute_group **sdev_groups;
> +static void ufshpb_scan_hpb_lu(struct ufs_hba *hba,
> + struct ufshpb_dev_info *hpb_dev_info,
> + u8 *desc_buf)
> +{
> + struct scsi_device *sdev;
> + struct ufshpb_lu *hpb;
> + int find_hpb_lu = 0;
> + int ret;
> +
> + shost_for_each_device(sdev, hba->host) {
> + struct ufshpb_lu_info hpb_lu_info = { 0 };
> + int lun = sdev->lun;
> +
> + if (lun >= hba->dev_info.max_lu_supported)
> + continue;
> +
> + ret = ufshpb_get_lu_info(hba, lun, &hpb_lu_info, desc_buf);
> + if (ret)
> + continue;
> +
> + hpb = ufshpb_alloc_hpb_lu(hba, lun, hpb_dev_info,
> + &hpb_lu_info);
> + if (!hpb)
> + continue;
> +
> + hpb->sdev_ufs_lu = sdev;
> + sdev->hostdata = hpb;
> +
> + list_add_tail(&hpb->list_hpb_lu, &lh_hpb_lu);
> + find_hpb_lu++;
> + }
> +
> + if (!find_hpb_lu)
> + return;
> +
> + ufshpb_check_hpb_reset_query(hba);
> +
> + list_for_each_entry(hpb, &lh_hpb_lu, list_hpb_lu) {
> + dev_info(hba->dev, "set state to present\n");
> + ufshpb_set_state(hpb, HPB_PRESENT);
> + }
> +}
Please remove the loop from the above function, make this function accept a
SCSI device pointer as argument and call this function from
ufshcd_slave_configure() or ufshcd_hpb_configure().
> +static void ufshpb_init(void *data, async_cookie_t cookie)
> +{
> + struct ufsf_feature_info *ufsf = (struct ufsf_feature_info *)data;
> + struct ufs_hba *hba;
> + struct ufshpb_dev_info hpb_dev_info = { 0 };
> + char *desc_buf;
> + int ret;
> +
> + hba = container_of(ufsf, struct ufs_hba, ufsf);
> +
> + desc_buf = kzalloc(QUERY_DESC_MAX_SIZE, GFP_KERNEL);
> + if (!desc_buf)
> + goto release_desc_buf;
> +
> + ret = ufshpb_get_dev_info(hba, &hpb_dev_info, desc_buf);
> + if (ret)
> + goto release_desc_buf;
> +
> + /*
> + * Because HPB driver uses scsi_device data structure,
> + * we should wait at this point until finishing initialization of all
> + * scsi devices. Even if timeout occurs, HPB driver will search
> + * the scsi_device list on struct scsi_host (shost->__host list_head)
> + * and can find out HPB logical units in all scsi_devices
> + */
> + wait_event_timeout(hba->ufsf.sdev_wait,
> + (atomic_read(&hba->ufsf.slave_conf_cnt)
> + == hpb_dev_info.num_lu),
> + SDEV_WAIT_TIMEOUT);
> +
> + ufshpb_issue_hpb_reset_query(hba);
> +
> + dev_dbg(hba->dev, "ufshpb: slave count %d, lu count %d\n",
> + atomic_read(&hba->ufsf.slave_conf_cnt), hpb_dev_info.num_lu);
> +
> + ufshpb_scan_hpb_lu(hba, &hpb_dev_info, desc_buf);
> +
> +release_desc_buf:
> + kfree(desc_buf);
> +}
Since the UFS driver calls scsi_scan_host() from ufshcd_add_lus(), do you
agree that the above wait_event_timeout() call can be eliminated by splitting
ufshpb_init() into two functions and by calling the part below
wait_event_timeout() after scsi_scan_host() has finished?
> +void ufshpb_remove(struct ufs_hba *hba)
> +{
> + struct ufshpb_lu *hpb, *n_hpb;
> + struct ufsf_feature_info *ufsf;
> + struct scsi_device *sdev;
> +
> + ufsf = &hba->ufsf;
> +
> + list_for_each_entry_safe(hpb, n_hpb, &lh_hpb_lu, list_hpb_lu) {
> + ufshpb_set_state(hpb, HPB_FAILED);
> +
> + sdev = hpb->sdev_ufs_lu;
> + sdev->hostdata = NULL;
> +
> + ufshpb_destroy_region_tbl(hpb);
> +
> + list_del_init(&hpb->list_hpb_lu);
> + ufshpb_remove_sysfs(hpb);
> +
> + kfree(hpb);
> + }
> +
> + dev_info(hba->dev, "ufshpb: remove success\n");
> +}
Should the code in the body of the above loop perhaps be called from inside
ufshcd_slave_destroy()?
> +void ufshpb_scan_feature(struct ufs_hba *hba)
> +{
> + init_waitqueue_head(&hba->ufsf.sdev_wait);
> + atomic_set(&hba->ufsf.slave_conf_cnt, 0);
> +
> + if (hba->dev_info.wspecversion >= HPB_SUPPORT_VERSION &&
> + (hba->dev_info.b_ufs_feature_sup & UFS_DEV_HPB_SUPPORT))
> + async_schedule(ufshpb_init, &hba->ufsf);
> +}
Why does this function use async_schedule()?
Thanks,
Bart.
Powered by blists - more mailing lists