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
This commit is contained in:
Linus Torvalds 2008-07-24 19:11:49 -07:00
commit 832fe9c222
28 changed files with 385 additions and 124 deletions

View file

@ -565,6 +565,7 @@ bool "s390 guest support (EXPERIMENTAL)"
depends on 64BIT && EXPERIMENTAL
select VIRTIO
select VIRTIO_RING
select VIRTIO_CONSOLE
help
Select this option if you want to run the kernel under s390 linux
endmenu

View file

@ -54,6 +54,7 @@
#include <asm/sections.h>
#include <asm/ebcdic.h>
#include <asm/compat.h>
#include <asm/kvm_virtio.h>
long psw_kernel_bits = (PSW_BASE_BITS | PSW_MASK_DAT | PSW_ASC_PRIMARY |
PSW_MASK_MCHECK | PSW_DEFAULT_KEY);
@ -766,7 +767,8 @@ setup_arch(char **cmdline_p)
printk("We are running under VM (64 bit mode)\n");
else if (MACHINE_IS_KVM) {
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
printk("We are running native (64 bit mode)\n");
#endif /* CONFIG_64BIT */

View file

@ -196,6 +196,7 @@ static int virtblk_probe(struct virtio_device *vdev)
int err;
u64 cap;
u32 v;
u32 blk_size;
if (index_to_minor(index) >= 1 << MINORBITS)
return -ENOSPC;
@ -290,6 +291,13 @@ static int virtblk_probe(struct virtio_device *vdev)
if (!err)
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);
return 0;
@ -330,7 +338,7 @@ static struct virtio_device_id id_table[] = {
static unsigned int features[] = {
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 = {

View file

@ -578,11 +578,14 @@ config HVC_DRIVER
It will automatically be selected if one of the back-end console drivers
is selected.
config HVC_IRQ
bool
config HVC_CONSOLE
bool "pSeries Hypervisor Virtual Console support"
depends on PPC_PSERIES
select HVC_DRIVER
select HVC_IRQ
help
pSeries machines when partitioned support a hypervisor virtual
console. This driver allows each pSeries partition to have a console
@ -593,6 +596,7 @@ config HVC_ISERIES
depends on PPC_ISERIES
default y
select HVC_DRIVER
select HVC_IRQ
help
iSeries machines support a hypervisor virtual console.
@ -614,13 +618,18 @@ config HVC_XEN
bool "Xen Hypervisor Console support"
depends on XEN
select HVC_DRIVER
select HVC_IRQ
default y
help
Xen virtual console device driver
config VIRTIO_CONSOLE
bool
tristate "Virtio console"
depends on VIRTIO
select HVC_DRIVER
help
Virtio console for use with lguest and other hypervisors.
config HVCS
tristate "IBM Hypervisor Virtual Console Server support"

View file

@ -48,6 +48,7 @@ obj-$(CONFIG_HVC_ISERIES) += hvc_iseries.o
obj-$(CONFIG_HVC_RTAS) += hvc_rtas.o
obj-$(CONFIG_HVC_BEAT) += hvc_beat.o
obj-$(CONFIG_HVC_DRIVER) += hvc_console.o
obj-$(CONFIG_HVC_IRQ) += hvc_irq.o
obj-$(CONFIG_HVC_XEN) += hvc_xen.o
obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o
obj-$(CONFIG_RAW_DRIVER) += raw.o

View file

@ -27,7 +27,6 @@
#include <linux/init.h>
#include <linux/kbd_kern.h>
#include <linux/kernel.h>
#include <linux/kref.h>
#include <linux/kthread.h>
#include <linux/list.h>
#include <linux/module.h>
@ -75,23 +74,6 @@ static int hvc_init(void);
static int sysrq_pressed;
#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 */
static LIST_HEAD(hvc_structs);
@ -298,27 +280,15 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops)
return 0;
}
EXPORT_SYMBOL_GPL(hvc_instantiate);
/* Wake the sleeping khvcd */
static void hvc_kick(void)
void hvc_kick(void)
{
hvc_kicked = 1;
wake_up_process(hvc_task);
}
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;
}
EXPORT_SYMBOL_GPL(hvc_kick);
static void hvc_unthrottle(struct tty_struct *tty)
{
@ -333,7 +303,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
{
struct hvc_struct *hp;
unsigned long flags;
int irq = 0;
int rc = 0;
/* Auto increments kref reference if found. */
@ -352,18 +321,15 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
tty->low_latency = 1; /* Makes flushes to ldisc synchronous. */
hp->tty = tty;
/* Save for request_irq outside of spin_lock. */
irq = hp->irq;
if (irq)
hp->irq_requested = 1;
if (hp->ops->notifier_add)
rc = hp->ops->notifier_add(hp, hp->data);
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
* up there so we'll clean up here and clear out the previously set
* tty fields and return the kref reference.
@ -371,7 +337,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp)
if (rc) {
spin_lock_irqsave(&hp->lock, flags);
hp->tty = NULL;
hp->irq_requested = 0;
spin_unlock_irqrestore(&hp->lock, flags);
tty->driver_data = NULL;
kref_put(&hp->kref, destroy_hvc_struct);
@ -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)
{
struct hvc_struct *hp;
int irq = 0;
unsigned long flags;
if (tty_hung_up_p(filp))
@ -404,9 +368,8 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
spin_lock_irqsave(&hp->lock, flags);
if (--hp->count == 0) {
if (hp->irq_requested)
irq = hp->irq;
hp->irq_requested = 0;
if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data);
/* We are done with the tty pointer now. */
hp->tty = NULL;
@ -418,10 +381,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp)
* waking periodically to check chars_in_buffer().
*/
tty_wait_until_sent(tty, HVC_CLOSE_WAIT);
if (irq)
free_irq(irq, hp);
} else {
if (hp->count < 0)
printk(KERN_ERR "hvc_close %X: oops, count is %d\n",
@ -436,7 +395,6 @@ static void hvc_hangup(struct tty_struct *tty)
{
struct hvc_struct *hp = tty->driver_data;
unsigned long flags;
int irq = 0;
int temp_open_count;
if (!hp)
@ -458,13 +416,12 @@ static void hvc_hangup(struct tty_struct *tty)
hp->count = 0;
hp->n_outbuf = 0;
hp->tty = NULL;
if (hp->irq_requested)
/* Saved for use outside of spin_lock. */
irq = hp->irq;
hp->irq_requested = 0;
if (hp->ops->notifier_del)
hp->ops->notifier_del(hp, hp->data);
spin_unlock_irqrestore(&hp->lock, flags);
if (irq)
free_irq(irq, hp);
while(temp_open_count) {
--temp_open_count;
kref_put(&hp->kref, destroy_hvc_struct);
@ -575,7 +532,7 @@ static u32 timeout = MIN_TIMEOUT;
#define HVC_POLL_READ 0x00000001
#define HVC_POLL_WRITE 0x00000002
static int hvc_poll(struct hvc_struct *hp)
int hvc_poll(struct hvc_struct *hp)
{
struct tty_struct *tty;
int i, n, poll_mask = 0;
@ -602,10 +559,10 @@ static int hvc_poll(struct hvc_struct *hp)
if (test_bit(TTY_THROTTLED, &tty->flags))
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
*/
if (hp->irq == 0)
if (!hp->irq_requested)
poll_mask |= HVC_POLL_READ;
/* Read data if any */
@ -674,6 +631,7 @@ static int hvc_poll(struct hvc_struct *hp)
return poll_mask;
}
EXPORT_SYMBOL_GPL(hvc_poll);
/*
* This kthread is either polling or interrupt driven. This is determined by
@ -733,7 +691,7 @@ static const struct tty_operations hvc_ops = {
.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 hvc_struct *hp;
@ -754,7 +712,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
memset(hp, 0x00, sizeof(*hp));
hp->vtermno = vtermno;
hp->irq = irq;
hp->data = data;
hp->ops = ops;
hp->outbuf_size = outbuf_size;
hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))];
@ -784,6 +742,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq,
return hp;
}
EXPORT_SYMBOL_GPL(hvc_alloc);
int __devexit hvc_remove(struct hvc_struct *hp)
{

View file

@ -26,6 +26,7 @@
#ifndef 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
@ -42,24 +43,50 @@
*/
#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 */
struct hv_ops {
int (*get_chars)(uint32_t vtermno, 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) */
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) */
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);
/* 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);
/* 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)
#include <asm/xmon.h>

44
drivers/char/hvc_irq.c Normal file
View file

@ -0,0 +1,44 @@
/*
* 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;
}

View file

@ -200,6 +200,8 @@ static int put_chars(uint32_t vtermno, const char *buf, int count)
static struct hv_ops hvc_get_put_ops = {
.get_chars = get_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,

View file

@ -80,6 +80,8 @@ static int filtered_get_chars(uint32_t vtermno, char *buf, int count)
static struct hv_ops hvc_get_put_ops = {
.get_chars = filtered_get_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,

View file

@ -100,6 +100,8 @@ static int read_console(uint32_t vtermno, char *buf, int len)
static struct hv_ops hvc_ops = {
.get_chars = read_console,
.put_chars = write_console,
.notifier_add = notifier_add_irq,
.notifier_del = notifier_del_irq,
};
static int __init xen_init(void)

View file

@ -46,6 +46,9 @@ static char *in, *inbuf;
/* The operations for our console. */
static struct hv_ops virtio_cons;
/* The hvc device */
static struct hvc_struct *hvc;
/*D:310 The put_chars() callback is pretty straightforward.
*
* 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))
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.
* 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))
static int __devinit virtcons_probe(struct virtio_device *dev)
{
int err;
struct hvc_struct *hvc;
vdev = dev;
@ -158,7 +181,7 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
/* Find the input queue. */
/* FIXME: This is why we want to wean off hvc: we do nothing
* 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)) {
err = PTR_ERR(in_vq);
goto free;
@ -173,15 +196,18 @@ static int __devinit virtcons_probe(struct virtio_device *dev)
/* Start using the new console output. */
virtio_cons.get_chars = get_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
* we use zero. The second argument is the interrupt number; we
* currently leave this as zero: it would be better not to use the
* hvc mechanism and fix this (FIXME!).
* we use zero. The second argument is the parameter for the
* notification mechanism (like irq number). We currently leave this
* as zero, virtqueues have implicit notifications.
*
* The third argument is a "struct hv_ops" containing the put_chars()
* and get_chars() pointers. The final argument is the output buffer
* size: we can do any size, so we put PAGE_SIZE here. */
* get_chars(), notifier_add() and notifier_del() pointers.
* 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);
if (IS_ERR(hvc)) {
err = PTR_ERR(hvc);

View file

@ -98,16 +98,20 @@ static u32 lg_get_features(struct virtio_device *vdev)
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;
/* Second half of bitmap is features we accept. */
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);
for (i = 0; i < min(desc->feature_len * 8, 32); i++) {
if (features & (1 << i))
bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
for (i = 0; i < bits; i++) {
if (test_bit(i, vdev->features))
out_features[i / 8] |= (1 << (i % 8));
}
}
@ -297,7 +301,7 @@ static void lg_del_vq(struct virtqueue *vq)
/* The ops structure which hooks everything together. */
static struct virtio_config_ops lguest_config_ops = {
.get_features = lg_get_features,
.set_features = lg_set_features,
.finalize_features = lg_finalize_features,
.get = lg_get,
.set = lg_set,
.get_status = lg_get_status,

View file

@ -19,6 +19,7 @@
//#define DEBUG
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/ethtool.h>
#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/virtio_net.h>
@ -54,9 +55,15 @@ struct virtnet_info
struct tasklet_struct tasklet;
bool free_in_tasklet;
/* I like... big packets and I cannot lie! */
bool big_packets;
/* Receive & send queues. */
struct sk_buff_head recv;
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)
@ -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));
}
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)
{
struct virtnet_info *vi = svq->vdev->priv;
@ -88,6 +112,7 @@ static void receive_skb(struct net_device *dev, struct sk_buff *skb,
unsigned len)
{
struct virtio_net_hdr *hdr = skb_vnet_hdr(skb);
int err;
if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
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,
goto drop;
}
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_packets++;
@ -160,7 +198,7 @@ static void try_fill_recv(struct virtnet_info *vi)
{
struct sk_buff *skb;
struct scatterlist sg[2+MAX_SKB_FRAGS];
int num, err;
int num, err, i;
sg_init_table(sg, 2+MAX_SKB_FRAGS);
for (;;) {
@ -170,6 +208,24 @@ static void try_fill_recv(struct virtnet_info *vi)
skb_put(skb, MAX_PACKET_LEN);
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;
skb_queue_head(&vi->recv, skb);
@ -335,16 +391,11 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
free_old_xmit_skbs(vi);
/* If we has a buffer left over from last time, send it now. */
if (unlikely(vi->last_xmit_skb)) {
if (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;
}
vi->last_xmit_skb = NULL;
}
if (unlikely(vi->last_xmit_skb) &&
xmit_skb(vi, vi->last_xmit_skb) != 0)
goto stop_queue;
vi->last_xmit_skb = NULL;
/* Put new one in send queue and do transmit */
if (likely(skb)) {
@ -370,6 +421,11 @@ static int start_xmit(struct sk_buff *skb, struct net_device *dev)
netif_start_queue(dev);
goto again;
}
if (skb) {
/* Drop this skb: we only queue one. */
vi->dev->stats.tx_dropped++;
kfree_skb(skb);
}
goto done;
}
@ -408,6 +464,22 @@ static int virtnet_close(struct net_device *dev)
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)
{
int err;
@ -427,6 +499,7 @@ static int virtnet_probe(struct virtio_device *vdev)
#ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = virtnet_netpoll;
#endif
SET_ETHTOOL_OPS(dev, &virtnet_ethtool_ops);
SET_NETDEV_DEV(dev, &vdev->dev);
/* Do we support "hardware" checksums? */
@ -462,11 +535,18 @@ static int virtnet_probe(struct virtio_device *vdev)
vi->dev = dev;
vi->vdev = vdev;
vdev->priv = vi;
vi->pages = NULL;
/* If they give us a callback when all buffers are done, we don't need
* the timer. */
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. */
vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done);
if (IS_ERR(vi->rvq)) {
@ -541,6 +621,10 @@ static void virtnet_remove(struct virtio_device *vdev)
vdev->config->del_vq(vi->svq);
vdev->config->del_vq(vi->rvq);
unregister_netdev(vi->dev);
while (vi->pages)
__free_pages(get_a_page(vi, GFP_KERNEL), 0);
free_netdev(vi->dev);
}
@ -553,7 +637,9 @@ static unsigned int features[] = {
VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM,
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_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 = {

View file

@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/virtio.h>
#include <linux/virtio_config.h>
#include <linux/virtio_console.h>
#include <linux/interrupt.h>
#include <linux/virtio_ring.h>
#include <linux/pfn.h>
@ -87,16 +88,20 @@ static u32 kvm_get_features(struct virtio_device *vdev)
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;
/* Second half of bitmap is features we accept. */
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);
for (i = 0; i < min(desc->feature_len * 8, 32); i++) {
if (features & (1 << i))
bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
for (i = 0; i < bits; i++) {
if (test_bit(i, vdev->features))
out_features[i / 8] |= (1 << (i % 8));
}
}
@ -222,7 +227,7 @@ static void kvm_del_vq(struct virtqueue *vq)
*/
static struct virtio_config_ops kvm_vq_configspace_ops = {
.get_features = kvm_get_features,
.set_features = kvm_set_features,
.finalize_features = kvm_finalize_features,
.get = kvm_get,
.set = kvm_set,
.get_status = kvm_get_status,
@ -333,6 +338,25 @@ static int __init kvm_devices_init(void)
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.
*/

View file

@ -71,13 +71,6 @@ static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
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)
{
dev->config->set_status(dev, dev->config->get_status(dev) | status);
@ -120,12 +113,16 @@ static int virtio_dev_probe(struct device *_d)
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);
if (err)
add_status(dev, VIRTIO_CONFIG_S_FAILED);
else {
/* They should never have set feature bits beyond 32 */
dev->config->set_features(dev, dev->features[0]);
dev->config->finalize_features(dev);
add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
}
return err;
@ -147,13 +144,20 @@ static int virtio_dev_remove(struct device *_d)
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)
{
/* Catch this early. */
BUG_ON(driver->feature_table_size && !driver->feature_table);
driver->driver.bus = &virtio_bus;
driver->driver.probe = virtio_dev_probe;
driver->driver.remove = virtio_dev_remove;
return driver_register(&driver->driver);
}
EXPORT_SYMBOL_GPL(register_virtio_driver);

View file

@ -94,12 +94,17 @@ static u32 vp_get_features(struct virtio_device *vdev)
return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
}
/* virtio config->set_features() implementation */
static void vp_set_features(struct virtio_device *vdev, u32 features)
/* virtio config->finalize_features() implementation */
static void vp_finalize_features(struct virtio_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 */
@ -297,7 +302,7 @@ static struct virtio_config_ops virtio_pci_config_ops = {
.find_vq = vp_find_vq,
.del_vq = vp_del_vq,
.get_features = vp_get_features,
.set_features = vp_set_features,
.finalize_features = vp_finalize_features,
};
/* the PCI probing function */

View file

@ -18,6 +18,7 @@
*/
#include <linux/virtio.h>
#include <linux/virtio_ring.h>
#include <linux/virtio_config.h>
#include <linux/device.h>
#ifdef DEBUG
@ -87,8 +88,11 @@ static int vring_add_buf(struct virtqueue *_vq,
if (vq->num_free < out + in) {
pr_debug("Can't add buf len %i - avail = %i\n",
out + in, vq->num_free);
/* We notify *even if* VRING_USED_F_NO_NOTIFY is set here. */
vq->notify(&vq->vq);
/* 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);
END_USE(vq);
return -ENOSPC;
}
@ -320,4 +324,19 @@ void vring_del_virtqueue(struct virtqueue *vq)
}
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");

View file

@ -50,4 +50,14 @@ struct kvm_vqconfig {
#define KVM_S390_VIRTIO_RESET 1
#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

View file

@ -1,5 +1,7 @@
#ifndef _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>
/* The ID for virtio console */

View file

@ -1,5 +1,7 @@
#ifndef _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>
/* The ID for virtio_balloon */

View file

@ -1,5 +1,7 @@
#ifndef _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>
/* The ID for virtio_block */
@ -11,6 +13,7 @@
#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */
#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */
#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
{
@ -26,6 +29,8 @@ struct virtio_blk_config
__u8 heads;
__u8 sectors;
} geometry;
/* block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
__u32 blk_size;
} __attribute__((packed));
/* These two define direction. */

View file

@ -1,5 +1,8 @@
#ifndef _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
* features and pass configuration information, but each implementation can
* store and access that space differently. */
@ -15,6 +18,12 @@
/* We've given up on this device. */
#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
* suppressed them? */
#define VIRTIO_F_NOTIFY_ON_EMPTY 24
@ -52,9 +61,10 @@
* @get_features: get the array of feature bits for this device.
* vdev: the virtio_device
* 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
* 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
{
@ -70,7 +80,7 @@ struct virtio_config_ops
void (*callback)(struct virtqueue *));
void (*del_vq)(struct virtqueue *vq);
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. */

View file

@ -1,6 +1,8 @@
#ifndef _LINUX_VIRTIO_CONSOLE_H
#define _LINUX_VIRTIO_CONSOLE_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 */
#define VIRTIO_ID_CONSOLE 3

View file

@ -1,5 +1,7 @@
#ifndef _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>
/* The ID for virtio_net */

View file

@ -9,9 +9,8 @@
* Authors:
* Anthony Liguori <aliguori@us.ibm.com>
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*
* This header is BSD licensed so anyone can use the definitions to implement
* compatible drivers/servers.
*/
#ifndef _LINUX_VIRTIO_PCI_H

View file

@ -120,6 +120,8 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
void (*notify)(struct virtqueue *vq),
void (*callback)(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);
#endif /* __KERNEL__ */

View file

@ -1,5 +1,7 @@
#ifndef _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>
/* The ID for virtio_rng */