summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJorge Troncoso <jatron@google.com>2023-02-22 01:41:18 -0800
committerJorge Troncoso <jatron@google.com>2023-02-25 06:32:43 -0800
commit83ef8698f9d1477c892cad15b4e48574ed634903 (patch)
tree1a5e10a5a7a1225493ed02ccfc16bfefe9e93de6 /drivers
parent56db7b8b08d5bb350a02e1f794dc6eb02827917f (diff)
downloadarm-trusted-firmware-83ef8698f9d1477c892cad15b4e48574ed634903.tar.gz
fix(ufs): flush the entire PRDT
Previously, if the image being read exceeded 12,800 KB (or 50 PRDT entries of size 256 KB), the UFS driver would not flush the entire Physical Region Descriptor Table (PRDT). This would cause the UFS host controller to read empty PRDT entries, which eventually would make the system crash. This change updates the UFS driver to flush the entire PRDT, irrespective of the size of the image being read. This change also throws an error if the memory allocated for UFS descriptors is not sufficient to hold the entire Physical Region Descriptor Table (PRDT). Signed-off-by: Jorge Troncoso <jatron@google.com> Change-Id: I291dc62748992481be3cc156ce1474a6e3990ea9
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ufs/ufs.c17
1 files changed, 14 insertions, 3 deletions
diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c
index d6c893d3a..1fe0b0e1f 100644
--- a/drivers/ufs/ufs.c
+++ b/drivers/ufs/ufs.c
@@ -289,6 +289,8 @@ static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun,
unsigned int ulba;
unsigned int lba_cnt;
int prdt_size;
+ uintptr_t desc_limit;
+ size_t flush_size;
hd = (utrd_header_t *)utrd->header;
upiu = (cmd_upiu_t *)utrd->upiu;
@@ -342,17 +344,25 @@ static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun,
assert(0);
break;
}
- if (hd->dd == DD_IN)
+ if (hd->dd == DD_IN) {
flush_dcache_range(buf, length);
- else if (hd->dd == DD_OUT)
+ } else if (hd->dd == DD_OUT) {
inv_dcache_range(buf, length);
+ }
+
+ utrd->size_prdt = 0;
if (length) {
upiu->exp_data_trans_len = htobe32(length);
assert(lba_cnt <= UINT16_MAX);
prdt = (prdt_t *)utrd->prdt;
+ desc_limit = ufs_params.desc_base + ufs_params.desc_size;
prdt_size = 0;
while (length > 0) {
+ if ((uintptr_t)prdt + sizeof(prdt_t) > desc_limit) {
+ ERROR("UFS: Exceeded descriptor limit. Image is too large\n");
+ panic();
+ }
prdt->dba = (unsigned int)(buf & UINT32_MAX);
prdt->dbau = (unsigned int)((buf >> 32) & UINT32_MAX);
/* prdt->dbc counts from 0 */
@@ -372,7 +382,8 @@ 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->header, UFS_DESC_SIZE);
+ flush_size = utrd->prdt + utrd->size_prdt - utrd->header;
+ flush_dcache_range(utrd->header, flush_size);
return 0;
}