RE: [RFC PATCH 3/5] scsi: ufs: Introduce HPB module

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



 
> 
> This is a patch for the HPB module.
> The HPB module queries UFS for device information during initialization.
> We added the export symbol to two functions in ufshcd.c to initialize
> the HPB module.
> 
> The HPB module can be loaded or built-in as needed.
> The memory pool size used in the HPB module is implemented as a module
> parameter, so that it can be configurable by the user.
Why not just allow for max-active-regions per the device's configuration?
The platform vendor can provision it per its need.


> +
> +static int ufshpb_alloc_region_tbl(struct ufs_hba *hba, struct ufshpb_lu
> *hpb)
> +{
> +       struct ufshpb_region *rgn_table, *rgn;
> +       struct ufshpb_subregion *srgn;
> +       int rgn_idx, srgn_idx, total_srgn_cnt, srgn_cnt, i;
> +       int ret = 0;
> +
> +       rgn_table = kvcalloc(hpb->rgns_per_lu, sizeof(struct ufshpb_region),
> +                           GFP_KERNEL);
> +       if (!rgn_table)
> +               return -ENOMEM;
> +
> +       hpb->rgn_tbl = rgn_table;
> +
> +       total_srgn_cnt = hpb->srgns_per_lu;
> +       for (rgn_idx = 0, srgn_cnt = 0; rgn_idx < hpb->rgns_per_lu;
> +            rgn_idx++, total_srgn_cnt -= srgn_cnt) {
Maybe simplify and improve readability by moving the srgn_cnt into the for clause:
	int srgn_cnt = hpb->srgns_per_rgn;

> +               rgn = rgn_table + rgn_idx;
> +               rgn->rgn_idx = rgn_idx;
> +
> +               srgn_cnt = min(total_srgn_cnt, hpb->srgns_per_rgn);
I guess you are carefully counting the sbregions because the spec allows the lun not to be subregion aligned.
So for any region but the last its hpb->srgns_per_rgn, and for the last one its:
	If (rgn_idx == hpb->rgns_per_lu - 1)
		srgn_cnt = ((hpb->srgns_per_lu - 1) % hpb->srgns_per_rgn) + 1;

> +
> +               ret = ufshpb_alloc_subregion_tbl(hpb, rgn, srgn_cnt);
> +               if (ret)
> +                       goto release_srgn_table;
> +               ufshpb_init_subregion_tbl(hpb, rgn);
> +
> +               rgn->rgn_state = HPB_RGN_INACTIVE;
> +               }
> +       }
> +
> +       if (total_srgn_cnt != 0) {
And you won't be needing this anymore

> +               dev_err(hba->dev, "ufshpb(%d) error total_subregion_count %d",
> +                       hpb->lun, total_srgn_cnt);
> +               goto release_srgn_table;
> +       }
> +
> +       return 0;
> +release_srgn_table:
> +       for (i = 0; i < rgn_idx; i++) {
> +               rgn = rgn_table + i;
> +               if (rgn->srgn_tbl)
> +                       kvfree(rgn->srgn_tbl);
> +       }
> +       kvfree(rgn_table);
> +       return ret;
> +}
> +
> +static void ufshpb_destroy_subregion_tbl(struct ufshpb_lu *hpb,
> +                                        struct ufshpb_region *rgn)
> +{
> +       int srgn_idx;
> +
> +       for (srgn_idx = 0; srgn_idx < rgn->srgn_cnt; srgn_idx++) {
> +               struct ufshpb_subregion *srgn;
> +
> +               srgn = rgn->srgn_tbl + srgn_idx;
> +               srgn->srgn_state = HPB_SRGN_UNUSED;
> +       }
> +}
> +
> +static void ufshpb_destroy_region_tbl(struct ufshpb_lu *hpb)
> +{
> +       int rgn_idx;
> +
> +       for (rgn_idx = 0; rgn_idx < hpb->rgns_per_lu; rgn_idx++) {
> +               struct ufshpb_region *rgn;
> +
> +               rgn = hpb->rgn_tbl + rgn_idx;
> +               if (rgn->rgn_state != HPB_RGN_INACTIVE) {
> +                       rgn->rgn_state = HPB_RGN_INACTIVE;
> +
> +                       ufshpb_destroy_subregion_tbl(hpb, rgn);
> +               }
> +
> +               kvfree(rgn->srgn_tbl);
This looks like it belongs to ufshpb_destroy_subregion_tbl?

> +       }
> +
> +       kvfree(hpb->rgn_tbl);
> +}
> +


> +static void ufshpb_issue_hpb_reset_query(struct ufs_hba *hba)

> +               return;
> +       }
> +       /* wait for the device to complete HPB reset query */
How about calling ufshpb_issue_hpb_reset_query right after ufshpb_get_dev_info?
This way waiting for the device to complete its reset can be done while scsi is scanning the luns?

> +
> +static void ufshpb_reset(struct ufs_hba *hba)
> +static void ufshpb_reset_host(struct ufs_hba *hba)
> +static void ufshpb_suspend(struct ufs_hba *hba)
> +static void ufshpb_resume(struct ufs_hba *hba)
The above 4 functions essentially runs the same code but set a different state.
Maybe call a helper?

> +static int ufshpb_create_sysfs(struct ufs_hba *hba, struct ufshpb_lu *hpb)
Why separate from ufs-sysfs?
Also you might want to introduce all the stats not as part of the functional patch.
> +
> +static int ufshpb_get_geo_info(struct ufs_hba *hba, u8 *geo_buf,
> +                              struct ufshpb_dev_info *hpb_dev_info)
> +{
> +       int hpb_device_max_active_rgns = 0;
> +       int hpb_num_lu;
> +
> +       hpb_dev_info->max_num_lun =
> +               geo_buf[GEOMETRY_DESC_PARAM_MAX_NUM_LUN] == 0x00 ? 8 :
> 32;
You already have this in hba->dev_info.max_lu_supported
> +
> +       hpb_num_lu = geo_buf[GEOMETRY_DESC_HPB_NUMBER_LU];
You should capture hpb_dev_info->max_num_lun = hpb_num_lu

> +       if (hpb_num_lu == 0) {
> +               dev_err(hba->dev, "No HPB LU supported\n");
> +               return -ENODEV;
> +       }
> +
> +       hpb_dev_info->rgn_size =
> geo_buf[GEOMETRY_DESC_HPB_REGION_SIZE];
> +       hpb_dev_info->srgn_size =
> geo_buf[GEOMETRY_DESC_HPB_SUBREGION_SIZE];
> +       hpb_device_max_active_rgns =
> +               get_unaligned_be16(geo_buf +
> +                       GEOMETRY_DESC_HPB_DEVICE_MAX_ACTIVE_REGIONS);
> +
> +       if (hpb_dev_info->rgn_size == 0 || hpb_dev_info->srgn_size == 0 ||
> +           hpb_device_max_active_rgns == 0) {
> +               dev_err(hba->dev, "No HPB supported device\n");
> +               return -ENODEV;
> +       }
> +
> +       return 0;
> +}
> +
> +static int ufshpb_get_dev_info(struct ufs_hba *hba,
> +                              struct ufshpb_dev_info *hpb_dev_info,
> +                              u8 *desc_buf)
> +{
> +       int ret;
> +
> +       ret = ufshpb_read_desc(hba, QUERY_DESC_IDN_DEVICE, 0, SELECTOR,
> +                            desc_buf, hba->desc_size.dev_desc);
What with this SELECTOR stuff?
Why not the default 0?

> +       if (ret) {
> +               dev_err(hba->dev, "%s: idn: %d query request failed\n",
> +                       __func__, QUERY_DESC_IDN_DEVICE);
> +               return -ENODEV;
> +       }
> +
> +       /*
> +        * Get the number of user logical unit to check whether all
> +        * scsi_device finish initialization
> +        */
> +       hpb_dev_info->num_lu = desc_buf[DEVICE_DESC_PARAM_NUM_LU];
What about the other hpb fields in the device descriptor:
DEVICE_DESC_PARAM_HPB_VER and DEVICE_DESC_PARAM_HPB_CONTROL ?

> +
> +       ret = ufshpb_read_desc(hba, QUERY_DESC_IDN_GEOMETRY, 0,
> SELECTOR,
> +                              desc_buf, hba->desc_size.geom_desc);
> +       if (ret) {
> +               dev_err(hba->dev, "%s: idn: %d query request failed\n",
> +                       __func__, QUERY_DESC_IDN_DEVICE);
> +               return ret;
> +       }
> +
> +       ret = ufshpb_get_geo_info(hba, desc_buf, hpb_dev_info);
> +       if (ret)
> +               return ret;
> +
> +       return 0;
> +}
> +
> +       hpb_lu_info->num_blocks = get_unaligned_be64(
> +                       desc_buf + UNIT_DESC_PARAM_LOGICAL_BLK_COUNT);
> +       hpb_lu_info->pinned_start = get_unaligned_be16(
> +                       desc_buf + UNIT_DESC_HPB_LU_PIN_REGION_START_OFFSET);
> +       hpb_lu_info->num_pinned = get_unaligned_be16(
> +                       desc_buf + UNIT_DESC_HPB_LU_NUM_PIN_REGIONS);
> +       hpb_lu_info->max_active_rgns = get_unaligned_be16(
> +                       desc_buf + UNIT_DESC_HPB_LU_MAX_ACTIVE_REGIONS);
You already have it, its max_active_rgns

> +
> +       return 0;
> +}
> +

> +unsigned int ufshpb_host_map_kbytes = 1 * 1024;
> +module_param(ufshpb_host_map_kbytes, uint, 0644);
> +MODULE_PARM_DESC(ufshpb_host_map_kbytes,
> +        "ufshpb host mapping memory kilo-bytes for ufshpb memory-pool");
You should introduce this module parameter in the patch that uses it.

> +
> +/**
> + * struct ufshpb_dev_info - UFSHPB device related info
> + * @max_num_lun: maximum number of logical unit that HPB is supported
> + * @num_ln: the number of user logical unit to check whether all lu finished
Typo num_lu


Thanks,
Avri




[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [SCSI Target Devel]     [Linux SCSI Target Infrastructure]     [Kernel Newbies]     [IDE]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux ATA RAID]     [Linux IIO]     [Samba]     [Device Mapper]

  Powered by Linux