From 20fdbcf502bd457a4b74ffa9a610d573594f1f6c Mon Sep 17 00:00:00 2001 From: Jorge Troncoso Date: Wed, 22 Feb 2023 15:30:47 -0800 Subject: [PATCH] fix(ufs): set the PRDT length field properly The PRDT length field contains the count of the entries in the PRDT. See JEDEC Standard No. 223E, section 6.1.1, "UTP Transfer Request Descriptor," page 66. Previously we were setting the PRDT length field to the number of bytes in the PRDT divided by four (the size in units of 32 bits). This was incorrect according to the spec. Signed-off-by: Jorge Troncoso Change-Id: I960771e6ce57002872392993042fae9ec505447e --- drivers/ufs/ufs.c | 15 ++++++--------- include/drivers/ufs.h | 2 +- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/ufs/ufs.c b/drivers/ufs/ufs.c index 1fe0b0e1f..60743740e 100644 --- a/drivers/ufs/ufs.c +++ b/drivers/ufs/ufs.c @@ -288,9 +288,8 @@ static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun, prdt_t *prdt; unsigned int ulba; unsigned int lba_cnt; - int prdt_size; uintptr_t desc_limit; - size_t flush_size; + uintptr_t prdt_end; hd = (utrd_header_t *)utrd->header; upiu = (cmd_upiu_t *)utrd->upiu; @@ -350,14 +349,13 @@ static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun, inv_dcache_range(buf, length); } - utrd->size_prdt = 0; + utrd->prdt_length = 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"); @@ -375,15 +373,14 @@ static int ufs_prepare_cmd(utp_utrd_t *utrd, uint8_t op, uint8_t lun, } buf += MAX_PRDT_SIZE; prdt++; - prdt_size += sizeof(prdt_t); + utrd->prdt_length++; } - utrd->size_prdt = ALIGN_8(prdt_size); - hd->prdtl = utrd->size_prdt >> 2; + hd->prdtl = utrd->prdt_length; hd->prdto = (utrd->size_upiu + utrd->size_resp_upiu) >> 2; } - flush_size = utrd->prdt + utrd->size_prdt - utrd->header; - flush_dcache_range(utrd->header, flush_size); + prdt_end = utrd->prdt + utrd->prdt_length * sizeof(prdt_t); + flush_dcache_range(utrd->header, prdt_end - utrd->header); return 0; } diff --git a/include/drivers/ufs.h b/include/drivers/ufs.h index 1cd1beeee..e4ec00d5c 100644 --- a/include/drivers/ufs.h +++ b/include/drivers/ufs.h @@ -519,7 +519,7 @@ typedef struct utp_utrd { uintptr_t prdt; size_t size_upiu; size_t size_resp_upiu; - size_t size_prdt; + size_t prdt_length; int task_tag; } utp_utrd_t; -- 2.39.5