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; }
static bool vring_enable_cb(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); START_USE(vq); /* We optimistically turn back on interrupts, then check if there was * more to do. */ vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; mb(); if (unlikely(more_used(vq))) { END_USE(vq); return false; } END_USE(vq); return true; }
irqreturn_t vring_interrupt(int irq, void *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); if (!more_used(vq)) { pr_debug("virtqueue interrupt with no work for %p\n", vq); return IRQ_NONE; } if (unlikely(vq->broken)) return IRQ_HANDLED; pr_debug("virtqueue callback for %p (%p)\n", vq, vq->vq.callback); if (vq->vq.callback) vq->vq.callback(&vq->vq); return IRQ_HANDLED; }
static bool vring_restart(struct virtqueue *_vq) { struct vring_virtqueue *vq = to_vvq(_vq); DPrintf(6, ("%s\n", __FUNCTION__) ); //BUG_ON(!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)); /* We optimistically turn back on interrupts, then check if there was * more to do. */ vring_enable_interrupts(_vq); if (more_used(vq)) { vring_disable_interrupts(_vq); return 0; } return 1; }
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; }