scsi: ufs: seperate device and host quirks
Currently we use the host quirks mechanism in order to handle both device and host controller quirks. In order to support many UFS devices we should separate handling the device quirks from the host controller's. Change-Id: I6c23be42ff78689f9aad4d5c0c9f0a678bfb5c14 Signed-off-by: Raviv Shvili <rshvili@codeaurora.org> [venkatg@codeaurora.org: resolved trivial merge conflicts] Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
This commit is contained in:
parent
125fc97a4f
commit
61df89e001
6 changed files with 177 additions and 1 deletions
|
@ -1,6 +1,6 @@
|
|||
# UFSHCD makefile
|
||||
obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
|
||||
obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
|
||||
obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o ufs_quirks.o
|
||||
obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
|
||||
obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
|
||||
obj-$(CONFIG_SCSI_UFS_TEST) += ufs_test.o
|
||||
|
|
|
@ -178,6 +178,36 @@ enum unit_desc_param {
|
|||
UNIT_DESC_PARAM_LARGE_UNIT_SIZE_M1 = 0x22,
|
||||
};
|
||||
|
||||
/* Device descriptor parameters offsets in bytes*/
|
||||
enum device_desc_param {
|
||||
DEVICE_DESC_PARAM_LEN = 0x0,
|
||||
DEVICE_DESC_PARAM_TYPE = 0x1,
|
||||
DEVICE_DESC_PARAM_DEVICE_TYPE = 0x2,
|
||||
DEVICE_DESC_PARAM_DEVICE_CLASS = 0x3,
|
||||
DEVICE_DESC_PARAM_DEVICE_SUB_CLASS = 0x4,
|
||||
DEVICE_DESC_PARAM_PRTCL = 0x5,
|
||||
DEVICE_DESC_PARAM_NUM_LU = 0x6,
|
||||
DEVICE_DESC_PARAM_NUM_WLU = 0x7,
|
||||
DEVICE_DESC_PARAM_BOOT_ENBL = 0x8,
|
||||
DEVICE_DESC_PARAM_DESC_ACCSS_ENBL = 0x9,
|
||||
DEVICE_DESC_PARAM_INIT_PWR_MODE = 0xA,
|
||||
DEVICE_DESC_PARAM_HIGH_PR_LUN = 0xB,
|
||||
DEVICE_DESC_PARAM_SEC_RMV_TYPE = 0xC,
|
||||
DEVICE_DESC_PARAM_SEC_LU = 0xD,
|
||||
DEVICE_DESC_PARAM_BKOP_TERM_LT = 0xE,
|
||||
DEVICE_DESC_PARAM_ACTVE_ICC_LVL = 0xF,
|
||||
DEVICE_DESC_PARAM_SPEC_VER = 0x10,
|
||||
DEVICE_DESC_PARAM_MANF_DATE = 0x12,
|
||||
DEVICE_DESC_PARAM_MANF_NAME = 0x14,
|
||||
DEVICE_DESC_PARAM_PRDCT_NAME = 0x15,
|
||||
DEVICE_DESC_PARAM_SN = 0x16,
|
||||
DEVICE_DESC_PARAM_OEM_ID = 0x17,
|
||||
DEVICE_DESC_PARAM_MANF_ID = 0x18,
|
||||
DEVICE_DESC_PARAM_UD_OFFSET = 0x1A,
|
||||
DEVICE_DESC_PARAM_UD_LEN = 0x1B,
|
||||
DEVICE_DESC_PARAM_RTT_CAP = 0x1C,
|
||||
DEVICE_DESC_PARAM_FRQ_RTC = 0x1D,
|
||||
};
|
||||
/*
|
||||
* Logical Unit Write Protect
|
||||
* 00h: LU not write protected
|
||||
|
|
78
drivers/scsi/ufs/ufs_quirks.c
Normal file
78
drivers/scsi/ufs/ufs_quirks.c
Normal file
|
@ -0,0 +1,78 @@
|
|||
/* Copyright (c) 2014, 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
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "ufshcd.h"
|
||||
#include "ufs_quirks.h"
|
||||
|
||||
|
||||
static struct ufs_card_fix ufs_fixups[] = {
|
||||
/* UFS cards deviations table */
|
||||
END_FIX
|
||||
};
|
||||
|
||||
int ufs_get_device_info(struct ufs_hba *hba, struct ufs_card_info *card_data)
|
||||
{
|
||||
int err;
|
||||
u8 model_index;
|
||||
u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE];
|
||||
u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE];
|
||||
|
||||
err = ufshcd_read_device_desc(hba, desc_buf,
|
||||
QUERY_DESC_DEVICE_MAX_SIZE);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
card_data->vendor = 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);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
strlcpy(card_data->model, str_desc_buf, MAX_MODEL_LEN + 1);
|
||||
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.vendor = 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;
|
||||
}
|
||||
|
||||
for (f = ufs_fixups; f->quirk; f++) {
|
||||
/* if same vendor */
|
||||
if (((f->card.vendor == card_data.vendor) ||
|
||||
(f->card.vendor == UFS_ANY_VENDOR)) &&
|
||||
/* and same model */
|
||||
(STR_PRFX_EQUAL(f->card.model, card_data.model) ||
|
||||
!strcmp(f->card.model, UFS_ANY_MODEL)))
|
||||
/* update quirks */
|
||||
hba->dev_quirks |= f->quirk;
|
||||
}
|
||||
out:
|
||||
kfree(card_data.model);
|
||||
}
|
62
drivers/scsi/ufs/ufs_quirks.h
Normal file
62
drivers/scsi/ufs/ufs_quirks.h
Normal file
|
@ -0,0 +1,62 @@
|
|||
/* Copyright (c) 2014, 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
|
||||
* only version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _UFS_QUIRKS_H_
|
||||
#define _UFS_QUIRKS_H_
|
||||
|
||||
/* return true if s1 is a prefix of s2 */
|
||||
#define STR_PRFX_EQUAL(s1, s2) !strncmp(s1, s2, strlen(s1))
|
||||
|
||||
#define UFS_ANY_VENDOR -1
|
||||
#define UFS_ANY_MODEL "ANY_MODEL"
|
||||
|
||||
#define MAX_MODEL_LEN 16
|
||||
|
||||
#define UFS_VENDOR_TOSHIBA 0x98
|
||||
/* UFS TOSHIBA MODELS */
|
||||
#define UFS_MODEL_TOSHIBA_32GB "THGLF2G8D4KBADR"
|
||||
#define UFS_MODEL_TOSHIBA_64GB "THGLF2G9D8KBADG"
|
||||
|
||||
/**
|
||||
* ufs_card_info - ufs device details
|
||||
* @vendor: card details
|
||||
* @model: card model
|
||||
*/
|
||||
struct ufs_card_info {
|
||||
unsigned int vendor;
|
||||
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;
|
||||
unsigned int quirk;
|
||||
};
|
||||
|
||||
#define END_FIX { { 0 } , 0 }
|
||||
|
||||
/* add specific device quirk */
|
||||
#define UFS_FIX(_vendor, _model, _quirk) \
|
||||
{ \
|
||||
.card.vendor = (_vendor),\
|
||||
.card.model = (_model), \
|
||||
.quirk = (_quirk), \
|
||||
}
|
||||
|
||||
struct ufs_hba;
|
||||
void ufs_advertise_fixup_device(struct ufs_hba *hba);
|
||||
#endif /* UFS_QUIRKS_H_ */
|
|
@ -4770,6 +4770,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
|
|||
if (ret)
|
||||
goto out;
|
||||
|
||||
ufs_advertise_fixup_device(hba);
|
||||
|
||||
if (!hba->is_init_prefetch) {
|
||||
ret = ufshcd_get_device_ref_clk(hba);
|
||||
if (ret) {
|
||||
|
|
|
@ -68,6 +68,7 @@
|
|||
|
||||
#include "ufs.h"
|
||||
#include "ufshci.h"
|
||||
#include "ufs_quirks.h"
|
||||
|
||||
#define UFSHCD "ufshcd"
|
||||
#define UFSHCD_DRIVER_VERSION "0.2"
|
||||
|
@ -531,6 +532,9 @@ struct ufs_hba {
|
|||
|
||||
unsigned int quirks; /* Deviations from standard UFSHCI spec. */
|
||||
|
||||
/* Device deviations from standard UFS device spec. */
|
||||
unsigned int dev_quirks;
|
||||
|
||||
/* Interrupt aggregation support is broken */
|
||||
#define UFSHCD_QUIRK_BROKEN_INTR_AGGR (1<<0)
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue