From 38a5ecb756e217a80ed951747797ab150449ee9b Mon Sep 17 00:00:00 2001 From: Channagoud kadabi Date: Mon, 14 Mar 2022 18:56:03 -0700 Subject: [PATCH] fix(ufs): fix cache maintenance issues Fix software cache maintenance issues that can happen when cpu prefetches data before DMA operations are complete. This change fixes two cases one for ufs_read_blocks and other for ufs_check_resp, in both cases invalidation of buffer was done before the DMA operation completed. This caused cpu prefetcher to bring data into cache before DMA completed and caused UFS read failures. The changes also removes unwanted cache operations to local variable utrd which is not consumed by UFS host controller and zeroing out buffer in ufs_read_capacity. Change-Id: I9a288eb19d6705f6fa8bdb0b817a6411235fd8b6 Signed-off-by: Channagoud kadabi --- drivers/ufs/ufs.c | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 3d6d99fb0..be6bc4a65 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -356,7 +356,6 @@ static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun, hd->prdto = (utrd->size_upiu + utrd->size_resp_upiu) >> 2; } - flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t)); flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE); return 0; } @@ -415,7 +414,6 @@ static int ufs_prepare_query(utp_utrd_t *utrd, uint8_t op, uint8_t idn, assert(0); break; } - flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t)); flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE); return 0; } @@ -439,7 +437,6 @@ static void ufs_prepare_nop_out(utp_utrd_t *utrd) nop_out->trans_type = 0; nop_out->task_tag = utrd->task_tag; - flush_dcache_range((uintptr_t)utrd, sizeof(utp_utrd_t)); flush_dcache_range((uintptr_t)utrd->header, UFS_DESC_SIZE); } @@ -473,7 +470,6 @@ static int ufs_check_resp(utp_utrd_t *utrd, int trans_type) hd = (utrd_header_t *)utrd->header; resp = (resp_upiu_t *)utrd->resp_upiu; - inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE); do { data = mmio_read_32(ufs_params.reg_base + IS); if ((data & ~(UFS_INT_UCCS | UFS_INT_UTRCS)) != 0) @@ -483,6 +479,12 @@ static int ufs_check_resp(utp_utrd_t *utrd, int trans_type) data = mmio_read_32(ufs_params.reg_base + UTRLDBR); assert((data & (1 << slot)) == 0); + /* + * Invalidate the header after DMA read operation has + * completed to avoid cpu referring to the prefetched + * data brought in before DMA completion. + */ + inv_dcache_range((uintptr_t)hd, UFS_DESC_SIZE); assert(hd->ocs == OCS_SUCCESS); assert((resp->trans_type & TRANS_TYPE_CODE_MASK) == trans_type); (void)resp; @@ -660,8 +662,6 @@ static void ufs_read_capacity(int lun, unsigned int *num, unsigned int *size) buf = (uintptr_t)data; buf = (buf + CACHE_WRITEBACK_GRANULE - 1) & ~(CACHE_WRITEBACK_GRANULE - 1); - memset((void *)buf, 0, CACHE_WRITEBACK_GRANULE); - flush_dcache_range(buf, CACHE_WRITEBACK_GRANULE); do { get_utrd(&utrd); ufs_prepare_cmd(&utrd, CDBCMD_READ_CAPACITY_10, lun, 0, @@ -710,6 +710,11 @@ size_t ufs_read_blocks(int lun, int lba, uintptr_t buf, size_t size) #ifdef UFS_RESP_DEBUG dump_upiu(&utrd); #endif + /* + * Invalidate prefetched cache contents before cpu + * accesses the buf. + */ + inv_dcache_range(buf, size); resp = (resp_upiu_t *)utrd.resp_upiu; (void)result; return size - resp->res_trans_cnt;