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;
}
Esempio n. 2
0
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;
}
Esempio n. 3
0
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;
}
Esempio n. 5
0
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;
}