Changeset View
Changeset View
Standalone View
Standalone View
sys/dev/virtio/virtqueue.c
Show First 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | |||||
static void vq_ring_init(struct virtqueue *); | static void vq_ring_init(struct virtqueue *); | ||||
static void vq_ring_update_avail(struct virtqueue *, uint16_t); | static void vq_ring_update_avail(struct virtqueue *, uint16_t); | ||||
static uint16_t vq_ring_enqueue_segments(struct virtqueue *, | static uint16_t vq_ring_enqueue_segments(struct virtqueue *, | ||||
struct vring_desc *, uint16_t, struct sglist *, int, int); | struct vring_desc *, uint16_t, struct sglist *, int, int); | ||||
static int vq_ring_use_indirect(struct virtqueue *, int); | static int vq_ring_use_indirect(struct virtqueue *, int); | ||||
static void vq_ring_enqueue_indirect(struct virtqueue *, void *, | static void vq_ring_enqueue_indirect(struct virtqueue *, void *, | ||||
struct sglist *, int, int); | struct sglist *, int, int); | ||||
static int vq_ring_enable_interrupt(struct virtqueue *, uint16_t); | static int vq_ring_enable_interrupt(struct virtqueue *, uint16_t); | ||||
static int vq_ring_must_notify_host(struct virtqueue *); | |||||
static void vq_ring_notify_host(struct virtqueue *); | |||||
static void vq_ring_free_chain(struct virtqueue *, uint16_t); | static void vq_ring_free_chain(struct virtqueue *, uint16_t); | ||||
SDT_PROVIDER_DEFINE(virtqueue); | SDT_PROVIDER_DEFINE(virtqueue); | ||||
SDT_PROBE_DEFINE6(virtqueue, , enqueue_segments, entry, "struct virtqueue *", | SDT_PROBE_DEFINE6(virtqueue, , enqueue_segments, entry, "struct virtqueue *", | ||||
"struct vring_desc *", "uint16_t", "struct sglist *", "int", "int"); | "struct vring_desc *", "uint16_t", "struct sglist *", "int", "int"); | ||||
SDT_PROBE_DEFINE1(virtqueue, , enqueue_segments, return, "uint16_t"); | SDT_PROBE_DEFINE1(virtqueue, , enqueue_segments, return, "uint16_t"); | ||||
#define vq_modern(_vq) (((_vq)->vq_flags & VIRTQUEUE_FLAG_MODERN) != 0) | #define vq_modern(_vq) (((_vq)->vq_flags & VIRTQUEUE_FLAG_MODERN) != 0) | ||||
▲ Show 20 Lines • Show All 282 Lines • ▼ Show 20 Lines | |||||
int | int | ||||
virtqueue_full(struct virtqueue *vq) | virtqueue_full(struct virtqueue *vq) | ||||
{ | { | ||||
return (vq->vq_free_cnt == 0); | return (vq->vq_free_cnt == 0); | ||||
} | } | ||||
void | bool | ||||
virtqueue_notify(struct virtqueue *vq) | virtqueue_notify(struct virtqueue *vq) | ||||
{ | { | ||||
/* Ensure updated avail->idx is visible to host. */ | /* Ensure updated avail->idx is visible to host. */ | ||||
mb(); | mb(); | ||||
if (vq_ring_must_notify_host(vq)) | if (vq_ring_must_notify_host(vq)) | ||||
vq_ring_notify_host(vq); | vq_ring_notify_host(vq); | ||||
vq->vq_queued_cnt = 0; | vq->vq_queued_cnt = 0; | ||||
/* Unlike the Linux API, we currently never report failure. */ | |||||
return true; | |||||
} | } | ||||
int | int | ||||
virtqueue_nused(struct virtqueue *vq) | virtqueue_nused(struct virtqueue *vq) | ||||
{ | { | ||||
uint16_t used_idx, nused; | uint16_t used_idx, nused; | ||||
used_idx = vq_htog16(vq, vq->vq_ring.used->idx); | used_idx = vq_htog16(vq, vq->vq_ring.used->idx); | ||||
▲ Show 20 Lines • Show All 360 Lines • ▼ Show 20 Lines | vq_ring_enable_interrupt(struct virtqueue *vq, uint16_t ndesc) | ||||
* entries. | * entries. | ||||
*/ | */ | ||||
if (virtqueue_nused(vq) > ndesc) | if (virtqueue_nused(vq) > ndesc) | ||||
return (1); | return (1); | ||||
return (0); | return (0); | ||||
} | } | ||||
static int | bool | ||||
vq_ring_must_notify_host(struct virtqueue *vq) | vq_ring_must_notify_host(struct virtqueue *vq) | ||||
{ | { | ||||
uint16_t new_idx, prev_idx, event_idx, flags; | uint16_t new_idx, prev_idx, event_idx, flags; | ||||
if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) { | if (vq->vq_flags & VIRTQUEUE_FLAG_EVENT_IDX) { | ||||
new_idx = vq_htog16(vq, vq->vq_ring.avail->idx); | new_idx = vq_htog16(vq, vq->vq_ring.avail->idx); | ||||
prev_idx = new_idx - vq->vq_queued_cnt; | prev_idx = new_idx - vq->vq_queued_cnt; | ||||
event_idx = vq_htog16(vq, vring_avail_event(&vq->vq_ring)); | event_idx = vq_htog16(vq, vring_avail_event(&vq->vq_ring)); | ||||
return (vring_need_event(event_idx, new_idx, prev_idx) != 0); | return (vring_need_event(event_idx, new_idx, prev_idx) != 0); | ||||
} | } | ||||
flags = vq->vq_ring.used->flags; | flags = vq->vq_ring.used->flags; | ||||
return ((flags & vq_gtoh16(vq, VRING_USED_F_NO_NOTIFY)) == 0); | return ((flags & vq_gtoh16(vq, VRING_USED_F_NO_NOTIFY)) == 0); | ||||
} | } | ||||
static void | bool | ||||
vq_ring_notify_host(struct virtqueue *vq) | vq_ring_notify_host(struct virtqueue *vq) | ||||
{ | { | ||||
/* TODO: return success/failure */ | |||||
VIRTIO_BUS_NOTIFY_VQ(vq->vq_dev, vq->vq_queue_index, | VIRTIO_BUS_NOTIFY_VQ(vq->vq_dev, vq->vq_queue_index, | ||||
vq->vq_notify_offset); | vq->vq_notify_offset); | ||||
return true; | |||||
} | } | ||||
static void | static void | ||||
vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx) | vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx) | ||||
{ | { | ||||
struct vring_desc *dp; | struct vring_desc *dp; | ||||
struct vq_desc_extra *dxp; | struct vq_desc_extra *dxp; | ||||
Show All 30 Lines |