Commit 99262a3d authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'virtio-for-linus' of...

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

Pull virtio updates from Rusty Russell.

* tag 'virtio-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus:
  virtio: fix typo in comment
  virtio-mmio: Devices parameter parsing
  virtio_blk: Drop unused request tracking list
  virtio-blk: Fix hot-unplug race in remove method
  virtio: Use ida to allocate virtio index
  virtio: balloon: separate out common code between remove and freeze functions
  virtio: balloon: drop restore_common()
  9p: disconnect channel when PCI device is removed
  virtio: update documentation to v0.9.5 of spec
parents bf67f3a5 c6190804
...@@ -110,6 +110,7 @@ parameter is applicable: ...@@ -110,6 +110,7 @@ parameter is applicable:
USB USB support is enabled. USB USB support is enabled.
USBHID USB Human Interface Device support is enabled. USBHID USB Human Interface Device support is enabled.
V4L Video For Linux support is enabled. V4L Video For Linux support is enabled.
VMMIO Driver for memory mapped virtio devices is enabled.
VGA The VGA console has been enabled. VGA The VGA console has been enabled.
VT Virtual terminal support is enabled. VT Virtual terminal support is enabled.
WDT Watchdog support is enabled. WDT Watchdog support is enabled.
...@@ -2932,6 +2933,22 @@ bytes respectively. Such letter suffixes can also be entirely omitted. ...@@ -2932,6 +2933,22 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
video= [FB] Frame buffer configuration video= [FB] Frame buffer configuration
See Documentation/fb/modedb.txt. See Documentation/fb/modedb.txt.
virtio_mmio.device=
[VMMIO] Memory mapped virtio (platform) device.
<size>@<baseaddr>:<irq>[:<id>]
where:
<size> := size (can use standard suffixes
like K, M and G)
<baseaddr> := physical base address
<irq> := interrupt number (as passed to
request_irq())
<id> := (optional) platform device id
example:
virtio_mmio.device=1K@0x100b0000:48:7
Can be used multiple times for multiple devices.
vga= [BOOT,X86-32] Select a particular video mode vga= [BOOT,X86-32] Select a particular video mode
See Documentation/x86/boot.txt and See Documentation/x86/boot.txt and
Documentation/svga.txt. Documentation/svga.txt.
......
This diff is collapsed.
...@@ -29,9 +29,6 @@ struct virtio_blk ...@@ -29,9 +29,6 @@ struct virtio_blk
/* The disk structure for the kernel. */ /* The disk structure for the kernel. */
struct gendisk *disk; struct gendisk *disk;
/* Request tracking. */
struct list_head reqs;
mempool_t *pool; mempool_t *pool;
/* Process context for config space updates */ /* Process context for config space updates */
...@@ -55,7 +52,6 @@ struct virtio_blk ...@@ -55,7 +52,6 @@ struct virtio_blk
struct virtblk_req struct virtblk_req
{ {
struct list_head list;
struct request *req; struct request *req;
struct virtio_blk_outhdr out_hdr; struct virtio_blk_outhdr out_hdr;
struct virtio_scsi_inhdr in_hdr; struct virtio_scsi_inhdr in_hdr;
...@@ -99,7 +95,6 @@ static void blk_done(struct virtqueue *vq) ...@@ -99,7 +95,6 @@ static void blk_done(struct virtqueue *vq)
} }
__blk_end_request_all(vbr->req, error); __blk_end_request_all(vbr->req, error);
list_del(&vbr->list);
mempool_free(vbr, vblk->pool); mempool_free(vbr, vblk->pool);
} }
/* In case queue is stopped waiting for more buffers. */ /* In case queue is stopped waiting for more buffers. */
...@@ -184,7 +179,6 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk, ...@@ -184,7 +179,6 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
return false; return false;
} }
list_add_tail(&vbr->list, &vblk->reqs);
return true; return true;
} }
...@@ -437,7 +431,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) ...@@ -437,7 +431,6 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
goto out_free_index; goto out_free_index;
} }
INIT_LIST_HEAD(&vblk->reqs);
spin_lock_init(&vblk->lock); spin_lock_init(&vblk->lock);
vblk->vdev = vdev; vblk->vdev = vdev;
vblk->sg_elems = sg_elems; vblk->sg_elems = sg_elems;
...@@ -583,21 +576,29 @@ static void __devexit virtblk_remove(struct virtio_device *vdev) ...@@ -583,21 +576,29 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
{ {
struct virtio_blk *vblk = vdev->priv; struct virtio_blk *vblk = vdev->priv;
int index = vblk->index; int index = vblk->index;
struct virtblk_req *vbr;
unsigned long flags;
/* Prevent config work handler from accessing the device. */ /* Prevent config work handler from accessing the device. */
mutex_lock(&vblk->config_lock); mutex_lock(&vblk->config_lock);
vblk->config_enable = false; vblk->config_enable = false;
mutex_unlock(&vblk->config_lock); mutex_unlock(&vblk->config_lock);
/* Nothing should be pending. */
BUG_ON(!list_empty(&vblk->reqs));
/* Stop all the virtqueues. */ /* Stop all the virtqueues. */
vdev->config->reset(vdev); vdev->config->reset(vdev);
flush_work(&vblk->config_work); flush_work(&vblk->config_work);
del_gendisk(vblk->disk); del_gendisk(vblk->disk);
/* Abort requests dispatched to driver. */
spin_lock_irqsave(&vblk->lock, flags);
while ((vbr = virtqueue_detach_unused_buf(vblk->vq))) {
__blk_end_request_all(vbr->req, -EIO);
mempool_free(vbr, vblk->pool);
}
spin_unlock_irqrestore(&vblk->lock, flags);
blk_cleanup_queue(vblk->disk->queue); blk_cleanup_queue(vblk->disk->queue);
put_disk(vblk->disk); put_disk(vblk->disk);
mempool_destroy(vblk->pool); mempool_destroy(vblk->pool);
......
...@@ -46,4 +46,15 @@ config VIRTIO_BALLOON ...@@ -46,4 +46,15 @@ config VIRTIO_BALLOON
If unsure, say N. If unsure, say N.
config VIRTIO_MMIO_CMDLINE_DEVICES
bool "Memory mapped virtio devices parameter parsing"
depends on VIRTIO_MMIO
---help---
Allow virtio-mmio devices instantiation via the kernel command line
or module parameters. Be aware that using incorrect parameters (base
address in particular) can crash your system - you have been warned.
See Documentation/kernel-parameters.txt for details.
If unsure, say 'N'.
endmenu endmenu
...@@ -2,9 +2,10 @@ ...@@ -2,9 +2,10 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/idr.h>
/* Unique numbering for virtio devices. */ /* Unique numbering for virtio devices. */
static unsigned int dev_index; static DEFINE_IDA(virtio_index_ida);
static ssize_t device_show(struct device *_d, static ssize_t device_show(struct device *_d,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
...@@ -193,7 +194,11 @@ int register_virtio_device(struct virtio_device *dev) ...@@ -193,7 +194,11 @@ int register_virtio_device(struct virtio_device *dev)
dev->dev.bus = &virtio_bus; dev->dev.bus = &virtio_bus;
/* Assign a unique device index and hence name. */ /* Assign a unique device index and hence name. */
dev->index = dev_index++; err = ida_simple_get(&virtio_index_ida, 0, 0, GFP_KERNEL);
if (err < 0)
goto out;
dev->index = err;
dev_set_name(&dev->dev, "virtio%u", dev->index); dev_set_name(&dev->dev, "virtio%u", dev->index);
/* We always start by resetting the device, in case a previous /* We always start by resetting the device, in case a previous
...@@ -208,6 +213,7 @@ int register_virtio_device(struct virtio_device *dev) ...@@ -208,6 +213,7 @@ int register_virtio_device(struct virtio_device *dev)
/* device_register() causes the bus infrastructure to look for a /* device_register() causes the bus infrastructure to look for a
* matching driver. */ * matching driver. */
err = device_register(&dev->dev); err = device_register(&dev->dev);
out:
if (err) if (err)
add_status(dev, VIRTIO_CONFIG_S_FAILED); add_status(dev, VIRTIO_CONFIG_S_FAILED);
return err; return err;
...@@ -217,6 +223,7 @@ EXPORT_SYMBOL_GPL(register_virtio_device); ...@@ -217,6 +223,7 @@ EXPORT_SYMBOL_GPL(register_virtio_device);
void unregister_virtio_device(struct virtio_device *dev) void unregister_virtio_device(struct virtio_device *dev)
{ {
device_unregister(&dev->dev); device_unregister(&dev->dev);
ida_simple_remove(&virtio_index_ida, dev->index);
} }
EXPORT_SYMBOL_GPL(unregister_virtio_device); EXPORT_SYMBOL_GPL(unregister_virtio_device);
......
...@@ -381,21 +381,25 @@ static int virtballoon_probe(struct virtio_device *vdev) ...@@ -381,21 +381,25 @@ static int virtballoon_probe(struct virtio_device *vdev)
return err; return err;
} }
static void __devexit virtballoon_remove(struct virtio_device *vdev) static void remove_common(struct virtio_balloon *vb)
{ {
struct virtio_balloon *vb = vdev->priv;
kthread_stop(vb->thread);
/* There might be pages left in the balloon: free them. */ /* There might be pages left in the balloon: free them. */
while (vb->num_pages) while (vb->num_pages)
leak_balloon(vb, vb->num_pages); leak_balloon(vb, vb->num_pages);
update_balloon_size(vb); update_balloon_size(vb);
/* Now we reset the device so we can clean up the queues. */ /* Now we reset the device so we can clean up the queues. */
vdev->config->reset(vdev); vb->vdev->config->reset(vb->vdev);
vdev->config->del_vqs(vdev); vb->vdev->config->del_vqs(vb->vdev);
}
static void __devexit virtballoon_remove(struct virtio_device *vdev)
{
struct virtio_balloon *vb = vdev->priv;
kthread_stop(vb->thread);
remove_common(vb);
kfree(vb); kfree(vb);
} }
...@@ -409,17 +413,11 @@ static int virtballoon_freeze(struct virtio_device *vdev) ...@@ -409,17 +413,11 @@ static int virtballoon_freeze(struct virtio_device *vdev)
* function is called. * function is called.
*/ */
while (vb->num_pages) remove_common(vb);
leak_balloon(vb, vb->num_pages);
update_balloon_size(vb);
/* Ensure we don't get any more requests from the host */
vdev->config->reset(vdev);
vdev->config->del_vqs(vdev);
return 0; return 0;
} }
static int restore_common(struct virtio_device *vdev) static int virtballoon_restore(struct virtio_device *vdev)
{ {
struct virtio_balloon *vb = vdev->priv; struct virtio_balloon *vb = vdev->priv;
int ret; int ret;
...@@ -432,11 +430,6 @@ static int restore_common(struct virtio_device *vdev) ...@@ -432,11 +430,6 @@ static int restore_common(struct virtio_device *vdev)
update_balloon_size(vb); update_balloon_size(vb);
return 0; return 0;
} }
static int virtballoon_restore(struct virtio_device *vdev)
{
return restore_common(vdev);
}
#endif #endif
static unsigned int features[] = { static unsigned int features[] = {
......
...@@ -6,6 +6,50 @@ ...@@ -6,6 +6,50 @@
* This module allows virtio devices to be used over a virtual, memory mapped * This module allows virtio devices to be used over a virtual, memory mapped
* platform device. * platform device.
* *
* The guest device(s) may be instantiated in one of three equivalent ways:
*
* 1. Static platform device in board's code, eg.:
*
* static struct platform_device v2m_virtio_device = {
* .name = "virtio-mmio",
* .id = -1,
* .num_resources = 2,
* .resource = (struct resource []) {
* {
* .start = 0x1001e000,
* .end = 0x1001e0ff,
* .flags = IORESOURCE_MEM,
* }, {
* .start = 42 + 32,
* .end = 42 + 32,
* .flags = IORESOURCE_IRQ,
* },
* }
* };
*
* 2. Device Tree node, eg.:
*
* virtio_block@1e000 {
* compatible = "virtio,mmio";
* reg = <0x1e000 0x100>;
* interrupts = <42>;
* }
*
* 3. Kernel module (or command line) parameter. Can be used more than once -
* one device will be created for each one. Syntax:
*
* [virtio_mmio.]device=<size>@<baseaddr>:<irq>[:<id>]
* where:
* <size> := size (can use standard suffixes like K, M or G)
* <baseaddr> := physical base address
* <irq> := interrupt number (as passed to request_irq())
* <id> := (optional) platform device id
* eg.:
* virtio_mmio.device=0x100@0x100b0000:48 \
* virtio_mmio.device=1K@0x1001e000:74
*
*
*
* Registers layout (all 32-bit wide): * Registers layout (all 32-bit wide):
* *
* offset d. name description * offset d. name description
...@@ -42,6 +86,8 @@ ...@@ -42,6 +86,8 @@
* See the COPYING file in the top-level directory. * See the COPYING file in the top-level directory.
*/ */
#define pr_fmt(fmt) "virtio-mmio: " fmt
#include <linux/highmem.h> #include <linux/highmem.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
...@@ -449,6 +495,122 @@ static int __devexit virtio_mmio_remove(struct platform_device *pdev) ...@@ -449,6 +495,122 @@ static int __devexit virtio_mmio_remove(struct platform_device *pdev)
/* Devices list parameter */
#if defined(CONFIG_VIRTIO_MMIO_CMDLINE_DEVICES)
static struct device vm_cmdline_parent = {
.init_name = "virtio-mmio-cmdline",
};
static int vm_cmdline_parent_registered;
static int vm_cmdline_id;
static int vm_cmdline_set(const char *device,
const struct kernel_param *kp)
{
int err;
struct resource resources[2] = {};
char *str;
long long int base;
int processed, consumed = 0;
struct platform_device *pdev;
resources[0].flags = IORESOURCE_MEM;
resources[1].flags = IORESOURCE_IRQ;
resources[0].end = memparse(device, &str) - 1;
processed = sscanf(str, "@%lli:%u%n:%d%n",
&base, &resources[1].start, &consumed,
&vm_cmdline_id, &consumed);
if (processed < 2 || processed > 3 || str[consumed])
return -EINVAL;
resources[0].start = base;
resources[0].end += base;
resources[1].end = resources[1].start;
if (!vm_cmdline_parent_registered) {
err = device_register(&vm_cmdline_parent);
if (err) {
pr_err("Failed to register parent device!\n");
return err;
}
vm_cmdline_parent_registered = 1;
}
pr_info("Registering device virtio-mmio.%d at 0x%llx-0x%llx, IRQ %d.\n",
vm_cmdline_id,
(unsigned long long)resources[0].start,
(unsigned long long)resources[0].end,
(int)resources[1].start);
pdev = platform_device_register_resndata(&vm_cmdline_parent,
"virtio-mmio", vm_cmdline_id++,
resources, ARRAY_SIZE(resources), NULL, 0);
if (IS_ERR(pdev))
return PTR_ERR(pdev);
return 0;
}
static int vm_cmdline_get_device(struct device *dev, void *data)
{
char *buffer = data;
unsigned int len = strlen(buffer);
struct platform_device *pdev = to_platform_device(dev);
snprintf(buffer + len, PAGE_SIZE - len, "0x%llx@0x%llx:%llu:%d\n",
pdev->resource[0].end - pdev->resource[0].start + 1ULL,
(unsigned long long)pdev->resource[0].start,
(unsigned long long)pdev->resource[1].start,
pdev->id);
return 0;
}
static int vm_cmdline_get(char *buffer, const struct kernel_param *kp)
{
buffer[0] = '\0';
device_for_each_child(&vm_cmdline_parent, buffer,
vm_cmdline_get_device);
return strlen(buffer) + 1;
}
static struct kernel_param_ops vm_cmdline_param_ops = {
.set = vm_cmdline_set,
.get = vm_cmdline_get,
};
device_param_cb(device, &vm_cmdline_param_ops, NULL, S_IRUSR);
static int vm_unregister_cmdline_device(struct device *dev,
void *data)
{
platform_device_unregister(to_platform_device(dev));
return 0;
}
static void vm_unregister_cmdline_devices(void)
{
if (vm_cmdline_parent_registered) {
device_for_each_child(&vm_cmdline_parent, NULL,
vm_unregister_cmdline_device);
device_unregister(&vm_cmdline_parent);
vm_cmdline_parent_registered = 0;
}
}
#else
static void vm_unregister_cmdline_devices(void)
{
}
#endif
/* Platform driver */ /* Platform driver */
static struct of_device_id virtio_mmio_match[] = { static struct of_device_id virtio_mmio_match[] = {
...@@ -475,6 +637,7 @@ static int __init virtio_mmio_init(void) ...@@ -475,6 +637,7 @@ static int __init virtio_mmio_init(void)
static void __exit virtio_mmio_exit(void) static void __exit virtio_mmio_exit(void)
{ {
platform_driver_unregister(&virtio_mmio_driver); platform_driver_unregister(&virtio_mmio_driver);
vm_unregister_cmdline_devices();
} }
module_init(virtio_mmio_init); module_init(virtio_mmio_init);
......
...@@ -74,15 +74,6 @@ ...@@ -74,15 +74,6 @@
* @set_status: write the status byte * @set_status: write the status byte
* vdev: the virtio_device * vdev: the virtio_device
* status: the new status byte * status: the new status byte
* @request_vqs: request the specified number of virtqueues
* vdev: the virtio_device
* max_vqs: the max number of virtqueues we want
* If supplied, must call before any virtqueues are instantiated.
* To modify the max number of virtqueues after request_vqs has been
* called, call free_vqs and then request_vqs with a new value.
* @free_vqs: cleanup resources allocated by request_vqs
* vdev: the virtio_device
* If supplied, must call after all virtqueues have been deleted.
* @reset: reset the device * @reset: reset the device
* vdev: the virtio device * vdev: the virtio device
* After this, status and feature negotiation must be done again * After this, status and feature negotiation must be done again
...@@ -156,7 +147,7 @@ static inline bool virtio_has_feature(const struct virtio_device *vdev, ...@@ -156,7 +147,7 @@ static inline bool virtio_has_feature(const struct virtio_device *vdev,
* @vdev: the virtio device * @vdev: the virtio device
* @fbit: the feature bit * @fbit: the feature bit
* @offset: the type to search for. * @offset: the type to search for.
* @val: a pointer to the value to fill in. * @v: a pointer to the value to fill in.
* *
* The return value is -ENOENT if the feature doesn't exist. Otherwise * The return value is -ENOENT if the feature doesn't exist. Otherwise
* the config value is copied into whatever is pointed to by v. */ * the config value is copied into whatever is pointed to by v. */
......
...@@ -615,7 +615,8 @@ static void p9_virtio_remove(struct virtio_device *vdev) ...@@ -615,7 +615,8 @@ static void p9_virtio_remove(struct virtio_device *vdev)
{ {
struct virtio_chan *chan = vdev->priv; struct virtio_chan *chan = vdev->priv;
BUG_ON(chan->inuse); if (chan->inuse)
p9_virtio_close(chan->client);
vdev->config->del_vqs(vdev); vdev->config->del_vqs(vdev);
mutex_lock(&virtio_9p_lock); mutex_lock(&virtio_9p_lock);
......
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