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,6 +422,7 @@ typedef struct IDEState {
422 int atapi_dma; /* true if dma is requested for the packet cmd */ 422 int atapi_dma; /* true if dma is requested for the packet cmd */
423 /* ATA DMA state */ 423 /* ATA DMA state */
424 int io_buffer_size; 424 int io_buffer_size;
  425 + QEMUIOVector iovec;
425 /* PIO transfer handling */ 426 /* PIO transfer handling */
426 int req_nb_sectors; /* number of sectors per interrupt */ 427 int req_nb_sectors; /* number of sectors per interrupt */
427 EndTransferFunc *end_transfer_func; 428 EndTransferFunc *end_transfer_func;
@@ -862,6 +863,66 @@ static void ide_sector_read(IDEState *s) @@ -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 static void ide_dma_error(IDEState *s) 926 static void ide_dma_error(IDEState *s)
866 { 927 {
867 ide_transfer_stop(s); 928 ide_transfer_stop(s);
@@ -883,10 +944,12 @@ static int ide_handle_write_error(IDEState *s, int error, int op) @@ -883,10 +944,12 @@ static int ide_handle_write_error(IDEState *s, int error, int op)
883 s->bmdma->status |= op; 944 s->bmdma->status |= op;
884 vm_stop(0); 945 vm_stop(0);
885 } else { 946 } else {
886 - if (op == BM_STATUS_DMA_RETRY) 947 + if (op == BM_STATUS_DMA_RETRY) {
  948 + dma_buf_commit(s, 0);
887 ide_dma_error(s); 949 ide_dma_error(s);
888 - else 950 + } else {
889 ide_rw_error(s); 951 ide_rw_error(s);
  952 + }
890 } 953 }
891 954
892 return 1; 955 return 1;
@@ -940,6 +1003,39 @@ static int dma_buf_rw(BMDMAState *bm, int is_write) @@ -940,6 +1003,39 @@ static int dma_buf_rw(BMDMAState *bm, int is_write)
940 return 1; 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 static void ide_read_dma_cb(void *opaque, int ret) 1039 static void ide_read_dma_cb(void *opaque, int ret)
944 { 1040 {
945 BMDMAState *bm = opaque; 1041 BMDMAState *bm = opaque;
@@ -948,6 +1044,7 @@ static void ide_read_dma_cb(void *opaque, int ret) @@ -948,6 +1044,7 @@ static void ide_read_dma_cb(void *opaque, int ret)
948 int64_t sector_num; 1044 int64_t sector_num;
949 1045
950 if (ret < 0) { 1046 if (ret < 0) {
  1047 + dma_buf_commit(s, 1);
951 ide_dma_error(s); 1048 ide_dma_error(s);
952 return; 1049 return;
953 } 1050 }
@@ -955,11 +1052,10 @@ static void ide_read_dma_cb(void *opaque, int ret) @@ -955,11 +1052,10 @@ static void ide_read_dma_cb(void *opaque, int ret)
955 n = s->io_buffer_size >> 9; 1052 n = s->io_buffer_size >> 9;
956 sector_num = ide_get_sector(s); 1053 sector_num = ide_get_sector(s);
957 if (n > 0) { 1054 if (n > 0) {
  1055 + dma_buf_commit(s, 1);
958 sector_num += n; 1056 sector_num += n;
959 ide_set_sector(s, sector_num); 1057 ide_set_sector(s, sector_num);
960 s->nsector -= n; 1058 s->nsector -= n;
961 - if (dma_buf_rw(bm, 1) == 0)  
962 - goto eot;  
963 } 1059 }
964 1060
965 /* end of transfer ? */ 1061 /* end of transfer ? */
@@ -977,15 +1073,19 @@ static void ide_read_dma_cb(void *opaque, int ret) @@ -977,15 +1073,19 @@ static void ide_read_dma_cb(void *opaque, int ret)
977 1073
978 /* launch next transfer */ 1074 /* launch next transfer */
979 n = s->nsector; 1075 n = s->nsector;
980 - if (n > IDE_DMA_BUF_SECTORS)  
981 - n = IDE_DMA_BUF_SECTORS;  
982 s->io_buffer_index = 0; 1076 s->io_buffer_index = 0;
983 s->io_buffer_size = n * 512; 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 #ifdef DEBUG_AIO 1084 #ifdef DEBUG_AIO
985 printf("aio_read: sector_num=%" PRId64 " n=%d\n", sector_num, n); 1085 printf("aio_read: sector_num=%" PRId64 " n=%d\n", sector_num, n);
986 #endif 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 ide_dma_submit_check(s, ide_read_dma_cb, bm); 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,6 +1181,7 @@ static void ide_write_dma_cb(void *opaque, int ret)
1081 n = s->io_buffer_size >> 9; 1181 n = s->io_buffer_size >> 9;
1082 sector_num = ide_get_sector(s); 1182 sector_num = ide_get_sector(s);
1083 if (n > 0) { 1183 if (n > 0) {
  1184 + dma_buf_commit(s, 0);
1084 sector_num += n; 1185 sector_num += n;
1085 ide_set_sector(s, sector_num); 1186 ide_set_sector(s, sector_num);
1086 s->nsector -= n; 1187 s->nsector -= n;
@@ -1099,20 +1200,20 @@ static void ide_write_dma_cb(void *opaque, int ret) @@ -1099,20 +1200,20 @@ static void ide_write_dma_cb(void *opaque, int ret)
1099 return; 1200 return;
1100 } 1201 }
1101 1202
1102 - /* launch next transfer */  
1103 n = s->nsector; 1203 n = s->nsector;
1104 - if (n > IDE_DMA_BUF_SECTORS)  
1105 - n = IDE_DMA_BUF_SECTORS;  
1106 - s->io_buffer_index = 0;  
1107 s->io_buffer_size = n * 512; 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 goto eot; 1207 goto eot;
  1208 + if (!s->iovec.niov) {
  1209 + wait_for_bounce_buffer(bm, ide_write_dma_cb);
  1210 + return;
  1211 + }
1111 #ifdef DEBUG_AIO 1212 #ifdef DEBUG_AIO
1112 printf("aio_write: sector_num=%" PRId64 " n=%d\n", sector_num, n); 1213 printf("aio_write: sector_num=%" PRId64 " n=%d\n", sector_num, n);
1113 #endif 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 ide_dma_submit_check(s, ide_write_dma_cb, bm); 1217 ide_dma_submit_check(s, ide_write_dma_cb, bm);
1117 } 1218 }
1118 1219