提交 862c9280 编写于 作者: A aurel32

DB-DMA IDE asynchronous I/O

Signed-off-by: NLaurent Vivier <Laurent@vivier.eu>
Signed-off-by: NAurelien Jarno <aurelien@aurel32.net>

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6681 c046a42c-6fe2-441c-8c8c-71466251a162
上级 3c4cf535
...@@ -3429,110 +3429,143 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, ...@@ -3429,110 +3429,143 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
typedef struct MACIOIDEState { typedef struct MACIOIDEState {
IDEState ide_if[2]; IDEState ide_if[2];
int stream_index; BlockDriverAIOCB *aiocb;
} MACIOIDEState; } MACIOIDEState;
static void pmac_atapi_read(DBDMA_io *io) static void pmac_ide_atapi_transfer_cb(void *opaque, int ret)
{ {
DBDMA_io *io = opaque;
MACIOIDEState *m = io->opaque; MACIOIDEState *m = io->opaque;
IDEState *s = m->ide_if->cur_drive; IDEState *s = m->ide_if->cur_drive;
int ret, len;
while (io->len > 0 &&
s->packet_transfer_size > 0) {
len = s->cd_sector_size;
ret = cd_read_sector(s->bs, s->lba, s->io_buffer, len);
if (ret < 0) { if (ret < 0) {
io->dma_end(io); m->aiocb = NULL;
ide_transfer_stop(s); qemu_sglist_destroy(&s->sg);
ide_atapi_io_error(s, ret); ide_atapi_io_error(s, ret);
io->dma_end(opaque);
return; return;
} }
if (len > io->len) if (s->io_buffer_size > 0) {
len = io->len; m->aiocb = NULL;
qemu_sglist_destroy(&s->sg);
cpu_physical_memory_write(io->addr, s->packet_transfer_size -= s->io_buffer_size;
s->io_buffer + m->stream_index, len);
/* db-dma can ask for 512 bytes whereas block size is 2048... */ s->io_buffer_index += s->io_buffer_size;
s->lba += s->io_buffer_index >> 11;
s->io_buffer_index &= 0x7ff;
}
m->stream_index += len; if (s->packet_transfer_size <= 0)
s->lba += m->stream_index / s->cd_sector_size; ide_atapi_cmd_ok(s);
m->stream_index %= s->cd_sector_size;
io->len -= len; if (io->len == 0) {
io->addr += len; io->dma_end(opaque);
s->packet_transfer_size -= len; return;
} }
if (io->len <= 0) /* launch next transfer */
io->dma_end(io);
if (s->packet_transfer_size <= 0) { s->io_buffer_size = io->len;
s->status = READY_STAT | SEEK_STAT;
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO qemu_sglist_init(&s->sg, io->len / TARGET_PAGE_SIZE + 1);
| ATAPI_INT_REASON_CD; qemu_sglist_add(&s->sg, io->addr, io->len);
ide_set_irq(s); io->addr += io->len;
io->len = 0;
m->aiocb = dma_bdrv_read(s->bs, &s->sg,
(int64_t)(s->lba << 2) + (s->io_buffer_index >> 9),
pmac_ide_atapi_transfer_cb, io);
if (!m->aiocb) {
qemu_sglist_destroy(&s->sg);
/* Note: media not present is the most likely case */
ide_atapi_cmd_error(s, SENSE_NOT_READY,
ASC_MEDIUM_NOT_PRESENT);
io->dma_end(opaque);
return;
} }
} }
static void pmac_ide_transfer(DBDMA_io *io) static void pmac_ide_transfer_cb(void *opaque, int ret)
{ {
DBDMA_io *io = opaque;
MACIOIDEState *m = io->opaque; MACIOIDEState *m = io->opaque;
IDEState *s = m->ide_if->cur_drive; IDEState *s = m->ide_if->cur_drive;
int n;
int64_t sector_num; int64_t sector_num;
int ret, n;
int len;
if (s->is_cdrom) { if (ret < 0) {
pmac_atapi_read(io); m->aiocb = NULL;
qemu_sglist_destroy(&s->sg);
ide_dma_error(s);
io->dma_end(io);
return; return;
} }
while (io->len > 0 && s->nsector > 0) {
sector_num = ide_get_sector(s); sector_num = ide_get_sector(s);
if (s->io_buffer_size > 0) {
m->aiocb = NULL;
qemu_sglist_destroy(&s->sg);
n = (s->io_buffer_size + 0x1ff) >> 9;
sector_num += n;
ide_set_sector(s, sector_num);
s->nsector -= n;
}
n = s->nsector; /* end of transfer ? */
if (n > IDE_DMA_BUF_SECTORS) if (s->nsector == 0) {
n = IDE_DMA_BUF_SECTORS; s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s);
len = n << 9;
if (len > io->len)
len = io->len;
n = (len + 511) >> 9;
if (s->is_read) {
ret = bdrv_read(s->bs, sector_num, s->io_buffer, n);
cpu_physical_memory_write(io->addr, s->io_buffer, len);
} else {
cpu_physical_memory_read(io->addr, s->io_buffer, len);
ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
} }
if (ret != 0) { /* end of DMA ? */
if (io->len == 0) {
io->dma_end(io); io->dma_end(io);
ide_rw_error(s);
return; return;
} }
io->len -= len; /* launch next transfer */
io->addr += len;
ide_set_sector(s, sector_num + n);
s->nsector -= n;
}
if (io->len <= 0) s->io_buffer_index = 0;
io->dma_end(io); s->io_buffer_size = io->len;
if (s->nsector <= 0) { qemu_sglist_init(&s->sg, io->len / TARGET_PAGE_SIZE + 1);
s->status = READY_STAT | SEEK_STAT; qemu_sglist_add(&s->sg, io->addr, io->len);
ide_set_irq(s); io->addr += io->len;
} io->len = 0;
if (s->is_read)
m->aiocb = dma_bdrv_read(s->bs, &s->sg, sector_num,
pmac_ide_transfer_cb, io);
else
m->aiocb = dma_bdrv_write(s->bs, &s->sg, sector_num,
pmac_ide_transfer_cb, io);
if (!m->aiocb)
pmac_ide_transfer_cb(io, -1);
}
static void pmac_ide_transfer(DBDMA_io *io)
{
MACIOIDEState *m = io->opaque;
IDEState *s = m->ide_if->cur_drive;
s->io_buffer_size = 0;
if (s->is_cdrom) {
pmac_ide_atapi_transfer_cb(io, 0);
return; return;
}
pmac_ide_transfer_cb(io, 0);
}
static void pmac_ide_flush(DBDMA_io *io)
{
MACIOIDEState *m = io->opaque;
if (m->aiocb)
qemu_aio_flush();
} }
/* PowerMac IDE memory IO */ /* PowerMac IDE memory IO */
...@@ -3712,7 +3745,7 @@ int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq, ...@@ -3712,7 +3745,7 @@ int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq,
ide_init2(d->ide_if, hd_table[0], hd_table[1], irq); ide_init2(d->ide_if, hd_table[0], hd_table[1], irq);
if (dbdma) if (dbdma)
DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, d); DBDMA_register_channel(dbdma, channel, dma_irq, pmac_ide_transfer, pmac_ide_flush, d);
pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read, pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read,
pmac_ide_write, d); pmac_ide_write, d);
......
...@@ -160,6 +160,7 @@ typedef struct DBDMA_channel { ...@@ -160,6 +160,7 @@ typedef struct DBDMA_channel {
qemu_irq irq; qemu_irq irq;
DBDMA_io io; DBDMA_io io;
DBDMA_rw rw; DBDMA_rw rw;
DBDMA_flush flush;
dbdma_cmd current; dbdma_cmd current;
int processing; int processing;
} DBDMA_channel; } DBDMA_channel;
...@@ -367,6 +368,7 @@ static void dbdma_end(DBDMA_io *io) ...@@ -367,6 +368,7 @@ static void dbdma_end(DBDMA_io *io)
current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS])); current->xfer_status = cpu_to_le16(be32_to_cpu(ch->regs[DBDMA_STATUS]));
current->res_count = cpu_to_le16(be32_to_cpu(io->len)); current->res_count = cpu_to_le16(be32_to_cpu(io->len));
dbdma_cmdptr_save(ch); dbdma_cmdptr_save(ch);
if (io->is_last)
ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH); ch->regs[DBDMA_STATUS] &= cpu_to_be32(~FLUSH);
conditional_interrupt(ch); conditional_interrupt(ch);
...@@ -632,7 +634,7 @@ static void DBDMA_run_bh(void *opaque) ...@@ -632,7 +634,7 @@ static void DBDMA_run_bh(void *opaque)
} }
void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
DBDMA_rw rw, DBDMA_rw rw, DBDMA_flush flush,
void *opaque) void *opaque)
{ {
DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan; DBDMA_channel *ch = ( DBDMA_channel *)dbdma + nchan;
...@@ -642,6 +644,7 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, ...@@ -642,6 +644,7 @@ void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
ch->irq = irq; ch->irq = irq;
ch->channel = nchan; ch->channel = nchan;
ch->rw = rw; ch->rw = rw;
ch->flush = flush;
ch->io.opaque = opaque; ch->io.opaque = opaque;
ch->io.channel = ch; ch->io.channel = ch;
} }
...@@ -687,6 +690,8 @@ dbdma_control_write(DBDMA_channel *ch) ...@@ -687,6 +690,8 @@ dbdma_control_write(DBDMA_channel *ch)
if (status & ACTIVE) if (status & ACTIVE)
qemu_bh_schedule(dbdma_bh); qemu_bh_schedule(dbdma_bh);
if (status & FLUSH)
ch->flush(&ch->io);
} }
static void dbdma_writel (void *opaque, static void dbdma_writel (void *opaque,
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
typedef struct DBDMA_io DBDMA_io; typedef struct DBDMA_io DBDMA_io;
typedef void (*DBDMA_flush)(DBDMA_io *io);
typedef void (*DBDMA_rw)(DBDMA_io *io); typedef void (*DBDMA_rw)(DBDMA_io *io);
typedef void (*DBDMA_end)(DBDMA_io *io); typedef void (*DBDMA_end)(DBDMA_io *io);
struct DBDMA_io { struct DBDMA_io {
...@@ -36,7 +37,7 @@ struct DBDMA_io { ...@@ -36,7 +37,7 @@ struct DBDMA_io {
void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq, void DBDMA_register_channel(void *dbdma, int nchan, qemu_irq irq,
DBDMA_rw rw, DBDMA_rw rw, DBDMA_flush flush,
void *opaque); void *opaque);
void DBDMA_schedule(void); void DBDMA_schedule(void);
void* DBDMA_init (int *dbdma_mem_index); void* DBDMA_init (int *dbdma_mem_index);
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册