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

Commit eb142de1 authored by qctecmdr's avatar qctecmdr Committed by Gerrit - the friendly Code Review server
Browse files

Merge "scsi: ufs: sysfs: health descriptor"

parents 261ee411 da1dcbff
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
@@ -151,8 +151,9 @@ enum ufs_desc_def_size {
	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_GEOMETRY_DEF_SIZE		= 0x48,
	QUERY_DESC_POWER_DEF_SIZE		= 0x62,
	QUERY_DESC_HEALTH_DEF_SIZE		= 0x25,
};

/* Unit descriptor parameters offsets in bytes*/
@@ -206,6 +207,15 @@ enum device_desc_param {
	DEVICE_DESC_PARAM_FRQ_RTC		= 0x1D,
};

/* Health descriptor parameters offsets in bytes*/
enum health_desc_param {
	HEALTH_DESC_PARAM_LEN			= 0x0,
	HEALTH_DESC_PARAM_TYPE			= 0x1,
	HEALTH_DESC_PARAM_EOL_INFO		= 0x2,
	HEALTH_DESC_PARAM_LIFE_TIME_EST_A	= 0x3,
	HEALTH_DESC_PARAM_LIFE_TIME_EST_B	= 0x4,
};

/*
 * Logical Unit Write Protect
 * 00h: LU not write protected
+106 −0
Original line number Diff line number Diff line
@@ -43,6 +43,8 @@
#include <linux/nls.h>
#include <linux/of.h>
#include <linux/blkdev.h>
#include <asm/unaligned.h>

#include "ufshcd.h"
#include "ufs_quirks.h"
#include "unipro.h"
@@ -4520,6 +4522,9 @@ int ufshcd_map_desc_id_to_length(struct ufs_hba *hba,
	case QUERY_DESC_IDN_STRING:
		*desc_len = QUERY_DESC_MAX_SIZE;
		break;
	case QUERY_DESC_IDN_HEALTH:
		*desc_len = hba->desc_size.hlth_desc;
		break;
	case QUERY_DESC_IDN_RFU_0:
	case QUERY_DESC_IDN_RFU_1:
		*desc_len = 0;
@@ -8560,6 +8565,11 @@ static void ufshcd_init_desc_sizes(struct ufs_hba *hba)
		&hba->desc_size.geom_desc);
	if (err)
		hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE;

	err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0,
		&hba->desc_size.hlth_desc);
	if (err)
		hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
}

static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
@@ -8570,6 +8580,7 @@ static void ufshcd_def_desc_sizes(struct ufs_hba *hba)
	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;
	hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE;
}

static void ufshcd_apply_pm_quirks(struct ufs_hba *hba)
@@ -10690,16 +10701,111 @@ static void ufshcd_add_spm_lvl_sysfs_nodes(struct ufs_hba *hba)
		dev_err(hba->dev, "Failed to create sysfs for spm_lvl\n");
}

static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba,
				  enum desc_idn desc_id,
				  u8 desc_index,
				  u8 param_offset,
				  u8 *sysfs_buf,
				  u8 param_size)
{
	u8 desc_buf[8] = {0};
	int ret;

	if (param_size > 8)
		return -EINVAL;

	pm_runtime_get_sync(hba->dev);
	ret = ufshcd_read_desc_param(hba, desc_id, desc_index,
				param_offset, desc_buf, param_size);
	pm_runtime_put_sync(hba->dev);

	if (ret)
		return -EINVAL;
	switch (param_size) {
	case 1:
		ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%02X\n", *desc_buf);
		break;
	case 2:
		ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%04X\n",
			get_unaligned_be16(desc_buf));
		break;
	case 4:
		ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%08X\n",
			get_unaligned_be32(desc_buf));
		break;
	case 8:
		ret = snprintf(sysfs_buf, PAGE_SIZE, "0x%016llX\n",
			get_unaligned_be64(desc_buf));
		break;
	}

	return ret;
}


#define UFS_DESC_PARAM(_name, _puname, _duname, _size)			\
	static ssize_t _name##_show(struct device *dev,			\
		struct device_attribute *attr, char *buf)			\
{									\
	struct ufs_hba *hba = dev_get_drvdata(dev); 		\
	return ufs_sysfs_read_desc_param(hba, QUERY_DESC_IDN_##_duname, \
		0, _duname##_DESC_PARAM##_puname, buf, _size);		\
}									\
static DEVICE_ATTR_RO(_name)

#define UFS_HEALTH_DESC_PARAM(_name, _uname, _size)			\
		UFS_DESC_PARAM(_name, _uname, HEALTH, _size)

UFS_HEALTH_DESC_PARAM(eol_info, _EOL_INFO, 1);
UFS_HEALTH_DESC_PARAM(life_time_estimation_a, _LIFE_TIME_EST_A, 1);
UFS_HEALTH_DESC_PARAM(life_time_estimation_b, _LIFE_TIME_EST_B, 1);

static struct attribute *ufs_sysfs_health_descriptor[] = {
	&dev_attr_eol_info.attr,
	&dev_attr_life_time_estimation_a.attr,
	&dev_attr_life_time_estimation_b.attr,
	NULL,
};

static const struct attribute_group ufs_sysfs_health_descriptor_group = {
	.name = "health_descriptor",
	.attrs = ufs_sysfs_health_descriptor,
};

static const struct attribute_group *ufs_sysfs_groups[] = {
	&ufs_sysfs_health_descriptor_group,
	NULL,
};


static void ufshcd_add_desc_sysfs_nodes(struct device *dev)
{
	int ret;

	ret = sysfs_create_groups(&dev->kobj, ufs_sysfs_groups);
	if (ret)
		dev_err(dev,
			"%s: sysfs groups creation failed (err = %d)\n",
			__func__, ret);
}

static void ufshcd_remove_desc_sysfs_nodes(struct device *dev)
{
	sysfs_remove_groups(&dev->kobj, ufs_sysfs_groups);
}

static inline void ufshcd_add_sysfs_nodes(struct ufs_hba *hba)
{
	ufshcd_add_rpm_lvl_sysfs_nodes(hba);
	ufshcd_add_spm_lvl_sysfs_nodes(hba);
	ufshcd_add_desc_sysfs_nodes(hba->dev);
}

static inline void ufshcd_remove_sysfs_nodes(struct ufs_hba *hba)
{
	device_remove_file(hba->dev, &hba->rpm_lvl_attr);
	device_remove_file(hba->dev, &hba->spm_lvl_attr);
	ufshcd_remove_desc_sysfs_nodes(hba->dev);
}

static void __ufshcd_shutdown_clkscaling(struct ufs_hba *hba)
+1 −0
Original line number Diff line number Diff line
@@ -259,6 +259,7 @@ struct ufs_desc_size {
	int interc_desc;
	int unit_desc;
	int conf_desc;
	int hlth_desc;
};

/**
+2 −1
Original line number Diff line number Diff line
@@ -55,7 +55,8 @@ enum desc_idn {
	QUERY_DESC_IDN_RFU_1		= 0x6,
	QUERY_DESC_IDN_GEOMETRY		= 0x7,
	QUERY_DESC_IDN_POWER		= 0x8,
	QUERY_DESC_IDN_RFU_2		= 0x9,
	QUERY_DESC_IDN_HEALTH           = 0x9,
	QUERY_DESC_IDN_RFU_2		= 0x0A,
	QUERY_DESC_IDN_MAX,
};