Backport of the virtio drivers to RHEL4.
The patch applies against the kvm-guest-drivers-linux-1 release but also
contains diffs for Anthony's spin_lock_irqsave/restore patch. Of note is
that to build for RHEL4 Makefile is renamed to Makefile-2.6 so that Makefile
can contain the build rules for the modules. RHEL4 (AFAIK) does not contain
the Kbuild stuff. The make command is then make -f Makefile-2.6
david
diff -r -U 10 -N kvm-guest-drivers-linux-1.orig/external-module-compat.h kvm-guest-drivers-linux-1/external-module-compat.h
--- kvm-guest-drivers-linux-1.orig/external-module-compat.h 2008-03-06 01:08:36.000000000 -0700
+++ kvm-guest-drivers-linux-1/external-module-compat.h 2008-03-19 22:28:41.000000000 -0600
@@ -6,42 +6,59 @@
#include <linux/types.h>
#include <linux/scatterlist.h>
#include <linux/blkdev.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#ifndef CONFIG_HIGH_RES_TIMERS
#define COMPAT_cb_softirq
#endif
+#define COMPAT_csum_offset
+
+#define COMPAT_RHEL4
+
+#ifdef COMPAT_RHEL4
+#define IRQF_SHARED SA_SHIRQ
+#define pm_message_t u32
+#define COMPAT_csum
+#define COMPAT_gso
+#define COMPAT_uevent_env
+#endif
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
struct virtio_device_id {
__u32 device;
__u32 vendor;
};
#define VIRTIO_DEV_ANY_ID 0xffffffff
#define COMPAT_kobject_uevent_env
#define sg_page(sg) ((sg)->page)
static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents)
{
memset(sgl, 0, sizeof(*sgl) * nents);
}
static inline void end_dequeued_request(struct request *rq, int uptodate)
{
+#ifdef COMPAT_RHEL4
+ if (!end_that_request_first(rq, uptodate, rq->hard_nr_sectors))
+ end_that_request_last(rq);
+#else
if (!end_that_request_first(rq, uptodate, rq->hard_nr_sectors))
end_that_request_last(rq, uptodate);
+#endif
}
#define DECLARE_MAC_BUF(var) char var[18] __maybe_unused
#define MAC_FMT "%02x:%02x:%02x:%02x:%02x:%02x"
static inline char *print_mac(char *buf, const u8 *addr)
{
sprintf(buf, MAC_FMT,
addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
@@ -56,22 +73,20 @@
#define napi_enable(napi) netif_poll_enable(dev)
#define napi_disable(napi) netif_poll_disable(dev)
#define netif_napi_add(dev, napi, pollfn, weightval) \
do { \
(dev)->poll = (pollfn); \
(dev)->weight = 16; \
} while(0)
#define netif_rx_schedule(dev, napi) netif_rx_schedule(dev)
-#define COMPAT_csum_offset
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
#define scsi_cmd_ioctl(filp, rq, gendisk, cmd, data) \
scsi_cmd_ioctl(filp, gendisk, cmd, data)
#define task_pid_nr(current) (0)
#define __mandatory_lock(ino) (0)
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
@@ -128,21 +143,23 @@
#endif
#endif
#include "include/linux/virtio.h"
#include "include/linux/virtio_ring.h"
#include "include/linux/virtio_config.h"
#include "include/linux/virtio_pci.h"
#include "include/linux/virtio_net.h"
#include "include/linux/virtio_blk.h"
+#ifndef COMPAT_RHEL4
#include <linux/pci_regs.h>
+#endif
#include <linux/pci.h>
static inline u8 pci_dev_revision(struct pci_dev *dev)
{
u32 class;
pci_read_config_dword(dev, PCI_CLASS_REVISION, &class);
return class & 0xff;
}
diff -r -U 10 -N kvm-guest-drivers-linux-1.orig/include/linux/virtio_ring.h kvm-guest-drivers-linux-1/include/linux/virtio_ring.h
--- kvm-guest-drivers-linux-1.orig/include/linux/virtio_ring.h 2008-03-05 19:00:22.000000000 -0700
+++ kvm-guest-drivers-linux-1/include/linux/virtio_ring.h 2008-03-19 22:28:41.000000000 -0600
@@ -103,21 +103,23 @@
}
static inline unsigned vring_size(unsigned int num, unsigned long pagesize)
{
return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
+ pagesize - 1) & ~(pagesize - 1))
+ sizeof(__u16) * 2 + sizeof(struct vring_used_elem) * num;
}
#ifdef __KERNEL__
+#if 0
#include <linux/irqreturn.h>
+#endif
struct virtio_device;
struct virtqueue;
struct virtqueue *vring_new_virtqueue(unsigned int num,
struct virtio_device *vdev,
void *pages,
void (*notify)(struct virtqueue *vq),
void (*callback)(struct virtqueue *vq));
void vring_del_virtqueue(struct virtqueue *vq);
diff -r -U 10 -N kvm-guest-drivers-linux-1.orig/Makefile kvm-guest-drivers-linux-1/Makefile
--- kvm-guest-drivers-linux-1.orig/Makefile 2008-03-06 01:08:36.000000000 -0700
+++ kvm-guest-drivers-linux-1/Makefile 2008-03-19 22:28:41.000000000 -0600
@@ -1,47 +1,8 @@
-KERNELDIR = /lib/modules/$(shell uname -r)/build
-KVERREL = $(patsubst /lib/modules/%/build,%,$(KERNELDIR))
+EXTRA_CFLAGS := -I$(src)/include -include $(src)/external-module-compat.h
-DESTDIR=
-
-INSTALLDIR = $(patsubst %/build,%/extra,$(KERNELDIR))
-ORIGMODDIR = $(patsubst %/build,%/kernel,$(KERNELDIR))
-
-LINUX = ../linux-2.6
-
-KVER = $(shell uname -r)
-KERNELDIR = /lib/modules/$(KVER)/build
-LINUX = ../linux-2.6
-
-hack = mv $1 $1.orig && \
- awk -f hack-module.awk $1.orig > $1 && rm $1.orig
-
-all::
- $(MAKE) -C $(KERNELDIR) M=`pwd` "$$@"
-
-sync:
- mkdir -p include/linux
- cp -a "$(LINUX)"/drivers/virtio/*.[ch] .
- cp -a "$(LINUX)"/include/linux/virtio*.h include/linux/
- cp -a "$(LINUX)"/drivers/block/virtio_blk.c .
- cp -a "$(LINUX)"/drivers/net/virtio_net.c .
- $(call hack, virtio.c)
- $(call hack, virtio_pci.c)
- $(call hack, virtio_net.c)
-
-install:
- mkdir -p $(DESTDIR)/$(INSTALLDIR)
- cp *.ko $(DESTDIR)/$(INSTALLDIR)
- for i in $(ORIGMODDIR)/drivers/virtio/*.ko \
- $(ORIGMODDIR)/drivers/net/virtio_net.ko \
- $(ORIGMODDIR)/drivers/block/virtio_blk.ko; do \
- if [ -f "$$i" ]; then mv "$$i" "$$i.orig"; fi; \
- done
- /sbin/depmod -a
-
-clean:
- $(MAKE) -C $(KERNELDIR) M=`pwd` $@
- rm -f Module.symvers
-
-realclean: clean
- $(RM) -r *.c include/ *~
+obj-m += virtio.o
+obj-m += virtio_pci.o
+obj-m += virtio_ring.o
+obj-m += virtio_net.o
+obj-m += virtio_blk.o
diff -r -U 10 -N kvm-guest-drivers-linux-1.orig/Makefile-2.6 kvm-guest-drivers-linux-1/Makefile-2.6
--- kvm-guest-drivers-linux-1.orig/Makefile-2.6 1969-12-31 17:00:00.000000000 -0700
+++ kvm-guest-drivers-linux-1/Makefile-2.6 2008-03-19 23:22:19.000000000 -0600
@@ -0,0 +1,47 @@
+KERNELDIR = /lib/modules/$(shell uname -r)/build
+KVERREL = $(patsubst /lib/modules/%/build,%,$(KERNELDIR))
+
+DESTDIR=
+
+INSTALLDIR = $(patsubst %/build,%/extra,$(KERNELDIR))
+ORIGMODDIR = $(patsubst %/build,%/kernel,$(KERNELDIR))
+
+LINUX = ../linux-2.6
+
+KVER = $(shell uname -r)
+KERNELDIR = /lib/modules/$(KVER)/build
+LINUX = ../linux-2.6
+
+hack = mv $1 $1.orig && \
+ awk -f hack-module.awk $1.orig > $1 && rm $1.orig
+
+all::
+ $(MAKE) -C $(KERNELDIR) M=`pwd` "$$@"
+
+sync:
+ mkdir -p include/linux
+ cp -a "$(LINUX)"/drivers/virtio/*.[ch] .
+ cp -a "$(LINUX)"/include/linux/virtio*.h include/linux/
+ cp -a "$(LINUX)"/drivers/block/virtio_blk.c .
+ cp -a "$(LINUX)"/drivers/net/virtio_net.c .
+ $(call hack, virtio.c)
+ $(call hack, virtio_pci.c)
+ $(call hack, virtio_net.c)
+
+install:
+ mkdir -p $(DESTDIR)/$(INSTALLDIR)
+ cp *.ko $(DESTDIR)/$(INSTALLDIR)
+ for i in $(ORIGMODDIR)/drivers/virtio/*.ko \
+ $(ORIGMODDIR)/drivers/net/virtio_net.ko \
+ $(ORIGMODDIR)/drivers/block/virtio_blk.ko; do \
+ if [ -f "$$i" ]; then mv "$$i" "$$i.orig"; fi; \
+ done
+ /sbin/depmod -a
+
+clean:
+ $(MAKE) -C $(KERNELDIR) M=`pwd` $@
+ rm -f Module.symvers
+
+realclean: clean
+ $(RM) -r *.c include/ *~
+
diff -r -U 10 -N kvm-guest-drivers-linux-1.orig/virtio_blk.c kvm-guest-drivers-linux-1/virtio_blk.c
--- kvm-guest-drivers-linux-1.orig/virtio_blk.c 2008-03-05 19:00:22.000000000 -0700
+++ kvm-guest-drivers-linux-1/virtio_blk.c 2008-03-19 22:28:41.000000000 -0600
@@ -31,20 +31,25 @@
};
struct virtblk_req
{
struct list_head list;
struct request *req;
struct virtio_blk_outhdr out_hdr;
struct virtio_blk_inhdr in_hdr;
};
+#ifdef COMPAT_RHEL4
+static kmem_cache_t *vblk_cachep;
+#endif
+
+
static void blk_done(struct virtqueue *vq)
{
struct virtio_blk *vblk = vq->vdev->priv;
struct virtblk_req *vbr;
unsigned int len;
unsigned long flags;
spin_lock_irqsave(&vblk->lock, flags);
while ((vbr = vblk->vq->vq_ops->get_buf(vblk->vq, &len)) != NULL) {
int uptodate;
@@ -77,25 +82,29 @@
vbr = mempool_alloc(vblk->pool, GFP_ATOMIC);
if (!vbr)
/* When another request finishes we'll try again. */
return false;
vbr->req = req;
if (blk_fs_request(vbr->req)) {
vbr->out_hdr.type = 0;
vbr->out_hdr.sector = vbr->req->sector;
+#ifndef COMPAT_RHEL4
vbr->out_hdr.ioprio = vbr->req->ioprio;
+#endif
} else if (blk_pc_request(vbr->req)) {
vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
vbr->out_hdr.sector = 0;
+#ifndef COMPAT_RHEL4
vbr->out_hdr.ioprio = vbr->req->ioprio;
+#endif
} else {
/* We don't put anything else in the queue. */
BUG();
}
if (blk_barrier_rq(vbr->req))
vbr->out_hdr.type |= VIRTIO_BLK_T_BARRIER;
/* This init could be done at vblk creation time */
sg_init_table(vblk->sg, VIRTIO_MAX_SG);
@@ -131,63 +140,72 @@
while ((req = elv_next_request(q)) != NULL) {
vblk = req->rq_disk->private_data;
BUG_ON(req->nr_phys_segments > ARRAY_SIZE(vblk->sg));
/* If this request fails, stop queue and wait for something to
finish to restart it. */
if (!do_req(q, vblk, req)) {
blk_stop_queue(q);
break;
}
+
blkdev_dequeue_request(req);
+
issued++;
}
if (issued)
vblk->vq->vq_ops->kick(vblk->vq);
}
static int virtblk_ioctl(struct inode *inode, struct file *filp,
unsigned cmd, unsigned long data)
{
return scsi_cmd_ioctl(filp, inode->i_bdev->bd_disk->queue,
inode->i_bdev->bd_disk, cmd,
(void __user *)data);
}
+#ifndef COMPAT_RHEL4
/* We provide getgeo only to please some old bootloader/partitioning tools */
static int virtblk_getgeo(struct block_device *bd, struct hd_geometry *geo)
{
/* some standard values, similar to sd */
geo->heads = 1 << 6;
geo->sectors = 1 << 5;
geo->cylinders = get_capacity(bd->bd_disk) >> 11;
return 0;
}
+#endif
static struct block_device_operations virtblk_fops = {
.ioctl = virtblk_ioctl,
.owner = THIS_MODULE,
+#ifndef COMPAT_RHEL4
.getgeo = virtblk_getgeo,
+#endif
};
static int index_to_minor(int index)
{
return index << PART_BITS;
}
static int virtblk_probe(struct virtio_device *vdev)
{
struct virtio_blk *vblk;
int err;
u64 cap;
u32 v;
+#ifdef COMPAT_RHEL4
+ int cache_created = 0;
+#endif
if (index_to_minor(index) >= 1 << MINORBITS)
return -ENOSPC;
vdev->priv = vblk = kmalloc(sizeof(*vblk), GFP_KERNEL);
if (!vblk) {
err = -ENOMEM;
goto out;
}
@@ -195,21 +213,41 @@
spin_lock_init(&vblk->lock);
vblk->vdev = vdev;
/* We expect one virtqueue, for output. */
vblk->vq = vdev->config->find_vq(vdev, 0, blk_done);
if (IS_ERR(vblk->vq)) {
err = PTR_ERR(vblk->vq);
goto out_free_vblk;
}
+#ifdef COMPAT_RHEL4
+ if (!vblk_cachep) {
+ vblk_cachep = kmem_cache_create("virtio_blk",
+ sizeof(struct virtblk_req),
+ 0, SLAB_HWCACHE_ALIGN,
+ NULL, NULL);
+ cache_created = 1;
+ }
+
+ if (vblk_cachep == NULL) {
+ err = -ENOMEM;
+ goto out_free_vblk;
+ }
+
+ vblk->pool = mempool_create(1,
+ mempool_alloc_slab,
+ mempool_free_slab,
+ vblk_cachep);
+#else
vblk->pool = mempool_create_kmalloc_pool(1,sizeof(struct virtblk_req));
+#endif
if (!vblk->pool) {
err = -ENOMEM;
goto out_free_vq;
}
/* FIXME: How many partitions? How long is a piece of string? */
vblk->disk = alloc_disk(1 << PART_BITS);
if (!vblk->disk) {
err = -ENOMEM;
goto out_mempool;
@@ -234,22 +272,27 @@
'a' + m1, 'a' + m2, 'a' + m3);
}
vblk->disk->major = major;
vblk->disk->first_minor = index_to_minor(index);
vblk->disk->private_data = vblk;
vblk->disk->fops = &virtblk_fops;
index++;
/* If barriers are supported, tell block layer that queue is ordered */
- if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER))
+ if (vdev->config->feature(vdev, VIRTIO_BLK_F_BARRIER)) {
+#ifdef COMPAT_RHEL4
+ blk_queue_ordered(vblk->disk->queue, 1);
+#else
blk_queue_ordered(vblk->disk->queue, QUEUE_ORDERED_TAG, NULL);
+#endif
+ }
/* Host must always specify the capacity. */
__virtio_config_val(vdev, offsetof(struct virtio_blk_config, capacity),
&cap);
/* If capacity is too big, truncate with warning. */
if ((sector_t)cap != cap) {
dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n",
(unsigned long long)cap);
cap = (sector_t)-1;
@@ -271,20 +314,24 @@
blk_queue_max_hw_segments(vblk->disk->queue, v);
add_disk(vblk->disk);
return 0;
out_put_disk:
put_disk(vblk->disk);
out_mempool:
mempool_destroy(vblk->pool);
out_free_vq:
+#ifdef COMPAT_RHEL4
+ if (cache_created && kmem_cache_destroy(vblk_cachep))
+ printk(KERN_ERR "virtblk_probe: kmem_cache_destroy failed\n");
+#endif
vdev->config->del_vq(vblk->vq);
out_free_vblk:
kfree(vblk);
out:
return err;
}
static void virtblk_remove(struct virtio_device *vdev)
{
struct virtio_blk *vblk = vdev->priv;
@@ -293,32 +340,42 @@
/* Nothing should be pending. */
BUG_ON(!list_empty(&vblk->reqs));
/* Stop all the virtqueues. */
vdev->config->reset(vdev);
blk_cleanup_queue(vblk->disk->queue);
put_disk(vblk->disk);
unregister_blkdev(major, "virtblk");
mempool_destroy(vblk->pool);
+
+#ifdef COMPAT_RHEL4
+ if (vblk_cachep && kmem_cache_destroy(vblk_cachep))
+ printk(KERN_ERR "virtblk_remove: kmem_cache_destroy failed\n");
+#endif
+
vdev->config->del_vq(vblk->vq);
kfree(vblk);
}
static struct virtio_device_id id_table[] = {
{ VIRTIO_ID_BLOCK, VIRTIO_DEV_ANY_ID },
{ 0 },
};
static struct virtio_driver virtio_blk = {
+#ifdef COMPAT_RHEL4
+ .driver.name = "virtio_blk",
+#else
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
+#endif
.id_table = id_table,
.probe = virtblk_probe,
.remove = __devexit_p(virtblk_remove),
};
static int __init init(void)
{
major = register_blkdev(0, "virtblk");
if (major < 0)
return major;
diff -r -U 10 -N kvm-guest-drivers-linux-1.orig/virtio.c kvm-guest-drivers-linux-1/virtio.c
--- kvm-guest-drivers-linux-1.orig/virtio.c 2008-03-06 02:09:19.000000000 -0700
+++ kvm-guest-drivers-linux-1/virtio.c 2008-03-19 22:28:41.000000000 -0600
@@ -1,34 +1,50 @@
#include <linux/virtio.h>
#include <linux/spinlock.h>
#include <linux/virtio_config.h>
+#ifdef COMPAT_RHEL4
+static ssize_t device_show(struct device *_d, char *buf)
+#else
static ssize_t device_show(struct device *_d,
struct device_attribute *attr, char *buf)
+#endif
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
return sprintf(buf, "%hu", dev->id.device);
}
+#ifdef COMPAT_RHEL4
+static ssize_t vendor_show(struct device *_d, char *buf)
+#else
static ssize_t vendor_show(struct device *_d,
struct device_attribute *attr, char *buf)
+#endif
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
return sprintf(buf, "%hu", dev->id.vendor);
}
+#ifdef COMPAT_RHEL4
+static ssize_t status_show(struct device *_d, char *buf)
+#else
static ssize_t status_show(struct device *_d,
struct device_attribute *attr, char *buf)
+#endif
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
return sprintf(buf, "0x%08x", dev->config->get_status(dev));
}
+#ifdef COMPAT_RHEL4
+static ssize_t modalias_show(struct device *_d, char *buf)
+#else
static ssize_t modalias_show(struct device *_d,
struct device_attribute *attr, char *buf)
+#endif
{
struct virtio_device *dev = container_of(_d,struct virtio_device,dev);
return sprintf(buf, "virtio:d%08Xv%08X\n",
dev->id.device, dev->id.vendor);
}
static struct device_attribute virtio_dev_attrs[] = {
__ATTR_RO(device),
__ATTR_RO(vendor),
__ATTR_RO(status),
@@ -53,46 +69,50 @@
struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
const struct virtio_device_id *ids;
ids = container_of(_dr, struct virtio_driver, driver)->id_table;
for (i = 0; ids[i].device; i++)
if (virtio_id_match(dev, &ids[i]))
return 1;
return 0;
}
+#ifndef COMPAT_uevent_env
#ifdef COMPAT_kobject_uevent_env
static int virtio_uevent(struct device *_dv, char **envp, int num_envp,
char *buffer, int buffer_size)
{
struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
int cur_index = 0, cur_len = 0;
return add_uevent_var(envp, num_envp, &cur_index, buffer, buffer_size,
&cur_len, "MODALIAS=virtio:d%08Xv%08X",
dev->id.device, dev->id.vendor);
}
#else
static int virtio_uevent(struct device *_dv, struct kobj_uevent_env *env)
{
struct virtio_device *dev = container_of(_dv,struct virtio_device,dev);
return add_uevent_var(env, "MODALIAS=virtio:d%08Xv%08X",
dev->id.device, dev->id.vendor);
}
#endif
+#endif
static struct bus_type virtio_bus = {
.name = "virtio",
.match = virtio_dev_match,
.dev_attrs = virtio_dev_attrs,
+#ifndef COMPAT_uevent_env
.uevent = virtio_uevent,
+#endif
};
static void add_status(struct virtio_device *dev, unsigned status)
{
dev->config->set_status(dev, dev->config->get_status(dev) | status);
}
static int virtio_dev_probe(struct device *_d)
{
int err;
diff -r -U 10 -N kvm-guest-drivers-linux-1.orig/virtio_net.c kvm-guest-drivers-linux-1/virtio_net.c
--- kvm-guest-drivers-linux-1.orig/virtio_net.c 2008-03-06 02:09:19.000000000 -0700
+++ kvm-guest-drivers-linux-1/virtio_net.c 2008-03-19 22:28:41.000000000 -0600
@@ -20,40 +20,49 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/module.h>
#include <linux/virtio.h>
#include <linux/virtio_net.h>
#include <linux/scatterlist.h>
static int napi_weight = 128;
module_param(napi_weight, int, 0444);
-static int csum = 1, gso = 1;
+#ifndef COMPAT_csum
+static int csum = 1;
module_param(csum, bool, 0444);
+#endif
+#ifndef COMPAT_gso
+static int gso = 1;
module_param(gso, bool, 0444);
+#endif
/* FIXME: MTU in config. */
#define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN)
struct virtnet_info
{
struct virtio_device *vdev;
struct virtqueue *rvq, *svq;
struct net_device *dev;
struct napi_struct napi;
/* Number of input buffers, and max we've ever had. */
unsigned int num, max;
/* Receive & send queues. */
struct sk_buff_head recv;
struct sk_buff_head send;
+
+#ifdef COMPAT_RHEL4
+ struct net_device_stats stats;
+#endif
};
static inline struct virtio_net_hdr *skb_vnet_hdr(struct sk_buff *skb)
{
return (struct virtio_net_hdr *)skb->cb;
}
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));
@@ -65,51 +74,60 @@
/* Suppress further interrupts. */
svq->vq_ops->disable_cb(svq);
/* We were waiting for more output buffers. */
netif_wake_queue(vi->dev);
}
static void receive_skb(struct net_device *dev, struct sk_buff *skb,
unsigned len)
{
+#ifdef COMPAT_RHEL4
+ struct virtnet_info *vi = netdev_priv(dev);
+#endif
+#if !defined(COMPAT_gso) || !defined(COMPAT_csum_offset)
struct virtio_net_hdr *hdr = skb_vnet_hdr(skb);
+#endif
if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
pr_debug("%s: short packet %i\n", dev->name, len);
#ifndef COMPAT_net_stats
dev->stats.rx_length_errors++;
+#elif defined(COMPAT_RHEL4)
+ vi->stats.rx_length_errors++;
#endif
goto drop;
}
len -= sizeof(struct virtio_net_hdr);
BUG_ON(len > MAX_PACKET_LEN);
skb_trim(skb, len);
skb->protocol = eth_type_trans(skb, dev);
pr_debug("Receiving skb proto 0x%04x len %i type %i\n",
ntohs(skb->protocol), skb->len, skb->pkt_type);
#ifndef COMPAT_net_stats
dev->stats.rx_bytes += skb->len;
-#endif
-#ifndef COMPAT_net_stats
dev->stats.rx_packets++;
+#elif defined(COMPAT_RHEL4)
+ vi->stats.rx_bytes += skb->len;
+ vi->stats.rx_packets++;
#endif
#ifndef COMPAT_csum_offset
if (hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
pr_debug("Needs csum!\n");
if (!skb_partial_csum_set(skb,hdr->csum_start,hdr->csum_offset))
goto frame_err;
}
#endif
+#ifndef COMPAT_gso
if (hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
pr_debug("GSO!\n");
switch (hdr->gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
case VIRTIO_NET_HDR_GSO_TCPV4:
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
break;
case VIRTIO_NET_HDR_GSO_UDP:
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
break;
case VIRTIO_NET_HDR_GSO_TCPV6:
@@ -130,52 +148,65 @@
if (net_ratelimit())
printk(KERN_WARNING "%s: zero gso size.\n",
dev->name);
goto frame_err;
}
/* Header must be checked, and gso_segs computed. */
skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
skb_shinfo(skb)->gso_segs = 0;
}
+#endif
netif_receive_skb(skb);
return;
+#ifndef COMPAT_gso
frame_err:
+#endif
#ifndef COMPAT_net_stats
dev->stats.rx_frame_errors++;
#endif
drop:
dev_kfree_skb(skb);
}
static void try_fill_recv(struct virtnet_info *vi)
{
struct sk_buff *skb;
struct scatterlist sg[1+MAX_SKB_FRAGS];
int num, err;
sg_init_table(sg, 1+MAX_SKB_FRAGS);
for (;;) {
+#ifdef COMPAT_RHEL4
+ skb = dev_alloc_skb(MAX_PACKET_LEN);
+ if (unlikely(!skb))
+ break;
+ skb->dev = vi->dev;
+#else
skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN);
if (unlikely(!skb))
break;
-
+#endif
skb_put(skb, MAX_PACKET_LEN);
vnet_hdr_to_sg(sg, skb);
num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
skb_queue_head(&vi->recv, skb);
err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb);
if (err) {
+#ifdef COMPAT_RHEL4
+ __skb_unlink(skb, &vi->recv);
+#else
skb_unlink(skb, &vi->recv);
+#endif
kfree_skb(skb);
break;
}
vi->num++;
}
if (unlikely(vi->num > vi->max))
vi->max = vi->num;
vi->rvq->vq_ops->kick(vi->rvq);
}
@@ -276,57 +307,63 @@
static void free_old_xmit_skbs(struct virtnet_info *vi)
{
struct sk_buff *skb;
unsigned int len;
while ((skb = vi->svq->vq_ops->get_buf(vi->svq, &len)) != NULL) {
pr_debug("Sent skb %p\n", skb);
__skb_unlink(skb, &vi->send);
#ifndef COMPAT_net_stats
vi->dev->stats.tx_bytes += len;
-#endif
-#ifndef COMPAT_net_stats
vi->dev->stats.tx_packets++;
+#elif defined(COMPAT_RHEL4)
+ vi->stats.tx_bytes += len;
+ vi->stats.tx_packets++;
#endif
kfree_skb(skb);
}
}
static int start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct virtnet_info *vi = netdev_priv(dev);
int num, err;
struct scatterlist sg[1+MAX_SKB_FRAGS];
struct virtio_net_hdr *hdr;
+#ifndef COMPAT_RHEL4
const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
DECLARE_MAC_BUF(mac);
+#endif
sg_init_table(sg, 1+MAX_SKB_FRAGS);
+#ifndef COMPAT_RHEL4
pr_debug("%s: xmit %p %s\n", dev->name, skb, print_mac(mac, dest));
+#endif
/* Encode metadata header at front. */
hdr = skb_vnet_hdr(skb);
#ifdef COMPAT_csum_offset
hdr->flags = 0;
hdr->csum_offset = hdr->csum_start = 0;
#else
if (skb->ip_summed == CHECKSUM_PARTIAL) {
hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
hdr->csum_start = skb->csum_start - skb_headroom(skb);
hdr->csum_offset = skb->csum_offset;
} else {
hdr->flags = 0;
hdr->csum_offset = hdr->csum_start = 0;
}
#endif
+#ifndef COMPAT_gso
if (skb_is_gso(skb)) {
#ifdef COMPAT_transport_header
BUG();
#else
hdr->hdr_len = skb_transport_header(skb) - skb->data;
#endif
hdr->gso_size = skb_shinfo(skb)->gso_size;
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
@@ -334,20 +371,21 @@
else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
else
BUG();
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
hdr->gso_type |= VIRTIO_NET_HDR_GSO_ECN;
} else {
hdr->gso_type = VIRTIO_NET_HDR_GSO_NONE;
hdr->gso_size = hdr->hdr_len = 0;
}
+#endif
vnet_hdr_to_sg(sg, skb);
num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1;
__skb_queue_head(&vi->send, skb);
again:
/* Free up any pending old buffers before queueing new ones. */
free_old_xmit_skbs(vi);
err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb);
if (err) {
@@ -390,54 +428,74 @@
__netif_rx_schedule(vi->dev);
#else
__netif_rx_schedule(dev, &vi->napi);
#endif
}
return 0;
}
static int virtnet_close(struct net_device *dev)
{
+#ifdef COMPAT_RHEL4
+ netif_stop_queue(dev);
+#else
struct virtnet_info *vi = netdev_priv(dev);
napi_disable(&vi->napi);
-
+#endif
return 0;
}
+
+#ifdef COMPAT_RHEL4
+static struct net_device_stats *virtio_get_stats(struct net_device *dev)
+{
+ struct virtnet_info *vi = netdev_priv(dev);
+ return &vi->stats;
+}
+#endif
+
static int virtnet_probe(struct virtio_device *vdev)
{
int err;
struct net_device *dev;
struct virtnet_info *vi;
/* Allocate ourselves a network device with room for our info */
dev = alloc_etherdev(sizeof(struct virtnet_info));
if (!dev)
return -ENOMEM;
/* Set up network device as normal. */
dev->open = virtnet_open;
dev->stop = virtnet_close;
dev->hard_start_xmit = start_xmit;
dev->features = NETIF_F_HIGHDMA;
SET_NETDEV_DEV(dev, &vdev->dev);
+#ifdef COMPAT_RHEL4
+ dev->get_stats = virtio_get_stats;
+#endif
/* Do we support "hardware" checksums? */
+#ifndef COMPAT_csum
if (csum && vdev->config->feature(vdev, VIRTIO_NET_F_CSUM)) {
/* This opens up the world of extra features. */
dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
+#ifndef COMPAT_gso
if (gso && vdev->config->feature(vdev, VIRTIO_NET_F_GSO)) {
dev->features |= NETIF_F_TSO | NETIF_F_UFO
| NETIF_F_TSO_ECN | NETIF_F_TSO6;
}
+#endif
}
+#endif
+
/* Configuration may specify what MAC to use. Otherwise random. */
if (vdev->config->feature(vdev, VIRTIO_NET_F_MAC)) {
vdev->config->get(vdev,
offsetof(struct virtio_net_config, mac),
dev->dev_addr, dev->addr_len);
} else
random_ether_addr(dev->dev_addr);
/* Set up our device-specific information */
@@ -516,22 +574,26 @@
unregister_netdev(vi->dev);
free_netdev(vi->dev);
}
static struct virtio_device_id id_table[] = {
{ VIRTIO_ID_NET, VIRTIO_DEV_ANY_ID },
{ 0 },
};
static struct virtio_driver virtio_net = {
+#ifdef COMPAT_RHEL4
+ .driver.name = "virtio_net",
+#else
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
+#endif
.id_table = id_table,
.probe = virtnet_probe,
.remove = __devexit_p(virtnet_remove),
};
static int __init init(void)
{
return register_virtio_driver(&virtio_net);
}
diff -r -U 10 -N kvm-guest-drivers-linux-1.orig/virtio_pci.c kvm-guest-drivers-linux-1/virtio_pci.c
--- kvm-guest-drivers-linux-1.orig/virtio_pci.c 2008-03-06 02:09:19.000000000 -0700
+++ kvm-guest-drivers-linux-1/virtio_pci.c 2008-03-19 22:28:41.000000000 -0600
@@ -170,57 +170,59 @@
* I really need an EIO hook for the vring so I can ack the interrupt once we
* know that we'll be handling the IRQ but before we invoke the callback since
* the callback may notify the host which results in the host attempting to
* raise an interrupt that we would then mask once we acknowledged the
* interrupt. */
static irqreturn_t vp_interrupt(int irq, void *opaque)
{
struct virtio_pci_device *vp_dev = opaque;
struct virtio_pci_vq_info *info;
irqreturn_t ret = IRQ_NONE;
+ unsigned long flags;
u8 isr;
/* reading the ISR has the effect of also clearing it so it's very
* important to save off the value. */
isr = ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR);
/* It's definitely not us if the ISR was not high */
if (!isr)
return IRQ_NONE;
/* Configuration change? Tell driver if it wants to know. */
if (isr & VIRTIO_PCI_ISR_CONFIG) {
struct virtio_driver *drv;
drv = container_of(vp_dev->vdev.dev.driver,
struct virtio_driver, driver);
if (drv->config_changed)
drv->config_changed(&vp_dev->vdev);
}
- spin_lock(&vp_dev->lock);
+ spin_lock_irqsave(&vp_dev->lock, flags);
list_for_each_entry(info, &vp_dev->virtqueues, node) {
if (vring_interrupt(irq, info->vq) == IRQ_HANDLED)
ret = IRQ_HANDLED;
}
- spin_unlock(&vp_dev->lock);
+ spin_unlock_irqrestore(&vp_dev->lock, flags);
return ret;
}
/* the config->find_vq() implementation */
static struct virtqueue *vp_find_vq(struct virtio_device *vdev, unsigned index,
void (*callback)(struct virtqueue *vq))
{
struct virtio_pci_device *vp_dev = to_vp_device(vdev);
struct virtio_pci_vq_info *info;
struct virtqueue *vq;
+ unsigned long flags;
u16 num;
int err;
/* Select the queue we're interested in */
iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
/* Check if queue is either not available or already active. */
num = ioread16(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NUM);
if (!num || ioread32(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN))
return ERR_PTR(-ENOENT);
@@ -248,43 +250,44 @@
vq = vring_new_virtqueue(info->num, vdev, info->queue,
vp_notify, callback);
if (!vq) {
err = -ENOMEM;
goto out_activate_queue;
}
vq->priv = info;
info->vq = vq;
- spin_lock(&vp_dev->lock);
+ spin_lock_irqsave(&vp_dev->lock, flags);
list_add(&info->node, &vp_dev->virtqueues);
- spin_unlock(&vp_dev->lock);
+ spin_unlock_irqrestore(&vp_dev->lock, flags);
return vq;
out_activate_queue:
iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
kfree(info->queue);
out_info:
kfree(info);
return ERR_PTR(err);
}
/* the config->del_vq() implementation */
static void vp_del_vq(struct virtqueue *vq)
{
struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
struct virtio_pci_vq_info *info = vq->priv;
+ unsigned long flags;
- spin_lock(&vp_dev->lock);
+ spin_lock_irqsave(&vp_dev->lock, flags);
list_del(&info->node);
- spin_unlock(&vp_dev->lock);
+ spin_unlock_irqrestore(&vp_dev->lock, flags);
vring_del_virtqueue(vq);
/* Select and deactivate the queue */
iowrite16(info->queue_index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
kfree(info->queue);
kfree(info);
}
@@ -389,29 +392,33 @@
pci_set_drvdata(pci_dev, NULL);
pci_iounmap(pci_dev, vp_dev->ioaddr);
pci_release_regions(pci_dev);
pci_disable_device(pci_dev);
kfree(vp_dev);
}
#ifdef CONFIG_PM
static int virtio_pci_suspend(struct pci_dev *pci_dev, pm_message_t state)
{
+#ifndef COMPAT_RHEL4
pci_save_state(pci_dev);
pci_set_power_state(pci_dev, PCI_D3hot);
+#endif
return 0;
}
static int virtio_pci_resume(struct pci_dev *pci_dev)
{
+#ifndef COMPAT_RHEL4
pci_restore_state(pci_dev);
pci_set_power_state(pci_dev, PCI_D0);
+#endif
return 0;
}
#endif
static struct pci_driver virtio_pci_driver = {
.name = "virtio-pci",
.id_table = virtio_pci_id_table,
.probe = virtio_pci_probe,
.remove = virtio_pci_remove,
#ifdef CONFIG_PM
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2008.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
kvm-devel mailing list
kvm-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/kvm-devel