@@ -29,6 +29,19 @@ struct ufs_dev_fix {
unsigned int quirk;
};
+enum dev_val_type {
+ DEV_VAL_FDEVICEINIT = 0x0,
+ DEV_VAL_NUM,
+};
+
+struct ufs_dev_value {
+ u16 wmanufacturerid;
+ u8 *model;
+ u32 key;
+ u32 val;
+ bool enable;
+};
+
#define END_FIX { }
/* add specific device quirk */
@@ -38,6 +51,13 @@ struct ufs_dev_fix {
.quirk = (_quirk), \
}
+#define UFS_DEV_VAL(_vendor, _model, _key, _val) { \
+ .wmanufacturerid = (_vendor),\
+ .model = (_model), \
+ .key = (_key), \
+ .val = (_val), \
+}
+
/*
* Some vendor's UFS device sends back to back NACs for the DL data frames
* causing the host controller to raise the DFES error status. Sometimes
@@ -207,6 +207,21 @@ static struct ufs_dev_fix ufs_fixups[] = {
END_FIX
};
+static struct ufs_dev_value ufs_dev_values[] = {
+ END_FIX
+};
+
+static inline bool
+ufs_get_dev_specific_value(struct ufs_hba *hba,
+ enum dev_val_type type, u32 *val)
+{
+ if (!ufs_dev_values[type].enable)
+ return false;
+
+ *val = hba->dev_value[type];
+ return true;
+}
+
static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba);
static void ufshcd_async_scan(void *data, async_cookie_t cookie);
static int ufshcd_reset_and_restore(struct ufs_hba *hba);
@@ -6923,11 +6938,34 @@ void ufshcd_fixup_dev_quirks(struct ufs_hba *hba, struct ufs_dev_fix *fixups)
}
EXPORT_SYMBOL_GPL(ufshcd_fixup_dev_quirks);
+void ufshcd_set_dev_values(struct ufs_hba *hba, struct ufs_dev_value *value)
+{
+ struct ufs_dev_value *f;
+ struct ufs_dev_info *dev_info = &hba->dev_info;
+
+ if (!value)
+ return;
+
+ for (f = value; f->val; f++) {
+ if ((f->wmanufacturerid == dev_info->wmanufacturerid ||
+ f->wmanufacturerid == UFS_ANY_VENDOR) &&
+ ((dev_info->model &&
+ STR_PRFX_EQUAL(f->model, dev_info->model)) ||
+ !strcmp(f->model, UFS_ANY_MODEL))) {
+ f->enable = true;
+ hba->dev_value[f->key] = f->val;
+ }
+ }
+}
+EXPORT_SYMBOL_GPL(ufshcd_set_dev_values);
+
static void ufs_fixup_device_setup(struct ufs_hba *hba)
{
/* fix by general quirk table */
ufshcd_fixup_dev_quirks(hba, ufs_fixups);
+ ufshcd_set_dev_values(hba, ufs_dev_values);
+
/* allow vendors to fix quirks */
ufshcd_vops_fixup_dev_quirks(hba);
}
@@ -670,6 +670,7 @@ struct ufs_hba {
/* Device deviations from standard UFS device spec. */
unsigned int dev_quirks;
+ u32 dev_value[DEV_VAL_NUM];
struct blk_mq_tag_set tmf_tag_set;
struct request_queue *tmf_queue;
Respective UFS devices have their own characteristics and many of them could be a form of numbers, such as timeout and a number of retires. This introduces the way to set those things per specific device vendor or specific device. I wrote this like the style of ufs_fixups stuffs. Signed-off-by: Kiwoong Kim <kwmad.kim@samsung.com> --- drivers/scsi/ufs/ufs_quirks.h | 20 ++++++++++++++++++++ drivers/scsi/ufs/ufshcd.c | 38 ++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufshcd.h | 1 + 3 files changed, 59 insertions(+)