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 <kadabi@google.com>
This commit is contained in:
Channagoud kadabi 2022-03-14 18:56:03 -07:00
parent 29ba22e8ed
commit 38a5ecb756
1 changed files with 11 additions and 6 deletions

View File

@ -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;