Re: [PATCH v7 7/8] scsi: ufs-qcom: add debug prints for test bus

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Looks good to me.
Reviewed-by: Subhash Jadavani <subhashj@xxxxxxxxxxxxxx>

> Adds support for configuring and reading the test bus and debug
> registers. This change also adds another vops in order to print the
> debug registers.
>
> Signed-off-by: Yaniv Gardi <ygardi@xxxxxxxxxxxxxx>
>
> ---
>  drivers/scsi/ufs/ufs-qcom.c | 165
> +++++++++++++++++++++++++++++++++++++++++++-
>  drivers/scsi/ufs/ufs-qcom.h |  37 +++++++++-
>  drivers/scsi/ufs/ufshcd.c   |   2 +
>  drivers/scsi/ufs/ufshcd.h   |   8 +++
>  4 files changed, 208 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
> index b275a9a..1633808 100644
> --- a/drivers/scsi/ufs/ufs-qcom.c
> +++ b/drivers/scsi/ufs/ufs-qcom.c
> @@ -23,6 +23,24 @@
>  #include "unipro.h"
>  #include "ufs-qcom.h"
>  #include "ufshci.h"
> +#define UFS_QCOM_DEFAULT_DBG_PRINT_EN	\
> +	(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
> +
> +enum {
> +	TSTBUS_UAWM,
> +	TSTBUS_UARM,
> +	TSTBUS_TXUC,
> +	TSTBUS_RXUC,
> +	TSTBUS_DFC,
> +	TSTBUS_TRLUT,
> +	TSTBUS_TMRLUT,
> +	TSTBUS_OCSC,
> +	TSTBUS_UTP_HCI,
> +	TSTBUS_COMBINED,
> +	TSTBUS_WRAPPER,
> +	TSTBUS_UNIPRO,
> +	TSTBUS_MAX,
> +};
>
>  static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS];
>
> @@ -30,6 +48,15 @@ static void ufs_qcom_get_speed_mode(struct
> ufs_pa_layer_attr *p, char *result);
>  static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
>  		const char *speed_mode);
>  static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote);
> +static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host);
> +static void ufs_qcom_dump_regs(struct ufs_hba *hba, int offset, int len,
> +		char *prefix)
> +{
> +	print_hex_dump(KERN_ERR, prefix,
> +			len > 4 ? DUMP_PREFIX_OFFSET : DUMP_PREFIX_NONE,
> +			16, 4, (void __force *)hba->mmio_base + offset,
> +			len * 4, false);
> +}
>
>  static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32
> *tx_lanes)
>  {
> @@ -996,6 +1023,15 @@ static int ufs_qcom_init(struct ufs_hba *hba)
>  	if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
>  		ufs_qcom_hosts[hba->dev->id] = host;
>
> +	host->dbg_print_en |= UFS_QCOM_DEFAULT_DBG_PRINT_EN;
> +	ufs_qcom_get_default_testbus_cfg(host);
> +	err = ufs_qcom_testbus_config(host);
> +	if (err) {
> +		dev_warn(dev, "%s: failed to configure the testbus %d\n",
> +				__func__, err);
> +		err = 0;
> +	}
> +
>  	goto out;
>
>  out_disable_phy:
> @@ -1025,12 +1061,134 @@ void ufs_qcom_clk_scale_notify(struct ufs_hba
> *hba)
>
>  	if (!dev_req_params)
>  		return;
> +}
> +
> +static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host)
> +{
> +	/* provide a legal default configuration */
> +	host->testbus.select_major = TSTBUS_UAWM;
> +	host->testbus.select_minor = 1;
> +}
> +
> +static bool ufs_qcom_testbus_cfg_is_ok(struct ufs_qcom_host *host)
> +{
> +	if (host->testbus.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);
> +		return false;
> +	}
> +
> +	/*
> +	 * Not performing check for each individual select_major
> +	 * mappings of select_minor, since there is no harm in
> +	 * configuring a non-existent select_minor
> +	 */
> +	if (host->testbus.select_minor > 0x1F) {
> +		dev_err(host->hba->dev,
> +			"%s: 0x%05X is not a legal testbus option\n",
> +			__func__, host->testbus.select_minor);
> +		return false;
> +	}
> +
> +	return true;
> +}
> +
> +int ufs_qcom_testbus_config(struct ufs_qcom_host *host)
> +{
> +	int reg;
> +	int offset;
> +	u32 mask = TEST_BUS_SUB_SEL_MASK;
> +
> +	if (!host)
> +		return -EINVAL;
>
> -	ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
> -				dev_req_params->pwr_rx,
> -				dev_req_params->hs_rate);
> +	if (!ufs_qcom_testbus_cfg_is_ok(host))
> +		return -EPERM;
> +
> +	switch (host->testbus.select_major) {
> +	case TSTBUS_UAWM:
> +		reg = UFS_TEST_BUS_CTRL_0;
> +		offset = 24;
> +		break;
> +	case TSTBUS_UARM:
> +		reg = UFS_TEST_BUS_CTRL_0;
> +		offset = 16;
> +		break;
> +	case TSTBUS_TXUC:
> +		reg = UFS_TEST_BUS_CTRL_0;
> +		offset = 8;
> +		break;
> +	case TSTBUS_RXUC:
> +		reg = UFS_TEST_BUS_CTRL_0;
> +		offset = 0;
> +		break;
> +	case TSTBUS_DFC:
> +		reg = UFS_TEST_BUS_CTRL_1;
> +		offset = 24;
> +		break;
> +	case TSTBUS_TRLUT:
> +		reg = UFS_TEST_BUS_CTRL_1;
> +		offset = 16;
> +		break;
> +	case TSTBUS_TMRLUT:
> +		reg = UFS_TEST_BUS_CTRL_1;
> +		offset = 8;
> +		break;
> +	case TSTBUS_OCSC:
> +		reg = UFS_TEST_BUS_CTRL_1;
> +		offset = 0;
> +		break;
> +	case TSTBUS_WRAPPER:
> +		reg = UFS_TEST_BUS_CTRL_2;
> +		offset = 16;
> +		break;
> +	case TSTBUS_COMBINED:
> +		reg = UFS_TEST_BUS_CTRL_2;
> +		offset = 8;
> +		break;
> +	case TSTBUS_UTP_HCI:
> +		reg = UFS_TEST_BUS_CTRL_2;
> +		offset = 0;
> +		break;
> +	case TSTBUS_UNIPRO:
> +		reg = UFS_UNIPRO_CFG;
> +		offset = 1;
> +		break;
> +	/*
> +	 * No need for a default case, since
> +	 * ufs_qcom_testbus_cfg_is_ok() checks that the configuration
> +	 * is legal
> +	 */
> +	}
> +	mask <<= offset;
> +
> +	pm_runtime_get_sync(host->hba->dev);
> +	ufshcd_hold(host->hba, false);
> +	ufshcd_rmwl(host->hba, TEST_BUS_SEL,
> +		    (u32)host->testbus.select_major << 19,
> +		    REG_UFS_CFG1);
> +	ufshcd_rmwl(host->hba, mask,
> +		    (u32)host->testbus.select_minor << offset,
> +		    reg);
> +	ufshcd_release(host->hba);
> +	pm_runtime_put_sync(host->hba->dev);
> +
> +	return 0;
>  }
>
> +static void ufs_qcom_testbus_read(struct ufs_hba *hba)
> +{
> +	ufs_qcom_dump_regs(hba, UFS_TEST_BUS, 1, "UFS_TEST_BUS ");
> +}
> +
> +static void ufs_qcom_dump_dbg_regs(struct ufs_hba *hba)
> +{
> +	ufs_qcom_dump_regs(hba, REG_UFS_SYS1CLK_1US, 16,
> +			"HCI Vendor Specific Registers ");
> +
> +	ufs_qcom_testbus_read(hba);
> +}
>  /**
>   * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
>   *
> @@ -1049,6 +1207,7 @@ static struct ufs_hba_variant_ops ufs_hba_qcom_vops
> = {
>  	.pwr_change_notify	= ufs_qcom_pwr_change_notify,
>  	.suspend		= ufs_qcom_suspend,
>  	.resume			= ufs_qcom_resume,
> +	.dbg_register_dump	= ufs_qcom_dump_dbg_regs,
>  };
>
>  /**
> diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
> index db2c0a0..1b71a1b 100644
> --- a/drivers/scsi/ufs/ufs-qcom.h
> +++ b/drivers/scsi/ufs/ufs-qcom.h
> @@ -58,6 +58,16 @@ enum {
>  	REG_UFS_CFG2                        = 0xE0,
>  	REG_UFS_HW_VERSION                  = 0xE4,
>
> +	UFS_TEST_BUS				= 0xE8,
> +	UFS_TEST_BUS_CTRL_0			= 0xEC,
> +	UFS_TEST_BUS_CTRL_1			= 0xF0,
> +	UFS_TEST_BUS_CTRL_2			= 0xF4,
> +	UFS_UNIPRO_CFG				= 0xF8,
> +
> +};
> +
> +/* QCOM UFS host controller vendor specific debug registers */
> +enum {
>  	UFS_DBG_RD_REG_UAWM			= 0x100,
>  	UFS_DBG_RD_REG_UARM			= 0x200,
>  	UFS_DBG_RD_REG_TXUC			= 0x300,
> @@ -73,6 +83,9 @@ enum {
>  	UFS_UFS_DBG_RD_EDTL_RAM			= 0x1900,
>  };
>
> +#define TEST_BUS_EN		BIT(18)
> +#define TEST_BUS_SEL		GENMASK(22, 19)
> +
>  /* bit definitions for REG_UFS_CFG2 register */
>  #define UAWM_HW_CGC_EN		(1 << 0)
>  #define UARM_HW_CGC_EN		(1 << 1)
> @@ -83,6 +96,9 @@ enum {
>  #define TMRLUT_HW_CGC_EN	(1 << 6)
>  #define OCSC_HW_CGC_EN		(1 << 7)
>
> +/* bit definition for UFS_UFS_TEST_BUS_CTRL_n */
> +#define TEST_BUS_SUB_SEL_MASK	0x1F  /* All XXX_SEL fields are 5 bits wide
> */
> +
>  #define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\
>  				 TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\
>  				 DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\
> @@ -106,6 +122,15 @@ enum ufs_qcom_phy_init_type {
>  	UFS_PHY_INIT_CFG_RESTORE,
>  };
>
> +/* QCOM UFS debug print bit mask */
> +#define UFS_QCOM_DBG_PRINT_REGS_EN	BIT(0)
> +#define UFS_QCOM_DBG_PRINT_ICE_REGS_EN	BIT(1)
> +#define UFS_QCOM_DBG_PRINT_TEST_BUS_EN	BIT(2)
> +
> +#define UFS_QCOM_DBG_PRINT_ALL	\
> +	(UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_ICE_REGS_EN | \
> +	 UFS_QCOM_DBG_PRINT_TEST_BUS_EN)
> +
>  static inline void
>  ufs_qcom_get_controller_revision(struct ufs_hba *hba,
>  				 u8 *major, u16 *minor, u16 *step)
> @@ -157,8 +182,13 @@ struct ufs_hw_version {
>  	u16 minor;
>  	u8 major;
>  };
> -struct ufs_qcom_host {
>
> +struct ufs_qcom_testbus {
> +	u8 select_major;
> +	u8 select_minor;
> +};
> +
> +struct ufs_qcom_host {
>  	/*
>  	 * Set this capability if host controller supports the QUniPro mode
>  	 * and if driver wants the Host controller to operate in QUniPro mode.
> @@ -179,12 +209,17 @@ struct ufs_qcom_host {
>  	bool is_lane_clks_enabled;
>
>  	struct ufs_hw_version hw_ver;
> +	/* Bitmask for enabling debug prints */
> +	u32 dbg_print_en;
> +	struct ufs_qcom_testbus testbus;
>  };
>
>  #define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba)
>  #define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)
>  #define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
>
> +int ufs_qcom_testbus_config(struct ufs_qcom_host *host);
> +
>  static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_host *host)
>  {
>  	if (host->caps & UFS_QCOM_CAP_QUNIPRO)
> diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
> index 2ef9834..52f9dad 100644
> --- a/drivers/scsi/ufs/ufshcd.c
> +++ b/drivers/scsi/ufs/ufshcd.c
> @@ -625,6 +625,7 @@ start:
>  out:
>  	return rc;
>  }
> +EXPORT_SYMBOL_GPL(ufshcd_hold);
>
>  static void ufshcd_gate_work(struct work_struct *work)
>  {
> @@ -712,6 +713,7 @@ void ufshcd_release(struct ufs_hba *hba)
>  	__ufshcd_release(hba);
>  	spin_unlock_irqrestore(hba->host->host_lock, flags);
>  }
> +EXPORT_SYMBOL_GPL(ufshcd_release);
>
>  static ssize_t ufshcd_clkgate_delay_show(struct device *dev,
>  		struct device_attribute *attr, char *buf)
> diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
> index f2aa47e..471c667 100644
> --- a/drivers/scsi/ufs/ufshcd.h
> +++ b/drivers/scsi/ufs/ufshcd.h
> @@ -259,6 +259,7 @@ struct ufs_pwr_mode_info {
>   *			to be set.
>   * @suspend: called during host controller PM callback
>   * @resume: called during host controller PM callback
> + * @dbg_register_dump: used to dump controller debug information
>   */
>  struct ufs_hba_variant_ops {
>  	const char *name;
> @@ -275,6 +276,7 @@ struct ufs_hba_variant_ops {
>  					struct ufs_pa_layer_attr *);
>  	int     (*suspend)(struct ufs_hba *, enum ufs_pm_op);
>  	int     (*resume)(struct ufs_hba *, enum ufs_pm_op);
> +	void	(*dbg_register_dump)(struct ufs_hba *hba);
>  };
>
>  /* clock gating state  */
> @@ -773,4 +775,10 @@ static inline int ufshcd_vops_resume(struct ufs_hba
> *hba, enum ufs_pm_op op)
>  	return 0;
>  }
>
> +static inline void ufshcd_vops_dbg_register_dump(struct ufs_hba *hba)
> +{
> +	if (hba->vops && hba->vops->dbg_register_dump)
> +		hba->vops->dbg_register_dump(hba);
> +}
> +
>  #endif /* End of Header */
> --
> 1.8.5.2
>
> --
> QUALCOMM ISRAEL, on behalf of Qualcomm Innovation Center, Inc. is a member
> of Code Aurora Forum, hosted by The Linux Foundation
> --
> To unsubscribe from this list: send the line "unsubscribe linux-scsi" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


--
To unsubscribe from this list: send the line "unsubscribe linux-arm-msm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [Linux for Sparc]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux