Loading drivers/scsi/ufs/ufs.h +7 −0 Original line number Diff line number Diff line Loading @@ -495,7 +495,14 @@ struct ufs_vreg_info { }; struct ufs_dev_info { /* device descriptor info */ u8 b_device_sub_class; u16 w_manufacturer_id; u8 i_product_name; /* query flags */ bool f_power_on_wp_en; /* Keeps information if any of the LU is power on write protected */ bool is_lu_power_on_wp; }; Loading drivers/scsi/ufs/ufs_quirks.c +16 −48 Original line number Diff line number Diff line /* * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -34,73 +34,41 @@ static struct ufs_card_fix ufs_fixups[] = { END_FIX }; static int ufs_get_device_info(struct ufs_hba *hba, struct ufs_card_info *card_data) void ufs_advertise_fixup_device(struct ufs_hba *hba) { int err; u8 model_index; u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1]; u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; char *model; struct ufs_card_fix *f; err = ufshcd_read_device_desc(hba, desc_buf, QUERY_DESC_DEVICE_MAX_SIZE); if (err) model = kmalloc(MAX_MODEL_LEN + 1, GFP_KERNEL); if (!model) goto out; /* * getting vendor (manufacturerID) and Bank Index in big endian * format */ card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE); err = ufshcd_read_string_desc(hba, model_index, str_desc_buf, QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); err = ufshcd_read_string_desc(hba, hba->dev_info.i_product_name, str_desc_buf, QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); if (err) goto out; str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), strlcpy(model, (str_desc_buf + QUERY_DESC_HDR_SIZE), min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], MAX_MODEL_LEN)); /* Null terminate the model string */ card_data->model[MAX_MODEL_LEN] = '\0'; out: return err; } void ufs_advertise_fixup_device(struct ufs_hba *hba) { int err; struct ufs_card_fix *f; struct ufs_card_info card_data; card_data.wmanufacturerid = 0; card_data.model = kmalloc(MAX_MODEL_LEN + 1, GFP_KERNEL); if (!card_data.model) goto out; /* get device data*/ err = ufs_get_device_info(hba, &card_data); if (err) { dev_err(hba->dev, "%s: Failed getting device info\n", __func__); goto out; } model[MAX_MODEL_LEN] = '\0'; for (f = ufs_fixups; f->quirk; f++) { /* if same wmanufacturerid */ if (((f->card.wmanufacturerid == card_data.wmanufacturerid) || (f->card.wmanufacturerid == UFS_ANY_VENDOR)) && if (((f->w_manufacturer_id == hba->dev_info.w_manufacturer_id) || (f->w_manufacturer_id == UFS_ANY_VENDOR)) && /* and same model */ (STR_PRFX_EQUAL(f->card.model, card_data.model) || !strcmp(f->card.model, UFS_ANY_MODEL))) (STR_PRFX_EQUAL(f->model, model) || !strcmp(f->model, UFS_ANY_MODEL))) /* update quirks */ hba->dev_quirks |= f->quirk; } out: kfree(card_data.model); kfree(model); } drivers/scsi/ufs/ufs_quirks.h +6 −15 Original line number Diff line number Diff line /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -30,33 +30,24 @@ #define UFS_MODEL_TOSHIBA_32GB "THGLF2G8D4KBADR" #define UFS_MODEL_TOSHIBA_64GB "THGLF2G9D8KBADG" /** * ufs_card_info - ufs device details * @wmanufacturerid: card details * @model: card model */ struct ufs_card_info { u16 wmanufacturerid; char *model; }; /** * ufs_card_fix - ufs device quirk info * @card: ufs card details * @quirk: device quirk */ struct ufs_card_fix { struct ufs_card_info card; u16 w_manufacturer_id; char *model; unsigned int quirk; }; #define END_FIX { { 0 } , 0 } #define END_FIX { 0 } /* add specific device quirk */ #define UFS_FIX(_vendor, _model, _quirk) \ { \ .card.wmanufacturerid = (_vendor),\ .card.model = (_model), \ .w_manufacturer_id = (_vendor),\ .model = (_model), \ .quirk = (_quirk), \ } Loading drivers/scsi/ufs/ufshcd.c +28 −0 Original line number Diff line number Diff line Loading @@ -6895,6 +6895,29 @@ static int ufshcd_set_dev_ref_clk(struct ufs_hba *hba) return err; } static int ufs_read_device_desc_data(struct ufs_hba *hba) { int err; u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; err = ufshcd_read_device_desc(hba, desc_buf, sizeof(desc_buf)); if (err) return err; /* * getting vendor (manufacturerID) and Bank Index in big endian * format */ hba->dev_info.w_manufacturer_id = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; hba->dev_info.b_device_sub_class = desc_buf[DEVICE_DESC_PARAM_DEVICE_SUB_CLASS]; hba->dev_info.i_product_name = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; return 0; } /** * ufshcd_probe_hba - probe hba to detect device and initialize * @hba: per-adapter instance Loading Loading @@ -6932,6 +6955,11 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out; /* cache important parameters from device descriptor for later use */ ret = ufs_read_device_desc_data(hba); if (ret) goto out; ufs_advertise_fixup_device(hba); ufshcd_tune_unipro_params(hba); Loading Loading
drivers/scsi/ufs/ufs.h +7 −0 Original line number Diff line number Diff line Loading @@ -495,7 +495,14 @@ struct ufs_vreg_info { }; struct ufs_dev_info { /* device descriptor info */ u8 b_device_sub_class; u16 w_manufacturer_id; u8 i_product_name; /* query flags */ bool f_power_on_wp_en; /* Keeps information if any of the LU is power on write protected */ bool is_lu_power_on_wp; }; Loading
drivers/scsi/ufs/ufs_quirks.c +16 −48 Original line number Diff line number Diff line /* * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved. * Copyright (c) 2013-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -34,73 +34,41 @@ static struct ufs_card_fix ufs_fixups[] = { END_FIX }; static int ufs_get_device_info(struct ufs_hba *hba, struct ufs_card_info *card_data) void ufs_advertise_fixup_device(struct ufs_hba *hba) { int err; u8 model_index; u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1]; u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; char *model; struct ufs_card_fix *f; err = ufshcd_read_device_desc(hba, desc_buf, QUERY_DESC_DEVICE_MAX_SIZE); if (err) model = kmalloc(MAX_MODEL_LEN + 1, GFP_KERNEL); if (!model) goto out; /* * getting vendor (manufacturerID) and Bank Index in big endian * format */ card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE); err = ufshcd_read_string_desc(hba, model_index, str_desc_buf, QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); err = ufshcd_read_string_desc(hba, hba->dev_info.i_product_name, str_desc_buf, QUERY_DESC_STRING_MAX_SIZE, ASCII_STD); if (err) goto out; str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0'; strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE), strlcpy(model, (str_desc_buf + QUERY_DESC_HDR_SIZE), min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET], MAX_MODEL_LEN)); /* Null terminate the model string */ card_data->model[MAX_MODEL_LEN] = '\0'; out: return err; } void ufs_advertise_fixup_device(struct ufs_hba *hba) { int err; struct ufs_card_fix *f; struct ufs_card_info card_data; card_data.wmanufacturerid = 0; card_data.model = kmalloc(MAX_MODEL_LEN + 1, GFP_KERNEL); if (!card_data.model) goto out; /* get device data*/ err = ufs_get_device_info(hba, &card_data); if (err) { dev_err(hba->dev, "%s: Failed getting device info\n", __func__); goto out; } model[MAX_MODEL_LEN] = '\0'; for (f = ufs_fixups; f->quirk; f++) { /* if same wmanufacturerid */ if (((f->card.wmanufacturerid == card_data.wmanufacturerid) || (f->card.wmanufacturerid == UFS_ANY_VENDOR)) && if (((f->w_manufacturer_id == hba->dev_info.w_manufacturer_id) || (f->w_manufacturer_id == UFS_ANY_VENDOR)) && /* and same model */ (STR_PRFX_EQUAL(f->card.model, card_data.model) || !strcmp(f->card.model, UFS_ANY_MODEL))) (STR_PRFX_EQUAL(f->model, model) || !strcmp(f->model, UFS_ANY_MODEL))) /* update quirks */ hba->dev_quirks |= f->quirk; } out: kfree(card_data.model); kfree(model); }
drivers/scsi/ufs/ufs_quirks.h +6 −15 Original line number Diff line number Diff line /* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved. /* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and Loading Loading @@ -30,33 +30,24 @@ #define UFS_MODEL_TOSHIBA_32GB "THGLF2G8D4KBADR" #define UFS_MODEL_TOSHIBA_64GB "THGLF2G9D8KBADG" /** * ufs_card_info - ufs device details * @wmanufacturerid: card details * @model: card model */ struct ufs_card_info { u16 wmanufacturerid; char *model; }; /** * ufs_card_fix - ufs device quirk info * @card: ufs card details * @quirk: device quirk */ struct ufs_card_fix { struct ufs_card_info card; u16 w_manufacturer_id; char *model; unsigned int quirk; }; #define END_FIX { { 0 } , 0 } #define END_FIX { 0 } /* add specific device quirk */ #define UFS_FIX(_vendor, _model, _quirk) \ { \ .card.wmanufacturerid = (_vendor),\ .card.model = (_model), \ .w_manufacturer_id = (_vendor),\ .model = (_model), \ .quirk = (_quirk), \ } Loading
drivers/scsi/ufs/ufshcd.c +28 −0 Original line number Diff line number Diff line Loading @@ -6895,6 +6895,29 @@ static int ufshcd_set_dev_ref_clk(struct ufs_hba *hba) return err; } static int ufs_read_device_desc_data(struct ufs_hba *hba) { int err; u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE]; err = ufshcd_read_device_desc(hba, desc_buf, sizeof(desc_buf)); if (err) return err; /* * getting vendor (manufacturerID) and Bank Index in big endian * format */ hba->dev_info.w_manufacturer_id = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 | desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]; hba->dev_info.b_device_sub_class = desc_buf[DEVICE_DESC_PARAM_DEVICE_SUB_CLASS]; hba->dev_info.i_product_name = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME]; return 0; } /** * ufshcd_probe_hba - probe hba to detect device and initialize * @hba: per-adapter instance Loading Loading @@ -6932,6 +6955,11 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) if (ret) goto out; /* cache important parameters from device descriptor for later use */ ret = ufs_read_device_desc_data(hba); if (ret) goto out; ufs_advertise_fixup_device(hba); ufshcd_tune_unipro_params(hba); Loading