Commit 7aea4412b677749afa237940aa49f364cb19a2a8
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 |