Commit 832fe9c2 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:
  virtio: Add transport feature handling stub for virtio_ring.
  virtio: Rename set_features to finalize_features
  virtio: Formally reserve bits 28-31 to be 'transport' features.
  s390: use virtio_console for KVM on s390
  virtio: console as a config option
  virtio_console: use virtqueue notification for hvc_console
  hvc_console: rework setup to replace irq functions with callbacks
  virtio_blk: check for hardsector size from host
  virtio: Use bus_type probe and remove methods
  virtio: don't always force a notification when ring is full
  virtio: clarify that ABI is usable by any implementations
  virtio: Recycle unused recv buffer pages for large skbs in net driver
  virtio net: Allow receiving SG packets
  virtio net: Add ethtool ops for SG/GSO
  virtio: fix virtio_net xmit of freed skb bug
parents ed9559d3 e34f8725
...@@ -565,6 +565,7 @@ bool "s390 guest support (EXPERIMENTAL)" ...@@ -565,6 +565,7 @@ bool "s390 guest support (EXPERIMENTAL)"
depends on 64BIT && EXPERIMENTAL depends on 64BIT && EXPERIMENTAL
select VIRTIO select VIRTIO
select VIRTIO_RING select VIRTIO_RING
select VIRTIO_CONSOLE
help help
Select this option if you want to run the kernel under s390 linux Select this option if you want to run the kernel under s390 linux
endmenu endmenu
......
...@@ -54,6 +54,7 @@ ...@@ -54,6 +54,7 @@
#include <asm/sections.h> #include <asm/sections.h>
#include <asm/ebcdic.h> #include <asm/ebcdic.h>
#include <asm/compat.h> #include <asm/compat.h>
#include <asm/kvm_virtio.h>
long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY | long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
PSW_MASK_MCHECK | PSW_DEFAULT_KEY); PSW_MASK_MCHECK | PSW_DEFAULT_KEY);
...@@ -766,7 +767,8 @@ setup_arch(char **cmdline_p) ...@@ -766,7 +767,8 @@ setup_arch(char **cmdline_p)
printk("We are running under VM (64 bit mode)\n"); printk("We are running under VM (64 bit mode)\n");
else if (MACHINE_IS_KVM) { else if (MACHINE_IS_KVM) {
printk("We are running under KVM (64 bit mode)\n"); printk("We are running under KVM (64 bit mode)\n");
add_preferred_console("ttyS", 1, NULL); add_preferred_console("hvc", 0, NULL);
s390_virtio_console_init();
} else } else
printk("We are running native (64 bit mode)\n"); printk("We are running native (64 bit mode)\n");
#endif /* CONFIG_64BIT */ #endif /* CONFIG_64BIT */
......
...@@ -196,6 +196,7 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -196,6 +196,7 @@ static int virtblk_probe(struct virtio_device *vdev)
int err; int err;
u64 cap; u64 cap;
u32 v; u32 v;
u32 blk_size;
if (index_to_minor(index) >= 1 << MINORBITS) if (index_to_minor(index) >= 1 << MINORBITS)
return -ENOSPC; return -ENOSPC;
...@@ -290,6 +291,13 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -290,6 +291,13 @@ static int virtblk_probe(struct virtio_device *vdev)
if (!err) if (!err)
blk_queue_max_hw_segments(vblk->disk->queue, v); blk_queue_max_hw_segments(vblk->disk->queue, v);
/* Host can optionally specify the block size of the device */
err = virtio_config_val(vdev, VIRTIO_BLK_F_BLK_SIZE,
offsetof(struct virtio_blk_config, blk_size),
&blk_size);
if (!err)
blk_queue_hardsect_size(vblk->disk->queue, blk_size);
add_disk(vblk->disk); add_disk(vblk->disk);
return 0; return 0;
...@@ -330,7 +338,7 @@ static struct virtio_device_id id_table[] = { ...@@ -330,7 +338,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_GEOMETRY, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
}; };
static struct virtio_driver virtio_blk = { static struct virtio_driver virtio_blk = {
......
...@@ -578,11 +578,14 @@ config HVC_DRIVER ...@@ -578,11 +578,14 @@ config HVC_DRIVER
It will automatically be selected if one of the back-end console drivers It will automatically be selected if one of the back-end console drivers
is selected. is selected.
config HVC_IRQ
bool
config HVC_CONSOLE config HVC_CONSOLE
bool "pSeries Hypervisor Virtual Console support" bool "pSeries Hypervisor Virtual Console support"
depends on PPC_PSERIES depends on PPC_PSERIES
select HVC_DRIVER select HVC_DRIVER
select HVC_IRQ
help help
pSeries machines when partitioned support a hypervisor virtual pSeries machines when partitioned support a hypervisor virtual
console. This driver allows each pSeries partition to have a console console. This driver allows each pSeries partition to have a console
...@@ -593,6 +596,7 @@ config HVC_ISERIES ...@@ -593,6 +596,7 @@ config HVC_ISERIES
depends on PPC_ISERIES depends on PPC_ISERIES
default y default y
select HVC_DRIVER select HVC_DRIVER
select HVC_IRQ
help help
iSeries machines support a hypervisor virtual console. iSeries machines support a hypervisor virtual console.
...@@ -614,13 +618,18 @@ config HVC_XEN ...@@ -614,13 +618,18 @@ config HVC_XEN
bool "Xen Hypervisor Console support" bool "Xen Hypervisor Console support"
depends on XEN depends on XEN
select HVC_DRIVER select HVC_DRIVER
select HVC_IRQ
default y default y
help help
Xen virtual console device driver Xen virtual console device driver
config VIRTIO_CONSOLE config VIRTIO_CONSOLE
bool tristate "Virtio console"
depends on VIRTIO
select HVC_DRIVER select HVC_DRIVER
help
Virtio console for use with lguest and other hypervisors.
config HVCS config HVCS
tristate "IBM Hypervisor Virtual Console Server support" tristate "IBM Hypervisor Virtual Console Server support"
......
...@@ -48,6 +48,7 @@ obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o ...@@ -48,6 +48,7 @@ obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
obj-$(CONFIG_HVC_BEAT) += hvc_beat.o obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
obj-$(CONFIG_HVC_XEN) += hvc_xen.o obj-$(CONFIG_HVC_XEN) += hvc_xen.o
obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_RAW_DRIVER) += raw.o
......
...@@ -27,7 +27,6 @@ ...@@ -27,7 +27,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/kbd_kern.h> #include <linux/kbd_kern.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/kthread.h> #include <linux/kthread.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -75,23 +74,6 @@ static int hvc_init(void); ...@@ -75,23 +74,6 @@ static int hvc_init(void);
static int sysrq_pressed; static int sysrq_pressed;
#endif #endif
struct hvc_struct {
spinlock_t lock;
int index;
struct tty_struct *tty;
unsigned int count;
int do_wakeup;
char *outbuf;
int outbuf_size;
int n_outbuf;
uint32_t vtermno;
struct hv_ops *ops;
int irq_requested;
int irq;
struct list_head next;
struct kref kref; /* ref count & hvc_struct lifetime */
};
/* dynamic list of hvc_struct instances */ /* dynamic list of hvc_struct instances */
static LIST_HEAD(hvc_structs); static LIST_HEAD(hvc_structs);
...@@ -298,27 +280,15 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) ...@@ -298,27 +280,15 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(hvc_instantiate);
/* Wake the sleeping khvcd */ /* Wake the sleeping khvcd */
static void hvc_kick(void) void hvc_kick(void)
{ {
hvc_kicked = 1; hvc_kicked = 1;
wake_up_process(hvc_task); wake_up_process(hvc_task);
} }
EXPORT_SYMBOL_GPL(hvc_kick);
static int hvc_poll(struct hvc_struct *hp);
/*
* NOTE: This API isn't used if the console adapter doesn't support interrupts.
* In this case the console is poll driven.
*/
static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
{
/* if hvc_poll request a repoll, then kick the hvcd thread */
if (hvc_poll(dev_instance))
hvc_kick();
return IRQ_HANDLED;
}
static void hvc_unthrottle(struct tty_struct *tty) static void hvc_unthrottle(struct tty_struct *tty)
{ {
...@@ -333,7 +303,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) ...@@ -333,7 +303,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
{ {
struct hvc_struct *hp; struct hvc_struct *hp;
unsigned long flags; unsigned long flags;
int irq = 0;
int rc = 0; int rc = 0;
/* Auto increments kref reference if found. */ /* Auto increments kref reference if found. */
...@@ -352,18 +321,15 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) ...@@ -352,18 +321,15 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
tty->low_latency = 1; /* Makes flushes to ldisc synchronous. */ tty->low_latency = 1; /* Makes flushes to ldisc synchronous. */
hp->tty = tty; hp->tty = tty;
/* Save for request_irq outside of spin_lock. */
irq = hp->irq; if (hp->ops->notifier_add)
if (irq) rc = hp->ops->notifier_add(hp, hp->data);
hp->irq_requested = 1;
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
/* check error, fallback to non-irq */
if (irq)
rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED, "hvc_console", hp);
/* /*
* If the request_irq() fails and we return an error. The tty layer * If the notifier fails we return an error. The tty layer
* will call hvc_close() after a failed open but we don't want to clean * will call hvc_close() after a failed open but we don't want to clean
* up there so we'll clean up here and clear out the previously set * up there so we'll clean up here and clear out the previously set
* tty fields and return the kref reference. * tty fields and return the kref reference.
...@@ -371,7 +337,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) ...@@ -371,7 +337,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
if (rc) { if (rc) {
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
hp->tty = NULL; hp->tty = NULL;
hp->irq_requested = 0;
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
tty->driver_data = NULL; tty->driver_data = NULL;
kref_put(&hp->kref, destroy_hvc_struct); kref_put(&hp->kref, destroy_hvc_struct);
...@@ -386,7 +351,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) ...@@ -386,7 +351,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
static void hvc_close(struct tty_struct *tty, struct file * filp) static void hvc_close(struct tty_struct *tty, struct file * filp)
{ {
struct hvc_struct *hp; struct hvc_struct *hp;
int irq = 0;
unsigned long flags; unsigned long flags;
if (tty_hung_up_p(filp)) if (tty_hung_up_p(filp))
...@@ -404,9 +368,8 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) ...@@ -404,9 +368,8 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
spin_lock_irqsave(&hp->lock, flags); spin_lock_irqsave(&hp->lock, flags);
if (--hp->count == 0) { if (--hp->count == 0) {
if (hp->irq_requested) if (hp->ops->notifier_del)
irq = hp->irq; hp->ops->notifier_del(hp, hp->data);
hp->irq_requested = 0;
/* We are done with the tty pointer now. */ /* We are done with the tty pointer now. */
hp->tty = NULL; hp->tty = NULL;
...@@ -418,10 +381,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) ...@@ -418,10 +381,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
* waking periodically to check chars_in_buffer(). * waking periodically to check chars_in_buffer().
*/ */
tty_wait_until_sent(tty, HVC_CLOSE_WAIT); tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
if (irq)
free_irq(irq, hp);
} else { } else {
if (hp->count < 0) if (hp->count < 0)
printk(KERN_ERR "hvc_close %X: oops, count is %d\n", printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
...@@ -436,7 +395,6 @@ static void hvc_hangup(struct tty_struct *tty) ...@@ -436,7 +395,6 @@ static void hvc_hangup(struct tty_struct *tty)
{ {
struct hvc_struct *hp = tty->driver_data; struct hvc_struct *hp = tty->driver_data;
unsigned long flags; unsigned long flags;
int irq = 0;
int temp_open_count; int temp_open_count;
if (!hp) if (!hp)
...@@ -458,13 +416,12 @@ static void hvc_hangup(struct tty_struct *tty) ...@@ -458,13 +416,12 @@ static void hvc_hangup(struct tty_struct *tty)
hp->count = 0; hp->count = 0;
hp->n_outbuf = 0; hp->n_outbuf = 0;
hp->tty = NULL; hp->tty = NULL;
if (hp->irq_requested)
/* Saved for use outside of spin_lock. */ if (hp->ops->notifier_del)
irq = hp->irq; hp->ops->notifier_del(hp, hp->data);
hp->irq_requested = 0;
spin_unlock_irqrestore(&hp->lock, flags); spin_unlock_irqrestore(&hp->lock, flags);
if (irq)
free_irq(irq, hp);
while(temp_open_count) { while(temp_open_count) {
--temp_open_count; --temp_open_count;
kref_put(&hp->kref, destroy_hvc_struct); kref_put(&hp->kref, destroy_hvc_struct);
...@@ -575,7 +532,7 @@ static u32 timeout = MIN_TIMEOUT; ...@@ -575,7 +532,7 @@ static u32 timeout = MIN_TIMEOUT;
#define HVC_POLL_READ 0x00000001 #define HVC_POLL_READ 0x00000001
#define HVC_POLL_WRITE 0x00000002 #define HVC_POLL_WRITE 0x00000002
static int hvc_poll(struct hvc_struct *hp) int hvc_poll(struct hvc_struct *hp)
{ {
struct tty_struct *tty; struct tty_struct *tty;
int i, n, poll_mask = 0; int i, n, poll_mask = 0;
...@@ -602,10 +559,10 @@ static int hvc_poll(struct hvc_struct *hp) ...@@ -602,10 +559,10 @@ static int hvc_poll(struct hvc_struct *hp)
if (test_bit(TTY_THROTTLED, &tty->flags)) if (test_bit(TTY_THROTTLED, &tty->flags))
goto throttled; goto throttled;
/* If we aren't interrupt driven and aren't throttled, we always /* If we aren't notifier driven and aren't throttled, we always
* request a reschedule * request a reschedule
*/ */
if (hp->irq == 0) if (!hp->irq_requested)
poll_mask |= HVC_POLL_READ; poll_mask |= HVC_POLL_READ;
/* Read data if any */ /* Read data if any */
...@@ -674,6 +631,7 @@ static int hvc_poll(struct hvc_struct *hp) ...@@ -674,6 +631,7 @@ static int hvc_poll(struct hvc_struct *hp)
return poll_mask; return poll_mask;
} }
EXPORT_SYMBOL_GPL(hvc_poll);
/* /*
* This kthread is either polling or interrupt driven. This is determined by * This kthread is either polling or interrupt driven. This is determined by
...@@ -733,7 +691,7 @@ static const struct tty_operations hvc_ops = { ...@@ -733,7 +691,7 @@ static const struct tty_operations hvc_ops = {
.chars_in_buffer = hvc_chars_in_buffer, .chars_in_buffer = hvc_chars_in_buffer,
}; };
struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int data,
struct hv_ops *ops, int outbuf_size) struct hv_ops *ops, int outbuf_size)
{ {
struct hvc_struct *hp; struct hvc_struct *hp;
...@@ -754,7 +712,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, ...@@ -754,7 +712,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
memset(hp, 0x00, sizeof(*hp)); memset(hp, 0x00, sizeof(*hp));
hp->vtermno = vtermno; hp->vtermno = vtermno;
hp->irq = irq; hp->data = data;
hp->ops = ops; hp->ops = ops;
hp->outbuf_size = outbuf_size; hp->outbuf_size = outbuf_size;
hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
...@@ -784,6 +742,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, ...@@ -784,6 +742,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
return hp; return hp;
} }
EXPORT_SYMBOL_GPL(hvc_alloc);
int __devexit hvc_remove(struct hvc_struct *hp) int __devexit hvc_remove(struct hvc_struct *hp)
{ {
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#ifndef HVC_CONSOLE_H #ifndef HVC_CONSOLE_H
#define HVC_CONSOLE_H #define HVC_CONSOLE_H
#include <linux/kref.h>
/* /*
* This is the max number of console adapters that can/will be found as * This is the max number of console adapters that can/will be found as
...@@ -42,24 +43,50 @@ ...@@ -42,24 +43,50 @@
*/ */
#define HVC_ALLOC_TTY_ADAPTERS 8 #define HVC_ALLOC_TTY_ADAPTERS 8
struct hvc_struct {
spinlock_t lock;
int index;
struct tty_struct *tty;
unsigned int count;
int do_wakeup;
char *outbuf;
int outbuf_size;
int n_outbuf;
uint32_t vtermno;
struct hv_ops *ops;
int irq_requested;
int data;
struct list_head next;
struct kref kref; /* ref count & hvc_struct lifetime */
};
/* implemented by a low level driver */ /* implemented by a low level driver */
struct hv_ops { struct hv_ops {
int (*get_chars)(uint32_t vtermno, char *buf, int count); int (*get_chars)(uint32_t vtermno, char *buf, int count);
int (*put_chars)(uint32_t vtermno, const char *buf, int count); int (*put_chars)(uint32_t vtermno, const char *buf, int count);
};
struct hvc_struct; /* Callbacks for notification. Called in open and close */
int (*notifier_add)(struct hvc_struct *hp, int irq);
void (*notifier_del)(struct hvc_struct *hp, int irq);
};
/* 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, 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 irq, extern struct hvc_struct * __devinit hvc_alloc(uint32_t vtermno, int data,
struct hv_ops *ops, int outbuf_size); struct hv_ops *ops, int outbuf_size);
/* remove a vterm from hvc tty operation (modele_exit or hotplug remove) */ /* remove a vterm from hvc tty operation (module_exit or hotplug remove) */
extern int __devexit hvc_remove(struct hvc_struct *hp); extern int __devexit hvc_remove(struct hvc_struct *hp);
/* data available */
int hvc_poll(struct hvc_struct *hp);
void hvc_kick(void);
/* default notifier for irq based notification */
extern int notifier_add_irq(struct hvc_struct *hp, int data);
extern void notifier_del_irq(struct hvc_struct *hp, int data);
#if defined(CONFIG_XMON) && defined(CONFIG_SMP) #if defined(CONFIG_XMON) && defined(CONFIG_SMP)
#include <asm/xmon.h> #include <asm/xmon.h>
......
/*
* Copyright IBM Corp. 2001,2008
*
* This file contains the IRQ specific code for hvc_console
*
*/
#include <linux/interrupt.h>
#include "hvc_console.h"
static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance)
{
/* if hvc_poll request a repoll, then kick the hvcd thread */
if (hvc_poll(dev_instance))
hvc_kick();
return IRQ_HANDLED;
}
/*
* For IRQ based systems these callbacks can be used
*/
int notifier_add_irq(struct hvc_struct *hp, int irq)
{
int rc;
if (!irq) {
hp->irq_requested = 0;
return 0;
}
rc = request_irq(irq, hvc_handle_interrupt, IRQF_DISABLED,
"hvc_console", hp);
if (!rc)
hp->irq_requested = 1;
return rc;
}
void notifier_del_irq(struct hvc_struct *hp, int irq)
{
if (!irq)
return;
free_irq(irq, hp);
hp->irq_requested = 0;
}
...@@ -200,6 +200,8 @@ static int put_chars(uint32_t vtermno, const char *buf, int count) ...@@ -200,6 +200,8 @@ static int put_chars(uint32_t vtermno, const char *buf, int count)
static struct hv_ops hvc_get_put_ops = { static 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_del = notifier_del_irq,
}; };
static int __devinit hvc_vio_probe(struct vio_dev *vdev, static int __devinit hvc_vio_probe(struct vio_dev *vdev,
......
...@@ -80,6 +80,8 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count) ...@@ -80,6 +80,8 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count)
static struct hv_ops hvc_get_put_ops = { static 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_del = notifier_del_irq,
}; };
static int __devinit hvc_vio_probe(struct vio_dev *vdev, static int __devinit hvc_vio_probe(struct vio_dev *vdev,
......
...@@ -100,6 +100,8 @@ static int read_console(uint32_t vtermno, char *buf, int len) ...@@ -100,6 +100,8 @@ static int read_console(uint32_t vtermno, char *buf, int len)
static struct hv_ops hvc_ops = { static 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_del = notifier_del_irq,
}; };
static int __init xen_init(void) static int __init xen_init(void)
......
...@@ -46,6 +46,9 @@ static char *in, *inbuf; ...@@ -46,6 +46,9 @@ static char *in, *inbuf;
/* The operations for our console. */ /* The operations for our console. */
static struct hv_ops virtio_cons; static struct hv_ops virtio_cons;
/* The hvc device */
static struct hvc_struct *hvc;
/*D:310 The put_chars() callback is pretty straightforward. /*D:310 The put_chars() callback is pretty straightforward.
* *
* We turn the characters into a scatter-gather list, add it to the output * We turn the characters into a scatter-gather list, add it to the output
...@@ -134,6 +137,27 @@ int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) ...@@ -134,6 +137,27 @@ int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
return hvc_instantiate(0, 0, &virtio_cons); return hvc_instantiate(0, 0, &virtio_cons);
} }
/*
* we support only one console, the hvc struct is a global var
* There is no need to do anything
*/
static int notifier_add_vio(struct hvc_struct *hp, int data)
{
hp->irq_requested = 1;
return 0;
}
static void notifier_del_vio(struct hvc_struct *hp, int data)
{
hp->irq_requested = 0;
}
static void hvc_handle_input(struct virtqueue *vq)
{
if (hvc_poll(hvc))
hvc_kick();
}
/*D:370 Once we're further in boot, we get probed like any other virtio device. /*D:370 Once we're further in boot, we get probed like any other virtio device.
* At this stage we set up the output virtqueue. * At this stage we set up the output virtqueue.
* *
...@@ -144,7 +168,6 @@ int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int)) ...@@ -144,7 +168,6 @@ int __init virtio_cons_early_init(int (*put_chars)(u32, const char *, int))
static int __devinit virtcons_probe(struct virtio_device *dev) static int __devinit virtcons_probe(struct virtio_device *dev)
{ {
int err; int err;
struct hvc_struct *hvc;
vdev = dev; vdev = dev;
...@@ -158,7 +181,7 @@ static int __devinit virtcons_probe(struct virtio_device *dev) ...@@ -158,7 +181,7 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
/* Find the input queue. */ /* Find the input queue. */
/* FIXME: This is why we want to wean off hvc: we do nothing /* FIXME: This is why we want to wean off hvc: we do nothing
* when input comes in. */ * when input comes in. */
in_vq = vdev->config->find_vq(vdev, 0, NULL); in_vq = vdev->config->find_vq(vdev, 0, hvc_handle_input);
if (IS_ERR(in_vq)) { if (IS_ERR(in_vq)) {
err = PTR_ERR(in_vq); err = PTR_ERR(in_vq);
goto free; goto free;
...@@ -173,15 +196,18 @@ static int __devinit virtcons_probe(struct virtio_device *dev) ...@@ -173,15 +196,18 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
/* Start using the new console output. */ /* Start using the new console output. */
virtio_cons.get_chars = get_chars; virtio_cons.get_chars = get_chars;
virtio_cons.put_chars = put_chars; virtio_cons.put_chars = put_chars;
virtio_cons.notifier_add = notifier_add_vio;
virtio_cons.notifier_del = notifier_del_vio;
/* The first argument of hvc_alloc() is the virtual console number, so /* The first argument of hvc_alloc() is the virtual console number, so
* we use zero. The second argument is the interrupt number; we * we use zero. The second argument is the parameter for the
* currently leave this as zero: it would be better not to use the * notification mechanism (like irq number). We currently leave this
* hvc mechanism and fix this (FIXME!). * as zero, virtqueues have implicit notifications.
* *
* The third argument is a "struct hv_ops" containing the put_chars() * The third argument is a "struct hv_ops" containing the put_chars()
* and get_chars() pointers. The final argument is the output buffer * get_chars(), notifier_add() and notifier_del() pointers.
* size: we can do any size, so we put PAGE_SIZE here. */ * The final argument is the output buffer size: we can do any size,
* so we put PAGE_SIZE here. */
hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE); hvc = hvc_alloc(0, 0, &virtio_cons, PAGE_SIZE);
if (IS_ERR(hvc)) { if (IS_ERR(hvc)) {
err = PTR_ERR(hvc); err = PTR_ERR(hvc);
......
...@@ -98,16 +98,20 @@ static u32 lg_get_features(struct virtio_device *vdev) ...@@ -98,16 +98,20 @@ static u32 lg_get_features(struct virtio_device *vdev)
return features; return features;
} }
static void lg_set_features(struct virtio_device *vdev, u32 features) static void lg_finalize_features(struct virtio_device *vdev)
{ {
unsigned int i; unsigned int i, bits;
struct lguest_device_desc *desc = to_lgdev(vdev)->desc; struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
/* Second half of bitmap is features we accept. */ /* Second half of bitmap is features we accept. */
u8 *out_features = lg_features(desc) + desc->feature_len; u8 *out_features = lg_features(desc) + desc->feature_len;
/* Give virtio_ring a chance to accept features. */
vring_transport_features(vdev);
memset(out_features, 0, desc->feature_len); memset(out_features, 0, desc->feature_len);
for (i = 0; i < min(desc->feature_len * 8, 32); i++) { bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
if (features & (1 << i)) for (i = 0; i < bits; i++) {
if (test_bit(i, vdev->features))
out_features[i / 8] |= (1 << (i % 8)); out_features[i / 8] |= (1 << (i % 8));
} }
} }
...@@ -297,7 +301,7 @@ static void lg_del_vq(struct virtqueue *vq) ...@@ -297,7 +301,7 @@ static void lg_del_vq(struct virtqueue *vq)
/* The ops structure which hooks everything together. */ /* The ops structure which hooks everything together. */
static struct virtio_config_ops lguest_config_ops = { static struct virtio_config_ops lguest_config_ops = {
.get_features = lg_get_features, .get_features = lg_get_features,
.set_features = lg_set_features, .finalize_features = lg_finalize_features,
.get = lg_get, .get = lg_get,
.set = lg_set, .set = lg_set,
.get_status = lg_get_status, .get_status = lg_get_status,
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
//#define DEBUG //#define DEBUG
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/virtio.h> #include <linux/virtio.h>
#include <linux/virtio_net.h> #include <linux/virtio_net.h>
...@@ -54,9 +55,15 @@ struct virtnet_info ...@@ -54,9 +55,15 @@ struct virtnet_info
struct tasklet_struct tasklet; struct tasklet_struct tasklet;
bool free_in_tasklet; bool free_in_tasklet;
/* I like... big packets and I cannot lie! */
bool big_packets;
/* Receive & send queues. */ /* Receive & send queues. */
struct sk_buff_head recv; struct sk_buff_head recv;
struct sk_buff_head send; struct sk_buff_head send;
/* Chain pages by the private ptr. */
struct page *pages;
}; };
static inline struct virtio_net_hdr *skb_vnet_hdr(struct sk_buff *skb) static inline struct virtio_net_hdr *skb_vnet_hdr(struct sk_buff *skb)
...@@ -69,6 +76,23 @@ static inline void vnet_hdr_to_sg(struct scatterlist *sg, struct sk_buff *skb) ...@@ -69,6 +76,23 @@ static inline void vnet_hdr_to_sg(struct scatterlist *sg, struct sk_buff *skb)
sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr)); sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr));
} }
static void give_a_page(struct virtnet_info *vi, struct page *page)
{
page->private = (unsigned long)vi->pages;
vi->pages = page;
}
static struct page *get_a_page(struct virtnet_info *vi, gfp_t gfp_mask)
{
struct page *p = vi->pages;
if (p)
vi->pages = (struct page *)p->private;
else
p = alloc_page(gfp_mask);
return p;
}
static void skb_xmit_done(struct virtqueue *svq) static void skb_xmit_done(struct virtqueue *svq)
{ {
struct virtnet_info *vi = svq->vdev->priv; struct virtnet_info *vi = svq->vdev->priv;
...@@ -88,6 +112,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, ...@@ -88,6 +112,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
unsigned len) unsigned len)
{ {
struct virtio_net_hdr *hdr = skb_vnet_hdr(skb); struct virtio_net_hdr *hdr = skb_vnet_hdr(skb);
int err;
if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) { if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
pr_debug("%s: short packet %i\n", dev->name, len); pr_debug("%s: short packet %i\n", dev->name, len);
...@@ -95,10 +120,23 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb, ...@@ -95,10 +120,23 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
goto drop; goto drop;
} }
len -= sizeof(struct virtio_net_hdr); len -= sizeof(struct virtio_net_hdr);
BUG_ON(len > MAX_PACKET_LEN);
skb_trim(skb, len); if (len <= MAX_PACKET_LEN) {
unsigned int i;
for (i = 0; i < skb_shinfo(skb)->nr_frags; i++)
give_a_page(dev->priv, skb_shinfo(skb)->frags[i].page);
skb->data_len = 0;
skb_shinfo(skb)->nr_frags = 0;
}
err = pskb_trim(skb, len);
if (err) {
pr_debug("%s: pskb_trim failed %i %d\n", dev->name, len, err);
dev->stats.rx_dropped++;
goto drop;
}
skb->truesize += skb->data_len;
dev->stats.rx_bytes += skb->len; dev->stats.rx_bytes += skb->len;
dev->stats.rx_packets++; dev->stats.rx_packets++;
...@@ -160,7 +198,7 @@ static void try_fill_recv(struct virtnet_info *vi) ...@@ -160,7 +198,7 @@ static void try_fill_recv(struct virtnet_info *vi)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct scatterlist sg[2+MAX_SKB_FRAGS]; struct scatterlist sg[2+MAX_SKB_FRAGS];
int num, err; int num, err, i;
sg_init_table(sg, 2+MAX_SKB_FRAGS); sg_init_table(sg, 2+MAX_SKB_FRAGS);
for (;;) { for (;;) {
...@@ -170,6 +208,24 @@ static void try_fill_recv(struct virtnet_info *vi) ...@@ -170,6 +208,24 @@ static void try_fill_recv(struct virtnet_info *vi)
skb_put(skb, MAX_PACKET_LEN); skb_put(skb, MAX_PACKET_LEN);
vnet_hdr_to_sg(sg, skb); vnet_hdr_to_sg(sg, skb);
if (vi->big_packets) {
for (i = 0; i < MAX_SKB_FRAGS; i++) {
skb_frag_t *f = &skb_shinfo(skb)->frags[i];
f->page = get_a_page(vi, GFP_ATOMIC);
if (!f->page)
break;
f->page_offset = 0;
f->size = PAGE_SIZE;
skb->data_len += PAGE_SIZE;
skb->len += PAGE_SIZE;
skb_shinfo(skb)->nr_frags++;
}
}
num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
skb_queue_head(&vi->recv, skb); skb_queue_head(&vi->recv, skb);
...@@ -335,16 +391,11 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -335,16 +391,11 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
free_old_xmit_skbs(vi); free_old_xmit_skbs(vi);
/* If we has a buffer left over from last time, send it now. */ /* If we has a buffer left over from last time, send it now. */
if (unlikely(vi->last_xmit_skb)) { if (unlikely(vi->last_xmit_skb) &&
if (xmit_skb(vi, vi->last_xmit_skb) != 0) { xmit_skb(vi, vi->last_xmit_skb) != 0)
/* Drop this skb: we only queue one. */
vi->dev->stats.tx_dropped++;
kfree_skb(skb);
skb = NULL;
goto stop_queue; goto stop_queue;
}
vi->last_xmit_skb = NULL; vi->last_xmit_skb = NULL;
}
/* Put new one in send queue and do transmit */ /* Put new one in send queue and do transmit */
if (likely(skb)) { if (likely(skb)) {
...@@ -370,6 +421,11 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -370,6 +421,11 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_start_queue(dev); netif_start_queue(dev);
goto again; goto again;
} }
if (skb) {
/* Drop this skb: we only queue one. */
vi->dev->stats.tx_dropped++;
kfree_skb(skb);
}
goto done; goto done;
} }
...@@ -408,6 +464,22 @@ static int virtnet_close(struct net_device *dev) ...@@ -408,6 +464,22 @@ static int virtnet_close(struct net_device *dev)
return 0; return 0;
} }
static int virtnet_set_tx_csum(struct net_device *dev, u32 data)
{
struct virtnet_info *vi = netdev_priv(dev);
struct virtio_device *vdev = vi->vdev;
if (data && !virtio_has_feature(vdev, VIRTIO_NET_F_CSUM))
return -ENOSYS;
return ethtool_op_set_tx_hw_csum(dev, data);
}
static struct ethtool_ops virtnet_ethtool_ops = {
.set_tx_csum = virtnet_set_tx_csum,
.set_sg = ethtool_op_set_sg,
};
static int virtnet_probe(struct virtio_device *vdev) static int virtnet_probe(struct virtio_device *vdev)
{ {
int err; int err;
...@@ -427,6 +499,7 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -427,6 +499,7 @@ static int virtnet_probe(struct virtio_device *vdev)
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = virtnet_netpoll; dev->poll_controller = virtnet_netpoll;
#endif #endif
SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops);
SET_NETDEV_DEV(dev, &vdev->dev); SET_NETDEV_DEV(dev, &vdev->dev);
/* Do we support "hardware" checksums? */ /* Do we support "hardware" checksums? */
...@@ -462,11 +535,18 @@ static int virtnet_probe(struct virtio_device *vdev) ...@@ -462,11 +535,18 @@ static int virtnet_probe(struct virtio_device *vdev)
vi->dev = dev; vi->dev = dev;
vi->vdev = vdev; vi->vdev = vdev;
vdev->priv = vi; vdev->priv = vi;
vi->pages = NULL;
/* If they give us a callback when all buffers are done, we don't need /* If they give us a callback when all buffers are done, we don't need
* the timer. */ * the timer. */
vi->free_in_tasklet = virtio_has_feature(vdev,VIRTIO_F_NOTIFY_ON_EMPTY); vi->free_in_tasklet = virtio_has_feature(vdev,VIRTIO_F_NOTIFY_ON_EMPTY);
/* If we can receive ANY GSO packets, we must allocate large ones. */
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4)
|| virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6)
|| virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
vi->big_packets = true;
/* We expect two virtqueues, receive then send. */ /* We expect two virtqueues, receive then send. */
vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done); vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
if (IS_ERR(vi->rvq)) { if (IS_ERR(vi->rvq)) {
...@@ -541,6 +621,10 @@ static void virtnet_remove(struct virtio_device *vdev) ...@@ -541,6 +621,10 @@ static void virtnet_remove(struct virtio_device *vdev)
vdev->config->del_vq(vi->svq); vdev->config->del_vq(vi->svq);
vdev->config->del_vq(vi->rvq); vdev->config->del_vq(vi->rvq);
unregister_netdev(vi->dev); unregister_netdev(vi->dev);
while (vi->pages)
__free_pages(get_a_page(vi, GFP_KERNEL), 0);
free_netdev(vi->dev); free_netdev(vi->dev);
} }
...@@ -553,7 +637,9 @@ static unsigned int features[] = { ...@@ -553,7 +637,9 @@ static unsigned int features[] = {
VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM, VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM,
VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC, VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
VIRTIO_NET_F_HOST_ECN, VIRTIO_F_NOTIFY_ON_EMPTY, VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */
VIRTIO_F_NOTIFY_ON_EMPTY,
}; };
static struct virtio_driver virtio_net = { static struct virtio_driver virtio_net = {
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/virtio.h> #include <linux/virtio.h>
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
#include <linux/virtio_console.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/virtio_ring.h> #include <linux/virtio_ring.h>
#include <linux/pfn.h> #include <linux/pfn.h>
...@@ -87,16 +88,20 @@ static u32 kvm_get_features(struct virtio_device *vdev) ...@@ -87,16 +88,20 @@ static u32 kvm_get_features(struct virtio_device *vdev)
return features; return features;
} }
static void kvm_set_features(struct virtio_device *vdev, u32 features) static void kvm_finalize_features(struct virtio_device *vdev)
{ {
unsigned int i; unsigned int i, bits;
struct kvm_device_desc *desc = to_kvmdev(vdev)->desc; struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
/* Second half of bitmap is features we accept. */ /* Second half of bitmap is features we accept. */
u8 *out_features = kvm_vq_features(desc) + desc->feature_len; u8 *out_features = kvm_vq_features(desc) + desc->feature_len;
/* Give virtio_ring a chance to accept features. */
vring_transport_features(vdev);
memset(out_features, 0, desc->feature_len); memset(out_features, 0, desc->feature_len);
for (i = 0; i < min(desc->feature_len * 8, 32); i++) { bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
if (features & (1 << i)) for (i = 0; i < bits; i++) {
if (test_bit(i, vdev->features))
out_features[i / 8] |= (1 << (i % 8)); out_features[i / 8] |= (1 << (i % 8));
} }
} }
...@@ -222,7 +227,7 @@ static void kvm_del_vq(struct virtqueue *vq) ...@@ -222,7 +227,7 @@ static void kvm_del_vq(struct virtqueue *vq)
*/ */
static struct virtio_config_ops kvm_vq_configspace_ops = { static struct virtio_config_ops kvm_vq_configspace_ops = {
.get_features = kvm_get_features, .get_features = kvm_get_features,
.set_features = kvm_set_features, .finalize_features = kvm_finalize_features,
.get = kvm_get, .get = kvm_get,
.set = kvm_set, .set = kvm_set,
.get_status = kvm_get_status, .get_status = kvm_get_status,
...@@ -333,6 +338,25 @@ static int __init kvm_devices_init(void) ...@@ -333,6 +338,25 @@ static int __init kvm_devices_init(void)
return 0; return 0;
} }
/* code for early console output with virtio_console */
static __init int early_put_chars(u32 vtermno, const char *buf, int count)
{
char scratch[17];
unsigned int len = count;
if (len > sizeof(scratch) - 1)
len = sizeof(scratch) - 1;
scratch[len] = '\0';
memcpy(scratch, buf, len);
kvm_hypercall1(KVM_S390_VIRTIO_NOTIFY, __pa(scratch));
return len;
}
void s390_virtio_console_init(void)
{
virtio_cons_early_init(early_put_chars);
}
/* /*
* We do this after core stuff, but before the drivers. * We do this after core stuff, but before the drivers.
*/ */
......
...@@ -71,13 +71,6 @@ static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env) ...@@ -71,13 +71,6 @@ static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
dev->id.device, dev->id.vendor); dev->id.device, dev->id.vendor);
} }
static struct bus_type virtio_bus = {
.name = "virtio",
.match = virtio_dev_match,
.dev_attrs = virtio_dev_attrs,
.uevent = virtio_uevent,
};
static void add_status(struct virtio_device *dev, unsigned status) static void add_status(struct virtio_device *dev, unsigned status)
{ {
dev->config->set_status(dev, dev->config->get_status(dev) | status); dev->config->set_status(dev, dev->config->get_status(dev) | status);
...@@ -120,12 +113,16 @@ static int virtio_dev_probe(struct device *_d) ...@@ -120,12 +113,16 @@ static int virtio_dev_probe(struct device *_d)
set_bit(f, dev->features); set_bit(f, dev->features);
} }
/* Transport features always preserved to pass to finalize_features. */
for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++)
if (device_features & (1 << i))
set_bit(i, dev->features);
err = drv->probe(dev); err = drv->probe(dev);
if (err) if (err)
add_status(dev, VIRTIO_CONFIG_S_FAILED); add_status(dev, VIRTIO_CONFIG_S_FAILED);
else { else {
/* They should never have set feature bits beyond 32 */ dev->config->finalize_features(dev);
dev->config->set_features(dev, dev->features[0]);
add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK); add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
} }
return err; return err;
...@@ -147,13 +144,20 @@ static int virtio_dev_remove(struct device *_d) ...@@ -147,13 +144,20 @@ static int virtio_dev_remove(struct device *_d)
return 0; return 0;
} }
static struct bus_type virtio_bus = {
.name = "virtio",
.match = virtio_dev_match,
.dev_attrs = virtio_dev_attrs,
.uevent = virtio_uevent,
.probe = virtio_dev_probe,
.remove = virtio_dev_remove,
};
int register_virtio_driver(struct virtio_driver *driver) int register_virtio_driver(struct virtio_driver *driver)
{ {
/* Catch this early. */ /* Catch this early. */
BUG_ON(driver->feature_table_size && !driver->feature_table); BUG_ON(driver->feature_table_size && !driver->feature_table);
driver->driver.bus = &virtio_bus; driver->driver.bus = &virtio_bus;
driver->driver.probe = virtio_dev_probe;
driver->driver.remove = virtio_dev_remove;
return driver_register(&driver->driver); return driver_register(&driver->driver);
} }
EXPORT_SYMBOL_GPL(register_virtio_driver); EXPORT_SYMBOL_GPL(register_virtio_driver);
......
...@@ -94,12 +94,17 @@ static u32 vp_get_features(struct virtio_device *vdev) ...@@ -94,12 +94,17 @@ static u32 vp_get_features(struct virtio_device *vdev)
return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES); return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
} }
/* virtio config->set_features() implementation */ /* virtio config->finalize_features() implementation */
static void vp_set_features(struct virtio_device *vdev, u32 features) static void vp_finalize_features(struct virtio_device *vdev)
{ {
struct virtio_pci_device *vp_dev = to_vp_device(vdev); struct virtio_pci_device *vp_dev = to_vp_device(vdev);
iowrite32(features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES); /* Give virtio_ring a chance to accept features. */
vring_transport_features(vdev);
/* We only support 32 feature bits. */
BUILD_BUG_ON(ARRAY_SIZE(vdev->features) != 1);
iowrite32(vdev->features[0], vp_dev->ioaddr+VIRTIO_PCI_GUEST_FEATURES);
} }
/* virtio config->get() implementation */ /* virtio config->get() implementation */
...@@ -297,7 +302,7 @@ static struct virtio_config_ops virtio_pci_config_ops = { ...@@ -297,7 +302,7 @@ static struct virtio_config_ops virtio_pci_config_ops = {
.find_vq = vp_find_vq, .find_vq = vp_find_vq,
.del_vq = vp_del_vq, .del_vq = vp_del_vq,
.get_features = vp_get_features, .get_features = vp_get_features,
.set_features = vp_set_features, .finalize_features = vp_finalize_features,
}; };
/* the PCI probing function */ /* the PCI probing function */
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
*/ */
#include <linux/virtio.h> #include <linux/virtio.h>
#include <linux/virtio_ring.h> #include <linux/virtio_ring.h>
#include <linux/virtio_config.h>
#include <linux/device.h> #include <linux/device.h>
#ifdef DEBUG #ifdef DEBUG
...@@ -87,7 +88,10 @@ static int vring_add_buf(struct virtqueue *_vq, ...@@ -87,7 +88,10 @@ static int vring_add_buf(struct virtqueue *_vq,
if (vq->num_free < out + in) { if (vq->num_free < out + in) {
pr_debug("Can't add buf len %i - avail = %i\n", pr_debug("Can't add buf len %i - avail = %i\n",
out + in, vq->num_free); out + in, vq->num_free);
/* We notify *even if* VRING_USED_F_NO_NOTIFY is set here. */ /* FIXME: for historical reasons, we force a notify here if
* there are outgoing parts to the buffer. Presumably the
* host should service the ring ASAP. */
if (out)
vq->notify(&vq->vq); vq->notify(&vq->vq);
END_USE(vq); END_USE(vq);
return -ENOSPC; return -ENOSPC;
...@@ -320,4 +324,19 @@ void vring_del_virtqueue(struct virtqueue *vq) ...@@ -320,4 +324,19 @@ void vring_del_virtqueue(struct virtqueue *vq)
} }
EXPORT_SYMBOL_GPL(vring_del_virtqueue); EXPORT_SYMBOL_GPL(vring_del_virtqueue);
/* Manipulates transport-specific feature bits. */
void vring_transport_features(struct virtio_device *vdev)
{
unsigned int i;
for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++) {
switch (i) {
default:
/* We don't understand this bit. */
clear_bit(i, vdev->features);
}
}
}
EXPORT_SYMBOL_GPL(vring_transport_features);
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -50,4 +50,14 @@ struct kvm_vqconfig { ...@@ -50,4 +50,14 @@ struct kvm_vqconfig {
#define KVM_S390_VIRTIO_RESET 1 #define KVM_S390_VIRTIO_RESET 1
#define KVM_S390_VIRTIO_SET_STATUS 2 #define KVM_S390_VIRTIO_SET_STATUS 2
#ifdef __KERNEL__
/* early virtio console setup */
#ifdef CONFIG_VIRTIO_CONSOLE
extern void s390_virtio_console_init(void);
#else
static inline void s390_virtio_console_init(void)
{
}
#endif /* CONFIG_VIRTIO_CONSOLE */
#endif /* __KERNEL__ */
#endif #endif
#ifndef _LINUX_VIRTIO_9P_H #ifndef _LINUX_VIRTIO_9P_H
#define _LINUX_VIRTIO_9P_H #define _LINUX_VIRTIO_9P_H
/* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers. */
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
/* The ID for virtio console */ /* The ID for virtio console */
......
#ifndef _LINUX_VIRTIO_BALLOON_H #ifndef _LINUX_VIRTIO_BALLOON_H
#define _LINUX_VIRTIO_BALLOON_H #define _LINUX_VIRTIO_BALLOON_H
/* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers. */
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
/* The ID for virtio_balloon */ /* The ID for virtio_balloon */
......
#ifndef _LINUX_VIRTIO_BLK_H #ifndef _LINUX_VIRTIO_BLK_H
#define _LINUX_VIRTIO_BLK_H #define _LINUX_VIRTIO_BLK_H
/* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers. */
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
/* The ID for virtio_block */ /* The ID for virtio_block */
...@@ -11,6 +13,7 @@ ...@@ -11,6 +13,7 @@
#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */ #define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */
#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */ #define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */
#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */ #define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
struct virtio_blk_config struct virtio_blk_config
{ {
...@@ -26,6 +29,8 @@ struct virtio_blk_config ...@@ -26,6 +29,8 @@ struct virtio_blk_config
__u8 heads; __u8 heads;
__u8 sectors; __u8 sectors;
} geometry; } geometry;
/* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
__u32 blk_size;
} __attribute__((packed)); } __attribute__((packed));
/* These two define direction. */ /* These two define direction. */
......
#ifndef _LINUX_VIRTIO_CONFIG_H #ifndef _LINUX_VIRTIO_CONFIG_H
#define _LINUX_VIRTIO_CONFIG_H #define _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. */
/* Virtio devices use a standardized configuration space to define their /* Virtio devices use a standardized configuration space to define their
* features and pass configuration information, but each implementation can * features and pass configuration information, but each implementation can
* store and access that space differently. */ * store and access that space differently. */
...@@ -15,6 +18,12 @@ ...@@ -15,6 +18,12 @@
/* We've given up on this device. */ /* We've given up on this device. */
#define VIRTIO_CONFIG_S_FAILED 0x80 #define VIRTIO_CONFIG_S_FAILED 0x80
/* Some virtio feature bits (currently bits 28 through 31) are reserved for the
* transport being used (eg. virtio_ring), the rest are per-device feature
* bits. */
#define VIRTIO_TRANSPORT_F_START 28
#define VIRTIO_TRANSPORT_F_END 32
/* Do we get callbacks when the ring is completely used, even if we've /* Do we get callbacks when the ring is completely used, even if we've
* suppressed them? */ * suppressed them? */
#define VIRTIO_F_NOTIFY_ON_EMPTY 24 #define VIRTIO_F_NOTIFY_ON_EMPTY 24
...@@ -52,9 +61,10 @@ ...@@ -52,9 +61,10 @@
* @get_features: get the array of feature bits for this device. * @get_features: get the array of feature bits for this device.
* vdev: the virtio_device * vdev: the virtio_device
* Returns the first 32 feature bits (all we currently need). * Returns the first 32 feature bits (all we currently need).
* @set_features: confirm what device features we'll be using. * @finalize_features: confirm what device features we'll be using.
* vdev: the virtio_device * vdev: the virtio_device
* feature: the first 32 feature bits * This gives the final feature bits for the device: it can change
* the dev->feature bits if it wants.
*/ */
struct virtio_config_ops struct virtio_config_ops
{ {
...@@ -70,7 +80,7 @@ struct virtio_config_ops ...@@ -70,7 +80,7 @@ struct virtio_config_ops
void (*callback)(struct virtqueue *)); void (*callback)(struct virtqueue *));
void (*del_vq)(struct virtqueue *vq); void (*del_vq)(struct virtqueue *vq);
u32 (*get_features)(struct virtio_device *vdev); u32 (*get_features)(struct virtio_device *vdev);
void (*set_features)(struct virtio_device *vdev, u32 features); void (*finalize_features)(struct virtio_device *vdev);
}; };
/* If driver didn't advertise the feature, it will never appear. */ /* If driver didn't advertise the feature, it will never appear. */
......
#ifndef _LINUX_VIRTIO_CONSOLE_H #ifndef _LINUX_VIRTIO_CONSOLE_H
#define _LINUX_VIRTIO_CONSOLE_H #define _LINUX_VIRTIO_CONSOLE_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. */
/* The ID for virtio console */ /* The ID for virtio console */
#define VIRTIO_ID_CONSOLE 3 #define VIRTIO_ID_CONSOLE 3
......
#ifndef _LINUX_VIRTIO_NET_H #ifndef _LINUX_VIRTIO_NET_H
#define _LINUX_VIRTIO_NET_H #define _LINUX_VIRTIO_NET_H
/* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers. */
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
/* The ID for virtio_net */ /* The ID for virtio_net */
......
...@@ -9,9 +9,8 @@ ...@@ -9,9 +9,8 @@
* Authors: * Authors:
* Anthony Liguori <aliguori@us.ibm.com> * Anthony Liguori <aliguori@us.ibm.com>
* *
* This work is licensed under the terms of the GNU GPL, version 2 or later. * This header is BSD licensed so anyone can use the definitions to implement
* See the COPYING file in the top-level directory. * compatible drivers/servers.
*
*/ */
#ifndef _LINUX_VIRTIO_PCI_H #ifndef _LINUX_VIRTIO_PCI_H
......
...@@ -120,6 +120,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int num, ...@@ -120,6 +120,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
void (*notify)(struct virtqueue *vq), void (*notify)(struct virtqueue *vq),
void (*callback)(struct virtqueue *vq)); void (*callback)(struct virtqueue *vq));
void vring_del_virtqueue(struct virtqueue *vq); void vring_del_virtqueue(struct virtqueue *vq);
/* Filter out transport-specific feature bits. */
void vring_transport_features(struct virtio_device *vdev);
irqreturn_t vring_interrupt(int irq, void *_vq); irqreturn_t vring_interrupt(int irq, void *_vq);
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
......
#ifndef _LINUX_VIRTIO_RNG_H #ifndef _LINUX_VIRTIO_RNG_H
#define _LINUX_VIRTIO_RNG_H #define _LINUX_VIRTIO_RNG_H
/* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers. */
#include <linux/virtio_config.h> #include <linux/virtio_config.h>
/* The ID for virtio_rng */ /* The ID for virtio_rng */
......
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