@@ -232,7 +232,7 @@ static void sifive_pdma_write(void *opaque, hwaddr offset,
232
232
{
233
233
SiFivePDMAState * s = opaque ;
234
234
int ch = SIFIVE_PDMA_CHAN_NO (offset );
235
- bool claimed ;
235
+ bool claimed , run ;
236
236
237
237
if (ch >= SIFIVE_PDMA_CHANS ) {
238
238
qemu_log_mask (LOG_GUEST_ERROR , "%s: Invalid channel no %d\n" ,
@@ -244,6 +244,7 @@ static void sifive_pdma_write(void *opaque, hwaddr offset,
244
244
switch (offset ) {
245
245
case DMA_CONTROL :
246
246
claimed = !!(s -> chan [ch ].control & CONTROL_CLAIM );
247
+ run = !!(s -> chan [ch ].control & CONTROL_RUN );
247
248
248
249
if (!claimed && (value & CONTROL_CLAIM )) {
249
250
/* reset Next* registers */
@@ -254,13 +255,19 @@ static void sifive_pdma_write(void *opaque, hwaddr offset,
254
255
s -> chan [ch ].next_src = 0 ;
255
256
}
256
257
258
+ /* claim bit can only be cleared when run is low */
259
+ if (run && !(value & CONTROL_CLAIM )) {
260
+ value |= CONTROL_CLAIM ;
261
+ }
262
+
257
263
s -> chan [ch ].control = value ;
258
264
259
265
/*
260
266
* If channel was not claimed before run bit is set,
267
+ * or if the channel is disclaimed when run was low,
261
268
* DMA won't run.
262
269
*/
263
- if (!claimed ) {
270
+ if (!claimed || (! run && !( value & CONTROL_CLAIM )) ) {
264
271
s -> chan [ch ].control &= ~CONTROL_RUN ;
265
272
return ;
266
273
}
0 commit comments