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); | ... | ... |