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 <jatron@google.com>
Change-Id: I960771e6ce57002872392993042fae9ec505447e
This commit is contained in:
Jorge Troncoso 2023-02-22 15:30:47 -08:00
parent 83ef8698f9
commit 20fdbcf502
2 changed files with 7 additions and 10 deletions

View file

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

View file

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