Commit 10df38ca authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus

* git://git.kernel.org/pub/scm/linux/kernel/git/rusty/linux-2.6-for-linus: (44 commits)
  Add MAINTAINERS entry for virtio_console
  virtio: console: Fill ports' entire in_vq with buffers
  virtio: console: Error out if we can't allocate buffers for control queue
  virtio: console: Add ability to remove module
  virtio: console: Ensure no memleaks in case of unused buffers
  virtio: console: show error message if hvc_alloc fails for console ports
  virtio: console: Add debugfs files for each port to expose debug info
  virtio: console: Add ability to hot-unplug ports
  virtio: console: Handle port hot-plug
  virtio: console: Remove cached data on port close
  virtio: console: Register with sysfs and create a 'name' attribute for ports
  virtio: console: Ensure only one process can have a port open at a time
  virtio: console: Add file operations to ports for open/read/write/poll
  virtio: console: Associate each port with a char device
  virtio: console: Prepare for writing to userspace buffers
  virtio: console: Add a new MULTIPORT feature, support for generic ports
  virtio: console: Introduce a send_buf function for a common path for sending data to host
  virtio: console: Introduce function to hand off data from host to readers
  virtio: console: Separate out find_vqs operation into a different function
  virtio: console: Separate out console init into a new function
  ...
parents dbd00429 c6100286
...@@ -34,7 +34,6 @@ ...@@ -34,7 +34,6 @@
#include <sys/uio.h> #include <sys/uio.h>
#include <termios.h> #include <termios.h>
#include <getopt.h> #include <getopt.h>
#include <zlib.h>
#include <assert.h> #include <assert.h>
#include <sched.h> #include <sched.h>
#include <limits.h> #include <limits.h>
......
...@@ -2393,6 +2393,12 @@ L: linuxppc-dev@ozlabs.org ...@@ -2393,6 +2393,12 @@ L: linuxppc-dev@ozlabs.org
S: Odd Fixes S: Odd Fixes
F: drivers/char/hvc_* F: drivers/char/hvc_*
VIRTIO CONSOLE DRIVER
M: Amit Shah <amit.shah@redhat.com>
L: virtualization@lists.linux-foundation.org
S: Maintained
F: drivers/char/virtio_console.c
GSPCA FINEPIX SUBDRIVER GSPCA FINEPIX SUBDRIVER
M: Frank Zago <frank@zago.net> M: Frank Zago <frank@zago.net>
L: linux-media@vger.kernel.org L: linux-media@vger.kernel.org
......
...@@ -243,10 +243,12 @@ static int index_to_minor(int index) ...@@ -243,10 +243,12 @@ static int index_to_minor(int index)
static int __devinit virtblk_probe(struct virtio_device *vdev) static int __devinit virtblk_probe(struct virtio_device *vdev)
{ {
struct virtio_blk *vblk; struct virtio_blk *vblk;
struct request_queue *q;
int err; int err;
u64 cap; u64 cap;
u32 v; u32 v, blk_size, sg_elems, opt_io_size;
u32 blk_size, sg_elems; u16 min_io_size;
u8 physical_block_exp, alignment_offset;
if (index_to_minor(index) >= 1 << MINORBITS) if (index_to_minor(index) >= 1 << MINORBITS)
return -ENOSPC; return -ENOSPC;
...@@ -293,13 +295,13 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) ...@@ -293,13 +295,13 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
goto out_mempool; goto out_mempool;
} }
vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock); q = vblk->disk->queue = blk_init_queue(do_virtblk_request, &vblk->lock);
if (!vblk->disk->queue) { if (!q) {
err = -ENOMEM; err = -ENOMEM;
goto out_put_disk; goto out_put_disk;
} }
vblk->disk->queue->queuedata = vblk; q->queuedata = vblk;
if (index < 26) { if (index < 26) {
sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26); sprintf(vblk->disk->disk_name, "vd%c", 'a' + index % 26);
...@@ -323,10 +325,10 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) ...@@ -323,10 +325,10 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
/* If barriers are supported, tell block layer that queue is ordered */ /* If barriers are supported, tell block layer that queue is ordered */
if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH)) if (virtio_has_feature(vdev, VIRTIO_BLK_F_FLUSH))
blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_DRAIN_FLUSH, blk_queue_ordered(q, QUEUE_ORDERED_DRAIN_FLUSH,
virtblk_prepare_flush); virtblk_prepare_flush);
else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER)) else if (virtio_has_feature(vdev, VIRTIO_BLK_F_BARRIER))
blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL); blk_queue_ordered(q, QUEUE_ORDERED_TAG, NULL);
/* If disk is read-only in the host, the guest should obey */ /* If disk is read-only in the host, the guest should obey */
if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
...@@ -345,14 +347,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) ...@@ -345,14 +347,14 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
set_capacity(vblk->disk, cap); set_capacity(vblk->disk, cap);
/* We can handle whatever the host told us to handle. */ /* We can handle whatever the host told us to handle. */
blk_queue_max_phys_segments(vblk->disk->queue, vblk->sg_elems-2); blk_queue_max_phys_segments(q, vblk->sg_elems-2);
blk_queue_max_hw_segments(vblk->disk->queue, vblk->sg_elems-2); blk_queue_max_hw_segments(q, vblk->sg_elems-2);
/* No need to bounce any requests */ /* No need to bounce any requests */
blk_queue_bounce_limit(vblk->disk->queue, BLK_BOUNCE_ANY); blk_queue_bounce_limit(q, BLK_BOUNCE_ANY);
/* No real sector limit. */ /* No real sector limit. */
blk_queue_max_sectors(vblk->disk->queue, -1U); blk_queue_max_sectors(q, -1U);
/* Host can optionally specify maximum segment size and number of /* Host can optionally specify maximum segment size and number of
* segments. */ * segments. */
...@@ -360,16 +362,45 @@ static int __devinit virtblk_probe(struct virtio_device *vdev) ...@@ -360,16 +362,45 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
offsetof(struct virtio_blk_config, size_max), offsetof(struct virtio_blk_config, size_max),
&v); &v);
if (!err) if (!err)
blk_queue_max_segment_size(vblk->disk->queue, v); blk_queue_max_segment_size(q, v);
else else
blk_queue_max_segment_size(vblk->disk->queue, -1U); blk_queue_max_segment_size(q, -1U);
/* Host can optionally specify the block size of the device */ /* Host can optionally specify the block size of the device */
err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE, err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE,
offsetof(struct virtio_blk_config, blk_size), offsetof(struct virtio_blk_config, blk_size),
&blk_size); &blk_size);
if (!err) if (!err)
blk_queue_logical_block_size(vblk->disk->queue, blk_size); blk_queue_logical_block_size(q, blk_size);
else
blk_size = queue_logical_block_size(q);
/* Use topology information if available */
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
offsetof(struct virtio_blk_config, physical_block_exp),
&physical_block_exp);
if (!err && physical_block_exp)
blk_queue_physical_block_size(q,
blk_size * (1 << physical_block_exp));
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
offsetof(struct virtio_blk_config, alignment_offset),
&alignment_offset);
if (!err && alignment_offset)
blk_queue_alignment_offset(q, blk_size * alignment_offset);
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
offsetof(struct virtio_blk_config, min_io_size),
&min_io_size);
if (!err && min_io_size)
blk_queue_io_min(q, blk_size * min_io_size);
err = virtio_config_val(vdev, VIRTIO_BLK_F_TOPOLOGY,
offsetof(struct virtio_blk_config, opt_io_size),
&opt_io_size);
if (!err && opt_io_size)
blk_queue_io_opt(q, blk_size * opt_io_size);
add_disk(vblk->disk); add_disk(vblk->disk);
return 0; return 0;
...@@ -412,7 +443,7 @@ static struct virtio_device_id id_table[] = { ...@@ -412,7 +443,7 @@ static struct virtio_device_id id_table[] = {
static unsigned int features[] = { static unsigned int features[] = {
VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_BARRIER, VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX,
VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH VIRTIO_BLK_F_SCSI, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_TOPOLOGY
}; };
/* /*
......
...@@ -666,6 +666,14 @@ config VIRTIO_CONSOLE ...@@ -666,6 +666,14 @@ config VIRTIO_CONSOLE
help help
Virtio console for use with lguest and other hypervisors. Virtio console for use with lguest and other hypervisors.
Also serves as a general-purpose serial device for data
transfer between the guest and host. Character devices at
/dev/vportNpn will be created when corresponding ports are
found, where N is the device number and n is the port number
within that device. If specified by the host, a sysfs
attribute called 'name' will be populated with a name for
the port which can be used by udev scripts to create a
symlink to the device.
config HVCS config HVCS
tristate "IBM Hypervisor Virtual Console Server support" tristate "IBM Hypervisor Virtual Console Server support"
......
...@@ -84,7 +84,7 @@ static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt) ...@@ -84,7 +84,7 @@ static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt)
return cnt; return cnt;
} }
static struct hv_ops hvc_beat_get_put_ops = { static const struct hv_ops hvc_beat_get_put_ops = {
.get_chars = hvc_beat_get_chars, .get_chars = hvc_beat_get_chars,
.put_chars = hvc_beat_put_chars, .put_chars = hvc_beat_put_chars,
}; };
......
...@@ -125,7 +125,7 @@ static struct hvc_struct *hvc_get_by_index(int index) ...@@ -125,7 +125,7 @@ static struct hvc_struct *hvc_get_by_index(int index)
* console interfaces but can still be used as a tty device. This has to be * console interfaces but can still be used as a tty device. This has to be
* static because kmalloc will not work during early console init. * static because kmalloc will not work during early console init.
*/ */
static struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES];
static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] =
{[0 ... MAX_NR_HVC_CONSOLES - 1] = -1}; {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1};
...@@ -247,7 +247,7 @@ static void destroy_hvc_struct(struct kref *kref) ...@@ -247,7 +247,7 @@ static void destroy_hvc_struct(struct kref *kref)
* vty adapters do NOT get an hvc_instantiate() callback since they * vty adapters do NOT get an hvc_instantiate() callback since they
* appear after early console init. * appear after early console init.
*/ */
int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops)
{ {
struct hvc_struct *hp; struct hvc_struct *hp;
...@@ -749,7 +749,8 @@ static const struct tty_operations hvc_ops = { ...@@ -749,7 +749,8 @@ static const struct tty_operations hvc_ops = {
}; };
struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data, struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
struct hv_ops *ops, int outbuf_size) const struct hv_ops *ops,
int outbuf_size)
{ {
struct hvc_struct *hp; struct hvc_struct *hp;
int i; int i;
......
...@@ -55,7 +55,7 @@ struct hvc_struct { ...@@ -55,7 +55,7 @@ struct hvc_struct {
int outbuf_size; int outbuf_size;
int n_outbuf; int n_outbuf;
uint32_t vtermno; uint32_t vtermno;
struct hv_ops *ops; const struct hv_ops *ops;
int irq_requested; int irq_requested;
int data; int data;
struct winsize ws; struct winsize ws;
...@@ -76,11 +76,12 @@ struct hv_ops { ...@@ -76,11 +76,12 @@ struct hv_ops {
}; };
/* Register a vterm and a slot index for use as a console (console_init) */ /* Register a vterm and a slot index for use as a console (console_init) */
extern int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops); extern int hvc_instantiate(uint32_t vtermno, int index,
const struct hv_ops *ops);
/* register a vterm for hvc tty operation (module_init or hotplug add) */ /* register a vterm for hvc tty operation (module_init or hotplug add) */
extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data, extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data,
struct hv_ops *ops, int outbuf_size); const struct hv_ops *ops, int outbuf_size);
/* remove a vterm from hvc tty operation (module_exit or hotplug remove) */ /* remove a vterm from hvc tty operation (module_exit or hotplug remove) */
extern int hvc_remove(struct hvc_struct *hp); extern int hvc_remove(struct hvc_struct *hp);
......
...@@ -197,7 +197,7 @@ static int put_chars(uint32_t vtermno, const char *buf, int count) ...@@ -197,7 +197,7 @@ static int put_chars(uint32_t vtermno, const char *buf, int count)
return sent; return sent;
} }
static struct hv_ops hvc_get_put_ops = { static const struct hv_ops hvc_get_put_ops = {
.get_chars = get_chars, .get_chars = get_chars,
.put_chars = put_chars, .put_chars = put_chars,
.notifier_add = notifier_add_irq, .notifier_add = notifier_add_irq,
......
...@@ -922,7 +922,7 @@ static int hvc_iucv_pm_restore_thaw(struct device *dev) ...@@ -922,7 +922,7 @@ static int hvc_iucv_pm_restore_thaw(struct device *dev)
/* HVC operations */ /* HVC operations */
static struct hv_ops hvc_iucv_ops = { static const struct hv_ops hvc_iucv_ops = {
.get_chars = hvc_iucv_get_chars, .get_chars = hvc_iucv_get_chars,
.put_chars = hvc_iucv_put_chars, .put_chars = hvc_iucv_put_chars,
.notifier_add = hvc_iucv_notifier_add, .notifier_add = hvc_iucv_notifier_add,
......
...@@ -71,7 +71,7 @@ static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count) ...@@ -71,7 +71,7 @@ static int hvc_rtas_read_console(uint32_t vtermno, char *buf, int count)
return i; return i;
} }
static struct hv_ops hvc_rtas_get_put_ops = { static const struct hv_ops hvc_rtas_get_put_ops = {
.get_chars = hvc_rtas_read_console, .get_chars = hvc_rtas_read_console,
.put_chars = hvc_rtas_write_console, .put_chars = hvc_rtas_write_console,
}; };
......
...@@ -58,7 +58,7 @@ static int hvc_udbg_get(uint32_t vtermno, char *buf, int count) ...@@ -58,7 +58,7 @@ static int hvc_udbg_get(uint32_t vtermno, char *buf, int count)
return i; return i;
} }
static struct hv_ops hvc_udbg_ops = { static const struct hv_ops hvc_udbg_ops = {
.get_chars = hvc_udbg_get, .get_chars = hvc_udbg_get,
.put_chars = hvc_udbg_put, .put_chars = hvc_udbg_put,
}; };
......
...@@ -77,7 +77,7 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count) ...@@ -77,7 +77,7 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count)
return got; return got;
} }
static struct hv_ops hvc_get_put_ops = { static const struct hv_ops hvc_get_put_ops = {
.get_chars = filtered_get_chars, .get_chars = filtered_get_chars,
.put_chars = hvc_put_chars, .put_chars = hvc_put_chars,
.notifier_add = notifier_add_irq, .notifier_add = notifier_add_irq,
......
...@@ -122,7 +122,7 @@ static int read_console(uint32_t vtermno, char *buf, int len) ...@@ -122,7 +122,7 @@ static int read_console(uint32_t vtermno, char *buf, int len)
return recv; return recv;
} }
static struct hv_ops hvc_ops = { static const struct hv_ops hvc_ops = {
.get_chars = read_console, .get_chars = read_console,
.put_chars = write_console, .put_chars = write_console,
.notifier_add = notifier_add_irq, .notifier_add = notifier_add_irq,
......
This diff is collapsed.
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
struct virtio_balloon struct virtio_balloon
{ {
struct virtio_device *vdev; struct virtio_device *vdev;
struct virtqueue *inflate_vq, *deflate_vq; struct virtqueue *inflate_vq, *deflate_vq, *stats_vq;
/* Where the ballooning thread waits for config to change. */ /* Where the ballooning thread waits for config to change. */
wait_queue_head_t config_change; wait_queue_head_t config_change;
...@@ -49,6 +49,10 @@ struct virtio_balloon ...@@ -49,6 +49,10 @@ struct virtio_balloon
/* The array of pfns we tell the Host about. */ /* The array of pfns we tell the Host about. */
unsigned int num_pfns; unsigned int num_pfns;
u32 pfns[256]; u32 pfns[256];
/* Memory statistics */
int need_stats_update;
struct virtio_balloon_stat stats[VIRTIO_BALLOON_S_NR];
}; };
static struct virtio_device_id id_table[] = { static struct virtio_device_id id_table[] = {
...@@ -154,6 +158,72 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num) ...@@ -154,6 +158,72 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
} }
} }
static inline void update_stat(struct virtio_balloon *vb, int idx,
u16 tag, u64 val)
{
BUG_ON(idx >= VIRTIO_BALLOON_S_NR);
vb->stats[idx].tag = tag;
vb->stats[idx].val = val;
}
#define pages_to_bytes(x) ((u64)(x) << PAGE_SHIFT)
static void update_balloon_stats(struct virtio_balloon *vb)
{
unsigned long events[NR_VM_EVENT_ITEMS];
struct sysinfo i;
int idx = 0;
all_vm_events(events);
si_meminfo(&i);
update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_IN,
pages_to_bytes(events[PSWPIN]));
update_stat(vb, idx++, VIRTIO_BALLOON_S_SWAP_OUT,
pages_to_bytes(events[PSWPOUT]));
update_stat(vb, idx++, VIRTIO_BALLOON_S_MAJFLT, events[PGMAJFAULT]);
update_stat(vb, idx++, VIRTIO_BALLOON_S_MINFLT, events[PGFAULT]);
update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMFREE,
pages_to_bytes(i.freeram));
update_stat(vb, idx++, VIRTIO_BALLOON_S_MEMTOT,
pages_to_bytes(i.totalram));
}
/*
* While most virtqueues communicate guest-initiated requests to the hypervisor,
* the stats queue operates in reverse. The driver initializes the virtqueue
* with a single buffer. From that point forward, all conversations consist of
* a hypervisor request (a call to this function) which directs us to refill
* the virtqueue with a fresh stats buffer. Since stats collection can sleep,
* we notify our kthread which does the actual work via stats_handle_request().
*/
static void stats_request(struct virtqueue *vq)
{
struct virtio_balloon *vb;
unsigned int len;
vb = vq->vq_ops->get_buf(vq, &len);
if (!vb)
return;
vb->need_stats_update = 1;
wake_up(&vb->config_change);
}
static void stats_handle_request(struct virtio_balloon *vb)
{
struct virtqueue *vq;
struct scatterlist sg;
vb->need_stats_update = 0;
update_balloon_stats(vb);
vq = vb->stats_vq;
sg_init_one(&sg, vb->stats, sizeof(vb->stats));
if (vq->vq_ops->add_buf(vq, &sg, 1, 0, vb) < 0)
BUG();
vq->vq_ops->kick(vq);
}
static void virtballoon_changed(struct virtio_device *vdev) static void virtballoon_changed(struct virtio_device *vdev)
{ {
struct virtio_balloon *vb = vdev->priv; struct virtio_balloon *vb = vdev->priv;
...@@ -190,8 +260,11 @@ static int balloon(void *_vballoon) ...@@ -190,8 +260,11 @@ static int balloon(void *_vballoon)
try_to_freeze(); try_to_freeze();
wait_event_interruptible(vb->config_change, wait_event_interruptible(vb->config_change,
(diff = towards_target(vb)) != 0 (diff = towards_target(vb)) != 0
|| vb->need_stats_update
|| kthread_should_stop() || kthread_should_stop()
|| freezing(current)); || freezing(current));
if (vb->need_stats_update)
stats_handle_request(vb);
if (diff > 0) if (diff > 0)
fill_balloon(vb, diff); fill_balloon(vb, diff);
else if (diff < 0) else if (diff < 0)
...@@ -204,10 +277,10 @@ static int balloon(void *_vballoon) ...@@ -204,10 +277,10 @@ static int balloon(void *_vballoon)
static int virtballoon_probe(struct virtio_device *vdev) static int virtballoon_probe(struct virtio_device *vdev)
{ {
struct virtio_balloon *vb; struct virtio_balloon *vb;
struct virtqueue *vqs[2]; struct virtqueue *vqs[3];
vq_callback_t *callbacks[] = { balloon_ack, balloon_ack }; vq_callback_t *callbacks[] = { balloon_ack, balloon_ack, stats_request };
const char *names[] = { "inflate", "deflate" }; const char *names[] = { "inflate", "deflate", "stats" };
int err; int err, nvqs;
vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL); vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
if (!vb) { if (!vb) {
...@@ -219,14 +292,31 @@ static int virtballoon_probe(struct virtio_device *vdev) ...@@ -219,14 +292,31 @@ static int virtballoon_probe(struct virtio_device *vdev)
vb->num_pages = 0; vb->num_pages = 0;
init_waitqueue_head(&vb->config_change); init_waitqueue_head(&vb->config_change);
vb->vdev = vdev; vb->vdev = vdev;
vb->need_stats_update = 0;
/* We expect two virtqueues. */ /* We expect two virtqueues: inflate and deflate,
err = vdev->config->find_vqs(vdev, 2, vqs, callbacks, names); * and optionally stat. */
nvqs = virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ) ? 3 : 2;
err = vdev->config->find_vqs(vdev, nvqs, vqs, callbacks, names);
if (err) if (err)
goto out_free_vb; goto out_free_vb;
vb->inflate_vq = vqs[0]; vb->inflate_vq = vqs[0];
vb->deflate_vq = vqs[1]; vb->deflate_vq = vqs[1];
if (virtio_has_feature(vb->vdev, VIRTIO_BALLOON_F_STATS_VQ)) {
struct scatterlist sg;
vb->stats_vq = vqs[2];
/*
* Prime this virtqueue with one buffer so the hypervisor can
* use it to signal us later.
*/
sg_init_one(&sg, vb->stats, sizeof vb->stats);
if (vb->stats_vq->vq_ops->add_buf(vb->stats_vq,
&sg, 1, 0, vb) < 0)
BUG();
vb->stats_vq->vq_ops->kick(vb->stats_vq);
}
vb->thread = kthread_run(balloon, vb, "vballoon"); vb->thread = kthread_run(balloon, vb, "vballoon");
if (IS_ERR(vb->thread)) { if (IS_ERR(vb->thread)) {
...@@ -264,7 +354,10 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev) ...@@ -264,7 +354,10 @@ static void __devexit virtballoon_remove(struct virtio_device *vdev)
kfree(vb); kfree(vb);
} }
static unsigned int features[] = { VIRTIO_BALLOON_F_MUST_TELL_HOST }; static unsigned int features[] = {
VIRTIO_BALLOON_F_MUST_TELL_HOST,
VIRTIO_BALLOON_F_STATS_VQ,
};
static struct virtio_driver virtio_balloon_driver = { static struct virtio_driver virtio_balloon_driver = {
.feature_table = features, .feature_table = features,
......
...@@ -702,7 +702,7 @@ static struct pci_driver virtio_pci_driver = { ...@@ -702,7 +702,7 @@ static struct pci_driver virtio_pci_driver = {
.name = "virtio-pci", .name = "virtio-pci",
.id_table = virtio_pci_id_table, .id_table = virtio_pci_id_table,
.probe = virtio_pci_probe, .probe = virtio_pci_probe,
.remove = virtio_pci_remove, .remove = __devexit_p(virtio_pci_remove),
#ifdef CONFIG_PM #ifdef CONFIG_PM
.suspend = virtio_pci_suspend, .suspend = virtio_pci_suspend,
.resume = virtio_pci_resume, .resume = virtio_pci_resume,
......
...@@ -21,6 +21,24 @@ ...@@ -21,6 +21,24 @@
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
#include <linux/device.h> #include <linux/device.h>
/* virtio guest is communicating with a virtual "device" that actually runs on
* a host processor. Memory barriers are used to control SMP effects. */
#ifdef CONFIG_SMP
/* Where possible, use SMP barriers which are more lightweight than mandatory
* barriers, because mandatory barriers control MMIO effects on accesses
* through relaxed memory I/O windows (which virtio does not use). */
#define virtio_mb() smp_mb()
#define virtio_rmb() smp_rmb()
#define virtio_wmb() smp_wmb()
#else
/* We must force memory ordering even if guest is UP since host could be
* running on another CPU, but SMP barriers are defined to barrier() in that
* configuration. So fall back to mandatory barriers instead. */
#define virtio_mb() mb()
#define virtio_rmb() rmb()
#define virtio_wmb() wmb()
#endif
#ifdef DEBUG #ifdef DEBUG
/* For development, we want to crash whenever the ring is screwed. */ /* For development, we want to crash whenever the ring is screwed. */
#define BAD_RING(_vq, fmt, args...) \ #define BAD_RING(_vq, fmt, args...) \
...@@ -36,10 +54,9 @@ ...@@ -36,10 +54,9 @@
panic("%s:in_use = %i\n", \ panic("%s:in_use = %i\n", \
(_vq)->vq.name, (_vq)->in_use); \ (_vq)->vq.name, (_vq)->in_use); \
(_vq)->in_use = __LINE__; \ (_vq)->in_use = __LINE__; \
mb(); \
} while (0) } while (0)
#define END_USE(_vq) \ #define END_USE(_vq) \
do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; mb(); } while(0) do { BUG_ON(!(_vq)->in_use); (_vq)->in_use = 0; } while(0)
#else #else
#define BAD_RING(_vq, fmt, args...) \ #define BAD_RING(_vq, fmt, args...) \
do { \ do { \
...@@ -221,13 +238,13 @@ static void vring_kick(struct virtqueue *_vq) ...@@ -221,13 +238,13 @@ static void vring_kick(struct virtqueue *_vq)
START_USE(vq); START_USE(vq);
/* Descriptors and available array need to be set before we expose the /* Descriptors and available array need to be set before we expose the
* new available array entries. */ * new available array entries. */
wmb(); virtio_wmb();
vq->vring.avail->idx += vq->num_added; vq->vring.avail->idx += vq->num_added;
vq->num_added = 0; vq->num_added = 0;
/* Need to update avail index before checking if we should notify */ /* Need to update avail index before checking if we should notify */
mb(); virtio_mb();
if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY)) if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
/* Prod other side to tell it about changes. */ /* Prod other side to tell it about changes. */
...@@ -286,7 +303,7 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len) ...@@ -286,7 +303,7 @@ static void *vring_get_buf(struct virtqueue *_vq, unsigned int *len)
} }
/* Only get used array entries after they have been exposed by host. */ /* Only get used array entries after they have been exposed by host. */
rmb(); virtio_rmb();
i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id; i = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].id;
*len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len; *len = vq->vring.used->ring[vq->last_used_idx%vq->vring.num].len;
...@@ -324,7 +341,7 @@ static bool vring_enable_cb(struct virtqueue *_vq) ...@@ -324,7 +341,7 @@ static bool vring_enable_cb(struct virtqueue *_vq)
/* We optimistically turn back on interrupts, then check if there was /* We optimistically turn back on interrupts, then check if there was
* more to do. */ * more to do. */
vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT; vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
mb(); virtio_mb();
if (unlikely(more_used(vq))) { if (unlikely(more_used(vq))) {
END_USE(vq); END_USE(vq);
return false; return false;
...@@ -334,6 +351,30 @@ static bool vring_enable_cb(struct virtqueue *_vq) ...@@ -334,6 +351,30 @@ static bool vring_enable_cb(struct virtqueue *_vq)
return true; return true;
} }
static void *vring_detach_unused_buf(struct virtqueue *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
unsigned int i;
void *buf;
START_USE(vq);
for (i = 0; i < vq->vring.num; i++) {
if (!vq->data[i])
continue;
/* detach_buf clears data, so grab it now. */
buf = vq->data[i];
detach_buf(vq, i);
END_USE(vq);
return buf;
}
/* That should have freed everything. */
BUG_ON(vq->num_free != vq->vring.num);
END_USE(vq);
return NULL;
}
irqreturn_t vring_interrupt(int irq, void *_vq) irqreturn_t vring_interrupt(int irq, void *_vq)
{ {
struct vring_virtqueue *vq = to_vvq(_vq); struct vring_virtqueue *vq = to_vvq(_vq);
...@@ -360,6 +401,7 @@ static struct virtqueue_ops vring_vq_ops = { ...@@ -360,6 +401,7 @@ static struct virtqueue_ops vring_vq_ops = {
.kick = vring_kick, .kick = vring_kick,
.disable_cb = vring_disable_cb, .disable_cb = vring_disable_cb,
.enable_cb = vring_enable_cb, .enable_cb = vring_enable_cb,
.detach_unused_buf = vring_detach_unused_buf,
}; };
struct virtqueue *vring_new_virtqueue(unsigned int num, struct virtqueue *vring_new_virtqueue(unsigned int num,
...@@ -406,8 +448,11 @@ struct virtqueue *vring_new_virtqueue(unsigned int num, ...@@ -406,8 +448,11 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
/* Put everything in free lists. */ /* Put everything in free lists. */
vq->num_free = num; vq->num_free = num;
vq->free_head = 0; vq->free_head = 0;
for (i = 0; i < num-1; i++) for (i = 0; i < num-1; i++) {
vq->vring.desc[i].next = i+1; vq->vring.desc[i].next = i+1;
vq->data[i] = NULL;
}
vq->data[i] = NULL;
return &vq->vq; return &vq->vq;
} }
......
...@@ -51,6 +51,9 @@ struct virtqueue { ...@@ -51,6 +51,9 @@ struct virtqueue {
* This re-enables callbacks; it returns "false" if there are pending * This re-enables callbacks; it returns "false" if there are pending
* buffers in the queue, to detect a possible race between the driver * buffers in the queue, to detect a possible race between the driver
* checking for more work, and enabling callbacks. * checking for more work, and enabling callbacks.
* @detach_unused_buf: detach first unused buffer
* vq: the struct virtqueue we're talking about.
* Returns NULL or the "data" token handed to add_buf
* *
* Locking rules are straightforward: the driver is responsible for * Locking rules are straightforward: the driver is responsible for
* locking. No two operations may be invoked simultaneously, with the exception * locking. No two operations may be invoked simultaneously, with the exception
...@@ -71,6 +74,7 @@ struct virtqueue_ops { ...@@ -71,6 +74,7 @@ struct virtqueue_ops {
void (*disable_cb)(struct virtqueue *vq); void (*disable_cb)(struct virtqueue *vq);
bool (*enable_cb)(struct virtqueue *vq); bool (*enable_cb)(struct virtqueue *vq);
void *(*detach_unused_buf)(struct virtqueue *vq);
}; };
/** /**
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
/* The feature bitmap for virtio balloon */ /* The feature bitmap for virtio balloon */
#define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */ #define VIRTIO_BALLOON_F_MUST_TELL_HOST 0 /* Tell before reclaiming pages */
#define VIRTIO_BALLOON_F_STATS_VQ 1 /* Memory Stats virtqueue */
/* Size of a PFN in the balloon interface. */ /* Size of a PFN in the balloon interface. */
#define VIRTIO_BALLOON_PFN_SHIFT 12 #define VIRTIO_BALLOON_PFN_SHIFT 12
...@@ -18,4 +19,18 @@ struct virtio_balloon_config ...@@ -18,4 +19,18 @@ struct virtio_balloon_config
/* Number of pages we've actually got in balloon. */ /* Number of pages we've actually got in balloon. */
__le32 actual; __le32 actual;
}; };
#define VIRTIO_BALLOON_S_SWAP_IN 0 /* Amount of memory swapped in */
#define VIRTIO_BALLOON_S_SWAP_OUT 1 /* Amount of memory swapped out */
#define VIRTIO_BALLOON_S_MAJFLT 2 /* Number of major faults */
#define VIRTIO_BALLOON_S_MINFLT 3 /* Number of minor faults */
#define VIRTIO_BALLOON_S_MEMFREE 4 /* Total amount of free memory */
#define VIRTIO_BALLOON_S_MEMTOT 5 /* Total amount of memory */
#define VIRTIO_BALLOON_S_NR 6
struct virtio_balloon_stat {
u16 tag;
u64 val;
} __attribute__((packed));
#endif /* _LINUX_VIRTIO_BALLOON_H */ #endif /* _LINUX_VIRTIO_BALLOON_H */
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/ #define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */ #define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
#define VIRTIO_BLK_F_FLUSH 9 /* Cache flush command support */ #define VIRTIO_BLK_F_FLUSH 9 /* Cache flush command support */
#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */
struct virtio_blk_config { struct virtio_blk_config {
/* The capacity (in 512-byte sectors). */ /* The capacity (in 512-byte sectors). */
...@@ -29,8 +30,20 @@ struct virtio_blk_config { ...@@ -29,8 +30,20 @@ struct virtio_blk_config {
__u8 heads; __u8 heads;
__u8 sectors; __u8 sectors;
} geometry; } geometry;
/* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */ /* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
__u32 blk_size; __u32 blk_size;
/* the next 4 entries are guarded by VIRTIO_BLK_F_TOPOLOGY */
/* exponent for physical block per logical block. */
__u8 physical_block_exp;
/* alignment offset in logical blocks. */
__u8 alignment_offset;
/* minimum I/O size without performance penalty in logical blocks. */
__u16 min_io_size;
/* optimal sustained I/O size in logical blocks. */
__u32 opt_io_size;
} __attribute__((packed)); } __attribute__((packed));
/* /*
......
...@@ -3,19 +3,45 @@ ...@@ -3,19 +3,45 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/virtio_ids.h> #include <linux/virtio_ids.h>
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
/* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so /*
* anyone can use the definitions to implement compatible drivers/servers. */ * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
* anyone can use the definitions to implement compatible drivers/servers.
*
* Copyright (C) Red Hat, Inc., 2009, 2010
*/
/* Feature bits */ /* Feature bits */
#define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */ #define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */
#define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */
struct virtio_console_config { struct virtio_console_config {
/* colums of the screens */ /* colums of the screens */
__u16 cols; __u16 cols;
/* rows of the screens */ /* rows of the screens */
__u16 rows; __u16 rows;
/* max. number of ports this device can hold */
__u32 max_nr_ports;
/* number of ports added so far */
__u32 nr_ports;
} __attribute__((packed)); } __attribute__((packed));
/*
* A message that's passed between the Host and the Guest for a
* particular port.
*/
struct virtio_console_control {
__u32 id; /* Port number */
__u16 event; /* The kind of control event (see below) */
__u16 value; /* Extra information for the key */
};
/* Some events for control messages */
#define VIRTIO_CONSOLE_PORT_READY 0
#define VIRTIO_CONSOLE_CONSOLE_PORT 1
#define VIRTIO_CONSOLE_RESIZE 2
#define VIRTIO_CONSOLE_PORT_OPEN 3
#define VIRTIO_CONSOLE_PORT_NAME 4
#define VIRTIO_CONSOLE_PORT_REMOVE 5
#ifdef __KERNEL__ #ifdef __KERNEL__
int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)); int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int));
......
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