Merge "scsi: ufs: Fix race condition in ufs qcom debugfs driver"

This commit is contained in:
Linux Build Service Account 2017-10-17 05:38:28 -07:00 committed by Gerrit - the friendly Code Review server
commit ab56a31bcb
3 changed files with 38 additions and 19 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Linux Foundation. All rights reserved.
* Copyright (c) 2015,2017, 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
@ -117,6 +117,9 @@ static ssize_t ufs_qcom_dbg_testbus_cfg_write(struct file *file,
int ret = 0;
int major;
int minor;
unsigned long flags;
struct ufs_hba *hba = host->hba;
ret = simple_write_to_buffer(configuration, TESTBUS_CFG_BUFF_LINE_SIZE,
&buff_pos, ubuf, cnt);
@ -142,8 +145,15 @@ static ssize_t ufs_qcom_dbg_testbus_cfg_write(struct file *file,
goto out;
}
if (!ufs_qcom_testbus_cfg_is_ok(host, major, minor)) {
ret = -EPERM;
goto out;
}
spin_lock_irqsave(hba->host->host_lock, flags);
host->testbus.select_major = (u8)major;
host->testbus.select_minor = (u8)minor;
spin_unlock_irqrestore(hba->host->host_lock, flags);
/*
* Sanity check of the {major, minor} tuple is done in the

View file

@ -2563,12 +2563,13 @@ static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
host->testbus.select_minor = 37;
}
static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host,
u8 select_major, u8 select_minor)
{
if (host->testbus.select_major >= TSTBUS_MAX) {
if (select_major >= TSTBUS_MAX) {
dev_err(host->hba->dev,
"%s: UFS_CFG1[TEST_BUS_SEL} may not equal 0x%05X\n",
__func__, host->testbus.select_major);
__func__, select_major);
return false;
}
@ -2577,10 +2578,10 @@ static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
* mappings of select_minor, since there is no harm in
* configuring a non-existent select_minor
*/
if (host->testbus.select_minor > 0xFF) {
if (select_minor > 0xFF) {
dev_err(host->hba->dev,
"%s: 0x%05X is not a legal testbus option\n",
__func__, host->testbus.select_minor);
__func__, select_minor);
return false;
}
@ -2594,16 +2595,16 @@ static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
*/
int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
{
int reg;
int offset;
int reg = 0;
int offset, ret = 0, testbus_sel_offset = 19;
u32 mask = TEST_BUS_SUB_SEL_MASK;
unsigned long flags;
struct ufs_hba *hba;
if (!host)
return -EINVAL;
if (!ufs_qcom_testbus_cfg_is_ok(host))
return -EPERM;
hba = host->hba;
spin_lock_irqsave(hba->host->host_lock, flags);
switch (host->testbus.select_major) {
case TSTBUS_UAWM:
reg = UFS_TEST_BUS_CTRL_0;
@ -2661,21 +2662,27 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
*/
}
mask <<= offset;
ufshcd_rmwl(host->hba, TEST_BUS_SEL,
(u32)host->testbus.select_major << 19,
spin_unlock_irqrestore(hba->host->host_lock, flags);
if (reg) {
ufshcd_rmwl(host->hba, TEST_BUS_SEL,
(u32)host->testbus.select_major << testbus_sel_offset,
REG_UFS_CFG1);
ufshcd_rmwl(host->hba, mask,
ufshcd_rmwl(host->hba, mask,
(u32)host->testbus.select_minor << offset,
reg);
} else {
dev_err(hba->dev, "%s: Problem setting minor\n", __func__);
ret = -EINVAL;
goto out;
}
ufs_qcom_enable_test_bus(host);
/*
* Make sure the test bus configuration is
* committed before returning.
*/
mb();
return 0;
out:
return ret;
}
static void ufs_qcom_testbus_read(struct ufs_hba *hba)

View file

@ -100,7 +100,7 @@ enum {
/* bit definitions for REG_UFS_CFG1 register */
#define QUNIPRO_SEL UFS_BIT(0)
#define TEST_BUS_EN BIT(18)
#define TEST_BUS_SEL GENMASK(22, 19)
#define TEST_BUS_SEL 0x780000
#define UFS_REG_TEST_BUS_EN BIT(30)
/* bit definitions for REG_UFS_CFG2 register */
@ -391,6 +391,8 @@ ufs_qcom_get_debug_reg_offset(struct ufs_qcom_host *host, u32 reg)
#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)
#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host, u8 select_major,
u8 select_minor);
int ufs_qcom_testbus_config(struct ufs_qcom_host *host);
void ufs_qcom_print_hw_debug_reg_all(struct ufs_hba *hba, void *priv,
void (*print_fn)(struct ufs_hba *hba, int offset, int num_regs,