Commit ad96e867 authored by Jean-Philippe Brucker's avatar Jean-Philippe Brucker Committed by Will Deacon
Browse files

virtio/net: Clean virtqueue state



Currently the virtqueue state is mixed with the netdev state. Move it to a
separate structure.
Signed-off-by: default avatarJean-Philippe Brucker <jean-philippe.brucker@arm.com>
Signed-off-by: default avatarJulien Thierry <julien.thierry@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent d87b503f
...@@ -36,18 +36,23 @@ struct net_dev_operations { ...@@ -36,18 +36,23 @@ struct net_dev_operations {
int (*tx)(struct iovec *iov, u16 in, struct net_dev *ndev); int (*tx)(struct iovec *iov, u16 in, struct net_dev *ndev);
}; };
struct net_dev_queue {
int id;
struct net_dev *ndev;
struct virt_queue vq;
pthread_t thread;
struct mutex lock;
pthread_cond_t cond;
};
struct net_dev { struct net_dev {
struct mutex mutex; struct mutex mutex;
struct virtio_device vdev; struct virtio_device vdev;
struct list_head list; struct list_head list;
struct virt_queue vqs[VIRTIO_NET_NUM_QUEUES * 2 + 1]; struct net_dev_queue queues[VIRTIO_NET_NUM_QUEUES * 2 + 1];
struct virtio_net_config config; struct virtio_net_config config;
u32 features, rx_vqs, tx_vqs, queue_pairs; u32 features, queue_pairs;
pthread_t io_thread[VIRTIO_NET_NUM_QUEUES * 2 + 1];
struct mutex io_lock[VIRTIO_NET_NUM_QUEUES * 2 + 1];
pthread_cond_t io_cond[VIRTIO_NET_NUM_QUEUES * 2 + 1];
int vhost_fd; int vhost_fd;
int tap_fd; int tap_fd;
...@@ -92,28 +97,22 @@ static void virtio_net_fix_rx_hdr(struct virtio_net_hdr *hdr, struct net_dev *nd ...@@ -92,28 +97,22 @@ static void virtio_net_fix_rx_hdr(struct virtio_net_hdr *hdr, struct net_dev *nd
static void *virtio_net_rx_thread(void *p) static void *virtio_net_rx_thread(void *p)
{ {
struct iovec iov[VIRTIO_NET_QUEUE_SIZE]; struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
struct virt_queue *vq; struct net_dev_queue *queue = p;
struct virt_queue *vq = &queue->vq;
struct net_dev *ndev = queue->ndev;
struct kvm *kvm; struct kvm *kvm;
struct net_dev *ndev = p;
u16 out, in; u16 out, in;
u16 head; u16 head;
int len, copied; int len, copied;
u32 id;
mutex_lock(&ndev->mutex);
id = ndev->rx_vqs++ * 2;
mutex_unlock(&ndev->mutex);
kvm__set_thread_name("virtio-net-rx"); kvm__set_thread_name("virtio-net-rx");
kvm = ndev->kvm; kvm = ndev->kvm;
vq = &ndev->vqs[id];
while (1) { while (1) {
mutex_lock(&ndev->io_lock[id]); mutex_lock(&queue->lock);
if (!virt_queue__available(vq)) if (!virt_queue__available(vq))
pthread_cond_wait(&ndev->io_cond[id], &ndev->io_lock[id].mutex); pthread_cond_wait(&queue->cond, &queue->lock.mutex);
mutex_unlock(&ndev->io_lock[id]); mutex_unlock(&queue->lock);
while (virt_queue__available(vq)) { while (virt_queue__available(vq)) {
unsigned char buffer[MAX_PACKET_SIZE + sizeof(struct virtio_net_hdr_mrg_rxbuf)]; unsigned char buffer[MAX_PACKET_SIZE + sizeof(struct virtio_net_hdr_mrg_rxbuf)];
...@@ -127,7 +126,7 @@ static void *virtio_net_rx_thread(void *p) ...@@ -127,7 +126,7 @@ static void *virtio_net_rx_thread(void *p)
len = ndev->ops->rx(&dummy_iov, 1, ndev); len = ndev->ops->rx(&dummy_iov, 1, ndev);
if (len < 0) { if (len < 0) {
pr_warning("%s: rx on vq %u failed (%d), exiting thread\n", pr_warning("%s: rx on vq %u failed (%d), exiting thread\n",
__func__, id, len); __func__, queue->id, len);
goto out_err; goto out_err;
} }
...@@ -155,7 +154,7 @@ static void *virtio_net_rx_thread(void *p) ...@@ -155,7 +154,7 @@ static void *virtio_net_rx_thread(void *p)
/* We should interrupt guest right now, otherwise latency is huge. */ /* We should interrupt guest right now, otherwise latency is huge. */
if (virtio_queue__should_signal(vq)) if (virtio_queue__should_signal(vq))
ndev->vdev.ops->signal_vq(kvm, &ndev->vdev, id); ndev->vdev.ops->signal_vq(kvm, &ndev->vdev, queue->id);
} }
} }
...@@ -168,28 +167,23 @@ out_err: ...@@ -168,28 +167,23 @@ out_err:
static void *virtio_net_tx_thread(void *p) static void *virtio_net_tx_thread(void *p)
{ {
struct iovec iov[VIRTIO_NET_QUEUE_SIZE]; struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
struct virt_queue *vq; struct net_dev_queue *queue = p;
struct virt_queue *vq = &queue->vq;
struct net_dev *ndev = queue->ndev;
struct kvm *kvm; struct kvm *kvm;
struct net_dev *ndev = p;
u16 out, in; u16 out, in;
u16 head; u16 head;
int len; int len;
u32 id;
mutex_lock(&ndev->mutex);
id = ndev->tx_vqs++ * 2 + 1;
mutex_unlock(&ndev->mutex);
kvm__set_thread_name("virtio-net-tx"); kvm__set_thread_name("virtio-net-tx");
kvm = ndev->kvm; kvm = ndev->kvm;
vq = &ndev->vqs[id];
while (1) { while (1) {
mutex_lock(&ndev->io_lock[id]); mutex_lock(&queue->lock);
if (!virt_queue__available(vq)) if (!virt_queue__available(vq))
pthread_cond_wait(&ndev->io_cond[id], &ndev->io_lock[id].mutex); pthread_cond_wait(&queue->cond, &queue->lock.mutex);
mutex_unlock(&ndev->io_lock[id]); mutex_unlock(&queue->lock);
while (virt_queue__available(vq)) { while (virt_queue__available(vq)) {
struct virtio_net_hdr *hdr; struct virtio_net_hdr *hdr;
...@@ -199,7 +193,7 @@ static void *virtio_net_tx_thread(void *p) ...@@ -199,7 +193,7 @@ static void *virtio_net_tx_thread(void *p)
len = ndev->ops->tx(iov, out, ndev); len = ndev->ops->tx(iov, out, ndev);
if (len < 0) { if (len < 0) {
pr_warning("%s: tx on vq %u failed (%d)\n", pr_warning("%s: tx on vq %u failed (%d)\n",
__func__, id, errno); __func__, queue->id, errno);
goto out_err; goto out_err;
} }
...@@ -207,7 +201,7 @@ static void *virtio_net_tx_thread(void *p) ...@@ -207,7 +201,7 @@ static void *virtio_net_tx_thread(void *p)
} }
if (virtio_queue__should_signal(vq)) if (virtio_queue__should_signal(vq))
ndev->vdev.ops->signal_vq(kvm, &ndev->vdev, id); ndev->vdev.ops->signal_vq(kvm, &ndev->vdev, queue->id);
} }
out_err: out_err:
...@@ -224,24 +218,24 @@ static virtio_net_ctrl_ack virtio_net_handle_mq(struct kvm* kvm, struct net_dev ...@@ -224,24 +218,24 @@ static virtio_net_ctrl_ack virtio_net_handle_mq(struct kvm* kvm, struct net_dev
static void *virtio_net_ctrl_thread(void *p) static void *virtio_net_ctrl_thread(void *p)
{ {
struct iovec iov[VIRTIO_NET_QUEUE_SIZE]; struct iovec iov[VIRTIO_NET_QUEUE_SIZE];
struct net_dev_queue *queue = p;
struct virt_queue *vq = &queue->vq;
struct net_dev *ndev = queue->ndev;
u16 out, in, head; u16 out, in, head;
struct net_dev *ndev = p;
struct kvm *kvm = ndev->kvm; struct kvm *kvm = ndev->kvm;
u32 id = ndev->queue_pairs * 2;
struct virt_queue *vq = &ndev->vqs[id];
struct virtio_net_ctrl_hdr *ctrl; struct virtio_net_ctrl_hdr *ctrl;
virtio_net_ctrl_ack *ack; virtio_net_ctrl_ack *ack;
kvm__set_thread_name("virtio-net-ctrl"); kvm__set_thread_name("virtio-net-ctrl");
while (1) { while (1) {
mutex_lock(&ndev->io_lock[id]); mutex_lock(&queue->lock);
if (!virt_queue__available(vq)) if (!virt_queue__available(vq))
pthread_cond_wait(&ndev->io_cond[id], &ndev->io_lock[id].mutex); pthread_cond_wait(&queue->cond, &queue->lock.mutex);
mutex_unlock(&ndev->io_lock[id]); mutex_unlock(&queue->lock);
while (virt_queue__available(vq)) { while (virt_queue__available(vq)) {
head = virt_queue__get_iov(&ndev->vqs[id], iov, &out, &in, kvm); head = virt_queue__get_iov(vq, iov, &out, &in, kvm);
ctrl = iov[0].iov_base; ctrl = iov[0].iov_base;
ack = iov[out].iov_base; ack = iov[out].iov_base;
...@@ -253,11 +247,11 @@ static void *virtio_net_ctrl_thread(void *p) ...@@ -253,11 +247,11 @@ static void *virtio_net_ctrl_thread(void *p)
*ack = VIRTIO_NET_ERR; *ack = VIRTIO_NET_ERR;
break; break;
} }
virt_queue__set_used_elem(&ndev->vqs[id], head, iov[out].iov_len); virt_queue__set_used_elem(vq, head, iov[out].iov_len);
} }
if (virtio_queue__should_signal(&ndev->vqs[id])) if (virtio_queue__should_signal(vq))
ndev->vdev.ops->signal_vq(kvm, &ndev->vdev, id); ndev->vdev.ops->signal_vq(kvm, &ndev->vdev, queue->id);
} }
pthread_exit(NULL); pthread_exit(NULL);
...@@ -267,14 +261,16 @@ static void *virtio_net_ctrl_thread(void *p) ...@@ -267,14 +261,16 @@ static void *virtio_net_ctrl_thread(void *p)
static void virtio_net_handle_callback(struct kvm *kvm, struct net_dev *ndev, int queue) static void virtio_net_handle_callback(struct kvm *kvm, struct net_dev *ndev, int queue)
{ {
struct net_dev_queue *net_queue = &ndev->queues[queue];
if ((u32)queue >= (ndev->queue_pairs * 2 + 1)) { if ((u32)queue >= (ndev->queue_pairs * 2 + 1)) {
pr_warning("Unknown queue index %u", queue); pr_warning("Unknown queue index %u", queue);
return; return;
} }
mutex_lock(&ndev->io_lock[queue]); mutex_lock(&net_queue->lock);
pthread_cond_signal(&ndev->io_cond[queue]); pthread_cond_signal(&net_queue->cond);
mutex_unlock(&ndev->io_lock[queue]); mutex_unlock(&net_queue->lock);
} }
static int virtio_net_request_tap(struct net_dev *ndev, struct ifreq *ifr, static int virtio_net_request_tap(struct net_dev *ndev, struct ifreq *ifr,
...@@ -552,6 +548,7 @@ static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align, ...@@ -552,6 +548,7 @@ static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align,
u32 pfn) u32 pfn)
{ {
struct vhost_vring_state state = { .index = vq }; struct vhost_vring_state state = { .index = vq };
struct net_dev_queue *net_queue;
struct vhost_vring_addr addr; struct vhost_vring_addr addr;
struct net_dev *ndev = dev; struct net_dev *ndev = dev;
struct virt_queue *queue; struct virt_queue *queue;
...@@ -560,24 +557,30 @@ static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align, ...@@ -560,24 +557,30 @@ static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align,
compat__remove_message(compat_id); compat__remove_message(compat_id);
queue = &ndev->vqs[vq]; net_queue = &ndev->queues[vq];
net_queue->id = vq;
net_queue->ndev = ndev;
queue = &net_queue->vq;
queue->pfn = pfn; queue->pfn = pfn;
p = virtio_get_vq(kvm, queue->pfn, page_size); p = virtio_get_vq(kvm, queue->pfn, page_size);
vring_init(&queue->vring, VIRTIO_NET_QUEUE_SIZE, p, align); vring_init(&queue->vring, VIRTIO_NET_QUEUE_SIZE, p, align);
virtio_init_device_vq(&ndev->vdev, queue); virtio_init_device_vq(&ndev->vdev, queue);
mutex_init(&ndev->io_lock[vq]); mutex_init(&net_queue->lock);
pthread_cond_init(&ndev->io_cond[vq], NULL); pthread_cond_init(&net_queue->cond, NULL);
if (is_ctrl_vq(ndev, vq)) { if (is_ctrl_vq(ndev, vq)) {
pthread_create(&ndev->io_thread[vq], NULL, virtio_net_ctrl_thread, ndev); pthread_create(&net_queue->thread, NULL, virtio_net_ctrl_thread,
net_queue);
return 0; return 0;
} else if (ndev->vhost_fd == 0 ) { } else if (ndev->vhost_fd == 0 ) {
if (vq & 1) if (vq & 1)
pthread_create(&ndev->io_thread[vq], NULL, virtio_net_tx_thread, ndev); pthread_create(&net_queue->thread, NULL,
virtio_net_tx_thread, net_queue);
else else
pthread_create(&ndev->io_thread[vq], NULL, virtio_net_rx_thread, ndev); pthread_create(&net_queue->thread, NULL,
virtio_net_rx_thread, net_queue);
return 0; return 0;
} }
...@@ -611,6 +614,7 @@ static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align, ...@@ -611,6 +614,7 @@ static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align,
static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi) static void notify_vq_gsi(struct kvm *kvm, void *dev, u32 vq, u32 gsi)
{ {
struct net_dev *ndev = dev; struct net_dev *ndev = dev;
struct net_dev_queue *queue = &ndev->queues[vq];
struct vhost_vring_file file; struct vhost_vring_file file;
int r; int r;
...@@ -666,7 +670,7 @@ static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq) ...@@ -666,7 +670,7 @@ static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq)
{ {
struct net_dev *ndev = dev; struct net_dev *ndev = dev;
return &ndev->vqs[vq]; return &ndev->queues[vq].vq;
} }
static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment