From beae65628d875a28b85708cc41f2862477d70a98 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 5 Jan 2023 16:28:07 -0800 Subject: [PATCH] BACKPORT: FROMGIT: scsi: ufs: core: Allow UFS host drivers to override the sg entry size Modify the UFSHCD core to allow 'struct ufshcd_sg_entry' to be variable-length. The default is the standard length, but variants can override ufs_hba::sg_entry_size with a larger value if there are vendor-specific fields following the standard ones. This is needed to support inline encryption with ufs-exynos (FMP). Cc: Eric Biggers Reviewed-by: Avri Altman Change-Id: I4fa3303b0ed70951ea4ec345bb3d58c6a008917d Signed-off-by: Eric Biggers [ bvanassche: edited commit message and introduced CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE ] Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen Bug: 258234315 (cherry picked from commit ada1e653a5eae7361d95781ed812caa0c8e07dbb git://git.kernel.org/pub/scm/linux/kernel/git/mkp/scsi.git for-next) [ bvanassche: backported this patch to the Android kernel tree ] Signed-off-by: Bart Van Assche --- drivers/ufs/core/ufshcd-crypto.h | 2 +- drivers/ufs/core/ufshcd.c | 14 +++++++------- drivers/ufs/host/Kconfig | 4 ++++ include/ufs/ufshcd.h | 28 ++++++++++++++++++++++++++++ include/ufs/ufshci.h | 5 +---- 5 files changed, 41 insertions(+), 12 deletions(-) diff --git a/drivers/ufs/core/ufshcd-crypto.h b/drivers/ufs/core/ufshcd-crypto.h index 55c2a5dff60d..190195f131d7 100644 --- a/drivers/ufs/core/ufshcd-crypto.h +++ b/drivers/ufs/core/ufshcd-crypto.h @@ -47,7 +47,7 @@ static inline void ufshcd_crypto_clear_prdt(struct ufs_hba *hba, return; memzero_explicit(lrbp->ucd_prdt_ptr, - hba->sg_entry_size * scsi_sg_count(lrbp->cmd)); + ufshcd_sg_entry_size(hba) * scsi_sg_count(lrbp->cmd)); } bool ufshcd_crypto_enable(struct ufs_hba *hba); diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index eaf80baa5961..9d137f2d6def 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -538,7 +538,7 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt) prdt_length = le16_to_cpu( lrbp->utr_descriptor_ptr->prd_table_length); if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN) - prdt_length /= hba->sg_entry_size; + prdt_length /= ufshcd_sg_entry_size(hba); dev_err(hba->dev, "UPIU[%d] - PRDT - %d entries phys@0x%llx\n", @@ -547,7 +547,7 @@ void ufshcd_print_trs(struct ufs_hba *hba, unsigned long bitmap, bool pr_prdt) if (pr_prdt) ufshcd_hex_dump("UPIU PRDT: ", lrbp->ucd_prdt_ptr, - hba->sg_entry_size * prdt_length); + ufshcd_sg_entry_size(hba) * prdt_length); } } @@ -2470,7 +2470,7 @@ static void ufshcd_sgl_to_prdt(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, int if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN) lrbp->utr_descriptor_ptr->prd_table_length = - cpu_to_le16(sg_entries * hba->sg_entry_size); + cpu_to_le16(sg_entries * ufshcd_sg_entry_size(hba)); else lrbp->utr_descriptor_ptr->prd_table_length = cpu_to_le16(sg_entries); @@ -2491,7 +2491,7 @@ static void ufshcd_sgl_to_prdt(struct ufs_hba *hba, struct ufshcd_lrb *lrbp, int prd->size = cpu_to_le32(len - 1); prd->addr = cpu_to_le64(sg->dma_address); prd->reserved = 0; - prd = (void *)prd + hba->sg_entry_size; + prd = (void *)prd + ufshcd_sg_entry_size(hba); } } else { lrbp->utr_descriptor_ptr->prd_table_length = 0; @@ -2816,7 +2816,7 @@ static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i) lrb->utr_descriptor_ptr = utrdlp + i; lrb->utrd_dma_addr = hba->utrdl_dma_addr + i * sizeof(struct utp_transfer_req_desc); - lrb->ucd_req_ptr = (struct utp_upiu_req *)cmd_descp; + lrb->ucd_req_ptr = (struct utp_upiu_req *)cmd_descp->command_upiu; lrb->ucd_req_dma_addr = cmd_desc_element_addr; lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp->response_upiu; lrb->ucd_rsp_dma_addr = cmd_desc_element_addr + response_offset; @@ -3715,7 +3715,7 @@ static int ufshcd_memory_alloc(struct ufs_hba *hba) size_t utmrdl_size, utrdl_size, ucdl_size; /* Allocate memory for UTP command descriptors */ - ucdl_size = (sizeof_utp_transfer_cmd_desc(hba) * hba->nutrs); + ucdl_size = sizeof_utp_transfer_cmd_desc(hba) * hba->nutrs; hba->ucdl_base_addr = dmam_alloc_coherent(hba->dev, ucdl_size, &hba->ucdl_dma_addr, @@ -9829,7 +9829,7 @@ int ufshcd_alloc_host(struct device *dev, struct ufs_hba **hba_handle) hba->dev = dev; hba->dev_ref_clk_freq = REF_CLK_FREQ_INVAL; hba->nop_out_timeout = NOP_OUT_TIMEOUT; - hba->sg_entry_size = sizeof(struct ufshcd_sg_entry); + ufshcd_set_sg_entry_size(hba, sizeof(struct ufshcd_sg_entry)); INIT_LIST_HEAD(&hba->clk_list_head); spin_lock_init(&hba->outstanding_lock); diff --git a/drivers/ufs/host/Kconfig b/drivers/ufs/host/Kconfig index 4cc2dbd79ed0..7f01f453e792 100644 --- a/drivers/ufs/host/Kconfig +++ b/drivers/ufs/host/Kconfig @@ -124,3 +124,7 @@ config SCSI_UFS_EXYNOS Select this if you have UFS host controller on Samsung Exynos SoC. If unsure, say N. + +config SCSI_UFS_VARIABLE_SG_ENTRY_SIZE + bool + default y if SCSI_UFS_EXYNOS && SCSI_UFS_CRYPTO diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 44a76271a39d..ccd3b9902943 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -915,7 +915,9 @@ struct ufs_hba { const struct ufs_hba_variant_ops *vops; struct ufs_hba_variant_params *vps; void *priv; +#ifdef CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE size_t sg_entry_size; +#endif unsigned int irq; bool is_irq_enabled; enum ufs_ref_clk_freq dev_ref_clk_freq; @@ -1026,6 +1028,32 @@ struct ufs_hba { ANDROID_KABI_RESERVE(4); }; +#ifdef CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE +static inline size_t ufshcd_sg_entry_size(const struct ufs_hba *hba) +{ + return hba->sg_entry_size; +} + +static inline void ufshcd_set_sg_entry_size(struct ufs_hba *hba, size_t sg_entry_size) +{ + WARN_ON_ONCE(sg_entry_size < sizeof(struct ufshcd_sg_entry)); + hba->sg_entry_size = sg_entry_size; +} +#else +static inline size_t ufshcd_sg_entry_size(const struct ufs_hba *hba) +{ + return sizeof(struct ufshcd_sg_entry); +} + +#define ufshcd_set_sg_entry_size(hba, sg_entry_size) \ + ({ (void)(hba); BUILD_BUG_ON(sg_entry_size != sizeof(struct ufshcd_sg_entry)); }) +#endif + +static inline size_t sizeof_utp_transfer_cmd_desc(const struct ufs_hba *hba) +{ + return sizeof(struct utp_transfer_cmd_desc) + SG_ALL * ufshcd_sg_entry_size(hba); +} + /* Returns true if clocks can be gated. Otherwise false */ static inline bool ufshcd_is_clkgating_allowed(struct ufs_hba *hba) { diff --git a/include/ufs/ufshci.h b/include/ufs/ufshci.h index 0990cc97e198..9346efea3eb3 100644 --- a/include/ufs/ufshci.h +++ b/include/ufs/ufshci.h @@ -425,7 +425,7 @@ struct ufshcd_sg_entry { __le32 size; /* * followed by variant-specific fields if - * hba->sg_entry_size != sizeof(struct ufshcd_sg_entry) + * CONFIG_SCSI_UFS_VARIABLE_SG_ENTRY_SIZE has been defined. */ }; @@ -442,9 +442,6 @@ struct utp_transfer_cmd_desc { u8 prd_table[]; }; -#define sizeof_utp_transfer_cmd_desc(hba) \ - (sizeof(struct utp_transfer_cmd_desc) + SG_ALL * (hba)->sg_entry_size) - /** * struct request_desc_header - Descriptor Header common to both UTRD and UTMRD * @dword0: Descriptor Header DW0