On 15/7/26 18:07, Tao Ding wrote:
During SDMA transfers, the controller raises an interrupt at buffer boundaries
to request a system address update. The host driver will rewrite the SDHC_SYSAD
register.
(according to PartA2_SD_Host_Controller_Simplified_Specification_Ver2.00.pdf
section 2.2.1)
However, the current code will ignore write operations to SDHC_SYSAD.
To fix this bug, when SDMA encounters a boundary, a state is set to record it.
In this state, SDHC_SYSAD can be written. In other cases, it is still protected
by TRANSFERRING_DATA.
Meanwhile, a subsection has been added for migration.
Suggested-by: Bin Meng <[email protected]>
Signed-off-by: Tao Ding <[email protected]>
---
+static bool sdhci_sdma_transfer_active(SDHCIState *s)
+{
+ return TRANSFERRING_DATA(s->prnsts) &&
+ (s->trnmod & SDHC_TRNS_DMA) &&
+ s->blkcnt &&
+ (s->blksize & BLOCK_SIZE_MASK) &&
+ SDHC_DMA_TYPE(s->hostctl1) == SDHC_CTRL_SDMA;
+}
@@ -1185,7 +1198,7 @@ sdhci_write(void *opaque, hwaddr offset, uint64_t val,
unsigned size)
switch (offset & ~0x3) {
case SDHC_SYSAD:
- if (!TRANSFERRING_DATA(s->prnsts)) {
+ if (!TRANSFERRING_DATA(s->prnsts) || s->sdma_boundary_paused) {
s->sdmasysad = (s->sdmasysad & mask) | value;
MASKED_WRITE(s->sdmasysad, mask, value);
/* Writing to last byte of sdmasysad might trigger transfer */
So the SYSAD write-protection guard didn't account for the
boundary-pause state, silently dropping the driver's continuation write
and stalling SDMA transfers forever once a boundary was crossed, OK.
Series queued!