Commit 862c928064cf0f079d81b24db932a093e49d101d
1 parent
3c4cf535
DB-DMA IDE asynchronous I/O
Signed-off-by: Laurent Vivier <Laurent@vivier.eu> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6681 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
112 additions
and
73 deletions
hw/ide.c
| ... | ... | @@ -3429,110 +3429,143 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, |
| 3429 | 3429 | |
| 3430 | 3430 | typedef struct MACIOIDEState { |
| 3431 | 3431 | IDEState ide_if[2]; |
| 3432 | - int stream_index; | |
| 3432 | + BlockDriverAIOCB *aiocb; | |
| 3433 | 3433 | } MACIOIDEState; |
| 3434 | 3434 | |
| 3435 | -static void pmac_atapi_read(DBDMA_io *io) | |
| 3435 | +static void pmac_ide_atapi_transfer_cb(void *opaque, int ret) | |
| 3436 | 3436 | { |
| 3437 | + DBDMA_io *io = opaque; | |
| 3437 | 3438 | MACIOIDEState *m = io->opaque; |
| 3438 | 3439 | IDEState *s = m->ide_if->cur_drive; |
| 3439 | - int ret, len; | |
| 3440 | - | |
| 3441 | - while (io->len > 0 && | |
| 3442 | - s->packet_transfer_size > 0) { | |
| 3443 | 3440 | |
| 3444 | - len = s->cd_sector_size; | |
| 3445 | - ret = cd_read_sector(s->bs, s->lba, s->io_buffer, len); | |
| 3446 | - if (ret < 0) { | |
| 3447 | - io->dma_end(io); | |
| 3448 | - ide_transfer_stop(s); | |
| 3449 | - ide_atapi_io_error(s, ret); | |
| 3450 | - return; | |
| 3451 | - } | |
| 3441 | + if (ret < 0) { | |
| 3442 | + m->aiocb = NULL; | |
| 3443 | + qemu_sglist_destroy(&s->sg); | |
| 3444 | + ide_atapi_io_error(s, ret); | |
| 3445 | + io->dma_end(opaque); | |
| 3446 | + return; | |
| 3447 | + } | |
| 3452 | 3448 | |
| 3453 | - if (len > io->len) | |
| 3454 | - len = io->len; | |
| 3449 | + if (s->io_buffer_size > 0) { | |
| 3450 | + m->aiocb = NULL; | |
| 3451 | + qemu_sglist_destroy(&s->sg); | |
| 3455 | 3452 | |
| 3456 | - cpu_physical_memory_write(io->addr, | |
| 3457 | - s->io_buffer + m->stream_index, len); | |
| 3453 | + s->packet_transfer_size -= s->io_buffer_size; | |
| 3458 | 3454 | |
| 3459 | - /* db-dma can ask for 512 bytes whereas block size is 2048... */ | |
| 3455 | + s->io_buffer_index += s->io_buffer_size; | |
| 3456 | + s->lba += s->io_buffer_index >> 11; | |
| 3457 | + s->io_buffer_index &= 0x7ff; | |
| 3458 | + } | |
| 3460 | 3459 | |
| 3461 | - m->stream_index += len; | |
| 3462 | - s->lba += m->stream_index / s->cd_sector_size; | |
| 3463 | - m->stream_index %= s->cd_sector_size; | |
| 3460 | + if (s->packet_transfer_size <= 0) | |
| 3461 | + ide_atapi_cmd_ok(s); | |
| 3464 | 3462 | |
| 3465 | - io->len -= len; | |
| 3466 | - io->addr += len; | |
| 3467 | - s->packet_transfer_size -= len; | |
| 3463 | + if (io->len == 0) { | |
| 3464 | + io->dma_end(opaque); | |
| 3465 | + return; | |
| 3468 | 3466 | } |
| 3469 | 3467 | |
| 3470 | - if (io->len <= 0) | |
| 3471 | - io->dma_end(io); | |
| 3468 | + /* launch next transfer */ | |
| 3472 | 3469 | |
| 3473 | - if (s->packet_transfer_size <= 0) { | |
| 3474 | - s->status = READY_STAT | SEEK_STAT; | |
| 3475 | - s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | |
| 3476 | - | ATAPI_INT_REASON_CD; | |
| 3477 | - ide_set_irq(s); | |
| 3470 | + s->io_buffer_size = io->len; | |
| 3471 | + | |
| 3472 | + qemu_sglist_init(&s->sg, io->len / TARGET_PAGE_SIZE + 1); | |
| 3473 | + qemu_sglist_add(&s->sg, io->addr, io->len); | |
| 3474 | + io->addr += io->len; | |
| 3475 | + io->len = 0; | |
| 3476 | + | |
| 3477 | + m->aiocb = dma_bdrv_read(s->bs, &s->sg, | |
| 3478 | + (int64_t)(s->lba << 2) + (s->io_buffer_index >> 9), | |
| 3479 | + pmac_ide_atapi_transfer_cb, io); | |
| 3480 | + if (!m->aiocb) { | |
| 3481 | + qemu_sglist_destroy(&s->sg); | |
| 3482 | + /* Note: media not present is the most likely case */ | |
| 3483 | + ide_atapi_cmd_error(s, SENSE_NOT_READY, | |
| 3484 | + ASC_MEDIUM_NOT_PRESENT); | |
| 3485 | + io->dma_end(opaque); | |
| 3486 | + return; | |
| 3478 | 3487 | } |
| 3479 | 3488 | } |
| 3480 | 3489 | |
| 3481 | -static void pmac_ide_transfer(DBDMA_io *io) | |
| 3490 | +static void pmac_ide_transfer_cb(void *opaque, int ret) | |
| 3482 | 3491 | { |
| 3492 | + DBDMA_io *io = opaque; | |
| 3483 | 3493 | MACIOIDEState *m = io->opaque; |
| 3484 | 3494 | IDEState *s = m->ide_if->cur_drive; |
| 3495 | + int n; | |
| 3485 | 3496 | int64_t sector_num; |
| 3486 | - int ret, n; | |
| 3487 | - int len; | |
| 3488 | 3497 | |
| 3489 | - if (s->is_cdrom) { | |
| 3490 | - pmac_atapi_read(io); | |
| 3498 | + if (ret < 0) { | |
| 3499 | + m->aiocb = NULL; | |
| 3500 | + qemu_sglist_destroy(&s->sg); | |
| 3501 | + ide_dma_error(s); | |
| 3502 | + io->dma_end(io); | |
| 3491 | 3503 | return; |
| 3492 | 3504 | } |
| 3493 | 3505 | |
| 3494 | - while (io->len > 0 && s->nsector > 0) { | |
| 3506 | + sector_num = ide_get_sector(s); | |
| 3507 | + if (s->io_buffer_size > 0) { | |
| 3508 | + m->aiocb = NULL; | |
| 3509 | + qemu_sglist_destroy(&s->sg); | |
| 3510 | + n = (s->io_buffer_size + 0x1ff) >> 9; | |
| 3511 | + sector_num += n; | |
| 3512 | + ide_set_sector(s, sector_num); | |
| 3513 | + s->nsector -= n; | |
| 3514 | + } | |
| 3515 | + | |
| 3516 | + /* end of transfer ? */ | |
| 3517 | + if (s->nsector == 0) { | |
| 3518 | + s->status = READY_STAT | SEEK_STAT; | |
| 3519 | + ide_set_irq(s); | |
| 3520 | + } | |
| 3495 | 3521 | |
| 3496 | - sector_num = ide_get_sector(s); | |
| 3522 | + /* end of DMA ? */ | |
| 3497 | 3523 | |
| 3498 | - n = s->nsector; | |
| 3499 | - if (n > IDE_DMA_BUF_SECTORS) | |
| 3500 | - n = IDE_DMA_BUF_SECTORS; | |
| 3524 | + if (io->len == 0) { | |
| 3525 | + io->dma_end(io); | |
| 3526 | + return; | |
| 3527 | + } | |
| 3501 | 3528 | |
| 3502 | - len = n << 9; | |
| 3503 | - if (len > io->len) | |
| 3504 | - len = io->len; | |
| 3505 | - n = (len + 511) >> 9; | |
| 3529 | + /* launch next transfer */ | |
| 3506 | 3530 | |
| 3507 | - if (s->is_read) { | |
| 3508 | - ret = bdrv_read(s->bs, sector_num, s->io_buffer, n); | |
| 3509 | - cpu_physical_memory_write(io->addr, s->io_buffer, len); | |
| 3510 | - } else { | |
| 3511 | - cpu_physical_memory_read(io->addr, s->io_buffer, len); | |
| 3512 | - ret = bdrv_write(s->bs, sector_num, s->io_buffer, n); | |
| 3513 | - } | |
| 3531 | + s->io_buffer_index = 0; | |
| 3532 | + s->io_buffer_size = io->len; | |
| 3514 | 3533 | |
| 3515 | - if (ret != 0) { | |
| 3516 | - io->dma_end(io); | |
| 3517 | - ide_rw_error(s); | |
| 3518 | - return; | |
| 3519 | - } | |
| 3534 | + qemu_sglist_init(&s->sg, io->len / TARGET_PAGE_SIZE + 1); | |
| 3535 | + qemu_sglist_add(&s->sg, io->addr, io->len); | |
| 3536 | + io->addr += io->len; | |
| 3537 | + io->len = 0; | |
| 3520 | 3538 | |
| 3521 | - io->len -= len; | |
| 3522 | - io->addr += len; | |
| 3523 | - ide_set_sector(s, sector_num + n); | |
| 3524 | - s->nsector -= n; | |
| 3525 | - } | |
| 3539 | + if (s->is_read) | |
| 3540 | + m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num, | |
| 3541 | + pmac_ide_transfer_cb, io); | |
| 3542 | + else | |
| 3543 | + m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num, | |
| 3544 | + pmac_ide_transfer_cb, io); | |
| 3545 | + if (!m->aiocb) | |
| 3546 | + pmac_ide_transfer_cb(io, -1); | |
| 3547 | +} | |
| 3526 | 3548 | |
| 3527 | - if (io->len <= 0) | |
| 3528 | - io->dma_end(io); | |
| 3549 | +static void pmac_ide_transfer(DBDMA_io *io) | |
| 3550 | +{ | |
| 3551 | + MACIOIDEState *m = io->opaque; | |
| 3552 | + IDEState *s = m->ide_if->cur_drive; | |
| 3529 | 3553 | |
| 3530 | - if (s->nsector <= 0) { | |
| 3531 | - s->status = READY_STAT | SEEK_STAT; | |
| 3532 | - ide_set_irq(s); | |
| 3554 | + s->io_buffer_size = 0; | |
| 3555 | + if (s->is_cdrom) { | |
| 3556 | + pmac_ide_atapi_transfer_cb(io, 0); | |
| 3557 | + return; | |
| 3533 | 3558 | } |
| 3534 | 3559 | |
| 3535 | - return; | |
| 3560 | + pmac_ide_transfer_cb(io, 0); | |
| 3561 | +} | |
| 3562 | + | |
| 3563 | +static void pmac_ide_flush(DBDMA_io *io) | |
| 3564 | +{ | |
| 3565 | + MACIOIDEState *m = io->opaque; | |
| 3566 | + | |
| 3567 | + if (m->aiocb) | |
| 3568 | + qemu_aio_flush(); | |
| 3536 | 3569 | } |
| 3537 | 3570 | |
| 3538 | 3571 | /* PowerMac IDE memory IO */ |
| ... | ... | @@ -3712,7 +3745,7 @@ int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq, |
| 3712 | 3745 | ide_init2(d->ide_if, hd_table[0], hd_table[1], irq); |
| 3713 | 3746 | |
| 3714 | 3747 | if (dbdma) |
| 3715 | - DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, d); | |
| 3748 | + DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d); | |
| 3716 | 3749 | |
| 3717 | 3750 | pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, |
| 3718 | 3751 | pmac_ide_write, d); | ... | ... |
hw/mac_dbdma.c
| ... | ... | @@ -160,6 +160,7 @@ typedef struct DBDMA_channel { |
| 160 | 160 | qemu_irq irq; |
| 161 | 161 | DBDMA_io io; |
| 162 | 162 | DBDMA_rw rw; |
| 163 | + DBDMA_flush flush; | |
| 163 | 164 | dbdma_cmd current; |
| 164 | 165 | int processing; |
| 165 | 166 | } DBDMA_channel; |
| ... | ... | @@ -367,7 +368,8 @@ static void dbdma_end(DBDMA_io *io) |
| 367 | 368 | current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS])); |
| 368 | 369 | current->res_count = cpu_to_le16(be32_to_cpu(io->len)); |
| 369 | 370 | dbdma_cmdptr_save(ch); |
| 370 | - ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH); | |
| 371 | + if (io->is_last) | |
| 372 | + ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH); | |
| 371 | 373 | |
| 372 | 374 | conditional_interrupt(ch); |
| 373 | 375 | conditional_branch(ch); |
| ... | ... | @@ -632,7 +634,7 @@ static void DBDMA_run_bh(void *opaque) |
| 632 | 634 | } |
| 633 | 635 | |
| 634 | 636 | void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, |
| 635 | - DBDMA_rw rw, | |
| 637 | + DBDMA_rw rw, DBDMA_flush flush, | |
| 636 | 638 | void *opaque) |
| 637 | 639 | { |
| 638 | 640 | DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan; |
| ... | ... | @@ -642,6 +644,7 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, |
| 642 | 644 | ch->irq = irq; |
| 643 | 645 | ch->channel = nchan; |
| 644 | 646 | ch->rw = rw; |
| 647 | + ch->flush = flush; | |
| 645 | 648 | ch->io.opaque = opaque; |
| 646 | 649 | ch->io.channel = ch; |
| 647 | 650 | } |
| ... | ... | @@ -687,6 +690,8 @@ dbdma_control_write(DBDMA_channel *ch) |
| 687 | 690 | |
| 688 | 691 | if (status & ACTIVE) |
| 689 | 692 | qemu_bh_schedule(dbdma_bh); |
| 693 | + if (status & FLUSH) | |
| 694 | + ch->flush(&ch->io); | |
| 690 | 695 | } |
| 691 | 696 | |
| 692 | 697 | static void dbdma_writel (void *opaque, | ... | ... |
hw/mac_dbdma.h
| ... | ... | @@ -22,6 +22,7 @@ |
| 22 | 22 | |
| 23 | 23 | typedef struct DBDMA_io DBDMA_io; |
| 24 | 24 | |
| 25 | +typedef void (*DBDMA_flush)(DBDMA_io *io); | |
| 25 | 26 | typedef void (*DBDMA_rw)(DBDMA_io *io); |
| 26 | 27 | typedef void (*DBDMA_end)(DBDMA_io *io); |
| 27 | 28 | struct DBDMA_io { |
| ... | ... | @@ -36,7 +37,7 @@ struct DBDMA_io { |
| 36 | 37 | |
| 37 | 38 | |
| 38 | 39 | void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, |
| 39 | - DBDMA_rw rw, | |
| 40 | + DBDMA_rw rw, DBDMA_flush flush, | |
| 40 | 41 | void *opaque); |
| 41 | 42 | void DBDMA_schedule(void); |
| 42 | 43 | void* DBDMA_init (int *dbdma_mem_index); | ... | ... |