| From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
| From: Eric Biggers <ebiggers@google.com> |
| Date: Mon, 24 Feb 2020 14:37:12 -0800 |
| Subject: ONHOLD: ANDROID: scsi: ufs: allow ufs variants to override 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). |
| |
| [CPNOTE: 19/07/21] Lee: Requested status from Eric via the bug |
| [CPNOTE: 21/07/21] Lee: Upstream when "hardware key manager" user appears upstream |
| |
| Bug: 129991660 |
| Bug: 162257402 |
| Change-Id: I6ab9458d5c23331013e6b736d6fea378a6b5b86c |
| Signed-off-by: Eric Biggers <ebiggers@google.com> |
| --- |
| drivers/scsi/ufs/ufshcd.c | 34 ++++++++++++++++++---------------- |
| drivers/scsi/ufs/ufshcd.h | 2 ++ |
| drivers/scsi/ufs/ufshci.h | 12 ++++++++++-- |
| 3 files changed, 30 insertions(+), 18 deletions(-) |
| |
| diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c |
| --- a/drivers/scsi/ufs/ufshcd.c |
| +++ b/drivers/scsi/ufs/ufshcd.c |
| @@ -506,7 +506,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 /= sizeof(struct ufshcd_sg_entry); |
| + prdt_length /= hba->sg_entry_size; |
| |
| dev_err(hba->dev, |
| "UPIU[%d] - PRDT - %d entries phys@0x%llx\n", |
| @@ -515,7 +515,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, |
| - sizeof(struct ufshcd_sg_entry) * prdt_length); |
| + hba->sg_entry_size * prdt_length); |
| } |
| } |
| |
| @@ -2358,7 +2358,7 @@ int ufshcd_send_uic_cmd(struct ufs_hba *hba, struct uic_command *uic_cmd) |
| */ |
| static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) |
| { |
| - struct ufshcd_sg_entry *prd_table; |
| + struct ufshcd_sg_entry *prd; |
| struct scatterlist *sg; |
| struct scsi_cmnd *cmd; |
| int sg_segments; |
| @@ -2373,13 +2373,12 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) |
| |
| if (hba->quirks & UFSHCD_QUIRK_PRDT_BYTE_GRAN) |
| lrbp->utr_descriptor_ptr->prd_table_length = |
| - cpu_to_le16((sg_segments * |
| - sizeof(struct ufshcd_sg_entry))); |
| + cpu_to_le16(sg_segments * hba->sg_entry_size); |
| else |
| lrbp->utr_descriptor_ptr->prd_table_length = |
| cpu_to_le16(sg_segments); |
| |
| - prd_table = lrbp->ucd_prdt_ptr; |
| + prd = (struct ufshcd_sg_entry *)lrbp->ucd_prdt_ptr; |
| |
| scsi_for_each_sg(cmd, sg, sg_segments, i) { |
| const unsigned int len = sg_dma_len(sg); |
| @@ -2393,9 +2392,10 @@ static int ufshcd_map_sg(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) |
| * indicates 4 bytes, '7' indicates 8 bytes, etc." |
| */ |
| WARN_ONCE(len > 256 * 1024, "len = %#x\n", len); |
| - prd_table[i].size = cpu_to_le32(len - 1); |
| - prd_table[i].addr = cpu_to_le64(sg->dma_address); |
| - prd_table[i].reserved = 0; |
| + 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; |
| } |
| } else { |
| lrbp->utr_descriptor_ptr->prd_table_length = 0; |
| @@ -2663,10 +2663,11 @@ static inline bool is_device_wlun(struct scsi_device *sdev) |
| |
| static void ufshcd_init_lrb(struct ufs_hba *hba, struct ufshcd_lrb *lrb, int i) |
| { |
| - struct utp_transfer_cmd_desc *cmd_descp = hba->ucdl_base_addr; |
| + struct utp_transfer_cmd_desc *cmd_descp = (void *)hba->ucdl_base_addr + |
| + i * sizeof_utp_transfer_cmd_desc(hba); |
| struct utp_transfer_req_desc *utrdlp = hba->utrdl_base_addr; |
| dma_addr_t cmd_desc_element_addr = hba->ucdl_dma_addr + |
| - i * sizeof(struct utp_transfer_cmd_desc); |
| + i * sizeof_utp_transfer_cmd_desc(hba); |
| u16 response_offset = offsetof(struct utp_transfer_cmd_desc, |
| response_upiu); |
| u16 prdt_offset = offsetof(struct utp_transfer_cmd_desc, prd_table); |
| @@ -2674,11 +2675,11 @@ 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 + i); |
| + lrb->ucd_req_ptr = (struct utp_upiu_req *)cmd_descp; |
| lrb->ucd_req_dma_addr = cmd_desc_element_addr; |
| - lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp[i].response_upiu; |
| + lrb->ucd_rsp_ptr = (struct utp_upiu_rsp *)cmd_descp->response_upiu; |
| lrb->ucd_rsp_dma_addr = cmd_desc_element_addr + response_offset; |
| - lrb->ucd_prdt_ptr = cmd_descp[i].prd_table; |
| + lrb->ucd_prdt_ptr = (struct ufshcd_sg_entry *)cmd_descp->prd_table; |
| lrb->ucd_prdt_dma_addr = cmd_desc_element_addr + prdt_offset; |
| } |
| |
| @@ -3583,7 +3584,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(struct utp_transfer_cmd_desc) * 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, |
| @@ -3677,7 +3678,7 @@ static void ufshcd_host_memory_configure(struct ufs_hba *hba) |
| prdt_offset = |
| offsetof(struct utp_transfer_cmd_desc, prd_table); |
| |
| - cmd_desc_size = sizeof(struct utp_transfer_cmd_desc); |
| + cmd_desc_size = sizeof_utp_transfer_cmd_desc(hba); |
| cmd_desc_dma_addr = hba->ucdl_dma_addr; |
| |
| for (i = 0; i < hba->nutrs; i++) { |
| @@ -9450,6 +9451,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); |
| INIT_LIST_HEAD(&hba->clk_list_head); |
| spin_lock_init(&hba->outstanding_lock); |
| |
| diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h |
| --- a/drivers/scsi/ufs/ufshcd.h |
| +++ b/drivers/scsi/ufs/ufshcd.h |
| @@ -754,6 +754,7 @@ struct ufs_hba_monitor { |
| * @ufs_version: UFS Version to which controller complies |
| * @vops: pointer to variant specific operations |
| * @priv: pointer to variant specific private data |
| + * @sg_entry_size: size of struct ufshcd_sg_entry (may include variant fields) |
| * @irq: Irq number of the controller |
| * @active_uic_cmd: handle of active UIC command |
| * @uic_cmd_mutex: mutex for UIC command |
| @@ -847,6 +848,7 @@ struct ufs_hba { |
| const struct ufs_hba_variant_ops *vops; |
| struct ufs_hba_variant_params *vps; |
| void *priv; |
| + size_t sg_entry_size; |
| unsigned int irq; |
| bool is_irq_enabled; |
| enum ufs_ref_clk_freq dev_ref_clk_freq; |
| diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h |
| --- a/drivers/scsi/ufs/ufshci.h |
| +++ b/drivers/scsi/ufs/ufshci.h |
| @@ -423,20 +423,28 @@ struct ufshcd_sg_entry { |
| __le64 addr; |
| __le32 reserved; |
| __le32 size; |
| + /* |
| + * followed by variant-specific fields if |
| + * hba->sg_entry_size != sizeof(struct ufshcd_sg_entry) |
| + */ |
| }; |
| |
| /** |
| * struct utp_transfer_cmd_desc - UTP Command Descriptor (UCD) |
| * @command_upiu: Command UPIU Frame address |
| * @response_upiu: Response UPIU Frame address |
| - * @prd_table: Physical Region Descriptor |
| + * @prd_table: Physical Region Descriptor: an array of SG_ALL struct |
| + * ufshcd_sg_entry's. Variant-specific fields may be present after each. |
| */ |
| struct utp_transfer_cmd_desc { |
| u8 command_upiu[ALIGNED_UPIU_SIZE]; |
| u8 response_upiu[ALIGNED_UPIU_SIZE]; |
| - struct ufshcd_sg_entry prd_table[SG_ALL]; |
| + 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 |