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 |