Merge "scsi: ufs: Fix race condition in ufs qcom debugfs driver"
This commit is contained in:
commit
ab56a31bcb
3 changed files with 38 additions and 19 deletions
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue