Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b590e789 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "scsi: ufs: Factor out ufshcd_read_desc_param"

parents e42f2fbf 833ea2a4
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -850,8 +850,8 @@ static const struct file_operations ufsdbg_host_regs_fops = {
static int ufsdbg_dump_device_desc_show(struct seq_file *file, void *data)
{
	int err = 0;
	int buff_len = QUERY_DESC_DEVICE_MAX_SIZE;
	u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE];
	int buff_len = QUERY_DESC_DEVICE_DEF_SIZE;
	u8 desc_buf[QUERY_DESC_DEVICE_DEF_SIZE];
	struct ufs_hba *hba = (struct ufs_hba *)file->private;

	struct desc_field_offset device_desc_field_name[] = {
+8 −13
Original line number Diff line number Diff line
@@ -65,6 +65,7 @@
#define UFS_MAX_LUNS		(SCSI_W_LUN_BASE + UFS_UPIU_MAX_UNIT_NUM_ID)
#define UFS_UPIU_WLUN_ID	(1 << 7)
#define UFS_UPIU_MAX_GENERAL_LUN	8
#define QUERY_DESC_IDN_CONFIGURATION	QUERY_DESC_IDN_CONFIGURAION

/* Well known logical unit id in LUN field of UPIU */
enum {
@@ -144,19 +145,13 @@ enum desc_header_offset {
	QUERY_DESC_DESC_TYPE_OFFSET	= 0x01,
};

enum ufs_desc_max_size {
	QUERY_DESC_DEVICE_MAX_SIZE		= 0x40,
	QUERY_DESC_CONFIGURAION_MAX_SIZE	= 0x90,
	QUERY_DESC_UNIT_MAX_SIZE		= 0x23,
	QUERY_DESC_INTERCONNECT_MAX_SIZE	= 0x06,
	/*
	 * Max. 126 UNICODE characters (2 bytes per character) plus 2 bytes
	 * of descriptor header.
	 */
	QUERY_DESC_STRING_MAX_SIZE		= 0xFE,
	QUERY_DESC_GEOMETRY_MAZ_SIZE		= 0x44,
	QUERY_DESC_POWER_MAX_SIZE		= 0x62,
	QUERY_DESC_RFU_MAX_SIZE			= 0x00,
enum ufs_desc_def_size {
	QUERY_DESC_DEVICE_DEF_SIZE		= 0x40,
	QUERY_DESC_CONFIGURATION_DEF_SIZE	= 0x90,
	QUERY_DESC_UNIT_DEF_SIZE		= 0x23,
	QUERY_DESC_INTERCONNECT_DEF_SIZE	= 0x06,
	QUERY_DESC_GEOMETRY_DEF_SIZE		= 0x44,
	QUERY_DESC_POWER_DEF_SIZE		= 0x62,
};

/* Unit descriptor parameters offsets in bytes*/
+4 −4
Original line number Diff line number Diff line
@@ -51,7 +51,7 @@ static struct ufs_card_fix ufs_fixups[] = {
void ufs_advertise_fixup_device(struct ufs_hba *hba)
{
	int err;
	u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1];
	u8 str_desc_buf[QUERY_DESC_MAX_SIZE + 1];
	char *model;
	struct ufs_card_fix *f;

@@ -59,13 +59,13 @@ void ufs_advertise_fixup_device(struct ufs_hba *hba)
	if (!model)
		goto out;

	memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE);
	memset(str_desc_buf, 0, QUERY_DESC_MAX_SIZE);
	err = ufshcd_read_string_desc(hba, hba->dev_info.i_product_name,
			str_desc_buf, QUERY_DESC_STRING_MAX_SIZE, ASCII_STD);
			str_desc_buf, QUERY_DESC_MAX_SIZE, ASCII_STD);
	if (err)
		goto out;

	str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0';
	str_desc_buf[QUERY_DESC_MAX_SIZE] = '\0';
	strlcpy(model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
		min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET],
		      MAX_MODEL_LEN));
+2 −2
Original line number Diff line number Diff line
@@ -603,8 +603,8 @@ static void ufs_test_random_async_query(void *data, async_cookie_t cookie)
	struct ufs_test_data *utd = test_iosched->blk_dev_test_data;
	struct scsi_device *sdev;
	struct ufs_hba *hba;
	int buff_len = QUERY_DESC_UNIT_MAX_SIZE;
	u8 desc_buf[QUERY_DESC_UNIT_MAX_SIZE];
	int buff_len = QUERY_DESC_UNIT_DEF_SIZE;
	u8 desc_buf[QUERY_DESC_UNIT_DEF_SIZE];
	bool flag;
	u32 att;
	int ret = 0;
+186 −53
Original line number Diff line number Diff line
@@ -251,19 +251,6 @@ static void ufshcd_hex_dump(struct ufs_hba *hba, const char * const str,
		       16, 4, buf, len, false);
}

static u32 ufs_query_desc_max_size[] = {
	QUERY_DESC_DEVICE_MAX_SIZE,
	QUERY_DESC_CONFIGURAION_MAX_SIZE,
	QUERY_DESC_UNIT_MAX_SIZE,
	QUERY_DESC_RFU_MAX_SIZE,
	QUERY_DESC_INTERCONNECT_MAX_SIZE,
	QUERY_DESC_STRING_MAX_SIZE,
	QUERY_DESC_RFU_MAX_SIZE,
	QUERY_DESC_GEOMETRY_MAZ_SIZE,
	QUERY_DESC_POWER_MAX_SIZE,
	QUERY_DESC_RFU_MAX_SIZE,
};

enum {
	UFSHCD_MAX_CHANNEL	= 0,
	UFSHCD_MAX_ID		= 1,
@@ -3628,7 +3615,7 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba,
		goto out;
	}

	if (*buf_len <= QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) {
	if (*buf_len < QUERY_DESC_MIN_SIZE || *buf_len > QUERY_DESC_MAX_SIZE) {
		dev_err(hba->dev, "%s: descriptor buffer size (%d) is out of range\n",
				__func__, *buf_len);
		err = -EINVAL;
@@ -3707,6 +3694,92 @@ int ufshcd_query_descriptor(struct ufs_hba *hba,
}
EXPORT_SYMBOL(ufshcd_query_descriptor);

/**
 * ufshcd_read_desc_length - read the specified descriptor length from header
 * @hba: Pointer to adapter instance
 * @desc_id: descriptor idn value
 * @desc_index: descriptor index
 * @desc_length: pointer to variable to read the length of descriptor
 *
 * Return 0 in case of success, non-zero otherwise
 */
static int ufshcd_read_desc_length(struct ufs_hba *hba,
	enum desc_idn desc_id,
	int desc_index,
	int *desc_length)
{
	int ret;
	u8 header[QUERY_DESC_HDR_SIZE];
	int header_len = QUERY_DESC_HDR_SIZE;

	if (desc_id >= QUERY_DESC_IDN_MAX)
		return -EINVAL;

	ret = ufshcd_query_descriptor(hba, UPIU_QUERY_OPCODE_READ_DESC,
					desc_id, desc_index, 0, header,
					&header_len);

	if (ret) {
		dev_err(hba->dev, "%s: Failed to get descriptor header id %d",
			__func__, desc_id);
		return ret;
	} else if (desc_id != header[QUERY_DESC_DESC_TYPE_OFFSET]) {
		dev_warn(hba->dev, "%s: descriptor header id %d and desc_id %d mismatch",
			__func__, header[QUERY_DESC_DESC_TYPE_OFFSET],
			desc_id);
		ret = -EINVAL;
	}

	*desc_length = header[QUERY_DESC_LENGTH_OFFSET];
	return ret;

}

/**
 * ufshcd_map_desc_id_to_length - map descriptor IDN to its length
 * @hba: Pointer to adapter instance
 * @desc_id: descriptor idn value
 * @desc_len: mapped desc length (out)
 *
 * Return 0 in case of success, non-zero otherwise
 */
int ufshcd_map_desc_id_to_length(struct ufs_hba *hba,
	enum desc_idn desc_id, int *desc_len)
{
	switch (desc_id) {
	case QUERY_DESC_IDN_DEVICE:
		*desc_len = hba->desc_size.dev_desc;
		break;
	case QUERY_DESC_IDN_POWER:
		*desc_len = hba->desc_size.pwr_desc;
		break;
	case QUERY_DESC_IDN_GEOMETRY:
		*desc_len = hba->desc_size.geom_desc;
		break;
	case QUERY_DESC_IDN_CONFIGURATION:
		*desc_len = hba->desc_size.conf_desc;
		break;
	case QUERY_DESC_IDN_UNIT:
		*desc_len = hba->desc_size.unit_desc;
		break;
	case QUERY_DESC_IDN_INTERCONNECT:
		*desc_len = hba->desc_size.interc_desc;
		break;
	case QUERY_DESC_IDN_STRING:
		*desc_len = QUERY_DESC_MAX_SIZE;
		break;
	case QUERY_DESC_IDN_RFU_0:
	case QUERY_DESC_IDN_RFU_1:
		*desc_len = 0;
		break;
	default:
		*desc_len = 0;
		return -EINVAL;
	}
	return 0;
}
EXPORT_SYMBOL(ufshcd_map_desc_id_to_length);

/**
 * ufshcd_read_desc_param - read the specified descriptor parameter
 * @hba: Pointer to adapter instance
@@ -3721,37 +3794,45 @@ EXPORT_SYMBOL(ufshcd_query_descriptor);
static int ufshcd_read_desc_param(struct ufs_hba *hba,
				  enum desc_idn desc_id,
				  int desc_index,
				  u32 param_offset,
				  u8 param_offset,
				  u8 *param_read_buf,
				  u32 param_size)
				  u8 param_size)
{
	int ret;
	u8 *desc_buf;
	u32 buff_len;
	int buff_len;
	bool is_kmalloc = true;

	/* safety checks */
	if (desc_id >= QUERY_DESC_IDN_MAX)
	/* Safety check */
	if (desc_id >= QUERY_DESC_IDN_MAX || !param_size)
		return -EINVAL;

	buff_len = ufs_query_desc_max_size[desc_id];
	if ((param_offset + param_size) > buff_len)
		return -EINVAL;
	/* Get the max length of descriptor from structure filled up at probe
	 * time.
	 */
	ret = ufshcd_map_desc_id_to_length(hba, desc_id, &buff_len);

	if (!param_offset && (param_size == buff_len)) {
		/* memory space already available to hold full descriptor */
		desc_buf = param_read_buf;
		is_kmalloc = false;
	} else {
		/* allocate memory to hold full descriptor */
	/* Sanity checks */
	if (ret || !buff_len) {
		dev_err(hba->dev, "%s: Failed to get full descriptor length",
			__func__);
		return ret;
	}

	/* Check whether we need temp memory */
	if (param_offset != 0 || param_size < buff_len) {
		desc_buf = kmalloc(buff_len, GFP_KERNEL);
		if (!desc_buf)
			return -ENOMEM;
	} else {
		desc_buf = param_read_buf;
		is_kmalloc = false;
	}

	/* Request for full descriptor */
	ret = ufshcd_query_descriptor(hba, UPIU_QUERY_OPCODE_READ_DESC,
				      desc_id, desc_index, 0, desc_buf,
				      &buff_len);
					desc_id, desc_index, 0,
					desc_buf, &buff_len);

	if (ret) {
		dev_err(hba->dev, "%s: Failed reading descriptor. desc_id %d, desc_index %d, param_offset %d, ret %d",
@@ -3768,25 +3849,9 @@ static int ufshcd_read_desc_param(struct ufs_hba *hba,
		goto out;
	}

	/*
	 * While reading variable size descriptors (like string descriptor),
	 * some UFS devices may report the "LENGTH" (field in "Transaction
	 * Specific fields" of Query Response UPIU) same as what was requested
	 * in Query Request UPIU instead of reporting the actual size of the
	 * variable size descriptor.
	 * Although it's safe to ignore the "LENGTH" field for variable size
	 * descriptors as we can always derive the length of the descriptor from
	 * the descriptor header fields. Hence this change impose the length
	 * match check only for fixed size descriptors (for which we always
	 * request the correct size as part of Query Request UPIU).
	 */
	if ((desc_id != QUERY_DESC_IDN_STRING) &&
	    (buff_len != desc_buf[QUERY_DESC_LENGTH_OFFSET])) {
		dev_err(hba->dev, "%s: desc_buf length mismatch: buff_len %d, buff_len(desc_header) %d",
			__func__, buff_len, desc_buf[QUERY_DESC_LENGTH_OFFSET]);
		ret = -EINVAL;
		goto out;
	}
	/* Check wherher we will not copy more data, than available */
	if (is_kmalloc && param_size > buff_len)
		param_size = buff_len;

	if (is_kmalloc)
		memcpy(param_read_buf, &desc_buf[param_offset], param_size);
@@ -7170,10 +7235,19 @@ static u32 ufshcd_find_max_sup_active_icc_level(struct ufs_hba *hba,
static void ufshcd_set_active_icc_lvl(struct ufs_hba *hba)
{
	int ret;
	int buff_len = QUERY_DESC_POWER_MAX_SIZE;
	u8 desc_buf[QUERY_DESC_POWER_MAX_SIZE];
	int buff_len = hba->desc_size.pwr_desc;
	u8 *desc_buf = NULL;
	u32 icc_level;

	if (buff_len) {
		desc_buf = kmalloc(buff_len, GFP_KERNEL);
		if (!desc_buf) {
			dev_err(hba->dev,
				"%s: Failed to allocate desc_buf\n", __func__);
			return;
		}
	}

	ret = ufshcd_read_power_desc(hba, desc_buf, buff_len);
	if (ret) {
		dev_err(hba->dev,
@@ -7554,9 +7628,18 @@ static int ufshcd_set_dev_ref_clk(struct ufs_hba *hba)
static int ufs_read_device_desc_data(struct ufs_hba *hba)
{
	int err;
	u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE];
	u8 *desc_buf = NULL;

	err = ufshcd_read_device_desc(hba, desc_buf, sizeof(desc_buf));
	if (hba->desc_size.dev_desc) {
		desc_buf = kmalloc(hba->desc_size.dev_desc, GFP_KERNEL);
		if (!desc_buf) {
			err = -ENOMEM;
			dev_err(hba->dev,
				"%s: Failed to allocate desc_buf\n", __func__);
			return err;
		}
	}
	err = ufshcd_read_device_desc(hba, desc_buf, hba->desc_size.dev_desc);
	if (err)
		return err;

@@ -7574,6 +7657,51 @@ static int ufs_read_device_desc_data(struct ufs_hba *hba)
	return 0;
}

static void ufshcd_init_desc_sizes(struct ufs_hba *hba)
{
	int err;

	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_DEVICE, 0,
		&hba->desc_size.dev_desc);
	if (err)
		hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE;

	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_POWER, 0,
		&hba->desc_size.pwr_desc);
	if (err)
		hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE;

	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_INTERCONNECT, 0,
		&hba->desc_size.interc_desc);
	if (err)
		hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE;

	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_CONFIGURATION, 0,
		&hba->desc_size.conf_desc);
	if (err)
		hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE;

	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_UNIT, 0,
		&hba->desc_size.unit_desc);
	if (err)
		hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE;

	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_GEOMETRY, 0,
		&hba->desc_size.geom_desc);
	if (err)
		hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
}

static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
{
	hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE;
	hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE;
	hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE;
	hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE;
	hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE;
	hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;
}

/**
 * ufshcd_probe_hba - probe hba to detect device and initialize
 * @hba: per-adapter instance
@@ -7614,6 +7742,8 @@ static int ufshcd_probe_hba(struct ufs_hba *hba)
	if (ret)
		goto out;

	/* Init check for device descriptor sizes */
	ufshcd_init_desc_sizes(hba);
	ufs_advertise_fixup_device(hba);
	ufshcd_tune_unipro_params(hba);

@@ -10075,6 +10205,9 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)

	ufshcd_init_lanes_per_dir(hba);

	/* Set descriptor lengths to specification defaults */
	ufshcd_def_desc_sizes(hba);

	err = ufshcd_hba_init(hba);
	if (err)
		goto out_error;
Loading