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

Reply via email to