use AIO for DMA transfers - enabled DMA for CDROMs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2103 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
e84a4fedf7
commit
8ccad811e6
435
hw/ide.c
435
hw/ide.c
@ -26,6 +26,8 @@
|
|||||||
/* debug IDE devices */
|
/* debug IDE devices */
|
||||||
//#define DEBUG_IDE
|
//#define DEBUG_IDE
|
||||||
//#define DEBUG_IDE_ATAPI
|
//#define DEBUG_IDE_ATAPI
|
||||||
|
//#define DEBUG_AIO
|
||||||
|
#define USE_DMA_CDROM
|
||||||
|
|
||||||
/* Bits of HD_STATUS */
|
/* Bits of HD_STATUS */
|
||||||
#define ERR_STAT 0x01
|
#define ERR_STAT 0x01
|
||||||
@ -368,19 +370,20 @@ typedef struct IDEState {
|
|||||||
#define UDIDETCR0 0x73
|
#define UDIDETCR0 0x73
|
||||||
#define UDIDETCR1 0x7B
|
#define UDIDETCR1 0x7B
|
||||||
|
|
||||||
typedef int IDEDMAFunc(IDEState *s,
|
|
||||||
target_phys_addr_t phys_addr,
|
|
||||||
int transfer_size1);
|
|
||||||
|
|
||||||
typedef struct BMDMAState {
|
typedef struct BMDMAState {
|
||||||
uint8_t cmd;
|
uint8_t cmd;
|
||||||
uint8_t status;
|
uint8_t status;
|
||||||
uint32_t addr;
|
uint32_t addr;
|
||||||
|
|
||||||
struct PCIIDEState *pci_dev;
|
struct PCIIDEState *pci_dev;
|
||||||
/* current transfer state */
|
/* current transfer state */
|
||||||
|
uint32_t cur_addr;
|
||||||
|
uint32_t cur_prd_last;
|
||||||
|
uint32_t cur_prd_addr;
|
||||||
|
uint32_t cur_prd_len;
|
||||||
IDEState *ide_if;
|
IDEState *ide_if;
|
||||||
IDEDMAFunc *dma_cb;
|
BlockDriverCompletionFunc *dma_cb;
|
||||||
|
BlockDriverAIOCB *aiocb;
|
||||||
} BMDMAState;
|
} BMDMAState;
|
||||||
|
|
||||||
typedef struct PCIIDEState {
|
typedef struct PCIIDEState {
|
||||||
@ -390,7 +393,7 @@ typedef struct PCIIDEState {
|
|||||||
int type; /* see IDE_TYPE_xxx */
|
int type; /* see IDE_TYPE_xxx */
|
||||||
} PCIIDEState;
|
} PCIIDEState;
|
||||||
|
|
||||||
static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb);
|
static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb);
|
||||||
|
|
||||||
static void padstr(char *str, const char *src, int len)
|
static void padstr(char *str, const char *src, int len)
|
||||||
{
|
{
|
||||||
@ -513,10 +516,17 @@ static void ide_atapi_identify(IDEState *s)
|
|||||||
padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
|
padstr((uint8_t *)(p + 23), QEMU_VERSION, 8); /* firmware version */
|
||||||
padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */
|
padstr((uint8_t *)(p + 27), "QEMU CD-ROM", 40); /* model */
|
||||||
put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
|
put_le16(p + 48, 1); /* dword I/O (XXX: should not be set on CDROM) */
|
||||||
|
#ifdef USE_DMA_CDROM
|
||||||
|
put_le16(p + 49, 1 << 9 | 1 << 8); /* DMA and LBA supported */
|
||||||
|
put_le16(p + 53, 7); /* words 64-70, 54-58, 88 valid */
|
||||||
|
put_le16(p + 63, 7); /* mdma0-2 supported */
|
||||||
|
put_le16(p + 64, 0x3f); /* PIO modes supported */
|
||||||
|
#else
|
||||||
put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
|
put_le16(p + 49, 1 << 9); /* LBA supported, no DMA */
|
||||||
put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
|
put_le16(p + 53, 3); /* words 64-70, 54-58 valid */
|
||||||
put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
|
put_le16(p + 63, 0x103); /* DMA modes XXX: may be incorrect */
|
||||||
put_le16(p + 64, 1); /* PIO modes */
|
put_le16(p + 64, 1); /* PIO modes */
|
||||||
|
#endif
|
||||||
put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
|
put_le16(p + 65, 0xb4); /* minimum DMA multiword tx cycle time */
|
||||||
put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
|
put_le16(p + 66, 0xb4); /* recommended DMA multiword tx cycle time */
|
||||||
put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
|
put_le16(p + 67, 0x12c); /* minimum PIO cycle time without flow control */
|
||||||
@ -526,7 +536,9 @@ static void ide_atapi_identify(IDEState *s)
|
|||||||
put_le16(p + 72, 30); /* in ns */
|
put_le16(p + 72, 30); /* in ns */
|
||||||
|
|
||||||
put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */
|
put_le16(p + 80, 0x1e); /* support up to ATA/ATAPI-4 */
|
||||||
|
#ifdef USE_DMA_CDROM
|
||||||
|
put_le16(p + 88, 0x3f | (1 << 13)); /* udma5 set and supported */
|
||||||
|
#endif
|
||||||
memcpy(s->identify_data, p, sizeof(s->identify_data));
|
memcpy(s->identify_data, p, sizeof(s->identify_data));
|
||||||
s->identify_set = 1;
|
s->identify_set = 1;
|
||||||
}
|
}
|
||||||
@ -659,54 +671,101 @@ static void ide_sector_read(IDEState *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ide_read_dma_cb(IDEState *s,
|
/* return 0 if buffer completed */
|
||||||
target_phys_addr_t phys_addr,
|
static int dma_buf_rw(BMDMAState *bm, int is_write)
|
||||||
int transfer_size1)
|
|
||||||
{
|
{
|
||||||
int len, transfer_size, n;
|
IDEState *s = bm->ide_if;
|
||||||
|
struct {
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t size;
|
||||||
|
} prd;
|
||||||
|
int l, len;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
l = s->io_buffer_size - s->io_buffer_index;
|
||||||
|
if (l <= 0)
|
||||||
|
break;
|
||||||
|
if (bm->cur_prd_len == 0) {
|
||||||
|
/* end of table (with a fail safe of one page) */
|
||||||
|
if (bm->cur_prd_last ||
|
||||||
|
(bm->cur_addr - bm->addr) >= 4096)
|
||||||
|
return 0;
|
||||||
|
cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
|
||||||
|
bm->cur_addr += 8;
|
||||||
|
prd.addr = le32_to_cpu(prd.addr);
|
||||||
|
prd.size = le32_to_cpu(prd.size);
|
||||||
|
len = prd.size & 0xfffe;
|
||||||
|
if (len == 0)
|
||||||
|
len = 0x10000;
|
||||||
|
bm->cur_prd_len = len;
|
||||||
|
bm->cur_prd_addr = prd.addr;
|
||||||
|
bm->cur_prd_last = (prd.size & 0x80000000);
|
||||||
|
}
|
||||||
|
if (l > bm->cur_prd_len)
|
||||||
|
l = bm->cur_prd_len;
|
||||||
|
if (l > 0) {
|
||||||
|
if (is_write) {
|
||||||
|
cpu_physical_memory_write(bm->cur_prd_addr,
|
||||||
|
s->io_buffer + s->io_buffer_index, l);
|
||||||
|
} else {
|
||||||
|
cpu_physical_memory_read(bm->cur_prd_addr,
|
||||||
|
s->io_buffer + s->io_buffer_index, l);
|
||||||
|
}
|
||||||
|
bm->cur_prd_addr += l;
|
||||||
|
bm->cur_prd_len -= l;
|
||||||
|
s->io_buffer_index += l;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XXX: handle errors */
|
||||||
|
static void ide_read_dma_cb(void *opaque, int ret)
|
||||||
|
{
|
||||||
|
BMDMAState *bm = opaque;
|
||||||
|
IDEState *s = bm->ide_if;
|
||||||
|
int n;
|
||||||
int64_t sector_num;
|
int64_t sector_num;
|
||||||
|
|
||||||
transfer_size = transfer_size1;
|
n = s->io_buffer_size >> 9;
|
||||||
while (transfer_size > 0) {
|
sector_num = ide_get_sector(s);
|
||||||
len = s->io_buffer_size - s->io_buffer_index;
|
if (n > 0) {
|
||||||
if (len <= 0) {
|
sector_num += n;
|
||||||
/* transfert next data */
|
ide_set_sector(s, sector_num);
|
||||||
n = s->nsector;
|
s->nsector -= n;
|
||||||
if (n == 0)
|
if (dma_buf_rw(bm, 1) == 0)
|
||||||
break;
|
goto eot;
|
||||||
if (n > MAX_MULT_SECTORS)
|
|
||||||
n = MAX_MULT_SECTORS;
|
|
||||||
sector_num = ide_get_sector(s);
|
|
||||||
bdrv_read(s->bs, sector_num, s->io_buffer, n);
|
|
||||||
s->io_buffer_index = 0;
|
|
||||||
s->io_buffer_size = n * 512;
|
|
||||||
len = s->io_buffer_size;
|
|
||||||
sector_num += n;
|
|
||||||
ide_set_sector(s, sector_num);
|
|
||||||
s->nsector -= n;
|
|
||||||
}
|
|
||||||
if (len > transfer_size)
|
|
||||||
len = transfer_size;
|
|
||||||
cpu_physical_memory_write(phys_addr,
|
|
||||||
s->io_buffer + s->io_buffer_index, len);
|
|
||||||
s->io_buffer_index += len;
|
|
||||||
transfer_size -= len;
|
|
||||||
phys_addr += len;
|
|
||||||
}
|
}
|
||||||
if (s->io_buffer_index >= s->io_buffer_size && s->nsector == 0) {
|
|
||||||
|
/* end of transfer ? */
|
||||||
|
if (s->nsector == 0) {
|
||||||
s->status = READY_STAT | SEEK_STAT;
|
s->status = READY_STAT | SEEK_STAT;
|
||||||
ide_set_irq(s);
|
ide_set_irq(s);
|
||||||
#ifdef DEBUG_IDE_ATAPI
|
eot:
|
||||||
printf("dma status=0x%x\n", s->status);
|
bm->status &= ~BM_STATUS_DMAING;
|
||||||
#endif
|
bm->status |= BM_STATUS_INT;
|
||||||
return 0;
|
bm->dma_cb = NULL;
|
||||||
|
bm->ide_if = NULL;
|
||||||
|
bm->aiocb = NULL;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return transfer_size1 - transfer_size;
|
|
||||||
|
/* launch next transfer */
|
||||||
|
n = s->nsector;
|
||||||
|
if (n > MAX_MULT_SECTORS)
|
||||||
|
n = MAX_MULT_SECTORS;
|
||||||
|
s->io_buffer_index = 0;
|
||||||
|
s->io_buffer_size = n * 512;
|
||||||
|
#ifdef DEBUG_AIO
|
||||||
|
printf("aio_read: sector_num=%lld n=%d\n", sector_num, n);
|
||||||
|
#endif
|
||||||
|
bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n,
|
||||||
|
ide_read_dma_cb, bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ide_sector_read_dma(IDEState *s)
|
static void ide_sector_read_dma(IDEState *s)
|
||||||
{
|
{
|
||||||
s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
|
s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
|
||||||
s->io_buffer_index = 0;
|
s->io_buffer_index = 0;
|
||||||
s->io_buffer_size = 0;
|
s->io_buffer_size = 0;
|
||||||
ide_dma_start(s, ide_read_dma_cb);
|
ide_dma_start(s, ide_read_dma_cb);
|
||||||
@ -761,71 +820,56 @@ static void ide_sector_write(IDEState *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ide_write_dma_cb(IDEState *s,
|
/* XXX: handle errors */
|
||||||
target_phys_addr_t phys_addr,
|
static void ide_write_dma_cb(void *opaque, int ret)
|
||||||
int transfer_size1)
|
|
||||||
{
|
{
|
||||||
int len, transfer_size, n;
|
BMDMAState *bm = opaque;
|
||||||
|
IDEState *s = bm->ide_if;
|
||||||
|
int n;
|
||||||
int64_t sector_num;
|
int64_t sector_num;
|
||||||
|
|
||||||
transfer_size = transfer_size1;
|
n = s->io_buffer_size >> 9;
|
||||||
for(;;) {
|
sector_num = ide_get_sector(s);
|
||||||
len = s->io_buffer_size - s->io_buffer_index;
|
if (n > 0) {
|
||||||
if (len == 0) {
|
sector_num += n;
|
||||||
n = s->io_buffer_size >> 9;
|
ide_set_sector(s, sector_num);
|
||||||
sector_num = ide_get_sector(s);
|
s->nsector -= n;
|
||||||
bdrv_write(s->bs, sector_num, s->io_buffer,
|
|
||||||
s->io_buffer_size >> 9);
|
|
||||||
sector_num += n;
|
|
||||||
ide_set_sector(s, sector_num);
|
|
||||||
s->nsector -= n;
|
|
||||||
n = s->nsector;
|
|
||||||
if (n == 0) {
|
|
||||||
/* end of transfer */
|
|
||||||
s->status = READY_STAT | SEEK_STAT;
|
|
||||||
#ifdef TARGET_I386
|
|
||||||
if (win2k_install_hack && ((++s->irq_count % 16) == 0)) {
|
|
||||||
/* It seems there is a bug in the Windows 2000 installer
|
|
||||||
HDD IDE driver which fills the disk with empty logs
|
|
||||||
when the IDE write IRQ comes too early. This hack tries
|
|
||||||
to correct that at the expense of slower write
|
|
||||||
performances. Use this option _only_ to install Windows
|
|
||||||
2000. You must disable it for normal use. */
|
|
||||||
qemu_mod_timer(s->sector_write_timer,
|
|
||||||
qemu_get_clock(vm_clock) + (ticks_per_sec / 1000));
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
ide_set_irq(s);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
if (n > MAX_MULT_SECTORS)
|
|
||||||
n = MAX_MULT_SECTORS;
|
|
||||||
s->io_buffer_index = 0;
|
|
||||||
s->io_buffer_size = n * 512;
|
|
||||||
len = s->io_buffer_size;
|
|
||||||
}
|
|
||||||
if (transfer_size <= 0)
|
|
||||||
break;
|
|
||||||
if (len > transfer_size)
|
|
||||||
len = transfer_size;
|
|
||||||
cpu_physical_memory_read(phys_addr,
|
|
||||||
s->io_buffer + s->io_buffer_index, len);
|
|
||||||
s->io_buffer_index += len;
|
|
||||||
transfer_size -= len;
|
|
||||||
phys_addr += len;
|
|
||||||
}
|
}
|
||||||
return transfer_size1 - transfer_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ide_sector_write_dma(IDEState *s)
|
/* end of transfer ? */
|
||||||
{
|
if (s->nsector == 0) {
|
||||||
int n;
|
s->status = READY_STAT | SEEK_STAT;
|
||||||
s->status = READY_STAT | SEEK_STAT | DRQ_STAT;
|
ide_set_irq(s);
|
||||||
|
eot:
|
||||||
|
bm->status &= ~BM_STATUS_DMAING;
|
||||||
|
bm->status |= BM_STATUS_INT;
|
||||||
|
bm->dma_cb = NULL;
|
||||||
|
bm->ide_if = NULL;
|
||||||
|
bm->aiocb = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* launch next transfer */
|
||||||
n = s->nsector;
|
n = s->nsector;
|
||||||
if (n > MAX_MULT_SECTORS)
|
if (n > MAX_MULT_SECTORS)
|
||||||
n = MAX_MULT_SECTORS;
|
n = MAX_MULT_SECTORS;
|
||||||
s->io_buffer_index = 0;
|
s->io_buffer_index = 0;
|
||||||
s->io_buffer_size = n * 512;
|
s->io_buffer_size = n * 512;
|
||||||
|
|
||||||
|
if (dma_buf_rw(bm, 0) == 0)
|
||||||
|
goto eot;
|
||||||
|
#ifdef DEBUG_AIO
|
||||||
|
printf("aio_write: sector_num=%lld n=%d\n", sector_num, n);
|
||||||
|
#endif
|
||||||
|
bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n,
|
||||||
|
ide_write_dma_cb, bm);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ide_sector_write_dma(IDEState *s)
|
||||||
|
{
|
||||||
|
s->status = READY_STAT | SEEK_STAT | DRQ_STAT | BUSY_STAT;
|
||||||
|
s->io_buffer_index = 0;
|
||||||
|
s->io_buffer_size = 0;
|
||||||
ide_dma_start(s, ide_write_dma_cb);
|
ide_dma_start(s, ide_write_dma_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -882,6 +926,23 @@ static void lba_to_msf(uint8_t *buf, int lba)
|
|||||||
buf[2] = lba % 75;
|
buf[2] = lba % 75;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cd_data_to_raw(uint8_t *buf, int lba)
|
||||||
|
{
|
||||||
|
/* sync bytes */
|
||||||
|
buf[0] = 0x00;
|
||||||
|
memset(buf + 1, 0xff, 10);
|
||||||
|
buf[11] = 0x00;
|
||||||
|
buf += 12;
|
||||||
|
/* MSF */
|
||||||
|
lba_to_msf(buf, lba);
|
||||||
|
buf[3] = 0x01; /* mode 1 data */
|
||||||
|
buf += 4;
|
||||||
|
/* data */
|
||||||
|
buf += 2048;
|
||||||
|
/* XXX: ECC not computed */
|
||||||
|
memset(buf, 0, 288);
|
||||||
|
}
|
||||||
|
|
||||||
static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
|
static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
|
||||||
int sector_size)
|
int sector_size)
|
||||||
{
|
{
|
||||||
@ -890,20 +951,8 @@ static void cd_read_sector(BlockDriverState *bs, int lba, uint8_t *buf,
|
|||||||
bdrv_read(bs, (int64_t)lba << 2, buf, 4);
|
bdrv_read(bs, (int64_t)lba << 2, buf, 4);
|
||||||
break;
|
break;
|
||||||
case 2352:
|
case 2352:
|
||||||
/* sync bytes */
|
bdrv_read(bs, (int64_t)lba << 2, buf + 16, 4);
|
||||||
buf[0] = 0x00;
|
cd_data_to_raw(buf, lba);
|
||||||
memset(buf + 1, 0xff, 10);
|
|
||||||
buf[11] = 0x00;
|
|
||||||
buf += 12;
|
|
||||||
/* MSF */
|
|
||||||
lba_to_msf(buf, lba);
|
|
||||||
buf[3] = 0x01; /* mode 1 data */
|
|
||||||
buf += 4;
|
|
||||||
/* data */
|
|
||||||
bdrv_read(bs, (int64_t)lba << 2, buf, 4);
|
|
||||||
buf += 2048;
|
|
||||||
/* ECC */
|
|
||||||
memset(buf, 0, 288);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@ -1013,46 +1062,58 @@ static void ide_atapi_cmd_read_pio(IDEState *s, int lba, int nb_sectors,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* ATAPI DMA support */
|
/* ATAPI DMA support */
|
||||||
static int ide_atapi_cmd_read_dma_cb(IDEState *s,
|
|
||||||
target_phys_addr_t phys_addr,
|
/* XXX: handle read errors */
|
||||||
int transfer_size1)
|
static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret)
|
||||||
{
|
{
|
||||||
int len, transfer_size;
|
BMDMAState *bm = opaque;
|
||||||
|
IDEState *s = bm->ide_if;
|
||||||
transfer_size = transfer_size1;
|
int data_offset, n;
|
||||||
while (transfer_size > 0) {
|
|
||||||
#ifdef DEBUG_IDE_ATAPI
|
if (s->io_buffer_size > 0) {
|
||||||
printf("transfer_size: %d phys_addr=%08x\n", transfer_size, phys_addr);
|
if (s->cd_sector_size == 2352) {
|
||||||
#endif
|
n = 1;
|
||||||
if (s->packet_transfer_size <= 0)
|
cd_data_to_raw(s->io_buffer, s->lba);
|
||||||
break;
|
} else {
|
||||||
len = s->cd_sector_size - s->io_buffer_index;
|
n = s->io_buffer_size >> 11;
|
||||||
if (len <= 0) {
|
|
||||||
/* transfert next data */
|
|
||||||
cd_read_sector(s->bs, s->lba, s->io_buffer, s->cd_sector_size);
|
|
||||||
s->lba++;
|
|
||||||
s->io_buffer_index = 0;
|
|
||||||
len = s->cd_sector_size;
|
|
||||||
}
|
}
|
||||||
if (len > transfer_size)
|
s->packet_transfer_size -= s->io_buffer_size;
|
||||||
len = transfer_size;
|
s->lba += n;
|
||||||
cpu_physical_memory_write(phys_addr,
|
if (dma_buf_rw(bm, 1) == 0)
|
||||||
s->io_buffer + s->io_buffer_index, len);
|
goto eot;
|
||||||
s->packet_transfer_size -= len;
|
|
||||||
s->io_buffer_index += len;
|
|
||||||
transfer_size -= len;
|
|
||||||
phys_addr += len;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (s->packet_transfer_size <= 0) {
|
if (s->packet_transfer_size <= 0) {
|
||||||
s->status = READY_STAT;
|
s->status = READY_STAT;
|
||||||
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
|
s->nsector = (s->nsector & ~7) | ATAPI_INT_REASON_IO | ATAPI_INT_REASON_CD;
|
||||||
ide_set_irq(s);
|
ide_set_irq(s);
|
||||||
#ifdef DEBUG_IDE_ATAPI
|
eot:
|
||||||
printf("dma status=0x%x\n", s->status);
|
bm->status &= ~BM_STATUS_DMAING;
|
||||||
#endif
|
bm->status |= BM_STATUS_INT;
|
||||||
return 0;
|
bm->dma_cb = NULL;
|
||||||
|
bm->ide_if = NULL;
|
||||||
|
bm->aiocb = NULL;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return transfer_size1 - transfer_size;
|
|
||||||
|
s->io_buffer_index = 0;
|
||||||
|
if (s->cd_sector_size == 2352) {
|
||||||
|
n = 1;
|
||||||
|
s->io_buffer_size = s->cd_sector_size;
|
||||||
|
data_offset = 16;
|
||||||
|
} else {
|
||||||
|
n = s->packet_transfer_size >> 11;
|
||||||
|
if (n > (MAX_MULT_SECTORS / 4))
|
||||||
|
n = (MAX_MULT_SECTORS / 4);
|
||||||
|
s->io_buffer_size = n * 2048;
|
||||||
|
data_offset = 0;
|
||||||
|
}
|
||||||
|
#ifdef DEBUG_AIO
|
||||||
|
printf("aio_read_cd: lba=%u n=%d\n", s->lba, n);
|
||||||
|
#endif
|
||||||
|
bm->aiocb = bdrv_aio_read(s->bs, (int64_t)s->lba << 2,
|
||||||
|
s->io_buffer + data_offset, n * 4,
|
||||||
|
ide_atapi_cmd_read_dma_cb, bm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* start a CD-CDROM read command with DMA */
|
/* start a CD-CDROM read command with DMA */
|
||||||
@ -1062,10 +1123,12 @@ static void ide_atapi_cmd_read_dma(IDEState *s, int lba, int nb_sectors,
|
|||||||
{
|
{
|
||||||
s->lba = lba;
|
s->lba = lba;
|
||||||
s->packet_transfer_size = nb_sectors * sector_size;
|
s->packet_transfer_size = nb_sectors * sector_size;
|
||||||
s->io_buffer_index = sector_size;
|
s->io_buffer_index = 0;
|
||||||
|
s->io_buffer_size = 0;
|
||||||
s->cd_sector_size = sector_size;
|
s->cd_sector_size = sector_size;
|
||||||
|
|
||||||
s->status = READY_STAT | DRQ_STAT;
|
/* XXX: check if BUSY_STAT should be set */
|
||||||
|
s->status = READY_STAT | DRQ_STAT | BUSY_STAT;
|
||||||
ide_dma_start(s, ide_atapi_cmd_read_dma_cb);
|
ide_dma_start(s, ide_atapi_cmd_read_dma_cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2103,59 +2166,19 @@ static void ide_map(PCIDevice *pci_dev, int region_num,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XXX: full callback usage to prepare non blocking I/Os support -
|
static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb)
|
||||||
error handling */
|
|
||||||
static void ide_dma_loop(BMDMAState *bm)
|
|
||||||
{
|
|
||||||
struct {
|
|
||||||
uint32_t addr;
|
|
||||||
uint32_t size;
|
|
||||||
} prd;
|
|
||||||
target_phys_addr_t cur_addr;
|
|
||||||
int len, i, len1;
|
|
||||||
|
|
||||||
cur_addr = bm->addr;
|
|
||||||
/* at most one page to avoid hanging if erroneous parameters */
|
|
||||||
for(i = 0; i < 512; i++) {
|
|
||||||
cpu_physical_memory_read(cur_addr, (uint8_t *)&prd, 8);
|
|
||||||
prd.addr = le32_to_cpu(prd.addr);
|
|
||||||
prd.size = le32_to_cpu(prd.size);
|
|
||||||
#ifdef DEBUG_IDE
|
|
||||||
printf("ide: dma: prd: %08x: addr=0x%08x size=0x%08x\n",
|
|
||||||
(int)cur_addr, prd.addr, prd.size);
|
|
||||||
#endif
|
|
||||||
len = prd.size & 0xfffe;
|
|
||||||
if (len == 0)
|
|
||||||
len = 0x10000;
|
|
||||||
while (len > 0) {
|
|
||||||
len1 = bm->dma_cb(bm->ide_if, prd.addr, len);
|
|
||||||
if (len1 == 0)
|
|
||||||
goto the_end;
|
|
||||||
prd.addr += len1;
|
|
||||||
len -= len1;
|
|
||||||
}
|
|
||||||
/* end of transfer */
|
|
||||||
if (prd.size & 0x80000000)
|
|
||||||
break;
|
|
||||||
cur_addr += 8;
|
|
||||||
}
|
|
||||||
/* end of transfer */
|
|
||||||
the_end:
|
|
||||||
bm->status &= ~BM_STATUS_DMAING;
|
|
||||||
bm->status |= BM_STATUS_INT;
|
|
||||||
bm->dma_cb = NULL;
|
|
||||||
bm->ide_if = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void ide_dma_start(IDEState *s, IDEDMAFunc *dma_cb)
|
|
||||||
{
|
{
|
||||||
BMDMAState *bm = s->bmdma;
|
BMDMAState *bm = s->bmdma;
|
||||||
if(!bm)
|
if(!bm)
|
||||||
return;
|
return;
|
||||||
bm->ide_if = s;
|
bm->ide_if = s;
|
||||||
bm->dma_cb = dma_cb;
|
bm->dma_cb = dma_cb;
|
||||||
|
bm->cur_addr = bm->addr;
|
||||||
|
bm->cur_prd_last = 0;
|
||||||
|
bm->cur_prd_addr = 0;
|
||||||
|
bm->cur_prd_len = 0;
|
||||||
if (bm->status & BM_STATUS_DMAING) {
|
if (bm->status & BM_STATUS_DMAING) {
|
||||||
ide_dma_loop(bm);
|
bm->dma_cb(bm, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2167,14 +2190,28 @@ static void bmdma_cmd_writeb(void *opaque, uint32_t addr, uint32_t val)
|
|||||||
#endif
|
#endif
|
||||||
if (!(val & BM_CMD_START)) {
|
if (!(val & BM_CMD_START)) {
|
||||||
/* XXX: do it better */
|
/* XXX: do it better */
|
||||||
bm->status &= ~BM_STATUS_DMAING;
|
if (bm->status & BM_STATUS_DMAING) {
|
||||||
|
bm->status &= ~BM_STATUS_DMAING;
|
||||||
|
/* cancel DMA request */
|
||||||
|
bm->ide_if = NULL;
|
||||||
|
bm->dma_cb = NULL;
|
||||||
|
if (bm->aiocb) {
|
||||||
|
#ifdef DEBUG_AIO
|
||||||
|
printf("aio_cancel\n");
|
||||||
|
#endif
|
||||||
|
bdrv_aio_cancel(bm->aiocb);
|
||||||
|
bm->aiocb = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
bm->cmd = val & 0x09;
|
bm->cmd = val & 0x09;
|
||||||
} else {
|
} else {
|
||||||
bm->status |= BM_STATUS_DMAING;
|
if (!(bm->status & BM_STATUS_DMAING)) {
|
||||||
|
bm->status |= BM_STATUS_DMAING;
|
||||||
|
/* start dma transfer if possible */
|
||||||
|
if (bm->dma_cb)
|
||||||
|
bm->dma_cb(bm, 0);
|
||||||
|
}
|
||||||
bm->cmd = val & 0x09;
|
bm->cmd = val & 0x09;
|
||||||
/* start dma transfer if possible */
|
|
||||||
if (bm->dma_cb)
|
|
||||||
ide_dma_loop(bm);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user