mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-08 06:03:24 +00:00
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. Thanks, Rusty. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJUQFBQAAoJENkgDmzRrbjxJRIP/1yCQRElQewxURSmJelyqCdU 0mHYB0R9Mf3tfre1xnofqs2lWeSMc/4ptKHsVR6pupoztSwnz7HsLHfEFvFJh4mj KsaqYElxkNxTcfyHwLjyJS0/J6tG1tYypXGiimTBS0bvFHL3XZdimVgJ6WvX+gO7 YSaDEX8/EqCERafslS5+gKJlz3drDOnCZCe9y4BDSmsvl2k7bkpSxIn8vsR6jIC0 c5JpUy6QVF+3XA/J932M7yRs+xpqxNoUWiyY3ar9o3CtQAaQB0ZAetSxY6hTfvVc GlNFzCifdsaQwsl2SVsE2h6tWaRhtMtcGWQuhHThIPyIf8XxhYyBRY2FLo70LMz1 eqtwy6F/Bg/nzUsdee4PZBMeoKHlAEL12RpsEKgfUoLzj16Aqa8ll+Agbglbkw8G f3d2FwzKAlpY5NwHETC1wYy52PJ3efqksRWuhokmYpxNSbHJS/lsiJOE7272/4Qr MtXuvRmo22tf34XFd5y7zqWjgZ58eeFOqQWi/K+6ZgpqVOvikjrXXKEuiVdjO0ZD kTVR/sQKiR+79rzENk80XBhWaMveECNXF1TiZ/3MmURkmEOBRQMxRQ20BX3exvna AJ/WVA5DcfXZc1yyqknE1NLGrvSBMJENH13x2QPwrqNWAryOOKuF1VKKIwWlDw5j vtx5nXiJa8YYdxI2TJCN =JK6x -----END PGP SIGNATURE----- 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 ...
This commit is contained in:
commit
0e6e58f941
@ -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;
|
||||
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user