From: Can Guo <quic_cang@xxxxxxxxxxx> As Event Specific Interrupt message format is not defined in UFSHCI JEDEC specs, and the ESI handling highly depends on how the format is designed, hence add a vendor specific ops such that SoC vendors can configure their own ESI handlers. If ESI vops is not provided or returning error, go with the legacy (central) interrupt way. Added APIs to enable ESI and config ESI base addresses. Signed-off-by: Can Guo <quic_cang@xxxxxxxxxxx> --- drivers/ufs/core/ufs-mcq.c | 14 ++++++++++++++ drivers/ufs/core/ufshcd-priv.h | 8 ++++++++ drivers/ufs/core/ufshcd.c | 6 ++++++ include/ufs/ufshcd.h | 5 +++++ 4 files changed, 33 insertions(+) diff --git a/drivers/ufs/core/ufs-mcq.c b/drivers/ufs/core/ufs-mcq.c index e23557b..7f95754 100644 --- a/drivers/ufs/core/ufs-mcq.c +++ b/drivers/ufs/core/ufs-mcq.c @@ -457,3 +457,17 @@ unsigned long ufshcd_mcq_poll_cqe_lock(struct ufs_hba *hba, return completed_reqs; } + +void ufshcd_mcq_enable_esi(struct ufs_hba *hba) +{ + ufshcd_writel(hba, ufshcd_readl(hba, REG_UFS_MEM_CFG) | 0x2, + REG_UFS_MEM_CFG); +} +EXPORT_SYMBOL_GPL(ufshcd_mcq_enable_esi); + +void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg) +{ + ufshcd_writel(hba, msg->address_lo, REG_UFS_ESILBA); + ufshcd_writel(hba, msg->address_hi, REG_UFS_ESIUBA); +} +EXPORT_SYMBOL_GPL(ufshcd_mcq_config_esi); diff --git a/drivers/ufs/core/ufshcd-priv.h b/drivers/ufs/core/ufshcd-priv.h index 4e9e2755..b709695 100644 --- a/drivers/ufs/core/ufshcd-priv.h +++ b/drivers/ufs/core/ufshcd-priv.h @@ -254,6 +254,14 @@ static inline int ufshcd_mcq_vops_get_hba_mac(struct ufs_hba *hba) return -EOPNOTSUPP; } +static inline int ufshcd_mcq_vops_config_esi(struct ufs_hba *hba) +{ + if (hba->vops && hba->vops->config_esi) + return hba->vops->config_esi(hba); + + return -EOPNOTSUPP; +} + static inline void ufshcd_inc_tp(struct ufs_hw_queue *q) { u32 mask = q->max_entries - 1; diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index ec40d46..f5bb0eb 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -8306,6 +8306,12 @@ static int ufshcd_config_mcq(struct ufs_hba *hba) goto err; } + ret = ufshcd_mcq_vops_config_esi(hba); + if (ret) { + dev_info(hba->dev, "MCQ ESI not available %d\n", ret); + ret = 0; + } + ufshcd_enable_intr(hba, UFSHCD_ENABLE_MCQ_INTRS); ufshcd_mcq_make_queues_operational(hba); ufshcd_mcq_config_mac(hba, hba->nutrs); diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 8c10b09..71bab73 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -16,6 +16,7 @@ #include <linux/blk-crypto-profile.h> #include <linux/blk-mq.h> #include <linux/devfreq.h> +#include <linux/msi.h> #include <linux/pm_runtime.h> #include <scsi/scsi_device.h> #include <ufs/unipro.h> @@ -297,6 +298,7 @@ struct ufs_pwr_mode_info { * @get_outstanding_cqs: called to get outstanding completion queues * @config_queues: called to config Runtime Operation Pointers * @get_hba_mac: called to get vendor specific mac value + * @config_esi: called to config Event Specific Interrupt */ struct ufs_hba_variant_ops { const char *name; @@ -339,6 +341,7 @@ struct ufs_hba_variant_ops { unsigned long *ocqs); int (*config_queues)(struct ufs_hba *hba); int (*get_hba_mac)(struct ufs_hba *hba); + int (*config_esi)(struct ufs_hba *hba); }; /* clock gating state */ @@ -1230,6 +1233,8 @@ extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, extern int ufshcd_config_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *desired_pwr_mode); extern int ufshcd_uic_change_pwr_mode(struct ufs_hba *hba, u8 mode); +extern void ufshcd_mcq_enable_esi(struct ufs_hba *hba); +extern void ufshcd_mcq_config_esi(struct ufs_hba *hba, struct msi_msg *msg); /* UIC command interfaces for DME primitives */ #define DME_LOCAL 0 -- 2.7.4