Skip to content

Commit

Permalink
virtio_net: refactor freeze/restore logic into virtnet reset logic
Browse files Browse the repository at this point in the history
For XDP we will need to reset the queues to allow for buffer headroom
to be configured. In order to do this we need to essentially run the
freeze()/restore() code path. Unfortunately the locking requirements
between the freeze/restore and reset paths are different however so
we can not simply reuse the code.

This patch refactors the code path and adds a reset helper routine.

Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Acked-by: Jason Wang <jasowang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
John Fastabend authored and David S. Miller committed Feb 7, 2017
1 parent 722d828 commit 9fe7bfc
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 48 deletions.
75 changes: 46 additions & 29 deletions drivers/net/virtio_net.c
Original file line number Diff line number Diff line change
Expand Up @@ -1661,6 +1661,49 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
.set_settings = virtnet_set_settings,
};

static void virtnet_freeze_down(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
int i;

/* Make sure no work handler is accessing the device */
flush_work(&vi->config_work);

netif_device_detach(vi->dev);
cancel_delayed_work_sync(&vi->refill);

if (netif_running(vi->dev)) {
for (i = 0; i < vi->max_queue_pairs; i++)
napi_disable(&vi->rq[i].napi);
}
}

static int init_vqs(struct virtnet_info *vi);

static int virtnet_restore_up(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
int err, i;

err = init_vqs(vi);
if (err)
return err;

virtio_device_ready(vdev);

if (netif_running(vi->dev)) {
for (i = 0; i < vi->curr_queue_pairs; i++)
if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
schedule_delayed_work(&vi->refill, 0);

for (i = 0; i < vi->max_queue_pairs; i++)
virtnet_napi_enable(&vi->rq[i]);
}

netif_device_attach(vi->dev);
return err;
}

static int virtnet_xdp_set(struct net_device *dev, struct bpf_prog *prog)
{
unsigned long int max_sz = PAGE_SIZE - sizeof(struct padded_vnet_hdr);
Expand Down Expand Up @@ -2353,21 +2396,9 @@ static void virtnet_remove(struct virtio_device *vdev)
static int virtnet_freeze(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
int i;

virtnet_cpu_notif_remove(vi);

/* Make sure no work handler is accessing the device */
flush_work(&vi->config_work);

netif_device_detach(vi->dev);
cancel_delayed_work_sync(&vi->refill);

if (netif_running(vi->dev)) {
for (i = 0; i < vi->max_queue_pairs; i++)
napi_disable(&vi->rq[i].napi);
}

virtnet_freeze_down(vdev);
remove_vq_common(vi);

return 0;
Expand All @@ -2376,25 +2407,11 @@ static int virtnet_freeze(struct virtio_device *vdev)
static int virtnet_restore(struct virtio_device *vdev)
{
struct virtnet_info *vi = vdev->priv;
int err, i;
int err;

err = init_vqs(vi);
err = virtnet_restore_up(vdev);
if (err)
return err;

virtio_device_ready(vdev);

if (netif_running(vi->dev)) {
for (i = 0; i < vi->curr_queue_pairs; i++)
if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
schedule_delayed_work(&vi->refill, 0);

for (i = 0; i < vi->max_queue_pairs; i++)
virtnet_napi_enable(&vi->rq[i]);
}

netif_device_attach(vi->dev);

virtnet_set_queues(vi, vi->curr_queue_pairs);

err = virtnet_cpu_notif_add(vi);
Expand Down
42 changes: 23 additions & 19 deletions drivers/virtio/virtio.c
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,6 @@ static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
dev->id.device, dev->id.vendor);
}

static void add_status(struct virtio_device *dev, unsigned status)
{
dev->config->set_status(dev, dev->config->get_status(dev) | status);
}

void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
unsigned int fbit)
{
Expand Down Expand Up @@ -145,14 +140,15 @@ void virtio_config_changed(struct virtio_device *dev)
}
EXPORT_SYMBOL_GPL(virtio_config_changed);

static void virtio_config_disable(struct virtio_device *dev)
void virtio_config_disable(struct virtio_device *dev)
{
spin_lock_irq(&dev->config_lock);
dev->config_enabled = false;
spin_unlock_irq(&dev->config_lock);
}
EXPORT_SYMBOL_GPL(virtio_config_disable);

static void virtio_config_enable(struct virtio_device *dev)
void virtio_config_enable(struct virtio_device *dev)
{
spin_lock_irq(&dev->config_lock);
dev->config_enabled = true;
Expand All @@ -161,8 +157,15 @@ static void virtio_config_enable(struct virtio_device *dev)
dev->config_change_pending = false;
spin_unlock_irq(&dev->config_lock);
}
EXPORT_SYMBOL_GPL(virtio_config_enable);

void virtio_add_status(struct virtio_device *dev, unsigned int status)
{
dev->config->set_status(dev, dev->config->get_status(dev) | status);
}
EXPORT_SYMBOL_GPL(virtio_add_status);

static int virtio_finalize_features(struct virtio_device *dev)
int virtio_finalize_features(struct virtio_device *dev)
{
int ret = dev->config->finalize_features(dev);
unsigned status;
Expand All @@ -173,7 +176,7 @@ static int virtio_finalize_features(struct virtio_device *dev)
if (!virtio_has_feature(dev, VIRTIO_F_VERSION_1))
return 0;

add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
virtio_add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
status = dev->config->get_status(dev);
if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) {
dev_err(&dev->dev, "virtio: device refuses features: %x\n",
Expand All @@ -182,6 +185,7 @@ static int virtio_finalize_features(struct virtio_device *dev)
}
return 0;
}
EXPORT_SYMBOL_GPL(virtio_finalize_features);

static int virtio_dev_probe(struct device *_d)
{
Expand All @@ -193,7 +197,7 @@ static int virtio_dev_probe(struct device *_d)
u64 driver_features_legacy;

/* We have a driver! */
add_status(dev, VIRTIO_CONFIG_S_DRIVER);
virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER);

/* Figure out what features the device supports. */
device_features = dev->config->get_features(dev);
Expand Down Expand Up @@ -247,7 +251,7 @@ static int virtio_dev_probe(struct device *_d)

return 0;
err:
add_status(dev, VIRTIO_CONFIG_S_FAILED);
virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
return err;

}
Expand All @@ -265,7 +269,7 @@ static int virtio_dev_remove(struct device *_d)
WARN_ON_ONCE(dev->config->get_status(dev));

/* Acknowledge the device's existence again. */
add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
return 0;
}

Expand Down Expand Up @@ -316,7 +320,7 @@ int register_virtio_device(struct virtio_device *dev)
dev->config->reset(dev);

/* Acknowledge that we've seen the device. */
add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);

INIT_LIST_HEAD(&dev->vqs);

Expand All @@ -325,7 +329,7 @@ int register_virtio_device(struct virtio_device *dev)
err = device_register(&dev->dev);
out:
if (err)
add_status(dev, VIRTIO_CONFIG_S_FAILED);
virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
return err;
}
EXPORT_SYMBOL_GPL(register_virtio_device);
Expand Down Expand Up @@ -365,18 +369,18 @@ int virtio_device_restore(struct virtio_device *dev)
dev->config->reset(dev);

/* Acknowledge that we've seen the device. */
add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
virtio_add_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);

/* Maybe driver failed before freeze.
* Restore the failed status, for debugging. */
if (dev->failed)
add_status(dev, VIRTIO_CONFIG_S_FAILED);
virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);

if (!drv)
return 0;

/* We have a driver! */
add_status(dev, VIRTIO_CONFIG_S_DRIVER);
virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER);

ret = virtio_finalize_features(dev);
if (ret)
Expand All @@ -389,14 +393,14 @@ int virtio_device_restore(struct virtio_device *dev)
}

/* Finally, tell the device we're all set */
add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
virtio_add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);

virtio_config_enable(dev);

return 0;

err:
add_status(dev, VIRTIO_CONFIG_S_FAILED);
virtio_add_status(dev, VIRTIO_CONFIG_S_FAILED);
return ret;
}
EXPORT_SYMBOL_GPL(virtio_device_restore);
Expand Down
4 changes: 4 additions & 0 deletions include/linux/virtio.h
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,16 @@ static inline struct virtio_device *dev_to_virtio(struct device *_dev)
return container_of(_dev, struct virtio_device, dev);
}

void virtio_add_status(struct virtio_device *dev, unsigned int status);
int register_virtio_device(struct virtio_device *dev);
void unregister_virtio_device(struct virtio_device *dev);

void virtio_break_device(struct virtio_device *dev);

void virtio_config_changed(struct virtio_device *dev);
void virtio_config_disable(struct virtio_device *dev);
void virtio_config_enable(struct virtio_device *dev);
int virtio_finalize_features(struct virtio_device *dev);
#ifdef CONFIG_PM_SLEEP
int virtio_device_freeze(struct virtio_device *dev);
int virtio_device_restore(struct virtio_device *dev);
Expand Down

0 comments on commit 9fe7bfc

Please sign in to comment.