Commit 5774cf98ca7da4161ee4265a2db0d92ffff005f3
Committed by
Anthony Liguori
1 parent
024431b3
virtio: make vring_desc_*() take phys addrs
Change the vring descriptor helpers to take the physical address of the descriptor table rather than a virtqueue. This is needed in order to allow these helpers to be used with an indirect descriptor table. Signed-off-by: Mark McLoughlin <markmc@redhat.com> Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Showing
1 changed file
with
33 additions
and
26 deletions
hw/virtio.c
| ... | ... | @@ -85,31 +85,31 @@ static void virtqueue_init(VirtQueue *vq) |
| 85 | 85 | VIRTIO_PCI_VRING_ALIGN); |
| 86 | 86 | } |
| 87 | 87 | |
| 88 | -static inline uint64_t vring_desc_addr(VirtQueue *vq, int i) | |
| 88 | +static inline uint64_t vring_desc_addr(target_phys_addr_t desc_pa, int i) | |
| 89 | 89 | { |
| 90 | 90 | target_phys_addr_t pa; |
| 91 | - pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr); | |
| 91 | + pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, addr); | |
| 92 | 92 | return ldq_phys(pa); |
| 93 | 93 | } |
| 94 | 94 | |
| 95 | -static inline uint32_t vring_desc_len(VirtQueue *vq, int i) | |
| 95 | +static inline uint32_t vring_desc_len(target_phys_addr_t desc_pa, int i) | |
| 96 | 96 | { |
| 97 | 97 | target_phys_addr_t pa; |
| 98 | - pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, len); | |
| 98 | + pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, len); | |
| 99 | 99 | return ldl_phys(pa); |
| 100 | 100 | } |
| 101 | 101 | |
| 102 | -static inline uint16_t vring_desc_flags(VirtQueue *vq, int i) | |
| 102 | +static inline uint16_t vring_desc_flags(target_phys_addr_t desc_pa, int i) | |
| 103 | 103 | { |
| 104 | 104 | target_phys_addr_t pa; |
| 105 | - pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags); | |
| 105 | + pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, flags); | |
| 106 | 106 | return lduw_phys(pa); |
| 107 | 107 | } |
| 108 | 108 | |
| 109 | -static inline uint16_t vring_desc_next(VirtQueue *vq, int i) | |
| 109 | +static inline uint16_t vring_desc_next(target_phys_addr_t desc_pa, int i) | |
| 110 | 110 | { |
| 111 | 111 | target_phys_addr_t pa; |
| 112 | - pa = vq->vring.desc + sizeof(VRingDesc) * i + offsetof(VRingDesc, next); | |
| 112 | + pa = desc_pa + sizeof(VRingDesc) * i + offsetof(VRingDesc, next); | |
| 113 | 113 | return lduw_phys(pa); |
| 114 | 114 | } |
| 115 | 115 | |
| ... | ... | @@ -269,20 +269,21 @@ static unsigned int virtqueue_get_head(VirtQueue *vq, unsigned int idx) |
| 269 | 269 | return head; |
| 270 | 270 | } |
| 271 | 271 | |
| 272 | -static unsigned virtqueue_next_desc(VirtQueue *vq, unsigned int i) | |
| 272 | +static unsigned virtqueue_next_desc(target_phys_addr_t desc_pa, | |
| 273 | + unsigned int i, unsigned int max) | |
| 273 | 274 | { |
| 274 | 275 | unsigned int next; |
| 275 | 276 | |
| 276 | 277 | /* If this descriptor says it doesn't chain, we're done. */ |
| 277 | - if (!(vring_desc_flags(vq, i) & VRING_DESC_F_NEXT)) | |
| 278 | - return vq->vring.num; | |
| 278 | + if (!(vring_desc_flags(desc_pa, i) & VRING_DESC_F_NEXT)) | |
| 279 | + return max; | |
| 279 | 280 | |
| 280 | 281 | /* Check they're not leading us off end of descriptors. */ |
| 281 | - next = vring_desc_next(vq, i); | |
| 282 | + next = vring_desc_next(desc_pa, i); | |
| 282 | 283 | /* Make sure compiler knows to grab that: we don't want it changing! */ |
| 283 | 284 | wmb(); |
| 284 | 285 | |
| 285 | - if (next >= vq->vring.num) { | |
| 286 | + if (next >= max) { | |
| 286 | 287 | fprintf(stderr, "Desc next is %u", next); |
| 287 | 288 | exit(1); |
| 288 | 289 | } |
| ... | ... | @@ -292,10 +293,12 @@ static unsigned virtqueue_next_desc(VirtQueue *vq, unsigned int i) |
| 292 | 293 | |
| 293 | 294 | int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) |
| 294 | 295 | { |
| 295 | - unsigned int idx; | |
| 296 | + target_phys_addr_t desc_pa = vq->vring.desc; | |
| 297 | + unsigned int idx, max; | |
| 296 | 298 | int num_bufs, in_total, out_total; |
| 297 | 299 | |
| 298 | 300 | idx = vq->last_avail_idx; |
| 301 | + max = vq->vring.num; | |
| 299 | 302 | |
| 300 | 303 | num_bufs = in_total = out_total = 0; |
| 301 | 304 | while (virtqueue_num_heads(vq, idx)) { |
| ... | ... | @@ -304,21 +307,21 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) |
| 304 | 307 | i = virtqueue_get_head(vq, idx++); |
| 305 | 308 | do { |
| 306 | 309 | /* If we've got too many, that implies a descriptor loop. */ |
| 307 | - if (++num_bufs > vq->vring.num) { | |
| 310 | + if (++num_bufs > max) { | |
| 308 | 311 | fprintf(stderr, "Looped descriptor"); |
| 309 | 312 | exit(1); |
| 310 | 313 | } |
| 311 | 314 | |
| 312 | - if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) { | |
| 315 | + if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) { | |
| 313 | 316 | if (in_bytes > 0 && |
| 314 | - (in_total += vring_desc_len(vq, i)) >= in_bytes) | |
| 317 | + (in_total += vring_desc_len(desc_pa, i)) >= in_bytes) | |
| 315 | 318 | return 1; |
| 316 | 319 | } else { |
| 317 | 320 | if (out_bytes > 0 && |
| 318 | - (out_total += vring_desc_len(vq, i)) >= out_bytes) | |
| 321 | + (out_total += vring_desc_len(desc_pa, i)) >= out_bytes) | |
| 319 | 322 | return 1; |
| 320 | 323 | } |
| 321 | - } while ((i = virtqueue_next_desc(vq, i)) != vq->vring.num); | |
| 324 | + } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max); | |
| 322 | 325 | } |
| 323 | 326 | |
| 324 | 327 | return 0; |
| ... | ... | @@ -326,7 +329,8 @@ int virtqueue_avail_bytes(VirtQueue *vq, int in_bytes, int out_bytes) |
| 326 | 329 | |
| 327 | 330 | int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) |
| 328 | 331 | { |
| 329 | - unsigned int i, head; | |
| 332 | + unsigned int i, head, max; | |
| 333 | + target_phys_addr_t desc_pa = vq->vring.desc; | |
| 330 | 334 | target_phys_addr_t len; |
| 331 | 335 | |
| 332 | 336 | if (!virtqueue_num_heads(vq, vq->last_avail_idx)) |
| ... | ... | @@ -335,23 +339,26 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) |
| 335 | 339 | /* When we start there are none of either input nor output. */ |
| 336 | 340 | elem->out_num = elem->in_num = 0; |
| 337 | 341 | |
| 342 | + max = vq->vring.num; | |
| 343 | + | |
| 338 | 344 | i = head = virtqueue_get_head(vq, vq->last_avail_idx++); |
| 339 | 345 | do { |
| 340 | 346 | struct iovec *sg; |
| 341 | 347 | int is_write = 0; |
| 342 | 348 | |
| 343 | - if (vring_desc_flags(vq, i) & VRING_DESC_F_WRITE) { | |
| 344 | - elem->in_addr[elem->in_num] = vring_desc_addr(vq, i); | |
| 349 | + if (vring_desc_flags(desc_pa, i) & VRING_DESC_F_WRITE) { | |
| 350 | + elem->in_addr[elem->in_num] = vring_desc_addr(desc_pa, i); | |
| 345 | 351 | sg = &elem->in_sg[elem->in_num++]; |
| 346 | 352 | is_write = 1; |
| 347 | 353 | } else |
| 348 | 354 | sg = &elem->out_sg[elem->out_num++]; |
| 349 | 355 | |
| 350 | 356 | /* Grab the first descriptor, and check it's OK. */ |
| 351 | - sg->iov_len = vring_desc_len(vq, i); | |
| 357 | + sg->iov_len = vring_desc_len(desc_pa, i); | |
| 352 | 358 | len = sg->iov_len; |
| 353 | 359 | |
| 354 | - sg->iov_base = cpu_physical_memory_map(vring_desc_addr(vq, i), &len, is_write); | |
| 360 | + sg->iov_base = cpu_physical_memory_map(vring_desc_addr(desc_pa, i), | |
| 361 | + &len, is_write); | |
| 355 | 362 | |
| 356 | 363 | if (sg->iov_base == NULL || len != sg->iov_len) { |
| 357 | 364 | fprintf(stderr, "virtio: trying to map MMIO memory\n"); |
| ... | ... | @@ -359,11 +366,11 @@ int virtqueue_pop(VirtQueue *vq, VirtQueueElement *elem) |
| 359 | 366 | } |
| 360 | 367 | |
| 361 | 368 | /* If we've got too many, that implies a descriptor loop. */ |
| 362 | - if ((elem->in_num + elem->out_num) > vq->vring.num) { | |
| 369 | + if ((elem->in_num + elem->out_num) > max) { | |
| 363 | 370 | fprintf(stderr, "Looped descriptor"); |
| 364 | 371 | exit(1); |
| 365 | 372 | } |
| 366 | - } while ((i = virtqueue_next_desc(vq, i)) != vq->vring.num); | |
| 373 | + } while ((i = virtqueue_next_desc(desc_pa, i, max)) != max); | |
| 367 | 374 | |
| 368 | 375 | elem->index = head; |
| 369 | 376 | ... | ... |