void* vring_detach_unused_buf(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); unsigned int i; void *buf; for (i = 0; i < vq->vring.num; i++) { if (!vq->data[i]) continue; buf = vq->data[i]; detach_buf(vq, i); vq->vring.avail->idx--; return buf; } return NULL; }
static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len) { struct vring_virtqueue *vq = to_vvq(_vq); void *ret; struct vring_used_elem *u; unsigned int i; if (!more_used(vq)) { DPrintf(4, ("No more buffers in queue: last_used_idx %d vring.used->idx %d\n", vq->last_used_idx, vq->vring.used->idx)); return NULL; } /* Only get used array entries after they have been exposed by host. */ rmb(); u = &vq->vring.used->ring[vq->last_used_idx % vq->vring.num]; i = u->id; *len = u->len; DPrintf(4, ("%s>>> id %d, len %d\n", __FUNCTION__, i, *len) ); if (i >= vq->vring.num) { DPrintf(0, ("id %u out of range\n", i) ); return NULL; } if (!vq->data[i]) { DPrintf(0, ("id %u is not a head!\n", i) ); return NULL; } /* detach_buf clears data, so grab it now. */ ret = vq->data[i]; detach_buf(vq, i); ++vq->last_used_idx; if (!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) { *vq->vring.vring_last_used_ptr = vq->last_used_idx; mb(); } return ret; }
void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) { struct vring_virtqueue *vq = to_vvq(_vq); u16 last_used; unsigned i; void *ret; rmb(); last_used = (vq->last_used_idx & (vq->vring.num-1)); i = vq->vring.used->ring[last_used].id; *len = vq->vring.used->ring[last_used].len; ret = vq->data[i]; detach_buf(vq, i); vq->last_used_idx++; return ret; }
void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len) { struct vring_virtqueue *vq = to_vvq(_vq); void *ret; unsigned int i; START_USE(vq); if (unlikely(vq->broken)) { END_USE(vq); return NULL; } if (!more_used(vq)) { pr_debug("No more buffers in queue\n"); END_USE(vq); return NULL; } /* Only get used array entries after they have been exposed by host. */ virtio_rmb(); i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id; *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len; if (unlikely(i >= vq->vring.num)) { BAD_RING(vq, "id %u out of range\n", i); return NULL; } if (unlikely(!vq->data[i])) { BAD_RING(vq, "id %u is not a head!\n", i); return NULL; } /* detach_buf clears data, so grab it now. */ ret = vq->data[i]; detach_buf(vq, i); vq->last_used_idx++; END_USE(vq); return ret; }
void *virtqueue_detach_unused_buf(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); unsigned int i; void *buf; START_USE(vq); for (i = 0; i < vq->vring.num; i++) { if (!vq->data[i]) continue; /* detach_buf clears data, so grab it now. */ buf = vq->data[i]; detach_buf(vq, i); END_USE(vq); return buf; } /* That should have freed everything. */ BUG_ON(vq->num_free != vq->vring.num); END_USE(vq); return NULL; }