提交 0e6e58f9 编写于 作者: L Linus Torvalds

Merge tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux

Pull virtio updates from Rusty Russell:
 "One cc: stable commit, the rest are a series of minor cleanups which
  have been sitting in MST's tree during my vacation.  I changed a
  function name and made one trivial change, then they spent two days in
  linux-next"

* tag 'virtio-next-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux: (25 commits)
  virtio-rng: refactor probe error handling
  virtio_scsi: drop scan callback
  virtio_balloon: enable VQs early on restore
  virtio_scsi: fix race on device removal
  virito_scsi: use freezable WQ for events
  virtio_net: enable VQs early on restore
  virtio_console: enable VQs early on restore
  virtio_scsi: enable VQs early on restore
  virtio_blk: enable VQs early on restore
  virtio_scsi: move kick event out from virtscsi_init
  virtio_net: fix use after free on allocation failure
  9p/trans_virtio: enable VQs early
  virtio_console: enable VQs early
  virtio_blk: enable VQs early
  virtio_net: enable VQs early
  virtio: add API to enable VQs early
  virtio_net: minor cleanup
  virtio-net: drop config_mutex
  virtio_net: drop config_enable
  virtio-blk: drop config_mutex
  ...
......@@ -41,12 +41,6 @@ struct virtio_blk
/* Process context for config space updates */
struct work_struct config_work;
/* Lock for config space updates */
struct mutex config_lock;
/* enable config space updates */
bool config_enable;
/* What host tells us, plus 2 for header & tailer. */
unsigned int sg_elems;
......@@ -347,10 +341,6 @@ static void virtblk_config_changed_work(struct work_struct *work)
char *envp[] = { "RESIZE=1", NULL };
u64 capacity, size;
mutex_lock(&vblk->config_lock);
if (!vblk->config_enable)
goto done;
/* Host must always specify the capacity. */
virtio_cread(vdev, struct virtio_blk_config, capacity, &capacity);
......@@ -374,8 +364,6 @@ static void virtblk_config_changed_work(struct work_struct *work)
set_capacity(vblk->disk, capacity);
revalidate_disk(vblk->disk);
kobject_uevent_env(&disk_to_dev(vblk->disk)->kobj, KOBJ_CHANGE, envp);
done:
mutex_unlock(&vblk->config_lock);
}
static void virtblk_config_changed(struct virtio_device *vdev)
......@@ -606,10 +594,8 @@ static int virtblk_probe(struct virtio_device *vdev)
vblk->vdev = vdev;
vblk->sg_elems = sg_elems;
mutex_init(&vblk->config_lock);
INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
vblk->config_enable = true;
err = init_vq(vblk);
if (err)
......@@ -733,6 +719,8 @@ static int virtblk_probe(struct virtio_device *vdev)
if (!err && opt_io_size)
blk_queue_io_opt(q, blk_size * opt_io_size);
virtio_device_ready(vdev);
add_disk(vblk->disk);
err = device_create_file(disk_to_dev(vblk->disk), &dev_attr_serial);
if (err)
......@@ -771,10 +759,8 @@ static void virtblk_remove(struct virtio_device *vdev)
int index = vblk->index;
int refc;
/* Prevent config work handler from accessing the device. */
mutex_lock(&vblk->config_lock);
vblk->config_enable = false;
mutex_unlock(&vblk->config_lock);
/* Make sure no work handler is accessing the device. */
flush_work(&vblk->config_work);
del_gendisk(vblk->disk);
blk_cleanup_queue(vblk->disk->queue);
......@@ -784,8 +770,6 @@ static void virtblk_remove(struct virtio_device *vdev)
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
flush_work(&vblk->config_work);
refc = atomic_read(&disk_to_dev(vblk->disk)->kobj.kref.refcount);
put_disk(vblk->disk);
vdev->config->del_vqs(vdev);
......@@ -805,11 +789,7 @@ static int virtblk_freeze(struct virtio_device *vdev)
/* Ensure we don't receive any more interrupts */
vdev->config->reset(vdev);
/* Prevent config work handler from accessing the device. */
mutex_lock(&vblk->config_lock);
vblk->config_enable = false;
mutex_unlock(&vblk->config_lock);
/* Make sure no work handler is accessing the device. */
flush_work(&vblk->config_work);
blk_mq_stop_hw_queues(vblk->disk->queue);
......@@ -823,12 +803,14 @@ static int virtblk_restore(struct virtio_device *vdev)
struct virtio_blk *vblk = vdev->priv;
int ret;
vblk->config_enable = true;
ret = init_vq(vdev->priv);
if (!ret)
blk_mq_start_stopped_hw_queues(vblk->disk->queue, true);
if (ret)
return ret;
virtio_device_ready(vdev);
blk_mq_start_stopped_hw_queues(vblk->disk->queue, true);
return 0;
}
#endif
......
......@@ -109,8 +109,8 @@ static int probe_common(struct virtio_device *vdev)
vi->index = index = ida_simple_get(&rng_index_ida, 0, 0, GFP_KERNEL);
if (index < 0) {
kfree(vi);
return index;
err = index;
goto err_ida;
}
sprintf(vi->name, "virtio_rng.%d", index);
init_completion(&vi->have_data);
......@@ -128,13 +128,16 @@ static int probe_common(struct virtio_device *vdev)
vi->vq = virtio_find_single_vq(vdev, random_recv_done, "input");
if (IS_ERR(vi->vq)) {
err = PTR_ERR(vi->vq);
vi->vq = NULL;
kfree(vi);
ida_simple_remove(&rng_index_ida, index);
return err;
goto err_find;
}
return 0;
err_find:
ida_simple_remove(&rng_index_ida, index);
err_ida:
kfree(vi);
return err;
}
static void remove_common(struct virtio_device *vdev)
......
......@@ -1449,6 +1449,8 @@ static int add_port(struct ports_device *portdev, u32 id)
spin_lock_init(&port->outvq_lock);
init_waitqueue_head(&port->waitqueue);
virtio_device_ready(portdev->vdev);
/* Fill the in_vq with buffers so the host can send us data. */
nr_added_bufs = fill_queue(port->in_vq, &port->inbuf_lock);
if (!nr_added_bufs) {
......@@ -2182,6 +2184,8 @@ static int virtcons_restore(struct virtio_device *vdev)
if (ret)
return ret;
virtio_device_ready(portdev->vdev);
if (use_multiport(portdev))
fill_queue(portdev->c_ivq, &portdev->c_ivq_lock);
......
......@@ -462,16 +462,12 @@ static void mic_handle_config_change(struct mic_device_desc __iomem *d,
struct mic_device_ctrl __iomem *dc
= (void __iomem *)d + mic_aligned_desc_size(d);
struct mic_vdev *mvdev = (struct mic_vdev *)ioread64(&dc->vdev);
struct virtio_driver *drv;
if (ioread8(&dc->config_change) != MIC_VIRTIO_PARAM_CONFIG_CHANGED)
return;
dev_dbg(mdrv->dev, "%s %d\n", __func__, __LINE__);
drv = container_of(mvdev->vdev.dev.driver,
struct virtio_driver, driver);
if (drv->config_changed)
drv->config_changed(&mvdev->vdev);
virtio_config_changed(&mvdev->vdev);
iowrite8(1, &dc->guest_ack);
}
......
......@@ -123,9 +123,6 @@ struct virtnet_info {
/* Host can handle any s/g split between our header and packet data */
bool any_header_sg;
/* enable config space updates */
bool config_enable;
/* Active statistics */
struct virtnet_stats __percpu *stats;
......@@ -135,9 +132,6 @@ struct virtnet_info {
/* Work struct for config space updates */
struct work_struct config_work;
/* Lock for config space updates */
struct mutex config_lock;
/* Does the affinity hint is set for virtqueues? */
bool affinity_hint_set;
......@@ -1414,13 +1408,9 @@ static void virtnet_config_changed_work(struct work_struct *work)
container_of(work, struct virtnet_info, config_work);
u16 v;
mutex_lock(&vi->config_lock);
if (!vi->config_enable)
goto done;
if (virtio_cread_feature(vi->vdev, VIRTIO_NET_F_STATUS,
struct virtio_net_config, status, &v) < 0)
goto done;
return;
if (v & VIRTIO_NET_S_ANNOUNCE) {
netdev_notify_peers(vi->dev);
......@@ -1431,7 +1421,7 @@ static void virtnet_config_changed_work(struct work_struct *work)
v &= VIRTIO_NET_S_LINK_UP;
if (vi->status == v)
goto done;
return;
vi->status = v;
......@@ -1442,8 +1432,6 @@ static void virtnet_config_changed_work(struct work_struct *work)
netif_carrier_off(vi->dev);
netif_tx_stop_all_queues(vi->dev);
}
done:
mutex_unlock(&vi->config_lock);
}
static void virtnet_config_changed(struct virtio_device *vdev)
......@@ -1764,8 +1752,6 @@ static int virtnet_probe(struct virtio_device *vdev)
u64_stats_init(&virtnet_stats->rx_syncp);
}
mutex_init(&vi->config_lock);
vi->config_enable = true;
INIT_WORK(&vi->config_work, virtnet_config_changed_work);
/* If we can receive ANY GSO packets, we must allocate large ones. */
......@@ -1813,6 +1799,8 @@ static int virtnet_probe(struct virtio_device *vdev)
goto free_vqs;
}
virtio_device_ready(vdev);
/* Last of all, set up some receive buffers. */
for (i = 0; i < vi->curr_queue_pairs; i++) {
try_fill_recv(&vi->rq[i], GFP_KERNEL);
......@@ -1849,6 +1837,8 @@ static int virtnet_probe(struct virtio_device *vdev)
return 0;
free_recv_bufs:
vi->vdev->config->reset(vdev);
free_receive_bufs(vi);
unregister_netdev(dev);
free_vqs:
......@@ -1882,17 +1872,13 @@ static void virtnet_remove(struct virtio_device *vdev)
unregister_hotcpu_notifier(&vi->nb);
/* Prevent config work handler from accessing the device. */
mutex_lock(&vi->config_lock);
vi->config_enable = false;
mutex_unlock(&vi->config_lock);
/* Make sure no work handler is accessing the device. */
flush_work(&vi->config_work);
unregister_netdev(vi->dev);
remove_vq_common(vi);
flush_work(&vi->config_work);
free_percpu(vi->stats);
free_netdev(vi->dev);
}
......@@ -1905,10 +1891,8 @@ static int virtnet_freeze(struct virtio_device *vdev)
unregister_hotcpu_notifier(&vi->nb);
/* Prevent config work handler from accessing the device */
mutex_lock(&vi->config_lock);
vi->config_enable = false;
mutex_unlock(&vi->config_lock);
/* 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);
......@@ -1923,8 +1907,6 @@ static int virtnet_freeze(struct virtio_device *vdev)
remove_vq_common(vi);
flush_work(&vi->config_work);
return 0;
}
......@@ -1937,6 +1919,8 @@ static int virtnet_restore(struct virtio_device *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->rq[i], GFP_KERNEL))
......@@ -1948,10 +1932,6 @@ static int virtnet_restore(struct virtio_device *vdev)
netif_device_attach(vi->dev);
mutex_lock(&vi->config_lock);
vi->config_enable = true;
mutex_unlock(&vi->config_lock);
rtnl_lock();
virtnet_set_queues(vi, vi->curr_queue_pairs);
rtnl_unlock();
......
......@@ -406,15 +406,8 @@ static void kvm_extint_handler(struct ext_code ext_code,
switch (param) {
case VIRTIO_PARAM_CONFIG_CHANGED:
{
struct virtio_driver *drv;
drv = container_of(vq->vdev->dev.driver,
struct virtio_driver, driver);
if (drv->config_changed)
drv->config_changed(vq->vdev);
virtio_config_changed(vq->vdev);
break;
}
case VIRTIO_PARAM_DEV_ADD:
schedule_work(&hotplug_work);
break;
......
......@@ -940,11 +940,7 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
vring_interrupt(0, vq);
}
if (test_bit(0, &vcdev->indicators2)) {
drv = container_of(vcdev->vdev.dev.driver,
struct virtio_driver, driver);
if (drv && drv->config_changed)
drv->config_changed(&vcdev->vdev);
virtio_config_changed(&vcdev->vdev);
clear_bit(0, &vcdev->indicators2);
}
}
......
......@@ -110,6 +110,9 @@ struct virtio_scsi {
/* CPU hotplug notifier */
struct notifier_block nb;
/* Protected by event_vq lock */
bool stop_events;
struct virtio_scsi_vq ctrl_vq;
struct virtio_scsi_vq event_vq;
struct virtio_scsi_vq req_vqs[];
......@@ -303,6 +306,11 @@ static void virtscsi_cancel_event_work(struct virtio_scsi *vscsi)
{
int i;
/* Stop scheduling work before calling cancel_work_sync. */
spin_lock_irq(&vscsi->event_vq.vq_lock);
vscsi->stop_events = true;
spin_unlock_irq(&vscsi->event_vq.vq_lock);
for (i = 0; i < VIRTIO_SCSI_EVENT_LEN; i++)
cancel_work_sync(&vscsi->event_list[i].work);
}
......@@ -390,7 +398,8 @@ static void virtscsi_complete_event(struct virtio_scsi *vscsi, void *buf)
{
struct virtio_scsi_event_node *event_node = buf;
schedule_work(&event_node->work);
if (!vscsi->stop_events)
queue_work(system_freezable_wq, &event_node->work);
}
static void virtscsi_event_done(struct virtqueue *vq)
......@@ -851,13 +860,6 @@ static void virtscsi_init_vq(struct virtio_scsi_vq *virtscsi_vq,
virtscsi_vq->vq = vq;
}
static void virtscsi_scan(struct virtio_device *vdev)
{
struct Scsi_Host *shost = (struct Scsi_Host *)vdev->priv;
scsi_scan_host(shost);
}
static void virtscsi_remove_vqs(struct virtio_device *vdev)
{
struct Scsi_Host *sh = virtio_scsi_host(vdev);
......@@ -916,9 +918,6 @@ static int virtscsi_init(struct virtio_device *vdev,
virtscsi_config_set(vdev, cdb_size, VIRTIO_SCSI_CDB_SIZE);
virtscsi_config_set(vdev, sense_size, VIRTIO_SCSI_SENSE_SIZE);
if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG))
virtscsi_kick_event_all(vscsi);
err = 0;
out:
......@@ -997,10 +996,13 @@ static int virtscsi_probe(struct virtio_device *vdev)
err = scsi_add_host(shost, &vdev->dev);
if (err)
goto scsi_add_host_failed;
/*
* scsi_scan_host() happens in virtscsi_scan() via virtio_driver->scan()
* after VIRTIO_CONFIG_S_DRIVER_OK has been set..
*/
virtio_device_ready(vdev);
if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG))
virtscsi_kick_event_all(vscsi);
scsi_scan_host(shost);
return 0;
scsi_add_host_failed:
......@@ -1048,8 +1050,15 @@ static int virtscsi_restore(struct virtio_device *vdev)
return err;
err = register_hotcpu_notifier(&vscsi->nb);
if (err)
if (err) {
vdev->config->del_vqs(vdev);
return err;
}
virtio_device_ready(vdev);
if (virtio_has_feature(vdev, VIRTIO_SCSI_F_HOTPLUG))
virtscsi_kick_event_all(vscsi);
return err;
}
......@@ -1073,7 +1082,6 @@ static struct virtio_driver virtio_scsi_driver = {
.driver.owner = THIS_MODULE,
.id_table = id_table,
.probe = virtscsi_probe,
.scan = virtscsi_scan,
#ifdef CONFIG_PM_SLEEP
.freeze = virtscsi_freeze,
.restore = virtscsi_restore,
......
......@@ -117,6 +117,43 @@ void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
}
EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
static void __virtio_config_changed(struct virtio_device *dev)
{
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
if (!dev->config_enabled)
dev->config_change_pending = true;
else if (drv && drv->config_changed)
drv->config_changed(dev);
}
void virtio_config_changed(struct virtio_device *dev)
{
unsigned long flags;
spin_lock_irqsave(&dev->config_lock, flags);
__virtio_config_changed(dev);
spin_unlock_irqrestore(&dev->config_lock, flags);
}
EXPORT_SYMBOL_GPL(virtio_config_changed);
static void virtio_config_disable(struct virtio_device *dev)
{
spin_lock_irq(&dev->config_lock);
dev->config_enabled = false;
spin_unlock_irq(&dev->config_lock);
}
static void virtio_config_enable(struct virtio_device *dev)
{
spin_lock_irq(&dev->config_lock);
dev->config_enabled = true;
if (dev->config_change_pending)
__virtio_config_changed(dev);
dev->config_change_pending = false;
spin_unlock_irq(&dev->config_lock);
}
static int virtio_dev_probe(struct device *_d)
{
int err, i;
......@@ -153,6 +190,8 @@ static int virtio_dev_probe(struct device *_d)
add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
if (drv->scan)
drv->scan(dev);
virtio_config_enable(dev);
}
return err;
......@@ -163,6 +202,8 @@ static int virtio_dev_remove(struct device *_d)
struct virtio_device *dev = dev_to_virtio(_d);
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
virtio_config_disable(dev);
drv->remove(dev);
/* Driver should have reset device. */
......@@ -211,6 +252,10 @@ int register_virtio_device(struct virtio_device *dev)
dev->index = err;
dev_set_name(&dev->dev, "virtio%u", dev->index);
spin_lock_init(&dev->config_lock);
dev->config_enabled = false;
dev->config_change_pending = false;
/* We always start by resetting the device, in case a previous
* driver messed it up. This also tests that code path a little. */
dev->config->reset(dev);
......@@ -239,6 +284,64 @@ void unregister_virtio_device(struct virtio_device *dev)
}
EXPORT_SYMBOL_GPL(unregister_virtio_device);
#ifdef CONFIG_PM_SLEEP
int virtio_device_freeze(struct virtio_device *dev)
{
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
virtio_config_disable(dev);
dev->failed = dev->config->get_status(dev) & VIRTIO_CONFIG_S_FAILED;
if (drv && drv->freeze)
return drv->freeze(dev);
return 0;
}
EXPORT_SYMBOL_GPL(virtio_device_freeze);
int virtio_device_restore(struct virtio_device *dev)
{
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
/* We always start by resetting the device, in case a previous
* driver messed it up. */
dev->config->reset(dev);
/* Acknowledge that we've seen the device. */
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);
if (!drv)
return 0;
/* We have a driver! */
add_status(dev, VIRTIO_CONFIG_S_DRIVER);
dev->config->finalize_features(dev);
if (drv->restore) {
int ret = drv->restore(dev);
if (ret) {
add_status(dev, VIRTIO_CONFIG_S_FAILED);
return ret;
}
}
/* Finally, tell the device we're all set */
add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
virtio_config_enable(dev);
return 0;
}
EXPORT_SYMBOL_GPL(virtio_device_restore);
#endif
static int virtio_init(void)
{
if (bus_register(&virtio_bus) != 0)
......
......@@ -504,6 +504,8 @@ static int virtballoon_restore(struct virtio_device *vdev)
if (ret)
return ret;
virtio_device_ready(vdev);
fill_balloon(vb, towards_target(vb));
update_balloon_size(vb);
return 0;
......
......@@ -234,8 +234,6 @@ static irqreturn_t vm_interrupt(int irq, void *opaque)
{
struct virtio_mmio_device *vm_dev = opaque;
struct virtio_mmio_vq_info *info;
struct virtio_driver *vdrv = container_of(vm_dev->vdev.dev.driver,
struct virtio_driver, driver);
unsigned long status;
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
......@@ -244,9 +242,8 @@ static irqreturn_t vm_interrupt(int irq, void *opaque)
status = readl(vm_dev->base + VIRTIO_MMIO_INTERRUPT_STATUS);
writel(status, vm_dev->base + VIRTIO_MMIO_INTERRUPT_ACK);
if (unlikely(status & VIRTIO_MMIO_INT_CONFIG)
&& vdrv && vdrv->config_changed) {
vdrv->config_changed(&vm_dev->vdev);
if (unlikely(status & VIRTIO_MMIO_INT_CONFIG)) {
virtio_config_changed(&vm_dev->vdev);
ret = IRQ_HANDLED;
}
......
......@@ -57,9 +57,6 @@ struct virtio_pci_device
/* Vectors allocated, excluding per-vq vectors if any */
unsigned msix_used_vectors;
/* Status saved during hibernate/restore */
u8 saved_status;
/* Whether we have vector per vq */
bool per_vq_vectors;
};
......@@ -211,12 +208,8 @@ static bool vp_notify(struct virtqueue *vq)
static irqreturn_t vp_config_changed(int irq, void *opaque)
{
struct virtio_pci_device *vp_dev = opaque;
struct virtio_driver *drv;
drv = container_of(vp_dev->vdev.dev.driver,
struct virtio_driver, driver);
if (drv && drv->config_changed)
drv->config_changed(&vp_dev->vdev);
virtio_config_changed(&vp_dev->vdev);
return IRQ_HANDLED;
}
......@@ -768,16 +761,9 @@ static int virtio_pci_freeze(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
struct virtio_driver *drv;
int ret;
drv = container_of(vp_dev->vdev.dev.driver,
struct virtio_driver, driver);
ret = 0;
vp_dev->saved_status = vp_get_status(&vp_dev->vdev);
if (drv && drv->freeze)
ret = drv->freeze(&vp_dev->vdev);
ret = virtio_device_freeze(&vp_dev->vdev);
if (!ret)
pci_disable_device(pci_dev);
......@@ -788,27 +774,14 @@ static int virtio_pci_restore(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
struct virtio_driver *drv;
int ret;
drv = container_of(vp_dev->vdev.dev.driver,
struct virtio_driver, driver);
ret = pci_enable_device(pci_dev);
if (ret)
return ret;
pci_set_master(pci_dev);
vp_finalize_features(&vp_dev->vdev);
if (drv && drv->restore)
ret = drv->restore(&vp_dev->vdev);
/* Finally, tell the device we're all set */
if (!ret)
vp_set_status(&vp_dev->vdev, vp_dev->saved_status);
return ret;
return virtio_device_restore(&vp_dev->vdev);
}
static const struct dev_pm_ops virtio_pci_pm_ops = {
......
......@@ -78,6 +78,10 @@ bool virtqueue_is_broken(struct virtqueue *vq);
/**
* virtio_device - representation of a device using virtio
* @index: unique position on the virtio bus
* @failed: saved value for CONFIG_S_FAILED bit (for restore)
* @config_enabled: configuration change reporting enabled
* @config_change_pending: configuration change reported while disabled
* @config_lock: protects configuration change reporting
* @dev: underlying device.
* @id: the device type identification (used to match it with a driver).
* @config: the configuration ops for this device.
......@@ -88,6 +92,10 @@ bool virtqueue_is_broken(struct virtqueue *vq);
*/
struct virtio_device {
int index;
bool failed;
bool config_enabled;
bool config_change_pending;
spinlock_t config_lock;
struct device dev;
struct virtio_device_id id;
const struct virtio_config_ops *config;
......@@ -108,6 +116,12 @@ void unregister_virtio_device(struct virtio_device *dev);
void virtio_break_device(struct virtio_device *dev);
void virtio_config_changed(struct virtio_device *dev);
#ifdef CONFIG_PM_SLEEP
int virtio_device_freeze(struct virtio_device *dev);
int virtio_device_restore(struct virtio_device *dev);
#endif
/**
* virtio_driver - operations for a virtio I/O driver
* @driver: underlying device driver (populate name and owner).
......
......@@ -109,6 +109,23 @@ struct virtqueue *virtio_find_single_vq(struct virtio_device *vdev,
return vq;
}
/**
* virtio_device_ready - enable vq use in probe function
* @vdev: the device
*
* Driver must call this to use vqs in the probe function.
*
* Note: vqs are enabled automatically after probe returns.
*/
static inline
void virtio_device_ready(struct virtio_device *dev)
{
unsigned status = dev->config->get_status(dev);
BUG_ON(status & VIRTIO_CONFIG_S_DRIVER_OK);
dev->config->set_status(dev, status | VIRTIO_CONFIG_S_DRIVER_OK);
}
static inline
const char *virtio_bus_name(struct virtio_device *vdev)
{
......
......@@ -575,6 +575,8 @@ static int p9_virtio_probe(struct virtio_device *vdev)
/* Ceiling limit to avoid denial of service attacks */
chan->p9_max_pages = nr_free_buffer_pages()/4;
virtio_device_ready(vdev);
mutex_lock(&virtio_9p_lock);
list_add_tail(&chan->chan_list, &virtio_chan_list);
mutex_unlock(&virtio_9p_lock);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册