scsi: ufs: debugfs: add option to read peer DME attribute

This patch adds the debugfs capability to read the DME attribute of
peer UniPro/M-PHY. This should help for debugging.

Change-Id: I26d3675bdda8b9fdf0f9aa6b81a1ffafbd828fd0
[subhashj@codeaurora.org: resolved trivial merge conflicts]
Signed-off-by: Subhash Jadavani <subhashj@codeaurora.org>
[venkatg@codeaurora.org: resolved trivial merge conflicts]
Signed-off-by: Venkat Gopalakrishnan <venkatg@codeaurora.org>
This commit is contained in:
Subhash Jadavani 2014-09-13 12:17:59 -07:00 committed by David Keitel
parent 3997870e3b
commit 04218a4f78
4 changed files with 101 additions and 13 deletions

View file

@ -753,6 +753,23 @@ out:
return ret;
}
static int ufsdbg_config_pwr_mode(struct ufs_hba *hba,
struct ufs_pa_layer_attr *desired_pwr_mode)
{
#define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */
int ret;
pm_runtime_get_sync(hba->dev);
scsi_block_requests(hba->host);
ret = ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US);
if (!ret)
ret = ufshcd_change_power_mode(hba, desired_pwr_mode);
scsi_unblock_requests(hba->host);
pm_runtime_put_sync(hba->dev);
return ret;
}
static ssize_t ufsdbg_power_mode_write(struct file *file,
const char __user *ubuf, size_t cnt,
loff_t *ppos)
@ -764,7 +781,6 @@ static ssize_t ufsdbg_power_mode_write(struct file *file,
loff_t buff_pos = 0;
int ret;
int idx = 0;
#define DOORBELL_CLR_TOUT_US (1000 * 1000) /* 1 sec */
ret = simple_write_to_buffer(pwr_mode_str, BUFF_LINE_CAPACITY,
&buff_pos, ubuf, cnt);
@ -800,13 +816,7 @@ static ssize_t ufsdbg_power_mode_write(struct file *file,
return cnt;
}
pm_runtime_get_sync(hba->dev);
scsi_block_requests(hba->host);
ret = ufshcd_wait_for_doorbell_clr(hba, DOORBELL_CLR_TOUT_US);
if (!ret)
ret = ufshcd_change_power_mode(hba, &final_pwr_mode);
scsi_unblock_requests(hba->host);
pm_runtime_put_sync(hba->dev);
ret = ufsdbg_config_pwr_mode(hba, &final_pwr_mode);
if (ret == -EBUSY)
dev_err(hba->dev,
"%s: ufshcd_config_pwr_mode failed: system is busy, try again\n",
@ -830,19 +840,21 @@ static const struct file_operations ufsdbg_power_mode_desc = {
.write = ufsdbg_power_mode_write,
};
static int ufsdbg_dme_local_read(void *data, u64 *attr_val)
static int ufsdbg_dme_read(void *data, u64 *attr_val, bool peer)
{
int ret;
struct ufs_hba *hba = data;
u32 read_val = 0;
u32 attr_id, read_val = 0;
int (*read_func) (struct ufs_hba *, u32, u32 *);
if (!hba)
return -EINVAL;
read_func = peer ? ufshcd_dme_peer_get : ufshcd_dme_get;
attr_id = peer ? hba->debugfs_files.dme_peer_attr_id :
hba->debugfs_files.dme_local_attr_id;
pm_runtime_get_sync(hba->dev);
ret = ufshcd_dme_get(hba,
UIC_ARG_MIB(hba->debugfs_files.dme_local_attr_id),
&read_val);
ret = ufshcd_dme_get(hba, UIC_ARG_MIB(attr_id), &read_val);
pm_runtime_put_sync(hba->dev);
if (!ret)
@ -863,11 +875,70 @@ static int ufsdbg_dme_local_set_attr_id(void *data, u64 attr_id)
return 0;
}
static int ufsdbg_dme_local_read(void *data, u64 *attr_val)
{
return ufsdbg_dme_read(data, attr_val, false);
}
DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_dme_local_read_ops,
ufsdbg_dme_local_read,
ufsdbg_dme_local_set_attr_id,
"%llu\n");
static int ufsdbg_dme_peer_read(void *data, u64 *attr_val)
{
int ret;
struct ufs_hba *hba = data;
struct ufs_pa_layer_attr orig_pwr_info;
struct ufs_pa_layer_attr temp_pwr_info;
bool restore_pwr_mode = false;
if (!hba)
return -EINVAL;
if (hba->quirks & UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE) {
orig_pwr_info = hba->pwr_info;
temp_pwr_info = orig_pwr_info;
if (orig_pwr_info.pwr_tx == FAST_MODE ||
orig_pwr_info.pwr_rx == FAST_MODE) {
temp_pwr_info.pwr_tx = FASTAUTO_MODE;
temp_pwr_info.pwr_rx = FASTAUTO_MODE;
ret = ufsdbg_config_pwr_mode(hba, &temp_pwr_info);
if (ret)
goto out;
else
restore_pwr_mode = true;
}
}
ret = ufsdbg_dme_read(data, attr_val, true);
if (hba->quirks & UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE) {
if (restore_pwr_mode)
ufsdbg_config_pwr_mode(hba, &orig_pwr_info);
}
out:
return ret;
}
static int ufsdbg_dme_peer_set_attr_id(void *data, u64 attr_id)
{
struct ufs_hba *hba = data;
if (!hba)
return -EINVAL;
hba->debugfs_files.dme_peer_attr_id = (u32)attr_id;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(ufsdbg_dme_peer_read_ops,
ufsdbg_dme_peer_read,
ufsdbg_dme_peer_set_attr_id,
"%llu\n");
void ufsdbg_add_debugfs(struct ufs_hba *hba)
{
if (!hba) {
@ -962,6 +1033,17 @@ void ufsdbg_add_debugfs(struct ufs_hba *hba)
goto err;
}
hba->debugfs_files.dme_peer_read =
debugfs_create_file("dme_peer_read", S_IRUSR | S_IWUSR,
hba->debugfs_files.debugfs_root, hba,
&ufsdbg_dme_peer_read_ops);
if (!hba->debugfs_files.dme_peer_read) {
dev_err(hba->dev,
"%s: failed create dme_peer_read debugfs entry\n",
__func__);
goto err;
}
ufsdbg_setup_fault_injection(hba);
return;

View file

@ -754,6 +754,8 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
hba->quirks |= (UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS
| UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP
| UFSHCD_QUIRK_BROKEN_LCC);
hba->quirks |= UFSHCD_QUIRK_DME_PEER_GET_FAST_MODE;
}
static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,

View file

@ -2777,6 +2777,7 @@ int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us)
bool timeout = false;
ktime_t start = ktime_get();
ufshcd_hold(hba, false);
spin_lock_irqsave(hba->host->host_lock, flags);
if (hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) {
ret = -EBUSY;
@ -2811,6 +2812,7 @@ int ufshcd_wait_for_doorbell_clr(struct ufs_hba *hba, u64 wait_timeout_us)
}
out:
spin_unlock_irqrestore(hba->host->host_lock, flags);
ufshcd_release(hba);
return ret;
}

View file

@ -378,7 +378,9 @@ struct debugfs_files {
struct dentry *dump_dev_desc;
struct dentry *power_mode;
struct dentry *dme_local_read;
struct dentry *dme_peer_read;
u32 dme_local_attr_id;
u32 dme_peer_attr_id;
#ifdef CONFIG_UFS_FAULT_INJECTION
struct fault_attr fail_attr;
#endif