[PATCH v2 7/7] ufs: Implement cache management
Bhupesh Sharma
bhupesh.sharma at linaro.org
Tue Aug 22 06:10:19 CEST 2023
On 8/16/23 8:35 PM, Marek Vasut wrote:
> Add function to flush and invalidate cache over request and response
> queue entries, and perform flush and optional invalidate over block
> layer data that are passed into the UFS layer. This makes it possible
> to use UFS with caches enabled.
>
> Signed-off-by: Marek Vasut <marek.vasut+renesas at mailbox.org>
> ---
> Cc: Bhupesh Sharma <bhupesh.sharma at linaro.org>
> Cc: Faiz Abbas <faiz_abbas at ti.com>
> ---
> V2: No change
> ---
> drivers/ufs/ufs.c | 42 +++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 41 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
> index 041caee714f..7c48d57f99d 100644
> --- a/drivers/ufs/ufs.c
> +++ b/drivers/ufs/ufs.c
> @@ -692,6 +692,21 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
> return (ufshcd_readl(hba, REG_CONTROLLER_STATUS) >> 8) & 0x7;
> }
>
> +/**
> + * ufshcd_cache_flush_and_invalidate - Flush and invalidate cache
> + *
> + * Flush and invalidate cache in aligned address..address+size range.
> + * The invalidation is in place to avoid stale data in cache.
> + */
> +static void ufshcd_cache_flush_and_invalidate(void *addr, unsigned long size)
> +{
> + uintptr_t aaddr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1);
> + unsigned long asize = ALIGN(size, ARCH_DMA_MINALIGN);
> +
> + flush_dcache_range(aaddr, aaddr + asize);
> + invalidate_dcache_range(aaddr, aaddr + asize);
> +}
> +
> /**
> * ufshcd_prepare_req_desc_hdr() - Fills the requests header
> * descriptor according to request
> @@ -735,6 +750,8 @@ static void ufshcd_prepare_req_desc_hdr(struct ufs_hba *hba,
> req_desc->header.dword_3 = 0;
>
> req_desc->prd_table_length = 0;
> +
> + ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc));
> }
>
> static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
> @@ -763,10 +780,15 @@ static void ufshcd_prepare_utp_query_req_upiu(struct ufs_hba *hba,
> memcpy(&ucd_req_ptr->qr, &query->request.upiu_req, QUERY_OSF_SIZE);
>
> /* Copy the Descriptor */
> - if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC)
> + if (query->request.upiu_req.opcode == UPIU_QUERY_OPCODE_WRITE_DESC) {
> memcpy(ucd_req_ptr + 1, query->descriptor, len);
> + ufshcd_cache_flush_and_invalidate(ucd_req_ptr, 2 * sizeof(*ucd_req_ptr));
> + } else {
> + ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr));
> + }
>
> memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
> + ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr));
> }
>
> static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba)
> @@ -783,6 +805,9 @@ static inline void ufshcd_prepare_utp_nop_upiu(struct ufs_hba *hba)
> ucd_req_ptr->header.dword_2 = 0;
>
> memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
> +
> + ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr));
> + ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr));
> }
>
> /**
> @@ -1409,6 +1434,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufs_hba *hba,
> memcpy(ucd_req_ptr->sc.cdb, pccb->cmd, cdb_len);
>
> memset(hba->ucd_rsp_ptr, 0, sizeof(struct utp_upiu_rsp));
> + ufshcd_cache_flush_and_invalidate(ucd_req_ptr, sizeof(*ucd_req_ptr));
> + ufshcd_cache_flush_and_invalidate(hba->ucd_rsp_ptr, sizeof(*hba->ucd_rsp_ptr));
> }
>
> static inline void prepare_prdt_desc(struct ufshcd_sg_entry *entry,
> @@ -1423,6 +1450,7 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
> {
> struct utp_transfer_req_desc *req_desc = hba->utrdl;
> struct ufshcd_sg_entry *prd_table = hba->ucd_prdt_ptr;
> + uintptr_t aaddr = (uintptr_t)(pccb->pdata) & ~(ARCH_DMA_MINALIGN - 1);
> ulong datalen = pccb->datalen;
> int table_length;
> u8 *buf;
> @@ -1430,9 +1458,19 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
>
> if (!datalen) {
> req_desc->prd_table_length = 0;
> + ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc));
> return;
> }
>
> + if (pccb->dma_dir == DMA_TO_DEVICE) { /* Write to device */
> + flush_dcache_range(aaddr, aaddr +
> + ALIGN(datalen, ARCH_DMA_MINALIGN));
> + }
> +
> + /* In any case, invalidate cache to avoid stale data in it. */
> + invalidate_dcache_range(aaddr, aaddr +
> + ALIGN(datalen, ARCH_DMA_MINALIGN));
> +
> table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY);
> buf = pccb->pdata;
> i = table_length;
> @@ -1446,6 +1484,8 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
> prepare_prdt_desc(&prd_table[table_length - i - 1], buf, datalen - 1);
>
> req_desc->prd_table_length = table_length;
> + ufshcd_cache_flush_and_invalidate(prd_table, sizeof(*prd_table) * table_length);
> + ufshcd_cache_flush_and_invalidate(req_desc, sizeof(*req_desc));
> }
>
> static int ufs_scsi_exec(struct udevice *scsi_dev, struct scsi_cmd *pccb)
Reviewed-by: Bhupesh Sharma <bhupesh.sharma at linaro.org>
Tested-by: Bhupesh Sharma <bhupesh.sharma at linaro.org>
More information about the U-Boot
mailing list