]>
Commit | Line | Data |
---|---|---|
7fd7e00b WB |
1 | From da4c6050712be98934918e348aa34a74be0e4e57 Mon Sep 17 00:00:00 2001 |
2 | From: Prasad J Pandit <pjp@fedoraproject.org> | |
3 | Date: Tue, 31 Jan 2017 17:54:15 +0530 | |
4 | Subject: [PATCH 3/8] sd: sdhci: check transfer mode register in multi block | |
5 | transfer | |
6 | ||
7 | In SDHCI device emulation the transfer mode register value | |
8 | is used during multi block transfer to check if block count | |
9 | register is enabled and should be updated. Transfer mode | |
10 | register could be set such that, block count register would | |
11 | not be updated, thus leading to an infinite loop. Add check | |
12 | to avoid it. | |
13 | ||
14 | Reported-by: Wjjzhang <wjjzhang@tencent.com> | |
15 | Reported-by: Jiang Xin <jiangxin1@huawei.com> | |
16 | Signed-off-by: Prasad J Pandit <pjp@fedoraproject.org> | |
17 | --- | |
18 | hw/sd/sdhci.c | 13 +++++++------ | |
19 | 1 file changed, 7 insertions(+), 6 deletions(-) | |
20 | ||
21 | diff --git a/hw/sd/sdhci.c b/hw/sd/sdhci.c | |
22 | index 01fbf22..35f953a 100644 | |
23 | --- a/hw/sd/sdhci.c | |
24 | +++ b/hw/sd/sdhci.c | |
25 | @@ -486,6 +486,12 @@ static void sdhci_sdma_transfer_multi_blocks(SDHCIState *s) | |
26 | uint32_t boundary_chk = 1 << (((s->blksize & 0xf000) >> 12) + 12); | |
27 | uint32_t boundary_count = boundary_chk - (s->sdmasysad % boundary_chk); | |
28 | ||
29 | + if (!(s->trnmod & SDHC_TRNS_MULTI) | |
30 | + || !(s->trnmod & SDHC_TRNS_BLK_CNT_EN) | |
31 | + || !s->blkcnt) { | |
32 | + return; | |
33 | + } | |
34 | + | |
35 | /* XXX: Some sd/mmc drivers (for example, u-boot-slp) do not account for | |
36 | * possible stop at page boundary if initial address is not page aligned, | |
37 | * allow them to work properly */ | |
38 | @@ -797,11 +803,6 @@ static void sdhci_data_transfer(void *opaque) | |
39 | if (s->trnmod & SDHC_TRNS_DMA) { | |
40 | switch (SDHC_DMA_TYPE(s->hostctl)) { | |
41 | case SDHC_CTRL_SDMA: | |
42 | - if ((s->trnmod & SDHC_TRNS_MULTI) && | |
43 | - (!(s->trnmod & SDHC_TRNS_BLK_CNT_EN) || s->blkcnt == 0)) { | |
44 | - break; | |
45 | - } | |
46 | - | |
47 | if ((s->blkcnt == 1) || !(s->trnmod & SDHC_TRNS_MULTI)) { | |
48 | sdhci_sdma_transfer_single_block(s); | |
49 | } else { | |
50 | @@ -1050,7 +1051,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val, unsigned size) | |
51 | if (!(s->capareg & SDHC_CAN_DO_DMA)) { | |
52 | value &= ~SDHC_TRNS_DMA; | |
53 | } | |
54 | - MASKED_WRITE(s->trnmod, mask, value); | |
55 | + MASKED_WRITE(s->trnmod, mask, value & 0x0037); | |
56 | MASKED_WRITE(s->cmdreg, mask >> 16, value >> 16); | |
57 | ||
58 | /* Writing to the upper byte of CMDREG triggers SD command generation */ | |
59 | -- | |
60 | 2.1.4 | |
61 |