diff mbox series

[02/13] ufs: fix dcache flush and invalidate range calculation

Message ID 20240910-topic-ufs-enhancements-v1-2-3ee0bffacc64@linaro.org
State Accepted
Delegated to: Tom Rini
Headers show
Series ufs: enhancements to support Qualcomm UFS controllers | expand

Commit Message

Neil Armstrong Sept. 10, 2024, 9:20 a.m. UTC
The current calculation will omit doing a flush/invalidate on the last
cacheline if the base address is not aligned with DMA_MINALIGN.

This causes commands failures and write corruptions on Qualcomm
platforms.

Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
---
 drivers/ufs/ufs.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

Comments

Neha Malcom Francis Sept. 10, 2024, 11:14 a.m. UTC | #1
On 10/09/24 14:50, Neil Armstrong wrote:
> The current calculation will omit doing a flush/invalidate on the last
> cacheline if the base address is not aligned with DMA_MINALIGN.
> 
> This causes commands failures and write corruptions on Qualcomm
> platforms.
> 
> Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>
> ---
>   drivers/ufs/ufs.c | 16 ++++++++--------
>   1 file changed, 8 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
> index e005cc90608..3d9a7d7ee12 100644
> --- a/drivers/ufs/ufs.c
> +++ b/drivers/ufs/ufs.c
> @@ -703,11 +703,11 @@ static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
>    */
>   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);
> +	uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1);
> +	uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN);
>   
> -	flush_dcache_range(aaddr, aaddr + asize);
> -	invalidate_dcache_range(aaddr, aaddr + asize);
> +	flush_dcache_range(start_addr, end_addr);
> +	invalidate_dcache_range(start_addr, end_addr);
>   }
>   
>   /**
> @@ -1466,13 +1466,13 @@ static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
>   	}
>   
>   	if (pccb->dma_dir == DMA_TO_DEVICE) {	/* Write to device */
> -		flush_dcache_range(aaddr, aaddr +
> -				   ALIGN(datalen, ARCH_DMA_MINALIGN));
> +		flush_dcache_range(aaddr,
> +				   ALIGN((uintptr_t)pccb->pdata + 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));
> +	invalidate_dcache_range(aaddr,
> +				ALIGN((uintptr_t)pccb->pdata + datalen, ARCH_DMA_MINALIGN));
>   
>   	table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY);
>   	buf = pccb->pdata;
> 

Reviewed-by: Neha Malcom Francis <n-francis@ti.com>
diff mbox series

Patch

diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index e005cc90608..3d9a7d7ee12 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -703,11 +703,11 @@  static inline u8 ufshcd_get_upmcrs(struct ufs_hba *hba)
  */
 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);
+	uintptr_t start_addr = (uintptr_t)addr & ~(ARCH_DMA_MINALIGN - 1);
+	uintptr_t end_addr = ALIGN((uintptr_t)addr + size, ARCH_DMA_MINALIGN);
 
-	flush_dcache_range(aaddr, aaddr + asize);
-	invalidate_dcache_range(aaddr, aaddr + asize);
+	flush_dcache_range(start_addr, end_addr);
+	invalidate_dcache_range(start_addr, end_addr);
 }
 
 /**
@@ -1466,13 +1466,13 @@  static void prepare_prdt_table(struct ufs_hba *hba, struct scsi_cmd *pccb)
 	}
 
 	if (pccb->dma_dir == DMA_TO_DEVICE) {	/* Write to device */
-		flush_dcache_range(aaddr, aaddr +
-				   ALIGN(datalen, ARCH_DMA_MINALIGN));
+		flush_dcache_range(aaddr,
+				   ALIGN((uintptr_t)pccb->pdata + 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));
+	invalidate_dcache_range(aaddr,
+				ALIGN((uintptr_t)pccb->pdata + datalen, ARCH_DMA_MINALIGN));
 
 	table_length = DIV_ROUND_UP(pccb->datalen, MAX_PRDT_ENTRY);
 	buf = pccb->pdata;