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

Commit c73a296b 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: Fix race condition in ufs qcom debugfs driver"

parents dac16415 732e9ce6
Loading
Loading
Loading
Loading
+11 −1
Original line number Diff line number Diff line
/*
 * 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
@@ -110,6 +110,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);
@@ -136,8 +139,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
+25 −17
Original line number Diff line number Diff line
/*
 * Copyright (c) 2013-2016, Linux Foundation. All rights reserved.
 * Copyright (c) 2013-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
@@ -2193,12 +2193,13 @@ static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
	host->testbus.select_minor = 1;
}

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;
	}

@@ -2207,10 +2208,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 > 0x1F) {
	if (select_minor > 0x1F) {
		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;
	}

@@ -2219,16 +2220,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;
@@ -2285,20 +2286,27 @@ int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
	 */
	}
	mask <<= offset;

	spin_unlock_irqrestore(hba->host->host_lock, flags);
	pm_runtime_get_sync(host->hba->dev);
	ufshcd_hold(host->hba, false);
	if (reg) {
		ufshcd_rmwl(host->hba, TEST_BUS_SEL,
		    (u32)host->testbus.select_major << 19,
		    (u32)host->testbus.select_major << testbus_sel_offset,
		    REG_UFS_CFG1);
		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);
out:
	ufshcd_release(host->hba, false);
	pm_runtime_put_sync(host->hba->dev);

	return 0;
	return ret;
}

static void ufs_qcom_testbus_read(struct ufs_hba *hba)
+4 −2
Original line number Diff line number Diff line
/* Copyright (c) 2013-2016, The Linux Foundation. All rights reserved.
/* Copyright (c) 2013-2017, The 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
@@ -99,7 +99,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

/* bit definitions for REG_UFS_CFG2 register */
#define UAWM_HW_CGC_EN		(1 << 0)
@@ -355,6 +355,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,