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 {
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 mutex mutex;
struct virtio_device vdev;
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;
u32 features, rx_vqs, tx_vqs, 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];
u32 features, queue_pairs;
int vhost_fd;
int tap_fd;
......@@ -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)
{
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 net_dev *ndev = p;
u16 out, in;
u16 head;
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 = ndev->kvm;
vq = &ndev->vqs[id];
while (1) {
mutex_lock(&ndev->io_lock[id]);
mutex_lock(&queue->lock);
if (!virt_queue__available(vq))
pthread_cond_wait(&ndev->io_cond[id], &ndev->io_lock[id].mutex);
mutex_unlock(&ndev->io_lock[id]);
pthread_cond_wait(&queue->cond, &queue->lock.mutex);
mutex_unlock(&queue->lock);
while (virt_queue__available(vq)) {
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)
len = ndev->ops->rx(&dummy_iov, 1, ndev);
if (len < 0) {
pr_warning("%s: rx on vq %u failed (%d), exiting thread\n",
__func__, id, len);
__func__, queue->id, len);
goto out_err;
}
......@@ -155,7 +154,7 @@ static void *virtio_net_rx_thread(void *p)
/* We should interrupt guest right now, otherwise latency is huge. */
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:
static void *virtio_net_tx_thread(void *p)
{
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 net_dev *ndev = p;
u16 out, in;
u16 head;
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 = ndev->kvm;
vq = &ndev->vqs[id];
while (1) {
mutex_lock(&ndev->io_lock[id]);
mutex_lock(&queue->lock);
if (!virt_queue__available(vq))
pthread_cond_wait(&ndev->io_cond[id], &ndev->io_lock[id].mutex);
mutex_unlock(&ndev->io_lock[id]);
pthread_cond_wait(&queue->cond, &queue->lock.mutex);
mutex_unlock(&queue->lock);
while (virt_queue__available(vq)) {
struct virtio_net_hdr *hdr;
......@@ -199,7 +193,7 @@ static void *virtio_net_tx_thread(void *p)
len = ndev->ops->tx(iov, out, ndev);
if (len < 0) {
pr_warning("%s: tx on vq %u failed (%d)\n",
__func__, id, errno);
__func__, queue->id, errno);
goto out_err;
}
......@@ -207,7 +201,7 @@ static void *virtio_net_tx_thread(void *p)
}
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:
......@@ -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)
{
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;
struct net_dev *ndev = p;
struct kvm *kvm = ndev->kvm;
u32 id = ndev->queue_pairs * 2;
struct virt_queue *vq = &ndev->vqs[id];
struct virtio_net_ctrl_hdr *ctrl;
virtio_net_ctrl_ack *ack;
kvm__set_thread_name("virtio-net-ctrl");
while (1) {
mutex_lock(&ndev->io_lock[id]);
mutex_lock(&queue->lock);
if (!virt_queue__available(vq))
pthread_cond_wait(&ndev->io_cond[id], &ndev->io_lock[id].mutex);
mutex_unlock(&ndev->io_lock[id]);
pthread_cond_wait(&queue->cond, &queue->lock.mutex);
mutex_unlock(&queue->lock);
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;
ack = iov[out].iov_base;
......@@ -253,11 +247,11 @@ static void *virtio_net_ctrl_thread(void *p)
*ack = VIRTIO_NET_ERR;
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]))
ndev->vdev.ops->signal_vq(kvm, &ndev->vdev, id);
if (virtio_queue__should_signal(vq))
ndev->vdev.ops->signal_vq(kvm, &ndev->vdev, queue->id);
}
pthread_exit(NULL);
......@@ -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)
{
struct net_dev_queue *net_queue = &ndev->queues[queue];
if ((u32)queue >= (ndev->queue_pairs * 2 + 1)) {
pr_warning("Unknown queue index %u", queue);
return;
}
mutex_lock(&ndev->io_lock[queue]);
pthread_cond_signal(&ndev->io_cond[queue]);
mutex_unlock(&ndev->io_lock[queue]);
mutex_lock(&net_queue->lock);
pthread_cond_signal(&net_queue->cond);
mutex_unlock(&net_queue->lock);
}
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,
u32 pfn)
{
struct vhost_vring_state state = { .index = vq };
struct net_dev_queue *net_queue;
struct vhost_vring_addr addr;
struct net_dev *ndev = dev;
struct virt_queue *queue;
......@@ -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);
queue = &ndev->vqs[vq];
net_queue = &ndev->queues[vq];
net_queue->id = vq;
net_queue->ndev = ndev;
queue = &net_queue->vq;
queue->pfn = pfn;
p = virtio_get_vq(kvm, queue->pfn, page_size);
vring_init(&queue->vring, VIRTIO_NET_QUEUE_SIZE, p, align);
virtio_init_device_vq(&ndev->vdev, queue);
mutex_init(&ndev->io_lock[vq]);
pthread_cond_init(&ndev->io_cond[vq], NULL);
mutex_init(&net_queue->lock);
pthread_cond_init(&net_queue->cond, NULL);
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;
} else if (ndev->vhost_fd == 0 ) {
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
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;
}
......@@ -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)
{
struct net_dev *ndev = dev;
struct net_dev_queue *queue = &ndev->queues[vq];
struct vhost_vring_file file;
int r;
......@@ -666,7 +670,7 @@ static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq)
{
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)
......
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