Commit db59203d104bcd26d21218d817399b6a98eb49f5

Authored by pbrook
1 parent 1c46d713

ESP DMA fix.


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1926 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 50 additions and 20 deletions
hw/esp.c
... ... @@ -229,12 +229,17 @@ static int esp_write_dma_cb(ESPState *s,
229 229 target_phys_addr_t phys_addr,
230 230 int transfer_size1)
231 231 {
  232 + int len;
  233 + if (bdrv_get_type_hint(s->bd[s->target]) == BDRV_TYPE_CDROM) {
  234 + len = transfer_size1/2048;
  235 + } else {
  236 + len = transfer_size1/512;
  237 + }
232 238 DPRINTF("Write callback (offset %lld len %lld size %d trans_size %d)\n",
233 239 s->offset, s->len, s->ti_size, transfer_size1);
234   - bdrv_write(s->bd[s->target], s->offset, s->ti_buf, s->len);
235   - s->offset = 0;
236   - s->len = 0;
237   - s->target = 0;
  240 +
  241 + bdrv_write(s->bd[s->target], s->offset, s->ti_buf+s->ti_rptr, len);
  242 + s->offset+=len;
238 243 return 0;
239 244 }
240 245  
... ... @@ -336,6 +341,7 @@ static void handle_satn(ESPState *s)
336 341 bdrv_read(s->bd[target], offset, s->ti_buf, len);
337 342 // XXX error handling
338 343 s->ti_dir = 1;
  344 + s->ti_rptr = 0;
339 345 break;
340 346 }
341 347 case 0x2a:
... ... @@ -359,6 +365,7 @@ static void handle_satn(ESPState *s)
359 365 s->offset = offset;
360 366 s->len = len;
361 367 s->target = target;
  368 + s->ti_rptr = 0;
362 369 // XXX error handling
363 370 s->ti_dir = 0;
364 371 break;
... ... @@ -415,10 +422,9 @@ static void handle_satn(ESPState *s)
415 422  
416 423 static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
417 424 {
418   - uint32_t dmaptr, dmalen;
  425 + uint32_t dmaptr;
419 426  
420   - dmalen = s->wregs[0] | (s->wregs[1] << 8);
421   - DPRINTF("Transfer status len %d\n", dmalen);
  427 + DPRINTF("Transfer status len %d\n", len);
422 428 if (s->dma) {
423 429 dmaptr = iommu_translate(s->espdmaregs[1]);
424 430 DPRINTF("DMA Direction: %c\n", s->espdmaregs[0] & 0x100? 'w': 'r');
... ... @@ -428,10 +434,10 @@ static void dma_write(ESPState *s, const uint8_t *buf, uint32_t len)
428 434 s->rregs[6] = SEQ_CD;
429 435 } else {
430 436 memcpy(s->ti_buf, buf, len);
431   - s->ti_size = dmalen;
  437 + s->ti_size = len;
432 438 s->ti_rptr = 0;
433 439 s->ti_wptr = 0;
434   - s->rregs[7] = dmalen;
  440 + s->rregs[7] = len;
435 441 }
436 442 s->espdmaregs[0] |= DMA_INTR;
437 443 pic_set_irq(s->irq, 1);
... ... @@ -442,34 +448,58 @@ static const uint8_t okbuf[] = {0, 0};
442 448  
443 449 static void handle_ti(ESPState *s)
444 450 {
445   - uint32_t dmaptr, dmalen;
  451 + uint32_t dmaptr, dmalen, minlen, len, from, to;
446 452 unsigned int i;
447 453  
448 454 dmalen = s->wregs[0] | (s->wregs[1] << 8);
449   - DPRINTF("Transfer Information len %d\n", dmalen);
  455 + if (dmalen==0) {
  456 + dmalen=0x10000;
  457 + }
  458 +
  459 + minlen = (dmalen < s->ti_size) ? dmalen : s->ti_size;
  460 + DPRINTF("Transfer Information len %d\n", minlen);
450 461 if (s->dma) {
451 462 dmaptr = iommu_translate(s->espdmaregs[1]);
452   - DPRINTF("DMA Direction: %c, addr 0x%8.8x\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr);
453   - for (i = 0; i < s->ti_size; i++) {
  463 + DPRINTF("DMA Direction: %c, addr 0x%8.8x %08x %d %d\n", s->espdmaregs[0] & 0x100? 'w': 'r', dmaptr, s->ti_size, s->ti_rptr, s->ti_dir);
  464 + from = s->espdmaregs[1];
  465 + to = from + minlen;
  466 + for (i = 0; i < minlen; i += len, from += len) {
454 467 dmaptr = iommu_translate(s->espdmaregs[1] + i);
  468 + if ((from & TARGET_PAGE_MASK) != (to & TARGET_PAGE_MASK)) {
  469 + len = TARGET_PAGE_SIZE - (from & ~TARGET_PAGE_MASK);
  470 + } else {
  471 + len = to - from;
  472 + }
  473 + DPRINTF("DMA address p %08x v %08x len %08x, from %08x, to %08x\n", dmaptr, s->espdmaregs[1] + i, len, from, to);
455 474 if (s->ti_dir)
456   - cpu_physical_memory_write(dmaptr, &s->ti_buf[i], 1);
  475 + cpu_physical_memory_write(dmaptr, &s->ti_buf[s->ti_rptr + i], len);
457 476 else
458   - cpu_physical_memory_read(dmaptr, &s->ti_buf[i], 1);
  477 + cpu_physical_memory_read(dmaptr, &s->ti_buf[s->ti_rptr + i], len);
459 478 }
460 479 if (s->dma_cb) {
461   - s->dma_cb(s, s->espdmaregs[1], dmalen);
  480 + s->dma_cb(s, s->espdmaregs[1], minlen);
  481 + }
  482 + if (minlen < s->ti_size) {
  483 + s->rregs[4] = STAT_IN | STAT_TC | (s->ti_dir ? STAT_DO : STAT_DI);
  484 + s->ti_size -= minlen;
  485 + s->ti_rptr += minlen;
  486 + } else {
  487 + s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
462 488 s->dma_cb = NULL;
  489 + s->offset = 0;
  490 + s->len = 0;
  491 + s->target = 0;
  492 + s->ti_rptr = 0;
463 493 }
464   - s->rregs[4] = STAT_IN | STAT_TC | STAT_ST;
465   - s->rregs[5] = INTR_BS;
  494 + s->rregs[5] = INTR_BS;
466 495 s->rregs[6] = 0;
  496 + s->rregs[7] = 0;
467 497 s->espdmaregs[0] |= DMA_INTR;
468 498 } else {
469   - s->ti_size = dmalen;
  499 + s->ti_size = minlen;
470 500 s->ti_rptr = 0;
471 501 s->ti_wptr = 0;
472   - s->rregs[7] = dmalen;
  502 + s->rregs[7] = minlen;
473 503 }
474 504 pic_set_irq(s->irq, 1);
475 505 }
... ...