Commit 7aea4412b677749afa237940aa49f364cb19a2a8

Authored by aliguori
1 parent 3b69e4b9

Convert IDE to directly access guest memory (Avi Kivity)

Instead of copying to a temporary buffer, map guest memory for IDE DMA
transactions.

Signed-off-by: Avi Kivity <avi@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@6398 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 117 additions and 16 deletions
hw/ide.c
... ... @@ -422,6 +422,7 @@ typedef struct IDEState {
422 422 int atapi_dma; /* true if dma is requested for the packet cmd */
423 423 /* ATA DMA state */
424 424 int io_buffer_size;
  425 + QEMUIOVector iovec;
425 426 /* PIO transfer handling */
426 427 int req_nb_sectors; /* number of sectors per interrupt */
427 428 EndTransferFunc *end_transfer_func;
... ... @@ -862,6 +863,66 @@ static void ide_sector_read(IDEState *s)
862 863 }
863 864 }
864 865  
  866 +
  867 +/* return 0 if buffer completed */
  868 +static int dma_buf_prepare(BMDMAState *bm, int is_write)
  869 +{
  870 + IDEState *s = bm->ide_if;
  871 + struct {
  872 + uint32_t addr;
  873 + uint32_t size;
  874 + } prd;
  875 + int l, len;
  876 + void *mem;
  877 + target_phys_addr_t l1;
  878 +
  879 + qemu_iovec_init(&s->iovec, s->nsector / (TARGET_PAGE_SIZE/512) + 1);
  880 + s->io_buffer_size = 0;
  881 + for(;;) {
  882 + if (bm->cur_prd_len == 0) {
  883 + /* end of table (with a fail safe of one page) */
  884 + if (bm->cur_prd_last ||
  885 + (bm->cur_addr - bm->addr) >= 4096)
  886 + return s->io_buffer_size != 0;
  887 + cpu_physical_memory_read(bm->cur_addr, (uint8_t *)&prd, 8);
  888 + bm->cur_addr += 8;
  889 + prd.addr = le32_to_cpu(prd.addr);
  890 + prd.size = le32_to_cpu(prd.size);
  891 + len = prd.size & 0xfffe;
  892 + if (len == 0)
  893 + len = 0x10000;
  894 + bm->cur_prd_len = len;
  895 + bm->cur_prd_addr = prd.addr;
  896 + bm->cur_prd_last = (prd.size & 0x80000000);
  897 + }
  898 + l = bm->cur_prd_len;
  899 + if (l > 0) {
  900 + l1 = l;
  901 + mem = cpu_physical_memory_map(bm->cur_prd_addr, &l1, is_write);
  902 + if (!mem) {
  903 + break;
  904 + }
  905 + qemu_iovec_add(&s->iovec, mem, l1);
  906 + bm->cur_prd_addr += l1;
  907 + bm->cur_prd_len -= l1;
  908 + s->io_buffer_size += l1;
  909 + }
  910 + }
  911 + return 1;
  912 +}
  913 +
  914 +static void dma_buf_commit(IDEState *s, int is_write)
  915 +{
  916 + int i;
  917 +
  918 + for (i = 0; i < s->iovec.niov; ++i) {
  919 + cpu_physical_memory_unmap(s->iovec.iov[i].iov_base,
  920 + s->iovec.iov[i].iov_len, is_write,
  921 + s->iovec.iov[i].iov_len);
  922 + }
  923 + qemu_iovec_destroy(&s->iovec);
  924 +}
  925 +
865 926 static void ide_dma_error(IDEState *s)
866 927 {
867 928 ide_transfer_stop(s);
... ... @@ -883,10 +944,12 @@ static int ide_handle_write_error(IDEState *s, int error, int op)
883 944 s->bmdma->status |= op;
884 945 vm_stop(0);
885 946 } else {
886   - if (op == BM_STATUS_DMA_RETRY)
  947 + if (op == BM_STATUS_DMA_RETRY) {
  948 + dma_buf_commit(s, 0);
887 949 ide_dma_error(s);
888   - else
  950 + } else {
889 951 ide_rw_error(s);
  952 + }
890 953 }
891 954  
892 955 return 1;
... ... @@ -940,6 +1003,39 @@ static int dma_buf_rw(BMDMAState *bm, int is_write)
940 1003 return 1;
941 1004 }
942 1005  
  1006 +typedef struct {
  1007 + BMDMAState *bm;
  1008 + void (*cb)(void *opaque, int ret);
  1009 + QEMUBH *bh;
  1010 +} MapFailureContinuation;
  1011 +
  1012 +static void reschedule_dma(void *opaque)
  1013 +{
  1014 + MapFailureContinuation *cont = opaque;
  1015 +
  1016 + cont->cb(cont->bm, 0);
  1017 + qemu_bh_delete(cont->bh);
  1018 + qemu_free(cont);
  1019 +}
  1020 +
  1021 +static void continue_after_map_failure(void *opaque)
  1022 +{
  1023 + MapFailureContinuation *cont = opaque;
  1024 +
  1025 + cont->bh = qemu_bh_new(reschedule_dma, opaque);
  1026 + qemu_bh_schedule(cont->bh);
  1027 +}
  1028 +
  1029 +static void wait_for_bounce_buffer(BMDMAState *bmdma,
  1030 + void (*cb)(void *opaque, int ret))
  1031 +{
  1032 + MapFailureContinuation *cont = qemu_malloc(sizeof(*cont));
  1033 +
  1034 + cont->bm = bmdma;
  1035 + cont->cb = cb;
  1036 + cpu_register_map_client(cont, continue_after_map_failure);
  1037 +}
  1038 +
943 1039 static void ide_read_dma_cb(void *opaque, int ret)
944 1040 {
945 1041 BMDMAState *bm = opaque;
... ... @@ -948,6 +1044,7 @@ static void ide_read_dma_cb(void *opaque, int ret)
948 1044 int64_t sector_num;
949 1045  
950 1046 if (ret < 0) {
  1047 + dma_buf_commit(s, 1);
951 1048 ide_dma_error(s);
952 1049 return;
953 1050 }
... ... @@ -955,11 +1052,10 @@ static void ide_read_dma_cb(void *opaque, int ret)
955 1052 n = s->io_buffer_size >> 9;
956 1053 sector_num = ide_get_sector(s);
957 1054 if (n > 0) {
  1055 + dma_buf_commit(s, 1);
958 1056 sector_num += n;
959 1057 ide_set_sector(s, sector_num);
960 1058 s->nsector -= n;
961   - if (dma_buf_rw(bm, 1) == 0)
962   - goto eot;
963 1059 }
964 1060  
965 1061 /* end of transfer ? */
... ... @@ -977,15 +1073,19 @@ static void ide_read_dma_cb(void *opaque, int ret)
977 1073  
978 1074 /* launch next transfer */
979 1075 n = s->nsector;
980   - if (n > IDE_DMA_BUF_SECTORS)
981   - n = IDE_DMA_BUF_SECTORS;
982 1076 s->io_buffer_index = 0;
983 1077 s->io_buffer_size = n * 512;
  1078 + if (dma_buf_prepare(bm, 1) == 0)
  1079 + goto eot;
  1080 + if (!s->iovec.niov) {
  1081 + wait_for_bounce_buffer(bm, ide_read_dma_cb);
  1082 + return;
  1083 + }
984 1084 #ifdef DEBUG_AIO
985 1085 printf("aio_read: sector_num=%" PRId64 " n=%d\n", sector_num, n);
986 1086 #endif
987   - bm->aiocb = bdrv_aio_read(s->bs, sector_num, s->io_buffer, n,
988   - ide_read_dma_cb, bm);
  1087 + bm->aiocb = bdrv_aio_readv(s->bs, sector_num, &s->iovec, n,
  1088 + ide_read_dma_cb, bm);
989 1089 ide_dma_submit_check(s, ide_read_dma_cb, bm);
990 1090 }
991 1091  
... ... @@ -1081,6 +1181,7 @@ static void ide_write_dma_cb(void *opaque, int ret)
1081 1181 n = s->io_buffer_size >> 9;
1082 1182 sector_num = ide_get_sector(s);
1083 1183 if (n > 0) {
  1184 + dma_buf_commit(s, 0);
1084 1185 sector_num += n;
1085 1186 ide_set_sector(s, sector_num);
1086 1187 s->nsector -= n;
... ... @@ -1099,20 +1200,20 @@ static void ide_write_dma_cb(void *opaque, int ret)
1099 1200 return;
1100 1201 }
1101 1202  
1102   - /* launch next transfer */
1103 1203 n = s->nsector;
1104   - if (n > IDE_DMA_BUF_SECTORS)
1105   - n = IDE_DMA_BUF_SECTORS;
1106   - s->io_buffer_index = 0;
1107 1204 s->io_buffer_size = n * 512;
1108   -
1109   - if (dma_buf_rw(bm, 0) == 0)
  1205 + /* launch next transfer */
  1206 + if (dma_buf_prepare(bm, 0) == 0)
1110 1207 goto eot;
  1208 + if (!s->iovec.niov) {
  1209 + wait_for_bounce_buffer(bm, ide_write_dma_cb);
  1210 + return;
  1211 + }
1111 1212 #ifdef DEBUG_AIO
1112 1213 printf("aio_write: sector_num=%" PRId64 " n=%d\n", sector_num, n);
1113 1214 #endif
1114   - bm->aiocb = bdrv_aio_write(s->bs, sector_num, s->io_buffer, n,
1115   - ide_write_dma_cb, bm);
  1215 + bm->aiocb = bdrv_aio_writev(s->bs, sector_num, &s->iovec, n,
  1216 + ide_write_dma_cb, bm);
1116 1217 ide_dma_submit_check(s, ide_write_dma_cb, bm);
1117 1218 }
1118 1219  
... ...