]> git.pld-linux.org Git - packages/kernel.git/commitdiff
- update from http://xenbits.xensource.com/linux-2.6.18-xen.hg
authorElan Ruusamäe <glen@pld-linux.org>
Sun, 18 May 2008 21:51:18 +0000 (21:51 +0000)
committercvs2git <feedback@pld-linux.org>
Sun, 24 Jun 2012 12:13:13 +0000 (12:13 +0000)
Changed files:
    kernel-xen-xen.patch -> 1.2

kernel-xen-xen.patch

index 672c41eb55d8557e5c10e03cc8a74c2cfbc43222..ec5d5d806d6919bb8ae13c0986bfb88aaac1eaa4 100644 (file)
@@ -1,32 +1,35 @@
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/boot/Makefile linux-2.6.18-xen.hg/arch/i386/boot/Makefile
---- linux-2.6.18/arch/i386/boot/Makefile       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/boot/Makefile        2007-12-23 11:14:54.372518519 +0100
-@@ -26,7 +26,7 @@
- #RAMDISK := -DRAMDISK=512
- targets               := vmlinux.bin bootsect bootsect.o \
--                 setup setup.o zImage bzImage
-+                 setup setup.o zImage bzImage vmlinuz vmlinux-stripped
- subdir-       := compressed
- hostprogs-y   := tools/build
-@@ -133,5 +133,13 @@
-       cp System.map $(INSTALL_PATH)/
-       if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
-+$(obj)/vmlinuz: $(obj)/vmlinux-stripped FORCE
-+      $(call if_changed,gzip)
-+      @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
-+
-+$(obj)/vmlinux-stripped: OBJCOPYFLAGS := -g --strip-unneeded
-+$(obj)/vmlinux-stripped: vmlinux FORCE
-+      $(call if_changed,objcopy)
-+
- install:
-       sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-2.6.18-xen.hg/arch/i386/Kconfig
---- linux-2.6.18/arch/i386/Kconfig     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/Kconfig      2007-12-23 11:14:54.369185012 +0100
+--- linux-2.6.18.8/Documentation/i2c/busses/i2c-i801   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/Documentation/i2c/busses/i2c-i801      2008-05-19 00:32:37.654858195 +0300
+@@ -10,6 +10,11 @@
+   * Intel 6300ESB
+   * Intel 82801FB/FR/FW/FRW (ICH6)
+   * Intel ICH7
++  * Intel 82801G (ICH7)
++  * Intel 82801H (ICH9)
++  * Intel 82801I (ICH9)
++  * Intel Tolapai
++  * Intel ICH10
+     Datasheets: Publicly available at the Intel website
+ Authors: 
+--- linux-2.6.18.8/MAINTAINERS 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/MAINTAINERS    2008-05-19 00:32:43.775210968 +0300
+@@ -2558,6 +2558,13 @@
+ L:    linux-ia64@vger.kernel.org
+ S:    Supported
++SFC NETWORK DRIVER
++P:    Steve Hodgson
++P:    Ben Hutchings
++P:    Robert Stonehouse
++M:    linux-net-drivers@solarflare.com
++S:    Supported
++
+ SGI VISUAL WORKSTATION 320 AND 540
+ P:    Andrey Panin
+ M:    pazke@donpac.ru
+--- linux-2.6.18.8/arch/i386/Kconfig   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/Kconfig      2008-05-19 00:33:01.816250845 +0300
 @@ -16,6 +16,7 @@
  
  config GENERIC_TIME
@@ -35,12 +38,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        default y
  
  config LOCKDEP_SUPPORT
-@@ -103,6 +104,15 @@
+@@ -103,6 +104,16 @@
        help
          Choose this option if your computer is a standard PC or compatible.
  
 +config X86_XEN
 +      bool "Xen-compatible"
++      select XEN
 +      select X86_UP_APIC if !SMP && XEN_PRIVILEGED_GUEST
 +      select X86_UP_IOAPIC if !SMP && XEN_PRIVILEGED_GUEST
 +      select SWIOTLB
@@ -51,7 +55,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
  config X86_ELAN
        bool "AMD Elan"
        help
-@@ -213,6 +223,7 @@
+@@ -213,6 +224,7 @@
  
  config HPET_TIMER
        bool "HPET Timer Support"
@@ -59,7 +63,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        help
          This enables the use of the HPET for the kernel's internal timer.
          HPET is the next generation timer replacing legacy 8254s.
-@@ -263,7 +274,7 @@
+@@ -263,7 +275,7 @@
  
  config X86_UP_APIC
        bool "Local APIC support on uniprocessors"
@@ -68,7 +72,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        help
          A local APIC (Advanced Programmable Interrupt Controller) is an
          integrated interrupt controller in the CPU. If you have a single-CPU
-@@ -288,12 +299,12 @@
+@@ -288,12 +300,12 @@
  
  config X86_LOCAL_APIC
        bool
@@ -83,7 +87,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        default y
  
  config X86_VISWS_APIC
-@@ -303,7 +314,7 @@
+@@ -303,7 +315,7 @@
  
  config X86_MCE
        bool "Machine Check Exception"
@@ -92,7 +96,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        ---help---
          Machine Check Exception support allows the processor to notify the
          kernel if it detects a problem (e.g. overheating, component failure).
-@@ -402,6 +413,7 @@
+@@ -402,6 +414,7 @@
  
  config MICROCODE
        tristate "/dev/cpu/microcode - Intel IA32 CPU microcode support"
@@ -100,7 +104,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        ---help---
          If you say Y here and also to "/dev file system support" in the
          'File systems' section, you will be able to update the microcode on
-@@ -434,6 +446,10 @@
+@@ -434,6 +447,10 @@
          with major 203 and minors 0 to 31 for /dev/cpu/0/cpuid to
          /dev/cpu/31/cpuid.
  
@@ -111,7 +115,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
  source "drivers/firmware/Kconfig"
  
  choice
-@@ -616,6 +632,7 @@
+@@ -616,6 +633,7 @@
  
  config MATH_EMULATION
        bool "Math emulation"
@@ -119,7 +123,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        ---help---
          Linux can emulate a math coprocessor (used for floating point
          operations) if you don't have one. 486DX and Pentium processors have
-@@ -641,6 +658,8 @@
+@@ -641,6 +659,8 @@
  
  config MTRR
        bool "MTRR (Memory Type Range Register) support"
@@ -128,7 +132,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        ---help---
          On Intel P6 family processors (Pentium Pro, Pentium II and later)
          the Memory Type Range Registers (MTRRs) may be used to control
-@@ -675,7 +694,7 @@
+@@ -675,7 +695,7 @@
  
  config EFI
        bool "Boot from EFI support"
@@ -137,7 +141,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        default n
        ---help---
        This enables the the kernel to boot on EFI platforms using
-@@ -693,7 +712,7 @@
+@@ -693,7 +713,7 @@
  
  config IRQBALANCE
        bool "Enable kernel irq balancing"
@@ -146,7 +150,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        default y
        help
          The default yes will allow the kernel to do irq load balancing.
-@@ -741,7 +760,7 @@
+@@ -741,7 +761,7 @@
  
  config KEXEC
        bool "kexec system call (EXPERIMENTAL)"
@@ -155,7 +159,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        help
          kexec is a system call that implements the ability to shutdown your
          current kernel, and to start another kernel.  It is like a reboot
-@@ -793,6 +812,7 @@
+@@ -793,6 +813,7 @@
  
  config COMPAT_VDSO
        bool "Compat VDSO support"
@@ -163,7 +167,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        default y
        help
          Map the VDSO to the predictable old-style address too.
-@@ -810,18 +830,18 @@
+@@ -810,18 +831,18 @@
        depends on HIGHMEM
  
  menu "Power management options (ACPI, APM)"
@@ -186,7 +190,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        ---help---
          APM is a BIOS specification for saving power using several different
          techniques. This is mostly useful for battery powered laptops with
-@@ -1006,6 +1026,7 @@
+@@ -1006,6 +1027,7 @@
  
  config PCI_GOBIOS
        bool "BIOS"
@@ -194,7 +198,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
  
  config PCI_GOMMCONFIG
        bool "MMConfig"
-@@ -1013,6 +1034,13 @@
+@@ -1013,6 +1035,13 @@
  config PCI_GODIRECT
        bool "Direct"
  
@@ -208,7 +212,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
  config PCI_GOANY
        bool "Any"
  
-@@ -1020,7 +1048,7 @@
+@@ -1020,7 +1049,7 @@
  
  config PCI_BIOS
        bool
@@ -217,13 +221,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        default y
  
  config PCI_DIRECT
-@@ -1033,6 +1061,18 @@
+@@ -1033,6 +1062,19 @@
        depends on PCI && ACPI && (PCI_GOMMCONFIG || PCI_GOANY)
        default y
  
 +config XEN_PCIDEV_FRONTEND
 +      bool
 +      depends on PCI && X86_XEN && (PCI_GOXEN_FE || PCI_GOANY)
++      select HOTPLUG
 +      default y
 +
 +config XEN_PCIDEV_FE_DEBUG
@@ -236,7 +241,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
  source "drivers/pci/pcie/Kconfig"
  
  source "drivers/pci/Kconfig"
-@@ -1043,7 +1083,7 @@
+@@ -1043,7 +1085,7 @@
  
  config ISA
        bool "ISA support"
@@ -245,7 +250,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        help
          Find out whether you have ISA slots on your motherboard.  ISA is the
          name of a bus system, i.e. the way the CPU talks to the other stuff
-@@ -1070,7 +1110,7 @@
+@@ -1070,7 +1112,7 @@
  source "drivers/eisa/Kconfig"
  
  config MCA
@@ -254,7 +259,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        default y if X86_VOYAGER
        help
          MicroChannel Architecture is found in some IBM PS/2 machines and
-@@ -1146,6 +1186,8 @@
+@@ -1146,6 +1188,8 @@
  
  source "crypto/Kconfig"
  
@@ -263,7 +268,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
  source "lib/Kconfig"
  
  #
-@@ -1171,7 +1213,7 @@
+@@ -1171,7 +1215,7 @@
  
  config X86_HT
        bool
@@ -272,10 +277,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
        default y
  
  config X86_BIOS_REBOOT
-@@ -1184,6 +1226,16 @@
+@@ -1182,6 +1226,17 @@
+ config X86_TRAMPOLINE
+       bool
        depends on X86_SMP || (X86_VOYAGER && SMP)
-       default y
++      depends on !XEN
++      default y
++
 +config X86_NO_TSS
 +      bool
 +      depends on X86_XEN
@@ -284,14 +292,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig linux-
 +config X86_NO_IDT
 +      bool
 +      depends on X86_XEN
-+      default y
-+
- config KTIME_SCALAR
-       bool
        default y
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig.cpu linux-2.6.18-xen.hg/arch/i386/Kconfig.cpu
---- linux-2.6.18/arch/i386/Kconfig.cpu 2007-12-23 11:26:51.000120088 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/Kconfig.cpu  2007-12-23 11:14:54.369185012 +0100
+ config KTIME_SCALAR
+--- linux-2.6.18.8/arch/i386/Kconfig.cpu       2008-05-19 00:42:33.777222817 +0300
++++ linux-2.6.18-xen.hg/arch/i386/Kconfig.cpu  2008-05-19 00:33:01.816250845 +0300
 @@ -252,7 +252,7 @@
  
  config X86_F00F_BUG
@@ -308,9 +313,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig.cpu li
 -      depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1 || MGEODE_LX) && !X86_NUMAQ
 +      depends on (MWINCHIP3D || MWINCHIP2 || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MGEODEGX1 || MGEODE_LX) && !X86_NUMAQ && !X86_XEN
        default y
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig.debug linux-2.6.18-xen.hg/arch/i386/Kconfig.debug
---- linux-2.6.18/arch/i386/Kconfig.debug       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/Kconfig.debug        2007-12-23 11:14:54.369185012 +0100
+--- linux-2.6.18.8/arch/i386/Kconfig.debug     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/Kconfig.debug        2008-05-19 00:33:01.864253612 +0300
 @@ -79,6 +79,7 @@
  config DOUBLEFAULT
        default y
@@ -319,9 +323,105 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Kconfig.debug
        help
            This option allows trapping of rare doublefault exceptions that
            would otherwise cause a system to silently reboot. Disabling this
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/acpi/boot-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/acpi/boot-xen.c
---- linux-2.6.18/arch/i386/kernel/acpi/boot-xen.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/acpi/boot-xen.c       2007-12-23 11:14:54.382519030 +0100
+--- linux-2.6.18.8/arch/i386/Makefile  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/Makefile     2008-05-19 00:33:01.868253842 +0300
+@@ -71,6 +71,10 @@
+ mflags-$(CONFIG_X86_SUMMIT) := -Iinclude/asm-i386/mach-summit
+ mcore-$(CONFIG_X86_SUMMIT)  := mach-default
++# Xen subarch support
++mflags-$(CONFIG_X86_XEN)      := -Iinclude/asm-i386/mach-xen
++mcore-$(CONFIG_X86_XEN)               := mach-xen
++
+ # generic subarchitecture
+ mflags-$(CONFIG_X86_GENERICARCH) := -Iinclude/asm-i386/mach-generic
+ mcore-$(CONFIG_X86_GENERICARCH) := mach-default
+@@ -102,9 +106,20 @@
+ boot := arch/i386/boot
+-PHONY += zImage bzImage compressed zlilo bzlilo \
++PHONY += zImage bzImage vmlinuz compressed zlilo bzlilo \
+          zdisk bzdisk fdimage fdimage144 fdimage288 isoimage install
++ifdef CONFIG_XEN
++CPPFLAGS := -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION) \
++      -Iinclude$(if $(KBUILD_SRC),2)/asm/mach-xen $(CPPFLAGS)
++all: vmlinuz
++
++# KBUILD_IMAGE specifies the target image being built
++KBUILD_IMAGE := $(boot)/vmlinuz
++
++vmlinuz: vmlinux
++      $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
++else
+ all: bzImage
+ # KBUILD_IMAGE specify target image being built
+@@ -124,6 +139,7 @@
+ fdimage fdimage144 fdimage288 isoimage: vmlinux
+       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@
++endif
+ install:
+       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
+--- linux-2.6.18.8/arch/i386/boot/Makefile     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/boot/Makefile        2008-05-19 00:33:01.952258684 +0300
+@@ -26,7 +26,7 @@
+ #RAMDISK := -DRAMDISK=512
+ targets               := vmlinux.bin bootsect bootsect.o \
+-                 setup setup.o zImage bzImage
++                 setup setup.o zImage bzImage vmlinuz vmlinux-stripped
+ subdir-       := compressed
+ hostprogs-y   := tools/build
+@@ -133,5 +133,13 @@
+       cp System.map $(INSTALL_PATH)/
+       if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi
++$(obj)/vmlinuz: $(obj)/vmlinux-stripped FORCE
++      $(call if_changed,gzip)
++      @echo 'Kernel: $@ is ready' ' (#'`cat .version`')'
++
++$(obj)/vmlinux-stripped: OBJCOPYFLAGS := -g --strip-unneeded
++$(obj)/vmlinux-stripped: vmlinux FORCE
++      $(call if_changed,objcopy)
++
+ install:
+       sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
+--- linux-2.6.18.8/arch/i386/kernel/Makefile   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/Makefile      2008-05-19 00:33:02.540292579 +0300
+@@ -43,6 +43,7 @@
+ EXTRA_AFLAGS   := -traditional
+ obj-$(CONFIG_SCx200)          += scx200.o
++obj-$(CONFIG_XEN)             += fixup.o
+ # vsyscall.o contains the vsyscall DSO images as __initdata.
+ # We must build both images before we can assemble it.
+@@ -80,5 +81,8 @@
+                       $(obj)/vsyscall-sysenter.o $(obj)/vsyscall-note.o FORCE
+       $(call if_changed,syscall)
++early_printk-y            += ../../x86_64/kernel/early_printk.o
+ k8-y                      += ../../x86_64/kernel/k8.o
++disabled-obj-$(CONFIG_XEN) := i8259.o reboot.o smpboot.o
++%/head.o %/head.s: $(if $(CONFIG_XEN),EXTRA_AFLAGS,dummy) :=
+--- linux-2.6.18.8/arch/i386/kernel/acpi/Makefile      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/acpi/Makefile 2008-05-19 00:33:02.540292579 +0300
+@@ -4,5 +4,7 @@
+ ifneq ($(CONFIG_ACPI_PROCESSOR),)
+ obj-y                         += cstate.o processor.o
++obj-$(CONFIG_XEN)             += processor_extcntl_xen.o
+ endif
++disabled-obj-$(CONFIG_XEN)    := cstate.o wakeup.o
+--- linux-2.6.18.8/arch/i386/kernel/acpi/boot-xen.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/acpi/boot-xen.c       2008-05-19 00:33:02.560293731 +0300
 @@ -0,0 +1,1168 @@
 +/*
 + *  boot.c - Architecture-Specific Low-Level ACPI Boot Support
@@ -1491,18 +1591,268 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/acpi/bo
 +
 +      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/acpi/Makefile linux-2.6.18-xen.hg/arch/i386/kernel/acpi/Makefile
---- linux-2.6.18/arch/i386/kernel/acpi/Makefile        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/acpi/Makefile 2007-12-23 11:14:54.382519030 +0100
-@@ -6,3 +6,4 @@
- obj-y                         += cstate.o processor.o
- endif
+--- linux-2.6.18.8/arch/i386/kernel/acpi/processor.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/acpi/processor.c      2008-05-19 00:33:02.676300418 +0300
+@@ -62,7 +62,18 @@
+ /* Initialize _PDC data based on the CPU vendor */
+ void arch_acpi_processor_init_pdc(struct acpi_processor *pr)
+ {
++#ifdef CONFIG_XEN
++      /* 
++       * As a work-around, just use cpu0's cpuinfo for all processors.
++       * Further work is required to expose xen hypervisor interface of
++       * getting physical cpuinfo to dom0 kernel and then
++       * arch_acpi_processor_init_pdc can set _PDC parameters according
++       * to Xen's phys information.
++       */
++      unsigned int cpu = 0;
++#else
+       unsigned int cpu = pr->id;
++#endif /* CONFIG_XEN */
+       struct cpuinfo_x86 *c = cpu_data + cpu;
  
-+disabled-obj-$(CONFIG_XEN)    := cstate.o wakeup.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/acpi/sleep-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/acpi/sleep-xen.c
---- linux-2.6.18/arch/i386/kernel/acpi/sleep-xen.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/acpi/sleep-xen.c      2007-12-23 11:14:54.385852540 +0100
-@@ -0,0 +1,134 @@
+       pr->pdc = NULL;
+--- linux-2.6.18.8/arch/i386/kernel/acpi/processor_extcntl_xen.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/acpi/processor_extcntl_xen.c  2008-05-19 00:33:02.676300418 +0300
+@@ -0,0 +1,235 @@
++/*
++ * processor_extcntl_xen.c - interface to notify Xen
++ *
++ *  Copyright (C) 2008, Intel corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or (at
++ *  your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful, but
++ *  WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ *  General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License along
++ *  with this program; if not, write to the Free Software Foundation, Inc.,
++ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/acpi.h>
++#include <linux/pm.h>
++#include <linux/cpu.h>
++
++#include <linux/cpufreq.h>
++#include <acpi/processor.h>
++#include <asm/hypercall.h>
++
++static int xen_processor_pmbits;
++static int __init set_xen_processor_pmbits(char *str)
++{
++      get_option(&str, &xen_processor_pmbits);
++
++      return 1;
++}
++__setup("xen_processor_pmbits=", set_xen_processor_pmbits);
++EXPORT_SYMBOL(xen_processor_pmbits);
++
++static int xen_cx_notifier(struct acpi_processor *pr, int action)
++{
++      int ret, count = 0, i;
++      xen_platform_op_t op = {
++              .cmd                    = XENPF_set_processor_pminfo,
++              .interface_version      = XENPF_INTERFACE_VERSION,
++              .u.set_pminfo.id        = pr->acpi_id,
++              .u.set_pminfo.type      = XEN_PM_CX,
++      };
++      struct xen_processor_cx *data, *buf;
++      struct acpi_processor_cx *cx;
++
++      if (action == PROCESSOR_PM_CHANGE)
++              return -EINVAL;
++
++      /* Convert to Xen defined structure and hypercall */
++      buf = kzalloc(pr->power.count * sizeof(struct xen_processor_cx),
++                      GFP_KERNEL);
++      if (!buf)
++              return -ENOMEM;
++
++      data = buf;
++      for (i = 1; i <= pr->power.count; i++) {
++              cx = &pr->power.states[i];
++              /* Skip invalid cstate entry */
++              if (!cx->valid)
++                      continue;
++
++              data->type = cx->type;
++              data->latency = cx->latency;
++              data->power = cx->power;
++              data->reg.space_id = cx->reg.space_id;
++              data->reg.bit_width = cx->reg.bit_width;
++              data->reg.bit_offset = cx->reg.bit_offset;
++              data->reg.access_size = cx->reg.reserved;
++              data->reg.address = cx->reg.address;
++
++              /* Get dependency relationships */
++              if (cx->csd_count) {
++                      printk("Wow! _CSD is found. Not support for now!\n");
++                      kfree(buf);
++                      return -EINVAL;
++              } else {
++                      data->dpcnt = 0;
++                      set_xen_guest_handle(data->dp, NULL);
++              }
++
++              data++;
++              count++;
++      }
++
++      if (!count) {
++              printk("No available Cx info for cpu %d\n", pr->acpi_id);
++              kfree(buf);
++              return -EINVAL;
++      }
++
++      op.u.set_pminfo.power.count = count;
++      op.u.set_pminfo.power.flags.bm_control = pr->flags.bm_control;
++      op.u.set_pminfo.power.flags.bm_check = pr->flags.bm_check;
++      op.u.set_pminfo.power.flags.has_cst = pr->flags.has_cst;
++      op.u.set_pminfo.power.flags.power_setup_done = pr->flags.power_setup_done;
++
++      set_xen_guest_handle(op.u.set_pminfo.power.states, buf);
++      ret = HYPERVISOR_platform_op(&op);
++      kfree(buf);
++      return ret;
++}
++
++static void convert_pct_reg(struct xen_pct_register *xpct,
++      struct acpi_pct_register *apct)
++{
++      xpct->descriptor = apct->descriptor;
++      xpct->length     = apct->length;
++      xpct->space_id   = apct->space_id;
++      xpct->bit_width  = apct->bit_width;
++      xpct->bit_offset = apct->bit_offset;
++      xpct->reserved   = apct->reserved;
++      xpct->address    = apct->address;
++}
++
++static void convert_pss_states(struct xen_processor_px *xpss, 
++      struct acpi_processor_px *apss, int state_count)
++{
++      int i;
++      for(i=0; i<state_count; i++) {
++              xpss->core_frequency     = apss->core_frequency;
++              xpss->power              = apss->power;
++              xpss->transition_latency = apss->transition_latency;
++              xpss->bus_master_latency = apss->bus_master_latency;
++              xpss->control            = apss->control;
++              xpss->status             = apss->status;
++              xpss++;
++              apss++;
++      }
++}
++
++static void convert_psd_pack(struct xen_psd_package *xpsd,
++      struct acpi_psd_package *apsd)
++{
++      xpsd->num_entries    = apsd->num_entries;
++      xpsd->revision       = apsd->revision;
++      xpsd->domain         = apsd->domain;
++      xpsd->coord_type     = apsd->coord_type;
++      xpsd->num_processors = apsd->num_processors;
++}
++
++static int xen_px_notifier(struct acpi_processor *pr, int action)
++{
++      int ret;
++      xen_platform_op_t op = {
++              .cmd                    = XENPF_set_processor_pminfo,
++              .interface_version      = XENPF_INTERFACE_VERSION,
++              .u.set_pminfo.id        = pr->acpi_id,
++              .u.set_pminfo.type      = XEN_PM_PX,
++      };
++      struct xen_processor_performance *perf;
++      struct xen_processor_px *states = NULL;
++      struct acpi_processor_performance *px;
++      struct acpi_psd_package *pdomain;
++
++      /* leave dynamic ppc handle in the future */
++      if (action == PROCESSOR_PM_CHANGE)
++              return 0;
++
++      perf = &op.u.set_pminfo.perf;
++      px = pr->performance;
++
++      perf->flags = XEN_PX_PPC | 
++                    XEN_PX_PCT | 
++                    XEN_PX_PSS | 
++                    XEN_PX_PSD;
++
++      /* ppc */
++      perf->ppc = pr->performance_platform_limit;
++
++      /* pct */
++      convert_pct_reg(&perf->control_register, &px->control_register);
++      convert_pct_reg(&perf->status_register, &px->status_register);
++
++      /* pss */
++      perf->state_count = px->state_count;
++      states = kzalloc(px->state_count*sizeof(xen_processor_px_t),GFP_KERNEL);
++      if (!states)
++              return -ENOMEM;
++      convert_pss_states(states, px->states, px->state_count);
++      set_xen_guest_handle(perf->states, states);
++
++      /* psd */
++      pdomain = &px->domain_info;
++      convert_psd_pack(&perf->domain_info, pdomain);
++      if (perf->domain_info.num_processors) {
++              if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ALL)
++                      perf->shared_type = CPUFREQ_SHARED_TYPE_ALL;
++              else if (pdomain->coord_type == DOMAIN_COORD_TYPE_SW_ANY)
++                      perf->shared_type = CPUFREQ_SHARED_TYPE_ANY;
++              else if (pdomain->coord_type == DOMAIN_COORD_TYPE_HW_ALL)
++                      perf->shared_type = CPUFREQ_SHARED_TYPE_HW;
++      } else
++              perf->shared_type = CPUFREQ_SHARED_TYPE_NONE;
++
++      ret = HYPERVISOR_platform_op(&op);
++      kfree(states);
++      return ret;
++}
++
++static int xen_tx_notifier(struct acpi_processor *pr, int action)
++{
++      return -EINVAL;
++}
++static int xen_hotplug_notifier(struct acpi_processor *pr, int event)
++{
++      return -EINVAL;
++}
++
++static struct processor_extcntl_ops xen_extcntl_ops = {
++      .hotplug                = xen_hotplug_notifier,
++};
++
++static int __cpuinit xen_init_processor_extcntl(void)
++{
++      if (xen_processor_pmbits & XEN_PROCESSOR_PM_CX)
++              xen_extcntl_ops.pm_ops[PM_TYPE_IDLE] = xen_cx_notifier;
++      if (xen_processor_pmbits & XEN_PROCESSOR_PM_PX)
++              xen_extcntl_ops.pm_ops[PM_TYPE_PERF] = xen_px_notifier;
++      if (xen_processor_pmbits & XEN_PROCESSOR_PM_TX)
++              xen_extcntl_ops.pm_ops[PM_TYPE_THR] = xen_tx_notifier;
++
++      return processor_register_extcntl(&xen_extcntl_ops);
++}
++core_initcall(xen_init_processor_extcntl);
+--- linux-2.6.18.8/arch/i386/kernel/acpi/sleep-xen.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/acpi/sleep-xen.c      2008-05-19 00:33:02.676300418 +0300
+@@ -0,0 +1,113 @@
 +/*
 + * sleep.c - x86-specific ACPI sleep support.
 + *
@@ -1615,31 +1965,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/acpi/sl
 +}
 +
 +core_initcall(acpisleep_dmi_init);
-+
-+#else /* CONFIG_ACPI_PV_SLEEP */
-+#include <asm/hypervisor.h>
-+#include <xen/interface/platform.h>
-+int acpi_notify_hypervisor_state(u8 sleep_state,
-+      u32 pm1a_cnt, u32 pm1b_cnt)
-+{
-+      struct xen_platform_op op = {
-+              .cmd = XENPF_enter_acpi_sleep,
-+              .interface_version = XENPF_INTERFACE_VERSION,
-+              .u = {
-+                      .enter_acpi_sleep = {
-+                              .pm1a_cnt_val = (u16)pm1a_cnt,
-+                              .pm1b_cnt_val = (u16)pm1b_cnt,
-+                              .sleep_state = sleep_state,
-+                      },
-+              },
-+      };
-+
-+      return HYPERVISOR_platform_op(&op);
-+}
 +#endif /* CONFIG_ACPI_PV_SLEEP */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/apic-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/apic-xen.c
---- linux-2.6.18/arch/i386/kernel/apic-xen.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/apic-xen.c    2007-12-23 11:14:54.389186058 +0100
+--- linux-2.6.18.8/arch/i386/kernel/apic-xen.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/apic-xen.c    2008-05-19 00:33:02.688301110 +0300
 @@ -0,0 +1,155 @@
 +/*
 + *    Local APIC handling, local APIC timers
@@ -1796,9 +2124,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/apic-xe
 +
 +      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/asm-offsets.c linux-2.6.18-xen.hg/arch/i386/kernel/asm-offsets.c
---- linux-2.6.18/arch/i386/kernel/asm-offsets.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/asm-offsets.c 2007-12-23 11:14:54.392519572 +0100
+--- linux-2.6.18.8/arch/i386/kernel/asm-offsets.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/asm-offsets.c 2008-05-19 00:33:02.696301571 +0300
 @@ -66,9 +66,14 @@
        OFFSET(pbe_orig_address, pbe, orig_address);
        OFFSET(pbe_next, pbe, next);
@@ -1815,9 +2142,15 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/asm-off
  
        DEFINE(PAGE_SIZE_asm, PAGE_SIZE);
        DEFINE(VDSO_PRELINK, VDSO_PRELINK);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/cpu/common-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/cpu/common-xen.c
---- linux-2.6.18/arch/i386/kernel/cpu/common-xen.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/common-xen.c      2007-12-23 11:14:54.392519572 +0100
+--- linux-2.6.18.8/arch/i386/kernel/cpu/Makefile       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/Makefile  2008-05-19 00:33:02.696301571 +0300
+@@ -17,3 +17,4 @@
+ obj-$(CONFIG_MTRR)    +=      mtrr/
+ obj-$(CONFIG_CPU_FREQ)        +=      cpufreq/
++
+--- linux-2.6.18.8/arch/i386/kernel/cpu/common-xen.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/common-xen.c      2008-05-19 00:33:02.712302493 +0300
 @@ -0,0 +1,743 @@
 +#include <linux/init.h>
 +#include <linux/string.h>
@@ -2562,9 +2895,28 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/cpu/com
 +      per_cpu(cpu_tlbstate, cpu).active_mm = &init_mm;
 +}
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/cpu/cpufreq/powernow-k8.c linux-2.6.18-xen.hg/arch/i386/kernel/cpu/cpufreq/powernow-k8.c
---- linux-2.6.18/arch/i386/kernel/cpu/cpufreq/powernow-k8.c    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/cpufreq/powernow-k8.c     2007-12-23 11:14:54.402520090 +0100
+--- linux-2.6.18.8/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c 2008-05-19 00:42:33.777222817 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/cpufreq/acpi-cpufreq.c    2008-05-19 00:33:02.720302954 +0300
+@@ -568,6 +568,17 @@
+ {
+       dprintk("acpi_cpufreq_init\n");
++#ifdef CONFIG_XEN
++      /*
++       * This effectively blocks in-kernel cpufreq driver to interfere
++       * external control logic
++       */
++      if (processor_pmperf_external()) {
++              printk("CPUFREQ is controllerd externally...exit then!\n");
++              return -1;
++      }
++#endif /* CONFIG_XEN */
++
+       acpi_cpufreq_early_init_acpi();
+       return cpufreq_register_driver(&acpi_cpufreq_driver);
+--- linux-2.6.18.8/arch/i386/kernel/cpu/cpufreq/powernow-k8.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/cpufreq/powernow-k8.c     2008-05-19 00:33:02.804307796 +0300
 @@ -46,7 +46,7 @@
  
  #define PFX "powernow-k8: "
@@ -2999,9 +3351,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/cpu/cpu
                printk(KERN_INFO PFX "Found %d %s "
                        "processors (" VERSION ")\n", supported_cpus,
                        boot_cpu_data.x86_model_id);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/cpu/cpufreq/powernow-k8.h linux-2.6.18-xen.hg/arch/i386/kernel/cpu/cpufreq/powernow-k8.h
---- linux-2.6.18/arch/i386/kernel/cpu/cpufreq/powernow-k8.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/cpufreq/powernow-k8.h     2007-12-23 11:14:54.405853593 +0100
+--- linux-2.6.18.8/arch/i386/kernel/cpu/cpufreq/powernow-k8.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/cpufreq/powernow-k8.h     2008-05-19 00:33:02.804307796 +0300
 @@ -1,5 +1,5 @@
  /*
 - *  (c) 2003-2006 Advanced Micro Devices, Inc.
@@ -3070,18 +3421,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/cpu/cpu
  
  /* define the two driver architectures */
  #define CPU_OPTERON 0
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/cpu/Makefile linux-2.6.18-xen.hg/arch/i386/kernel/cpu/Makefile
---- linux-2.6.18/arch/i386/kernel/cpu/Makefile 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/Makefile  2007-12-23 11:14:54.392519572 +0100
-@@ -17,3 +17,4 @@
+--- linux-2.6.18.8/arch/i386/kernel/cpu/mtrr/Makefile  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/mtrr/Makefile     2008-05-19 00:33:03.428343766 +0300
+@@ -3,3 +3,4 @@
+ obj-y         += cyrix.o
+ obj-y         += centaur.o
  
- obj-$(CONFIG_MTRR)    +=      mtrr/
- obj-$(CONFIG_CPU_FREQ)        +=      cpufreq/
-+
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/cpu/mtrr/main-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/cpu/mtrr/main-xen.c
---- linux-2.6.18/arch/i386/kernel/cpu/mtrr/main-xen.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/mtrr/main-xen.c   2007-12-23 11:14:54.419187634 +0100
-@@ -0,0 +1,197 @@
++obj-$(CONFIG_XEN) := main.o if.o
+--- linux-2.6.18.8/arch/i386/kernel/cpu/mtrr/main-xen.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/mtrr/main-xen.c   2008-05-19 00:33:03.476346532 +0300
+@@ -0,0 +1,198 @@
 +#include <linux/init.h>
 +#include <linux/proc_fs.h>
 +#include <linux/ctype.h>
@@ -3102,7 +3451,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/cpu/mtr
 +
 +      op.cmd = XENPF_read_memtype;
 +      op.u.read_memtype.reg = reg;
-+      (void)HYPERVISOR_platform_op(&op);
++      if (unlikely(HYPERVISOR_platform_op(&op)))
++              memset(&op.u.read_memtype, 0, sizeof(op.u.read_memtype));
 +
 +      *size = op.u.read_memtype.nr_mfns;
 +      *base = op.u.read_memtype.mfn;
@@ -3279,17 +3629,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/cpu/mtr
 +}
 +
 +subsys_initcall(mtrr_init);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/cpu/mtrr/Makefile linux-2.6.18-xen.hg/arch/i386/kernel/cpu/mtrr/Makefile
---- linux-2.6.18/arch/i386/kernel/cpu/mtrr/Makefile    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/cpu/mtrr/Makefile     2007-12-23 11:14:54.415854123 +0100
-@@ -3,3 +3,4 @@
- obj-y         += cyrix.o
- obj-y         += centaur.o
-+obj-$(CONFIG_XEN) := main.o if.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/crash.c linux-2.6.18-xen.hg/arch/i386/kernel/crash.c
---- linux-2.6.18/arch/i386/kernel/crash.c      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/crash.c       2007-12-23 11:14:54.422521143 +0100
+--- linux-2.6.18.8/arch/i386/kernel/crash.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/crash.c       2008-05-19 00:33:03.540350222 +0300
 @@ -90,6 +90,7 @@
        crash_save_this_cpu(regs, cpu);
  }
@@ -3319,45 +3660,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/crash.c
 +#endif /* CONFIG_XEN */
        crash_save_self(regs);
  }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/early_printk-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/early_printk-xen.c
---- linux-2.6.18/arch/i386/kernel/early_printk-xen.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/early_printk-xen.c    2007-12-23 11:14:54.422521143 +0100
+--- linux-2.6.18.8/arch/i386/kernel/early_printk-xen.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/early_printk-xen.c    2008-05-19 00:33:03.580352527 +0300
 @@ -0,0 +1,2 @@
 +
 +#include "../../x86_64/kernel/early_printk-xen.c"
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/entry.S linux-2.6.18-xen.hg/arch/i386/kernel/entry.S
---- linux-2.6.18/arch/i386/kernel/entry.S      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/entry.S       2007-12-23 11:14:54.425854647 +0100
-@@ -269,7 +269,7 @@
-       CFI_STARTPROC simple
-       CFI_DEF_CFA esp, 0
-       CFI_REGISTER esp, ebp
--      movl TSS_sysenter_esp0(%esp),%esp
-+      movl SYSENTER_stack_esp0(%esp),%esp
- sysenter_past_esp:
-       /*
-        * No need to follow this irqs on/off section: the syscall
-@@ -689,7 +689,7 @@
-  * that sets up the real kernel stack. Check here, since we can't
-  * allow the wrong stack to be used.
-  *
-- * "TSS_sysenter_esp0+12" is because the NMI/debug handler will have
-+ * "SYSENTER_stack_esp0+12" is because the NMI/debug handler will have
-  * already pushed 3 words if it hits on the sysenter instruction:
-  * eflags, cs and eip.
-  *
-@@ -701,7 +701,7 @@
-       cmpw $__KERNEL_CS,4(%esp);              \
-       jne ok;                                 \
- label:                                                \
--      movl TSS_sysenter_esp0+offset(%esp),%esp;       \
-+      movl SYSENTER_stack_esp0+offset(%esp),%esp;     \
-       pushfl;                                 \
-       pushl $__KERNEL_CS;                     \
-       pushl $sysenter_past_esp
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/entry-xen.S linux-2.6.18-xen.hg/arch/i386/kernel/entry-xen.S
---- linux-2.6.18/arch/i386/kernel/entry-xen.S  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/entry-xen.S   2007-12-23 11:14:54.425854647 +0100
+--- linux-2.6.18.8/arch/i386/kernel/entry-xen.S        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/entry-xen.S   2008-05-19 00:33:03.584352758 +0300
 @@ -0,0 +1,1238 @@
 +/*
 + *  linux/arch/i386/entry.S
@@ -4597,9 +4906,37 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/entry-x
 +#include "syscall_table.S"
 +
 +syscall_table_size=(.-sys_call_table)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/fixup.c linux-2.6.18-xen.hg/arch/i386/kernel/fixup.c
---- linux-2.6.18/arch/i386/kernel/fixup.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/fixup.c       2007-12-23 11:14:54.429188153 +0100
+--- linux-2.6.18.8/arch/i386/kernel/entry.S    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/entry.S       2008-05-19 00:33:03.584352758 +0300
+@@ -269,7 +269,7 @@
+       CFI_STARTPROC simple
+       CFI_DEF_CFA esp, 0
+       CFI_REGISTER esp, ebp
+-      movl TSS_sysenter_esp0(%esp),%esp
++      movl SYSENTER_stack_esp0(%esp),%esp
+ sysenter_past_esp:
+       /*
+        * No need to follow this irqs on/off section: the syscall
+@@ -689,7 +689,7 @@
+  * that sets up the real kernel stack. Check here, since we can't
+  * allow the wrong stack to be used.
+  *
+- * "TSS_sysenter_esp0+12" is because the NMI/debug handler will have
++ * "SYSENTER_stack_esp0+12" is because the NMI/debug handler will have
+  * already pushed 3 words if it hits on the sysenter instruction:
+  * eflags, cs and eip.
+  *
+@@ -701,7 +701,7 @@
+       cmpw $__KERNEL_CS,4(%esp);              \
+       jne ok;                                 \
+ label:                                                \
+-      movl TSS_sysenter_esp0+offset(%esp),%esp;       \
++      movl SYSENTER_stack_esp0+offset(%esp),%esp;     \
+       pushfl;                                 \
+       pushl $__KERNEL_CS;                     \
+       pushl $sysenter_past_esp
+--- linux-2.6.18.8/arch/i386/kernel/fixup.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/fixup.c       2008-05-19 00:33:03.584352758 +0300
 @@ -0,0 +1,88 @@
 +/******************************************************************************
 + * fixup.c
@@ -4649,8 +4986,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/fixup.c
 +      if (current->tgid == 1)
 +              return;
 +            
-+      HYPERVISOR_vm_assist(
-+              VMASST_CMD_disable, VMASST_TYPE_4gb_segments_notify);
++      VOID(HYPERVISOR_vm_assist(VMASST_CMD_disable,
++                                VMASST_TYPE_4gb_segments_notify));
 +
 +      if (test_and_set_bit(0, &printed))
 +              return;
@@ -4684,14 +5021,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/fixup.c
 +
 +static int __init fixup_init(void)
 +{
-+      HYPERVISOR_vm_assist(
-+              VMASST_CMD_enable, VMASST_TYPE_4gb_segments_notify);
++      WARN_ON(HYPERVISOR_vm_assist(VMASST_CMD_enable,
++                                   VMASST_TYPE_4gb_segments_notify));
 +      return 0;
 +}
 +__initcall(fixup_init);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/head-xen.S linux-2.6.18-xen.hg/arch/i386/kernel/head-xen.S
---- linux-2.6.18/arch/i386/kernel/head-xen.S   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/head-xen.S    2007-12-23 11:14:54.429188153 +0100
+--- linux-2.6.18.8/arch/i386/kernel/head-xen.S 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/head-xen.S    2008-05-19 00:33:03.588352989 +0300
 @@ -0,0 +1,207 @@
 +
 +
@@ -4900,9 +5236,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/head-xe
 +#endif
 +      ELFNOTE(Xen, XEN_ELFNOTE_LOADER,         .asciz, "generic")
 +      ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long,  1)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/init_task-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/init_task-xen.c
---- linux-2.6.18/arch/i386/kernel/init_task-xen.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/init_task-xen.c       2007-12-23 11:14:54.432521660 +0100
+--- linux-2.6.18.8/arch/i386/kernel/init_task-xen.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/init_task-xen.c       2008-05-19 00:33:03.596353450 +0300
 @@ -0,0 +1,51 @@
 +#include <linux/mm.h>
 +#include <linux/module.h>
@@ -4955,9 +5290,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/init_ta
 +DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS;
 +#endif
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/io_apic-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/io_apic-xen.c
---- linux-2.6.18/arch/i386/kernel/io_apic-xen.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/io_apic-xen.c 2007-12-23 11:14:54.435855171 +0100
+--- linux-2.6.18.8/arch/i386/kernel/io_apic-xen.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/io_apic-xen.c 2008-05-19 00:33:03.600353680 +0300
 @@ -0,0 +1,2770 @@
 +/*
 + *    Intel IO-APIC support for multi-Pentium hosts.
@@ -5036,7 +5370,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/io_apic
 +      apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr;
 +      apic_op.reg = reg;
 +      apic_op.value = value;
-+      HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op);
++      WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op));
 +}
 +
 +#define io_apic_read(a,r)    xen_io_apic_read(a,r)
@@ -7467,7 +7801,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/io_apic
 +              struct xen_platform_op op = { .cmd = XENPF_platform_quirk };
 +              op.u.platform_quirk.quirk_id = sis_apic_bug ?
 +                      QUIRK_IOAPIC_BAD_REGSEL : QUIRK_IOAPIC_GOOD_REGSEL;
-+              HYPERVISOR_platform_op(&op);
++              VOID(HYPERVISOR_platform_op(&op));
 +      }
 +      return 0;
 +}
@@ -7729,10 +8063,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/io_apic
 +}
 +
 +#endif /* CONFIG_ACPI */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/ioport-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/ioport-xen.c
---- linux-2.6.18/arch/i386/kernel/ioport-xen.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/ioport-xen.c  2007-12-23 11:14:54.435855171 +0100
-@@ -0,0 +1,122 @@
+--- linux-2.6.18.8/arch/i386/kernel/ioport-xen.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/ioport-xen.c  2008-05-19 00:33:03.604353911 +0300
+@@ -0,0 +1,123 @@
 +/*
 + *    linux/arch/i386/kernel/ioport.c
 + *
@@ -7818,7 +8151,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/ioport-
 +
 +              set_xen_guest_handle(set_iobitmap.bitmap, (char *)bitmap);
 +              set_iobitmap.nr_ports = IO_BITMAP_BITS;
-+              HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap);
++              WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap,
++                                            &set_iobitmap));
 +      }
 +
 +      set_bitmap(t->io_bitmap_ptr, from, num, !turn_on);
@@ -7855,9 +8189,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/ioport-
 +      set_iopl_mask(t->iopl);
 +      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/irq-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/irq-xen.c
---- linux-2.6.18/arch/i386/kernel/irq-xen.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/irq-xen.c     2007-12-23 11:14:54.435855171 +0100
+--- linux-2.6.18.8/arch/i386/kernel/irq-xen.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/irq-xen.c     2008-05-19 00:33:03.604353911 +0300
 @@ -0,0 +1,324 @@
 +/*
 + *    linux/arch/i386/kernel/irq.c
@@ -8183,9 +8516,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/irq-xen
 +}
 +#endif
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/ldt-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/ldt-xen.c
---- linux-2.6.18/arch/i386/kernel/ldt-xen.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/ldt-xen.c     2007-12-23 11:14:54.439188683 +0100
+--- linux-2.6.18.8/arch/i386/kernel/ldt-xen.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/ldt-xen.c     2008-05-19 00:33:03.608354141 +0300
 @@ -0,0 +1,270 @@
 +/*
 + * linux/kernel/ldt.c
@@ -8457,10 +8789,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/ldt-xen
 +      }
 +      return ret;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/machine_kexec.c linux-2.6.18-xen.hg/arch/i386/kernel/machine_kexec.c
---- linux-2.6.18/arch/i386/kernel/machine_kexec.c      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/machine_kexec.c       2007-12-23 11:14:54.439188683 +0100
-@@ -19,123 +19,52 @@
+--- linux-2.6.18.8/arch/i386/kernel/machine_kexec.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/machine_kexec.c       2008-05-19 00:33:03.612354372 +0300
+@@ -19,123 +19,67 @@
  #include <asm/desc.h>
  #include <asm/system.h>
  
@@ -8475,15 +8806,27 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/machine
 -#ifndef CONFIG_X86_PAE
 -#define LEVEL1_SIZE (1UL << 22UL)
 -static u32 pgtable_level1[1024] PAGE_ALIGNED;
--
++#ifdef CONFIG_XEN
++#include <xen/interface/kexec.h>
++#endif
 -static void identity_map_page(unsigned long address)
 -{
 -      unsigned long level1_index, level2_index;
 -      u32 *pgtable_level2;
--
++#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
++static u32 kexec_pgd[1024] PAGE_ALIGNED;
++#ifdef CONFIG_X86_PAE
++static u32 kexec_pmd0[1024] PAGE_ALIGNED;
++static u32 kexec_pmd1[1024] PAGE_ALIGNED;
++#endif
++static u32 kexec_pte0[1024] PAGE_ALIGNED;
++static u32 kexec_pte1[1024] PAGE_ALIGNED;
 -      /* Find the current page table */
 -      pgtable_level2 = __va(read_cr3());
--
++#ifdef CONFIG_XEN
 -      /* Find the indexes of the physical address to identity map */
 -      level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE;
 -      level2_index = address / LEVEL1_SIZE;
@@ -8491,27 +8834,37 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/machine
 -      /* Identity map the page table entry */
 -      pgtable_level1[level1_index] = address | L0_ATTR;
 -      pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR;
--
++#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT)
 -      /* Flush the tlb so the new mapping takes effect.
 -       * Global tlb entries are not flushed but that is not an issue.
 -       */
 -      load_cr3(pgtable_level2);
 -}
--
++#if PAGES_NR > KEXEC_XEN_NO_PAGES
++#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break
++#endif
 -#else
 -#define LEVEL1_SIZE (1UL << 21UL)
 -#define LEVEL2_SIZE (1UL << 30UL)
 -static u64 pgtable_level1[512] PAGE_ALIGNED;
 -static u64 pgtable_level2[512] PAGE_ALIGNED;
--
++#if PA_CONTROL_PAGE != 0
++#error PA_CONTROL_PAGE is non zero - Xen support will break
++#endif
 -static void identity_map_page(unsigned long address)
--{
++void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image)
+ {
 -      unsigned long level1_index, level2_index, level3_index;
 -      u64 *pgtable_level3;
--
++      void *control_page;
 -      /* Find the current page table */
 -      pgtable_level3 = __va(read_cr3());
--
++      memset(xki->page_list, 0, sizeof(xki->page_list));
 -      /* Find the indexes of the physical address to identity map */
 -      level1_index = (address % LEVEL1_SIZE)/LEVEL0_SIZE;
 -      level2_index = (address % LEVEL2_SIZE)/LEVEL1_SIZE;
@@ -8522,73 +8875,59 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/machine
 -      pgtable_level2[level2_index] = __pa(pgtable_level1) | L1_ATTR;
 -      set_64bit(&pgtable_level3[level3_index],
 -                                             __pa(pgtable_level2) | L2_ATTR);
-+#ifdef CONFIG_XEN
-+#include <xen/interface/kexec.h>
-+#endif
++      control_page = page_address(image->control_code_page);
++      memcpy(control_page, relocate_kernel, PAGE_SIZE);
  
 -      /* Flush the tlb so the new mapping takes effect.
 -       * Global tlb entries are not flushed but that is not an issue.
 -       */
 -      load_cr3(pgtable_level3);
 -}
-+#define PAGE_ALIGNED __attribute__ ((__aligned__(PAGE_SIZE)))
-+static u32 kexec_pgd[1024] PAGE_ALIGNED;
++      xki->page_list[PA_CONTROL_PAGE] = __ma(control_page);
++      xki->page_list[PA_PGD] = __ma(kexec_pgd);
 +#ifdef CONFIG_X86_PAE
-+static u32 kexec_pmd0[1024] PAGE_ALIGNED;
-+static u32 kexec_pmd1[1024] PAGE_ALIGNED;
++      xki->page_list[PA_PMD_0] = __ma(kexec_pmd0);
++      xki->page_list[PA_PMD_1] = __ma(kexec_pmd1);
  #endif
-+static u32 kexec_pte0[1024] PAGE_ALIGNED;
-+static u32 kexec_pte1[1024] PAGE_ALIGNED;
++      xki->page_list[PA_PTE_0] = __ma(kexec_pte0);
++      xki->page_list[PA_PTE_1] = __ma(kexec_pte1);
  
 -static void set_idt(void *newidt, __u16 limit)
 -{
 -      struct Xgt_desc_struct curidt;
-+#ifdef CONFIG_XEN
+-
 -      /* ia32 supports unaliged loads & stores */
 -      curidt.size    = limit;
 -      curidt.address = (unsigned long)newidt;
-+#define __ma(x) (pfn_to_mfn(__pa((x)) >> PAGE_SHIFT) << PAGE_SHIFT)
+-
 -      load_idt(&curidt);
 -};
-+#if PAGES_NR > KEXEC_XEN_NO_PAGES
-+#error PAGES_NR is greater than KEXEC_XEN_NO_PAGES - Xen support will break
-+#endif
-+#if PA_CONTROL_PAGE != 0
-+#error PA_CONTROL_PAGE is non zero - Xen support will break
-+#endif
+-
++}
  
 -static void set_gdt(void *newgdt, __u16 limit)
-+void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, struct kimage *image)
++int __init machine_kexec_setup_resources(struct resource *hypervisor,
++                                       struct resource *phys_cpus,
++                                       int nr_phys_cpus)
  {
 -      struct Xgt_desc_struct curgdt;
-+      void *control_page;
+-
 -      /* ia32 supports unaligned loads & stores */
 -      curgdt.size    = limit;
 -      curgdt.address = (unsigned long)newgdt;
-+      memset(xki->page_list, 0, sizeof(xki->page_list));
++      int k;
  
 -      load_gdt(&curgdt);
 -};
-+      control_page = page_address(image->control_code_page);
-+      memcpy(control_page, relocate_kernel, PAGE_SIZE);
++      /* The per-cpu crash note resources belong to the hypervisor resource */
++      for (k = 0; k < nr_phys_cpus; k++)
++              request_resource(hypervisor, phys_cpus + k);
  
 -static void load_segments(void)
 -{
 -#define __STR(X) #X
 -#define STR(X) __STR(X)
-+      xki->page_list[PA_CONTROL_PAGE] = __ma(control_page);
-+      xki->page_list[PA_PGD] = __ma(kexec_pgd);
-+#ifdef CONFIG_X86_PAE
-+      xki->page_list[PA_PMD_0] = __ma(kexec_pmd0);
-+      xki->page_list[PA_PMD_1] = __ma(kexec_pmd1);
-+#endif
-+      xki->page_list[PA_PTE_0] = __ma(kexec_pte0);
-+      xki->page_list[PA_PTE_1] = __ma(kexec_pte1);
+-
 -      __asm__ __volatile__ (
 -              "\tljmp $"STR(__KERNEL_CS)",$1f\n"
 -              "\t1:\n"
@@ -8601,6 +8940,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/machine
 -              ::: "eax", "memory");
 -#undef STR
 -#undef __STR
++      return 0;
  }
  
 -typedef asmlinkage NORET_TYPE void (*relocate_new_kernel_t)(
@@ -8612,11 +8952,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/machine
 -extern const unsigned char relocate_new_kernel[];
 -extern void relocate_new_kernel_end(void);
 -extern const unsigned int relocate_new_kernel_size;
++void machine_kexec_register_resources(struct resource *res) { ; }
++
 +#endif /* CONFIG_XEN */
  
  /*
   * A architecture hook called to validate the
-@@ -163,49 +92,38 @@
+@@ -163,49 +107,38 @@
  {
  }
  
@@ -8666,7 +9008,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/machine
 -      set_idt(phys_to_virt(0),0);
 +      control_page = page_address(image->control_code_page);
 +      memcpy(control_page, relocate_kernel, PAGE_SIZE);
-+
+-      /* now call it */
+-      rnk = (relocate_new_kernel_t) reboot_code_buffer;
+-      (*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae);
 +      page_list[PA_CONTROL_PAGE] = __pa(control_page);
 +      page_list[VA_CONTROL_PAGE] = (unsigned long)relocate_kernel;
 +      page_list[PA_PGD] = __pa(kexec_pgd);
@@ -8681,37 +9026,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/machine
 +      page_list[VA_PTE_0] = (unsigned long)kexec_pte0;
 +      page_list[PA_PTE_1] = __pa(kexec_pte1);
 +      page_list[VA_PTE_1] = (unsigned long)kexec_pte1;
--      /* now call it */
--      rnk = (relocate_new_kernel_t) reboot_code_buffer;
--      (*rnk)(page_list, reboot_code_buffer, image->start, cpu_has_pae);
++
 +      relocate_kernel((unsigned long)image->head, (unsigned long)page_list,
 +                      image->start, cpu_has_pae);
  }
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/Makefile linux-2.6.18-xen.hg/arch/i386/kernel/Makefile
---- linux-2.6.18/arch/i386/kernel/Makefile     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/Makefile      2007-12-23 11:14:54.382519030 +0100
-@@ -43,6 +43,7 @@
- EXTRA_AFLAGS   := -traditional
- obj-$(CONFIG_SCx200)          += scx200.o
-+obj-$(CONFIG_XEN)             += fixup.o
- # vsyscall.o contains the vsyscall DSO images as __initdata.
- # We must build both images before we can assemble it.
-@@ -80,5 +81,8 @@
-                       $(obj)/vsyscall-sysenter.o $(obj)/vsyscall-note.o FORCE
-       $(call if_changed,syscall)
-+early_printk-y            += ../../x86_64/kernel/early_printk.o
- k8-y                      += ../../x86_64/kernel/k8.o
-+disabled-obj-$(CONFIG_XEN) := i8259.o reboot.o smpboot.o trampoline.o
-+%/head.o %/head.s: $(if $(CONFIG_XEN),EXTRA_AFLAGS,dummy) :=
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/microcode-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/microcode-xen.c
---- linux-2.6.18/arch/i386/kernel/microcode-xen.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/microcode-xen.c       2007-12-23 11:14:54.439188683 +0100
+--- linux-2.6.18.8/arch/i386/kernel/microcode-xen.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/microcode-xen.c       2008-05-19 00:33:03.612354372 +0300
 @@ -0,0 +1,144 @@
 +/*
 + *    Intel CPU Microcode Update Driver for Linux
@@ -8857,9 +9178,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/microco
 +module_init(microcode_init)
 +module_exit(microcode_exit)
 +MODULE_ALIAS_MISCDEV(MICROCODE_MINOR);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/mpparse-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/mpparse-xen.c
---- linux-2.6.18/arch/i386/kernel/mpparse-xen.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/mpparse-xen.c 2007-12-23 11:14:54.442522194 +0100
+--- linux-2.6.18.8/arch/i386/kernel/mpparse-xen.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/mpparse-xen.c 2008-05-19 00:33:03.616354603 +0300
 @@ -0,0 +1,1185 @@
 +/*
 + *    Intel Multiprocessor Specification 1.1 and 1.4
@@ -10046,10 +10366,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/mpparse
 +
 +#endif /* CONFIG_X86_IO_APIC */
 +#endif /* CONFIG_ACPI */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/pci-dma-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/pci-dma-xen.c
---- linux-2.6.18/arch/i386/kernel/pci-dma-xen.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/pci-dma-xen.c 2007-12-23 11:14:54.445855703 +0100
-@@ -0,0 +1,382 @@
+--- linux-2.6.18.8/arch/i386/kernel/pci-dma-xen.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/pci-dma-xen.c 2008-05-19 00:33:03.644356217 +0300
+@@ -0,0 +1,415 @@
 +/*
 + * Dynamic DMA mapping support.
 + *
@@ -10129,6 +10448,39 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/pci-dma
 +      }                                               \
 +} while (0)
 +
++static int check_pages_physically_contiguous(unsigned long pfn, 
++                                           unsigned int offset,
++                                           size_t length)
++{
++      unsigned long next_mfn;
++      int i;
++      int nr_pages;
++      
++      next_mfn = pfn_to_mfn(pfn);
++      nr_pages = (offset + length + PAGE_SIZE-1) >> PAGE_SHIFT;
++      
++      for (i = 1; i < nr_pages; i++) {
++              if (pfn_to_mfn(++pfn) != ++next_mfn) 
++                      return 0;
++      }
++      return 1;
++}
++
++int range_straddles_page_boundary(paddr_t p, size_t size)
++{
++      extern unsigned long *contiguous_bitmap;
++      unsigned long pfn = p >> PAGE_SHIFT;
++      unsigned int offset = p & ~PAGE_MASK;
++
++      if (offset + size <= PAGE_SIZE)
++              return 0;
++      if (test_bit(pfn, contiguous_bitmap))
++              return 0;
++      if (check_pages_physically_contiguous(pfn, offset, size))
++              return 0;
++      return 1;
++}
++
 +int
 +dma_map_sg(struct device *hwdev, struct scatterlist *sg, int nents,
 +         enum dma_data_direction direction)
@@ -10432,10 +10784,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/pci-dma
 +              swiotlb_sync_single_for_device(dev, dma_handle, size, direction);
 +}
 +EXPORT_SYMBOL(dma_sync_single_for_device);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/process-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/process-xen.c
---- linux-2.6.18/arch/i386/kernel/process-xen.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/process-xen.c 2007-12-23 11:14:54.445855703 +0100
-@@ -0,0 +1,853 @@
+--- linux-2.6.18.8/arch/i386/kernel/process-xen.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/process-xen.c 2008-05-19 00:33:03.700359445 +0300
+@@ -0,0 +1,856 @@
 +/*
 + *  linux/arch/i386/kernel/process.c
 + *
@@ -10576,7 +10927,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/process
 +      local_irq_disable();
 +      cpu_clear(smp_processor_id(), cpu_initialized);
 +      preempt_enable_no_resched();
-+      HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
++      VOID(HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL));
 +      cpu_bringup();
 +}
 +#else
@@ -10747,7 +11098,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/process
 +              struct thread_struct *t = &tsk->thread;
 +              struct physdev_set_iobitmap set_iobitmap;
 +              memset(&set_iobitmap, 0, sizeof(set_iobitmap));
-+              HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap);
++              WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap,
++                                            &set_iobitmap));
 +              kfree(t->io_bitmap_ptr);
 +              t->io_bitmap_ptr = NULL;
 +              clear_thread_flag(TIF_IO_BITMAP);
@@ -11054,7 +11406,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/process
 +              mcl++;
 +      }
 +
-+      (void)HYPERVISOR_multicall(_mcl, mcl - _mcl);
++      BUG_ON(mcl > _mcl + ARRAY_SIZE(_mcl));
++      if (unlikely(HYPERVISOR_multicall_check(_mcl, mcl - _mcl, NULL)))
++              BUG();
 +
 +      /*
 +       * Restore %fs and %gs if needed.
@@ -11289,9 +11643,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/process
 +              sp -= get_random_int() % 8192;
 +      return sp & ~0xf;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/quirks-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/quirks-xen.c
---- linux-2.6.18/arch/i386/kernel/quirks-xen.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/quirks-xen.c  2007-12-23 11:14:54.449189209 +0100
+--- linux-2.6.18.8/arch/i386/kernel/quirks-xen.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/quirks-xen.c  2008-05-19 00:33:03.704359675 +0300
 @@ -0,0 +1,47 @@
 +/*
 + * This file contains work-arounds for x86 and x86_64 platform bugs.
@@ -11329,7 +11682,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/quirks-
 +              printk(KERN_INFO "Disabling irq balancing and affinity\n");
 +              op.cmd = XENPF_platform_quirk;
 +              op.u.platform_quirk.quirk_id = QUIRK_NOIRQBALANCING;
-+              (void)HYPERVISOR_platform_op(&op);
++              WARN_ON(HYPERVISOR_platform_op(&op));
 +      }
 +
 +      /* put back the original value for config space*/
@@ -11340,9 +11693,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/quirks-
 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_E7525_MCH,  quirk_intel_irqbalance);
 +DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL,  PCI_DEVICE_ID_INTEL_E7520_MCH,  quirk_intel_irqbalance);
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/relocate_kernel.S linux-2.6.18-xen.hg/arch/i386/kernel/relocate_kernel.S
---- linux-2.6.18/arch/i386/kernel/relocate_kernel.S    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/relocate_kernel.S     2007-12-23 11:14:54.452522713 +0100
+--- linux-2.6.18.8/arch/i386/kernel/relocate_kernel.S  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/relocate_kernel.S     2008-05-19 00:33:03.708359906 +0300
 @@ -7,16 +7,138 @@
   */
  
@@ -11574,42 +11926,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/relocat
 +idt_48:
 +      .word   0                       /* limit */
 +      .long   0                       /* base */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/setup.c linux-2.6.18-xen.hg/arch/i386/kernel/setup.c
---- linux-2.6.18/arch/i386/kernel/setup.c      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/setup.c       2007-12-23 11:14:54.455856217 +0100
-@@ -956,6 +956,28 @@
-       return 0;
- }
-+/*
-+ * This function checks if any part of the range <start,end> is mapped
-+ * with type.
-+ */
-+int
-+e820_any_mapped(u64 start, u64 end, unsigned type)
-+{
-+      int i;
-+
-+      for (i = 0; i < e820.nr_map; i++) {
-+              const struct e820entry *ei = &e820.map[i];
-+
-+              if (type && ei->type != type)
-+                      continue;
-+              if (ei->addr >= end || ei->addr + ei->size <= start)
-+                      continue;
-+              return 1;
-+      }
-+      return 0;
-+}
-+EXPORT_SYMBOL_GPL(e820_any_mapped);
-+
-  /*
-   * This function checks if the entire range <start,end> is mapped with type.
-   *
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/setup-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/setup-xen.c
---- linux-2.6.18/arch/i386/kernel/setup-xen.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/setup-xen.c   2007-12-23 11:14:54.452522713 +0100
-@@ -0,0 +1,1918 @@
+--- linux-2.6.18.8/arch/i386/kernel/setup-xen.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/setup-xen.c   2008-05-19 00:33:03.792364748 +0300
+@@ -0,0 +1,1919 @@
 +/*
 + *  linux/arch/i386/kernel/setup.c
 + *
@@ -12348,6 +12667,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/setup-x
 +#endif
 +              add_memory_region(start, size, type);
 +      } while (biosmap++,--nr_map);
++
++#ifdef CONFIG_XEN
++      if (is_initial_xendomain()) {
++              struct xen_memory_map memmap;
++
++              memmap.nr_entries = E820MAX;
++              set_xen_guest_handle(memmap.buffer, machine_e820.map);
++
++              if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap))
++                      BUG();
++              machine_e820.nr_map = memmap.nr_entries;
++      } else
++              machine_e820 = e820;
++#endif
++
 +      return 0;
 +}
 +
@@ -13014,10 +13348,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/setup-x
 +                      crashk_res.end - crashk_res.start + 1);
 +#endif
 +#endif
-+
-+      if (!xen_feature(XENFEAT_auto_translated_physmap))
-+              phys_to_machine_mapping =
-+                      (unsigned long *)xen_start_info->mfn_list;
 +}
 +
 +/*
@@ -13185,18 +13515,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/setup-x
 +static void __init register_memory(void)
 +{
 +#ifdef CONFIG_XEN
-+      if (is_initial_xendomain()) {
-+              struct xen_memory_map memmap;
-+
-+              memmap.nr_entries = E820MAX;
-+              set_xen_guest_handle(memmap.buffer, machine_e820.map);
-+
-+              if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap))
-+                      BUG();
-+
-+              machine_e820.nr_map = memmap.nr_entries;
++      if (is_initial_xendomain())
 +              e820_setup_gap(machine_e820.map, machine_e820.nr_map);
-+      }
 +      else
 +#endif
 +              e820_setup_gap(e820.map, e820.nr_map);
@@ -13233,11 +13553,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/setup-x
 +      /* Register a call for panic conditions. */
 +      atomic_notifier_chain_register(&panic_notifier_list, &xen_panic_block);
 +
-+      HYPERVISOR_vm_assist(VMASST_CMD_enable, VMASST_TYPE_4gb_segments);
-+      HYPERVISOR_vm_assist(VMASST_CMD_enable,
-+                           VMASST_TYPE_writable_pagetables);
++      WARN_ON(HYPERVISOR_vm_assist(VMASST_CMD_enable,
++                                   VMASST_TYPE_4gb_segments));
++      WARN_ON(HYPERVISOR_vm_assist(VMASST_CMD_enable,
++                                   VMASST_TYPE_writable_pagetables));
 +
 +      memcpy(&boot_cpu_data, &new_cpu_data, sizeof(new_cpu_data));
++      pre_setup_arch_hook();
 +      early_cpu_init();
 +#ifdef CONFIG_SMP
 +      prefill_possible_map();
@@ -13291,8 +13613,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/setup-x
 +      rd_doload = ((RAMDISK_FLAGS & RAMDISK_LOAD_FLAG) != 0);
 +#endif
 +
-+      setup_xen_features();
-+
 +      ARCH_SETUP
 +      if (efi_enabled)
 +              efi_init();
@@ -13439,7 +13759,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/setup-x
 +              efi_map_memmap();
 +
 +      set_iopl.iopl = 1;
-+      HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
++      WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl));
 +
 +#ifdef CONFIG_ACPI
 +      if (!is_initial_xendomain()) {
@@ -13528,9 +13848,39 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/setup-x
 + * c-basic-offset:8
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/smp-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/smp-xen.c
---- linux-2.6.18/arch/i386/kernel/smp-xen.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/smp-xen.c     2007-12-23 11:14:54.455856217 +0100
+--- linux-2.6.18.8/arch/i386/kernel/setup.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/setup.c       2008-05-19 00:33:03.796364978 +0300
+@@ -956,6 +956,28 @@
+       return 0;
+ }
++/*
++ * This function checks if any part of the range <start,end> is mapped
++ * with type.
++ */
++int
++e820_any_mapped(u64 start, u64 end, unsigned type)
++{
++      int i;
++
++      for (i = 0; i < e820.nr_map; i++) {
++              const struct e820entry *ei = &e820.map[i];
++
++              if (type && ei->type != type)
++                      continue;
++              if (ei->addr >= end || ei->addr + ei->size <= start)
++                      continue;
++              return 1;
++      }
++      return 0;
++}
++EXPORT_SYMBOL_GPL(e820_any_mapped);
++
+  /*
+   * This function checks if the entire range <start,end> is mapped with type.
+   *
+--- linux-2.6.18.8/arch/i386/kernel/smp-xen.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/smp-xen.c     2008-05-19 00:33:03.800365209 +0300
 @@ -0,0 +1,605 @@
 +/*
 + *    Intel SMP support routines.
@@ -14137,9 +14487,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/smp-xen
 +      return IRQ_HANDLED;
 +}
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/sysenter.c linux-2.6.18-xen.hg/arch/i386/kernel/sysenter.c
---- linux-2.6.18/arch/i386/kernel/sysenter.c   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/sysenter.c    2007-12-23 11:14:54.462523240 +0100
+--- linux-2.6.18.8/arch/i386/kernel/sysenter.c 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/sysenter.c    2008-05-19 00:33:03.808365670 +0300
 @@ -23,6 +23,10 @@
  #include <asm/pgtable.h>
  #include <asm/unistd.h>
@@ -14195,10 +14544,35 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/sysente
        put_cpu();      
  }
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/time-xen.c
---- linux-2.6.18/arch/i386/kernel/time-xen.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/time-xen.c    2007-12-23 11:14:54.462523240 +0100
-@@ -0,0 +1,1170 @@
+@@ -75,11 +109,6 @@
+ #ifdef CONFIG_COMPAT_VDSO
+       __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_READONLY);
+       printk("Compat vDSO mapped to %08lx.\n", __fix_to_virt(FIX_VDSO));
+-#else
+-      /*
+-       * In the non-compat case the ELF coredumping code needs the fixmap:
+-       */
+-      __set_fixmap(FIX_VDSO, __pa(syscall_page), PAGE_KERNEL_RO);
+ #endif
+       if (!boot_cpu_has(X86_FEATURE_SEP)) {
+@@ -142,6 +171,13 @@
+       vma->vm_end = addr + PAGE_SIZE;
+       /* MAYWRITE to allow gdb to COW and set breakpoints */
+       vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
++      /*
++       * Make sure the vDSO gets into every core dump.
++       * Dumping its contents makes post-mortem fully interpretable later
++       * without matching up the same kernel and hardware config to see
++       * what PC values meant.
++       */
++      vma->vm_flags |= VM_ALWAYSDUMP;
+       vma->vm_flags |= mm->def_flags;
+       vma->vm_page_prot = protection_map[vma->vm_flags & 7];
+       vma->vm_ops = &syscall_vm_ops;
+--- linux-2.6.18.8/arch/i386/kernel/time-xen.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/time-xen.c    2008-05-19 00:33:03.808365670 +0300
+@@ -0,0 +1,1194 @@
 +/*
 + *  linux/arch/i386/kernel/time.c
 + *
@@ -14503,7 +14877,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 + * Reads a consistent set of time-base values from Xen, into a shadow data
 + * area.
 + */
-+static void get_time_values_from_xen(int cpu)
++static void get_time_values_from_xen(unsigned int cpu)
 +{
 +      struct vcpu_time_info   *src;
 +      struct shadow_time_info *dst;
@@ -14524,7 +14898,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +      dst->tsc_to_usec_mul = dst->tsc_to_nsec_mul / 1000;
 +}
 +
-+static inline int time_values_up_to_date(int cpu)
++static inline int time_values_up_to_date(unsigned int cpu)
 +{
 +      struct vcpu_time_info   *src;
 +      struct shadow_time_info *dst;
@@ -14675,7 +15049,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +              op.u.settime.secs        = sec;
 +              op.u.settime.nsecs       = nsec;
 +              op.u.settime.system_time = shadow->system_timestamp;
-+              HYPERVISOR_platform_op(&op);
++              WARN_ON(HYPERVISOR_platform_op(&op));
 +              update_wallclock();
 +      } else if (independent_wallclock) {
 +              nsec -= shadow->system_timestamp;
@@ -14720,7 +15094,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +      op.u.settime.secs        = sec;
 +      op.u.settime.nsecs       = nsec;
 +      op.u.settime.system_time = processed_system_time;
-+      HYPERVISOR_platform_op(&op);
++      WARN_ON(HYPERVISOR_platform_op(&op));
 +
 +      update_wallclock();
 +
@@ -14756,7 +15130,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 + */
 +unsigned long long monotonic_clock(void)
 +{
-+      int cpu = get_cpu();
++      unsigned int cpu = get_cpu();
 +      struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu);
 +      u64 time;
 +      u32 local_time_version;
@@ -14822,7 +15196,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +{
 +      s64 delta, delta_cpu, stolen, blocked;
 +      u64 sched_time;
-+      int i, cpu = smp_processor_id();
++      unsigned int i, cpu = smp_processor_id();
 +      struct shadow_time_info *shadow = &per_cpu(shadow_time, cpu);
 +      struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu);
 +
@@ -14863,7 +15237,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +      if ((unlikely(delta < -(s64)permitted_clock_jitter) ||
 +           unlikely(delta_cpu < -(s64)permitted_clock_jitter))
 +          && printk_ratelimit()) {
-+              printk("Timer ISR/%d: Time went backwards: "
++              printk("Timer ISR/%u: Time went backwards: "
 +                     "delta=%lld delta_cpu=%lld shadow=%lld "
 +                     "off=%lld processed=%lld cpu_processed=%lld\n",
 +                     cpu, delta, delta_cpu, shadow->system_timestamp,
@@ -14946,7 +15320,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +      return IRQ_HANDLED;
 +}
 +
-+static void init_missing_ticks_accounting(int cpu)
++static void init_missing_ticks_accounting(unsigned int cpu)
 +{
 +      struct vcpu_register_runstate_memory_area area;
 +      struct vcpu_runstate_info *runstate = &per_cpu(runstate, cpu);
@@ -15115,8 +15489,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +      }
 +#endif
 +
-+      HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, 0,
-+                         &xen_set_periodic_tick);
++      switch (HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, 0,
++                                 &xen_set_periodic_tick)) {
++      case 0:
++#if CONFIG_XEN_COMPAT <= 0x030004
++      case -ENOSYS:
++#endif
++              break;
++      default:
++              BUG();
++      }
 +
 +      get_time_values_from_xen(0);
 +
@@ -15227,7 +15609,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +void halt(void)
 +{
 +      if (irqs_disabled())
-+              HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
++              VOID(HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL));
 +}
 +EXPORT_SYMBOL(halt);
 +
@@ -15239,8 +15621,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +      init_cpu_khz();
 +
 +      for_each_online_cpu(cpu) {
-+              HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu,
-+                                 &xen_set_periodic_tick);
++              switch (HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu,
++                                         &xen_set_periodic_tick)) {
++              case 0:
++#if CONFIG_XEN_COMPAT <= 0x030004
++              case -ENOSYS:
++#endif
++                      break;
++              default:
++                      BUG();
++              }
 +              get_time_values_from_xen(cpu);
 +              per_cpu(processed_system_time, cpu) =
 +                      per_cpu(shadow_time, 0).system_timestamp;
@@ -15261,8 +15651,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +
 +      BUG_ON(cpu == 0);
 +
-+      HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu,
-+                         &xen_set_periodic_tick);
++      switch (HYPERVISOR_vcpu_op(VCPUOP_set_periodic_timer, cpu,
++                         &xen_set_periodic_tick)) {
++      case 0:
++#if CONFIG_XEN_COMPAT <= 0x030004
++      case -ENOSYS:
++#endif
++              break;
++      default:
++              BUG();
++      }
 +
 +      do {
 +              seq = read_seqbegin(&xtime_lock);
@@ -15272,7 +15670,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +              init_missing_ticks_accounting(cpu);
 +      } while (read_seqretry(&xtime_lock, seq));
 +
-+      sprintf(timer_name[cpu], "timer%d", cpu);
++      sprintf(timer_name[cpu], "timer%u", cpu);
 +      irq = bind_virq_to_irqhandler(VIRQ_TIMER,
 +                                    cpu,
 +                                    timer_interrupt,
@@ -15310,7 +15708,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +      op.u.change_freq.flags = 0;
 +      op.u.change_freq.cpu = freq->cpu;
 +      op.u.change_freq.freq = (u64)freq->new * 1000;
-+      HYPERVISOR_platform_op(&op);
++      WARN_ON(HYPERVISOR_platform_op(&op));
 +
 +      return 0;
 +}
@@ -15369,33 +15767,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/time-xe
 +      return 0;
 +}
 +__initcall(xen_sysctl_init);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/traps.c linux-2.6.18-xen.hg/arch/i386/kernel/traps.c
---- linux-2.6.18/arch/i386/kernel/traps.c      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/traps.c       2007-12-23 11:14:54.465856754 +0100
-@@ -642,18 +642,11 @@
- static void io_check_error(unsigned char reason, struct pt_regs * regs)
- {
--      unsigned long i;
--
-       printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
-       show_registers(regs);
-       /* Re-enable the IOCK line, wait for a few seconds */
--      reason = (reason & 0xf) | 8;
--      outb(reason, 0x61);
--      i = 2000;
--      while (--i) udelay(1000);
--      reason &= ~8;
--      outb(reason, 0x61);
-+      clear_io_check_error(reason);
- }
- static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/traps-xen.c linux-2.6.18-xen.hg/arch/i386/kernel/traps-xen.c
---- linux-2.6.18/arch/i386/kernel/traps-xen.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/traps-xen.c   2007-12-23 11:14:54.465856754 +0100
-@@ -0,0 +1,1186 @@
+--- linux-2.6.18.8/arch/i386/kernel/traps-xen.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/traps-xen.c   2008-05-19 00:33:03.812365901 +0300
+@@ -0,0 +1,1190 @@
 +/*
 + *  linux/arch/i386/traps.c
 + *
@@ -16492,7 +16866,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/traps-x
 + * NB. All these are "trap gates" (i.e. events_mask isn't set) except
 + * for those that specify <dpl>|4 in the second field.
 + */
-+static trap_info_t trap_table[] = {
++static trap_info_t __cpuinitdata trap_table[] = {
 +      {  0, 0, __KERNEL_CS, (unsigned long)divide_error               },
 +      {  1, 0|4, __KERNEL_CS, (unsigned long)debug                    },
 +      {  3, 3|4, __KERNEL_CS, (unsigned long)int3                     },
@@ -16519,7 +16893,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/traps-x
 +
 +void __init trap_init(void)
 +{
-+      HYPERVISOR_set_trap_table(trap_table);
++      int ret;
++
++      ret = HYPERVISOR_set_trap_table(trap_table);
++      if (ret)
++              printk("HYPERVISOR_set_trap_table failed: error %d\n", ret);
 +
 +      if (cpu_has_fxsr) {
 +              /*
@@ -16549,9 +16927,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/traps-x
 +      cpu_init();
 +}
 +
-+void smp_trap_init(trap_info_t *trap_ctxt)
++void __cpuinit smp_trap_init(trap_info_t *trap_ctxt)
 +{
-+      trap_info_t *t = trap_table;
++      const trap_info_t *t = trap_table;
 +
 +      for (t = trap_table; t->address; t++) {
 +              trap_ctxt[t->vector].flags = t->flags;
@@ -16582,9 +16960,30 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/traps-x
 +}
 +__setup("call_trace=", call_trace_setup);
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/vm86.c linux-2.6.18-xen.hg/arch/i386/kernel/vm86.c
---- linux-2.6.18/arch/i386/kernel/vm86.c       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/vm86.c        2007-12-23 11:14:54.465856754 +0100
+--- linux-2.6.18.8/arch/i386/kernel/traps.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/traps.c       2008-05-19 00:33:03.816366131 +0300
+@@ -642,18 +642,11 @@
+ static void io_check_error(unsigned char reason, struct pt_regs * regs)
+ {
+-      unsigned long i;
+-
+       printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n");
+       show_registers(regs);
+       /* Re-enable the IOCK line, wait for a few seconds */
+-      reason = (reason & 0xf) | 8;
+-      outb(reason, 0x61);
+-      i = 2000;
+-      while (--i) udelay(1000);
+-      reason &= ~8;
+-      outb(reason, 0x61);
++      clear_io_check_error(reason);
+ }
+ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
+--- linux-2.6.18.8/arch/i386/kernel/vm86.c     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/vm86.c        2008-05-19 00:33:03.816366131 +0300
 @@ -97,7 +97,9 @@
  struct pt_regs * FASTCALL(save_v86_state(struct kernel_vm86_regs * regs));
  struct pt_regs * fastcall save_v86_state(struct kernel_vm86_regs * regs)
@@ -16639,9 +17038,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/vm86.c
  
        tsk->thread.screen_bitmap = info->screen_bitmap;
        if (info->flags & VM86_SCREEN_BITMAP)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/vmlinux.lds.S linux-2.6.18-xen.hg/arch/i386/kernel/vmlinux.lds.S
---- linux-2.6.18/arch/i386/kernel/vmlinux.lds.S        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/vmlinux.lds.S 2007-12-23 11:14:54.469190263 +0100
+--- linux-2.6.18.8/arch/i386/kernel/vmlinux.lds.S      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/vmlinux.lds.S 2008-05-19 00:33:03.820366362 +0300
 @@ -13,6 +13,12 @@
  OUTPUT_ARCH(i386)
  ENTRY(phys_startup_32)
@@ -16684,9 +17082,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/vmlinux
 +
 +  NOTES
  }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/vsyscall-note-xen.S linux-2.6.18-xen.hg/arch/i386/kernel/vsyscall-note-xen.S
---- linux-2.6.18/arch/i386/kernel/vsyscall-note-xen.S  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/kernel/vsyscall-note-xen.S   2007-12-23 11:14:54.469190263 +0100
+--- linux-2.6.18.8/arch/i386/kernel/vsyscall-note-xen.S        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/kernel/vsyscall-note-xen.S   2008-05-19 00:33:03.820366362 +0300
 @@ -0,0 +1,32 @@
 +/*
 + * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
@@ -16720,23 +17117,53 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/kernel/vsyscal
 +NOTE_KERNELCAP_BEGIN(1, 1)
 +NOTE_KERNELCAP(0, "nosegneg")
 +NOTE_KERNELCAP_END
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mach-xen/Makefile linux-2.6.18-xen.hg/arch/i386/mach-xen/Makefile
---- linux-2.6.18/arch/i386/mach-xen/Makefile   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/mach-xen/Makefile    2007-12-23 11:14:54.489191309 +0100
+--- linux-2.6.18.8/arch/i386/lib/Makefile      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/lib/Makefile 2008-05-19 00:33:03.824366592 +0300
+@@ -7,3 +7,4 @@
+       bitops.o
+ lib-$(CONFIG_X86_USE_3DNOW) += mmx.o
++lib-$(CONFIG_XEN_SCRUB_PAGES) += scrub.o
+--- linux-2.6.18.8/arch/i386/lib/scrub.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/lib/scrub.c  2008-05-19 00:33:03.848367976 +0300
+@@ -0,0 +1,21 @@
++#include <asm/cpufeature.h>
++#include <asm/page.h>
++#include <asm/processor.h>
++
++void scrub_pages(void *v, unsigned int count)
++{
++      if (likely(cpu_has_xmm2)) {
++              unsigned long n = count * (PAGE_SIZE / sizeof(long) / 4);
++
++              for (; n--; v += sizeof(long) * 4)
++                      asm("movnti %1,(%0)\n\t"
++                          "movnti %1,%c2(%0)\n\t"
++                          "movnti %1,2*%c2(%0)\n\t"
++                          "movnti %1,3*%c2(%0)\n\t"
++                          : : "r" (v), "r" (0L), "i" (sizeof(long))
++                          : "memory");
++              asm volatile("sfence" : : : "memory");
++      } else
++              for (; count--; v += PAGE_SIZE)
++                      clear_page(v);
++}
+--- linux-2.6.18.8/arch/i386/mach-xen/Makefile 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/mach-xen/Makefile    2008-05-19 00:33:03.900370973 +0300
 @@ -0,0 +1,5 @@
 +#
 +# Makefile for the linux kernel.
 +#
 +
 +obj-y                         := setup.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mach-xen/setup.c linux-2.6.18-xen.hg/arch/i386/mach-xen/setup.c
---- linux-2.6.18/arch/i386/mach-xen/setup.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/mach-xen/setup.c     2007-12-23 11:14:54.489191309 +0100
-@@ -0,0 +1,147 @@
+--- linux-2.6.18.8/arch/i386/mach-xen/setup.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/mach-xen/setup.c     2008-05-19 00:33:03.900370973 +0300
+@@ -0,0 +1,158 @@
 +/*
 + *    Machine specific setup for generic
 + */
 +
++#include <linux/mm.h>
 +#include <linux/smp.h>
 +#include <linux/init.h>
 +#include <linux/interrupt.h>
@@ -16822,17 +17249,39 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mach-xen/setup
 +extern void failsafe_callback(void);
 +extern void nmi(void);
 +
-+unsigned long *machine_to_phys_mapping;
++unsigned long *machine_to_phys_mapping = (void *)MACH2PHYS_VIRT_START;
 +EXPORT_SYMBOL(machine_to_phys_mapping);
 +unsigned int machine_to_phys_order;
 +EXPORT_SYMBOL(machine_to_phys_order);
 +
-+void __init machine_specific_arch_setup(void)
++void __init pre_setup_arch_hook(void)
 +{
-+      int ret;
 +      struct xen_machphys_mapping mapping;
 +      unsigned long machine_to_phys_nr_ents;
 +      struct xen_platform_parameters pp;
++
++      init_mm.pgd = swapper_pg_dir = (pgd_t *)xen_start_info->pt_base;
++
++      setup_xen_features();
++
++      if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0)
++              set_fixaddr_top(pp.virt_start);
++
++      if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
++              machine_to_phys_mapping = (unsigned long *)mapping.v_start;
++              machine_to_phys_nr_ents = mapping.max_mfn + 1;
++      } else
++              machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
++      machine_to_phys_order = fls(machine_to_phys_nr_ents - 1);
++
++      if (!xen_feature(XENFEAT_auto_translated_physmap))
++              phys_to_machine_mapping =
++                      (unsigned long *)xen_start_info->mfn_list;
++}
++
++void __init machine_specific_arch_setup(void)
++{
++      int ret;
 +      static struct callback_register __initdata event = {
 +              .type = CALLBACKTYPE_event,
 +              .address = { __KERNEL_CS, (unsigned long)hypervisor_callback },
@@ -16867,66 +17316,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mach-xen/setup
 +              HYPERVISOR_nmi_op(XENNMI_register_callback, &cb);
 +      }
 +#endif
-+
-+      if (HYPERVISOR_xen_version(XENVER_platform_parameters, &pp) == 0)
-+              set_fixaddr_top(pp.virt_start);
-+
-+      machine_to_phys_mapping = (unsigned long *)MACH2PHYS_VIRT_START;
-+      machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
-+      if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
-+              machine_to_phys_mapping = (unsigned long *)mapping.v_start;
-+              machine_to_phys_nr_ents = mapping.max_mfn + 1;
-+      }
-+      while ((1UL << machine_to_phys_order) < machine_to_phys_nr_ents )
-+              machine_to_phys_order++;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/Makefile linux-2.6.18-xen.hg/arch/i386/Makefile
---- linux-2.6.18/arch/i386/Makefile    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/Makefile     2007-12-23 11:14:54.369185012 +0100
-@@ -71,6 +71,10 @@
- mflags-$(CONFIG_X86_SUMMIT) := -Iinclude/asm-i386/mach-summit
- mcore-$(CONFIG_X86_SUMMIT)  := mach-default
-+# Xen subarch support
-+mflags-$(CONFIG_X86_XEN)      := -Iinclude/asm-i386/mach-xen
-+mcore-$(CONFIG_X86_XEN)               := mach-xen
-+
- # generic subarchitecture
- mflags-$(CONFIG_X86_GENERICARCH) := -Iinclude/asm-i386/mach-generic
- mcore-$(CONFIG_X86_GENERICARCH) := mach-default
-@@ -102,9 +106,20 @@
- boot := arch/i386/boot
--PHONY += zImage bzImage compressed zlilo bzlilo \
-+PHONY += zImage bzImage vmlinuz compressed zlilo bzlilo \
-          zdisk bzdisk fdimage fdimage144 fdimage288 isoimage install
-+ifdef CONFIG_XEN
-+CPPFLAGS := -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION) \
-+      -Iinclude$(if $(KBUILD_SRC),2)/asm/mach-xen $(CPPFLAGS)
-+all: vmlinuz
-+
-+# KBUILD_IMAGE specifies the target image being built
-+KBUILD_IMAGE := $(boot)/vmlinuz
-+
-+vmlinuz: vmlinux
-+      $(Q)$(MAKE) $(build)=$(boot) $(KBUILD_IMAGE)
-+else
- all: bzImage
- # KBUILD_IMAGE specify target image being built
-@@ -124,6 +139,7 @@
- fdimage fdimage144 fdimage288 isoimage: vmlinux
-       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) $@
-+endif
- install:
-       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(KBUILD_IMAGE) install
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/fault-xen.c linux-2.6.18-xen.hg/arch/i386/mm/fault-xen.c
---- linux-2.6.18/arch/i386/mm/fault-xen.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/mm/fault-xen.c       2007-12-23 11:14:54.519192886 +0100
+--- linux-2.6.18.8/arch/i386/mm/Makefile       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/mm/Makefile  2008-05-19 00:33:03.956374201 +0300
+@@ -8,3 +8,4 @@
+ obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+ obj-$(CONFIG_HIGHMEM) += highmem.o
+ obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap.o
++obj-$(CONFIG_XEN) += hypervisor.o
+--- linux-2.6.18.8/arch/i386/mm/fault-xen.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/mm/fault-xen.c       2008-05-19 00:33:03.960374432 +0300
 @@ -0,0 +1,779 @@
 +/*
 + *  linux/arch/i386/mm/fault.c
@@ -17707,9 +18106,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/fault-xen.c
 +      }
 +}
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/highmem-xen.c linux-2.6.18-xen.hg/arch/i386/mm/highmem-xen.c
---- linux-2.6.18/arch/i386/mm/highmem-xen.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/mm/highmem-xen.c     2007-12-23 11:14:54.519192886 +0100
+--- linux-2.6.18.8/arch/i386/mm/highmem-xen.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/mm/highmem-xen.c     2008-05-19 00:33:03.964374662 +0300
 @@ -0,0 +1,136 @@
 +#include <linux/highmem.h>
 +#include <linux/module.h>
@@ -17847,10 +18245,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/highmem-xen
 +EXPORT_SYMBOL(kmap_atomic_pte);
 +EXPORT_SYMBOL(kunmap_atomic);
 +EXPORT_SYMBOL(kmap_atomic_to_page);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.c linux-2.6.18-xen.hg/arch/i386/mm/hypervisor.c
---- linux-2.6.18/arch/i386/mm/hypervisor.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/mm/hypervisor.c      2007-12-23 11:14:54.522526395 +0100
-@@ -0,0 +1,550 @@
+--- linux-2.6.18.8/arch/i386/mm/hypervisor.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/mm/hypervisor.c      2008-05-19 00:33:03.964374662 +0300
+@@ -0,0 +1,602 @@
 +/******************************************************************************
 + * mm/hypervisor.c
 + * 
@@ -18034,12 +18431,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +      BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
 +}
 +
-+void xen_set_ldt(unsigned long ptr, unsigned long len)
++void xen_set_ldt(const void *ptr, unsigned int ents)
 +{
 +      struct mmuext_op op;
 +      op.cmd = MMUEXT_SET_LDT;
-+      op.arg1.linear_addr = ptr;
-+      op.arg2.nr_ents     = len;
++      op.arg1.linear_addr = (unsigned long)ptr;
++      op.arg2.nr_ents     = ents;
 +      BUG_ON(HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF) < 0);
 +}
 +
@@ -18102,9 +18499,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +      unsigned long vstart, unsigned int order, unsigned int address_bits)
 +{
 +      unsigned long *in_frames = discontig_frames, out_frame;
-+      unsigned long  frame, i, flags;
-+      long           rc;
-+      int            success;
++      unsigned long  frame, flags;
++      unsigned int   i;
++      int            rc, success;
 +      struct xen_memory_exchange exchange = {
 +              .in = {
 +                      .nr_extents   = 1UL << order,
@@ -18133,12 +18530,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +      set_xen_guest_handle(exchange.in.extent_start, in_frames);
 +      set_xen_guest_handle(exchange.out.extent_start, &out_frame);
 +
-+      scrub_pages(vstart, 1 << order);
++      scrub_pages((void *)vstart, 1 << order);
 +
 +      balloon_lock(flags);
 +
 +      /* 1. Zap current PTEs, remembering MFNs. */
-+      for (i = 0; i < (1UL<<order); i++) {
++      for (i = 0; i < (1U<<order); i++) {
 +              in_frames[i] = pfn_to_mfn((__pa(vstart) >> PAGE_SHIFT) + i);
 +              MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE),
 +                                      __pte_ma(0), 0);
@@ -18164,7 +18561,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +                                              &exchange.out) == 1);
 +              if (!success) {
 +                      /* Couldn't get special memory: fall back to normal. */
-+                      for (i = 0; i < (1UL<<order); i++)
++                      for (i = 0; i < (1U<<order); i++)
 +                              in_frames[i] = (__pa(vstart)>>PAGE_SHIFT) + i;
 +                      if (HYPERVISOR_memory_op(XENMEM_populate_physmap,
 +                                               &exchange.in) != (1UL<<order))
@@ -18174,7 +18571,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +#endif
 +
 +      /* 3. Map the new extent in place of old pages. */
-+      for (i = 0; i < (1UL<<order); i++) {
++      for (i = 0; i < (1U<<order); i++) {
 +              frame = success ? (out_frame + i) : in_frames[i];
 +              MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE),
 +                                      pfn_pte_ma(frame, PAGE_KERNEL), 0);
@@ -18200,9 +18597,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +void xen_destroy_contiguous_region(unsigned long vstart, unsigned int order)
 +{
 +      unsigned long *out_frames = discontig_frames, in_frame;
-+      unsigned long  frame, i, flags;
-+      long           rc;
-+      int            success;
++      unsigned long  frame, flags;
++      unsigned int   i;
++      int            rc, success;
 +      struct xen_memory_exchange exchange = {
 +              .in = {
 +                      .nr_extents   = 1,
@@ -18226,7 +18623,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +      set_xen_guest_handle(exchange.in.extent_start, &in_frame);
 +      set_xen_guest_handle(exchange.out.extent_start, out_frames);
 +
-+      scrub_pages(vstart, 1 << order);
++      scrub_pages((void *)vstart, 1 << order);
 +
 +      balloon_lock(flags);
 +
@@ -18236,7 +18633,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +      in_frame = pfn_to_mfn(__pa(vstart) >> PAGE_SHIFT);
 +
 +      /* 2. Zap current PTEs. */
-+      for (i = 0; i < (1UL<<order); i++) {
++      for (i = 0; i < (1U<<order); i++) {
 +              MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE),
 +                                      __pte_ma(0), 0);
 +              set_phys_to_machine((__pa(vstart)>>PAGE_SHIFT)+i,
@@ -18265,7 +18662,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +#endif
 +
 +      /* 4. Map new pages in place of old pages. */
-+      for (i = 0; i < (1UL<<order); i++) {
++      for (i = 0; i < (1U<<order); i++) {
 +              frame = success ? out_frames[i] : (in_frame + i);
 +              MULTI_update_va_mapping(cr_mcl + i, vstart + (i*PAGE_SIZE),
 +                                      pfn_pte_ma(frame, PAGE_KERNEL), 0);
@@ -18287,18 +18684,17 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +{
 +      unsigned long flags, frame;
 +      unsigned long *in_frames = discontig_frames, *out_frames = limited_frames;
-+      void *v;
 +      struct page *page;
-+      int i, nr_mcl, rc, success;
++      unsigned int i, n, nr_mcl;
++      int rc, success;
++      DECLARE_BITMAP(limit_map, 1 << MAX_CONTIG_ORDER);
 +
 +      struct xen_memory_exchange exchange = {
 +              .in = {
-+                      .nr_extents   = 1UL << order,
 +                      .extent_order = 0,
 +                      .domid        = DOMID_SELF
 +              },
 +              .out = {
-+                      .nr_extents   = 1UL << order,
 +                      .extent_order = 0,
 +                      .address_bits = address_bits,
 +                      .domid        = DOMID_SELF
@@ -18311,80 +18707,98 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +      if (unlikely(order > MAX_CONTIG_ORDER))
 +              return -ENOMEM;
 +
++      bitmap_zero(limit_map, 1U << order);
 +      set_xen_guest_handle(exchange.in.extent_start, in_frames);
 +      set_xen_guest_handle(exchange.out.extent_start, out_frames);
 +
 +      /* 0. Scrub the pages. */
-+      for ( i = 0 ; i < 1UL<<order ; i++ ) {
++      for (i = 0, n = 0; i < 1U<<order ; i++) {
 +              page = &pages[i];
++              if (!(pfn_to_mfn(page_to_pfn(page)) >> (address_bits - PAGE_SHIFT)))
++                      continue;
++              __set_bit(i, limit_map);
 +
-+              if (!PageHighMem(page)) {
-+                      v = page_address(page);
-+                      scrub_pages(v, 1);
-+              } else {
-+                      v = kmap(page);
-+                      scrub_pages(v, 1);
++              if (!PageHighMem(page))
++                      scrub_pages(page_address(page), 1);
++#ifdef CONFIG_XEN_SCRUB_PAGES
++              else {
++                      scrub_pages(kmap(page), 1);
 +                      kunmap(page);
++                      ++n;
 +              }
++#endif
 +      }
++      if (bitmap_empty(limit_map, 1U << order))
++              return 0;
 +
-+      kmap_flush_unused();
++      if (n)
++              kmap_flush_unused();
 +
 +      balloon_lock(flags);
 +
 +      /* 1. Zap current PTEs (if any), remembering MFNs. */
-+      for (i = 0, nr_mcl = 0; i < (1UL<<order); i++) {
++      for (i = 0, n = 0, nr_mcl = 0; i < (1U<<order); i++) {
++              if(!test_bit(i, limit_map))
++                      continue;
 +              page = &pages[i];
 +
-+              out_frames[i] = page_to_pfn(page);
-+              in_frames[i] = pfn_to_mfn(out_frames[i]);
++              out_frames[n] = page_to_pfn(page);
++              in_frames[n] = pfn_to_mfn(out_frames[n]);
 +
 +              if (!PageHighMem(page))
 +                      MULTI_update_va_mapping(cr_mcl + nr_mcl++,
 +                                              (unsigned long)page_address(page),
 +                                              __pte_ma(0), 0);
 +
-+              set_phys_to_machine(out_frames[i], INVALID_P2M_ENTRY);
++              set_phys_to_machine(out_frames[n], INVALID_P2M_ENTRY);
++              ++n;
 +      }
-+      if (HYPERVISOR_multicall_check(cr_mcl, nr_mcl, NULL))
++      if (nr_mcl && HYPERVISOR_multicall_check(cr_mcl, nr_mcl, NULL))
 +              BUG();
 +
 +      /* 2. Get new memory below the required limit. */
++      exchange.in.nr_extents = n;
++      exchange.out.nr_extents = n;
 +      rc = HYPERVISOR_memory_op(XENMEM_exchange, &exchange);
-+      success = (exchange.nr_exchanged == (1UL << order));
++      success = (exchange.nr_exchanged == n);
 +      BUG_ON(!success && ((exchange.nr_exchanged != 0) || (rc == 0)));
 +      BUG_ON(success && (rc != 0));
 +#if CONFIG_XEN_COMPAT <= 0x030002
 +      if (unlikely(rc == -ENOSYS)) {
 +              /* Compatibility when XENMEM_exchange is unsupported. */
 +              if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
-+                                       &exchange.in) != (1UL << order))
++                                       &exchange.in) != n)
 +                      BUG();
-+              success = (HYPERVISOR_memory_op(XENMEM_populate_physmap,
-+                                              &exchange.out) != (1UL <<order));
++              if (HYPERVISOR_memory_op(XENMEM_populate_physmap,
++                                       &exchange.out) != n)
++                      BUG();
++              success = 1;
 +      }
 +#endif
 +
 +      /* 3. Map the new pages in place of old pages. */
-+      for (i = 0, nr_mcl = 0; i < (1UL<<order); i++) {
-+              unsigned long pfn;
++      for (i = 0, n = 0, nr_mcl = 0; i < (1U<<order); i++) {
++              if(!test_bit(i, limit_map))
++                      continue;
 +              page = &pages[i];
-+              pfn = page_to_pfn(page);
 +
-+              frame = success ? out_frames[i] : in_frames[i];
++              frame = success ? out_frames[n] : in_frames[n];
 +
 +              if (!PageHighMem(page))
 +                      MULTI_update_va_mapping(cr_mcl + nr_mcl++,
 +                                              (unsigned long)page_address(page),
 +                                              pfn_pte_ma(frame, PAGE_KERNEL), 0);
 +
-+              set_phys_to_machine(pfn, frame);
++              set_phys_to_machine(page_to_pfn(page), frame);
++              ++n;
++      }
++      if (nr_mcl) {
++              cr_mcl[nr_mcl - 1].args[MULTI_UVMFLAGS_INDEX] = order
++                                                              ? UVMF_TLB_FLUSH|UVMF_ALL
++                                                              : UVMF_INVLPG|UVMF_ALL;
++              if (HYPERVISOR_multicall_check(cr_mcl, nr_mcl, NULL))
++                      BUG();
 +      }
-+      cr_mcl[nr_mcl - 1].args[MULTI_UVMFLAGS_INDEX] = order
-+                                                      ? UVMF_TLB_FLUSH|UVMF_ALL
-+                                                      : UVMF_INVLPG|UVMF_ALL;
-+      if (HYPERVISOR_multicall_check(cr_mcl, nr_mcl, NULL))
-+              BUG();
 +
 +      balloon_unlock(flags);
 +
@@ -18401,10 +18815,44 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/hypervisor.
 +              mach_lp, (u64)entry_a | ((u64)entry_b<<32));
 +}
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/init-xen.c linux-2.6.18-xen.hg/arch/i386/mm/init-xen.c
---- linux-2.6.18/arch/i386/mm/init-xen.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/mm/init-xen.c        2007-12-23 11:14:54.522526395 +0100
-@@ -0,0 +1,850 @@
++
++#define MAX_BATCHED_FULL_PTES 32
++
++int xen_change_pte_range(struct mm_struct *mm, pmd_t *pmd,
++                       unsigned long addr, unsigned long end, pgprot_t newprot)
++{
++      int rc = 0, i = 0;
++      mmu_update_t u[MAX_BATCHED_FULL_PTES];
++      pte_t *pte;
++      spinlock_t *ptl;
++
++      if (!xen_feature(XENFEAT_mmu_pt_update_preserve_ad))
++              return 0;
++
++      pte = pte_offset_map_lock(mm, pmd, addr, &ptl);
++      do {
++              if (pte_present(*pte)) {
++                      u[i].ptr = (__pmd_val(*pmd) & PHYSICAL_PAGE_MASK)
++                                 | ((unsigned long)pte & ~PAGE_MASK)
++                                 | MMU_PT_UPDATE_PRESERVE_AD;
++                      u[i].val = __pte_val(pte_modify(*pte, newprot));
++                      if (++i == MAX_BATCHED_FULL_PTES) {
++                              if ((rc = HYPERVISOR_mmu_update(
++                                      &u[0], i, NULL, DOMID_SELF)) != 0)
++                                      break;
++                              i = 0;
++                      }
++              }
++      } while (pte++, addr += PAGE_SIZE, addr != end);
++      if (i)
++              rc = HYPERVISOR_mmu_update( &u[0], i, NULL, DOMID_SELF);
++      pte_unmap_unlock(pte - 1, ptl);
++      BUG_ON(rc && rc != -ENOSYS);
++      return !rc;
++}
+--- linux-2.6.18.8/arch/i386/mm/init-xen.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/mm/init-xen.c        2008-05-19 00:33:03.968374893 +0300
+@@ -0,0 +1,847 @@
 +/*
 + *  linux/arch/i386/mm/init.c
 + *
@@ -18795,9 +19243,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/init-xen.c
 +      unsigned long vaddr;
 +      pgd_t *pgd_base = (pgd_t *)xen_start_info->pt_base;
 +
-+      swapper_pg_dir = pgd_base;
-+      init_mm.pgd    = pgd_base;
-+
 +      /* Enable PSE if available */
 +      if (cpu_has_pse) {
 +              set_in_cr4(X86_CR4_PSE);
@@ -19255,9 +19700,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/init-xen.c
 +}
 +#endif
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/ioremap-xen.c linux-2.6.18-xen.hg/arch/i386/mm/ioremap-xen.c
---- linux-2.6.18/arch/i386/mm/ioremap-xen.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/mm/ioremap-xen.c     2007-12-23 11:14:54.522526395 +0100
+--- linux-2.6.18.8/arch/i386/mm/ioremap-xen.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/mm/ioremap-xen.c     2008-05-19 00:33:03.968374893 +0300
 @@ -0,0 +1,443 @@
 +/*
 + * arch/i386/mm/ioremap.c
@@ -19337,7 +19781,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/ioremap-xen
 +               * Fill in the machine address: PTE ptr is done later by
 +               * apply_to_page_range(). 
 +               */
-+              v->val = __pte_val(pfn_pte_ma(mfn, prot));
++              v->val = __pte_val(pfn_pte_ma(mfn, prot)) | _PAGE_IO;
 +
 +              mfn++;
 +              address += PAGE_SIZE; 
@@ -19702,17 +20146,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/ioremap-xen
 +              --nrpages;
 +      }
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/Makefile linux-2.6.18-xen.hg/arch/i386/mm/Makefile
---- linux-2.6.18/arch/i386/mm/Makefile 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/mm/Makefile  2007-12-23 11:14:54.515859375 +0100
-@@ -8,3 +8,4 @@
- obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
- obj-$(CONFIG_HIGHMEM) += highmem.o
- obj-$(CONFIG_BOOT_IOREMAP) += boot_ioremap.o
-+obj-$(CONFIG_XEN) += hypervisor.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/pageattr.c linux-2.6.18-xen.hg/arch/i386/mm/pageattr.c
---- linux-2.6.18/arch/i386/mm/pageattr.c       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/mm/pageattr.c        2007-12-23 11:14:54.525859899 +0100
+--- linux-2.6.18.8/arch/i386/mm/pageattr.c     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/mm/pageattr.c        2008-05-19 00:33:03.972375123 +0300
 @@ -84,7 +84,7 @@
        unsigned long flags;
  
@@ -19722,111 +20157,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/pageattr.c
                return;
  
        spin_lock_irqsave(&pgd_lock, flags);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/pgtable.c linux-2.6.18-xen.hg/arch/i386/mm/pgtable.c
---- linux-2.6.18/arch/i386/mm/pgtable.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/mm/pgtable.c 2007-12-23 11:14:54.525859899 +0100
-@@ -12,6 +12,7 @@
- #include <linux/slab.h>
- #include <linux/pagemap.h>
- #include <linux/spinlock.h>
-+#include <linux/module.h>
- #include <asm/system.h>
- #include <asm/pgtable.h>
-@@ -137,6 +138,10 @@
-       __flush_tlb_one(vaddr);
- }
-+static int nr_fixmaps = 0;
-+unsigned long __FIXADDR_TOP = 0xfffff000;
-+EXPORT_SYMBOL(__FIXADDR_TOP);
-+
- void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
- {
-       unsigned long address = __fix_to_virt(idx);
-@@ -146,6 +151,13 @@
-               return;
-       }
-       set_pte_pfn(address, phys >> PAGE_SHIFT, flags);
-+      nr_fixmaps++;
-+}
-+
-+void set_fixaddr_top(unsigned long top)
-+{
-+      BUG_ON(nr_fixmaps > 0);
-+      __FIXADDR_TOP = top - PAGE_SIZE;
- }
- pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
-@@ -214,6 +226,7 @@
-               spin_lock_irqsave(&pgd_lock, flags);
-       }
-+      if (PTRS_PER_PMD == 1 || HAVE_SHARED_KERNEL_PMD)
-       clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
-                       swapper_pg_dir + USER_PTRS_PER_PGD,
-                       KERNEL_PGD_PTRS);
-@@ -248,6 +261,30 @@
-                       goto out_oom;
-               set_pgd(&pgd[i], __pgd(1 + __pa(pmd)));
-       }
-+
-+      if (!HAVE_SHARED_KERNEL_PMD) {
-+              unsigned long flags;
-+
-+              for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) {
-+                      pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
-+                      if (!pmd)
-+                              goto out_oom;
-+                      set_pgd(&pgd[USER_PTRS_PER_PGD], __pgd(1 + __pa(pmd)));
-+              }
-+
-+              spin_lock_irqsave(&pgd_lock, flags);
-+              for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) {
-+                      unsigned long v = (unsigned long)i << PGDIR_SHIFT;
-+                      pgd_t *kpgd = pgd_offset_k(v);
-+                      pud_t *kpud = pud_offset(kpgd, v);
-+                      pmd_t *kpmd = pmd_offset(kpud, v);
-+                      pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1);
-+                      memcpy(pmd, kpmd, PAGE_SIZE);
-+              }
-+              pgd_list_add(pgd);
-+              spin_unlock_irqrestore(&pgd_lock, flags);
-+      }
-+
-       return pgd;
- out_oom:
-@@ -262,9 +299,23 @@
-       int i;
-       /* in the PAE case user pgd entries are overwritten before usage */
--      if (PTRS_PER_PMD > 1)
--              for (i = 0; i < USER_PTRS_PER_PGD; ++i)
--                      kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
-+      if (PTRS_PER_PMD > 1) {
-+              for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
-+                      pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1);
-+                      kmem_cache_free(pmd_cache, pmd);
-+              }
-+              if (!HAVE_SHARED_KERNEL_PMD) {
-+                      unsigned long flags;
-+                      spin_lock_irqsave(&pgd_lock, flags);
-+                      pgd_list_del(pgd);
-+                      spin_unlock_irqrestore(&pgd_lock, flags);
-+                      for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) {
-+                              pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1);
-+                              memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t));
-+                              kmem_cache_free(pmd_cache, pmd);
-+                      }
-+              }
-+      }
-       /* in the non-PAE case, free_pgtables() clears user pgd entries */
-       kmem_cache_free(pgd_cache, pgd);
- }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/pgtable-xen.c linux-2.6.18-xen.hg/arch/i386/mm/pgtable-xen.c
---- linux-2.6.18/arch/i386/mm/pgtable-xen.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/mm/pgtable-xen.c     2007-12-23 11:14:54.525859899 +0100
+--- linux-2.6.18.8/arch/i386/mm/pgtable-xen.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/mm/pgtable-xen.c     2008-05-19 00:33:03.972375123 +0300
 @@ -0,0 +1,725 @@
 +/*
 + *  linux/arch/i386/mm/pgtable.c
@@ -20553,9 +20885,109 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/mm/pgtable-xen
 +          !mm->context.has_foreign_mappings)
 +              mm_unpin(mm);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/oprofile/Makefile linux-2.6.18-xen.hg/arch/i386/oprofile/Makefile
---- linux-2.6.18/arch/i386/oprofile/Makefile   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/oprofile/Makefile    2007-12-23 11:14:54.529193404 +0100
+--- linux-2.6.18.8/arch/i386/mm/pgtable.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/mm/pgtable.c 2008-05-19 00:33:03.972375123 +0300
+@@ -12,6 +12,7 @@
+ #include <linux/slab.h>
+ #include <linux/pagemap.h>
+ #include <linux/spinlock.h>
++#include <linux/module.h>
+ #include <asm/system.h>
+ #include <asm/pgtable.h>
+@@ -137,6 +138,10 @@
+       __flush_tlb_one(vaddr);
+ }
++static int nr_fixmaps = 0;
++unsigned long __FIXADDR_TOP = 0xfffff000;
++EXPORT_SYMBOL(__FIXADDR_TOP);
++
+ void __set_fixmap (enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
+ {
+       unsigned long address = __fix_to_virt(idx);
+@@ -146,6 +151,13 @@
+               return;
+       }
+       set_pte_pfn(address, phys >> PAGE_SHIFT, flags);
++      nr_fixmaps++;
++}
++
++void set_fixaddr_top(unsigned long top)
++{
++      BUG_ON(nr_fixmaps > 0);
++      __FIXADDR_TOP = top - PAGE_SIZE;
+ }
+ pte_t *pte_alloc_one_kernel(struct mm_struct *mm, unsigned long address)
+@@ -214,6 +226,7 @@
+               spin_lock_irqsave(&pgd_lock, flags);
+       }
++      if (PTRS_PER_PMD == 1 || HAVE_SHARED_KERNEL_PMD)
+       clone_pgd_range((pgd_t *)pgd + USER_PTRS_PER_PGD,
+                       swapper_pg_dir + USER_PTRS_PER_PGD,
+                       KERNEL_PGD_PTRS);
+@@ -248,6 +261,30 @@
+                       goto out_oom;
+               set_pgd(&pgd[i], __pgd(1 + __pa(pmd)));
+       }
++
++      if (!HAVE_SHARED_KERNEL_PMD) {
++              unsigned long flags;
++
++              for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) {
++                      pmd_t *pmd = kmem_cache_alloc(pmd_cache, GFP_KERNEL);
++                      if (!pmd)
++                              goto out_oom;
++                      set_pgd(&pgd[USER_PTRS_PER_PGD], __pgd(1 + __pa(pmd)));
++              }
++
++              spin_lock_irqsave(&pgd_lock, flags);
++              for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) {
++                      unsigned long v = (unsigned long)i << PGDIR_SHIFT;
++                      pgd_t *kpgd = pgd_offset_k(v);
++                      pud_t *kpud = pud_offset(kpgd, v);
++                      pmd_t *kpmd = pmd_offset(kpud, v);
++                      pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1);
++                      memcpy(pmd, kpmd, PAGE_SIZE);
++              }
++              pgd_list_add(pgd);
++              spin_unlock_irqrestore(&pgd_lock, flags);
++      }
++
+       return pgd;
+ out_oom:
+@@ -262,9 +299,23 @@
+       int i;
+       /* in the PAE case user pgd entries are overwritten before usage */
+-      if (PTRS_PER_PMD > 1)
+-              for (i = 0; i < USER_PTRS_PER_PGD; ++i)
+-                      kmem_cache_free(pmd_cache, (void *)__va(pgd_val(pgd[i])-1));
++      if (PTRS_PER_PMD > 1) {
++              for (i = 0; i < USER_PTRS_PER_PGD; ++i) {
++                      pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1);
++                      kmem_cache_free(pmd_cache, pmd);
++              }
++              if (!HAVE_SHARED_KERNEL_PMD) {
++                      unsigned long flags;
++                      spin_lock_irqsave(&pgd_lock, flags);
++                      pgd_list_del(pgd);
++                      spin_unlock_irqrestore(&pgd_lock, flags);
++                      for (i = USER_PTRS_PER_PGD; i < PTRS_PER_PGD; i++) {
++                              pmd_t *pmd = (void *)__va(pgd_val(pgd[i])-1);
++                              memset(pmd, 0, PTRS_PER_PMD*sizeof(pmd_t));
++                              kmem_cache_free(pmd_cache, pmd);
++                      }
++              }
++      }
+       /* in the non-PAE case, free_pgtables() clears user pgd entries */
+       kmem_cache_free(pgd_cache, pgd);
+ }
+--- linux-2.6.18.8/arch/i386/oprofile/Makefile 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/oprofile/Makefile    2008-05-19 00:33:03.976375354 +0300
 @@ -6,7 +6,14 @@
                oprofilefs.o oprofile_stats.o  \
                timer_int.o )
@@ -20571,9 +21003,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/oprofile/Makef
                                           op_model_ppro.o op_model_p4.o
  oprofile-$(CONFIG_X86_IO_APIC)                += nmi_timer_int.o
 +endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/oprofile/xenoprof.c linux-2.6.18-xen.hg/arch/i386/oprofile/xenoprof.c
---- linux-2.6.18/arch/i386/oprofile/xenoprof.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/oprofile/xenoprof.c  2007-12-23 11:14:54.532526912 +0100
+--- linux-2.6.18.8/arch/i386/oprofile/xenoprof.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/oprofile/xenoprof.c  2008-05-19 00:33:03.984375815 +0300
 @@ -0,0 +1,179 @@
 +/**
 + * @file xenoprof.c
@@ -20629,8 +21060,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/oprofile/xenop
 +              counter.kernel    = (uint32_t)counter_config[i].kernel;
 +              counter.user      = (uint32_t)counter_config[i].user;
 +              counter.unit_mask = (uint64_t)counter_config[i].unit_mask;
-+              HYPERVISOR_xenoprof_op(XENOPROF_counter, 
-+                                     &counter);
++              WARN_ON(HYPERVISOR_xenoprof_op(XENOPROF_counter,
++                                             &counter));
 +      }
 +}
 +
@@ -20754,26 +21185,22 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/oprofile/xenop
 +{
 +      xenoprofile_exit();
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/pci/irq.c linux-2.6.18-xen.hg/arch/i386/pci/irq.c
---- linux-2.6.18/arch/i386/pci/irq.c   2007-12-23 11:26:51.003453595 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/pci/irq.c    2007-12-23 11:14:54.535860422 +0100
-@@ -543,6 +543,12 @@
-               case PCI_DEVICE_ID_INTEL_ICH8_2:
-               case PCI_DEVICE_ID_INTEL_ICH8_3:
-               case PCI_DEVICE_ID_INTEL_ICH8_4:
-+              case PCI_DEVICE_ID_INTEL_ICH9_0:
-+              case PCI_DEVICE_ID_INTEL_ICH9_1:
-+              case PCI_DEVICE_ID_INTEL_ICH9_2:
-+              case PCI_DEVICE_ID_INTEL_ICH9_3:
-+              case PCI_DEVICE_ID_INTEL_ICH9_4:
-+              case PCI_DEVICE_ID_INTEL_ICH9_5:
-                       r->name = "PIIX/ICH";
-                       r->get = pirq_piix_get;
-                       r->set = pirq_piix_set;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/pci/irq-xen.c linux-2.6.18-xen.hg/arch/i386/pci/irq-xen.c
---- linux-2.6.18/arch/i386/pci/irq-xen.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/pci/irq-xen.c        2007-12-23 11:14:54.535860422 +0100
-@@ -0,0 +1,1205 @@
+--- linux-2.6.18.8/arch/i386/pci/Makefile      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/pci/Makefile 2008-05-19 00:33:03.984375815 +0300
+@@ -4,6 +4,10 @@
+ obj-$(CONFIG_PCI_MMCONFIG)    += mmconfig.o direct.o
+ obj-$(CONFIG_PCI_DIRECT)      += direct.o
++# pcifront should be after pcbios.o, mmconfig.o, and direct.o as it should only
++# take over if direct access to the PCI bus is unavailable
++obj-$(CONFIG_XEN_PCIDEV_FRONTEND)     += pcifront.o
++
+ pci-y                         := fixup.o
+ pci-$(CONFIG_ACPI)            += acpi.o
+ pci-y                         += legacy.o irq.o
+--- linux-2.6.18.8/arch/i386/pci/irq-xen.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/pci/irq-xen.c        2008-05-19 00:33:03.988376046 +0300
+@@ -0,0 +1,1215 @@
 +/*
 + *    Low-Level PCI Support for PC -- Routing of Interrupts
 + *
@@ -21035,13 +21462,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/pci/irq-xen.c
 + */
 +static int pirq_via586_get(struct pci_dev *router, struct pci_dev *dev, int pirq)
 +{
-+      static const unsigned int pirqmap[4] = { 3, 2, 5, 1 };
++      static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 };
 +      return read_config_nybble(router, 0x55, pirqmap[pirq-1]);
 +}
 +
 +static int pirq_via586_set(struct pci_dev *router, struct pci_dev *dev, int pirq, int irq)
 +{
-+      static const unsigned int pirqmap[4] = { 3, 2, 5, 1 };
++      static const unsigned int pirqmap[5] = { 3, 2, 5, 1, 1 };
 +      write_config_nybble(router, 0x55, pirqmap[pirq-1], irq);
 +      return 1;
 +}
@@ -21323,6 +21750,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/pci/irq-xen.c
 +              case PCI_DEVICE_ID_INTEL_ICH8_2:
 +              case PCI_DEVICE_ID_INTEL_ICH8_3:
 +              case PCI_DEVICE_ID_INTEL_ICH8_4:
++              case PCI_DEVICE_ID_INTEL_ICH9_0:
++              case PCI_DEVICE_ID_INTEL_ICH9_1:
++              case PCI_DEVICE_ID_INTEL_ICH9_2:
++              case PCI_DEVICE_ID_INTEL_ICH9_3:
++              case PCI_DEVICE_ID_INTEL_ICH9_4:
++              case PCI_DEVICE_ID_INTEL_ICH9_5:
++              case PCI_DEVICE_ID_INTEL_ICH10_0:
++              case PCI_DEVICE_ID_INTEL_ICH10_1:
++              case PCI_DEVICE_ID_INTEL_ICH10_2:
++              case PCI_DEVICE_ID_INTEL_ICH10_3:
 +                      r->name = "PIIX/ICH";
 +                      r->get = pirq_piix_get;
 +                      r->set = pirq_piix_set;
@@ -21979,23 +22416,27 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/pci/irq-xen.c
 +
 +      return count;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/pci/Makefile linux-2.6.18-xen.hg/arch/i386/pci/Makefile
---- linux-2.6.18/arch/i386/pci/Makefile        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/pci/Makefile 2007-12-23 11:14:54.532526912 +0100
-@@ -4,6 +4,10 @@
- obj-$(CONFIG_PCI_MMCONFIG)    += mmconfig.o direct.o
- obj-$(CONFIG_PCI_DIRECT)      += direct.o
-+# pcifront should be after pcbios.o, mmconfig.o, and direct.o as it should only
-+# take over if direct access to the PCI bus is unavailable
-+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)     += pcifront.o
-+
- pci-y                         := fixup.o
- pci-$(CONFIG_ACPI)            += acpi.o
- pci-y                         += legacy.o irq.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/pci/pcifront.c linux-2.6.18-xen.hg/arch/i386/pci/pcifront.c
---- linux-2.6.18/arch/i386/pci/pcifront.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/i386/pci/pcifront.c       2007-12-23 11:14:54.539193935 +0100
+--- linux-2.6.18.8/arch/i386/pci/irq.c 2008-05-19 00:42:33.781223047 +0300
++++ linux-2.6.18-xen.hg/arch/i386/pci/irq.c    2008-05-19 00:33:03.992376276 +0300
+@@ -543,6 +543,16 @@
+               case PCI_DEVICE_ID_INTEL_ICH8_2:
+               case PCI_DEVICE_ID_INTEL_ICH8_3:
+               case PCI_DEVICE_ID_INTEL_ICH8_4:
++              case PCI_DEVICE_ID_INTEL_ICH9_0:
++              case PCI_DEVICE_ID_INTEL_ICH9_1:
++              case PCI_DEVICE_ID_INTEL_ICH9_2:
++              case PCI_DEVICE_ID_INTEL_ICH9_3:
++              case PCI_DEVICE_ID_INTEL_ICH9_4:
++              case PCI_DEVICE_ID_INTEL_ICH9_5:
++              case PCI_DEVICE_ID_INTEL_ICH10_0:
++              case PCI_DEVICE_ID_INTEL_ICH10_1:
++              case PCI_DEVICE_ID_INTEL_ICH10_2:
++              case PCI_DEVICE_ID_INTEL_ICH10_3:
+                       r->name = "PIIX/ICH";
+                       r->get = pirq_piix_get;
+                       r->set = pirq_piix_set;
+--- linux-2.6.18.8/arch/i386/pci/pcifront.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/pci/pcifront.c       2008-05-19 00:33:03.996376507 +0300
 @@ -0,0 +1,55 @@
 +/*
 + * PCI Frontend Stub - puts some "dummy" functions in to the Linux x86 PCI core
@@ -22052,9 +22493,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/pci/pcifront.c
 +}
 +
 +arch_initcall(pcifront_x86_stub_init);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/power/cpu.c linux-2.6.18-xen.hg/arch/i386/power/cpu.c
---- linux-2.6.18/arch/i386/power/cpu.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/power/cpu.c  2007-12-23 11:14:54.542527446 +0100
+--- linux-2.6.18.8/arch/i386/power/Makefile    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/power/Makefile       2008-05-19 00:33:03.996376507 +0300
+@@ -1,2 +1,4 @@
+-obj-$(CONFIG_PM)              += cpu.o
++obj-$(subst m,y,$(CONFIG_APM))        += cpu.o
++obj-$(CONFIG_SOFTWARE_SUSPEND)        += cpu.o
++obj-$(CONFIG_ACPI_SLEEP)      += cpu.o
+ obj-$(CONFIG_SOFTWARE_SUSPEND)        += swsusp.o
+--- linux-2.6.18.8/arch/i386/power/cpu.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/i386/power/cpu.c  2008-05-19 00:33:04.000376737 +0300
 @@ -62,11 +62,12 @@
  
  static void fix_processor_context(void)
@@ -22069,18 +22517,155 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/power/cpu.c li
        load_TR_desc();                         /* This does ltr */
        load_LDT(&current->active_mm->context); /* This does lldt */
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/i386/power/Makefile linux-2.6.18-xen.hg/arch/i386/power/Makefile
---- linux-2.6.18/arch/i386/power/Makefile      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/i386/power/Makefile       2007-12-23 11:14:54.542527446 +0100
-@@ -1,2 +1,4 @@
--obj-$(CONFIG_PM)              += cpu.o
-+obj-$(subst m,y,$(CONFIG_APM))        += cpu.o
-+obj-$(CONFIG_SOFTWARE_SUSPEND)        += cpu.o
-+obj-$(CONFIG_ACPI_SLEEP)      += cpu.o
- obj-$(CONFIG_SOFTWARE_SUSPEND)        += swsusp.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/hp/common/sba_iommu.c linux-2.6.18-xen.hg/arch/ia64/hp/common/sba_iommu.c
---- linux-2.6.18/arch/ia64/hp/common/sba_iommu.c       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/hp/common/sba_iommu.c        2007-12-23 11:14:54.552527964 +0100
+--- linux-2.6.18.8/arch/ia64/Kconfig   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/Kconfig      2008-05-19 00:33:04.000376737 +0300
+@@ -58,6 +58,28 @@
+       bool
+       default y
++config XEN
++      bool "Xen hypervisor support"
++      default y
++      select XEN_XENCOMM
++      help
++        Enable Xen hypervisor support.  Resulting kernel runs
++        both as a guest OS on Xen and natively on hardware.
++
++config XEN_IA64_EXPOSE_P2M
++      bool "Xen/IA64 exposure p2m table"
++      depends on XEN
++      default y
++      help
++        expose p2m from xen
++
++config XEN_IA64_EXPOSE_P2M_USE_DTR
++      bool "Xen/IA64 map p2m table with dtr"
++      depends on XEN_IA64_EXPOSE_P2M
++      default y
++      help
++        use dtr to map the exposed p2m table
++
+ config SCHED_NO_NO_OMIT_FRAME_POINTER
+       bool
+       default y
+@@ -133,6 +155,10 @@
+ config IA64_HP_SIM
+       bool "Ski-simulator"
++config IA64_XEN
++      bool "Xen guest"
++      depends on XEN
++
+ endchoice
+ choice
+@@ -431,6 +457,29 @@
+ source "drivers/sn/Kconfig"
++config KEXEC
++      bool "kexec system call (EXPERIMENTAL)"
++      depends on EXPERIMENTAL && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU) && !XEN_UNPRIVILEGED_GUEST
++      help
++        kexec is a system call that implements the ability to shutdown your
++        current kernel, and to start another kernel.  It is like a reboot
++        but it is indepedent of the system firmware.   And like a reboot
++        you can start any kernel with it, not just Linux.
++
++        The name comes from the similiarity to the exec system call.
++
++        It is an ongoing process to be certain the hardware in a machine
++        is properly shutdown, so do not be surprised if this code does not
++        initially work for you.  It may help to enable device hotplugging
++        support.  As of this writing the exact hardware interface is
++        strongly in flux, so no good recommendation can be made.
++
++config CRASH_DUMP
++        bool "kernel crash dumps (EXPERIMENTAL)"
++        depends on EXPERIMENTAL && IA64_MCA_RECOVERY && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU)
++        help
++          Generate crash dump after being started by kexec.
++
+ source "drivers/firmware/Kconfig"
+ source "fs/Kconfig.binfmt"
+@@ -465,6 +514,21 @@
+       bool
+       default PCI
++config XEN_PCIDEV_FRONTEND
++      bool "Xen PCI Frontend"
++      depends on PCI && XEN
++      default y
++      help
++        The PCI device frontend driver allows the kernel to import arbitrary
++        PCI devices from a PCI backend to support PCI driver domains.
++
++config XEN_PCIDEV_FE_DEBUG
++      bool "Xen PCI Frontend Debugging"
++      depends on XEN_PCIDEV_FRONTEND
++      default n
++      help
++        Enables some debug statements within the PCI Frontend.
++
+ source "drivers/pci/pcie/Kconfig"
+ source "drivers/pci/Kconfig"
+@@ -528,3 +592,16 @@
+ source "security/Kconfig"
+ source "crypto/Kconfig"
++
++#
++# override default values of drivers/xen/Kconfig
++#
++if XEN
++config XEN_SMPBOOT
++      default n
++
++config XEN_DEVMEM
++      default n
++endif
++
++source "drivers/xen/Kconfig"
+--- linux-2.6.18.8/arch/ia64/Makefile  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/Makefile     2008-05-19 00:33:04.000376737 +0300
+@@ -45,6 +45,12 @@
+ endif
+ CFLAGS += $(cflags-y)
++
++cppflags-$(CONFIG_XEN) += \
++      -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION)
++
++CPPFLAGS += $(cppflags-y)
++
+ head-y := arch/ia64/kernel/head.o arch/ia64/kernel/init_task.o
+ libs-y                                += arch/ia64/lib/
+@@ -54,7 +60,9 @@
+ core-$(CONFIG_IA64_GENERIC)   += arch/ia64/dig/
+ core-$(CONFIG_IA64_HP_ZX1)    += arch/ia64/dig/
+ core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/
++core-$(CONFIG_IA64_XEN)               += arch/ia64/dig/
+ core-$(CONFIG_IA64_SGI_SN2)   += arch/ia64/sn/
++core-$(CONFIG_XEN)            += arch/ia64/xen/
+ drivers-$(CONFIG_PCI)         += arch/ia64/pci/
+ drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/
+@@ -87,8 +95,8 @@
+ boot: lib/lib.a vmlinux
+       $(Q)$(MAKE) $(build)=$(boot) $@
+-install: vmlinux.gz
+-      sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) $< System.map "$(INSTALL_PATH)"
++install:
++      -yes | sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)"
+ define archhelp
+   echo '* compressed  - Build compressed kernel image'
+--- linux-2.6.18.8/arch/ia64/hp/common/sba_iommu.c     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/hp/common/sba_iommu.c        2008-05-19 00:33:04.016377660 +0300
 @@ -42,6 +42,11 @@
  #include <asm/system.h>               /* wmb() */
  
@@ -22416,121 +23001,81 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/hp/common/sba_
  
                DBG_INIT("%s() prefetch spill addr: 0x%lx\n", __FUNCTION__, prefetch_spill_page);
        }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/Kconfig linux-2.6.18-xen.hg/arch/ia64/Kconfig
---- linux-2.6.18/arch/ia64/Kconfig     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/Kconfig      2007-12-23 11:14:54.542527446 +0100
-@@ -58,6 +58,28 @@
-       bool
-       default y
-+config XEN
-+      bool "Xen hypervisor support"
-+      default y
-+      select XEN_XENCOMM
-+      help
-+        Enable Xen hypervisor support.  Resulting kernel runs
-+        both as a guest OS on Xen and natively on hardware.
-+
-+config XEN_IA64_EXPOSE_P2M
-+      bool "Xen/IA64 exposure p2m table"
-+      depends on XEN
-+      default y
-+      help
-+        expose p2m from xen
-+
-+config XEN_IA64_EXPOSE_P2M_USE_DTR
-+      bool "Xen/IA64 map p2m table with dtr"
-+      depends on XEN_IA64_EXPOSE_P2M
-+      default y
-+      help
-+        use dtr to map the exposed p2m table
+--- linux-2.6.18.8/arch/ia64/kernel/Makefile   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/Makefile      2008-05-19 00:33:04.320395183 +0300
+@@ -28,6 +28,8 @@
+ obj-$(CONFIG_CPU_FREQ)                += cpufreq/
+ obj-$(CONFIG_IA64_MCA_RECOVERY)       += mca_recovery.o
+ obj-$(CONFIG_KPROBES)         += kprobes.o jprobes.o
++obj-$(CONFIG_KEXEC)           += machine_kexec.o relocate_kernel.o crash.o
++obj-$(CONFIG_CRASH_DUMP)      += crash_dump.o
+ obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
+ obj-$(CONFIG_AUDIT)           += audit.o
+ mca_recovery-y                        += mca_drv.o mca_drv_asm.o
+@@ -61,3 +63,61 @@
+ # We must build gate.so before we can assemble it.
+ # Note: kbuild does not track this dependency due to usage of .incbin
+ $(obj)/gate-data.o: $(obj)/gate.so
 +
- config SCHED_NO_NO_OMIT_FRAME_POINTER
-       bool
-       default y
-@@ -133,6 +155,10 @@
- config IA64_HP_SIM
-       bool "Ski-simulator"
-+config IA64_XEN
-+      bool "Xen guest"
-+      depends on XEN
++#
++# gate page paravirtualization for xen
++#
++obj-$(CONFIG_XEN) += xengate-data.o
 +
- endchoice
- choice
-@@ -431,6 +457,29 @@
- source "drivers/sn/Kconfig"
-+config KEXEC
-+      bool "kexec system call (EXPERIMENTAL)"
-+      depends on EXPERIMENTAL && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU)
-+      help
-+        kexec is a system call that implements the ability to shutdown your
-+        current kernel, and to start another kernel.  It is like a reboot
-+        but it is indepedent of the system firmware.   And like a reboot
-+        you can start any kernel with it, not just Linux.
++ifeq ($(CONFIG_XEN), y)
++# The gate DSO image is built using a special linker script.
++targets += xengate.so xengate-syms.o
++endif
 +
-+        The name comes from the similiarity to the exec system call.
++extra-$(CONFIG_XEN) += xengate.so xengate.lds xengate.o
 +
-+        It is an ongoing process to be certain the hardware in a machine
-+        is properly shutdown, so do not be surprised if this code does not
-+        initially work for you.  It may help to enable device hotplugging
-+        support.  As of this writing the exact hardware interface is
-+        strongly in flux, so no good recommendation can be made.
++AFLAGS_xengate.o += -D__XEN_IA64_VDSO_PARAVIRT
++$(obj)/xengate.o: $(src)/gate.S FORCE
++      $(call if_changed_dep,as_o_S)
 +
-+config CRASH_DUMP
-+        bool "kernel crash dumps (EXPERIMENTAL)"
-+        depends on EXPERIMENTAL && IA64_MCA_RECOVERY && !IA64_HP_SIM && (!SMP || HOTPLUG_CPU)
-+        help
-+          Generate crash dump after being started by kexec.
++CPPFLAGS_xengate.lds := -P -C -U$(ARCH) -D__XEN_IA64_VDSO_PARAVIRT
++$(obj)/xengate.lds: $(src)/gate.lds.S
++      $(call if_changed_dep,cpp_lds_S)
 +
- source "drivers/firmware/Kconfig"
- source "fs/Kconfig.binfmt"
-@@ -465,6 +514,21 @@
-       bool
-       default PCI
-+config XEN_PCIDEV_FRONTEND
-+      bool "Xen PCI Frontend"
-+      depends on PCI && XEN
-+      default y
-+      help
-+        The PCI device frontend driver allows the kernel to import arbitrary
-+        PCI devices from a PCI backend to support PCI driver domains.
++GATECFLAGS_xengate.so = -shared -s -Wl,-soname=linux-gate.so.1 \
++                   $(call ld-option, -Wl$(comma)--hash-style=sysv)
++$(obj)/xengate.so: $(obj)/xengate.lds $(obj)/xengate.o FORCE
++      $(call if_changed,gate)
 +
-+config XEN_PCIDEV_FE_DEBUG
-+      bool "Xen PCI Frontend Debugging"
-+      depends on XEN_PCIDEV_FRONTEND
-+      default n
-+      help
-+        Enables some debug statements within the PCI Frontend.
++ifeq ($(CONFIG_XEN), y)
++$(obj)/built-in.o: $(obj)/xengate-syms.o
++$(obj)/built-in.o: ld_flags += -R $(obj)/xengate-syms.o
++$(obj)/mca_recovery.o: $(obj)/gate-syms.o $(obj)/xengate-syms.o
++endif
 +
- source "drivers/pci/pcie/Kconfig"
- source "drivers/pci/Kconfig"
-@@ -528,3 +592,16 @@
- source "security/Kconfig"
- source "crypto/Kconfig"
++GATECFLAGS_xengate-syms.o = -r
++$(obj)/xengate-syms.o: $(obj)/xengate.lds $(obj)/xengate.o FORCE
++      $(call if_changed,gate)
++$(obj)/xengate-data.o: $(obj)/xengate.so
 +
 +#
-+# override default values of drivers/xen/Kconfig
++# .tmp_gate.o to calculate padding size for __kernel_syscall_via_epc
 +#
-+if XEN
-+config XEN_SMPBOOT
-+      default n
++extra-$(CONFIG_XEN) += gate-skip.s .tmp_gate.o
 +
-+config XEN_DEVMEM
-+      default n
++ifeq ($(CONFIG_XEN), y)
++AFLAGS_gate.o += -D__KERNEL_SYSCALL_VIA_EPC_PADDING
++$(obj)/gate.o: $(obj)/gate-skip.s FORCE
 +endif
 +
-+source "drivers/xen/Kconfig"
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/acpi.c linux-2.6.18-xen.hg/arch/ia64/kernel/acpi.c
---- linux-2.6.18/arch/ia64/kernel/acpi.c       2007-12-23 11:26:51.003453595 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/acpi.c        2007-12-23 11:14:54.572529022 +0100
++$(obj)/.tmp_gate.o: $(src)/gate.S FORCE
++      $(call if_changed_dep,as_o_S)
++
++quiet_cmd_gate_size = GATE_SIZE       $@
++      cmd_gate_size = $(NM) --extern-only --print-size $(obj)/xengate.o | \
++      $(AWK) '/__kernel_syscall_via_epc/{printf "\t.skip 0x"$$2" - "}' > $@; \
++      $(NM) --extern-only --print-size $(obj)/.tmp_gate.o | \
++      $(AWK) '/__kernel_syscall_via_epc/{printf "0x"$$2"\n"}' >> $@
++
++$(obj)/gate-skip.s: $(obj)/xengate.o $(obj)/.tmp_gate.o FORCE
++      $(call if_changed,gate_size)
+--- linux-2.6.18.8/arch/ia64/kernel/acpi.c     2008-05-19 00:42:33.781223047 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/acpi.c        2008-05-19 00:33:04.324395414 +0300
 @@ -109,6 +109,10 @@
                return "hpzx1";
        } else if (!strcmp(hdr->oem_id, "SGI")) {
@@ -22551,9 +23096,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/acpi.c
  # else
  #     error Unknown platform.  Fix acpi.c.
  # endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/asm-offsets.c linux-2.6.18-xen.hg/arch/ia64/kernel/asm-offsets.c
---- linux-2.6.18/arch/ia64/kernel/asm-offsets.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/asm-offsets.c 2007-12-23 11:14:54.572529022 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/asm-offsets.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/asm-offsets.c 2008-05-19 00:33:04.328395644 +0300
 @@ -268,4 +268,29 @@
        DEFINE(IA64_TIME_SOURCE_MMIO64, TIME_SOURCE_MMIO64);
        DEFINE(IA64_TIME_SOURCE_MMIO32, TIME_SOURCE_MMIO32);
@@ -22584,9 +23128,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/asm-off
 +      DEFINE_MAPPED_REG_OFS(XSI_B1NATS_OFS, vnat);    
 +#endif /* CONFIG_XEN */
  }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/crash.c linux-2.6.18-xen.hg/arch/ia64/kernel/crash.c
---- linux-2.6.18/arch/ia64/kernel/crash.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/crash.c       2007-12-23 11:14:54.575862524 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/crash.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/crash.c       2008-05-19 00:33:04.336396106 +0300
 @@ -0,0 +1,222 @@
 +/*
 + * arch/ia64/kernel/crash.c
@@ -22810,9 +23353,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/crash.c
 +
 +__initcall(machine_crash_setup);
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/crash_dump.c linux-2.6.18-xen.hg/arch/ia64/kernel/crash_dump.c
---- linux-2.6.18/arch/ia64/kernel/crash_dump.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/crash_dump.c  2007-12-23 11:14:54.575862524 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/crash_dump.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/crash_dump.c  2008-05-19 00:33:04.336396106 +0300
 @@ -0,0 +1,48 @@
 +/*
 + *    kernel/crash_dump.c - Memory preserving reboot related code.
@@ -22862,9 +23404,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/crash_d
 +      return csize;
 +}
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/efi.c linux-2.6.18-xen.hg/arch/ia64/kernel/efi.c
---- linux-2.6.18/arch/ia64/kernel/efi.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/efi.c 2007-12-23 11:14:54.579196027 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/efi.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/efi.c 2008-05-19 00:33:04.336396106 +0300
 @@ -26,6 +26,7 @@
  #include <linux/types.h>
  #include <linux/time.h>
@@ -23109,9 +23650,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/efi.c l
 +  return ~0UL;
 +}
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/entry.S linux-2.6.18-xen.hg/arch/ia64/kernel/entry.S
---- linux-2.6.18/arch/ia64/kernel/entry.S      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/entry.S       2007-12-23 11:14:54.579196027 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/entry.S    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/entry.S       2008-05-19 00:33:04.340396336 +0300
 @@ -180,7 +180,7 @@
   *    called.  The code starting at .map relies on this.  The rest of the code
   *    doesn't care about the interrupt masking status.
@@ -23258,9 +23798,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/entry.S
        data8 sys_ni_syscall                    // reserved for vserver
        data8 sys_waitid                        // 1270
        data8 sys_add_key
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/fsys.S linux-2.6.18-xen.hg/arch/ia64/kernel/fsys.S
---- linux-2.6.18/arch/ia64/kernel/fsys.S       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/fsys.S        2007-12-23 11:14:54.582529532 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/fsys.S     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/fsys.S        2008-05-19 00:33:04.340396336 +0300
 @@ -516,11 +516,34 @@
        adds r17=-1024,r15
        movl r14=sys_call_table
@@ -23322,37 +23861,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/fsys.S
        cmp.eq p8,p0=r3,r0                      // A
  (p10) br.cond.spnt.many ia64_ret_from_syscall // B    return if bad call-frame or r15 is a NaT
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/gate.lds.S linux-2.6.18-xen.hg/arch/ia64/kernel/gate.lds.S
---- linux-2.6.18/arch/ia64/kernel/gate.lds.S   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/gate.lds.S    2007-12-23 11:14:54.582529532 +0100
-@@ -28,6 +28,24 @@
-   . = GATE_ADDR + 0x500;
-   .data.patch                 : {
-+#ifdef __XEN_IA64_VDSO_PARAVIRT
-+#define __start_gate_mckinley_e9_patchlist \
-+      __start_gate_mckinley_e9_patchlist_xen
-+#define __end_gate_mckinley_e9_patchlist \
-+      __end_gate_mckinley_e9_patchlist_xen
-+#define __start_gate_vtop_patchlist \
-+      __start_gate_vtop_patchlist_xen
-+#define __end_gate_vtop_patchlist \
-+      __end_gate_vtop_patchlist_xen
-+#define __start_gate_fsyscall_patchlist \
-+      __start_gate_fsyscall_patchlist_xen
-+#define __end_gate_fsyscall_patchlist \
-+      __end_gate_fsyscall_patchlist_xen
-+#define __start_gate_brl_fsys_bubble_down_patchlist \
-+      __start_gate_brl_fsys_bubble_down_patchlist_xen
-+#define __end_gate_brl_fsys_bubble_down_patchlist \
-+      __end_gate_brl_fsys_bubble_down_patchlist_xen
-+#endif
-                                   __start_gate_mckinley_e9_patchlist = .;
-                                   *(.data.patch.mckinley_e9)
-                                   __end_gate_mckinley_e9_patchlist = .;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/gate.S linux-2.6.18-xen.hg/arch/ia64/kernel/gate.S
---- linux-2.6.18/arch/ia64/kernel/gate.S       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/gate.S        2007-12-23 11:14:54.582529532 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/gate.S     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/gate.S        2008-05-19 00:33:04.344396567 +0300
 @@ -32,102 +32,6 @@
  [1:](pr)brl.cond.sptk 0;                              \
        .xdata4 ".data.patch.brl_fsys_bubble_down", 1b-.
@@ -23611,9 +24121,35 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/gate.S
 +.include "arch/ia64/kernel/gate-skip.s"
 +#endif
 +END(__kernel_syscall_via_epc)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/head.S linux-2.6.18-xen.hg/arch/ia64/kernel/head.S
---- linux-2.6.18/arch/ia64/kernel/head.S       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/head.S        2007-12-23 11:14:54.585863043 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/gate.lds.S 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/gate.lds.S    2008-05-19 00:33:04.344396567 +0300
+@@ -28,6 +28,24 @@
+   . = GATE_ADDR + 0x500;
+   .data.patch                 : {
++#ifdef __XEN_IA64_VDSO_PARAVIRT
++#define __start_gate_mckinley_e9_patchlist \
++      __start_gate_mckinley_e9_patchlist_xen
++#define __end_gate_mckinley_e9_patchlist \
++      __end_gate_mckinley_e9_patchlist_xen
++#define __start_gate_vtop_patchlist \
++      __start_gate_vtop_patchlist_xen
++#define __end_gate_vtop_patchlist \
++      __end_gate_vtop_patchlist_xen
++#define __start_gate_fsyscall_patchlist \
++      __start_gate_fsyscall_patchlist_xen
++#define __end_gate_fsyscall_patchlist \
++      __end_gate_fsyscall_patchlist_xen
++#define __start_gate_brl_fsys_bubble_down_patchlist \
++      __start_gate_brl_fsys_bubble_down_patchlist_xen
++#define __end_gate_brl_fsys_bubble_down_patchlist \
++      __end_gate_brl_fsys_bubble_down_patchlist_xen
++#endif
+                                   __start_gate_mckinley_e9_patchlist = .;
+                                   *(.data.patch.mckinley_e9)
+                                   __end_gate_mckinley_e9_patchlist = .;
+--- linux-2.6.18.8/arch/ia64/kernel/head.S     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/head.S        2008-05-19 00:33:04.348396797 +0300
 @@ -367,6 +367,12 @@
        ;;
  (isBP)        st8 [r2]=r28            // save the address of the boot param area passed by the bootloader
@@ -23627,9 +24163,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/head.S
  #ifdef CONFIG_SMP
  (isAP)        br.call.sptk.many rp=start_secondary
  .ret0:
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/iosapic.c linux-2.6.18-xen.hg/arch/ia64/kernel/iosapic.c
---- linux-2.6.18/arch/ia64/kernel/iosapic.c    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/iosapic.c     2007-12-23 11:14:54.585863043 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/iosapic.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/iosapic.c     2008-05-19 00:33:04.348396797 +0300
 @@ -159,6 +159,75 @@
  static int iosapic_kmalloc_ok;
  static LIST_HEAD(free_rte_list);
@@ -23754,9 +24289,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/iosapic
        if (pcat_compat) {
                /*
                 * Disable the compatibility mode interrupts (8259 style),
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/irq_ia64.c linux-2.6.18-xen.hg/arch/ia64/kernel/irq_ia64.c
---- linux-2.6.18/arch/ia64/kernel/irq_ia64.c   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/irq_ia64.c    2007-12-23 11:14:54.585863043 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/irq_ia64.c 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/irq_ia64.c    2008-05-19 00:33:04.352397028 +0300
 @@ -30,6 +30,9 @@
  #include <linux/smp_lock.h>
  #include <linux/threads.h>
@@ -24161,10 +24695,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/irq_ia6
  #ifdef CONFIG_SMP
        phys_cpu_id = cpu_physical_id(cpu);
  #else
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/machine_kexec.c linux-2.6.18-xen.hg/arch/ia64/kernel/machine_kexec.c
---- linux-2.6.18/arch/ia64/kernel/machine_kexec.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/machine_kexec.c       2007-12-23 11:14:54.589196561 +0100
-@@ -0,0 +1,145 @@
+--- linux-2.6.18.8/arch/ia64/kernel/machine_kexec.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/machine_kexec.c       2008-05-19 00:33:04.356397258 +0300
+@@ -0,0 +1,204 @@
 +/*
 + * arch/ia64/kernel/machine_kexec.c
 + *
@@ -24309,84 +24842,68 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/machine
 +      xki->reboot_code_buffer =
 +              kexec_page_to_pfn(image->control_code_page) << PAGE_SHIFT;
 +}
-+#endif /* CONFIG_XEN */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/Makefile linux-2.6.18-xen.hg/arch/ia64/kernel/Makefile
---- linux-2.6.18/arch/ia64/kernel/Makefile     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/Makefile      2007-12-23 11:14:54.572529022 +0100
-@@ -28,6 +28,8 @@
- obj-$(CONFIG_CPU_FREQ)                += cpufreq/
- obj-$(CONFIG_IA64_MCA_RECOVERY)       += mca_recovery.o
- obj-$(CONFIG_KPROBES)         += kprobes.o jprobes.o
-+obj-$(CONFIG_KEXEC)           += machine_kexec.o relocate_kernel.o crash.o
-+obj-$(CONFIG_CRASH_DUMP)      += crash_dump.o
- obj-$(CONFIG_IA64_UNCACHED_ALLOCATOR) += uncached.o
- obj-$(CONFIG_AUDIT)           += audit.o
- mca_recovery-y                        += mca_drv.o mca_drv_asm.o
-@@ -61,3 +63,61 @@
- # We must build gate.so before we can assemble it.
- # Note: kbuild does not track this dependency due to usage of .incbin
- $(obj)/gate-data.o: $(obj)/gate.so
 +
-+#
-+# gate page paravirtualization for xen
-+#
-+obj-$(CONFIG_XEN) += xengate-data.o
++static struct resource xen_hypervisor_heap_res;
 +
-+ifeq ($(CONFIG_XEN), y)
-+# The gate DSO image is built using a special linker script.
-+targets += xengate.so xengate-syms.o
-+endif
++int __init machine_kexec_setup_resources(struct resource *hypervisor,
++                                       struct resource *phys_cpus,
++                                       int nr_phys_cpus)
++{
++      xen_kexec_range_t range;
++      int k;
 +
-+extra-$(CONFIG_XEN) += xengate.so xengate.lds xengate.o
++      /* fill in xen_hypervisor_heap_res with hypervisor heap
++       * machine address range
++       */
 +
-+AFLAGS_xengate.o += -D__XEN_IA64_VDSO_PARAVIRT
-+$(obj)/xengate.o: $(src)/gate.S FORCE
-+      $(call if_changed_dep,as_o_S)
++      memset(&range, 0, sizeof(range));
++      range.range = KEXEC_RANGE_MA_XENHEAP;
 +
-+CPPFLAGS_xengate.lds := -P -C -U$(ARCH) -D__XEN_IA64_VDSO_PARAVIRT
-+$(obj)/xengate.lds: $(src)/gate.lds.S
-+      $(call if_changed_dep,cpp_lds_S)
++      if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
++              return -1;
 +
-+GATECFLAGS_xengate.so = -shared -s -Wl,-soname=linux-gate.so.1 \
-+                   $(call ld-option, -Wl$(comma)--hash-style=sysv)
-+$(obj)/xengate.so: $(obj)/xengate.lds $(obj)/xengate.o FORCE
-+      $(call if_changed,gate)
++      xen_hypervisor_heap_res.name = "Hypervisor heap";
++      xen_hypervisor_heap_res.start = range.start;
++      xen_hypervisor_heap_res.end = range.start + range.size - 1;
++      xen_hypervisor_heap_res.flags = IORESOURCE_BUSY | IORESOURCE_MEM;
 +
-+ifeq ($(CONFIG_XEN), y)
-+$(obj)/built-in.o: $(obj)/xengate-syms.o
-+$(obj)/built-in.o: ld_flags += -R $(obj)/xengate-syms.o
-+$(obj)/mca_recovery.o: $(obj)/gate-syms.o $(obj)/xengate-syms.o
-+endif
++      /* The per-cpu crash note  resources belong inside the
++       * hypervisor heap resource */
++      for (k = 0; k < nr_phys_cpus; k++)
++              request_resource(&xen_hypervisor_heap_res, phys_cpus + k);
 +
-+GATECFLAGS_xengate-syms.o = -r
-+$(obj)/xengate-syms.o: $(obj)/xengate.lds $(obj)/xengate.o FORCE
-+      $(call if_changed,gate)
-+$(obj)/xengate-data.o: $(obj)/xengate.so
++      /* fill in efi_memmap_res with EFI memmap machine address range */
 +
-+#
-+# .tmp_gate.o to calculate padding size for __kernel_syscall_via_epc
-+#
-+extra-$(CONFIG_XEN) += gate-skip.s .tmp_gate.o
++      memset(&range, 0, sizeof(range));
++      range.range = KEXEC_RANGE_MA_EFI_MEMMAP;
 +
-+ifeq ($(CONFIG_XEN), y)
-+AFLAGS_gate.o += -D__KERNEL_SYSCALL_VIA_EPC_PADDING
-+$(obj)/gate.o: $(obj)/gate-skip.s FORCE
-+endif
++      if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
++              return -1;
 +
-+$(obj)/.tmp_gate.o: $(src)/gate.S FORCE
-+      $(call if_changed_dep,as_o_S)
++      efi_memmap_res.start = range.start;
++      efi_memmap_res.end = range.start + range.size - 1;
 +
-+quiet_cmd_gate_size = GATE_SIZE       $@
-+      cmd_gate_size = $(NM) --extern-only --print-size $(obj)/xengate.o | \
-+      $(AWK) '/__kernel_syscall_via_epc/{printf "\t.skip 0x"$$2" - "}' > $@; \
-+      $(NM) --extern-only --print-size $(obj)/.tmp_gate.o | \
-+      $(AWK) '/__kernel_syscall_via_epc/{printf "0x"$$2"\n"}' >> $@
++      /* fill in boot_param_res with boot parameter machine address range */
 +
-+$(obj)/gate-skip.s: $(obj)/xengate.o $(obj)/.tmp_gate.o FORCE
-+      $(call if_changed,gate_size)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/mca.c linux-2.6.18-xen.hg/arch/ia64/kernel/mca.c
---- linux-2.6.18/arch/ia64/kernel/mca.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/mca.c 2007-12-23 11:14:54.592530075 +0100
++      memset(&range, 0, sizeof(range));
++      range.range = KEXEC_RANGE_MA_BOOT_PARAM;
++
++      if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
++              return -1;
++
++      boot_param_res.start = range.start;
++      boot_param_res.end = range.start + range.size - 1;
++
++      return 0;
++}
++
++void machine_kexec_register_resources(struct resource *res)
++{
++      request_resource(res, &xen_hypervisor_heap_res);
++}
++#endif /* CONFIG_XEN */
+--- linux-2.6.18.8/arch/ia64/kernel/mca.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/mca.c 2008-05-19 00:33:04.360397489 +0300
 @@ -79,6 +79,7 @@
  #include <asm/system.h>
  #include <asm/sal.h>
@@ -24441,9 +24958,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/mca.c l
        }
        if (notify_die(DIE_MCA_MONARCH_LEAVE, "MCA", regs, (long)&nd, 0, recover)
                        == NOTIFY_STOP)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/pal.S linux-2.6.18-xen.hg/arch/ia64/kernel/pal.S
---- linux-2.6.18/arch/ia64/kernel/pal.S        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/pal.S 2007-12-23 11:14:54.595863584 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/pal.S      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/pal.S 2008-05-19 00:33:04.388399103 +0300
 @@ -16,6 +16,7 @@
  #include <asm/processor.h>
  
@@ -24470,9 +24986,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/pal.S l
  
  /*
   * Make a PAL call using the stacked registers calling convention.
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/patch.c linux-2.6.18-xen.hg/arch/ia64/kernel/patch.c
---- linux-2.6.18/arch/ia64/kernel/patch.c      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/patch.c       2007-12-23 11:14:54.599197091 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/patch.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/patch.c       2008-05-19 00:33:04.392399334 +0300
 @@ -184,9 +184,37 @@
        ia64_srlz_i();
  }
@@ -24511,9 +25026,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/patch.c
  #     define START(name)      ((unsigned long) __start_gate_##name##_patchlist)
  #     define END(name)        ((unsigned long)__end_gate_##name##_patchlist)
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/perfmon.c linux-2.6.18-xen.hg/arch/ia64/kernel/perfmon.c
---- linux-2.6.18/arch/ia64/kernel/perfmon.c    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/perfmon.c     2007-12-23 11:14:54.599197091 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/perfmon.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/perfmon.c     2008-05-19 00:33:04.396399564 +0300
 @@ -52,6 +52,31 @@
  #include <asm/delay.h>
  
@@ -24711,10 +25225,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/perfmon
        DPRINT(("ctx_state=%d task [%d]\n", ctx->ctx_state, task ? task->pid : -1));
  
        prev_state = ctx->ctx_state;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/relocate_kernel.S linux-2.6.18-xen.hg/arch/ia64/kernel/relocate_kernel.S
---- linux-2.6.18/arch/ia64/kernel/relocate_kernel.S    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/relocate_kernel.S     2007-12-23 11:14:54.605864096 +0100
-@@ -0,0 +1,380 @@
+--- linux-2.6.18.8/arch/ia64/kernel/relocate_kernel.S  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/relocate_kernel.S     2008-05-19 00:33:04.452402792 +0300
+@@ -0,0 +1,346 @@
 +/*
 + * arch/ia64/kernel/relocate_kernel.S
 + *
@@ -24737,11 +25250,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/relocat
 +        */
 +GLOBAL_ENTRY(relocate_new_kernel)
 +      .prologue
-+#ifdef CONFIG_XEN
-+      alloc r31=ar.pfs,8,0,0,0
-+#else
 +      alloc r31=ar.pfs,4,0,0,0
-+#endif
 +        .body
 +.reloc_entry:
 +{
@@ -24754,11 +25263,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/relocat
 +        srlz.i
 +}
 +      ;;
-+#ifdef CONFIG_XEN
-+      dep r2=0,r2,60,4                //to physical address
-+#else
 +      dep r2=0,r2,61,3                //to physical address
-+#endif
 +      ;;
 +      //first switch to physical mode
 +      add r3=1f-.reloc_entry, r2
@@ -24783,18 +25288,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/relocat
 +      //physical mode code begin
 +      mov b6=in1
 +#ifdef CONFIG_XEN
-+      dep r28=0,in2,60,4      //to physical address
++      mov r28=in2             //already a physical address
 +#else
 +      dep r28=0,in2,61,3      //to physical address
-+#endif
 +
 +      // purge all TC entries
 +#define O(member)       IA64_CPUINFO_##member##_OFFSET
-+#ifdef CONFIG_XEN
-+      mov r2=in4                      // load phys addr of cpu_info into r2
-+#else
 +        GET_THIS_PADDR(r2, cpu_info)    // load phys addr of cpu_info into r2
-+#endif
 +        ;;
 +        addl r17=O(PTCE_STRIDE),r2
 +        addl r2=O(PTCE_BASE),r2
@@ -24828,11 +25328,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/relocat
 +        srlz.i
 +        ;;
 +      //purge TR entry for kernel text and data
-+#ifdef CONFIG_XEN
-+      mov r16=in5
-+#else
 +        movl r16=KERNEL_START
-+#endif
 +        mov r18=KERNEL_TR_PAGE_SHIFT<<2
 +        ;;
 +        ptr.i r16, r18
@@ -24863,11 +25359,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/relocat
 +        mov r16=IA64_KR(CURRENT_STACK)
 +        ;;
 +        shl r16=r16,IA64_GRANULE_SHIFT
-+#ifdef CONFIG_XEN
-+      mov r19=in6
-+#else
 +        movl r19=PAGE_OFFSET
-+#endif
 +        ;;
 +        add r16=r19,r16
 +        mov r18=IA64_GRANULE_SHIFT<<2
@@ -24876,20 +25368,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/relocat
 +        ;;
 +        srlz.i
 +      ;;
-+
-+#ifdef XEN
-+      /* XXX: Is this neccessary ??? */
-+      // purge TR entry for VHPT
-+      mov r16=in7
-+      ;;
-+      dep r16=0,r16,0,IA64_GRANULE_SHIFT
-+      mov r18=IA64_GRANULE_SHIFT<<2
-+        ;;
-+        ptr.d r16,r18
-+        ;;
-+        srlz.i
-+      ;;
-+#endif
++#endif /* ! CONFIG_XEN */
 +
 +      //copy segments
 +      movl r16=PAGE_MASK
@@ -25095,9 +25574,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/relocat
 +END(ia64_dump_cpu_regs)
 +
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/salinfo.c linux-2.6.18-xen.hg/arch/ia64/kernel/salinfo.c
---- linux-2.6.18/arch/ia64/kernel/salinfo.c    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/salinfo.c     2007-12-23 11:14:54.609197603 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/salinfo.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/salinfo.c     2008-05-19 00:33:04.452402792 +0300
 @@ -375,6 +375,25 @@
                data->open = 0;
                return -ENOMEM;
@@ -25155,9 +25633,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/salinfo
                vfree(data->log_buffer);
                vfree(data->oemdata);
                data->log_buffer = NULL;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/setup.c linux-2.6.18-xen.hg/arch/ia64/kernel/setup.c
---- linux-2.6.18/arch/ia64/kernel/setup.c      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/setup.c       2007-12-23 11:14:54.609197603 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/setup.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/setup.c       2008-05-19 00:33:04.456403023 +0300
 @@ -43,6 +43,8 @@
  #include <linux/initrd.h>
  #include <linux/pm.h>
@@ -25273,15 +25750,15 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/setup.c
 +                              }
 +                      }
 +              }
-+#ifdef CONFIG_XEN
-+              }
-+#endif
 +              efi_memmap_res.start = ia64_boot_param->efi_memmap;
 +                efi_memmap_res.end = efi_memmap_res.start +
 +                        ia64_boot_param->efi_memmap_size;
 +                boot_param_res.start = kexec_virt_to_phys(ia64_boot_param);
 +                boot_param_res.end = boot_param_res.start +
 +                        sizeof(*ia64_boot_param);
++#ifdef CONFIG_XEN
++              }
++#endif
 +      }
 +#endif
        /* end of memory marker */
@@ -25446,9 +25923,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/setup.c
        pm_idle = default_idle;
  }
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/smp.c linux-2.6.18-xen.hg/arch/ia64/kernel/smp.c
---- linux-2.6.18/arch/ia64/kernel/smp.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/smp.c 2007-12-23 11:14:54.612531114 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/smp.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/smp.c 2008-05-19 00:33:04.460403253 +0300
 @@ -30,6 +30,7 @@
  #include <linux/delay.h>
  #include <linux/efi.h>
@@ -25531,9 +26007,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/smp.c l
        call_data = &data;
        mb();   /* ensure store to call_data precedes setting of IPI_CALL_FUNC */
        send_IPI_allbutself(IPI_CALL_FUNC);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/time.c linux-2.6.18-xen.hg/arch/ia64/kernel/time.c
---- linux-2.6.18/arch/ia64/kernel/time.c       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/time.c        2007-12-23 11:14:54.612531114 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/time.c     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/time.c        2008-05-19 00:33:04.464403484 +0300
 @@ -29,6 +29,14 @@
  #include <asm/sections.h>
  #include <asm/system.h>
@@ -25781,9 +26256,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/time.c
        /* Setup the CPU local timer tick */
        ia64_cpu_local_tick();
  }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/vmlinux.lds.S linux-2.6.18-xen.hg/arch/ia64/kernel/vmlinux.lds.S
---- linux-2.6.18/arch/ia64/kernel/vmlinux.lds.S        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/vmlinux.lds.S 2007-12-23 11:14:54.619198137 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/vmlinux.lds.S      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/vmlinux.lds.S 2008-05-19 00:33:04.472403945 +0300
 @@ -183,6 +183,12 @@
          __start_gate_section = .;
          *(.data.gate)
@@ -25797,58 +26271,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/vmlinux
        }
    . = ALIGN(PAGE_SIZE);               /* make sure the gate page doesn't expose kernel data */
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/kernel/xengate-data.S linux-2.6.18-xen.hg/arch/ia64/kernel/xengate-data.S
---- linux-2.6.18/arch/ia64/kernel/xengate-data.S       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/kernel/xengate-data.S        2007-12-23 11:14:54.619198137 +0100
+--- linux-2.6.18.8/arch/ia64/kernel/xengate-data.S     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/kernel/xengate-data.S        2008-05-19 00:33:04.472403945 +0300
 @@ -0,0 +1,3 @@
 +      .section .data.gate.xen, "aw"
 +
 +      .incbin "arch/ia64/kernel/xengate.so"
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/Makefile linux-2.6.18-xen.hg/arch/ia64/Makefile
---- linux-2.6.18/arch/ia64/Makefile    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/Makefile     2007-12-23 11:14:54.542527446 +0100
-@@ -45,6 +45,12 @@
- endif
- CFLAGS += $(cflags-y)
-+
-+cppflags-$(CONFIG_XEN) += \
-+      -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION)
-+
-+CPPFLAGS += $(cppflags-y)
-+
- head-y := arch/ia64/kernel/head.o arch/ia64/kernel/init_task.o
- libs-y                                += arch/ia64/lib/
-@@ -54,7 +60,9 @@
- core-$(CONFIG_IA64_GENERIC)   += arch/ia64/dig/
- core-$(CONFIG_IA64_HP_ZX1)    += arch/ia64/dig/
- core-$(CONFIG_IA64_HP_ZX1_SWIOTLB) += arch/ia64/dig/
-+core-$(CONFIG_IA64_XEN)               += arch/ia64/dig/
- core-$(CONFIG_IA64_SGI_SN2)   += arch/ia64/sn/
-+core-$(CONFIG_XEN)            += arch/ia64/xen/
- drivers-$(CONFIG_PCI)         += arch/ia64/pci/
- drivers-$(CONFIG_IA64_HP_SIM) += arch/ia64/hp/sim/
-@@ -87,8 +95,8 @@
- boot: lib/lib.a vmlinux
-       $(Q)$(MAKE) $(build)=$(boot) $@
--install: vmlinux.gz
--      sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) $< System.map "$(INSTALL_PATH)"
-+install:
-+      -yes | sh $(srctree)/arch/ia64/install.sh $(KERNELRELEASE) vmlinux.gz System.map "$(INSTALL_PATH)"
- define archhelp
-   echo '* compressed  - Build compressed kernel image'
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/mm/contig.c linux-2.6.18-xen.hg/arch/ia64/mm/contig.c
---- linux-2.6.18/arch/ia64/mm/contig.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/mm/contig.c  2007-12-23 11:14:54.632532163 +0100
+--- linux-2.6.18.8/arch/ia64/mm/contig.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/mm/contig.c  2008-05-19 00:33:04.492405098 +0300
 @@ -18,6 +18,9 @@
  #include <linux/efi.h>
  #include <linux/mm.h>
  #include <linux/swap.h>
-+#ifdef CONFIG_XEN
++#if defined(CONFIG_XEN) && defined(CONFIG_KEXEC)
 +#include <linux/kexec.h>
 +#endif
  
@@ -25872,9 +26307,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/mm/contig.c li
  }
  
  #ifdef CONFIG_SMP
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/mm/init.c linux-2.6.18-xen.hg/arch/ia64/mm/init.c
---- linux-2.6.18/arch/ia64/mm/init.c   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/mm/init.c    2007-12-23 11:14:54.635865674 +0100
+--- linux-2.6.18.8/arch/ia64/mm/init.c 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/mm/init.c    2008-05-19 00:33:04.496405328 +0300
 @@ -303,16 +303,34 @@
  setup_gate (void)
  {
@@ -25912,9 +26346,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/mm/init.c linu
        put_kernel_page(page, GATE_ADDR + PAGE_SIZE, PAGE_GATE);
  #else
        put_kernel_page(page, GATE_ADDR + PERCPU_PAGE_SIZE, PAGE_GATE);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/mm/ioremap.c linux-2.6.18-xen.hg/arch/ia64/mm/ioremap.c
---- linux-2.6.18/arch/ia64/mm/ioremap.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/mm/ioremap.c 2007-12-23 11:14:54.635865674 +0100
+--- linux-2.6.18.8/arch/ia64/mm/ioremap.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/mm/ioremap.c 2008-05-19 00:33:04.500405559 +0300
 @@ -16,6 +16,9 @@
  static inline void __iomem *
  __ioremap (unsigned long offset, unsigned long size)
@@ -25925,9 +26358,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/mm/ioremap.c l
        return (void __iomem *) (__IA64_UNCACHED_OFFSET | offset);
  }
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/init.c linux-2.6.18-xen.hg/arch/ia64/oprofile/init.c
---- linux-2.6.18/arch/ia64/oprofile/init.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/oprofile/init.c      2007-12-23 11:14:54.639199186 +0100
+--- linux-2.6.18.8/arch/ia64/oprofile/Makefile 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/oprofile/Makefile    2008-05-19 00:33:04.520406712 +0300
+@@ -8,3 +8,7 @@
+ oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
+ oprofile-$(CONFIG_PERFMON) += perfmon.o
++ifeq ($(CONFIG_XEN), y)
++oprofile-$(CONFIG_PERFMON) += xenoprof.o \
++      ../../../drivers/xen/xenoprof/xenoprofile.o
++endif
+--- linux-2.6.18.8/arch/ia64/oprofile/init.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/oprofile/init.c      2008-05-19 00:33:04.520406712 +0300
 @@ -11,6 +11,8 @@
  #include <linux/oprofile.h>
  #include <linux/init.h>
@@ -25964,20 +26406,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/init.
  #ifdef CONFIG_PERFMON
        perfmon_exit();
  #endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/Makefile linux-2.6.18-xen.hg/arch/ia64/oprofile/Makefile
---- linux-2.6.18/arch/ia64/oprofile/Makefile   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/oprofile/Makefile    2007-12-23 11:14:54.635865674 +0100
-@@ -8,3 +8,7 @@
- oprofile-y := $(DRIVER_OBJS) init.o backtrace.o
- oprofile-$(CONFIG_PERFMON) += perfmon.o
-+ifeq ($(CONFIG_XEN), y)
-+oprofile-$(CONFIG_PERFMON) += xenoprof.o \
-+      ../../../drivers/xen/xenoprof/xenoprofile.o
-+endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/oprofile_perfmon.h linux-2.6.18-xen.hg/arch/ia64/oprofile/oprofile_perfmon.h
---- linux-2.6.18/arch/ia64/oprofile/oprofile_perfmon.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/oprofile/oprofile_perfmon.h  2007-12-23 11:14:54.639199186 +0100
+--- linux-2.6.18.8/arch/ia64/oprofile/oprofile_perfmon.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/oprofile/oprofile_perfmon.h  2008-05-19 00:33:04.520406712 +0300
 @@ -0,0 +1,30 @@
 +#ifndef OPROFILE_PERFMON_H
 +#define OPROFILE_PERFMON_H
@@ -26009,9 +26439,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/oprof
 +#endif /* CONFIG_XEN */
 +
 +#endif /* OPROFILE_PERFMON_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/perfmon.c linux-2.6.18-xen.hg/arch/ia64/oprofile/perfmon.c
---- linux-2.6.18/arch/ia64/oprofile/perfmon.c  2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/oprofile/perfmon.c   2007-12-23 11:14:54.639199186 +0100
+--- linux-2.6.18.8/arch/ia64/oprofile/perfmon.c        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/oprofile/perfmon.c   2008-05-19 00:33:04.520406712 +0300
 @@ -13,6 +13,7 @@
  #include <asm/perfmon.h>
  #include <asm/ptrace.h>
@@ -26087,9 +26516,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/perfm
 -      pfm_unregister_buffer_fmt(oprofile_fmt.fmt_uuid);
 +      __perfmon_exit();
  }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/xenoprof.c linux-2.6.18-xen.hg/arch/ia64/oprofile/xenoprof.c
---- linux-2.6.18/arch/ia64/oprofile/xenoprof.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/oprofile/xenoprof.c  2007-12-23 11:14:54.639199186 +0100
+--- linux-2.6.18.8/arch/ia64/oprofile/xenoprof.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/oprofile/xenoprof.c  2008-05-19 00:33:04.524406942 +0300
 @@ -0,0 +1,142 @@
 +/******************************************************************************
 + * xenoprof ia64 specific part
@@ -26144,9 +26572,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/xenop
 +}
 +
 +/* XXX move them to an appropriate header file. */
-+struct resource* xen_ia64_allocate_resource(unsigned long size); 
-+void xen_ia64_release_resource(struct resource* res); 
-+void xen_ia64_unmap_resource(struct resource* res); 
++struct resource* xen_ia64_allocate_resource(unsigned long size);
++void xen_ia64_release_resource(struct resource *res);
++void xen_ia64_unmap_resource(struct resource *res);
 +
 +struct resource*
 +xenoprof_ia64_allocate_resource(int32_t max_samples)
@@ -26166,7 +26594,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/xenop
 +      return xen_ia64_allocate_resource(bufsize);
 +}
 +
-+void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffersbuf)
++void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffer *sbuf)
 +{
 +      if (sbuf->buffer) {
 +              xen_ia64_unmap_resource(sbuf->arch.res);
@@ -26175,11 +26603,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/xenop
 +      }
 +}
 +
-+int xenoprof_arch_map_shared_buffer(struct xenoprof_get_bufferget_buffer,
-+                                    struct xenoprof_shared_buffersbuf)
++int xenoprof_arch_map_shared_buffer(struct xenoprof_get_buffer *get_buffer,
++                                    struct xenoprof_shared_buffer *sbuf)
 +{
 +      int ret;
-+      struct resourceres;
++      struct resource *res;
 +
 +      sbuf->buffer = NULL;
 +      sbuf->arch.res = NULL;
@@ -26205,11 +26633,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/xenop
 +      return ret;
 +}
 +
-+int xenoprof_arch_set_passive(struct xenoprof_passivepdomain,
-+                              struct xenoprof_shared_buffersbuf)
++int xenoprof_arch_set_passive(struct xenoprof_passive *pdomain,
++                              struct xenoprof_shared_buffer *sbuf)
 +{
 +      int ret;
-+      struct resourceres;
++      struct resource *res;
 +
 +      sbuf->buffer = NULL;
 +      sbuf->arch.res = NULL;
@@ -26233,9 +26661,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/oprofile/xenop
 +
 +      return ret;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/pci/pci.c linux-2.6.18-xen.hg/arch/ia64/pci/pci.c
---- linux-2.6.18/arch/ia64/pci/pci.c   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/pci/pci.c    2007-12-23 11:14:54.639199186 +0100
+--- linux-2.6.18.8/arch/ia64/pci/pci.c 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/pci/pci.c    2008-05-19 00:33:04.524406942 +0300
 @@ -30,6 +30,15 @@
  #include <asm/irq.h>
  #include <asm/hw_irq.h>
@@ -26485,9 +26912,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/pci/pci.c linu
 +}
 +EXPORT_SYMBOL(xen_pcibios_setup_root_windows);
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/sn/kernel/setup.c linux-2.6.18-xen.hg/arch/ia64/sn/kernel/setup.c
---- linux-2.6.18/arch/ia64/sn/kernel/setup.c   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/sn/kernel/setup.c    2007-12-23 11:14:54.655866720 +0100
+--- linux-2.6.18.8/arch/ia64/sn/kernel/setup.c 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/sn/kernel/setup.c    2008-05-19 00:33:04.968432536 +0300
 @@ -763,5 +763,13 @@
                return 0;
        return test_bit(id, sn_prom_features);
@@ -26502,9 +26928,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/sn/kernel/setu
 +}
  EXPORT_SYMBOL(sn_prom_feature_available);
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/sn/pci/pcibr/pcibr_provider.c linux-2.6.18-xen.hg/arch/ia64/sn/pci/pcibr/pcibr_provider.c
---- linux-2.6.18/arch/ia64/sn/pci/pcibr/pcibr_provider.c       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/sn/pci/pcibr/pcibr_provider.c        2007-12-23 11:14:54.669200766 +0100
+--- linux-2.6.18.8/arch/ia64/sn/pci/pcibr/pcibr_provider.c     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/sn/pci/pcibr/pcibr_provider.c        2008-05-19 00:33:05.004434611 +0300
 @@ -15,6 +15,7 @@
  #include <asm/sn/pcibus_provider_defs.h>
  #include <asm/sn/pcidev.h>
@@ -26526,9 +26951,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/sn/pci/pcibr/p
  
        spin_lock_init(&soft->pbi_lock);
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/sn/pci/tioca_provider.c linux-2.6.18-xen.hg/arch/ia64/sn/pci/tioca_provider.c
---- linux-2.6.18/arch/ia64/sn/pci/tioca_provider.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/sn/pci/tioca_provider.c      2007-12-23 11:14:54.669200766 +0100
+--- linux-2.6.18.8/arch/ia64/sn/pci/tioca_provider.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/sn/pci/tioca_provider.c      2008-05-19 00:33:05.004434611 +0300
 @@ -611,7 +611,9 @@
                return NULL;
  
@@ -26540,9 +26964,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/sn/pci/tioca_p
  
        /* init kernel-private area */
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/sn/pci/tioce_provider.c linux-2.6.18-xen.hg/arch/ia64/sn/pci/tioce_provider.c
---- linux-2.6.18/arch/ia64/sn/pci/tioce_provider.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/ia64/sn/pci/tioce_provider.c      2007-12-23 11:14:54.669200766 +0100
+--- linux-2.6.18.8/arch/ia64/sn/pci/tioce_provider.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/sn/pci/tioce_provider.c      2008-05-19 00:33:05.008434842 +0300
 @@ -1006,7 +1006,9 @@
                return NULL;
  
@@ -26554,9 +26977,20 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/sn/pci/tioce_p
  
        tioce_kern = tioce_kern_init(tioce_common);
        if (tioce_kern == NULL) {
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypercall.S linux-2.6.18-xen.hg/arch/ia64/xen/hypercall.S
---- linux-2.6.18/arch/ia64/xen/hypercall.S     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/hypercall.S      2007-12-23 11:14:54.672534273 +0100
+--- linux-2.6.18.8/arch/ia64/xen/Makefile      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/Makefile 2008-05-19 00:33:05.008434842 +0300
+@@ -0,0 +1,9 @@
++#
++# Makefile for Xen components
++#
++
++obj-y := hypercall.o xenivt.o xenentry.o xensetup.o xenpal.o \
++       hypervisor.o util.o xencomm.o xcom_hcall.o \
++       xcom_privcmd.o xcom_asm.o xen_dma.o
++
++obj-$(CONFIG_IA64_GENERIC) += machvec.o
+--- linux-2.6.18.8/arch/ia64/xen/hypercall.S   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/hypercall.S      2008-05-19 00:33:05.008434842 +0300
 @@ -0,0 +1,141 @@
 +/*
 + * Support routines for Xen hypercalls
@@ -26577,7 +27011,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypercall.
 +GLOBAL_ENTRY(xen_get_psr)
 +      XEN_HYPER_GET_PSR
 +      br.ret.sptk.many rp
-+    ;;
++      ;;
 +END(xen_get_psr)
 +
 +GLOBAL_ENTRY(xen_get_ivr)
@@ -26684,13 +27118,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypercall.
 +#endif /* ASM_SUPPORTED */
 +
 +GLOBAL_ENTRY(xen_send_ipi)
-+        mov r14=r32
-+        mov r15=r33
-+        mov r2=0x400
-+        break 0x1000
-+        ;;
-+        br.ret.sptk.many rp
-+        ;;
++      mov r14=r32
++      mov r15=r33
++      mov r2=0x400
++      break 0x1000
++      ;;
++      br.ret.sptk.many rp
++      ;;
 +END(xen_send_ipi)
 +
 +GLOBAL_ENTRY(__hypercall)
@@ -26699,10 +27133,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypercall.
 +      br.ret.sptk.many b0
 +      ;; 
 +END(__hypercall)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor.c linux-2.6.18-xen.hg/arch/ia64/xen/hypervisor.c
---- linux-2.6.18/arch/ia64/xen/hypervisor.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/hypervisor.c     2007-12-23 11:14:54.672534273 +0100
-@@ -0,0 +1,1505 @@
+--- linux-2.6.18.8/arch/ia64/xen/hypervisor.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/hypervisor.c     2008-05-19 00:33:05.012435072 +0300
+@@ -0,0 +1,1526 @@
 +/******************************************************************************
 + * include/asm-ia64/shadow.h
 + *
@@ -26725,7 +27158,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 + *
 + */
 +
-+//#include <linux/kernel.h>
 +#include <linux/spinlock.h>
 +#include <linux/bootmem.h>
 +#include <linux/module.h>
@@ -26740,7 +27172,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +#include <xen/xencons.h>
 +#include <xen/balloon.h>
 +
-+shared_info_t *HYPERVISOR_shared_info __read_mostly = (shared_info_t *)XSI_BASE;
++shared_info_t *HYPERVISOR_shared_info __read_mostly =
++      (shared_info_t *)XSI_BASE;
 +EXPORT_SYMBOL(HYPERVISOR_shared_info);
 +
 +start_info_t *xen_start_info;
@@ -26765,7 +27198,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +
 +      if (ia64_platform_is("xen"))
 +              dig_setup(cmdline_p);
-+      
++
 +      if (!is_running_on_xen() || !is_initial_xendomain())
 +              return;
 +
@@ -26784,9 +27217,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      xen_smp_intr_init();
 +}
 +
-+//XXX same as i386, x86_64 contiguous_bitmap_set(), contiguous_bitmap_clear()
-+// move those to lib/contiguous_bitmap?
-+//XXX discontigmem/sparsemem
++/*
++ *XXX same as i386, x86_64 contiguous_bitmap_set(), contiguous_bitmap_clear()
++ * move those to lib/contiguous_bitmap?
++ *XXX discontigmem/sparsemem
++ */
 +
 +/*
 + * Bitmap is indexed by page number. If bit is set, the page is part of a
@@ -26809,16 +27244,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      pte_t *pte;
 +
 +      bitmap_start = (unsigned long)contiguous_bitmap +
-+                     ((__pa(start) >> PAGE_SHIFT) >> 3);
++                     ((__pa(start) >> PAGE_SHIFT) >> 3);
 +      bitmap_end = (unsigned long)contiguous_bitmap +
-+                   (((__pa(end) >> PAGE_SHIFT) + 2 * BITS_PER_LONG) >> 3);
++                   (((__pa(end) >> PAGE_SHIFT) + 2 * BITS_PER_LONG) >> 3);
 +
 +      start_page = bitmap_start & PAGE_MASK;
 +      end_page = PAGE_ALIGN(bitmap_end);
 +      node = paddr_to_nid(__pa(start));
 +
 +      bitmap = alloc_bootmem_pages_node(NODE_DATA(node),
-+                                        end_page - start_page);
++                                        end_page - start_page);
 +      BUG_ON(!bitmap);
 +      memset(bitmap, 0, end_page - start_page);
 +
@@ -26826,26 +27261,26 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +              pgd = pgd_offset_k(address);
 +              if (pgd_none(*pgd))
 +                      pgd_populate(&init_mm, pgd,
-+                                   alloc_bootmem_pages_node(NODE_DATA(node),
-+                                                            PAGE_SIZE));
++                                   alloc_bootmem_pages_node(NODE_DATA(node),
++                                                            PAGE_SIZE));
 +              pud = pud_offset(pgd, address);
 +
 +              if (pud_none(*pud))
 +                      pud_populate(&init_mm, pud,
-+                                   alloc_bootmem_pages_node(NODE_DATA(node),
-+                                                            PAGE_SIZE));
++                                   alloc_bootmem_pages_node(NODE_DATA(node),
++                                                            PAGE_SIZE));
 +              pmd = pmd_offset(pud, address);
 +
 +              if (pmd_none(*pmd))
 +                      pmd_populate_kernel(&init_mm, pmd,
-+                                          alloc_bootmem_pages_node
-+                                          (NODE_DATA(node), PAGE_SIZE));
++                                          alloc_bootmem_pages_node
++                                          (NODE_DATA(node), PAGE_SIZE));
 +              pte = pte_offset_kernel(pmd, address);
 +
 +              if (pte_none(*pte))
 +                      set_pte(pte,
-+                              pfn_pte(__pa(bitmap + (address - start_page))
-+                                      >> PAGE_SHIFT, PAGE_KERNEL));
++                              pfn_pte(__pa(bitmap + (address - start_page))
++                                      >> PAGE_SHIFT, PAGE_KERNEL));
 +      }
 +      return 0;
 +}
@@ -26930,9 +27365,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      }
 +}
 +
-+// __xen_create_contiguous_region(), __xen_destroy_contiguous_region()
-+// are based on i386 xen_create_contiguous_region(),
-+// xen_destroy_contiguous_region()
++/*
++ * __xen_create_contiguous_region(), __xen_destroy_contiguous_region()
++ * are based on i386 xen_create_contiguous_region(),
++ * xen_destroy_contiguous_region()
++ */
 +
 +/* Protected by balloon_lock. */
 +#define MAX_CONTIG_ORDER 7
@@ -26978,9 +27415,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      balloon_lock(flags);
 +
 +      /* Get a new contiguous memory extent. */
-+      for (i = 0; i < num_gpfn; i++) {
++      for (i = 0; i < num_gpfn; i++)
 +              in_frames[i] = start_gpfn + i;
-+      }
 +      out_frame = start_gpfn;
 +      error = HYPERVISOR_memory_op(XENMEM_exchange, &exchange);
 +      success = (exchange.nr_exchanged == num_gpfn);
@@ -27062,7 +27498,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +                       .domid        = DOMID_SELF
 +               },
 +              .nr_exchanged = 0
-+        };
++      };
 +      
 +
 +      if (!test_bit(start_gpfn, contiguous_bitmap))
@@ -27080,17 +27516,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +
 +      contiguous_bitmap_clear(start_gpfn, num_gpfn);
 +
-+        /* Do the exchange for non-contiguous MFNs. */
++      /* Do the exchange for non-contiguous MFNs. */
 +      in_frame = start_gpfn;
-+      for (i = 0; i < num_gpfn; i++) {
++      for (i = 0; i < num_gpfn; i++)
 +              out_frames[i] = start_gpfn + i;
-+      }
 +      error = HYPERVISOR_memory_op(XENMEM_exchange, &exchange);
 +      success = (exchange.nr_exchanged == 1);
 +      BUG_ON(!success && ((exchange.nr_exchanged != 0) || (error == 0)));
 +      BUG_ON(success && (error != 0));
 +      if (unlikely(error == -ENOSYS)) {
-+                /* Compatibility when XENMEM_exchange is unsupported. */
++              /* Compatibility when XENMEM_exchange is unsupported. */
 +              error = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
 +                                           &exchange.in);
 +              BUG_ON(error != 1);
@@ -27110,11 +27545,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +                                          order, address_bits);
 +}
 +
-+
-+///////////////////////////////////////////////////////////////////////////
-+// grant table hack
-+// cmd: GNTTABOP_xxx
-+
++/****************************************************************************
++ * grant table hack
++ * cmd: GNTTABOP_xxx
++ */
 +#include <linux/mm.h>
 +#include <xen/interface/xen.h>
 +#include <xen/gnttab.h>
@@ -27133,16 +27567,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +
 +      if (flags & GNTMAP_host_map) {
 +              if (flags & GNTMAP_application_map) {
-+                      xprintd("GNTMAP_application_map is not supported yet: flags 0x%x\n", flags);
++                      xprintd("GNTMAP_application_map is not supported yet:"
++                              " flags 0x%x\n", flags);
 +                      BUG();
 +              }
 +              if (flags & GNTMAP_contains_pte) {
-+                      xprintd("GNTMAP_contains_pte is not supported yet flags 0x%x\n", flags);
++                      xprintd("GNTMAP_contains_pte is not supported yet"
++                              " flags 0x%x\n", flags);
 +                      BUG();
 +              }
 +      } else if (flags & GNTMAP_device_map) {
-+              xprintd("GNTMAP_device_map is not supported yet 0x%x\n", flags);
-+              BUG();//XXX not yet. actually this flag is not used.
++              xprintd("GNTMAP_device_map is not supported yet 0x%x\n",
++                      flags);
++              BUG(); /* XXX not yet. actually this flag is not used. */
 +      } else {
 +              BUG();
 +      }
@@ -27162,15 +27599,17 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +}
 +EXPORT_SYMBOL(HYPERVISOR_grant_table_op);
 +
-+///////////////////////////////////////////////////////////////////////////
-+// foreign mapping
++/**************************************************************************
++ * foreign mapping
++ */
 +#include <linux/efi.h>
-+#include <asm/meminit.h> // for IA64_GRANULE_SIZE, GRANULEROUND{UP,DOWN}()
++#include <asm/meminit.h> /* for IA64_GRANULE_SIZE, GRANULEROUND{UP,DOWN}() */
 +
 +static unsigned long privcmd_resource_min = 0;
-+// Xen/ia64 currently can handle pseudo physical address bits up to
-+// (PAGE_SHIFT * 3)
-+static unsigned long privcmd_resource_max = GRANULEROUNDDOWN((1UL << (PAGE_SHIFT * 3)) - 1);
++/* Xen/ia64 currently can handle pseudo physical address bits up to
++ * (PAGE_SHIFT * 3) */
++static unsigned long privcmd_resource_max =
++      GRANULEROUNDDOWN((1UL << (PAGE_SHIFT * 3)) - 1);
 +static unsigned long privcmd_resource_align = IA64_GRANULE_SIZE;
 +
 +static unsigned long
@@ -27205,18 +27644,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      efi_map_end   = efi_map_start + ia64_boot_param->efi_memmap_size;
 +      efi_desc_size = ia64_boot_param->efi_memdesc_size;
 +
-+      // at first check the used highest address
++      /* at first check the used highest address */
 +      for (p = efi_map_start; p < efi_map_end; p += efi_desc_size) {
-+              // nothing
++              /* nothing */;
 +      }
 +      md = p - efi_desc_size;
 +      privcmd_resource_min = GRANULEROUNDUP(md_end_addr(md));
 +      if (xen_ia64_privcmd_check_size(privcmd_resource_min,
-+                                      privcmd_resource_max)) {
++                                      privcmd_resource_max))
 +              goto out;
-+      }
 +
-+      // the used highest address is too large. try to find the largest gap.
++      /* the used highest address is too large.
++       * try to find the largest gap. */
 +      tmp_min = privcmd_resource_max;
 +      tmp_max = 0;
 +      gap_size = 0;
@@ -27230,23 +27669,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +
 +              md = p;
 +              end = md_end_addr(md);
-+              if (end > privcmd_resource_max) {
++              if (end > privcmd_resource_max)
 +                      break;
-+              }
 +              if (end < prev_end) {
-+                      // work around. 
-+                      // Xen may pass incompletely sorted memory
-+                      // descriptors like
-+                      // [x, x + length]
-+                      // [x, x]
-+                      // this order should be reversed.
++                      /* work around. 
++                       * Xen may pass incompletely sorted memory
++                       * descriptors like
++                       * [x, x + length]
++                       * [x, x]
++                       * this order should be reversed. */
 +                      continue;
 +              }
 +              next = p + efi_desc_size;
 +              next_start = next->phys_addr;
-+              if (next_start > privcmd_resource_max) {
++              if (next_start > privcmd_resource_max)
 +                      next_start = privcmd_resource_max;
-+              }
 +              if (end < next_start && gap_size < (next_start - end)) {
 +                      tmp_min = end;
 +                      tmp_max = next_start;
@@ -27265,19 +27702,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      privcmd_resource_max = tmp_max;
 +      if (!xen_ia64_privcmd_check_size(privcmd_resource_min,
 +                                       privcmd_resource_max)) {
-+              // Any large enough gap isn't found.
-+              // go ahead anyway with the warning hoping that large region
-+              // won't be requested.
-+              printk(KERN_WARNING "xen privcmd: large enough region for privcmd mmap is not found.\n");
++              /* Any large enough gap isn't found.
++               * go ahead anyway with the warning hoping that large region
++               * won't be requested. */
++              printk(KERN_WARNING "xen privcmd: "
++                     "large enough region for privcmd mmap is not found.\n");
 +      }
 +
 +out:
-+      printk(KERN_INFO "xen privcmd uses pseudo physical addr range [0x%lx, 0x%lx] (%ldMB)\n",
++      printk(KERN_INFO "xen privcmd uses pseudo physical addr range "
++             "[0x%lx, 0x%lx] (%ldMB)\n",
 +             privcmd_resource_min, privcmd_resource_max, 
 +             (privcmd_resource_max - privcmd_resource_min) >> 20);
 +      BUG_ON(privcmd_resource_min >= privcmd_resource_max);
 +
-+      // XXX this should be somewhere appropriate
++      /* XXX this should be somewhere appropriate */
 +      (void)p2m_expose_init();
 +
 +      return 0;
@@ -27292,12 +27731,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +
 +struct xen_ia64_privcmd_range {
 +      atomic_t                        ref_count;
-+      unsigned long                   pgoff; // in PAGE_SIZE
-+      struct resource*                res;
++      unsigned long                   pgoff; /* in PAGE_SIZE */
++      struct resource                 *res;
 +
-+      // for foreign domain p2m mapping
-+      void*                           private;
-+      void (*callback)(struct xen_ia64_privcmd_range* range, void* arg);
++      /* for foreign domain p2m mapping */
++      void                            *private;
++      void (*callback)(struct xen_ia64_privcmd_range *range, void *arg);
 +
 +      unsigned long                   num_entries;
 +      struct xen_ia64_privcmd_entry   entries[0];
@@ -27305,30 +27744,30 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +
 +struct xen_ia64_privcmd_vma {
 +      int                             is_privcmd_mmapped;
-+      struct xen_ia64_privcmd_range*  range;
++      struct xen_ia64_privcmd_range   *range;
 +
 +      unsigned long                   num_entries;
-+      struct xen_ia64_privcmd_entry*  entries;
++      struct xen_ia64_privcmd_entry   *entries;
 +};
 +
 +static void
-+xen_ia64_privcmd_init_entry(struct xen_ia64_privcmd_entryentry)
++xen_ia64_privcmd_init_entry(struct xen_ia64_privcmd_entry *entry)
 +{
 +      atomic_set(&entry->map_count, 0);
 +      entry->gpfn = INVALID_GPFN;
 +}
 +
 +static int
-+xen_ia64_privcmd_entry_mmap(struct vm_area_structvma,
++xen_ia64_privcmd_entry_mmap(struct vm_area_struct *vma,
 +                          unsigned long addr,
-+                          struct xen_ia64_privcmd_rangeprivcmd_range,
++                          struct xen_ia64_privcmd_range *privcmd_range,
 +                          int i,
 +                          unsigned long gmfn,
 +                          pgprot_t prot,
 +                          domid_t domid)
 +{
 +      int error = 0;
-+      struct xen_ia64_privcmd_entryentry = &privcmd_range->entries[i];
++      struct xen_ia64_privcmd_entry *entry = &privcmd_range->entries[i];
 +      unsigned long gpfn;
 +      unsigned long flags;
 +
@@ -27344,21 +27783,24 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      gpfn = (privcmd_range->res->start >> PAGE_SHIFT) + i;
 +
 +      flags = ASSIGN_writable;
-+      if (pgprot_val(prot) == PROT_READ) {
++      if (pgprot_val(prot) == PROT_READ)
 +              flags = ASSIGN_readonly;
-+      }
 +      error = HYPERVISOR_add_physmap_with_gmfn(gpfn, gmfn, flags, domid);
-+      if (error != 0) {
++      if (error != 0)
 +              goto out;
-+      }
 +
 +      prot = vma->vm_page_prot;
 +      error = remap_pfn_range(vma, addr, gpfn, 1 << PAGE_SHIFT, prot);
++      /*
++       * VM_PFNMAP is set in remap_pfn_range().
++       * Reset the flag to avoid BUG_ON() in do_no_page().
++       */
++      vma->vm_flags &= ~VM_PFNMAP;
++
 +      if (error != 0) {
 +              error = HYPERVISOR_zap_physmap(gpfn, 0);
-+              if (error) {
-+                      BUG();//XXX
-+              }
++              if (error)
++                      BUG(); /* XXX */
 +      } else {
 +              atomic_inc(&entry->map_count);
 +              entry->gpfn = gpfn;
@@ -27369,60 +27811,67 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +}
 +
 +static void
-+xen_ia64_privcmd_entry_munmap(struct xen_ia64_privcmd_rangeprivcmd_range,
++xen_ia64_privcmd_entry_munmap(struct xen_ia64_privcmd_range *privcmd_range,
 +                            int i)
 +{
-+      struct xen_ia64_privcmd_entryentry = &privcmd_range->entries[i];
++      struct xen_ia64_privcmd_entry *entry = &privcmd_range->entries[i];
 +      unsigned long gpfn = entry->gpfn;
-+      //gpfn = (privcmd_range->res->start >> PAGE_SHIFT) +
-+      //      (vma->vm_pgoff - privcmd_range->pgoff);
++      /gpfn = (privcmd_range->res->start >> PAGE_SHIFT) +
++              (vma->vm_pgoff - privcmd_range->pgoff); */
 +      int error;
 +
 +      error = HYPERVISOR_zap_physmap(gpfn, 0);
-+      if (error) {
-+              BUG();//XXX
-+      }
++      if (error)
++              BUG(); /* XXX */
 +      entry->gpfn = INVALID_GPFN;
 +}
 +
 +static void
-+xen_ia64_privcmd_entry_open(struct xen_ia64_privcmd_rangeprivcmd_range,
++xen_ia64_privcmd_entry_open(struct xen_ia64_privcmd_range *privcmd_range,
 +                          int i)
 +{
-+      struct xen_ia64_privcmd_entryentry = &privcmd_range->entries[i];
-+      if (entry->gpfn != INVALID_GPFN) {
++      struct xen_ia64_privcmd_entry *entry = &privcmd_range->entries[i];
++      if (entry->gpfn != INVALID_GPFN)
 +              atomic_inc(&entry->map_count);
-+      } else {
++      else
 +              BUG_ON(atomic_read(&entry->map_count) != 0);
-+      }
 +}
 +
 +static void
-+xen_ia64_privcmd_entry_close(struct xen_ia64_privcmd_rangeprivcmd_range,
++xen_ia64_privcmd_entry_close(struct xen_ia64_privcmd_range *privcmd_range,
 +                           int i)
 +{
-+      struct xen_ia64_privcmd_entryentry = &privcmd_range->entries[i];
++      struct xen_ia64_privcmd_entry *entry = &privcmd_range->entries[i];
 +      if (entry->gpfn != INVALID_GPFN &&
-+          atomic_dec_and_test(&entry->map_count)) {
++          atomic_dec_and_test(&entry->map_count))
 +              xen_ia64_privcmd_entry_munmap(privcmd_range, i);
-+      }
 +}
 +
-+static void xen_ia64_privcmd_vma_open(struct vm_area_struct* vma);
-+static void xen_ia64_privcmd_vma_close(struct vm_area_struct* vma);
++static void xen_ia64_privcmd_vma_open(struct vm_area_struct *vma);
++static void xen_ia64_privcmd_vma_close(struct vm_area_struct *vma);
++
++static struct page *
++xen_ia64_privcmd_vma_nopage(struct vm_area_struct *vma,
++                          unsigned long address,
++                          int *type)
++{
++      return NOPAGE_SIGBUS;
++}
 +
 +struct vm_operations_struct xen_ia64_privcmd_vm_ops = {
-+      .open = &xen_ia64_privcmd_vma_open,
-+      .close = &xen_ia64_privcmd_vma_close,
++      .open = xen_ia64_privcmd_vma_open,
++      .close = xen_ia64_privcmd_vma_close,
++      .nopage = xen_ia64_privcmd_vma_nopage
 +};
 +
 +static void
-+__xen_ia64_privcmd_vma_open(struct vm_area_structvma,
-+                          struct xen_ia64_privcmd_vmaprivcmd_vma,
-+                          struct xen_ia64_privcmd_rangeprivcmd_range)
++__xen_ia64_privcmd_vma_open(struct vm_area_struct *vma,
++                          struct xen_ia64_privcmd_vma *privcmd_vma,
++                          struct xen_ia64_privcmd_range *privcmd_range)
 +{
 +      unsigned long entry_offset = vma->vm_pgoff - privcmd_range->pgoff;
-+      unsigned long num_entries = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
++      unsigned long num_entries =
++              (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
 +      unsigned long i;
 +
 +      BUG_ON(entry_offset < 0);
@@ -27432,36 +27881,37 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      privcmd_vma->num_entries = num_entries;
 +      privcmd_vma->entries = &privcmd_range->entries[entry_offset];
 +      vma->vm_private_data = privcmd_vma;
-+      for (i = 0; i < privcmd_vma->num_entries; i++) {
++      for (i = 0; i < privcmd_vma->num_entries; i++)
 +              xen_ia64_privcmd_entry_open(privcmd_range, entry_offset + i);
-+      }
 +
 +      vma->vm_private_data = privcmd_vma;
 +      vma->vm_ops = &xen_ia64_privcmd_vm_ops;
 +}
 +
 +static void
-+xen_ia64_privcmd_vma_open(struct vm_area_structvma)
++xen_ia64_privcmd_vma_open(struct vm_area_struct *vma)
 +{
-+      struct xen_ia64_privcmd_vma* old_privcmd_vma = (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
-+      struct xen_ia64_privcmd_vma* privcmd_vma = (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
-+      struct xen_ia64_privcmd_range* privcmd_range = privcmd_vma->range;
++      struct xen_ia64_privcmd_vma *old_privcmd_vma =
++              (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
++      struct xen_ia64_privcmd_vma *privcmd_vma =
++              (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
++      struct xen_ia64_privcmd_range *privcmd_range = privcmd_vma->range;
 +
 +      atomic_inc(&privcmd_range->ref_count);
-+      // vm_op->open() can't fail.
++      /* vm_op->open() can't fail. */
 +      privcmd_vma = kmalloc(sizeof(*privcmd_vma), GFP_KERNEL | __GFP_NOFAIL);
-+      // copy original value if necessary
++      /* copy original value if necessary */
 +      privcmd_vma->is_privcmd_mmapped = old_privcmd_vma->is_privcmd_mmapped;
 +
 +      __xen_ia64_privcmd_vma_open(vma, privcmd_vma, privcmd_range);
 +}
 +
 +static void
-+xen_ia64_privcmd_vma_close(struct vm_area_structvma)
++xen_ia64_privcmd_vma_close(struct vm_area_struct *vma)
 +{
-+      struct xen_ia64_privcmd_vmaprivcmd_vma =
++      struct xen_ia64_privcmd_vma *privcmd_vma =
 +              (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
-+      struct xen_ia64_privcmd_rangeprivcmd_range = privcmd_vma->range;
++      struct xen_ia64_privcmd_range *privcmd_range = privcmd_vma->range;
 +      unsigned long entry_offset = vma->vm_pgoff - privcmd_range->pgoff;
 +      unsigned long i;
 +
@@ -27475,7 +27925,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      if (atomic_dec_and_test(&privcmd_range->ref_count)) {
 +#if 1
 +              for (i = 0; i < privcmd_range->num_entries; i++) {
-+                      struct xen_ia64_privcmd_entryentry =
++                      struct xen_ia64_privcmd_entry *entry =
 +                              &privcmd_range->entries[i];
 +                      BUG_ON(atomic_read(&entry->map_count) != 0);
 +                      BUG_ON(entry->gpfn != INVALID_GPFN);
@@ -27493,7 +27943,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +int
 +privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
 +{
-+      struct xen_ia64_privcmd_vmaprivcmd_vma =
++      struct xen_ia64_privcmd_vma *privcmd_vma =
 +              (struct xen_ia64_privcmd_vma *)vma->vm_private_data;
 +      return (xchg(&privcmd_vma->is_privcmd_mmapped, 1) == 0);
 +}
@@ -27504,9 +27954,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      int error;
 +      unsigned long size = vma->vm_end - vma->vm_start;
 +      unsigned long num_entries = size >> PAGE_SHIFT;
-+      struct xen_ia64_privcmd_rangeprivcmd_range = NULL;
-+      struct xen_ia64_privcmd_vmaprivcmd_vma = NULL;
-+      struct resourceres = NULL;
++      struct xen_ia64_privcmd_range *privcmd_range = NULL;
++      struct xen_ia64_privcmd_vma *privcmd_vma = NULL;
++      struct resource *res = NULL;
 +      unsigned long i;
 +      BUG_ON(!is_running_on_xen());
 +
@@ -27516,39 +27966,34 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      privcmd_range =
 +              vmalloc(sizeof(*privcmd_range) +
 +                      sizeof(privcmd_range->entries[0]) * num_entries);
-+      if (privcmd_range == NULL) {
++      if (privcmd_range == NULL)
 +              goto out_enomem0;
-+      }
 +      privcmd_vma = kmalloc(sizeof(*privcmd_vma), GFP_KERNEL);
-+      if (privcmd_vma == NULL) {
++      if (privcmd_vma == NULL)
 +              goto out_enomem1;
-+      }
 +      privcmd_vma->is_privcmd_mmapped = 0;
 +
 +      res = kzalloc(sizeof(*res), GFP_KERNEL);
-+      if (res == NULL) {
++      if (res == NULL)
 +              goto out_enomem1;
-+      }
 +      res->name = "Xen privcmd mmap";
 +      error = allocate_resource(&iomem_resource, res, size,
 +                                privcmd_resource_min, privcmd_resource_max,
 +                                privcmd_resource_align, NULL, NULL);
-+      if (error) {
++      if (error)
 +              goto out_enomem1;
-+      }
 +      privcmd_range->res = res;
 +
 +      /* DONTCOPY is essential for Xen as copy_page_range is broken. */
-+      vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY | VM_PFNMAP;
++      vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
 +
 +      atomic_set(&privcmd_range->ref_count, 1);
 +      privcmd_range->pgoff = vma->vm_pgoff;
 +      privcmd_range->num_entries = num_entries;
 +      privcmd_range->private = NULL;
 +      privcmd_range->callback = NULL;
-+      for (i = 0; i < privcmd_range->num_entries; i++) {
++      for (i = 0; i < privcmd_range->num_entries; i++)
 +              xen_ia64_privcmd_init_entry(&privcmd_range->entries[i]);
-+      }
 +
 +      __xen_ia64_privcmd_vma_open(vma, privcmd_vma, privcmd_range);
 +      return 0;
@@ -27563,15 +28008,15 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +
 +int
 +direct_remap_pfn_range(struct vm_area_struct *vma,
-+                     unsigned long address,   // process virtual address
-+                     unsigned long gmfn,      // gmfn, gmfn + 1, ... gmfn + size/PAGE_SIZE
++                     unsigned long address,   /* process virtual address */
++                     unsigned long gmfn,      /* gmfn, gmfn + 1, ... gmfn + size/PAGE_SIZE */
 +                     unsigned long size,
 +                     pgprot_t prot,
-+                     domid_t  domid)          // target domain
++                     domid_t  domid)          /* target domain */
 +{
-+      struct xen_ia64_privcmd_vmaprivcmd_vma =
++      struct xen_ia64_privcmd_vma *privcmd_vma =
 +              (struct xen_ia64_privcmd_vma*)vma->vm_private_data;
-+      struct xen_ia64_privcmd_rangeprivcmd_range = privcmd_vma->range;
++      struct xen_ia64_privcmd_range *privcmd_range = privcmd_vma->range;
 +      unsigned long entry_offset = vma->vm_pgoff - privcmd_range->pgoff;
 +
 +      unsigned long i;
@@ -27580,28 +28025,27 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      BUG_ON(!is_running_on_xen());
 +
 +#if 0
-+      if (prot != vm->vm_page_prot) {
++      if (prot != vm->vm_page_prot)
 +              return -EINVAL;
-+      }
 +#endif
 +
 +      i = (address - vma->vm_start) >> PAGE_SHIFT;
 +      for (offset = 0; offset < size; offset += PAGE_SIZE) {
 +              error = xen_ia64_privcmd_entry_mmap(vma, (address + offset) & PAGE_MASK, privcmd_range, entry_offset + i, gmfn, prot, domid);
-+              if (error != 0) {
++              if (error != 0)
 +                      break;
-+              }
 +
 +              i++;
 +              gmfn++;
-+        }
++      }
 +
 +      return error;
 +}
 +
 +
-+///////////////////////////////////////////////////////////////////////////
-+// expose p2m table
++/**************************************************************************
++ * expose p2m table
++ */
 +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M
 +#include <linux/cpu.h>
 +#include <asm/uaccess.h>
@@ -27619,9 +28063,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +};
 +static unsigned long p2m_assign_start_pfn __read_mostly;
 +static unsigned long p2m_assign_end_pfn __read_mostly;
-+static unsigned long p2m_expose_size; // this is referenced only when resume.
-+                                      // so __read_mostly doesn't make sense.
-+volatile const pte_t* p2m_pte __read_mostly;
++static unsigned long p2m_expose_size; /* this is referenced only when resume.
++                                       * so __read_mostly doesn't make sense.
++                                       */
++volatile const pte_t *p2m_pte __read_mostly;
 +
 +#define GRANULE_PFN   PTRS_PER_PTE
 +static unsigned long p2m_granule_pfn __read_mostly = GRANULE_PFN;
@@ -27634,13 +28079,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +static int xen_ia64_p2m_expose __read_mostly = 1;
 +module_param(xen_ia64_p2m_expose, int, 0);
 +MODULE_PARM_DESC(xen_ia64_p2m_expose,
-+                 "enable/disable xen/ia64 p2m exposure optimization\n");
++               "enable/disable xen/ia64 p2m exposure optimization\n");
 +
 +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
 +static int xen_ia64_p2m_expose_use_dtr __read_mostly = 1;
 +module_param(xen_ia64_p2m_expose_use_dtr, int, 0);
 +MODULE_PARM_DESC(xen_ia64_p2m_expose_use_dtr,
-+                 "use/unuse dtr to map exposed p2m table\n");
++               "use/unuse dtr to map exposed p2m table\n");
 +
 +static const int p2m_page_shifts[] = {
 +      _PAGE_SIZE_4K,
@@ -27662,21 +28107,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +};
 +static struct p2m_itr_arg p2m_itr_arg __read_mostly;
 +
-+// This should be in asm-ia64/kregs.h
++/* This should be in asm-ia64/kregs.h */
 +#define IA64_TR_P2M_TABLE     3
 +
 +static void
-+p2m_itr(voidinfo)
++p2m_itr(void *info)
 +{
-+      struct p2m_itr_argarg = (struct p2m_itr_arg*)info;
++      struct p2m_itr_arg *arg = (struct p2m_itr_arg*)info;
 +      ia64_itr(0x2, IA64_TR_P2M_TABLE,
-+               arg->vaddr, arg->pteval, arg->log_page_size);
++               arg->vaddr, arg->pteval, arg->log_page_size);
 +      ia64_srlz_d();
 +}
 +
 +static int
 +p2m_expose_dtr_call(struct notifier_block *self,
-+                    unsigned long event, void* ptr)
++                  unsigned long event, void *ptr)
 +{
 +      unsigned int cpu = (unsigned int)(long)ptr;
 +      if (event != CPU_ONLINE)
@@ -27755,15 +28200,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +                              continue;
 +
 +                      granule_pfn = max(page_size >> PAGE_SHIFT,
-+                                        p2m_granule_pfn);
++                                        p2m_granule_pfn);
 +                      p2m_convert_min_pfn = ROUNDDOWN(p2m_min_low_pfn,
-+                                                      granule_pfn);
++                                                      granule_pfn);
 +                      p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn,
-+                                                    granule_pfn);
++                                                    granule_pfn);
 +                      num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn;
 +                      p2m_expose_size = num_pfn << PAGE_SHIFT;
 +                      p2m_size = p2m_table_size(num_pfn);
-+                      p2m_size = ROUNDUP(p2m_size, granule_pfn << PAGE_SHIFT);
++                      p2m_size = ROUNDUP(p2m_size,
++                                         granule_pfn << PAGE_SHIFT);
 +                      if (p2m_size == page_size)
 +                              break;
 +              }
@@ -27778,20 +28224,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      {
 +              BUG_ON(p2m_granule_pfn & (p2m_granule_pfn - 1));
 +              p2m_convert_min_pfn = ROUNDDOWN(p2m_min_low_pfn,
-+                                              p2m_granule_pfn);
-+              p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn, p2m_granule_pfn);
++                                              p2m_granule_pfn);
++              p2m_convert_max_pfn = ROUNDUP(p2m_max_low_pfn,
++                                            p2m_granule_pfn);
 +              num_pfn = p2m_convert_max_pfn - p2m_convert_min_pfn;
 +              p2m_expose_size = num_pfn << PAGE_SHIFT;
 +              p2m_size = p2m_table_size(num_pfn);
 +              p2m_size = ROUNDUP(p2m_size, p2m_granule_pfn << PAGE_SHIFT);
 +              align = max(privcmd_resource_align,
-+                          p2m_granule_pfn << PAGE_SHIFT);
++                          p2m_granule_pfn << PAGE_SHIFT);
 +      }
 +      
-+      // use privcmd region
++      /* use privcmd region */
 +      error = allocate_resource(&iomem_resource, &p2m_resource, p2m_size,
-+                                privcmd_resource_min, privcmd_resource_max,
-+                                align, NULL, NULL);
++                                privcmd_resource_min, privcmd_resource_max,
++                                align, NULL, NULL);
 +      if (error) {
 +              printk(KERN_ERR P2M_PREFIX
 +                     "can't allocate region for p2m exposure "
@@ -27804,8 +28251,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      p2m_assign_end_pfn = p2m_resource.end >> PAGE_SHIFT;
 +      
 +      error = HYPERVISOR_expose_p2m(p2m_convert_min_pfn,
-+                                    p2m_assign_start_pfn,
-+                                    p2m_expose_size, p2m_granule_pfn);
++                                    p2m_assign_start_pfn,
++                                    p2m_expose_size, p2m_granule_pfn);
 +      if (error) {
 +              printk(KERN_ERR P2M_PREFIX "failed expose p2m hypercall %d\n",
 +                     error);
@@ -27820,9 +28267,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +#ifdef CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR
 +      if (xen_ia64_p2m_expose_use_dtr) {
 +              p2m_itr_arg.vaddr = (unsigned long)__va(p2m_assign_start_pfn
-+                                                      << PAGE_SHIFT);
++                                                      << PAGE_SHIFT);
 +              p2m_itr_arg.pteval = pte_val(pfn_pte(p2m_assign_start_pfn,
-+                                                   PAGE_KERNEL));
++                                                   PAGE_KERNEL));
 +              p2m_itr_arg.log_page_size = log_page_size;
 +              smp_mb();
 +              smp_call_function(&p2m_itr, &p2m_itr_arg, 1, 1);
@@ -27870,8 +28317,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +       * interrupts are masked when resume.
 +       */
 +      error = HYPERVISOR_expose_p2m(p2m_convert_min_pfn,
-+                                    p2m_assign_start_pfn,
-+                                    p2m_expose_size, p2m_granule_pfn);
++                                    p2m_assign_start_pfn,
++                                    p2m_expose_size, p2m_granule_pfn);
 +      if (error) {
 +              printk(KERN_ERR P2M_PREFIX "failed expose p2m hypercall %d\n",
 +                     error);
@@ -27898,11 +28345,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      }
 +}
 +
-+//XXX inlinize?
++/* XXX inlinize? */
 +unsigned long
 +p2m_phystomach(unsigned long gpfn)
 +{
-+      volatile const pte_tpte;
++      volatile const pte_t *pte;
 +      unsigned long mfn;
 +      unsigned long pteval;
 +      
@@ -27914,8 +28361,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +
 +      mfn = INVALID_MFN;
 +      if (likely(__get_user(pteval, (unsigned long __user *)pte) == 0 &&
-+                 pte_present(__pte(pteval)) &&
-+                 pte_pfn(__pte(pteval)) != (INVALID_MFN >> PAGE_SHIFT)))
++                 pte_present(__pte(pteval)) &&
++                 pte_pfn(__pte(pteval)) != (INVALID_MFN >> PAGE_SHIFT)))
 +              mfn = (pteval & _PFN_MASK) >> PAGE_SHIFT;
 +
 +      return mfn;
@@ -27929,8 +28376,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +EXPORT_SYMBOL_GPL(p2m_pte);
 +EXPORT_SYMBOL_GPL(p2m_phystomach);
 +
-+///////////////////////////////////////////////////////////////////////////
-+// foreign domain p2m mapping
++/**************************************************************************
++ * foreign domain p2m mapping
++ */
 +#include <asm/xen/xencomm.h>
 +#include <xen/public/privcmd.h>
 +
@@ -27940,10 +28388,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +};
 +
 +static void
-+xen_foreign_p2m_unexpose(struct xen_ia64_privcmd_rangeprivcmd_range,
-+                       voidarg)
++xen_foreign_p2m_unexpose(struct xen_ia64_privcmd_range *privcmd_range,
++                       void *arg)
 +{
-+      struct foreign_p2m_privateprivate = (struct foreign_p2m_private*)arg;
++      struct foreign_p2m_private *private = (struct foreign_p2m_private*)arg;
 +      int ret;
 +
 +      privcmd_range->private = NULL;
@@ -27957,17 +28405,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +}
 +
 +int
-+xen_foreign_p2m_expose(privcmd_hypercall_thypercall)
++xen_foreign_p2m_expose(privcmd_hypercall_t *hypercall)
 +{
-+      // hypercall->
-+      // arg0: cmd = IA64_DOM0VP_expose_foreign_p2m
-+      // arg1: va
-+      // arg2: domid
-+      // arg3: __user* memmap_info
-+      // arg4: flags
++      /*
++       * hypercall->
++       * arg0: cmd = IA64_DOM0VP_expose_foreign_p2m
++       * arg1: va
++       * arg2: domid
++       * arg3: __user* memmap_info
++       * arg4: flags
++       */
 +
 +      int ret = 0;
-+      struct mm_structmm = current->mm;
++      struct mm_struct *mm = current->mm;
 +
 +      unsigned long vaddr = hypercall->arg[1];
 +      domid_t domid = hypercall->arg[2];
@@ -27976,19 +28426,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +
 +      struct xen_ia64_memmap_info memmap_info;
 +      size_t memmap_size;
-+      struct xen_ia64_memmap_infok_memmap_info = NULL;
++      struct xen_ia64_memmap_info *k_memmap_info = NULL;
 +      unsigned long max_gpfn;
 +      unsigned long p2m_size;
-+      struct resourceres;
++      struct resource *res;
 +      unsigned long gpfn;
 +
-+      struct vm_area_structvma;
-+      voidp;
++      struct vm_area_struct *vma;
++      void *p;
 +      unsigned long prev_src_gpfn_end;
 +
-+      struct xen_ia64_privcmd_vmaprivcmd_vma;
-+      struct xen_ia64_privcmd_rangeprivcmd_range;
-+      struct foreign_p2m_privateprivate = NULL;
++      struct xen_ia64_privcmd_vma *privcmd_vma;
++      struct xen_ia64_privcmd_range *privcmd_range;
++      struct foreign_p2m_private *private = NULL;
 +
 +      BUG_ON(hypercall->arg[0] != IA64_DOM0VP_expose_foreign_p2m);
 +
@@ -28043,12 +28493,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      }
 +      
 +      gpfn = res->start >> PAGE_SHIFT;
-+      // arg0: dest_gpfn
-+      // arg1: domid
-+      // arg2: XEN_GUEST_HANDLE(char) buffer: memmap_info
-+      // arg3: flags
-+      // The hypercall checks its intergirty/simplfies it and 
-+      // copy it back for us.
++      /*
++       * arg0: dest_gpfn
++       * arg1: domid
++       * arg2: XEN_GUEST_HANDLE(char) buffer: memmap_info
++       * arg3: flags
++       * The hypercall checks its intergirty/simplfies it and 
++       * copy it back for us.
++       */
 +      ret = xencomm_arch_expose_foreign_p2m(gpfn, domid,
 +            xencomm_map_no_alloc(k_memmap_info, memmap_size),
 +            hypercall->arg[4]);
@@ -28090,7 +28542,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +                                    vma->vm_page_prot);
 +              if (ret) {
 +                      for (i = 0; i < gpfn + gpfn_offset; i++) {
-+                              struct xen_ia64_privcmd_entryentry =
++                              struct xen_ia64_privcmd_entry *entry =
 +                                      &privcmd_range->entries[i];
 +                              BUG_ON(atomic_read(&entry->map_count) != 1 &&
 +                                     atomic_read(&entry->map_count) != 0);
@@ -28104,7 +28556,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +              for (i = gpfn_offset;
 +                   i < gpfn_offset + (size >> PAGE_SHIFT);
 +                   i++) {
-+                      struct xen_ia64_privcmd_entryentry =
++                      struct xen_ia64_privcmd_entry *entry =
 +                              &privcmd_range->entries[i];
 +                      BUG_ON(atomic_read(&entry->map_count) != 0);
 +                      BUG_ON(entry->gpfn != INVALID_GPFN);
@@ -28129,13 +28581,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +}
 +#endif
 +
-+///////////////////////////////////////////////////////////////////////////
-+// for xenoprof
-+
++/**************************************************************************
++ * for xenoprof
++ */
 +struct resource*
 +xen_ia64_allocate_resource(unsigned long size)
 +{
-+      struct resourceres;
++      struct resource *res;
 +      int error;
 +      
 +      res = kzalloc(sizeof(*res), GFP_KERNEL);
@@ -28145,8 +28597,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      res->name = "Xen";
 +      res->flags = IORESOURCE_MEM;
 +      error = allocate_resource(&iomem_resource, res, PAGE_ALIGN(size),
-+                                privcmd_resource_min, privcmd_resource_max,
-+                                IA64_GRANULE_SIZE, NULL, NULL);
++                                privcmd_resource_min, privcmd_resource_max,
++                                IA64_GRANULE_SIZE, NULL, NULL);
 +      if (error) {
 +              kfree(res);
 +              return ERR_PTR(error);
@@ -28156,7 +28608,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +EXPORT_SYMBOL_GPL(xen_ia64_allocate_resource);
 +
 +void
-+xen_ia64_release_resource(struct resourceres)
++xen_ia64_release_resource(struct resource *res)
 +{
 +      release_resource(res);
 +      kfree(res);
@@ -28164,7 +28616,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +EXPORT_SYMBOL_GPL(xen_ia64_release_resource);
 +
 +void
-+xen_ia64_unmap_resource(struct resourceres)
++xen_ia64_unmap_resource(struct resource *res)
 +{
 +      unsigned long gpfn = res->start >> PAGE_SHIFT;
 +      unsigned long nr_pages = (res->end - res->start) >> PAGE_SHIFT;
@@ -28181,8 +28633,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +}
 +EXPORT_SYMBOL_GPL(xen_ia64_unmap_resource);
 +
-+///////////////////////////////////////////////////////////////////////////
-+// opt feature
++/**************************************************************************
++ * opt feature
++ */
 +void
 +xen_ia64_enable_opt_feature(void)
 +{
@@ -28196,8 +28649,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      HYPERVISOR_opt_feature(&optf);
 +}
 +
-+///////////////////////////////////////////////////////////////////////////
-+// suspend/resume
++/**************************************************************************
++ * suspend/resume
++ */
 +void
 +xen_post_suspend(int suspend_cancelled)
 +{
@@ -28208,30 +28662,15 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/hypervisor
 +      xen_ia64_enable_opt_feature();
 +      /* add more if necessary */
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/machvec.c linux-2.6.18-xen.hg/arch/ia64/xen/machvec.c
---- linux-2.6.18/arch/ia64/xen/machvec.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/machvec.c        2007-12-23 11:14:54.672534273 +0100
+--- linux-2.6.18.8/arch/ia64/xen/machvec.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/machvec.c        2008-05-19 00:33:05.032436225 +0300
 @@ -0,0 +1,4 @@
 +#define MACHVEC_PLATFORM_NAME           xen
 +#define MACHVEC_PLATFORM_HEADER         <asm/machvec_xen.h>
 +#include <asm/machvec_init.h>
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/Makefile linux-2.6.18-xen.hg/arch/ia64/xen/Makefile
---- linux-2.6.18/arch/ia64/xen/Makefile        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/Makefile 2007-12-23 11:14:54.672534273 +0100
-@@ -0,0 +1,9 @@
-+#
-+# Makefile for Xen components
-+#
-+
-+obj-y := hypercall.o xenivt.o xenentry.o xensetup.o xenpal.o xenhpski.o \
-+       hypervisor.o util.o xencomm.o xcom_hcall.o \
-+       xcom_privcmd.o xen_dma.o
-+
-+obj-$(CONFIG_IA64_GENERIC) += machvec.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/swiotlb.c linux-2.6.18-xen.hg/arch/ia64/xen/swiotlb.c
---- linux-2.6.18/arch/ia64/xen/swiotlb.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/swiotlb.c        2007-12-23 11:14:54.672534273 +0100
+--- linux-2.6.18.8/arch/ia64/xen/swiotlb.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/swiotlb.c        2008-05-19 00:33:05.036436456 +0300
 @@ -0,0 +1,906 @@
 +/*
 + * Dynamic DMA mapping support.
@@ -29139,10 +29578,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/swiotlb.c
 +EXPORT_SYMBOL(swiotlb_alloc_coherent);
 +EXPORT_SYMBOL(swiotlb_free_coherent);
 +EXPORT_SYMBOL(swiotlb_dma_supported);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/util.c linux-2.6.18-xen.hg/arch/ia64/xen/util.c
---- linux-2.6.18/arch/ia64/xen/util.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/util.c   2007-12-23 11:14:54.675867776 +0100
-@@ -0,0 +1,105 @@
+--- linux-2.6.18.8/arch/ia64/xen/util.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/util.c   2008-05-19 00:33:05.036436456 +0300
+@@ -0,0 +1,102 @@
 +/******************************************************************************
 + * arch/ia64/xen/util.c
 + * This file is the ia64 counterpart of drivers/xen/util.c
@@ -29180,25 +29618,23 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/util.c lin
 +      int order;
 +      unsigned long virt;
 +      unsigned long nr_pages;
-+      struct vm_structarea;
-+      
++      struct vm_struct *area;
++
 +      order = get_order(size);
 +      virt = __get_free_pages(GFP_KERNEL, order);
-+      if (virt == 0) {
++      if (virt == 0)
 +              goto err0;
-+      }
 +      nr_pages = 1 << order;
 +      scrub_pages(virt, nr_pages);
-+      
++
 +      area = kmalloc(sizeof(*area), GFP_KERNEL);
-+      if (area == NULL) {
++      if (area == NULL)
 +              goto err1;
-+      }
-+      
-+        area->flags = VM_IOREMAP;//XXX
++
++        area->flags = VM_IOREMAP; /* XXX */
 +        area->addr = (void*)virt;
 +        area->size = size;
-+        area->pages = NULL; //XXX
++        area->pages = NULL; /* XXX */
 +        area->nr_pages = nr_pages;
 +        area->phys_addr = 0;  /* xenbus_map_ring_valloc uses this field!  */
 +
@@ -29208,7 +29644,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/util.c lin
 +      free_pages(virt, order);
 +err0:
 +      return NULL;
-+      
 +}
 +EXPORT_SYMBOL_GPL(alloc_vm_area);
 +
@@ -29218,8 +29653,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/util.c lin
 +      unsigned long i;
 +      unsigned long phys_addr = __pa(area->addr);
 +
-+      // This area is used for foreign page mappping.
-+      // So underlying machine page may not be assigned.
++      /* This area is used for foreign page mappping.
++       * So underlying machine page may not be assigned. */
 +      for (i = 0; i < (1 << order); i++) {
 +              unsigned long ret;
 +              unsigned long gpfn = (phys_addr >> PAGE_SHIFT) + i;
@@ -29248,10 +29683,39 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/util.c lin
 + *  tab-width: 8
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xcom_hcall.c linux-2.6.18-xen.hg/arch/ia64/xen/xcom_hcall.c
---- linux-2.6.18/arch/ia64/xen/xcom_hcall.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/xcom_hcall.c     2007-12-23 11:14:54.675867776 +0100
-@@ -0,0 +1,663 @@
+--- linux-2.6.18.8/arch/ia64/xen/xcom_asm.S    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/xcom_asm.S       2008-05-19 00:33:05.036436456 +0300
+@@ -0,0 +1,27 @@
++/*
++ * xencomm suspend support
++ * Support routines for Xen
++ *
++ * Copyright (C) 2005 Dan Magenheimer <dan.magenheimer@hp.com>
++ */
++#include <asm/asmmacro.h>
++#include <xen/interface/xen.h>
++
++/*
++ * Stub for suspend.
++ * Just force the stacked registers to be written in memory.
++ */
++GLOBAL_ENTRY(xencomm_arch_hypercall_suspend)
++      ;; 
++      alloc r20=ar.pfs,0,0,6,0
++      mov r2=__HYPERVISOR_sched_op
++      ;; 
++      /* We don't want to deal with RSE.  */
++      flushrs
++      mov r33=r32
++      mov r32=2 // SCHEDOP_shutdown
++      ;;
++      break 0x1000
++      ;; 
++      br.ret.sptk.many b0
++END(xencomm_arch_hypercall_suspend)
+--- linux-2.6.18.8/arch/ia64/xen/xcom_hcall.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/xcom_hcall.c     2008-05-19 00:33:05.036436456 +0300
+@@ -0,0 +1,661 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
@@ -29738,7 +30202,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xcom_hcall
 +}
 +EXPORT_SYMBOL_GPL(xencomm_hypercall_hvm_op);
 +
-+#ifndef CONFIG_VMX_GUEST
 +int
 +xencomm_hypercall_suspend(unsigned long srec)
 +{
@@ -29749,7 +30212,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xcom_hcall
 +      return xencomm_arch_hypercall_suspend(
 +              xencomm_map_no_alloc(&arg, sizeof(arg)));
 +}
-+#endif
 +
 +int
 +xencomm_hypercall_xenoprof_op(int op, void *arg)
@@ -29915,10 +30377,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xcom_hcall
 +
 +      return xencomm_arch_hypercall_kexec_op(cmd, desc);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xcom_privcmd.c linux-2.6.18-xen.hg/arch/ia64/xen/xcom_privcmd.c
---- linux-2.6.18/arch/ia64/xen/xcom_privcmd.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/xcom_privcmd.c   2007-12-23 11:14:54.675867776 +0100
-@@ -0,0 +1,823 @@
+--- linux-2.6.18.8/arch/ia64/xen/xcom_privcmd.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/xcom_privcmd.c   2008-05-19 00:33:05.040436686 +0300
+@@ -0,0 +1,824 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
 + * it under the terms of the GNU General Public License as published by
@@ -30032,6 +30493,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xcom_privc
 +              break;
 +      case XEN_SYSCTL_tbuf_op:
 +      case XEN_SYSCTL_sched_id:
++      case XEN_SYSCTL_availheap:
 +              break;
 +      case XEN_SYSCTL_perfc_op:
 +      {
@@ -30041,8 +30503,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xcom_privc
 +                      .interface_version = XEN_SYSCTL_INTERFACE_VERSION,
 +                      .u.perfc_op = {
 +                              .cmd = XEN_SYSCTL_PERFCOP_query,
-+                              // .desc.p = NULL,
-+                              // .val.p = NULL,
++                              /* .desc.p = NULL, */
++                              /* .val.p = NULL, */
 +                      },
 +              };
 +
@@ -30742,122 +31204,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xcom_privc
 +      }
 +}
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xencomm.c linux-2.6.18-xen.hg/arch/ia64/xen/xencomm.c
---- linux-2.6.18/arch/ia64/xen/xencomm.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/xencomm.c        2007-12-23 11:14:54.675867776 +0100
-@@ -0,0 +1,109 @@
-+/*
-+ * Copyright (C) 2006 Hollis Blanchard <hollisb@us.ibm.com>, IBM Corporation
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ * 
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ * 
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-+ */
-+
-+#include <linux/gfp.h>
-+#include <linux/mm.h>
-+#include <xen/interface/xen.h>
-+#include <asm/page.h>
-+
-+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
-+#include <xen/platform-compat.h>
-+#endif
-+
-+#include <asm/xen/xencomm.h>
-+
-+static unsigned long kernel_start_pa;
-+
-+void
-+xencomm_initialize (void)
-+{
-+      kernel_start_pa = KERNEL_START - ia64_tpa(KERNEL_START);
-+}
-+
-+/* Translate virtual address to physical address.  */
-+unsigned long
-+xencomm_vtop(unsigned long vaddr)
-+{
-+#ifndef CONFIG_VMX_GUEST
-+      struct page *page;
-+      struct vm_area_struct *vma;
-+#endif
-+
-+      if (vaddr == 0)
-+              return 0;
-+
-+#ifdef __ia64__
-+      if (REGION_NUMBER(vaddr) == 5) {
-+              pgd_t *pgd;
-+              pud_t *pud;
-+              pmd_t *pmd;
-+              pte_t *ptep;
-+
-+              /* On ia64, TASK_SIZE refers to current.  It is not initialized
-+                 during boot.
-+                 Furthermore the kernel is relocatable and __pa() doesn't
-+                 work on  addresses.  */
-+              if (vaddr >= KERNEL_START
-+                  && vaddr < (KERNEL_START + KERNEL_TR_PAGE_SIZE)) {
-+                      return vaddr - kernel_start_pa;
-+              }
-+
-+              /* In kernel area -- virtually mapped.  */
-+              pgd = pgd_offset_k(vaddr);
-+              if (pgd_none(*pgd) || pgd_bad(*pgd))
-+                      return ~0UL;
-+
-+              pud = pud_offset(pgd, vaddr);
-+              if (pud_none(*pud) || pud_bad(*pud))
-+                      return ~0UL;
-+
-+              pmd = pmd_offset(pud, vaddr);
-+              if (pmd_none(*pmd) || pmd_bad(*pmd))
-+                      return ~0UL;
-+
-+              ptep = pte_offset_kernel(pmd, vaddr);
-+              if (!ptep)
-+                      return ~0UL;
-+
-+              return (pte_val(*ptep) & _PFN_MASK) | (vaddr & ~PAGE_MASK);
-+      }
-+#endif
-+
-+      if (vaddr > TASK_SIZE) {
-+              /* kernel address */
-+              return __pa(vaddr);
-+      }
-+
-+
-+#ifdef CONFIG_VMX_GUEST
-+      /* No privcmd within vmx guest.  */
-+      return ~0UL;
-+#else
-+      /* XXX double-check (lack of) locking */
-+      vma = find_extend_vma(current->mm, vaddr);
-+      if (!vma)
-+              return ~0UL;
-+
-+      /* We assume the page is modified.  */
-+      page = follow_page(vma, vaddr, FOLL_WRITE | FOLL_TOUCH);
-+      if (!page)
-+              return ~0UL;
-+
-+      return (page_to_pfn(page) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);
-+#endif
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xen_dma.c linux-2.6.18-xen.hg/arch/ia64/xen/xen_dma.c
---- linux-2.6.18/arch/ia64/xen/xen_dma.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/xen_dma.c        2007-12-23 11:14:54.675867776 +0100
+--- linux-2.6.18.8/arch/ia64/xen/xen_dma.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/xen_dma.c        2008-05-19 00:33:05.044436917 +0300
 @@ -0,0 +1,155 @@
 +/*
 + * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
@@ -31014,9 +31362,120 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xen_dma.c
 +      gnttab_dma_unmap_page(dma_addr);
 +}
 +EXPORT_SYMBOL(xen_unmap_single);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xenentry.S linux-2.6.18-xen.hg/arch/ia64/xen/xenentry.S
---- linux-2.6.18/arch/ia64/xen/xenentry.S      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/xenentry.S       2007-12-23 11:14:54.679201278 +0100
+--- linux-2.6.18.8/arch/ia64/xen/xencomm.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/xencomm.c        2008-05-19 00:33:05.044436917 +0300
+@@ -0,0 +1,109 @@
++/*
++ * Copyright (C) 2006 Hollis Blanchard <hollisb@us.ibm.com>, IBM Corporation
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ * 
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ * 
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
++ */
++
++#include <linux/gfp.h>
++#include <linux/mm.h>
++#include <xen/interface/xen.h>
++#include <asm/page.h>
++
++#ifdef HAVE_XEN_PLATFORM_COMPAT_H
++#include <xen/platform-compat.h>
++#endif
++
++#include <asm/xen/xencomm.h>
++
++static unsigned long kernel_start_pa;
++
++void
++xencomm_initialize (void)
++{
++      kernel_start_pa = KERNEL_START - ia64_tpa(KERNEL_START);
++}
++
++/* Translate virtual address to physical address.  */
++unsigned long
++xencomm_vtop(unsigned long vaddr)
++{
++#ifndef CONFIG_VMX_GUEST
++      struct page *page;
++      struct vm_area_struct *vma;
++#endif
++
++      if (vaddr == 0)
++              return 0;
++
++#ifdef __ia64__
++      if (REGION_NUMBER(vaddr) == 5) {
++              pgd_t *pgd;
++              pud_t *pud;
++              pmd_t *pmd;
++              pte_t *ptep;
++
++              /* On ia64, TASK_SIZE refers to current.  It is not initialized
++                 during boot.
++                 Furthermore the kernel is relocatable and __pa() doesn't
++                 work on  addresses.  */
++              if (vaddr >= KERNEL_START
++                  && vaddr < (KERNEL_START + KERNEL_TR_PAGE_SIZE)) {
++                      return vaddr - kernel_start_pa;
++              }
++
++              /* In kernel area -- virtually mapped.  */
++              pgd = pgd_offset_k(vaddr);
++              if (pgd_none(*pgd) || pgd_bad(*pgd))
++                      return ~0UL;
++
++              pud = pud_offset(pgd, vaddr);
++              if (pud_none(*pud) || pud_bad(*pud))
++                      return ~0UL;
++
++              pmd = pmd_offset(pud, vaddr);
++              if (pmd_none(*pmd) || pmd_bad(*pmd))
++                      return ~0UL;
++
++              ptep = pte_offset_kernel(pmd, vaddr);
++              if (!ptep)
++                      return ~0UL;
++
++              return (pte_val(*ptep) & _PFN_MASK) | (vaddr & ~PAGE_MASK);
++      }
++#endif
++
++      if (vaddr > TASK_SIZE) {
++              /* kernel address */
++              return __pa(vaddr);
++      }
++
++
++#ifdef CONFIG_VMX_GUEST
++      /* No privcmd within vmx guest.  */
++      return ~0UL;
++#else
++      /* XXX double-check (lack of) locking */
++      vma = find_extend_vma(current->mm, vaddr);
++      if (!vma)
++              return ~0UL;
++
++      /* We assume the page is modified.  */
++      page = follow_page(vma, vaddr, FOLL_WRITE | FOLL_TOUCH);
++      if (!page)
++              return ~0UL;
++
++      return (page_to_pfn(page) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);
++#endif
++}
+--- linux-2.6.18.8/arch/ia64/xen/xenentry.S    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/xenentry.S       2008-05-19 00:33:05.044436917 +0300
 @@ -0,0 +1,931 @@
 +/*
 + * ia64/xen/entry.S
@@ -31949,33 +32408,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xenentry.S
 +#else
 +END(ia64_leave_kernel)
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xenhpski.c linux-2.6.18-xen.hg/arch/ia64/xen/xenhpski.c
---- linux-2.6.18/arch/ia64/xen/xenhpski.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/xenhpski.c       2007-12-23 11:14:54.679201278 +0100
-@@ -0,0 +1,19 @@
-+#include <linux/kernel.h>
-+#include <asm/hypervisor.h>
-+
-+int
-+running_on_sim(void)
-+{
-+      int i;
-+      long cpuid[6];
-+
-+      for (i = 0; i < 5; ++i)
-+              cpuid[i] = xen_get_cpuid(i);
-+      if ((cpuid[0] & 0xff) != 'H') return 0;
-+      if ((cpuid[3] & 0xff) != 0x4) return 0;
-+      if (((cpuid[3] >> 8) & 0xff) != 0x0) return 0;
-+      if (((cpuid[3] >> 16) & 0xff) != 0x0) return 0;
-+      if (((cpuid[3] >> 24) & 0x7) != 0x7) return 0;
-+      return 1;
-+}
-+
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xenivt.S linux-2.6.18-xen.hg/arch/ia64/xen/xenivt.S
---- linux-2.6.18/arch/ia64/xen/xenivt.S        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/xenivt.S 2007-12-23 11:14:54.679201278 +0100
-@@ -0,0 +1,2177 @@
+--- linux-2.6.18.8/arch/ia64/xen/xenivt.S      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/xenivt.S 2008-05-19 00:33:05.048437147 +0300
+@@ -0,0 +1,2178 @@
 +/*
 + * arch/ia64/xen/ivt.S
 + *
@@ -32674,16 +33109,17 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xenivt.S l
 +      st4 [r3]=r14                            // vpsr.ic = 1
 +      adds r3=8,r2                            // set up second base pointer
 +      ;;
++      sum PSR_DEFAULT_BITS
 +#else
 +      mov out0=cr.ifa
 +      mov out1=cr.isr
 +      adds r3=8,r2                            // set up second base pointer
 +      ;;
 +      ssm psr.ic | PSR_DEFAULT_BITS
++#endif
 +      ;;
 +      srlz.i                                  // guarantee that interruption collectin is on
 +      ;;
-+#endif
 +#ifdef CONFIG_XEN
 +    
 +#define MASK_TO_PEND_OFS    (-1)
@@ -34153,9 +34589,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xenivt.S l
 +
 +   
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xenminstate.h linux-2.6.18-xen.hg/arch/ia64/xen/xenminstate.h
---- linux-2.6.18/arch/ia64/xen/xenminstate.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/xenminstate.h    2007-12-23 11:14:54.679201278 +0100
+--- linux-2.6.18.8/arch/ia64/xen/xenminstate.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/xenminstate.h    2008-05-19 00:33:05.068438300 +0300
 @@ -0,0 +1,358 @@
 +#include <asm/cache.h>
 +
@@ -34515,9 +34950,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xenminstat
 +#else
 +#define SAVE_MIN              DO_SAVE_MIN(     , mov r30=r0, )
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xenpal.S linux-2.6.18-xen.hg/arch/ia64/xen/xenpal.S
---- linux-2.6.18/arch/ia64/xen/xenpal.S        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/xenpal.S 2007-12-23 11:14:54.679201278 +0100
+--- linux-2.6.18.8/arch/ia64/xen/xenpal.S      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/xenpal.S 2008-05-19 00:33:05.072438531 +0300
 @@ -0,0 +1,85 @@
 +/*
 + * ia64/xen/xenpal.S
@@ -34604,10 +35038,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xenpal.S l
 +      srlz.d                          // seralize restoration of psr.l
 +      br.ret.sptk.many b0
 +END(xen_pal_call_static)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xensetup.S linux-2.6.18-xen.hg/arch/ia64/xen/xensetup.S
---- linux-2.6.18/arch/ia64/xen/xensetup.S      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/ia64/xen/xensetup.S       2007-12-23 11:14:54.682534784 +0100
-@@ -0,0 +1,59 @@
+--- linux-2.6.18.8/arch/ia64/xen/xensetup.S    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/ia64/xen/xensetup.S       2008-05-19 00:33:05.072438531 +0300
+@@ -0,0 +1,40 @@
 +/*
 + * Support routines for Xen
 + *
@@ -34648,28 +35081,70 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/ia64/xen/xensetup.S
 +      br.ret.sptk.many rp
 +      ;;
 +END(early_xen_setup)
+--- linux-2.6.18.8/arch/powerpc/Kconfig        2008-05-19 00:42:33.785223278 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/Kconfig   2008-05-19 00:33:12.688877542 +0300
+@@ -439,6 +439,17 @@
+       bool
+       default n
++config PPC_XEN
++       bool "Enable Xen compatible kernel"
++       depends on PPC_MULTIPLATFORM && PPC64 && PPC_MAPLE && PPC_PSERIES && SMP
++       select XEN
++       select XEN_PRIVILEGED_GUEST
++       select XEN_UNPRIVILEGED_GUEST
++       select XEN_XENCOMM
++       
++       help
++        This option will compile a kernel compatible with Xen hypervisor
 +
-+#include <xen/interface/xen.h>
+ config XICS
+       depends on PPC_PSERIES
+       bool
+@@ -1080,6 +1091,8 @@
+ source "security/Kconfig"
++source "drivers/xen/Kconfig"
 +
-+/* Stub for suspend.
-+   Just force the stacked registers to be written in memory.  */      
-+GLOBAL_ENTRY(xencomm_arch_hypercall_suspend)
-+      ;; 
-+      alloc r20=ar.pfs,0,0,6,0
-+      mov r2=__HYPERVISOR_sched_op
-+      ;; 
-+      /* We don't want to deal with RSE.  */
-+      flushrs
-+      mov r33=r32
-+      mov r32=2 // SCHEDOP_shutdown
-+      ;;
-+      break 0x1000
-+      ;; 
-+      br.ret.sptk.many b0
-+END(xencomm_arch_hypercall_suspend)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/boot/Makefile linux-2.6.18-xen.hg/arch/powerpc/boot/Makefile
---- linux-2.6.18/arch/powerpc/boot/Makefile    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/boot/Makefile     2007-12-23 11:14:58.952759023 +0100
+ config KEYS_COMPAT
+       bool
+       depends on COMPAT && KEYS
+--- linux-2.6.18.8/arch/powerpc/Kconfig.debug  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/Kconfig.debug     2008-05-19 00:33:12.688877542 +0300
+@@ -160,6 +160,20 @@
+         Select this to enable early debugging for legacy iSeries. You need
+         to hit "Ctrl-x Ctrl-x" to see the messages on the console.
++config PPC_EARLY_DEBUG_XEN_DOM0
++      bool "Xen Dom0 Console"
++      depends on PPC_XEN
++      help
++        Select this to enable early debugging for Xen Dom0. Setting
++        this will result in a kernel that may not work as a DomU.
++
++config PPC_EARLY_DEBUG_XEN_DOMU
++      bool "Xen DomU Console"
++      depends on PPC_XEN && XEN_UNPRIVILEGED_GUEST
++      help
++        Select this to enable early debugging for Xen DomU. Setting
++        this will result in a kernel that may not work as a Dom0.
++
+ endchoice
+ endmenu
+--- linux-2.6.18.8/arch/powerpc/Makefile       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/Makefile  2008-05-19 00:33:12.688877542 +0300
+@@ -65,6 +65,7 @@
+ AFLAGS-$(CONFIG_PPC32)        := -Iarch/$(ARCH)
+ CFLAGS-$(CONFIG_PPC64)        := -mminimal-toc -mtraceback=none  -mcall-aixdesc
+ CFLAGS-$(CONFIG_PPC32)        := -Iarch/$(ARCH) -ffixed-r2 -mmultiple
++CFLAGS-$(CONFIG_PPC_XEN) += -Iinclude/asm-$(ARCH)/xen
+ CPPFLAGS      += $(CPPFLAGS-y)
+ AFLAGS                += $(AFLAGS-y)
+ CFLAGS                += -msoft-float -pipe $(CFLAGS-y)
+--- linux-2.6.18.8/arch/powerpc/boot/Makefile  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/boot/Makefile     2008-05-19 00:33:12.692877773 +0300
 @@ -36,8 +36,11 @@
  $(addprefix $(obj)/,$(zlib) main.o): $(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
  #$(addprefix $(obj)/,main.o): $(addprefix $(obj)/,zlib.h)
@@ -34682,9 +35157,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/boot/Makefi
  src-boot := $(addprefix $(obj)/, $(src-boot))
  obj-boot := $(addsuffix .o, $(basename $(src-boot)))
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/boot/xen_guest.S linux-2.6.18-xen.hg/arch/powerpc/boot/xen_guest.S
---- linux-2.6.18/arch/powerpc/boot/xen_guest.S 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/boot/xen_guest.S  2007-12-23 11:14:58.966093066 +0100
+--- linux-2.6.18.8/arch/powerpc/boot/xen_guest.S       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/boot/xen_guest.S  2008-05-19 00:33:12.712878926 +0300
 @@ -0,0 +1,7 @@
 +      .section __xen_guest
 +      .ascii  "GUEST_OS=linux"
@@ -34693,9 +35167,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/boot/xen_gu
 +      .ascii  ",VIRT_BASE=0x0"
 +      .ascii  ",LOADER=generic"
 +      .byte   0
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/configs/xen_maple_defconfig linux-2.6.18-xen.hg/arch/powerpc/configs/xen_maple_defconfig
---- linux-2.6.18/arch/powerpc/configs/xen_maple_defconfig      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/configs/xen_maple_defconfig       2007-12-23 11:14:58.979427095 +0100
+--- linux-2.6.18.8/arch/powerpc/configs/xen_maple_defconfig    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/configs/xen_maple_defconfig       2008-05-19 00:33:12.732880079 +0300
 @@ -0,0 +1,1342 @@
 +#
 +# Automatically generated make config: don't edit
@@ -36039,63 +36512,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/configs/xen
 +#
 +# Hardware crypto devices
 +#
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/Kconfig linux-2.6.18-xen.hg/arch/powerpc/Kconfig
---- linux-2.6.18/arch/powerpc/Kconfig  2007-12-23 11:26:51.006787102 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/Kconfig   2007-12-23 11:14:58.952759023 +0100
-@@ -439,6 +439,17 @@
-       bool
-       default n
-+config PPC_XEN
-+       bool "Enable Xen compatible kernel"
-+       depends on PPC_MULTIPLATFORM && PPC64 && PPC_MAPLE && PPC_PSERIES && SMP
-+       select XEN
-+       select XEN_PRIVILEGED_GUEST
-+       select XEN_UNPRIVILEGED_GUEST
-+       select XEN_XENCOMM
-+       
-+       help
-+        This option will compile a kernel compatible with Xen hypervisor
-+
- config XICS
-       depends on PPC_PSERIES
-       bool
-@@ -1080,6 +1091,8 @@
- source "security/Kconfig"
-+source "drivers/xen/Kconfig"
-+
- config KEYS_COMPAT
-       bool
-       depends on COMPAT && KEYS
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/Kconfig.debug linux-2.6.18-xen.hg/arch/powerpc/Kconfig.debug
---- linux-2.6.18/arch/powerpc/Kconfig.debug    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/Kconfig.debug     2007-12-23 11:14:58.952759023 +0100
-@@ -160,6 +160,20 @@
-         Select this to enable early debugging for legacy iSeries. You need
-         to hit "Ctrl-x Ctrl-x" to see the messages on the console.
-+config PPC_EARLY_DEBUG_XEN_DOM0
-+      bool "Xen Dom0 Console"
-+      depends on PPC_XEN
-+      help
-+        Select this to enable early debugging for Xen Dom0. Setting
-+        this will result in a kernel that may not work as a DomU.
-+
-+config PPC_EARLY_DEBUG_XEN_DOMU
-+      bool "Xen DomU Console"
-+      depends on PPC_XEN && XEN_UNPRIVILEGED_GUEST
-+      help
-+        Select this to enable early debugging for Xen DomU. Setting
-+        this will result in a kernel that may not work as a Dom0.
-+
- endchoice
- endmenu
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/kernel/cpu_setup_power4.S linux-2.6.18-xen.hg/arch/powerpc/kernel/cpu_setup_power4.S
---- linux-2.6.18/arch/powerpc/kernel/cpu_setup_power4.S        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/kernel/cpu_setup_power4.S 2007-12-23 11:14:58.982760606 +0100
+--- linux-2.6.18.8/arch/powerpc/kernel/cpu_setup_power4.S      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/kernel/cpu_setup_power4.S 2008-05-19 00:33:12.740880540 +0300
 @@ -73,6 +73,13 @@
        blr
  
@@ -36110,9 +36528,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/kernel/cpu_
        mfspr   r0,SPRN_HID0
        li      r11,5                   /* clear DOZE and SLEEP */
        rldimi  r0,r11,52,8             /* set NAP and DPM */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/kernel/prom_init.c linux-2.6.18-xen.hg/arch/powerpc/kernel/prom_init.c
---- linux-2.6.18/arch/powerpc/kernel/prom_init.c       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/kernel/prom_init.c        2007-12-23 11:14:59.016095685 +0100
+--- linux-2.6.18.8/arch/powerpc/kernel/prom_init.c     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/kernel/prom_init.c        2008-05-19 00:33:12.852886996 +0300
 @@ -188,6 +188,7 @@
  #define PLATFORM_LPAR         0x0001
  #define PLATFORM_POWERMAC     0x0400
@@ -36168,9 +36585,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/kernel/prom
  
        /*
         * On non-powermacs, try to instantiate RTAS and puts all CPUs
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/kernel/setup-common.c linux-2.6.18-xen.hg/arch/powerpc/kernel/setup-common.c
---- linux-2.6.18/arch/powerpc/kernel/setup-common.c    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/kernel/setup-common.c     2007-12-23 11:14:59.022762705 +0100
+--- linux-2.6.18.8/arch/powerpc/kernel/setup-common.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/kernel/setup-common.c     2008-05-19 00:33:12.864887688 +0300
 @@ -387,6 +387,12 @@
                }
        }
@@ -36184,9 +36600,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/kernel/setu
  #ifdef CONFIG_PPC64
        /*
         * On pSeries LPAR, we need to know how many cpus
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/kernel/udbg.c linux-2.6.18-xen.hg/arch/powerpc/kernel/udbg.c
---- linux-2.6.18/arch/powerpc/kernel/udbg.c    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/kernel/udbg.c     2007-12-23 11:14:59.032763228 +0100
+--- linux-2.6.18.8/arch/powerpc/kernel/udbg.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/kernel/udbg.c     2008-05-19 00:33:12.896889532 +0300
 @@ -45,6 +45,9 @@
  #elif defined(CONFIG_PPC_EARLY_DEBUG_ISERIES)
        /* For iSeries - hit Ctrl-x Ctrl-x to see the output */
@@ -36197,20 +36612,24 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/kernel/udbg
  #endif
  }
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/Makefile linux-2.6.18-xen.hg/arch/powerpc/Makefile
---- linux-2.6.18/arch/powerpc/Makefile 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/Makefile  2007-12-23 11:14:58.952759023 +0100
-@@ -65,6 +65,7 @@
- AFLAGS-$(CONFIG_PPC32)        := -Iarch/$(ARCH)
- CFLAGS-$(CONFIG_PPC64)        := -mminimal-toc -mtraceback=none  -mcall-aixdesc
- CFLAGS-$(CONFIG_PPC32)        := -Iarch/$(ARCH) -ffixed-r2 -mmultiple
-+CFLAGS-$(CONFIG_PPC_XEN) += -Iinclude/asm-$(ARCH)/xen
- CPPFLAGS      += $(CPPFLAGS-y)
- AFLAGS                += $(AFLAGS-y)
- CFLAGS                += -msoft-float -pipe $(CFLAGS-y)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/mm/slb_low.S linux-2.6.18-xen.hg/arch/powerpc/mm/slb_low.S
---- linux-2.6.18/arch/powerpc/mm/slb_low.S     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/mm/slb_low.S      2007-12-23 11:14:59.089432866 +0100
+--- linux-2.6.18.8/arch/powerpc/kernel/vdso.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/kernel/vdso.c     2008-05-19 00:33:12.896889532 +0300
+@@ -282,6 +282,13 @@
+        * pages though
+        */
+       vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC;
++      /*
++       * Make sure the vDSO gets into every core dump.
++       * Dumping its contents makes post-mortem fully interpretable later
++       * without matching up the same kernel and hardware config to see
++       * what PC values meant.
++       */
++      vma->vm_flags |= VM_ALWAYSDUMP;
+       vma->vm_flags |= mm->def_flags;
+       vma->vm_page_prot = protection_map[vma->vm_flags & 0x7];
+       vma->vm_ops = &vdso_vmops;
+--- linux-2.6.18.8/arch/powerpc/mm/slb_low.S   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/mm/slb_low.S      2008-05-19 00:33:12.992895066 +0300
 @@ -51,6 +51,23 @@
        */
        bne     cr7,1f
@@ -36235,9 +36654,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/mm/slb_low.
        /* Linear mapping encoding bits, the "li" instruction below will
         * be patched by the kernel at boot
         */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/Makefile linux-2.6.18-xen.hg/arch/powerpc/platforms/Makefile
---- linux-2.6.18/arch/powerpc/platforms/Makefile       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/Makefile        2007-12-23 11:14:59.109433918 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/Makefile     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/Makefile        2008-05-19 00:33:13.064899216 +0300
 @@ -12,6 +12,8 @@
  obj-$(CONFIG_PPC_86xx)                += 86xx/
  obj-$(CONFIG_PPC_PSERIES)     += pseries/
@@ -36247,9 +36665,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/M
  obj-$(CONFIG_PPC_MAPLE)               += maple/
  obj-$(CONFIG_PPC_CELL)                += cell/
  obj-$(CONFIG_EMBEDDED6xx)     += embedded6xx/
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/pseries/iommu.c linux-2.6.18-xen.hg/arch/powerpc/platforms/pseries/iommu.c
---- linux-2.6.18/arch/powerpc/platforms/pseries/iommu.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/pseries/iommu.c 2007-12-23 11:14:59.179437597 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/pseries/iommu.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/pseries/iommu.c 2008-05-19 00:33:13.728937491 +0300
 @@ -531,6 +531,17 @@
         * already allocated.
         */
@@ -36268,9 +36685,31 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/p
  
        for (pdn = dn; pdn && PCI_DN(pdn) && !PCI_DN(pdn)->iommu_table;
             pdn = pdn->parent) {
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/balloon.c linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/balloon.c
---- linux-2.6.18/arch/powerpc/platforms/xen/balloon.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/balloon.c   2007-12-23 11:14:59.186104615 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/Makefile 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/Makefile    2008-05-19 00:33:13.804941872 +0300
+@@ -0,0 +1,20 @@
++obj-y += gnttab.o
++obj-y += hcall.o
++obj-y += reboot.o
++obj-y += setup.o
++obj-y += smp.o
++obj-y += time.o
++obj-y += udbg_xen.o
++obj-y += xen_guest.o
++obj-y += xencomm.o
++
++# we need the latest __XEN_INTERFACE_VERSION__ (see xen-compat.h)
++CFLAGS_hcall.o += -D__XEN_TOOLS__
++
++ifndef CONFIG_XEN_BALLOON
++obj-y += balloon.o
++endif
++
++ifndef CONFIG_XEN_UTIL
++obj-y += util.o
++endif
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/balloon.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/balloon.c   2008-05-19 00:33:13.804941872 +0300
 @@ -0,0 +1,82 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -36354,9 +36793,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/x
 +EXPORT_SYMBOL_GPL(alloc_empty_pages_and_pagevec);
 +EXPORT_SYMBOL_GPL(free_empty_pages_and_pagevec);
 +EXPORT_SYMBOL_GPL(balloon_release_driver_page);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/gnttab.c linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/gnttab.c
---- linux-2.6.18/arch/powerpc/platforms/xen/gnttab.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/gnttab.c    2007-12-23 11:14:59.186104615 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/gnttab.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/gnttab.c    2008-05-19 00:33:13.804941872 +0300
 @@ -0,0 +1,468 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -36826,9 +37264,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/x
 +
 +      return shared;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/hcall.c linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/hcall.c
---- linux-2.6.18/arch/powerpc/platforms/xen/hcall.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/hcall.c     2007-12-23 11:14:59.189438125 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/hcall.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/hcall.c     2008-05-19 00:33:13.804941872 +0300
 @@ -0,0 +1,891 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -37721,33 +38158,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/x
 +
 +      return rc;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/Makefile linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/Makefile
---- linux-2.6.18/arch/powerpc/platforms/xen/Makefile   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/Makefile    2007-12-23 11:14:59.186104615 +0100
-@@ -0,0 +1,20 @@
-+obj-y += gnttab.o
-+obj-y += hcall.o
-+obj-y += reboot.o
-+obj-y += setup.o
-+obj-y += smp.o
-+obj-y += time.o
-+obj-y += udbg_xen.o
-+obj-y += xen_guest.o
-+obj-y += xencomm.o
-+
-+# we need the latest __XEN_INTERFACE_VERSION__ (see xen-compat.h)
-+CFLAGS_hcall.o += -D__XEN_TOOLS__
-+
-+ifndef CONFIG_XEN_BALLOON
-+obj-y += balloon.o
-+endif
-+
-+ifndef CONFIG_XEN_UTIL
-+obj-y += util.o
-+endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/reboot.c linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/reboot.c
---- linux-2.6.18/arch/powerpc/platforms/xen/reboot.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/reboot.c    2007-12-23 11:14:59.189438125 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/reboot.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/reboot.c    2008-05-19 00:33:13.808942103 +0300
 @@ -0,0 +1,53 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -37802,9 +38214,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/x
 +              ppc_md.halt      = domain_machine_power_off;
 +      }
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/setup.c linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/setup.c
---- linux-2.6.18/arch/powerpc/platforms/xen/setup.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/setup.c     2007-12-23 11:14:59.189438125 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/setup.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/setup.c     2008-05-19 00:33:13.808942103 +0300
 @@ -0,0 +1,336 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -38142,9 +38553,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/x
 +      .machine_crash_shutdown = xen_machine_crash_shutdown,
 +#endif
 +};
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/setup.h linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/setup.h
---- linux-2.6.18/arch/powerpc/platforms/xen/setup.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/setup.h     2007-12-23 11:14:59.189438125 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/setup.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/setup.h     2008-05-19 00:33:13.808942103 +0300
 @@ -0,0 +1,47 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -38193,9 +38603,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/x
 +
 +extern void __init xen_setup_time(struct machdep_calls *host_md);
 +extern void xen_setup_smp(void);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/smp.c linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/smp.c
---- linux-2.6.18/arch/powerpc/platforms/xen/smp.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/smp.c       2007-12-23 11:14:59.189438125 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/smp.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/smp.c       2008-05-19 00:33:13.848944409 +0300
 @@ -0,0 +1,444 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -38641,9 +39050,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/x
 +      xen_boot_secondary_vcpus();
 +      smp_release_cpus();
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/time.c linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/time.c
---- linux-2.6.18/arch/powerpc/platforms/xen/time.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/time.c      2007-12-23 11:14:59.189438125 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/time.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/time.c      2008-05-19 00:33:13.848944409 +0300
 @@ -0,0 +1,114 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -38759,9 +39167,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/x
 +      ppc_md.get_rtc_time = xen_get_rtc_time;
 +      host_md_get_rtc_time = host_md->get_rtc_time;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/udbg_xen.c linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/udbg_xen.c
---- linux-2.6.18/arch/powerpc/platforms/xen/udbg_xen.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/udbg_xen.c  2007-12-23 11:14:59.189438125 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/udbg_xen.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/udbg_xen.c  2008-05-19 00:33:13.852944639 +0300
 @@ -0,0 +1,164 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -38927,9 +39334,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/x
 +              intf = (struct xencons_interface *)mfn_to_virt(__console_mfn);
 +      }
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/util.c linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/util.c
---- linux-2.6.18/arch/powerpc/platforms/xen/util.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/util.c      2007-12-23 11:14:59.192771633 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/util.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/util.c      2008-05-19 00:33:13.852944639 +0300
 @@ -0,0 +1,70 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -39001,9 +39407,38 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/x
 +      preempt_enable();
 +}
 +EXPORT_SYMBOL_GPL(unlock_vm_area);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/xencomm.c linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/xencomm.c
---- linux-2.6.18/arch/powerpc/platforms/xen/xencomm.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/xencomm.c   2007-12-23 11:14:59.192771633 +0100
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/xen_guest.S      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/xen_guest.S 2008-05-19 00:33:13.852944639 +0300
+@@ -0,0 +1,27 @@
++/*
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
++ *
++ * Copyright (C) IBM Corp. 2006
++ *
++ * Authors: Jimi Xenidis <jimix@watson.ibm.com>
++ */
++
++      .section __xen_guest
++      .ascii  "GUEST_OS=linux"
++      .ascii  ",GUEST_VER=xen-3.0"
++      .ascii  ",XEN_VER=xen-3.0"
++      .ascii  ",VIRT_BASE=0xC000000000000000"
++      .ascii  ",LOADER=generic"
++      .byte   0
+--- linux-2.6.18.8/arch/powerpc/platforms/xen/xencomm.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/xencomm.c   2008-05-19 00:33:13.852944639 +0300
 @@ -0,0 +1,54 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -39059,40 +39494,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/x
 +
 +      return (page_to_pfn(page) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/platforms/xen/xen_guest.S linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/xen_guest.S
---- linux-2.6.18/arch/powerpc/platforms/xen/xen_guest.S        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/powerpc/platforms/xen/xen_guest.S 2007-12-23 11:14:59.192771633 +0100
-@@ -0,0 +1,27 @@
-+/*
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ *
-+ * This program is distributed in the hope that it will be useful,
-+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
-+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+ * GNU General Public License for more details.
-+ *
-+ * You should have received a copy of the GNU General Public License
-+ * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-+ *
-+ * Copyright (C) IBM Corp. 2006
-+ *
-+ * Authors: Jimi Xenidis <jimix@watson.ibm.com>
-+ */
-+
-+      .section __xen_guest
-+      .ascii  "GUEST_OS=linux"
-+      .ascii  ",GUEST_VER=xen-3.0"
-+      .ascii  ",XEN_VER=xen-3.0"
-+      .ascii  ",VIRT_BASE=0xC000000000000000"
-+      .ascii  ",LOADER=generic"
-+      .byte   0
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/sysdev/mpic.c linux-2.6.18-xen.hg/arch/powerpc/sysdev/mpic.c
---- linux-2.6.18/arch/powerpc/sysdev/mpic.c    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/sysdev/mpic.c     2007-12-23 11:14:59.199438646 +0100
+--- linux-2.6.18.8/arch/powerpc/sysdev/mpic.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/sysdev/mpic.c     2008-05-19 00:33:13.904947637 +0300
 @@ -765,6 +765,9 @@
        else if (hw >= MPIC_VEC_IPI_0) {
                WARN_ON(!(mpic->flags & MPIC_PRIMARY));
@@ -39121,9 +39524,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/sysdev/mpic
        /* Initialize interrupt sources */
        if (mpic->irq_count == 0)
                mpic->irq_count = mpic->num_sources;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/xmon/xmon.c linux-2.6.18-xen.hg/arch/powerpc/xmon/xmon.c
---- linux-2.6.18/arch/powerpc/xmon/xmon.c      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/powerpc/xmon/xmon.c       2007-12-23 11:14:59.206105666 +0100
+--- linux-2.6.18.8/arch/powerpc/xmon/xmon.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/powerpc/xmon/xmon.c       2008-05-19 00:33:13.916948328 +0300
 @@ -752,6 +752,9 @@
                        cmd = inchar();
                }
@@ -39134,9 +39536,236 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/powerpc/xmon/xmon.c
                case 'm':
                        cmd = inchar();
                        switch (cmd) {
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/boot/Makefile linux-2.6.18-xen.hg/arch/x86_64/boot/Makefile
---- linux-2.6.18/arch/x86_64/boot/Makefile     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/boot/Makefile      2007-12-23 11:15:00.042816270 +0100
+--- linux-2.6.18.8/arch/x86_64/Kconfig 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/Kconfig    2008-05-19 00:33:18.825231243 +0300
+@@ -135,6 +135,23 @@
+ endchoice
++config X86_64_XEN
++      bool "Enable Xen compatible kernel"
++      select XEN
++      select SWIOTLB
++      help
++        This option will compile a kernel compatible with Xen hypervisor
++
++config X86_NO_TSS
++      bool
++      depends on X86_64_XEN
++      default y
++
++config X86_NO_IDT
++      bool
++      depends on X86_64_XEN
++      default y
++
+ #
+ # Define implied options from the CPU selection here
+ #
+@@ -155,6 +172,7 @@
+ config X86_TSC
+       bool
++      depends on !X86_64_XEN
+       default y
+ config X86_GOOD_APIC
+@@ -197,7 +215,7 @@
+ config X86_HT
+       bool
+-      depends on SMP && !MK8
++      depends on SMP && !MK8 && !X86_64_XEN
+       default y
+ config MATH_EMULATION
+@@ -211,14 +229,22 @@
+ config X86_IO_APIC
+       bool
++      depends !XEN_UNPRIVILEGED_GUEST
++      default y
++
++config X86_XEN_GENAPIC
++      bool
++      depends on X86_64_XEN
+       default y
+ config X86_LOCAL_APIC
+       bool
++      depends !XEN_UNPRIVILEGED_GUEST
+       default y
+ config MTRR
+       bool "MTRR (Memory Type Range Register) support"
++      depends on !XEN_UNPRIVILEGED_GUEST
+       ---help---
+         On Intel P6 family processors (Pentium Pro, Pentium II and later)
+         the Memory Type Range Registers (MTRRs) may be used to control
+@@ -259,7 +285,7 @@
+ config SCHED_SMT
+       bool "SMT (Hyperthreading) scheduler support"
+-      depends on SMP
++      depends on SMP && !X86_64_XEN
+       default n
+       help
+         SMT scheduler support improves the CPU scheduler's decision making
+@@ -269,7 +295,7 @@
+ config SCHED_MC
+       bool "Multi-core scheduler support"
+-      depends on SMP
++      depends on SMP && !X86_64_XEN
+       default y
+       help
+         Multi-core scheduler support improves the CPU scheduler's decision
+@@ -280,7 +306,7 @@
+ config NUMA
+        bool "Non Uniform Memory Access (NUMA) Support"
+-       depends on SMP
++       depends on SMP && !X86_64_XEN
+        help
+        Enable NUMA (Non Uniform Memory Access) support. The kernel 
+        will try to allocate memory used by a CPU on the local memory 
+@@ -341,7 +367,7 @@
+ config ARCH_SPARSEMEM_ENABLE
+       def_bool y
+-      depends on (NUMA || EXPERIMENTAL)
++      depends on (NUMA || EXPERIMENTAL) && !X86_64_XEN
+ config ARCH_MEMORY_PROBE
+       def_bool y
+@@ -365,6 +391,7 @@
+       int "Maximum number of CPUs (2-256)"
+       range 2 255
+       depends on SMP
++      default "16" if X86_64_XEN
+       default "8"
+       help
+         This allows you to specify the maximum number of CPUs which this
+@@ -387,6 +414,7 @@
+ config HPET_TIMER
+       bool
++      depends on !X86_64_XEN
+       default y
+       help
+         Use the IA-PC HPET (High Precision Event Timer) to manage
+@@ -407,7 +435,7 @@
+       default y
+       select SWIOTLB
+       select AGP
+-      depends on PCI
++      depends on PCI && !X86_64_XEN
+       help
+         Support for full DMA access of devices with 32bit memory access only
+         on systems with more than 3GB. This is usually needed for USB,
+@@ -423,7 +451,7 @@
+       bool "IBM Calgary IOMMU support"
+       default y
+       select SWIOTLB
+-      depends on PCI && EXPERIMENTAL
++      depends on PCI && !X86_64_XEN && EXPERIMENTAL
+       help
+         Support for hardware IOMMUs in IBM's xSeries x366 and x460
+         systems. Needed to run systems with more than 3GB of memory
+@@ -444,6 +472,7 @@
+ config X86_MCE
+       bool "Machine check support" if EMBEDDED
++      depends on !X86_64_XEN
+       default y
+       help
+          Include a machine check error handler to report hardware errors.
+@@ -469,7 +498,7 @@
+ config KEXEC
+       bool "kexec system call (EXPERIMENTAL)"
+-      depends on EXPERIMENTAL
++      depends on EXPERIMENTAL && !XEN_UNPRIVILEGED_GUEST
+       help
+         kexec is a system call that implements the ability to shutdown your
+         current kernel, and to start another kernel.  It is like a reboot
+@@ -564,8 +593,9 @@
+       default y
+ menu "Power management options"
++      depends on !XEN_UNPRIVILEGED_GUEST
+-source kernel/power/Kconfig
++source "kernel/power/Kconfig"
+ source "drivers/acpi/Kconfig"
+@@ -588,6 +618,22 @@
+       bool "Support mmconfig PCI config space access"
+       depends on PCI && ACPI
++config XEN_PCIDEV_FRONTEND
++      bool "Xen PCI Frontend"
++      depends on PCI && X86_64_XEN
++      select HOTPLUG
++      default y
++      help
++        The PCI device frontend driver allows the kernel to import arbitrary
++        PCI devices from a PCI backend to support PCI driver domains.
++
++config XEN_PCIDEV_FE_DEBUG
++      bool "Xen PCI Frontend Debugging"
++      depends on XEN_PCIDEV_FRONTEND
++      default n
++      help
++        Enables some debug statements within the PCI Frontend.
++
+ source "drivers/pci/pcie/Kconfig"
+ source "drivers/pci/Kconfig"
+@@ -658,4 +704,6 @@
+ source "crypto/Kconfig"
++source "drivers/xen/Kconfig"
++
+ source "lib/Kconfig"
+--- linux-2.6.18.8/arch/x86_64/Makefile        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/Makefile   2008-05-19 00:33:18.825231243 +0300
+@@ -71,9 +71,22 @@
+ boot := arch/x86_64/boot
+-PHONY += bzImage bzlilo install archmrproper \
++PHONY += bzImage bzlilo vmlinuz install archmrproper \
+        fdimage fdimage144 fdimage288 isoimage archclean
++ifdef CONFIG_XEN
++CPPFLAGS := -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION) \
++      -Iinclude$(if $(KBUILD_SRC),2)/asm/mach-xen $(CPPFLAGS)
++LDFLAGS_vmlinux := -e startup_64
++#Default target when executing "make"
++all: vmlinuz
++
++BOOTIMAGE                     := $(boot)/vmlinuz
++KBUILD_IMAGE                  := $(BOOTIMAGE)
++
++vmlinuz: vmlinux
++      $(Q)$(MAKE) $(build)=$(boot) $(BOOTIMAGE)
++else
+ #Default target when executing "make"
+ all: bzImage
+@@ -91,6 +104,7 @@
+ fdimage fdimage144 fdimage288 isoimage: vmlinux
+       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@
++endif
+ install:
+       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@ 
+--- linux-2.6.18.8/arch/x86_64/boot/Makefile   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/boot/Makefile      2008-05-19 00:33:18.829231473 +0300
 @@ -26,7 +26,7 @@
  #RAMDISK := -DRAMDISK=512
  
@@ -39160,10 +39789,158 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/boot/Makefil
 +
  install:
        sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/ia32entry-xen.S linux-2.6.18-xen.hg/arch/x86_64/ia32/ia32entry-xen.S
---- linux-2.6.18/arch/x86_64/ia32/ia32entry-xen.S      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/ia32/ia32entry-xen.S       2007-12-23 11:15:00.056150298 +0100
-@@ -0,0 +1,668 @@
+--- linux-2.6.18.8/arch/x86_64/ia32/Makefile   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/ia32/Makefile      2008-05-19 00:33:18.841232165 +0300
+@@ -14,11 +14,14 @@
+ audit-class-$(CONFIG_AUDIT) := audit.o
+ obj-$(CONFIG_IA32_EMULATION) += $(audit-class-y)
++syscall32-types-y := sysenter syscall
++syscall32-types-$(subst 1,$(CONFIG_XEN),$(shell expr $(CONFIG_XEN_COMPAT)0 '<' 0x0302000)) += int80
++
+ $(obj)/syscall32_syscall.o: \
+-      $(foreach F,sysenter syscall,$(obj)/vsyscall-$F.so)
++      $(foreach F,$(syscall32-types-y),$(obj)/vsyscall-$F.so)
+ # Teach kbuild about targets
+-targets := $(foreach F,sysenter syscall,vsyscall-$F.o vsyscall-$F.so)
++targets := $(foreach F,$(syscall32-types-y),vsyscall-$F.o vsyscall-$F.so)
+ # The DSO images are built using a special linker script
+ quiet_cmd_syscall = SYSCALL $@
+@@ -27,9 +30,10 @@
+                          -Wl,-soname=linux-gate.so.1 -o $@ \
+                          -Wl,-T,$(filter-out FORCE,$^)
+-$(obj)/vsyscall-sysenter.so $(obj)/vsyscall-syscall.so: \
++$(foreach F,$(syscall32-types-y),$(obj)/vsyscall-$F.so): \
+ $(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
+       $(call if_changed,syscall)
+-AFLAGS_vsyscall-sysenter.o = -m32 -Wa,-32
+-AFLAGS_vsyscall-syscall.o = -m32 -Wa,-32
++AFLAGS_vsyscall-sysenter.o = -m32 -Wa,-32 -Iarch/i386/kernel
++AFLAGS_vsyscall-syscall.o = -m32 -Wa,-32 -Iarch/i386/kernel
++AFLAGS_vsyscall-int80.o = -m32 -Wa,-32 -Iarch/i386/kernel
+--- linux-2.6.18.8/arch/x86_64/ia32/ia32_binfmt.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/ia32/ia32_binfmt.c 2008-05-19 00:33:18.845232396 +0300
+@@ -65,55 +65,6 @@
+ #define ELF_NGREG (sizeof (struct user_regs_struct32) / sizeof(elf_greg_t))
+ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+-/*
+- * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
+- * extra segments containing the vsyscall DSO contents.  Dumping its
+- * contents makes post-mortem fully interpretable later without matching up
+- * the same kernel and hardware config to see what PC values meant.
+- * Dumping its extra ELF program headers includes all the other information
+- * a debugger needs to easily find how the vsyscall DSO was being used.
+- */
+-#define ELF_CORE_EXTRA_PHDRS  (find_vma(current->mm, VSYSCALL32_BASE) ?     \
+-    (VSYSCALL32_EHDR->e_phnum) : 0)
+-#define ELF_CORE_WRITE_EXTRA_PHDRS                                          \
+-do {                                                                        \
+-      if (find_vma(current->mm, VSYSCALL32_BASE)) {                         \
+-              const struct elf32_phdr *const vsyscall_phdrs =               \
+-                      (const struct elf32_phdr *) (VSYSCALL32_BASE          \
+-                                                 + VSYSCALL32_EHDR->e_phoff);\
+-              int i;                                                        \
+-              Elf32_Off ofs = 0;                                            \
+-              for (i = 0; i < VSYSCALL32_EHDR->e_phnum; ++i) {              \
+-                      struct elf32_phdr phdr = vsyscall_phdrs[i];           \
+-                      if (phdr.p_type == PT_LOAD) {                         \
+-                              BUG_ON(ofs != 0);                             \
+-                              ofs = phdr.p_offset = offset;                 \
+-                              phdr.p_memsz = PAGE_ALIGN(phdr.p_memsz);      \
+-                              phdr.p_filesz = phdr.p_memsz;                 \
+-                              offset += phdr.p_filesz;                      \
+-                      }                                                     \
+-                      else                                                  \
+-                              phdr.p_offset += ofs;                         \
+-                      phdr.p_paddr = 0; /* match other core phdrs */        \
+-                      DUMP_WRITE(&phdr, sizeof(phdr));                      \
+-              }                                                             \
+-      }                                                                     \
+-} while (0)
+-#define ELF_CORE_WRITE_EXTRA_DATA                                           \
+-do {                                                                        \
+-      if (find_vma(current->mm, VSYSCALL32_BASE)) {                         \
+-              const struct elf32_phdr *const vsyscall_phdrs =               \
+-                      (const struct elf32_phdr *) (VSYSCALL32_BASE          \
+-                                                 + VSYSCALL32_EHDR->e_phoff);      \
+-              int i;                                                        \
+-              for (i = 0; i < VSYSCALL32_EHDR->e_phnum; ++i) {              \
+-                      if (vsyscall_phdrs[i].p_type == PT_LOAD)              \
+-                              DUMP_WRITE((void *) (u64) vsyscall_phdrs[i].p_vaddr,\
+-                                  PAGE_ALIGN(vsyscall_phdrs[i].p_memsz));   \
+-              }                                                             \
+-      }                                                                     \
+-} while (0)
+-
+ struct elf_siginfo
+ {
+       int     si_signo;                       /* signal number */
+--- linux-2.6.18.8/arch/x86_64/ia32/ia32_signal.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/ia32/ia32_signal.c 2008-05-19 00:33:18.845232396 +0300
+@@ -113,25 +113,19 @@
+ }
+ asmlinkage long
+-sys32_sigsuspend(int history0, int history1, old_sigset_t mask,
+-               struct pt_regs *regs)
++sys32_sigsuspend(int history0, int history1, old_sigset_t mask)
+ {
+-      sigset_t saveset;
+-
+       mask &= _BLOCKABLE;
+       spin_lock_irq(&current->sighand->siglock);
+-      saveset = current->blocked;
++      current->saved_sigmask = current->blocked;
+       siginitset(&current->blocked, mask);
+       recalc_sigpending();
+       spin_unlock_irq(&current->sighand->siglock);
+-      regs->rax = -EINTR;
+-      while (1) {
+               current->state = TASK_INTERRUPTIBLE;
+               schedule();
+-              if (do_signal(regs, &saveset))
+-                      return -EINTR;
+-      }
++      set_thread_flag(TIF_RESTORE_SIGMASK);
++      return -ERESTARTNOHAND;
+ }
+ asmlinkage long
+@@ -508,11 +502,11 @@
+               current->comm, current->pid, frame, regs->rip, frame->pretcode);
+ #endif
+-      return 1;
++      return 0;
+ give_sigsegv:
+       force_sigsegv(sig, current);
+-      return 0;
++      return -EFAULT;
+ }
+ int ia32_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
+@@ -604,9 +598,9 @@
+               current->comm, current->pid, frame, regs->rip, frame->pretcode);
+ #endif
+-      return 1;
++      return 0;
+ give_sigsegv:
+       force_sigsegv(sig, current);
+-      return 0;
++      return -EFAULT;
+ }
+--- linux-2.6.18.8/arch/x86_64/ia32/ia32entry-xen.S    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/ia32/ia32entry-xen.S       2008-05-19 00:33:18.849232626 +0300
+@@ -0,0 +1,666 @@
 +/*
 + * Compatibility mode system call entry point for x86-64. 
 + *            
@@ -39216,8 +39993,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/ia32ent
 +      movl \offset+72(%rsp),%eax
 +      .endm
 +
-+#include "../kernel/xen_entry.S"
-+
 +      .macro CFI_STARTPROC32 simple
 +      CFI_STARTPROC   \simple
 +      CFI_UNDEFINED   r8
@@ -39821,8 +40596,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/ia32ent
 +      .quad sys_readlinkat            /* 305 */
 +      .quad sys_fchmodat
 +      .quad sys_faccessat
-+      .quad quiet_ni_syscall          /* pselect6 for now */
-+      .quad quiet_ni_syscall          /* ppoll for now */
++      .quad compat_sys_pselect6
++      .quad compat_sys_ppoll
 +      .quad sys_unshare               /* 310 */
 +      .quad compat_sys_set_robust_list
 +      .quad compat_sys_get_robust_list
@@ -39832,75 +40607,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/ia32ent
 +      .quad compat_sys_vmsplice
 +      .quad compat_sys_move_pages
 +ia32_syscall_end:             
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/Makefile linux-2.6.18-xen.hg/arch/x86_64/ia32/Makefile
---- linux-2.6.18/arch/x86_64/ia32/Makefile     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/ia32/Makefile      2007-12-23 11:15:00.052816796 +0100
-@@ -14,11 +14,14 @@
- audit-class-$(CONFIG_AUDIT) := audit.o
- obj-$(CONFIG_IA32_EMULATION) += $(audit-class-y)
-+syscall32-types-y := sysenter syscall
-+syscall32-types-$(subst 1,$(CONFIG_XEN),$(shell expr $(CONFIG_XEN_COMPAT)0 '<' 0x0302000)) += int80
-+
- $(obj)/syscall32_syscall.o: \
--      $(foreach F,sysenter syscall,$(obj)/vsyscall-$F.so)
-+      $(foreach F,$(syscall32-types-y),$(obj)/vsyscall-$F.so)
- # Teach kbuild about targets
--targets := $(foreach F,sysenter syscall,vsyscall-$F.o vsyscall-$F.so)
-+targets := $(foreach F,$(syscall32-types-y),vsyscall-$F.o vsyscall-$F.so)
- # The DSO images are built using a special linker script
- quiet_cmd_syscall = SYSCALL $@
-@@ -27,9 +30,10 @@
-                          -Wl,-soname=linux-gate.so.1 -o $@ \
-                          -Wl,-T,$(filter-out FORCE,$^)
--$(obj)/vsyscall-sysenter.so $(obj)/vsyscall-syscall.so: \
-+$(foreach F,$(syscall32-types-y),$(obj)/vsyscall-$F.so): \
- $(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE
-       $(call if_changed,syscall)
--AFLAGS_vsyscall-sysenter.o = -m32 -Wa,-32
--AFLAGS_vsyscall-syscall.o = -m32 -Wa,-32
-+AFLAGS_vsyscall-sysenter.o = -m32 -Wa,-32 -Iarch/i386/kernel
-+AFLAGS_vsyscall-syscall.o = -m32 -Wa,-32 -Iarch/i386/kernel
-+AFLAGS_vsyscall-int80.o = -m32 -Wa,-32 -Iarch/i386/kernel
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/syscall32_syscall-xen.S linux-2.6.18-xen.hg/arch/x86_64/ia32/syscall32_syscall-xen.S
---- linux-2.6.18/arch/x86_64/ia32/syscall32_syscall-xen.S      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/ia32/syscall32_syscall-xen.S       2007-12-23 11:15:00.059483805 +0100
-@@ -0,0 +1,28 @@
-+/* 32bit VDSOs mapped into user space. */
-+
-+      .section ".init.data","aw"
-+
-+#if CONFIG_XEN_COMPAT < 0x030200
-+
-+      .globl syscall32_int80
-+      .globl syscall32_int80_end
-+
-+syscall32_int80:
-+      .incbin "arch/x86_64/ia32/vsyscall-int80.so"
-+syscall32_int80_end:
-+
-+#endif
-+
-+      .globl syscall32_syscall
-+      .globl syscall32_syscall_end
-+
-+syscall32_syscall:
-+      .incbin "arch/x86_64/ia32/vsyscall-syscall.so"
-+syscall32_syscall_end:
-+
-+      .globl syscall32_sysenter
-+      .globl syscall32_sysenter_end
-+
-+syscall32_sysenter:
-+      .incbin "arch/x86_64/ia32/vsyscall-sysenter.so"
-+syscall32_sysenter_end:
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/syscall32-xen.c linux-2.6.18-xen.hg/arch/x86_64/ia32/syscall32-xen.c
---- linux-2.6.18/arch/x86_64/ia32/syscall32-xen.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/ia32/syscall32-xen.c       2007-12-23 11:15:00.059483805 +0100
+--- linux-2.6.18.8/arch/x86_64/ia32/ia32entry.S        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/ia32/ia32entry.S   2008-05-19 00:33:18.869233779 +0300
+@@ -703,8 +703,8 @@
+       .quad sys_readlinkat            /* 305 */
+       .quad sys_fchmodat
+       .quad sys_faccessat
+-      .quad quiet_ni_syscall          /* pselect6 for now */
+-      .quad quiet_ni_syscall          /* ppoll for now */
++      .quad compat_sys_pselect6
++      .quad compat_sys_ppoll
+       .quad sys_unshare               /* 310 */
+       .quad compat_sys_set_robust_list
+       .quad compat_sys_get_robust_list
+--- linux-2.6.18.8/arch/x86_64/ia32/syscall32-xen.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/ia32/syscall32-xen.c       2008-05-19 00:33:18.873234010 +0300
 @@ -0,0 +1,137 @@
 +/* Copyright 2002,2003 Andi Kleen, SuSE Labs */
 +
@@ -40016,11 +40737,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/syscall
 +/* May not be __init: called during resume */
 +void syscall32_cpu_init(void)
 +{
-+      static struct callback_register cstar = {
++      static const struct callback_register cstar = {
 +              .type = CALLBACKTYPE_syscall32,
 +              .address = (unsigned long)ia32_cstar_target
 +      };
-+      static struct callback_register sysenter = {
++      static const struct callback_register sysenter = {
 +              .type = CALLBACKTYPE_sysenter,
 +              .address = (unsigned long)ia32_sysenter_target
 +      };
@@ -40039,9 +40760,55 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/syscall
 +      if (use_sysenter < 0)
 +              use_sysenter = (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/vsyscall-int80.S linux-2.6.18-xen.hg/arch/x86_64/ia32/vsyscall-int80.S
---- linux-2.6.18/arch/x86_64/ia32/vsyscall-int80.S     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/ia32/vsyscall-int80.S      2007-12-23 11:15:00.059483805 +0100
+--- linux-2.6.18.8/arch/x86_64/ia32/syscall32.c        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/ia32/syscall32.c   2008-05-19 00:33:18.877234240 +0300
+@@ -59,6 +59,13 @@
+       vma->vm_end = VSYSCALL32_END;
+       /* MAYWRITE to allow gdb to COW and set breakpoints */
+       vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE;
++      /*
++       * Make sure the vDSO gets into every core dump.
++       * Dumping its contents makes post-mortem fully interpretable later
++       * without matching up the same kernel and hardware config to see
++       * what PC values meant.
++       */
++      vma->vm_flags |= VM_ALWAYSDUMP;
+       vma->vm_flags |= mm->def_flags;
+       vma->vm_page_prot = protection_map[vma->vm_flags & 7];
+       vma->vm_ops = &syscall32_vm_ops;
+--- linux-2.6.18.8/arch/x86_64/ia32/syscall32_syscall-xen.S    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/ia32/syscall32_syscall-xen.S       2008-05-19 00:33:18.877234240 +0300
+@@ -0,0 +1,28 @@
++/* 32bit VDSOs mapped into user space. */
++
++      .section ".init.data","aw"
++
++#if CONFIG_XEN_COMPAT < 0x030200
++
++      .globl syscall32_int80
++      .globl syscall32_int80_end
++
++syscall32_int80:
++      .incbin "arch/x86_64/ia32/vsyscall-int80.so"
++syscall32_int80_end:
++
++#endif
++
++      .globl syscall32_syscall
++      .globl syscall32_syscall_end
++
++syscall32_syscall:
++      .incbin "arch/x86_64/ia32/vsyscall-syscall.so"
++syscall32_syscall_end:
++
++      .globl syscall32_sysenter
++      .globl syscall32_sysenter_end
++
++syscall32_sysenter:
++      .incbin "arch/x86_64/ia32/vsyscall-sysenter.so"
++syscall32_sysenter_end:
+--- linux-2.6.18.8/arch/x86_64/ia32/vsyscall-int80.S   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/ia32/vsyscall-int80.S      2008-05-19 00:33:18.877234240 +0300
 @@ -0,0 +1,58 @@
 +/*
 + * Code for the vsyscall page.  This version uses the old int $0x80 method.
@@ -40101,9 +40868,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/vsyscal
 + */
 +#define SYSCALL_ENTER_KERNEL    int $0x80
 +#include "vsyscall-sigreturn.S"
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/vsyscall-sigreturn.S linux-2.6.18-xen.hg/arch/x86_64/ia32/vsyscall-sigreturn.S
---- linux-2.6.18/arch/x86_64/ia32/vsyscall-sigreturn.S 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/ia32/vsyscall-sigreturn.S  2007-12-23 11:15:00.059483805 +0100
+--- linux-2.6.18.8/arch/x86_64/ia32/vsyscall-sigreturn.S       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/ia32/vsyscall-sigreturn.S  2008-05-19 00:33:18.877234240 +0300
 @@ -139,5 +139,5 @@
        .align 4
  .LENDFDE3:
@@ -40111,214 +40877,47 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/ia32/vsyscal
 -#include "../../i386/kernel/vsyscall-note.S"
 +#include <vsyscall-note.S>
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/Kconfig linux-2.6.18-xen.hg/arch/x86_64/Kconfig
---- linux-2.6.18/arch/x86_64/Kconfig   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/Kconfig    2007-12-23 11:15:00.039482758 +0100
-@@ -135,6 +135,22 @@
- endchoice
-+config X86_64_XEN
-+      bool "Enable Xen compatible kernel"
-+      select SWIOTLB
-+      help
-+        This option will compile a kernel compatible with Xen hypervisor
-+
-+config X86_NO_TSS
-+      bool
-+      depends on X86_64_XEN
-+      default y
-+
-+config X86_NO_IDT
-+      bool
-+      depends on X86_64_XEN
-+      default y
-+
- #
- # Define implied options from the CPU selection here
- #
-@@ -155,6 +171,7 @@
- config X86_TSC
-       bool
-+      depends on !X86_64_XEN
-       default y
- config X86_GOOD_APIC
-@@ -197,7 +214,7 @@
- config X86_HT
-       bool
--      depends on SMP && !MK8
-+      depends on SMP && !MK8 && !X86_64_XEN
-       default y
- config MATH_EMULATION
-@@ -211,14 +228,22 @@
- config X86_IO_APIC
-       bool
-+      depends !XEN_UNPRIVILEGED_GUEST
-+      default y
-+
-+config X86_XEN_GENAPIC
-+      bool
-+      depends on X86_64_XEN
-       default y
- config X86_LOCAL_APIC
-       bool
-+      depends !XEN_UNPRIVILEGED_GUEST
-       default y
- config MTRR
-       bool "MTRR (Memory Type Range Register) support"
-+      depends on !XEN_UNPRIVILEGED_GUEST
-       ---help---
-         On Intel P6 family processors (Pentium Pro, Pentium II and later)
-         the Memory Type Range Registers (MTRRs) may be used to control
-@@ -259,7 +284,7 @@
- config SCHED_SMT
-       bool "SMT (Hyperthreading) scheduler support"
--      depends on SMP
-+      depends on SMP && !X86_64_XEN
-       default n
-       help
-         SMT scheduler support improves the CPU scheduler's decision making
-@@ -269,7 +294,7 @@
- config SCHED_MC
-       bool "Multi-core scheduler support"
--      depends on SMP
-+      depends on SMP && !X86_64_XEN
-       default y
-       help
-         Multi-core scheduler support improves the CPU scheduler's decision
-@@ -280,7 +305,7 @@
- config NUMA
-        bool "Non Uniform Memory Access (NUMA) Support"
--       depends on SMP
-+       depends on SMP && !X86_64_XEN
-        help
-        Enable NUMA (Non Uniform Memory Access) support. The kernel 
-        will try to allocate memory used by a CPU on the local memory 
-@@ -341,7 +366,7 @@
- config ARCH_SPARSEMEM_ENABLE
-       def_bool y
--      depends on (NUMA || EXPERIMENTAL)
-+      depends on (NUMA || EXPERIMENTAL) && !X86_64_XEN
- config ARCH_MEMORY_PROBE
-       def_bool y
-@@ -365,6 +390,7 @@
-       int "Maximum number of CPUs (2-256)"
-       range 2 255
-       depends on SMP
-+      default "16" if X86_64_XEN
-       default "8"
-       help
-         This allows you to specify the maximum number of CPUs which this
-@@ -387,6 +413,7 @@
- config HPET_TIMER
-       bool
-+      depends on !X86_64_XEN
-       default y
-       help
-         Use the IA-PC HPET (High Precision Event Timer) to manage
-@@ -407,7 +434,7 @@
-       default y
-       select SWIOTLB
-       select AGP
--      depends on PCI
-+      depends on PCI && !X86_64_XEN
-       help
-         Support for full DMA access of devices with 32bit memory access only
-         on systems with more than 3GB. This is usually needed for USB,
-@@ -423,7 +450,7 @@
-       bool "IBM Calgary IOMMU support"
-       default y
-       select SWIOTLB
--      depends on PCI && EXPERIMENTAL
-+      depends on PCI && !X86_64_XEN && EXPERIMENTAL
-       help
-         Support for hardware IOMMUs in IBM's xSeries x366 and x460
-         systems. Needed to run systems with more than 3GB of memory
-@@ -444,6 +471,7 @@
- config X86_MCE
-       bool "Machine check support" if EMBEDDED
-+      depends on !X86_64_XEN
-       default y
-       help
-          Include a machine check error handler to report hardware errors.
-@@ -469,7 +497,7 @@
- config KEXEC
-       bool "kexec system call (EXPERIMENTAL)"
--      depends on EXPERIMENTAL
-+      depends on EXPERIMENTAL && !XEN_UNPRIVILEGED_GUEST
-       help
-         kexec is a system call that implements the ability to shutdown your
-         current kernel, and to start another kernel.  It is like a reboot
-@@ -564,8 +592,9 @@
-       default y
- menu "Power management options"
-+      depends on !XEN_UNPRIVILEGED_GUEST
--source kernel/power/Kconfig
-+source "kernel/power/Kconfig"
- source "drivers/acpi/Kconfig"
-@@ -588,6 +617,21 @@
-       bool "Support mmconfig PCI config space access"
-       depends on PCI && ACPI
-+config XEN_PCIDEV_FRONTEND
-+      bool "Xen PCI Frontend"
-+      depends on PCI && X86_64_XEN
-+      default y
-+      help
-+        The PCI device frontend driver allows the kernel to import arbitrary
-+        PCI devices from a PCI backend to support PCI driver domains.
-+
-+config XEN_PCIDEV_FE_DEBUG
-+      bool "Xen PCI Frontend Debugging"
-+      depends on XEN_PCIDEV_FRONTEND
-+      default n
-+      help
-+        Enables some debug statements within the PCI Frontend.
-+
- source "drivers/pci/pcie/Kconfig"
- source "drivers/pci/Kconfig"
-@@ -658,4 +702,6 @@
- source "crypto/Kconfig"
+--- linux-2.6.18.8/arch/x86_64/kernel/Makefile 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/Makefile    2008-05-19 00:33:18.921236777 +0300
+@@ -21,11 +21,13 @@
+ obj-$(CONFIG_X86_CPUID)               += cpuid.o
+ obj-$(CONFIG_SMP)             += smp.o smpboot.o trampoline.o
+ obj-$(CONFIG_X86_LOCAL_APIC)  += apic.o  nmi.o
++obj-$(CONFIG_X86_XEN_GENAPIC) += genapic.o genapic_xen.o
+ obj-$(CONFIG_X86_IO_APIC)     += io_apic.o mpparse.o \
+               genapic.o genapic_cluster.o genapic_flat.o
+ obj-$(CONFIG_KEXEC)           += machine_kexec.o relocate_kernel.o crash.o
+ obj-$(CONFIG_CRASH_DUMP)      += crash_dump.o
+-obj-$(CONFIG_PM)              += suspend.o
++obj-$(CONFIG_SOFTWARE_SUSPEND)        += suspend.o
++obj-$(CONFIG_ACPI_SLEEP)      += suspend.o
+ obj-$(CONFIG_SOFTWARE_SUSPEND)        += suspend_asm.o
+ obj-$(CONFIG_CPU_FREQ)                += cpufreq/
+ obj-$(CONFIG_EARLY_PRINTK)    += early_printk.o
+@@ -55,3 +57,8 @@
+ msr-$(subst m,y,$(CONFIG_X86_MSR))  += ../../i386/kernel/msr.o
+ alternative-y                 += ../../i386/kernel/alternative.o
  
-+source "drivers/xen/Kconfig"
++time-$(CONFIG_XEN)            += ../../i386/kernel/time.o
++pci-dma-$(CONFIG_XEN)         += ../../i386/kernel/pci-dma.o
 +
- source "lib/Kconfig"
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/acpi/Makefile linux-2.6.18-xen.hg/arch/x86_64/kernel/acpi/Makefile
---- linux-2.6.18/arch/x86_64/kernel/acpi/Makefile      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/acpi/Makefile       2007-12-23 11:15:00.062817316 +0100
-@@ -5,5 +5,7 @@
++disabled-obj-$(CONFIG_XEN)    := i8259.o reboot.o smpboot.o trampoline.o
++%/head.o %/head.s: $(if $(CONFIG_XEN),EXTRA_AFLAGS,dummy) :=
+--- linux-2.6.18.8/arch/x86_64/kernel/acpi/Makefile    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/acpi/Makefile       2008-05-19 00:33:18.921236777 +0300
+@@ -5,5 +5,9 @@
  ifneq ($(CONFIG_ACPI_PROCESSOR),)
  obj-y                 += processor.o
  processor-y           := ../../../i386/kernel/acpi/processor.o ../../../i386/kernel/acpi/cstate.o
 +processor-$(CONFIG_XEN)       := ../../../i386/kernel/acpi/processor.o
  endif
  
++obj-$(CONFIG_XEN)     += processor_extcnt_xen.o
++processor_extcnt_xen-$(CONFIG_XEN) := ../../../i386/kernel/acpi/processor_extcntl_xen.o
 +disabled-obj-$(CONFIG_XEN) := wakeup.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/acpi/sleep-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/acpi/sleep-xen.c
---- linux-2.6.18/arch/x86_64/kernel/acpi/sleep-xen.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/acpi/sleep-xen.c    2007-12-23 11:15:00.066150829 +0100
-@@ -0,0 +1,167 @@
+--- linux-2.6.18.8/arch/x86_64/kernel/acpi/sleep-xen.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/acpi/sleep-xen.c    2008-05-19 00:33:18.921236777 +0300
+@@ -0,0 +1,146 @@
 +/*
 + *  acpi.c - Architecture-Specific Low-Level ACPI Support
 + *
@@ -40458,27 +41057,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/acpi/
 +}
 +
 +__setup("acpi_sleep=", acpi_sleep_setup);
-+
-+#else /* CONFIG_ACPI_PV_SLEEP */
-+#include <asm/hypervisor.h>
-+#include <xen/interface/platform.h>
-+int acpi_notify_hypervisor_state(u8 sleep_state,
-+      u32 pm1a_cnt, u32 pm1b_cnt)
-+{
-+      struct xen_platform_op op = {
-+              .cmd = XENPF_enter_acpi_sleep,
-+              .interface_version = XENPF_INTERFACE_VERSION,
-+              .u = {
-+                      .enter_acpi_sleep = {
-+                              .pm1a_cnt_val = (u16)pm1a_cnt,
-+                              .pm1b_cnt_val = (u16)pm1b_cnt,
-+                              .sleep_state = sleep_state,
-+                      },
-+              },
-+      };
-+
-+      return HYPERVISOR_platform_op(&op);
-+}
 +#endif                                /* CONFIG_ACPI_PV_SLEEP */
 +
 +#endif                                /*CONFIG_ACPI_SLEEP */
@@ -40486,9 +41064,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/acpi/
 +void acpi_pci_link_exit(void)
 +{
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/apic-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/apic-xen.c
---- linux-2.6.18/arch/x86_64/kernel/apic-xen.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/apic-xen.c  2007-12-23 11:15:00.066150829 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/apic-xen.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/apic-xen.c  2008-05-19 00:33:18.925237007 +0300
 @@ -0,0 +1,197 @@
 +/*
 + *    Local APIC handling, local APIC timers
@@ -40687,9 +41264,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/apic-
 +
 +      return 1;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/asm-offsets.c linux-2.6.18-xen.hg/arch/x86_64/kernel/asm-offsets.c
---- linux-2.6.18/arch/x86_64/kernel/asm-offsets.c      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/asm-offsets.c       2007-12-23 11:15:00.069484339 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/asm-offsets.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/asm-offsets.c       2008-05-19 00:33:18.929237238 +0300
 @@ -67,8 +67,10 @@
        DEFINE(pbe_address, offsetof(struct pbe, address));
        DEFINE(pbe_orig_address, offsetof(struct pbe, orig_address));
@@ -40701,9 +41277,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/asm-o
        BLANK();
        DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx));
        return 0;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/crash.c linux-2.6.18-xen.hg/arch/x86_64/kernel/crash.c
---- linux-2.6.18/arch/x86_64/kernel/crash.c    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/crash.c     2007-12-23 11:15:00.069484339 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/crash.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/crash.c     2008-05-19 00:33:18.933237468 +0300
 @@ -92,6 +92,7 @@
        crash_save_this_cpu(regs, cpu);
  }
@@ -40737,30 +41312,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/crash
 +#endif /* CONFIG_XEN */
        crash_save_self(regs);
  }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/e820.c linux-2.6.18-xen.hg/arch/x86_64/kernel/e820.c
---- linux-2.6.18/arch/x86_64/kernel/e820.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/e820.c      2007-12-23 11:15:00.072817848 +0100
-@@ -93,7 +93,7 @@
-  * This function checks if any part of the range <start,end> is mapped
-  * with type.
-  */
--int __meminit
-+int
- e820_any_mapped(unsigned long start, unsigned long end, unsigned type)
- { 
-       int i;
-@@ -107,6 +107,7 @@
-       } 
-       return 0;
- }
-+EXPORT_SYMBOL_GPL(e820_any_mapped);
- /*
-  * This function checks if the entire range <start,end> is mapped with type.
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/e820-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/e820-xen.c
---- linux-2.6.18/arch/x86_64/kernel/e820-xen.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/e820-xen.c  2007-12-23 11:15:00.069484339 +0100
-@@ -0,0 +1,783 @@
+--- linux-2.6.18.8/arch/x86_64/kernel/e820-xen.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/e820-xen.c  2008-05-19 00:33:18.933237468 +0300
+@@ -0,0 +1,798 @@
 +/* 
 + * Handle the memory map.
 + * The functions here do the job until bootmem takes over.
@@ -40808,6 +41362,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/e820-
 +
 +extern struct resource code_resource, data_resource;
 +
++#ifdef CONFIG_XEN
++extern struct e820map machine_e820;
++#endif
++
 +/* Check for some hardcoded bad areas that early boot is not allowed to touch */ 
 +static inline int bad_addr(unsigned long *addrp, unsigned long size)
 +{ 
@@ -40872,8 +41430,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/e820-
 +      for (i = 0; i < e820.nr_map; i++) { 
 +              struct e820entry *ei = &e820.map[i]; 
 +#else
-+      extern struct e820map machine_e820;
-+
 +      if (!is_initial_xendomain())
 +              return 0;
 +      for (i = 0; i < machine_e820.nr_map; i++) {
@@ -40904,8 +41460,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/e820-
 +      for (i = 0; i < e820.nr_map; i++) {
 +              struct e820entry *ei = &e820.map[i];
 +#else
-+      extern struct e820map machine_e820;
-+
 +      if (!is_initial_xendomain())
 +              return 0;
 +      for (i = 0; i < machine_e820.nr_map; i++) {
@@ -41367,6 +41921,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/e820-
 +
 +              add_memory_region(start, size, type);
 +      } while (biosmap++,--nr_map);
++
++#ifdef CONFIG_XEN
++      if (is_initial_xendomain()) {
++              struct xen_memory_map memmap;
++
++              memmap.nr_entries = E820MAX;
++              set_xen_guest_handle(memmap.buffer, machine_e820.map);
++
++              if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap))
++                      BUG();
++              machine_e820.nr_map = memmap.nr_entries;
++      } else
++              machine_e820 = e820;
++#endif
++
 +      return 0;
 +}
 +
@@ -41544,9 +42113,27 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/e820-
 +      printk(KERN_INFO "Allocating PCI resources starting at %lx (gap: %lx:%lx)\n",
 +              pci_mem_start, gapstart, gapsize);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/early_printk-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/early_printk-xen.c
---- linux-2.6.18/arch/x86_64/kernel/early_printk-xen.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/early_printk-xen.c  2007-12-23 11:15:00.072817848 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/e820.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/e820.c      2008-05-19 00:33:18.933237468 +0300
+@@ -93,7 +93,7 @@
+  * This function checks if any part of the range <start,end> is mapped
+  * with type.
+  */
+-int __meminit
++int
+ e820_any_mapped(unsigned long start, unsigned long end, unsigned type)
+ { 
+       int i;
+@@ -107,6 +107,7 @@
+       } 
+       return 0;
+ }
++EXPORT_SYMBOL_GPL(e820_any_mapped);
+ /*
+  * This function checks if the entire range <start,end> is mapped with type.
+--- linux-2.6.18.8/arch/x86_64/kernel/early_printk-xen.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/early_printk-xen.c  2008-05-19 00:33:18.937237699 +0300
 @@ -0,0 +1,302 @@
 +#include <linux/console.h>
 +#include <linux/kernel.h>
@@ -41850,9 +42437,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/early
 +}
 +
 +__setup("earlyprintk=", setup_early_printk);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/entry-xen.S linux-2.6.18-xen.hg/arch/x86_64/kernel/entry-xen.S
---- linux-2.6.18/arch/x86_64/kernel/entry-xen.S        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/entry-xen.S 2007-12-23 11:15:00.072817848 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/entry-xen.S      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/entry-xen.S 2008-05-19 00:33:18.937237699 +0300
 @@ -0,0 +1,1322 @@
 +/*
 + *  linux/arch/x86_64/entry.S
@@ -43176,174 +43762,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/entry
 +      CFI_ENDPROC
 +ENDPROC(arch_unwind_init_running)
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/genapic_xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/genapic_xen.c
---- linux-2.6.18/arch/x86_64/kernel/genapic_xen.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/genapic_xen.c       2007-12-23 11:15:00.079484858 +0100
-@@ -0,0 +1,161 @@
-+/*
-+ * Copyright 2004 James Cleverdon, IBM.
-+ * Subject to the GNU Public License, v.2
-+ *
-+ * Xen APIC subarch code.  Maximum 8 CPUs, logical delivery.
-+ *
-+ * Hacked for x86-64 by James Cleverdon from i386 architecture code by
-+ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
-+ * James Cleverdon.
-+ *
-+ * Hacked to pieces for Xen by Chris Wright.
-+ */
-+#include <linux/threads.h>
-+#include <linux/cpumask.h>
-+#include <linux/string.h>
-+#include <linux/kernel.h>
-+#include <linux/ctype.h>
-+#include <linux/init.h>
-+#ifdef CONFIG_XEN_PRIVILEGED_GUEST
-+#include <asm/smp.h>
-+#include <asm/ipi.h>
-+#else
-+#include <asm/apic.h>
-+#include <asm/apicdef.h>
-+#include <asm/genapic.h>
-+#endif
-+#include <xen/evtchn.h>
-+
-+DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]);
-+
-+static inline void __send_IPI_one(unsigned int cpu, int vector)
-+{
-+      int irq = per_cpu(ipi_to_irq, cpu)[vector];
-+      BUG_ON(irq < 0);
-+      notify_remote_via_irq(irq);
-+}
-+
-+void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest)
-+{
-+      int cpu;
-+
-+      switch (shortcut) {
-+      case APIC_DEST_SELF:
-+              __send_IPI_one(smp_processor_id(), vector);
-+              break;
-+      case APIC_DEST_ALLBUT:
-+              for (cpu = 0; cpu < NR_CPUS; ++cpu) {
-+                      if (cpu == smp_processor_id())
-+                              continue;
-+                      if (cpu_isset(cpu, cpu_online_map)) {
-+                              __send_IPI_one(cpu, vector);
-+                      }
-+              }
-+              break;
-+      case APIC_DEST_ALLINC:
-+              for (cpu = 0; cpu < NR_CPUS; ++cpu) {
-+                      if (cpu_isset(cpu, cpu_online_map)) {
-+                              __send_IPI_one(cpu, vector);
-+                      }
-+              }
-+              break;
-+      default:
-+              printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut,
-+                     vector);
-+              break;
-+      }
-+}
-+
-+static cpumask_t xen_target_cpus(void)
-+{
-+      return cpu_online_map;
-+}
-+
-+/*
-+ * Set up the logical destination ID.
-+ * Do nothing, not called now.
-+ */
-+static void xen_init_apic_ldr(void)
-+{
-+      Dprintk("%s\n", __FUNCTION__);
-+      return;
-+}
-+
-+static void xen_send_IPI_allbutself(int vector)
-+{
-+      /*
-+       * if there are no other CPUs in the system then
-+       * we get an APIC send error if we try to broadcast.
-+       * thus we have to avoid sending IPIs in this case.
-+       */
-+      Dprintk("%s\n", __FUNCTION__);
-+      if (num_online_cpus() > 1)
-+              xen_send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
-+}
-+
-+static void xen_send_IPI_all(int vector)
-+{
-+      Dprintk("%s\n", __FUNCTION__);
-+      xen_send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
-+}
-+
-+static void xen_send_IPI_mask(cpumask_t cpumask, int vector)
-+{
-+      unsigned long mask = cpus_addr(cpumask)[0];
-+      unsigned int cpu;
-+      unsigned long flags;
-+
-+      Dprintk("%s\n", __FUNCTION__);
-+      local_irq_save(flags);
-+      WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
-+
-+      for (cpu = 0; cpu < NR_CPUS; ++cpu) {
-+              if (cpu_isset(cpu, cpumask)) {
-+                      __send_IPI_one(cpu, vector);
-+              }
-+      }
-+      local_irq_restore(flags);
-+}
-+
-+#ifdef CONFIG_XEN_PRIVILEGED_GUEST
-+static int xen_apic_id_registered(void)
-+{
-+      /* better be set */
-+      Dprintk("%s\n", __FUNCTION__);
-+      return physid_isset(smp_processor_id(), phys_cpu_present_map);
-+}
-+#endif
-+
-+static unsigned int xen_cpu_mask_to_apicid(cpumask_t cpumask)
-+{
-+      Dprintk("%s\n", __FUNCTION__);
-+      return cpus_addr(cpumask)[0] & APIC_ALL_CPUS;
-+}
-+
-+static unsigned int phys_pkg_id(int index_msb)
-+{
-+      u32 ebx;
-+
-+      Dprintk("%s\n", __FUNCTION__);
-+      ebx = cpuid_ebx(1);
-+      return ((ebx >> 24) & 0xFF) >> index_msb;
-+}
-+
-+struct genapic apic_xen =  {
-+      .name = "xen",
-+#ifdef CONFIG_XEN_PRIVILEGED_GUEST
-+      .int_delivery_mode = dest_LowestPrio,
-+#endif
-+      .int_dest_mode = (APIC_DEST_LOGICAL != 0),
-+      .int_delivery_dest = APIC_DEST_LOGICAL | APIC_DM_LOWEST,
-+      .target_cpus = xen_target_cpus,
-+#ifdef CONFIG_XEN_PRIVILEGED_GUEST
-+      .apic_id_registered = xen_apic_id_registered,
-+#endif
-+      .init_apic_ldr = xen_init_apic_ldr,
-+      .send_IPI_all = xen_send_IPI_all,
-+      .send_IPI_allbutself = xen_send_IPI_allbutself,
-+      .send_IPI_mask = xen_send_IPI_mask,
-+      .cpu_mask_to_apicid = xen_cpu_mask_to_apicid,
-+      .phys_pkg_id = phys_pkg_id,
-+};
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/genapic-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/genapic-xen.c
---- linux-2.6.18/arch/x86_64/kernel/genapic-xen.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/genapic-xen.c       2007-12-23 11:15:00.076151352 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/genapic-xen.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/genapic-xen.c       2008-05-19 00:33:18.941237929 +0300
 @@ -0,0 +1,143 @@
 +/*
 + * Copyright 2004 James Cleverdon, IBM.
@@ -43488,175 +43908,172 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/genap
 +      xen_send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
 +#endif
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/head64-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/head64-xen.c
---- linux-2.6.18/arch/x86_64/kernel/head64-xen.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/head64-xen.c        2007-12-23 11:15:00.079484858 +0100
-@@ -0,0 +1,162 @@
+--- linux-2.6.18.8/arch/x86_64/kernel/genapic_xen.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/genapic_xen.c       2008-05-19 00:33:18.945238160 +0300
+@@ -0,0 +1,161 @@
 +/*
-+ *  linux/arch/x86_64/kernel/head64.c -- prepare to run common code
++ * Copyright 2004 James Cleverdon, IBM.
++ * Subject to the GNU Public License, v.2
 + *
-+ *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
++ * Xen APIC subarch code.  Maximum 8 CPUs, logical delivery.
 + *
-+ *  Jun Nakajima <jun.nakajima@intel.com>
-+ *    Modified for Xen.
++ * Hacked for x86-64 by James Cleverdon from i386 architecture code by
++ * Martin Bligh, Andi Kleen, James Bottomley, John Stultz, and
++ * James Cleverdon.
++ *
++ * Hacked to pieces for Xen by Chris Wright.
 + */
-+
-+#include <linux/init.h>
-+#include <linux/linkage.h>
-+#include <linux/types.h>
-+#include <linux/kernel.h>
++#include <linux/threads.h>
++#include <linux/cpumask.h>
 +#include <linux/string.h>
-+#include <linux/percpu.h>
-+#include <linux/module.h>
-+
-+#include <asm/processor.h>
-+#include <asm/proto.h>
++#include <linux/kernel.h>
++#include <linux/ctype.h>
++#include <linux/init.h>
++#ifdef CONFIG_XEN_PRIVILEGED_GUEST
 +#include <asm/smp.h>
-+#include <asm/bootsetup.h>
-+#include <asm/setup.h>
-+#include <asm/desc.h>
-+#include <asm/pgtable.h>
-+#include <asm/sections.h>
++#include <asm/ipi.h>
++#else
++#include <asm/apic.h>
++#include <asm/apicdef.h>
++#include <asm/genapic.h>
++#endif
++#include <xen/evtchn.h>
 +
-+unsigned long start_pfn;
++DECLARE_PER_CPU(int, ipi_to_irq[NR_IPIS]);
 +
-+/* Don't add a printk in there. printk relies on the PDA which is not initialized 
-+   yet. */
-+#if 0
-+static void __init clear_bss(void)
++static inline void __send_IPI_one(unsigned int cpu, int vector)
 +{
-+      memset(__bss_start, 0,
-+             (unsigned long) __bss_stop - (unsigned long) __bss_start);
++      int irq = per_cpu(ipi_to_irq, cpu)[vector];
++      BUG_ON(irq < 0);
++      notify_remote_via_irq(irq);
 +}
-+#endif
-+
-+#define NEW_CL_POINTER                0x228   /* Relative to real mode data */
-+#define OLD_CL_MAGIC_ADDR     0x90020
-+#define OLD_CL_MAGIC            0xA33F
-+#define OLD_CL_BASE_ADDR        0x90000
-+#define OLD_CL_OFFSET           0x90022
-+
-+extern char saved_command_line[];
 +
-+static void __init copy_bootdata(char *real_mode_data)
++void xen_send_IPI_shortcut(unsigned int shortcut, int vector, unsigned int dest)
 +{
-+#ifndef CONFIG_XEN
-+      int new_data;
-+      char * command_line;
++      int cpu;
 +
-+      memcpy(x86_boot_params, real_mode_data, BOOT_PARAM_SIZE);
-+      new_data = *(int *) (x86_boot_params + NEW_CL_POINTER);
-+      if (!new_data) {
-+              if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) {
-+                      printk("so old bootloader that it does not support commandline?!\n");
-+                      return;
++      switch (shortcut) {
++      case APIC_DEST_SELF:
++              __send_IPI_one(smp_processor_id(), vector);
++              break;
++      case APIC_DEST_ALLBUT:
++              for (cpu = 0; cpu < NR_CPUS; ++cpu) {
++                      if (cpu == smp_processor_id())
++                              continue;
++                      if (cpu_isset(cpu, cpu_online_map)) {
++                              __send_IPI_one(cpu, vector);
++                      }
 +              }
-+              new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET;
-+              printk("old bootloader convention, maybe loadlin?\n");
++              break;
++      case APIC_DEST_ALLINC:
++              for (cpu = 0; cpu < NR_CPUS; ++cpu) {
++                      if (cpu_isset(cpu, cpu_online_map)) {
++                              __send_IPI_one(cpu, vector);
++                      }
++              }
++              break;
++      default:
++              printk("XXXXXX __send_IPI_shortcut %08x vector %d\n", shortcut,
++                     vector);
++              break;
 +      }
-+      command_line = (char *) ((u64)(new_data));
-+      memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
-+#else
-+      int max_cmdline;
-+      
-+      if ((max_cmdline = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE)
-+              max_cmdline = COMMAND_LINE_SIZE;
-+      memcpy(saved_command_line, xen_start_info->cmd_line, max_cmdline);
-+      saved_command_line[max_cmdline-1] = '\0';
-+#endif
-+      printk("Bootdata ok (command line is %s)\n", saved_command_line);
 +}
 +
-+static void __init setup_boot_cpu_data(void)
++static cpumask_t xen_target_cpus(void)
 +{
-+      unsigned int dummy, eax;
-+
-+      /* get vendor info */
-+      cpuid(0, (unsigned int *)&boot_cpu_data.cpuid_level,
-+            (unsigned int *)&boot_cpu_data.x86_vendor_id[0],
-+            (unsigned int *)&boot_cpu_data.x86_vendor_id[8],
-+            (unsigned int *)&boot_cpu_data.x86_vendor_id[4]);
++      return cpu_online_map;
++}
 +
-+      /* get cpu type */
-+      cpuid(1, &eax, &dummy, &dummy,
-+              (unsigned int *) &boot_cpu_data.x86_capability);
-+      boot_cpu_data.x86 = (eax >> 8) & 0xf;
-+      boot_cpu_data.x86_model = (eax >> 4) & 0xf;
-+      boot_cpu_data.x86_mask = eax & 0xf;
++/*
++ * Set up the logical destination ID.
++ * Do nothing, not called now.
++ */
++static void xen_init_apic_ldr(void)
++{
++      Dprintk("%s\n", __FUNCTION__);
++      return;
 +}
 +
-+#include <xen/interface/memory.h>
-+unsigned long *machine_to_phys_mapping;
-+EXPORT_SYMBOL(machine_to_phys_mapping);
-+unsigned int machine_to_phys_order;
-+EXPORT_SYMBOL(machine_to_phys_order);
++static void xen_send_IPI_allbutself(int vector)
++{
++      /*
++       * if there are no other CPUs in the system then
++       * we get an APIC send error if we try to broadcast.
++       * thus we have to avoid sending IPIs in this case.
++       */
++      Dprintk("%s\n", __FUNCTION__);
++      if (num_online_cpus() > 1)
++              xen_send_IPI_shortcut(APIC_DEST_ALLBUT, vector, APIC_DEST_LOGICAL);
++}
 +
-+void __init x86_64_start_kernel(char * real_mode_data)
++static void xen_send_IPI_all(int vector)
 +{
-+      struct xen_machphys_mapping mapping;
-+      unsigned long machine_to_phys_nr_ents;
-+      char *s;
-+      int i;
++      Dprintk("%s\n", __FUNCTION__);
++      xen_send_IPI_shortcut(APIC_DEST_ALLINC, vector, APIC_DEST_LOGICAL);
++}
 +
-+      setup_xen_features();
++static void xen_send_IPI_mask(cpumask_t cpumask, int vector)
++{
++      unsigned long mask = cpus_addr(cpumask)[0];
++      unsigned int cpu;
++      unsigned long flags;
 +
-+      xen_start_info = (struct start_info *)real_mode_data;
-+      if (!xen_feature(XENFEAT_auto_translated_physmap))
-+              phys_to_machine_mapping =
-+                      (unsigned long *)xen_start_info->mfn_list;
-+      start_pfn = (__pa(xen_start_info->pt_base) >> PAGE_SHIFT) +
-+              xen_start_info->nr_pt_frames;
++      Dprintk("%s\n", __FUNCTION__);
++      local_irq_save(flags);
++      WARN_ON(mask & ~cpus_addr(cpu_online_map)[0]);
 +
-+      machine_to_phys_mapping = (unsigned long *)MACH2PHYS_VIRT_START;
-+      machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
-+      if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
-+              machine_to_phys_mapping = (unsigned long *)mapping.v_start;
-+              machine_to_phys_nr_ents = mapping.max_mfn + 1;
++      for (cpu = 0; cpu < NR_CPUS; ++cpu) {
++              if (cpu_isset(cpu, cpumask)) {
++                      __send_IPI_one(cpu, vector);
++              }
 +      }
-+      while ((1UL << machine_to_phys_order) < machine_to_phys_nr_ents )
-+              machine_to_phys_order++;
++      local_irq_restore(flags);
++}
 +
-+#if 0
-+      for (i = 0; i < 256; i++)
-+              set_intr_gate(i, early_idt_handler);
-+      asm volatile("lidt %0" :: "m" (idt_descr));
++#ifdef CONFIG_XEN_PRIVILEGED_GUEST
++static int xen_apic_id_registered(void)
++{
++      /* better be set */
++      Dprintk("%s\n", __FUNCTION__);
++      return physid_isset(smp_processor_id(), phys_cpu_present_map);
++}
 +#endif
 +
-+      /*
-+       * This must be called really, really early:
-+       */
-+      lockdep_init();
++static unsigned int xen_cpu_mask_to_apicid(cpumask_t cpumask)
++{
++      Dprintk("%s\n", __FUNCTION__);
++      return cpus_addr(cpumask)[0] & APIC_ALL_CPUS;
++}
 +
-+      for (i = 0; i < NR_CPUS; i++)
-+              cpu_pda(i) = &boot_cpu_pda[i];
++static unsigned int phys_pkg_id(int index_msb)
++{
++      u32 ebx;
 +
-+      pda_init(0);
-+      copy_bootdata(real_mode_data);
-+#ifdef CONFIG_SMP
-+      cpu_set(0, cpu_online_map);
-+#endif
-+      s = strstr(saved_command_line, "earlyprintk=");
-+      if (s != NULL)
-+              setup_early_printk(strchr(s, '=') + 1);
-+#ifdef CONFIG_NUMA
-+      s = strstr(saved_command_line, "numa=");
-+      if (s != NULL)
-+              numa_setup(s+5);
++      Dprintk("%s\n", __FUNCTION__);
++      ebx = cpuid_ebx(1);
++      return ((ebx >> 24) & 0xFF) >> index_msb;
++}
++
++struct genapic apic_xen =  {
++      .name = "xen",
++#ifdef CONFIG_XEN_PRIVILEGED_GUEST
++      .int_delivery_mode = dest_LowestPrio,
 +#endif
-+#ifdef CONFIG_X86_IO_APIC
-+      if (strstr(saved_command_line, "disableapic"))
-+              disable_apic = 1;
++      .int_dest_mode = (APIC_DEST_LOGICAL != 0),
++      .int_delivery_dest = APIC_DEST_LOGICAL | APIC_DM_LOWEST,
++      .target_cpus = xen_target_cpus,
++#ifdef CONFIG_XEN_PRIVILEGED_GUEST
++      .apic_id_registered = xen_apic_id_registered,
 +#endif
-+      /* You need early console to see that */
-+      if (__pa_symbol(&_end) >= KERNEL_TEXT_SIZE)
-+              panic("Kernel too big for kernel mapping\n");
-+
-+      setup_boot_cpu_data();
-+      start_kernel();
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/head-xen.S linux-2.6.18-xen.hg/arch/x86_64/kernel/head-xen.S
---- linux-2.6.18/arch/x86_64/kernel/head-xen.S 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/head-xen.S  2007-12-23 11:15:00.079484858 +0100
++      .init_apic_ldr = xen_init_apic_ldr,
++      .send_IPI_all = xen_send_IPI_all,
++      .send_IPI_allbutself = xen_send_IPI_allbutself,
++      .send_IPI_mask = xen_send_IPI_mask,
++      .cpu_mask_to_apicid = xen_cpu_mask_to_apicid,
++      .phys_pkg_id = phys_pkg_id,
++};
+--- linux-2.6.18.8/arch/x86_64/kernel/head-xen.S       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/head-xen.S  2008-05-19 00:33:18.945238160 +0300
 @@ -0,0 +1,214 @@
 +/*
 + *  linux/arch/x86_64/kernel/head.S -- start in 32bit and switch to 64bit
@@ -43872,9 +44289,173 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/head-
 +      ELFNOTE(Xen, XEN_ELFNOTE_FEATURES,       .asciz, "writable_page_tables|writable_descriptor_tables|auto_translated_physmap|pae_pgdir_above_4gb|supervisor_mode_kernel")
 +      ELFNOTE(Xen, XEN_ELFNOTE_LOADER,         .asciz, "generic")
 +      ELFNOTE(Xen, XEN_ELFNOTE_SUSPEND_CANCEL, .long,  1)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/init_task.c linux-2.6.18-xen.hg/arch/x86_64/kernel/init_task.c
---- linux-2.6.18/arch/x86_64/kernel/init_task.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/init_task.c 2007-12-23 11:15:00.082818365 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/head64-xen.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/head64-xen.c        2008-05-19 00:33:18.945238160 +0300
+@@ -0,0 +1,162 @@
++/*
++ *  linux/arch/x86_64/kernel/head64.c -- prepare to run common code
++ *
++ *  Copyright (C) 2000 Andrea Arcangeli <andrea@suse.de> SuSE
++ *
++ *  Jun Nakajima <jun.nakajima@intel.com>
++ *    Modified for Xen.
++ */
++
++#include <linux/init.h>
++#include <linux/linkage.h>
++#include <linux/types.h>
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/percpu.h>
++#include <linux/module.h>
++
++#include <asm/processor.h>
++#include <asm/proto.h>
++#include <asm/smp.h>
++#include <asm/bootsetup.h>
++#include <asm/setup.h>
++#include <asm/desc.h>
++#include <asm/pgtable.h>
++#include <asm/sections.h>
++
++unsigned long start_pfn;
++
++/* Don't add a printk in there. printk relies on the PDA which is not initialized 
++   yet. */
++#if 0
++static void __init clear_bss(void)
++{
++      memset(__bss_start, 0,
++             (unsigned long) __bss_stop - (unsigned long) __bss_start);
++}
++#endif
++
++#define NEW_CL_POINTER                0x228   /* Relative to real mode data */
++#define OLD_CL_MAGIC_ADDR     0x90020
++#define OLD_CL_MAGIC            0xA33F
++#define OLD_CL_BASE_ADDR        0x90000
++#define OLD_CL_OFFSET           0x90022
++
++extern char saved_command_line[];
++
++static void __init copy_bootdata(char *real_mode_data)
++{
++#ifndef CONFIG_XEN
++      int new_data;
++      char * command_line;
++
++      memcpy(x86_boot_params, real_mode_data, BOOT_PARAM_SIZE);
++      new_data = *(int *) (x86_boot_params + NEW_CL_POINTER);
++      if (!new_data) {
++              if (OLD_CL_MAGIC != * (u16 *) OLD_CL_MAGIC_ADDR) {
++                      printk("so old bootloader that it does not support commandline?!\n");
++                      return;
++              }
++              new_data = OLD_CL_BASE_ADDR + * (u16 *) OLD_CL_OFFSET;
++              printk("old bootloader convention, maybe loadlin?\n");
++      }
++      command_line = (char *) ((u64)(new_data));
++      memcpy(saved_command_line, command_line, COMMAND_LINE_SIZE);
++#else
++      int max_cmdline;
++      
++      if ((max_cmdline = MAX_GUEST_CMDLINE) > COMMAND_LINE_SIZE)
++              max_cmdline = COMMAND_LINE_SIZE;
++      memcpy(saved_command_line, xen_start_info->cmd_line, max_cmdline);
++      saved_command_line[max_cmdline-1] = '\0';
++#endif
++      printk("Bootdata ok (command line is %s)\n", saved_command_line);
++}
++
++static void __init setup_boot_cpu_data(void)
++{
++      unsigned int dummy, eax;
++
++      /* get vendor info */
++      cpuid(0, (unsigned int *)&boot_cpu_data.cpuid_level,
++            (unsigned int *)&boot_cpu_data.x86_vendor_id[0],
++            (unsigned int *)&boot_cpu_data.x86_vendor_id[8],
++            (unsigned int *)&boot_cpu_data.x86_vendor_id[4]);
++
++      /* get cpu type */
++      cpuid(1, &eax, &dummy, &dummy,
++              (unsigned int *) &boot_cpu_data.x86_capability);
++      boot_cpu_data.x86 = (eax >> 8) & 0xf;
++      boot_cpu_data.x86_model = (eax >> 4) & 0xf;
++      boot_cpu_data.x86_mask = eax & 0xf;
++}
++
++#include <xen/interface/memory.h>
++unsigned long *machine_to_phys_mapping;
++EXPORT_SYMBOL(machine_to_phys_mapping);
++unsigned int machine_to_phys_order;
++EXPORT_SYMBOL(machine_to_phys_order);
++
++void __init x86_64_start_kernel(char * real_mode_data)
++{
++      struct xen_machphys_mapping mapping;
++      unsigned long machine_to_phys_nr_ents;
++      char *s;
++      int i;
++
++      setup_xen_features();
++
++      xen_start_info = (struct start_info *)real_mode_data;
++      if (!xen_feature(XENFEAT_auto_translated_physmap))
++              phys_to_machine_mapping =
++                      (unsigned long *)xen_start_info->mfn_list;
++      start_pfn = (__pa(xen_start_info->pt_base) >> PAGE_SHIFT) +
++              xen_start_info->nr_pt_frames;
++
++      machine_to_phys_mapping = (unsigned long *)MACH2PHYS_VIRT_START;
++      machine_to_phys_nr_ents = MACH2PHYS_NR_ENTRIES;
++      if (HYPERVISOR_memory_op(XENMEM_machphys_mapping, &mapping) == 0) {
++              machine_to_phys_mapping = (unsigned long *)mapping.v_start;
++              machine_to_phys_nr_ents = mapping.max_mfn + 1;
++      }
++      while ((1UL << machine_to_phys_order) < machine_to_phys_nr_ents )
++              machine_to_phys_order++;
++
++#if 0
++      for (i = 0; i < 256; i++)
++              set_intr_gate(i, early_idt_handler);
++      asm volatile("lidt %0" :: "m" (idt_descr));
++#endif
++
++      /*
++       * This must be called really, really early:
++       */
++      lockdep_init();
++
++      for (i = 0; i < NR_CPUS; i++)
++              cpu_pda(i) = &boot_cpu_pda[i];
++
++      pda_init(0);
++      copy_bootdata(real_mode_data);
++#ifdef CONFIG_SMP
++      cpu_set(0, cpu_online_map);
++#endif
++      s = strstr(saved_command_line, "earlyprintk=");
++      if (s != NULL)
++              setup_early_printk(strchr(s, '=') + 1);
++#ifdef CONFIG_NUMA
++      s = strstr(saved_command_line, "numa=");
++      if (s != NULL)
++              numa_setup(s+5);
++#endif
++#ifdef CONFIG_X86_IO_APIC
++      if (strstr(saved_command_line, "disableapic"))
++              disable_apic = 1;
++#endif
++      /* You need early console to see that */
++      if (__pa_symbol(&_end) >= KERNEL_TEXT_SIZE)
++              panic("Kernel too big for kernel mapping\n");
++
++      setup_boot_cpu_data();
++      start_kernel();
++}
+--- linux-2.6.18.8/arch/x86_64/kernel/init_task.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/init_task.c 2008-05-19 00:33:18.961239082 +0300
 @@ -37,6 +37,8 @@
  struct task_struct init_task = INIT_TASK(init_task);
  
@@ -43891,9 +44472,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/init_
 +#endif
  
  #define ALIGN_TO_4K __attribute__((section(".data.init_task")))
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/io_apic-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/io_apic-xen.c
---- linux-2.6.18/arch/x86_64/kernel/io_apic-xen.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/io_apic-xen.c       2007-12-23 11:15:00.082818365 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/io_apic-xen.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/io_apic-xen.c       2008-05-19 00:33:19.005241619 +0300
 @@ -0,0 +1,2262 @@
 +/*
 + *    Intel IO-APIC support for multi-Pentium hosts.
@@ -44020,7 +44600,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/io_ap
 +      apic_op.apic_physbase = mp_ioapics[apic].mpc_apicaddr;
 +      apic_op.reg = reg;
 +      apic_op.value = value;
-+      HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op);
++      WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op));
 +}
 +
 +#define io_apic_read(a,r)    xen_io_apic_read(a,r)
@@ -46157,10 +46737,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/io_ap
 +}
 +#endif
 +#endif /* !CONFIG_XEN */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/ioport-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/ioport-xen.c
---- linux-2.6.18/arch/x86_64/kernel/ioport-xen.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/ioport-xen.c        2007-12-23 11:15:00.086151878 +0100
-@@ -0,0 +1,99 @@
+--- linux-2.6.18.8/arch/x86_64/kernel/ioport-xen.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/ioport-xen.c        2008-05-19 00:33:19.009241849 +0300
+@@ -0,0 +1,100 @@
 +/*
 + *    linux/arch/x86_64/kernel/ioport.c
 + *
@@ -46224,7 +46803,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/iopor
 +
 +              set_xen_guest_handle(set_iobitmap.bitmap, (char *)bitmap);
 +              set_iobitmap.nr_ports = IO_BITMAP_BITS;
-+              HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &set_iobitmap);
++              WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap,
++                                            &set_iobitmap));
 +      }
 +
 +      set_bitmap(t->io_bitmap_ptr, from, num, !turn_on);
@@ -46256,13 +46836,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/iopor
 +
 +      /* Force the change at ring 0. */
 +      set_iopl.iopl = (new_iopl == 0) ? 1 : new_iopl;
-+      HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
++      WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl));
 +
 +      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/irq-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/irq-xen.c
---- linux-2.6.18/arch/x86_64/kernel/irq-xen.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/irq-xen.c   2007-12-23 11:15:00.086151878 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/irq-xen.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/irq-xen.c   2008-05-19 00:33:19.009241849 +0300
 @@ -0,0 +1,197 @@
 +/*
 + *    linux/arch/x86_64/kernel/irq.c
@@ -46461,9 +47040,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/irq-x
 +        printk("unexpected IRQ trap at vector %02x\n", irq);
 +}
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/ldt-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/ldt-xen.c
---- linux-2.6.18/arch/x86_64/kernel/ldt-xen.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/ldt-xen.c   2007-12-23 11:15:00.086151878 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/ldt-xen.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/ldt-xen.c   2008-05-19 00:33:19.013242080 +0300
 @@ -0,0 +1,282 @@
 +/*
 + * linux/arch/x86_64/kernel/ldt.c
@@ -46747,10 +47325,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/ldt-x
 +      }
 +      return ret;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/machine_kexec.c linux-2.6.18-xen.hg/arch/x86_64/kernel/machine_kexec.c
---- linux-2.6.18/arch/x86_64/kernel/machine_kexec.c    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/machine_kexec.c     2007-12-23 11:15:00.089485388 +0100
-@@ -15,6 +15,113 @@
+--- linux-2.6.18.8/arch/x86_64/kernel/machine_kexec.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/machine_kexec.c     2008-05-19 00:33:19.013242080 +0300
+@@ -15,6 +15,128 @@
  #include <asm/mmu_context.h>
  #include <asm/io.h>
  
@@ -46843,6 +47420,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/machi
 +      xki->page_list[PA_PTE_1] = __ma(kexec_pte1);
 +}
 +
++int __init machine_kexec_setup_resources(struct resource *hypervisor,
++                                       struct resource *phys_cpus,
++                                       int nr_phys_cpus)
++{
++      int k;
++
++      /* The per-cpu crash note resources belong to the hypervisor resource */
++      for (k = 0; k < nr_phys_cpus; k++)
++              request_resource(hypervisor, phys_cpus + k);
++
++      return 0;
++}
++
++void machine_kexec_register_resources(struct resource *res) { ; }
++
 +#else /* CONFIG_XEN */
 +
 +#define x__pmd(x) __pmd(x)
@@ -46864,7 +47456,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/machi
  static void init_level2_page(pmd_t *level2p, unsigned long addr)
  {
        unsigned long end_addr;
-@@ -22,7 +129,7 @@
+@@ -22,7 +144,7 @@
        addr &= PAGE_MASK;
        end_addr = addr + PUD_SIZE;
        while (addr < end_addr) {
@@ -46873,7 +47465,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/machi
                addr += PMD_SIZE;
        }
  }
-@@ -47,12 +154,12 @@
+@@ -47,12 +169,12 @@
                }
                level2p = (pmd_t *)page_address(page);
                init_level2_page(level2p, addr);
@@ -46888,7 +47480,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/machi
                addr += PUD_SIZE;
        }
  out:
-@@ -83,12 +190,12 @@
+@@ -83,12 +205,12 @@
                if (result) {
                        goto out;
                }
@@ -46903,7 +47495,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/machi
                addr += PGDIR_SIZE;
        }
  out:
-@@ -99,77 +206,29 @@
+@@ -99,77 +221,29 @@
  static int init_pgtable(struct kimage *image, unsigned long start_pgtable)
  {
        pgd_t *level4p;
@@ -46918,22 +47510,22 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/machi
 -      /* x86-64 supports unaliged loads & stores */
 -      curidt.size    = limit;
 -      curidt.address = (unsigned long)newidt;
-+      unsigned long x_end_pfn = end_pfn;
+-
 -      __asm__ __volatile__ (
 -              "lidtq %0\n"
 -              : : "m" (curidt)
 -              );
 -};
--
--
--static void set_gdt(void *newgdt, u16 limit)
--{
--      struct desc_ptr curgdt;
++      unsigned long x_end_pfn = end_pfn;
 +#ifdef CONFIG_XEN
 +      x_end_pfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
 +#endif
  
+-static void set_gdt(void *newgdt, u16 limit)
+-{
+-      struct desc_ptr curgdt;
+-
 -      /* x86-64 supports unaligned loads & stores */
 -      curgdt.size    = limit;
 -      curgdt.address = (unsigned long)newgdt;
@@ -46988,7 +47580,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/machi
        return 0;
  }
  
-@@ -178,51 +237,43 @@
+@@ -178,51 +252,43 @@
        return;
  }
  
@@ -47066,36 +47658,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/machi
 +                      image->start);
  }
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/Makefile linux-2.6.18-xen.hg/arch/x86_64/kernel/Makefile
---- linux-2.6.18/arch/x86_64/kernel/Makefile   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/Makefile    2007-12-23 11:15:00.062817316 +0100
-@@ -21,11 +21,13 @@
- obj-$(CONFIG_X86_CPUID)               += cpuid.o
- obj-$(CONFIG_SMP)             += smp.o smpboot.o trampoline.o
- obj-$(CONFIG_X86_LOCAL_APIC)  += apic.o  nmi.o
-+obj-$(CONFIG_X86_XEN_GENAPIC) += genapic.o genapic_xen.o
- obj-$(CONFIG_X86_IO_APIC)     += io_apic.o mpparse.o \
-               genapic.o genapic_cluster.o genapic_flat.o
- obj-$(CONFIG_KEXEC)           += machine_kexec.o relocate_kernel.o crash.o
- obj-$(CONFIG_CRASH_DUMP)      += crash_dump.o
--obj-$(CONFIG_PM)              += suspend.o
-+obj-$(CONFIG_SOFTWARE_SUSPEND)        += suspend.o
-+obj-$(CONFIG_ACPI_SLEEP)      += suspend.o
- obj-$(CONFIG_SOFTWARE_SUSPEND)        += suspend_asm.o
- obj-$(CONFIG_CPU_FREQ)                += cpufreq/
- obj-$(CONFIG_EARLY_PRINTK)    += early_printk.o
-@@ -55,3 +57,8 @@
- msr-$(subst m,y,$(CONFIG_X86_MSR))  += ../../i386/kernel/msr.o
- alternative-y                 += ../../i386/kernel/alternative.o
-+time-$(CONFIG_XEN)            += ../../i386/kernel/time.o
-+pci-dma-$(CONFIG_XEN)         += ../../i386/kernel/pci-dma.o
-+
-+disabled-obj-$(CONFIG_XEN)    := i8259.o reboot.o smpboot.o trampoline.o
-+%/head.o %/head.s: $(if $(CONFIG_XEN),EXTRA_AFLAGS,dummy) :=
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/mpparse-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/mpparse-xen.c
---- linux-2.6.18/arch/x86_64/kernel/mpparse-xen.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/mpparse-xen.c       2007-12-23 11:15:00.092818896 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/mpparse-xen.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/mpparse-xen.c       2008-05-19 00:33:19.021242541 +0300
 @@ -0,0 +1,1011 @@
 +/*
 + *    Intel Multiprocessor Specification 1.1 and 1.4
@@ -48108,9 +48672,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/mppar
 +
 +#endif /*CONFIG_X86_IO_APIC*/
 +#endif /*CONFIG_ACPI*/
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/pci-swiotlb-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/pci-swiotlb-xen.c
---- linux-2.6.18/arch/x86_64/kernel/pci-swiotlb-xen.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/pci-swiotlb-xen.c   2007-12-23 11:15:00.096152403 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/pci-swiotlb-xen.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/pci-swiotlb-xen.c   2008-05-19 00:33:19.025242771 +0300
 @@ -0,0 +1,55 @@
 +/* Glue code to lib/swiotlb.c */
 +
@@ -48167,10 +48730,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/pci-s
 +      }
 +#endif
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/process-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/process-xen.c
---- linux-2.6.18/arch/x86_64/kernel/process-xen.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/process-xen.c       2007-12-23 11:15:00.099485909 +0100
-@@ -0,0 +1,829 @@
+--- linux-2.6.18.8/arch/x86_64/kernel/process-xen.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/process-xen.c       2008-05-19 00:33:19.029243002 +0300
+@@ -0,0 +1,833 @@
 +/*
 + *  linux/arch/x86-64/kernel/process.c
 + *
@@ -48325,7 +48887,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/proce
 +      local_irq_disable();
 +      cpu_clear(smp_processor_id(), cpu_initialized);
 +      preempt_enable_no_resched();
-+      HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL);
++      VOID(HYPERVISOR_vcpu_op(VCPUOP_down, smp_processor_id(), NULL));
 +      cpu_bringup();
 +}
 +#else
@@ -48491,7 +49053,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/proce
 +              put_cpu();
 +#endif
 +#ifdef CONFIG_XEN
-+              HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap, &iobmp_op);
++              WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iobitmap,
++                                            &iobmp_op));
 +#endif
 +              t->io_bitmap_max = 0;
 +      }
@@ -48499,7 +49062,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/proce
 +
 +void load_gs_index(unsigned gs)
 +{
-+      HYPERVISOR_set_segment_base(SEGBASE_GS_USER_SEL, gs);
++      WARN_ON(HYPERVISOR_set_segment_base(SEGBASE_GS_USER_SEL, gs));
 +}
 +
 +void flush_thread(void)
@@ -48723,7 +49286,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/proce
 +              mcl++;
 +      }
 +
-+      (void)HYPERVISOR_multicall(_mcl, mcl - _mcl);
++      BUG_ON(mcl > _mcl + ARRAY_SIZE(_mcl));
++      if (unlikely(HYPERVISOR_multicall_check(_mcl, mcl - _mcl, NULL)))
++              BUG();
++
 +      /* 
 +       * Switch DS and ES.
 +       * This won't pick up thread selector changes, but I guess that is ok.
@@ -48741,13 +49307,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/proce
 +              loadsegment(fs, next->fsindex);
 +
 +      if (next->fs)
-+              HYPERVISOR_set_segment_base(SEGBASE_FS, next->fs); 
++              WARN_ON(HYPERVISOR_set_segment_base(SEGBASE_FS, next->fs));
 +      
 +      if (unlikely(next->gsindex))
 +              load_gs_index(next->gsindex);
 +
 +      if (next->gs)
-+              HYPERVISOR_set_segment_base(SEGBASE_GS_USER, next->gs); 
++              WARN_ON(HYPERVISOR_set_segment_base(SEGBASE_GS_USER, next->gs));
 +
 +      /* 
 +       * Switch the PDA context.
@@ -49000,9 +49566,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/proce
 +{
 +}
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/relocate_kernel.S linux-2.6.18-xen.hg/arch/x86_64/kernel/relocate_kernel.S
---- linux-2.6.18/arch/x86_64/kernel/relocate_kernel.S  2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/relocate_kernel.S   2007-12-23 11:15:00.099485909 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/relocate_kernel.S        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/relocate_kernel.S   2008-05-19 00:33:19.033243233 +0300
 @@ -7,31 +7,195 @@
   */
  
@@ -49238,379 +49803,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/reloc
 +idt_80:
 +      .word   0                       /* limit */
 +      .quad   0                       /* base */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/setup64-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/setup64-xen.c
---- linux-2.6.18/arch/x86_64/kernel/setup64-xen.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/setup64-xen.c       2007-12-23 11:15:00.102819418 +0100
-@@ -0,0 +1,365 @@
-+/* 
-+ * X86-64 specific CPU setup.
-+ * Copyright (C) 1995  Linus Torvalds
-+ * Copyright 2001, 2002, 2003 SuSE Labs / Andi Kleen.
-+ * See setup.c for older changelog.
-+ *
-+ * Jun Nakajima <jun.nakajima@intel.com> 
-+ *   Modified for Xen
-+ *
-+ */ 
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/string.h>
-+#include <linux/bootmem.h>
-+#include <linux/bitops.h>
-+#include <linux/module.h>
-+#include <asm/bootsetup.h>
-+#include <asm/pda.h>
-+#include <asm/pgtable.h>
-+#include <asm/processor.h>
-+#include <asm/desc.h>
-+#include <asm/atomic.h>
-+#include <asm/mmu_context.h>
-+#include <asm/smp.h>
-+#include <asm/i387.h>
-+#include <asm/percpu.h>
-+#include <asm/proto.h>
-+#include <asm/sections.h>
-+#ifdef CONFIG_XEN
-+#include <asm/hypervisor.h>
-+#endif
-+
-+char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,};
-+
-+cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
-+
-+struct x8664_pda *_cpu_pda[NR_CPUS] __read_mostly;
-+EXPORT_SYMBOL(_cpu_pda);
-+struct x8664_pda boot_cpu_pda[NR_CPUS] __cacheline_aligned;
-+
-+#ifndef CONFIG_X86_NO_IDT
-+struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; 
-+#endif
-+
-+char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned")));
-+
-+unsigned long __supported_pte_mask __read_mostly = ~0UL;
-+EXPORT_SYMBOL(__supported_pte_mask);
-+static int do_not_nx __cpuinitdata = 0;
-+
-+/* noexec=on|off
-+Control non executable mappings for 64bit processes.
-+
-+on    Enable(default)
-+off   Disable
-+*/ 
-+int __init nonx_setup(char *str)
-+{
-+      if (!strncmp(str, "on", 2)) {
-+                __supported_pte_mask |= _PAGE_NX; 
-+              do_not_nx = 0; 
-+      } else if (!strncmp(str, "off", 3)) {
-+              do_not_nx = 1;
-+              __supported_pte_mask &= ~_PAGE_NX;
-+        }
-+      return 1;
-+} 
-+__setup("noexec=", nonx_setup);       /* parsed early actually */
-+
-+int force_personality32 = 0; 
-+
-+/* noexec32=on|off
-+Control non executable heap for 32bit processes.
-+To control the stack too use noexec=off
-+
-+on    PROT_READ does not imply PROT_EXEC for 32bit processes
-+off   PROT_READ implies PROT_EXEC (default)
-+*/
-+static int __init nonx32_setup(char *str)
-+{
-+      if (!strcmp(str, "on"))
-+              force_personality32 &= ~READ_IMPLIES_EXEC;
-+      else if (!strcmp(str, "off"))
-+              force_personality32 |= READ_IMPLIES_EXEC;
-+      return 1;
-+}
-+__setup("noexec32=", nonx32_setup);
-+
-+/*
-+ * Great future plan:
-+ * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
-+ * Always point %gs to its beginning
-+ */
-+void __init setup_per_cpu_areas(void)
-+{ 
-+      int i;
-+      unsigned long size;
-+
-+#ifdef CONFIG_HOTPLUG_CPU
-+      prefill_possible_map();
-+#endif
-+
-+      /* Copy section for each CPU (we discard the original) */
-+      size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
-+#ifdef CONFIG_MODULES
-+      if (size < PERCPU_ENOUGH_ROOM)
-+              size = PERCPU_ENOUGH_ROOM;
-+#endif
-+
-+      for_each_cpu_mask (i, cpu_possible_map) {
-+              char *ptr;
-+
-+              if (!NODE_DATA(cpu_to_node(i))) {
-+                      printk("cpu with no node %d, num_online_nodes %d\n",
-+                             i, num_online_nodes());
-+                      ptr = alloc_bootmem(size);
-+              } else { 
-+                      ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size);
-+              }
-+              if (!ptr)
-+                      panic("Cannot allocate cpu data for CPU %d\n", i);
-+              cpu_pda(i)->data_offset = ptr - __per_cpu_start;
-+              memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
-+      }
-+} 
-+
-+#ifdef CONFIG_XEN
-+static void switch_pt(void)
-+{
-+      xen_pt_switch(__pa_symbol(init_level4_pgt));
-+      xen_new_user_pt(__pa_symbol(__user_pgd(init_level4_pgt)));
-+}
-+
-+static void __cpuinit cpu_gdt_init(const struct desc_ptr *gdt_descr)
-+{
-+      unsigned long frames[16];
-+      unsigned long va;
-+      int f;
-+
-+      for (va = gdt_descr->address, f = 0;
-+           va < gdt_descr->address + gdt_descr->size;
-+           va += PAGE_SIZE, f++) {
-+              frames[f] = virt_to_mfn(va);
-+              make_page_readonly(
-+                      (void *)va, XENFEAT_writable_descriptor_tables);
-+      }
-+      if (HYPERVISOR_set_gdt(frames, (gdt_descr->size + 1) /
-+                               sizeof (struct desc_struct)))
-+              BUG();
-+}
-+#else
-+static void switch_pt(void)
-+{
-+      asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt)));
-+}
-+
-+static void __cpuinit cpu_gdt_init(const struct desc_ptr *gdt_descr)
-+{
-+      asm volatile("lgdt %0" :: "m" (*gdt_descr));
-+      asm volatile("lidt %0" :: "m" (idt_descr));
-+}
-+#endif
-+
-+void pda_init(int cpu)
-+{ 
-+      struct x8664_pda *pda = cpu_pda(cpu);
-+
-+      /* Setup up data that may be needed in __get_free_pages early */
-+      asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0)); 
-+#ifndef CONFIG_XEN
-+      wrmsrl(MSR_GS_BASE, pda);
-+#else
-+      HYPERVISOR_set_segment_base(SEGBASE_GS_KERNEL, (unsigned long)pda);
-+#endif
-+      pda->cpunumber = cpu; 
-+      pda->irqcount = -1;
-+      pda->kernelstack = 
-+              (unsigned long)stack_thread_info() - PDA_STACKOFFSET + THREAD_SIZE; 
-+      pda->active_mm = &init_mm;
-+      pda->mmu_state = 0;
-+
-+      if (cpu == 0) {
-+#ifdef CONFIG_XEN
-+              xen_init_pt();
-+#endif
-+              /* others are initialized in smpboot.c */
-+              pda->pcurrent = &init_task;
-+              pda->irqstackptr = boot_cpu_stack; 
-+      } else {
-+              pda->irqstackptr = (char *)
-+                      __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
-+              if (!pda->irqstackptr)
-+                      panic("cannot allocate irqstack for cpu %d", cpu); 
-+      }
-+
-+      switch_pt();
-+
-+      pda->irqstackptr += IRQSTACKSIZE-64;
-+} 
-+
-+#ifndef CONFIG_X86_NO_TSS
-+char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]
-+__attribute__((section(".bss.page_aligned")));
-+#endif
-+
-+/* May not be marked __init: used by software suspend */
-+void syscall_init(void)
-+{
-+#ifndef CONFIG_XEN
-+      /* 
-+       * LSTAR and STAR live in a bit strange symbiosis.
-+       * They both write to the same internal register. STAR allows to set CS/DS
-+       * but only a 32bit target. LSTAR sets the 64bit rip.    
-+       */ 
-+      wrmsrl(MSR_STAR,  ((u64)__USER32_CS)<<48  | ((u64)__KERNEL_CS)<<32); 
-+      wrmsrl(MSR_LSTAR, system_call); 
-+
-+      /* Flags to clear on syscall */
-+      wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE|0x3000); 
-+#endif
-+#ifdef CONFIG_IA32_EMULATION                  
-+      syscall32_cpu_init ();
-+#endif
-+}
-+
-+void __cpuinit check_efer(void)
-+{
-+      unsigned long efer;
-+
-+      rdmsrl(MSR_EFER, efer); 
-+        if (!(efer & EFER_NX) || do_not_nx) { 
-+                __supported_pte_mask &= ~_PAGE_NX; 
-+        }       
-+}
-+
-+unsigned long kernel_eflags;
-+
-+/*
-+ * cpu_init() initializes state that is per-CPU. Some data is already
-+ * initialized (naturally) in the bootstrap process, such as the GDT
-+ * and IDT. We reload them nevertheless, this function acts as a
-+ * 'CPU state barrier', nothing should get across.
-+ * A lot of state is already set up in PDA init.
-+ */
-+void __cpuinit cpu_init (void)
-+{
-+      int cpu = stack_smp_processor_id();
-+#ifndef CONFIG_X86_NO_TSS
-+      struct tss_struct *t = &per_cpu(init_tss, cpu);
-+      struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu);
-+      unsigned long v; 
-+      char *estacks = NULL; 
-+      unsigned i;
-+#endif
-+      struct task_struct *me;
-+
-+      /* CPU 0 is initialised in head64.c */
-+      if (cpu != 0) {
-+              pda_init(cpu);
-+              zap_low_mappings(cpu);
-+      }
-+#ifndef CONFIG_X86_NO_TSS
-+      else
-+              estacks = boot_exception_stacks; 
-+#endif
-+
-+      me = current;
-+
-+      if (cpu_test_and_set(cpu, cpu_initialized))
-+              panic("CPU#%d already initialized!\n", cpu);
-+
-+      printk("Initializing CPU#%d\n", cpu);
-+
-+      clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
-+
-+      /*
-+       * Initialize the per-CPU GDT with the boot GDT,
-+       * and set up the GDT descriptor:
-+       */
-+#ifndef CONFIG_XEN 
-+      if (cpu)
-+              memcpy(cpu_gdt(cpu), cpu_gdt_table, GDT_SIZE);
-+#endif
-+
-+      cpu_gdt_descr[cpu].size = GDT_SIZE;
-+      cpu_gdt_init(&cpu_gdt_descr[cpu]);
-+
-+      memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8);
-+      syscall_init();
-+
-+      wrmsrl(MSR_FS_BASE, 0);
-+      wrmsrl(MSR_KERNEL_GS_BASE, 0);
-+      barrier(); 
-+
-+      check_efer();
-+
-+#ifndef CONFIG_X86_NO_TSS
-+      /*
-+       * set up and load the per-CPU TSS
-+       */
-+      for (v = 0; v < N_EXCEPTION_STACKS; v++) {
-+              if (cpu) {
-+                      static const unsigned int order[N_EXCEPTION_STACKS] = {
-+                              [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
-+                              [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
-+                      };
-+
-+                      estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
-+                      if (!estacks)
-+                              panic("Cannot allocate exception stack %ld %d\n",
-+                                    v, cpu); 
-+              }
-+              switch (v + 1) {
-+#if DEBUG_STKSZ > EXCEPTION_STKSZ
-+              case DEBUG_STACK:
-+                      cpu_pda(cpu)->debugstack = (unsigned long)estacks;
-+                      estacks += DEBUG_STKSZ;
-+                      break;
-+#endif
-+              default:
-+                      estacks += EXCEPTION_STKSZ;
-+                      break;
-+              }
-+              orig_ist->ist[v] = t->ist[v] = (unsigned long)estacks;
-+      }
-+
-+      t->io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
-+      /*
-+       * <= is required because the CPU will access up to
-+       * 8 bits beyond the end of the IO permission bitmap.
-+       */
-+      for (i = 0; i <= IO_BITMAP_LONGS; i++)
-+              t->io_bitmap[i] = ~0UL;
-+#endif
-+
-+      atomic_inc(&init_mm.mm_count);
-+      me->active_mm = &init_mm;
-+      if (me->mm)
-+              BUG();
-+      enter_lazy_tlb(&init_mm, me);
-+
-+#ifndef CONFIG_X86_NO_TSS
-+      set_tss_desc(cpu, t);
-+#endif
-+#ifndef CONFIG_XEN
-+      load_TR_desc();
-+#endif
-+      load_LDT(&init_mm.context);
-+
-+      /*
-+       * Clear all 6 debug registers:
-+       */
-+
-+      set_debugreg(0UL, 0);
-+      set_debugreg(0UL, 1);
-+      set_debugreg(0UL, 2);
-+      set_debugreg(0UL, 3);
-+      set_debugreg(0UL, 6);
-+      set_debugreg(0UL, 7);
-+
-+      fpu_init(); 
-+
-+      raw_local_save_flags(kernel_eflags);
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/setup-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/setup-xen.c
---- linux-2.6.18/arch/x86_64/kernel/setup-xen.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/setup-xen.c 2007-12-23 11:15:00.102819418 +0100
-@@ -0,0 +1,1662 @@
+--- linux-2.6.18.8/arch/x86_64/kernel/setup-xen.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/setup-xen.c 2008-05-19 00:33:19.037243463 +0300
+@@ -0,0 +1,1652 @@
 +/*
 + *  linux/arch/x86-64/kernel/setup.c
 + *
@@ -50220,8 +50415,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/setup
 +
 +      copy_edid();
 +
-+      HYPERVISOR_vm_assist(VMASST_CMD_enable,
-+                           VMASST_TYPE_writable_pagetables);
++      WARN_ON(HYPERVISOR_vm_assist(VMASST_CMD_enable,
++                                   VMASST_TYPE_writable_pagetables));
 +
 +      ARCH_SETUP
 +#else
@@ -50516,18 +50711,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/setup
 +       */
 +      probe_roms();
 +#ifdef CONFIG_XEN
-+      if (is_initial_xendomain()) {
-+              struct xen_memory_map memmap;
-+
-+              memmap.nr_entries = E820MAX;
-+              set_xen_guest_handle(memmap.buffer, machine_e820.map);
-+
-+              if (HYPERVISOR_memory_op(XENMEM_machine_memory_map, &memmap))
-+                      BUG();
-+              machine_e820.nr_map = memmap.nr_entries;
-+
++      if (is_initial_xendomain())
 +              e820_reserve_resources(machine_e820.map, machine_e820.nr_map);
-+      }
 +#else
 +      e820_reserve_resources(e820.map, e820.nr_map);
 +#endif
@@ -50553,7 +50738,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/setup
 +              struct physdev_set_iopl set_iopl;
 +
 +              set_iopl.iopl = 1;
-+              HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
++              WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl));
 +
 +              if (is_initial_xendomain()) {
 +#ifdef CONFIG_VT
@@ -51273,10 +51458,536 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/setup
 +}
 +device_initcall(add_pcspkr);
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/smp-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/smp-xen.c
---- linux-2.6.18/arch/x86_64/kernel/smp-xen.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/smp-xen.c   2007-12-23 11:15:00.106152927 +0100
-@@ -0,0 +1,577 @@
+--- linux-2.6.18.8/arch/x86_64/kernel/setup64-xen.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/setup64-xen.c       2008-05-19 00:33:19.037243463 +0300
+@@ -0,0 +1,367 @@
++/* 
++ * X86-64 specific CPU setup.
++ * Copyright (C) 1995  Linus Torvalds
++ * Copyright 2001, 2002, 2003 SuSE Labs / Andi Kleen.
++ * See setup.c for older changelog.
++ *
++ * Jun Nakajima <jun.nakajima@intel.com> 
++ *   Modified for Xen
++ *
++ */ 
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/string.h>
++#include <linux/bootmem.h>
++#include <linux/bitops.h>
++#include <linux/module.h>
++#include <asm/bootsetup.h>
++#include <asm/pda.h>
++#include <asm/pgtable.h>
++#include <asm/processor.h>
++#include <asm/desc.h>
++#include <asm/atomic.h>
++#include <asm/mmu_context.h>
++#include <asm/smp.h>
++#include <asm/i387.h>
++#include <asm/percpu.h>
++#include <asm/proto.h>
++#include <asm/sections.h>
++#ifdef CONFIG_XEN
++#include <asm/hypervisor.h>
++#endif
++
++char x86_boot_params[BOOT_PARAM_SIZE] __initdata = {0,};
++
++cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE;
++
++struct x8664_pda *_cpu_pda[NR_CPUS] __read_mostly;
++EXPORT_SYMBOL(_cpu_pda);
++struct x8664_pda boot_cpu_pda[NR_CPUS] __cacheline_aligned;
++
++#ifndef CONFIG_X86_NO_IDT
++struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; 
++#endif
++
++char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned")));
++
++unsigned long __supported_pte_mask __read_mostly = ~0UL;
++EXPORT_SYMBOL(__supported_pte_mask);
++static int do_not_nx __cpuinitdata = 0;
++
++/* noexec=on|off
++Control non executable mappings for 64bit processes.
++
++on    Enable(default)
++off   Disable
++*/ 
++int __init nonx_setup(char *str)
++{
++      if (!strncmp(str, "on", 2)) {
++                __supported_pte_mask |= _PAGE_NX; 
++              do_not_nx = 0; 
++      } else if (!strncmp(str, "off", 3)) {
++              do_not_nx = 1;
++              __supported_pte_mask &= ~_PAGE_NX;
++        }
++      return 1;
++} 
++__setup("noexec=", nonx_setup);       /* parsed early actually */
++
++int force_personality32 = 0; 
++
++/* noexec32=on|off
++Control non executable heap for 32bit processes.
++To control the stack too use noexec=off
++
++on    PROT_READ does not imply PROT_EXEC for 32bit processes
++off   PROT_READ implies PROT_EXEC (default)
++*/
++static int __init nonx32_setup(char *str)
++{
++      if (!strcmp(str, "on"))
++              force_personality32 &= ~READ_IMPLIES_EXEC;
++      else if (!strcmp(str, "off"))
++              force_personality32 |= READ_IMPLIES_EXEC;
++      return 1;
++}
++__setup("noexec32=", nonx32_setup);
++
++/*
++ * Great future plan:
++ * Declare PDA itself and support (irqstack,tss,pgd) as per cpu data.
++ * Always point %gs to its beginning
++ */
++void __init setup_per_cpu_areas(void)
++{ 
++      int i;
++      unsigned long size;
++
++#ifdef CONFIG_HOTPLUG_CPU
++      prefill_possible_map();
++#endif
++
++      /* Copy section for each CPU (we discard the original) */
++      size = ALIGN(__per_cpu_end - __per_cpu_start, SMP_CACHE_BYTES);
++#ifdef CONFIG_MODULES
++      if (size < PERCPU_ENOUGH_ROOM)
++              size = PERCPU_ENOUGH_ROOM;
++#endif
++
++      for_each_cpu_mask (i, cpu_possible_map) {
++              char *ptr;
++
++              if (!NODE_DATA(cpu_to_node(i))) {
++                      printk("cpu with no node %d, num_online_nodes %d\n",
++                             i, num_online_nodes());
++                      ptr = alloc_bootmem(size);
++              } else { 
++                      ptr = alloc_bootmem_node(NODE_DATA(cpu_to_node(i)), size);
++              }
++              if (!ptr)
++                      panic("Cannot allocate cpu data for CPU %d\n", i);
++              cpu_pda(i)->data_offset = ptr - __per_cpu_start;
++              memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start);
++      }
++} 
++
++#ifdef CONFIG_XEN
++static void switch_pt(void)
++{
++      xen_pt_switch(__pa_symbol(init_level4_pgt));
++      xen_new_user_pt(__pa_symbol(__user_pgd(init_level4_pgt)));
++}
++
++static void __cpuinit cpu_gdt_init(const struct desc_ptr *gdt_descr)
++{
++      unsigned long frames[16];
++      unsigned long va;
++      int f;
++
++      for (va = gdt_descr->address, f = 0;
++           va < gdt_descr->address + gdt_descr->size;
++           va += PAGE_SIZE, f++) {
++              frames[f] = virt_to_mfn(va);
++              make_page_readonly(
++                      (void *)va, XENFEAT_writable_descriptor_tables);
++      }
++      if (HYPERVISOR_set_gdt(frames, (gdt_descr->size + 1) /
++                               sizeof (struct desc_struct)))
++              BUG();
++}
++#else
++static void switch_pt(void)
++{
++      asm volatile("movq %0,%%cr3" :: "r" (__pa_symbol(&init_level4_pgt)));
++}
++
++static void __cpuinit cpu_gdt_init(const struct desc_ptr *gdt_descr)
++{
++      asm volatile("lgdt %0" :: "m" (*gdt_descr));
++      asm volatile("lidt %0" :: "m" (idt_descr));
++}
++#endif
++
++void pda_init(int cpu)
++{ 
++      struct x8664_pda *pda = cpu_pda(cpu);
++
++      /* Setup up data that may be needed in __get_free_pages early */
++      asm volatile("movl %0,%%fs ; movl %0,%%gs" :: "r" (0)); 
++#ifndef CONFIG_XEN
++      wrmsrl(MSR_GS_BASE, pda);
++#else
++      if (HYPERVISOR_set_segment_base(SEGBASE_GS_KERNEL,
++                                      (unsigned long)pda))
++              BUG();
++#endif
++      pda->cpunumber = cpu; 
++      pda->irqcount = -1;
++      pda->kernelstack = 
++              (unsigned long)stack_thread_info() - PDA_STACKOFFSET + THREAD_SIZE; 
++      pda->active_mm = &init_mm;
++      pda->mmu_state = 0;
++
++      if (cpu == 0) {
++#ifdef CONFIG_XEN
++              xen_init_pt();
++#endif
++              /* others are initialized in smpboot.c */
++              pda->pcurrent = &init_task;
++              pda->irqstackptr = boot_cpu_stack; 
++      } else {
++              pda->irqstackptr = (char *)
++                      __get_free_pages(GFP_ATOMIC, IRQSTACK_ORDER);
++              if (!pda->irqstackptr)
++                      panic("cannot allocate irqstack for cpu %d", cpu); 
++      }
++
++      switch_pt();
++
++      pda->irqstackptr += IRQSTACKSIZE-64;
++} 
++
++#ifndef CONFIG_X86_NO_TSS
++char boot_exception_stacks[(N_EXCEPTION_STACKS - 1) * EXCEPTION_STKSZ + DEBUG_STKSZ]
++__attribute__((section(".bss.page_aligned")));
++#endif
++
++/* May not be marked __init: used by software suspend */
++void syscall_init(void)
++{
++#ifndef CONFIG_XEN
++      /* 
++       * LSTAR and STAR live in a bit strange symbiosis.
++       * They both write to the same internal register. STAR allows to set CS/DS
++       * but only a 32bit target. LSTAR sets the 64bit rip.    
++       */ 
++      wrmsrl(MSR_STAR,  ((u64)__USER32_CS)<<48  | ((u64)__KERNEL_CS)<<32); 
++      wrmsrl(MSR_LSTAR, system_call); 
++
++      /* Flags to clear on syscall */
++      wrmsrl(MSR_SYSCALL_MASK, EF_TF|EF_DF|EF_IE|0x3000); 
++#endif
++#ifdef CONFIG_IA32_EMULATION                  
++      syscall32_cpu_init ();
++#endif
++}
++
++void __cpuinit check_efer(void)
++{
++      unsigned long efer;
++
++      rdmsrl(MSR_EFER, efer); 
++        if (!(efer & EFER_NX) || do_not_nx) { 
++                __supported_pte_mask &= ~_PAGE_NX; 
++        }       
++}
++
++unsigned long kernel_eflags;
++
++/*
++ * cpu_init() initializes state that is per-CPU. Some data is already
++ * initialized (naturally) in the bootstrap process, such as the GDT
++ * and IDT. We reload them nevertheless, this function acts as a
++ * 'CPU state barrier', nothing should get across.
++ * A lot of state is already set up in PDA init.
++ */
++void __cpuinit cpu_init (void)
++{
++      int cpu = stack_smp_processor_id();
++#ifndef CONFIG_X86_NO_TSS
++      struct tss_struct *t = &per_cpu(init_tss, cpu);
++      struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu);
++      unsigned long v; 
++      char *estacks = NULL; 
++      unsigned i;
++#endif
++      struct task_struct *me;
++
++      /* CPU 0 is initialised in head64.c */
++      if (cpu != 0) {
++              pda_init(cpu);
++              zap_low_mappings(cpu);
++      }
++#ifndef CONFIG_X86_NO_TSS
++      else
++              estacks = boot_exception_stacks; 
++#endif
++
++      me = current;
++
++      if (cpu_test_and_set(cpu, cpu_initialized))
++              panic("CPU#%d already initialized!\n", cpu);
++
++      printk("Initializing CPU#%d\n", cpu);
++
++      clear_in_cr4(X86_CR4_VME|X86_CR4_PVI|X86_CR4_TSD|X86_CR4_DE);
++
++      /*
++       * Initialize the per-CPU GDT with the boot GDT,
++       * and set up the GDT descriptor:
++       */
++#ifndef CONFIG_XEN 
++      if (cpu)
++              memcpy(cpu_gdt(cpu), cpu_gdt_table, GDT_SIZE);
++#endif
++
++      cpu_gdt_descr[cpu].size = GDT_SIZE;
++      cpu_gdt_init(&cpu_gdt_descr[cpu]);
++
++      memset(me->thread.tls_array, 0, GDT_ENTRY_TLS_ENTRIES * 8);
++      syscall_init();
++
++      wrmsrl(MSR_FS_BASE, 0);
++      wrmsrl(MSR_KERNEL_GS_BASE, 0);
++      barrier(); 
++
++      check_efer();
++
++#ifndef CONFIG_X86_NO_TSS
++      /*
++       * set up and load the per-CPU TSS
++       */
++      for (v = 0; v < N_EXCEPTION_STACKS; v++) {
++              if (cpu) {
++                      static const unsigned int order[N_EXCEPTION_STACKS] = {
++                              [0 ... N_EXCEPTION_STACKS - 1] = EXCEPTION_STACK_ORDER,
++                              [DEBUG_STACK - 1] = DEBUG_STACK_ORDER
++                      };
++
++                      estacks = (char *)__get_free_pages(GFP_ATOMIC, order[v]);
++                      if (!estacks)
++                              panic("Cannot allocate exception stack %ld %d\n",
++                                    v, cpu); 
++              }
++              switch (v + 1) {
++#if DEBUG_STKSZ > EXCEPTION_STKSZ
++              case DEBUG_STACK:
++                      cpu_pda(cpu)->debugstack = (unsigned long)estacks;
++                      estacks += DEBUG_STKSZ;
++                      break;
++#endif
++              default:
++                      estacks += EXCEPTION_STKSZ;
++                      break;
++              }
++              orig_ist->ist[v] = t->ist[v] = (unsigned long)estacks;
++      }
++
++      t->io_bitmap_base = offsetof(struct tss_struct, io_bitmap);
++      /*
++       * <= is required because the CPU will access up to
++       * 8 bits beyond the end of the IO permission bitmap.
++       */
++      for (i = 0; i <= IO_BITMAP_LONGS; i++)
++              t->io_bitmap[i] = ~0UL;
++#endif
++
++      atomic_inc(&init_mm.mm_count);
++      me->active_mm = &init_mm;
++      if (me->mm)
++              BUG();
++      enter_lazy_tlb(&init_mm, me);
++
++#ifndef CONFIG_X86_NO_TSS
++      set_tss_desc(cpu, t);
++#endif
++#ifndef CONFIG_XEN
++      load_TR_desc();
++#endif
++      load_LDT(&init_mm.context);
++
++      /*
++       * Clear all 6 debug registers:
++       */
++
++      set_debugreg(0UL, 0);
++      set_debugreg(0UL, 1);
++      set_debugreg(0UL, 2);
++      set_debugreg(0UL, 3);
++      set_debugreg(0UL, 6);
++      set_debugreg(0UL, 7);
++
++      fpu_init(); 
++
++      raw_local_save_flags(kernel_eflags);
++}
+--- linux-2.6.18.8/arch/x86_64/kernel/signal.c 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/signal.c    2008-05-19 00:33:19.041243694 +0300
+@@ -38,37 +38,6 @@
+             sigset_t *set, struct pt_regs * regs); 
+ asmlinkage long
+-sys_rt_sigsuspend(sigset_t __user *unewset, size_t sigsetsize, struct pt_regs *regs)
+-{
+-      sigset_t saveset, newset;
+-
+-      /* XXX: Don't preclude handling different sized sigset_t's.  */
+-      if (sigsetsize != sizeof(sigset_t))
+-              return -EINVAL;
+-
+-      if (copy_from_user(&newset, unewset, sizeof(newset)))
+-              return -EFAULT;
+-      sigdelsetmask(&newset, ~_BLOCKABLE);
+-
+-      spin_lock_irq(&current->sighand->siglock);
+-      saveset = current->blocked;
+-      current->blocked = newset;
+-      recalc_sigpending();
+-      spin_unlock_irq(&current->sighand->siglock);
+-#ifdef DEBUG_SIG
+-      printk("rt_sigsuspend savset(%lx) newset(%lx) regs(%p) rip(%lx)\n",
+-              saveset, newset, regs, regs->rip);
+-#endif 
+-      regs->rax = -EINTR;
+-      while (1) {
+-              current->state = TASK_INTERRUPTIBLE;
+-              schedule();
+-              if (do_signal(regs, &saveset))
+-                      return -EINTR;
+-      }
+-}
+-
+-asmlinkage long
+ sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
+               struct pt_regs *regs)
+ {
+@@ -341,11 +310,11 @@
+               current->comm, current->pid, frame, regs->rip, frame->pretcode);
+ #endif
+-      return 1;
++      return 0;
+ give_sigsegv:
+       force_sigsegv(sig, current);
+-      return 0;
++      return -EFAULT;
+ }
+ /*
+@@ -408,7 +377,7 @@
+ #endif
+       ret = setup_rt_frame(sig, ka, info, oldset, regs);
+-      if (ret) {
++      if (ret == 0) {
+               spin_lock_irq(&current->sighand->siglock);
+               sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);
+               if (!(ka->sa.sa_flags & SA_NODEFER))
+@@ -425,11 +394,12 @@
+  * want to handle. Thus you cannot kill init even with a SIGKILL even by
+  * mistake.
+  */
+-int do_signal(struct pt_regs *regs, sigset_t *oldset)
++static void do_signal(struct pt_regs *regs)
+ {
+       struct k_sigaction ka;
+       siginfo_t info;
+       int signr;
++      sigset_t *oldset;
+       /*
+        * We want the common case to go fast, which
+@@ -438,9 +408,11 @@
+        * if so.
+        */
+       if (!user_mode(regs))
+-              return 1;
++              return;
+-      if (!oldset)
++      if (test_thread_flag(TIF_RESTORE_SIGMASK))
++              oldset = &current->saved_sigmask;
++      else
+               oldset = &current->blocked;
+       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+@@ -454,30 +426,46 @@
+                       set_debugreg(current->thread.debugreg7, 7);
+               /* Whee!  Actually deliver the signal.  */
+-              return handle_signal(signr, &info, &ka, oldset, regs);
++              if (handle_signal(signr, &info, &ka, oldset, regs) == 0) {
++                      /* a signal was successfully delivered; the saved
++                       * sigmask will have been stored in the signal frame,
++                       * and will be restored by sigreturn, so we can simply
++                       * clear the TIF_RESTORE_SIGMASK flag */
++                      clear_thread_flag(TIF_RESTORE_SIGMASK);
++              }
++              return;
+       }
+       /* Did we come from a system call? */
+       if ((long)regs->orig_rax >= 0) {
+               /* Restart the system call - no handlers present */
+               long res = regs->rax;
+-              if (res == -ERESTARTNOHAND ||
+-                  res == -ERESTARTSYS ||
+-                  res == -ERESTARTNOINTR) {
++              switch (res) {
++              case -ERESTARTNOHAND:
++              case -ERESTARTSYS:
++              case -ERESTARTNOINTR:
+                       regs->rax = regs->orig_rax;
+                       regs->rip -= 2;
+-              }
+-              if (regs->rax == (unsigned long)-ERESTART_RESTARTBLOCK) {
++                      break;
++              case -ERESTART_RESTARTBLOCK:
+                       regs->rax = test_thread_flag(TIF_IA32) ?
+                                       __NR_ia32_restart_syscall :
+                                       __NR_restart_syscall;
+                       regs->rip -= 2;
++                      break;
+               }
+       }
+-      return 0;
++
++      /* if there's no signal to deliver, we just put the saved sigmask
++         back. */
++      if (test_thread_flag(TIF_RESTORE_SIGMASK)) {
++              clear_thread_flag(TIF_RESTORE_SIGMASK);
++              sigprocmask(SIG_SETMASK, &current->saved_sigmask, NULL);
++      }
+ }
+-void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_flags)
++void
++do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
+ {
+ #ifdef DEBUG_SIG
+       printk("do_notify_resume flags:%x rip:%lx rsp:%lx caller:%lx pending:%lx\n",
+@@ -491,8 +479,8 @@
+       }
+       /* deal with pending signal delivery */
+-      if (thread_info_flags & _TIF_SIGPENDING)
+-              do_signal(regs,oldset);
++      if (thread_info_flags & (_TIF_SIGPENDING|_TIF_RESTORE_SIGMASK))
++              do_signal(regs);
+ }
+ void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
+--- linux-2.6.18.8/arch/x86_64/kernel/smp-xen.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/smp-xen.c   2008-05-19 00:33:19.041243694 +0300
+@@ -0,0 +1,575 @@
 +/*
 + *    Intel SMP support routines.
 + *
@@ -51349,7 +52060,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/smp-x
 +   to a full cache line because other CPUs can access it and we don't
 +   want false sharing in the per cpu data segment. */
 +static DEFINE_PER_CPU(union smp_flush_state, flush_state);
-+#endif
 +
 +/*
 + * We cannot call mmdrop() because we are in interrupt context, 
@@ -51363,7 +52073,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/smp-x
 +      load_cr3(swapper_pg_dir);
 +}
 +
-+#ifndef CONFIG_XEN
 +/*
 + *
 + * The flush IPI assumes that a thread switch happens in this order:
@@ -51854,9 +52563,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/smp-x
 +      return 0; /* Should not happen */
 +#endif
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/suspend.c linux-2.6.18-xen.hg/arch/x86_64/kernel/suspend.c
---- linux-2.6.18/arch/x86_64/kernel/suspend.c  2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/suspend.c   2007-12-23 11:15:00.106152927 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/suspend.c        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/suspend.c   2008-05-19 00:33:19.045243924 +0300
 @@ -114,12 +114,14 @@
  
  void fix_processor_context(void)
@@ -51872,10 +52580,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/suspe
  
        syscall_init();                         /* This sets MSR_*STAR and related */
        load_TR_desc();                         /* This does ltr */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/traps-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/traps-xen.c
---- linux-2.6.18/arch/x86_64/kernel/traps-xen.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/traps-xen.c 2007-12-23 11:15:00.112819947 +0100
-@@ -0,0 +1,1175 @@
+--- linux-2.6.18.8/arch/x86_64/kernel/traps-xen.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/traps-xen.c 2008-05-19 00:33:19.053244386 +0300
+@@ -0,0 +1,1173 @@
 +/*
 + *  linux/arch/x86-64/traps.c
 + *
@@ -52966,7 +53673,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/traps
 + * NB. All these are "interrupt gates" (i.e. events_mask is set) because we
 + * specify <dpl>|4 in the second field.
 + */
-+static trap_info_t trap_table[] = {
++static trap_info_t __cpuinitdata trap_table[] = {
 +        {  0, 0|4, __KERNEL_CS, (unsigned long)divide_error               },
 +        {  1, 0|4, __KERNEL_CS, (unsigned long)debug                      },
 +        {  3, 3|4, __KERNEL_CS, (unsigned long)int3                       },
@@ -52998,10 +53705,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/traps
 +        int ret;
 +
 +        ret = HYPERVISOR_set_trap_table(trap_table);
-+        
 +        if (ret) 
-+                printk("HYPERVISOR_set_trap_table faild: error %d\n",
-+                       ret);
++              printk("HYPERVISOR_set_trap_table failed: error %d\n", ret);
 +
 +      /*
 +       * Should be a barrier for any external CPU state.
@@ -53009,9 +53714,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/traps
 +      cpu_init();
 +}
 +
-+void smp_trap_init(trap_info_t *trap_ctxt)
++void __cpuinit smp_trap_init(trap_info_t *trap_ctxt)
 +{
-+      trap_info_t *t = trap_table;
++      const trap_info_t *t = trap_table;
 +
 +      for (t = trap_table; t->address; t++) {
 +              trap_ctxt[t->vector].flags = t->flags;
@@ -53051,9 +53756,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/traps
 +}
 +__setup("call_trace=", call_trace_setup);
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/vmlinux.lds.S linux-2.6.18-xen.hg/arch/x86_64/kernel/vmlinux.lds.S
---- linux-2.6.18/arch/x86_64/kernel/vmlinux.lds.S      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/vmlinux.lds.S       2007-12-23 11:15:00.112819947 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/vmlinux.lds.S    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/vmlinux.lds.S       2008-05-19 00:33:19.053244386 +0300
 @@ -13,6 +13,13 @@
  OUTPUT_ARCH(i386:x86-64)
  ENTRY(phys_startup_64)
@@ -53136,9 +53840,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/vmlin
 +
 +  NOTES
  }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/vsyscall-xen.c linux-2.6.18-xen.hg/arch/x86_64/kernel/vsyscall-xen.c
---- linux-2.6.18/arch/x86_64/kernel/vsyscall-xen.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/vsyscall-xen.c      2007-12-23 11:15:00.112819947 +0100
+--- linux-2.6.18.8/arch/x86_64/kernel/vsyscall-xen.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/vsyscall-xen.c      2008-05-19 00:33:19.057244616 +0300
 @@ -0,0 +1,227 @@
 +/*
 + *  linux/arch/x86_64/kernel/vsyscall.c
@@ -53367,10 +54070,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/vsysc
 +}
 +
 +__initcall(vsyscall_init);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/xen_entry.S linux-2.6.18-xen.hg/arch/x86_64/kernel/xen_entry.S
---- linux-2.6.18/arch/x86_64/kernel/xen_entry.S        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/kernel/xen_entry.S 2007-12-23 11:15:00.116153454 +0100
-@@ -0,0 +1,40 @@
+--- linux-2.6.18.8/arch/x86_64/kernel/xen_entry.S      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/kernel/xen_entry.S 2008-05-19 00:33:19.057244616 +0300
+@@ -0,0 +1,36 @@
 +/*
 + * Copied from arch/xen/i386/kernel/entry.S
 + */                        
@@ -53407,48 +54109,30 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/kernel/xen_e
 +                              XEN_LOCKED_UNBLOCK_EVENTS(reg)          ; \
 +                              XEN_PUT_VCPU_INFO(reg)
 +#define XEN_TEST_PENDING(reg) testb $0xFF,evtchn_upcall_pending(reg)
-+
-+VGCF_IN_SYSCALL = (1<<8)
-+        
-+      
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/Makefile linux-2.6.18-xen.hg/arch/x86_64/Makefile
---- linux-2.6.18/arch/x86_64/Makefile  2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/Makefile   2007-12-23 11:15:00.042816270 +0100
-@@ -71,9 +71,22 @@
- boot := arch/x86_64/boot
--PHONY += bzImage bzlilo install archmrproper \
-+PHONY += bzImage bzlilo vmlinuz install archmrproper \
-        fdimage fdimage144 fdimage288 isoimage archclean
-+ifdef CONFIG_XEN
-+CPPFLAGS := -D__XEN_INTERFACE_VERSION__=$(CONFIG_XEN_INTERFACE_VERSION) \
-+      -Iinclude$(if $(KBUILD_SRC),2)/asm/mach-xen $(CPPFLAGS)
-+LDFLAGS_vmlinux := -e startup_64
-+#Default target when executing "make"
-+all: vmlinuz
-+
-+BOOTIMAGE                     := $(boot)/vmlinuz
-+KBUILD_IMAGE                  := $(BOOTIMAGE)
-+
-+vmlinuz: vmlinux
-+      $(Q)$(MAKE) $(build)=$(boot) $(BOOTIMAGE)
-+else
- #Default target when executing "make"
- all: bzImage
-@@ -91,6 +104,7 @@
- fdimage fdimage144 fdimage288 isoimage: vmlinux
-       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@
-+endif
+--- linux-2.6.18.8/arch/x86_64/lib/Makefile    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/lib/Makefile       2008-05-19 00:33:19.061244847 +0300
+@@ -10,3 +10,4 @@
+       usercopy.o getuser.o putuser.o  \
+       thunk.o clear_page.o copy_page.o bitstr.o bitops.o
+ lib-y += memcpy.o memmove.o memset.o copy_user.o
++lib-$(CONFIG_XEN_SCRUB_PAGES) += scrub.o
+--- linux-2.6.18.8/arch/x86_64/lib/scrub.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/lib/scrub.c        2008-05-19 00:33:19.097246922 +0300
+@@ -0,0 +1 @@
++#include "../../i386/lib/scrub.c"
+--- linux-2.6.18.8/arch/x86_64/mm/Makefile     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/mm/Makefile        2008-05-19 00:33:19.101247152 +0300
+@@ -7,5 +7,8 @@
+ obj-$(CONFIG_NUMA) += numa.o
+ obj-$(CONFIG_K8_NUMA) += k8topology.o
+ obj-$(CONFIG_ACPI_NUMA) += srat.o
++obj-$(CONFIG_XEN) += hypervisor.o
  
- install:
-       $(Q)$(MAKE) $(build)=$(boot) BOOTIMAGE=$(BOOTIMAGE) $@ 
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/fault-xen.c linux-2.6.18-xen.hg/arch/x86_64/mm/fault-xen.c
---- linux-2.6.18/arch/x86_64/mm/fault-xen.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/mm/fault-xen.c     2007-12-23 11:15:00.126153975 +0100
+ hugetlbpage-y = ../../i386/mm/hugetlbpage.o
++ioremap-$(CONFIG_XEN) := ../../i386/mm/ioremap.o
++hypervisor-y := ../../i386/mm/hypervisor.o
+--- linux-2.6.18.8/arch/x86_64/mm/fault-xen.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/mm/fault-xen.c     2008-05-19 00:33:19.101247152 +0300
 @@ -0,0 +1,724 @@
 +/*
 + *  linux/arch/x86-64/mm/fault.c
@@ -54174,9 +54858,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/fault-xen
 +      return 1;
 +}
 +__setup("pagefaulttrace", enable_pagefaulttrace);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.c linux-2.6.18-xen.hg/arch/x86_64/mm/init-xen.c
---- linux-2.6.18/arch/x86_64/mm/init-xen.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/mm/init-xen.c      2007-12-23 11:15:00.126153975 +0100
+--- linux-2.6.18.8/arch/x86_64/mm/init-xen.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/mm/init-xen.c      2008-05-19 00:33:19.105247383 +0300
 @@ -0,0 +1,1205 @@
 +/*
 + *  linux/arch/x86_64/mm/init.c
@@ -54239,6 +54922,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.
 +EXPORT_SYMBOL(__kernel_page_user);
 +#endif
 +
++int after_bootmem;
++
 +extern unsigned long *contiguous_bitmap;
 +
 +static unsigned long dma_reserve __initdata;
@@ -54263,6 +54948,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.
 +      pte_t pte, *ptep;
 +      unsigned long *page = (unsigned long *) init_level4_pgt;
 +
++      BUG_ON(after_bootmem);
++
 +      if (xen_feature(feature))
 +              return;
 +
@@ -54387,7 +55074,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.
 +      printk(KERN_INFO "%lu pages swap cached\n",cached);
 +}
 +
-+int after_bootmem;
 +
 +static __init void *spp_getpage(void)
 +{ 
@@ -54553,11 +55239,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.
 +
 +#define PTE_SIZE PAGE_SIZE
 +
-+static inline void __set_pte(pte_t *dst, pte_t val)
-+{
-+      *dst = val;
-+}
-+
 +static inline int make_readonly(unsigned long paddr)
 +{
 +      extern char __vsyscall_0;
@@ -54626,28 +55307,28 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.
 +              unsigned long pte_phys;
 +              pte_t *pte, *pte_save;
 +
-+              if (address >= end) {
-+                      if (!after_bootmem)
-+                              for (; i < PTRS_PER_PMD; i++, pmd++)
-+                                      set_pmd(pmd, __pmd(0));
++              if (address >= end)
 +                      break;
-+              }
 +              pte = alloc_static_page(&pte_phys);
 +              pte_save = pte;
 +              for (k = 0; k < PTRS_PER_PTE; pte++, k++, address += PTE_SIZE) {
 +                      unsigned long pteval = address | _PAGE_NX | _KERNPG_TABLE;
 +
-+                      if ((address >= end) ||
-+                          ((address >> PAGE_SHIFT) >=
-+                           xen_start_info->nr_pages))
++                      if (address >= (after_bootmem
++                                      ? end
++                                      : xen_start_info->nr_pages << PAGE_SHIFT))
 +                              pteval = 0;
 +                      else if (make_readonly(address))
 +                              pteval &= ~_PAGE_RW;
-+                      __set_pte(pte, __pte(pteval & __supported_pte_mask));
++                      set_pte(pte, __pte(pteval & __supported_pte_mask));
++              }
++              if (!after_bootmem) {
++                      early_make_page_readonly(pte_save, XENFEAT_writable_page_tables);
++                      *pmd = __pmd(pte_phys | _KERNPG_TABLE);
++              } else {
++                      make_page_readonly(pte_save, XENFEAT_writable_page_tables);
++                      set_pmd(pmd, __pmd(pte_phys | _KERNPG_TABLE));
 +              }
-+              pte = pte_save;
-+              early_make_page_readonly(pte, XENFEAT_writable_page_tables);
-+              set_pmd(pmd, __pmd(pte_phys | _KERNPG_TABLE));
 +      }
 +}
 +
@@ -54684,11 +55365,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.
 +                      break;
 +
 +              pmd = alloc_static_page(&pmd_phys);
-+              early_make_page_readonly(pmd, XENFEAT_writable_page_tables);
++
 +              spin_lock(&init_mm.page_table_lock);
-+              set_pud(pud, __pud(pmd_phys | _KERNPG_TABLE));
++              *pud = __pud(pmd_phys | _KERNPG_TABLE);
 +              phys_pmd_init(pmd, paddr, end);
 +              spin_unlock(&init_mm.page_table_lock);
++
++              early_make_page_readonly(pmd, XENFEAT_writable_page_tables);
 +      }
 +      __flush_tlb();
 +} 
@@ -54773,7 +55456,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.
 +
 +      /* Kill mapping of low 1MB. */
 +      while (va < (unsigned long)&_text) {
-+              HYPERVISOR_update_va_mapping(va, __pte_ma(0), 0);
++              if (HYPERVISOR_update_va_mapping(va, __pte_ma(0), 0))
++                      BUG();
 +              va += PAGE_SIZE;
 +      }
 +
@@ -54806,7 +55490,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.
 +              pmd = (pmd_t *)&page[pmd_index(va)];
 +              if (pmd_none(*pmd))
 +                      break;
-+              HYPERVISOR_update_va_mapping(va, __pte_ma(0), 0);
++              if (HYPERVISOR_update_va_mapping(va, __pte_ma(0), 0))
++                      BUG();
 +              va += PAGE_SIZE;
 +      }
 +}
@@ -54859,8 +55544,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.
 +      start = PAGE_ALIGN((unsigned long)_end);
 +      end   = __START_KERNEL_map + (table_end << PAGE_SHIFT);
 +      for (; start < end; start += PAGE_SIZE)
-+              WARN_ON(HYPERVISOR_update_va_mapping(
-+                      start, __pte_ma(0), 0));
++              if (HYPERVISOR_update_va_mapping(start, __pte_ma(0), 0))
++                      BUG();
 +
 +      /* Allocate pte's for initial fixmaps from 'start_pfn' allocator. */
 +      table_end = ~0UL;
@@ -54917,20 +55602,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.
 +              pgd_t *pgd = pgd_offset_k(start);
 +              pud_t *pud;
 +
-+              if (after_bootmem) {
++              if (after_bootmem)
 +                      pud = pud_offset(pgd, start & PGDIR_MASK);
-+                      make_page_readonly(pud, XENFEAT_writable_page_tables);
-+                      pud_phys = __pa(pud);
-+              } else {
++              else
 +                      pud = alloc_static_page(&pud_phys);
-+                      early_make_page_readonly(pud, XENFEAT_writable_page_tables);
-+              }
 +              next = start + PGDIR_SIZE;
 +              if (next > end) 
 +                      next = end; 
 +              phys_pud_init(pud, __pa(start), __pa(next));
-+              if (!after_bootmem)
++              if (!after_bootmem) {
++                      early_make_page_readonly(pud, XENFEAT_writable_page_tables);
 +                      set_pgd(pgd_offset_k(start), mk_kernel_pgd(pud_phys));
++              }
 +      }
 +
 +      if (!after_bootmem) {
@@ -55383,21 +56066,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/init-xen.
 +{
 +      return (addr >= VSYSCALL_START) && (addr < VSYSCALL_END);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/Makefile linux-2.6.18-xen.hg/arch/x86_64/mm/Makefile
---- linux-2.6.18/arch/x86_64/mm/Makefile       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/mm/Makefile        2007-12-23 11:15:00.126153975 +0100
-@@ -7,5 +7,8 @@
- obj-$(CONFIG_NUMA) += numa.o
- obj-$(CONFIG_K8_NUMA) += k8topology.o
- obj-$(CONFIG_ACPI_NUMA) += srat.o
-+obj-$(CONFIG_XEN) += hypervisor.o
- hugetlbpage-y = ../../i386/mm/hugetlbpage.o
-+ioremap-$(CONFIG_XEN) := ../../i386/mm/ioremap.o
-+hypervisor-y := ../../i386/mm/hypervisor.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/pageattr-xen.c linux-2.6.18-xen.hg/arch/x86_64/mm/pageattr-xen.c
---- linux-2.6.18/arch/x86_64/mm/pageattr-xen.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/arch/x86_64/mm/pageattr-xen.c  2007-12-23 11:15:00.129487487 +0100
+--- linux-2.6.18.8/arch/x86_64/mm/pageattr-xen.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/mm/pageattr-xen.c  2008-05-19 00:33:19.553273207 +0300
 @@ -0,0 +1,502 @@
 +/* 
 + * Copyright 2002 Andi Kleen, SuSE Labs. 
@@ -55677,7 +56347,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/pageattr-
 +}
 +#endif        /* CONFIG_XEN */
 +
-+static inline pte_t *lookup_address(unsigned long address) 
++pte_t *lookup_address(unsigned long address) 
 +{ 
 +      pgd_t *pgd = pgd_offset_k(address);
 +      pud_t *pud;
@@ -55901,9 +56571,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/mm/pageattr-
 +
 +EXPORT_SYMBOL(change_page_attr);
 +EXPORT_SYMBOL(global_flush_tlb);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/oprofile/Makefile linux-2.6.18-xen.hg/arch/x86_64/oprofile/Makefile
---- linux-2.6.18/arch/x86_64/oprofile/Makefile 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/oprofile/Makefile  2007-12-23 11:15:00.132820998 +0100
+--- linux-2.6.18.8/arch/x86_64/oprofile/Makefile       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/oprofile/Makefile  2008-05-19 00:33:19.557273438 +0300
 @@ -11,9 +11,15 @@
        oprofilefs.o oprofile_stats.o \
        timer_int.o )
@@ -55922,9 +56591,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/oprofile/Mak
 +endif
 +oprofile-y = $(DRIVER_OBJS) $(XENOPROF_COMMON_OBJS) \
 +           $(addprefix ../../i386/oprofile/, $(OPROFILE-y))
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/pci/Makefile linux-2.6.18-xen.hg/arch/x86_64/pci/Makefile
---- linux-2.6.18/arch/x86_64/pci/Makefile      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/arch/x86_64/pci/Makefile       2007-12-23 11:15:00.132820998 +0100
+--- linux-2.6.18.8/arch/x86_64/pci/Makefile    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/arch/x86_64/pci/Makefile       2008-05-19 00:33:19.557273438 +0300
 @@ -15,8 +15,13 @@
  
  obj-$(CONFIG_NUMA)    += k8-bus.o
@@ -55939,9 +56607,107 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/arch/x86_64/pci/Makefile
  legacy-y += ../../i386/pci/legacy.o
  irq-y    += ../../i386/pci/irq.o
  common-y += ../../i386/pci/common.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/conf.linux-native/00_xen_to_native linux-2.6.18-xen.hg/buildconfigs/conf.linux-native/00_xen_to_native
---- linux-2.6.18/buildconfigs/conf.linux-native/00_xen_to_native       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/buildconfigs/conf.linux-native/00_xen_to_native        2007-12-23 11:15:00.629513738 +0100
+--- linux-2.6.18.8/block/elevator.c    2008-05-19 00:42:33.885229044 +0300
++++ linux-2.6.18-xen.hg/block/elevator.c       2008-05-19 00:33:19.697281508 +0300
+@@ -493,6 +493,16 @@
+       int ret;
+       while ((rq = __elv_next_request(q)) != NULL) {
++              /*
++               * Kill the empty barrier place holder, the driver must
++               * not ever see it.
++               */
++              if (blk_empty_barrier(rq)) {
++                      blkdev_dequeue_request(rq);
++                      end_that_request_chunk(rq, 1, 0);
++                      end_that_request_last(rq, 1);
++                      continue;
++              }
+               if (!(rq->flags & REQ_STARTED)) {
+                       elevator_t *e = q->elevator;
+--- linux-2.6.18.8/block/ll_rw_blk.c   2008-05-19 00:42:33.885229044 +0300
++++ linux-2.6.18-xen.hg/block/ll_rw_blk.c      2008-05-19 00:33:19.701281739 +0300
+@@ -483,9 +483,12 @@
+        * Queue ordered sequence.  As we stack them at the head, we
+        * need to queue in reverse order.  Note that we rely on that
+        * no fs request uses ELEVATOR_INSERT_FRONT and thus no fs
+-       * request gets inbetween ordered sequence.
++       * request gets inbetween ordered sequence. If this request is
++       * an empty barrier, we don't need to do a postflush ever since
++       * there will be no data written between the pre and post flush.
++       * Hence a single flush will suffice.
+        */
+-      if (q->ordered & QUEUE_ORDERED_POSTFLUSH)
++      if ((q->ordered & QUEUE_ORDERED_POSTFLUSH) && !blk_empty_barrier(rq))
+               queue_flush(q, QUEUE_ORDERED_POSTFLUSH);
+       else
+               q->ordseq |= QUEUE_ORDSEQ_POSTFLUSH;
+@@ -2967,7 +2970,7 @@
+ {
+       struct block_device *bdev = bio->bi_bdev;
+-      if (bdev != bdev->bd_contains) {
++      if (bio_sectors(bio) && bdev != bdev->bd_contains) {
+               struct hd_struct *p = bdev->bd_part;
+               const int rw = bio_data_dir(bio);
+@@ -3028,7 +3031,7 @@
+       might_sleep();
+       /* Test device or partition size, when known. */
+       maxsector = bio->bi_bdev->bd_inode->i_size >> 9;
+-      if (maxsector) {
++      if (maxsector && nr_sectors) {
+               sector_t sector = bio->bi_sector;
+               if (maxsector < nr_sectors || maxsector - nr_sectors < sector) {
+@@ -3094,7 +3097,7 @@
+               old_dev = bio->bi_bdev->bd_dev;
+               maxsector = bio->bi_bdev->bd_inode->i_size >> 9;
+-              if (maxsector) {
++              if (maxsector && nr_sectors) {
+                       sector_t sector = bio->bi_sector;
+                       if (maxsector < nr_sectors || maxsector - nr_sectors < sector) {
+@@ -3128,9 +3131,12 @@
+ {
+       int count = bio_sectors(bio);
++      bio->bi_rw |= rw;
++
++      if (!bio_empty_barrier(bio)) {
+       BIO_BUG_ON(!bio->bi_size);
+       BIO_BUG_ON(!bio->bi_io_vec);
+-      bio->bi_rw |= rw;
++
+       if (rw & WRITE)
+               count_vm_events(PGPGOUT, count);
+       else
+@@ -3144,6 +3150,7 @@
+                       (unsigned long long)bio->bi_sector,
+                       bdevname(bio->bi_bdev,b));
+       }
++      }
+       generic_make_request(bio);
+ }
+@@ -3260,6 +3267,13 @@
+       while ((bio = req->bio) != NULL) {
+               int nbytes;
++              /* For an empty barrier request, the low level driver must
++               * store a potential error location in ->sector. We pass
++               * that back up in ->bi_sector
++               */
++              if (blk_empty_barrier(req))
++                      bio->bi_sector = req->sector;
++
+               if (nr_bytes >= bio->bi_size) {
+                       req->bio = bio->bi_next;
+                       nbytes = bio->bi_size;
+--- linux-2.6.18.8/buildconfigs/conf.linux-native/00_xen_to_native     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/buildconfigs/conf.linux-native/00_xen_to_native        2008-05-19 00:33:19.705281969 +0300
 @@ -0,0 +1,86 @@
 +# Linux kernel version: 2.6.16.13-native
 +# Mon May 15 10:59:54 2006
@@ -56029,9 +56795,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/conf.linux-
 +CONFIG_X86_HT=y
 +# CONFIG_X86_NO_TSS is not set
 +# CONFIG_X86_NO_IDT is not set
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/create_config.sh linux-2.6.18-xen.hg/buildconfigs/create_config.sh
---- linux-2.6.18/buildconfigs/create_config.sh 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/buildconfigs/create_config.sh  2007-12-23 11:15:00.629513738 +0100
+--- linux-2.6.18.8/buildconfigs/create_config.sh       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/buildconfigs/create_config.sh  2008-05-19 00:33:19.705281969 +0300
 @@ -0,0 +1,54 @@
 +#!/bin/sh
 +set -e
@@ -56087,14 +56852,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/create_conf
 +        done
 +    fi
 +done
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defconfig_xen0_ia64 linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen0_ia64
---- linux-2.6.18/buildconfigs/linux-defconfig_xen0_ia64        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen0_ia64 2007-12-23 11:15:00.636180766 +0100
-@@ -0,0 +1,1697 @@
+--- linux-2.6.18.8/buildconfigs/linux-defconfig_xen0_ia64      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen0_ia64 2008-05-19 00:33:19.709282200 +0300
+@@ -0,0 +1,1701 @@
 +#
 +# Automatically generated make config: don't edit
 +# Linux kernel version: 2.6.18.8
-+# Mon Dec 17 13:38:33 2007
++# Tue Feb 19 11:20:09 2008
 +#
 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 +
@@ -56744,6 +57508,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_IXGB is not set
 +# CONFIG_S2IO is not set
 +# CONFIG_MYRI10GE is not set
++# CONFIG_SFC is not set
 +
 +#
 +# Token Ring devices
@@ -57763,6 +58528,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_BLKDEV_TAP=y
 +CONFIG_XEN_NETDEV_BACKEND=y
 +# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND is not set
 +# CONFIG_XEN_NETDEV_LOOPBACK is not set
 +CONFIG_XEN_PCIDEV_BACKEND=y
 +# CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
@@ -57774,6 +58541,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_BLKDEV_FRONTEND=y
 +CONFIG_XEN_NETDEV_FRONTEND=y
 +CONFIG_XEN_GRANT_DEV=y
++# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
 +CONFIG_XEN_FRAMEBUFFER=y
 +CONFIG_XEN_KEYBOARD=y
 +# CONFIG_XEN_SCRUB_PAGES is not set
@@ -57788,10 +58556,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_NO_IDLE_HZ=y
 +CONFIG_XEN_BALLOON=y
 +CONFIG_XEN_XENCOMM=y
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defconfig_xen0_x86_32 linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen0_x86_32
---- linux-2.6.18/buildconfigs/linux-defconfig_xen0_x86_32      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen0_x86_32       2007-12-23 11:15:00.659515321 +0100
-@@ -0,0 +1,1451 @@
+--- linux-2.6.18.8/buildconfigs/linux-defconfig_xen0_x86_32    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen0_x86_32       2008-05-19 00:33:19.709282200 +0300
+@@ -0,0 +1,1456 @@
 +#
 +# Automatically generated make config: don't edit
 +# Linux kernel version: 2.6.18.8
@@ -58042,6 +58809,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_PCIDEV_FRONTEND=y
 +# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
 +# CONFIG_PCIEPORTBUS is not set
++# CONFIG_PCI_MSI is not set
 +# CONFIG_PCI_DEBUG is not set
 +CONFIG_ISA_DMA_API=y
 +# CONFIG_SCx200 is not set
@@ -58546,6 +59314,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_IXGB is not set
 +# CONFIG_S2IO is not set
 +# CONFIG_MYRI10GE is not set
++# CONFIG_SFC is not set
 +
 +#
 +# Token Ring devices
@@ -59186,7 +59955,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# CONFIG_CRYPTO_DEV_PADLOCK is not set
 +CONFIG_XEN=y
-+CONFIG_XEN_INTERFACE_VERSION=0x00030206
++CONFIG_XEN_INTERFACE_VERSION=0x00030207
 +
 +#
 +# XEN
@@ -59200,6 +59969,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_BLKDEV_TAP=y
 +CONFIG_XEN_NETDEV_BACKEND=y
 +# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND is not set
 +# CONFIG_XEN_NETDEV_LOOPBACK is not set
 +CONFIG_XEN_PCIDEV_BACKEND=y
 +# CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
@@ -59210,6 +59981,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_TPMDEV_BACKEND=m
 +CONFIG_XEN_BLKDEV_FRONTEND=y
 +CONFIG_XEN_NETDEV_FRONTEND=y
++CONFIG_XEN_GRANT_DEV=y
++# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
 +CONFIG_XEN_SCRUB_PAGES=y
 +CONFIG_XEN_DISABLE_SERIAL=y
 +CONFIG_XEN_SYSFS=y
@@ -59223,7 +59996,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_SMPBOOT=y
 +CONFIG_XEN_BALLOON=y
 +CONFIG_XEN_DEVMEM=y
-+CONFIG_XEN_GRANT_DEV=y
 +
 +#
 +# Library routines
@@ -59243,14 +60015,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_X86_NO_TSS=y
 +CONFIG_X86_NO_IDT=y
 +CONFIG_KTIME_SCALAR=y
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defconfig_xen0_x86_64 linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen0_x86_64
---- linux-2.6.18/buildconfigs/linux-defconfig_xen0_x86_64      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen0_x86_64       2007-12-23 11:15:00.659515321 +0100
-@@ -0,0 +1,1389 @@
+--- linux-2.6.18.8/buildconfigs/linux-defconfig_xen0_x86_64    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen0_x86_64       2008-05-19 00:33:19.709282200 +0300
+@@ -0,0 +1,1388 @@
 +#
 +# Automatically generated make config: don't edit
 +# Linux kernel version: 2.6.18.8
-+# Tue Oct 16 09:32:39 2007
++# Mon Feb 18 10:41:04 2008
 +#
 +CONFIG_X86_64=y
 +CONFIG_64BIT=y
@@ -59275,7 +60046,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Code maturity level options
 +#
 +CONFIG_EXPERIMENTAL=y
-+CONFIG_BROKEN_ON_SMP=y
++CONFIG_LOCK_KERNEL=y
 +CONFIG_INIT_ENV_ARG_LIMIT=32
 +
 +#
@@ -59290,6 +60061,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_TASKSTATS is not set
 +# CONFIG_AUDIT is not set
 +# CONFIG_IKCONFIG is not set
++# CONFIG_CPUSETS is not set
 +# CONFIG_RELAY is not set
 +CONFIG_INITRAMFS_SOURCE=""
 +# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
@@ -59323,6 +60095,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_MODVERSIONS is not set
 +# CONFIG_MODULE_SRCVERSION_ALL is not set
 +CONFIG_KMOD=y
++CONFIG_STOP_MACHINE=y
 +
 +#
 +# Block layer
@@ -59360,16 +60133,17 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_X86_INTERNODE_CACHE_BYTES=128
 +CONFIG_X86_GOOD_APIC=y
 +CONFIG_MICROCODE=y
-+# CONFIG_X86_MSR is not set
-+# CONFIG_X86_CPUID is not set
++CONFIG_X86_MSR=y
++CONFIG_X86_CPUID=y
 +CONFIG_X86_IO_APIC=y
 +CONFIG_X86_XEN_GENAPIC=y
 +CONFIG_X86_LOCAL_APIC=y
 +CONFIG_MTRR=y
-+# CONFIG_SMP is not set
++CONFIG_SMP=y
 +CONFIG_PREEMPT_NONE=y
 +# CONFIG_PREEMPT_VOLUNTARY is not set
 +# CONFIG_PREEMPT is not set
++CONFIG_PREEMPT_BKL=y
 +CONFIG_ARCH_FLATMEM_ENABLE=y
 +CONFIG_SELECT_MEMORY_MODEL=y
 +CONFIG_FLATMEM_MANUAL=y
@@ -59380,6 +60154,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_SPARSEMEM_STATIC is not set
 +CONFIG_SPLIT_PTLOCK_CPUS=4
 +CONFIG_RESOURCES_64BIT=y
++CONFIG_NR_CPUS=8
++CONFIG_HOTPLUG_CPU=y
 +CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 +CONFIG_SWIOTLB=y
 +CONFIG_KEXEC=y
@@ -59391,10 +60167,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_HZ_1000 is not set
 +CONFIG_HZ=100
 +# CONFIG_REORDER is not set
-+CONFIG_K8_NB=y
 +CONFIG_GENERIC_HARDIRQS=y
 +CONFIG_GENERIC_IRQ_PROBE=y
 +CONFIG_ISA_DMA_API=y
++CONFIG_GENERIC_PENDING_IRQ=y
 +
 +#
 +# Power management options
@@ -59403,6 +60179,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_PM_LEGACY=y
 +# CONFIG_PM_DEBUG is not set
 +# CONFIG_SOFTWARE_SUSPEND is not set
++CONFIG_SUSPEND_SMP=y
 +
 +#
 +# ACPI (Advanced Configuration and Power Interface) Support
@@ -59415,20 +60192,22 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_ACPI_BATTERY=m
 +CONFIG_ACPI_BUTTON=m
 +CONFIG_ACPI_VIDEO=m
-+# CONFIG_ACPI_HOTKEY is not set
++CONFIG_ACPI_HOTKEY=m
 +CONFIG_ACPI_FAN=m
 +CONFIG_ACPI_DOCK=m
 +CONFIG_ACPI_PROCESSOR=m
++CONFIG_ACPI_HOTPLUG_CPU=y
 +CONFIG_ACPI_THERMAL=m
 +CONFIG_ACPI_ASUS=m
 +CONFIG_ACPI_IBM=m
 +CONFIG_ACPI_TOSHIBA=m
++# CONFIG_ACPI_CUSTOM_DSDT is not set
 +CONFIG_ACPI_BLACKLIST_YEAR=0
 +# CONFIG_ACPI_DEBUG is not set
 +CONFIG_ACPI_EC=y
 +CONFIG_ACPI_POWER=y
 +CONFIG_ACPI_SYSTEM=y
-+# CONFIG_ACPI_CONTAINER is not set
++CONFIG_ACPI_CONTAINER=m
 +CONFIG_ACPI_PV_SLEEP=y
 +
 +#
@@ -59441,10 +60220,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +CONFIG_PCI=y
 +CONFIG_PCI_DIRECT=y
-+# CONFIG_PCI_MMCONFIG is not set
++CONFIG_PCI_MMCONFIG=y
 +CONFIG_XEN_PCIDEV_FRONTEND=y
 +# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
 +# CONFIG_PCIEPORTBUS is not set
++# CONFIG_PCI_MSI is not set
 +# CONFIG_PCI_DEBUG is not set
 +
 +#
@@ -59461,9 +60241,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Executable file formats / Emulations
 +#
 +CONFIG_BINFMT_ELF=y
-+CONFIG_BINFMT_MISC=y
++# CONFIG_BINFMT_MISC is not set
 +CONFIG_IA32_EMULATION=y
-+# CONFIG_IA32_AOUT is not set
++CONFIG_IA32_AOUT=y
 +CONFIG_COMPAT=y
 +CONFIG_SYSVIPC_COMPAT=y
 +
@@ -59479,6 +60259,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_PACKET=y
 +# CONFIG_PACKET_MMAP is not set
 +CONFIG_UNIX=y
++CONFIG_XFRM=y
++# CONFIG_XFRM_USER is not set
 +# CONFIG_NET_KEY is not set
 +CONFIG_INET=y
 +# CONFIG_IP_MULTICAST is not set
@@ -59497,8 +60279,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_INET_IPCOMP is not set
 +# CONFIG_INET_XFRM_TUNNEL is not set
 +# CONFIG_INET_TUNNEL is not set
-+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++CONFIG_INET_XFRM_MODE_TRANSPORT=y
++CONFIG_INET_XFRM_MODE_TUNNEL=y
 +# CONFIG_INET_DIAG is not set
 +# CONFIG_TCP_CONG_ADVANCED is not set
 +CONFIG_TCP_CONG_BIC=y
@@ -59592,8 +60374,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Generic Driver Options
 +#
-+CONFIG_STANDALONE=y
-+# CONFIG_PREVENT_FIRMWARE_BUILD is not set
++# CONFIG_STANDALONE is not set
++CONFIG_PREVENT_FIRMWARE_BUILD=y
 +# CONFIG_FW_LOADER is not set
 +# CONFIG_DEBUG_DRIVER is not set
 +CONFIG_SYS_HYPERVISOR=y
@@ -59641,7 +60423,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_BLK_DEV_UB is not set
 +CONFIG_BLK_DEV_RAM=y
 +CONFIG_BLK_DEV_RAM_COUNT=16
-+CONFIG_BLK_DEV_RAM_SIZE=16384
++CONFIG_BLK_DEV_RAM_SIZE=4096
 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 +CONFIG_BLK_DEV_INITRD=y
 +# CONFIG_CDROM_PKTCDVD is not set
@@ -59740,7 +60522,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +CONFIG_SCSI_SPI_ATTRS=y
 +# CONFIG_SCSI_FC_ATTRS is not set
-+CONFIG_SCSI_ISCSI_ATTRS=y
++# CONFIG_SCSI_ISCSI_ATTRS is not set
 +# CONFIG_SCSI_SAS_ATTRS is not set
 +
 +#
@@ -59754,7 +60536,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_SCSI_AIC7XXX=y
 +CONFIG_AIC7XXX_CMDS_PER_DEVICE=32
 +CONFIG_AIC7XXX_RESET_DELAY_MS=15000
-+# CONFIG_AIC7XXX_BUILD_FIRMWARE is not set
 +CONFIG_AIC7XXX_DEBUG_ENABLE=y
 +CONFIG_AIC7XXX_DEBUG_MASK=0
 +CONFIG_AIC7XXX_REG_PRETTY_PRINT=y
@@ -59762,7 +60543,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_SCSI_AIC79XX=y
 +CONFIG_AIC79XX_CMDS_PER_DEVICE=32
 +CONFIG_AIC79XX_RESET_DELAY_MS=15000
-+# CONFIG_AIC79XX_BUILD_FIRMWARE is not set
 +# CONFIG_AIC79XX_ENABLE_RD_STRM is not set
 +CONFIG_AIC79XX_DEBUG_ENABLE=y
 +CONFIG_AIC79XX_DEBUG_MASK=0
@@ -59789,8 +60569,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_SCSI_SATA_VIA is not set
 +# CONFIG_SCSI_SATA_VITESSE is not set
 +CONFIG_SCSI_SATA_INTEL_COMBINED=y
-+CONFIG_SCSI_BUSLOGIC=y
-+# CONFIG_SCSI_OMIT_FLASHPOINT is not set
++# CONFIG_SCSI_BUSLOGIC is not set
 +# CONFIG_SCSI_DMX3191D is not set
 +# CONFIG_SCSI_EATA is not set
 +# CONFIG_SCSI_FUTURE_DOMAIN is not set
@@ -59812,21 +60591,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +CONFIG_MD=y
 +CONFIG_BLK_DEV_MD=y
-+CONFIG_MD_LINEAR=y
++# CONFIG_MD_LINEAR is not set
 +CONFIG_MD_RAID0=y
 +CONFIG_MD_RAID1=y
 +# CONFIG_MD_RAID10 is not set
-+CONFIG_MD_RAID456=y
-+# CONFIG_MD_RAID5_RESHAPE is not set
-+CONFIG_MD_MULTIPATH=y
++# CONFIG_MD_RAID456 is not set
++# CONFIG_MD_MULTIPATH is not set
 +# CONFIG_MD_FAULTY is not set
 +CONFIG_BLK_DEV_DM=y
-+CONFIG_DM_CRYPT=y
++# CONFIG_DM_CRYPT is not set
 +CONFIG_DM_SNAPSHOT=y
 +CONFIG_DM_MIRROR=y
 +# CONFIG_DM_ZERO is not set
-+CONFIG_DM_MULTIPATH=y
-+CONFIG_DM_MULTIPATH_EMC=y
++# CONFIG_DM_MULTIPATH is not set
 +
 +#
 +# Fusion MPT device support
@@ -59947,6 +60724,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_IXGB is not set
 +# CONFIG_S2IO is not set
 +# CONFIG_MYRI10GE is not set
++# CONFIG_SFC is not set
 +
 +#
 +# Token Ring devices
@@ -60034,7 +60812,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_VT=y
 +CONFIG_VT_CONSOLE=y
 +CONFIG_HW_CONSOLE=y
-+# CONFIG_VT_HW_CONSOLE_BINDING is not set
++CONFIG_VT_HW_CONSOLE_BINDING=y
 +# CONFIG_SERIAL_NONSTANDARD is not set
 +
 +#
@@ -60060,7 +60838,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_WATCHDOG is not set
 +# CONFIG_HW_RANDOM is not set
 +# CONFIG_NVRAM is not set
-+CONFIG_RTC=y
++# CONFIG_RTC is not set
++# CONFIG_GEN_RTC is not set
 +# CONFIG_DTLK is not set
 +# CONFIG_R3964 is not set
 +# CONFIG_APPLICOM is not set
@@ -60068,16 +60847,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Ftape, the floppy tape device driver
 +#
-+# CONFIG_FTAPE is not set
 +CONFIG_AGP=m
-+CONFIG_AGP_AMD64=m
-+# CONFIG_AGP_INTEL is not set
++# CONFIG_AGP_AMD64 is not set
++CONFIG_AGP_INTEL=m
 +CONFIG_AGP_SIS=m
 +CONFIG_AGP_VIA=m
 +CONFIG_DRM=m
 +CONFIG_DRM_TDFX=m
 +CONFIG_DRM_R128=m
 +CONFIG_DRM_RADEON=m
++CONFIG_DRM_I810=m
++CONFIG_DRM_I830=m
++CONFIG_DRM_I915=m
 +CONFIG_DRM_MGA=m
 +CONFIG_DRM_SIS=m
 +# CONFIG_DRM_VIA is not set
@@ -60276,8 +61057,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# LED devices
 +#
-+CONFIG_NEW_LEDS=y
-+CONFIG_LEDS_CLASS=m
++# CONFIG_NEW_LEDS is not set
 +
 +#
 +# LED drivers
@@ -60286,25 +61066,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# LED Triggers
 +#
-+CONFIG_LEDS_TRIGGERS=y
-+CONFIG_LEDS_TRIGGER_TIMER=y
-+CONFIG_LEDS_TRIGGER_IDE_DISK=y
-+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 +
 +#
 +# InfiniBand support
 +#
-+CONFIG_INFINIBAND=y
-+# CONFIG_INFINIBAND_USER_MAD is not set
-+# CONFIG_INFINIBAND_USER_ACCESS is not set
-+CONFIG_INFINIBAND_ADDR_TRANS=y
-+CONFIG_INFINIBAND_MTHCA=y
-+CONFIG_INFINIBAND_MTHCA_DEBUG=y
-+CONFIG_INFINIBAND_IPOIB=y
-+CONFIG_INFINIBAND_IPOIB_DEBUG=y
-+CONFIG_INFINIBAND_IPOIB_DEBUG_DATA=y
-+CONFIG_INFINIBAND_SRP=y
-+CONFIG_INFINIBAND_ISER=y
++# CONFIG_INFINIBAND is not set
 +
 +#
 +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
@@ -60328,11 +61094,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# RTC drivers
 +#
-+CONFIG_RTC_DRV_DS1553=m
-+CONFIG_RTC_DRV_DS1742=m
++# CONFIG_RTC_DRV_DS1553 is not set
++# CONFIG_RTC_DRV_DS1742 is not set
 +CONFIG_RTC_DRV_M48T86=m
 +CONFIG_RTC_DRV_TEST=m
-+CONFIG_RTC_DRV_V3020=m
++# CONFIG_RTC_DRV_V3020 is not set
 +
 +#
 +# DMA Engine support
@@ -60397,9 +61163,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# DOS/FAT/NT Filesystems
 +#
-+CONFIG_FAT_FS=y
-+CONFIG_MSDOS_FS=y
-+CONFIG_VFAT_FS=y
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++CONFIG_VFAT_FS=m
 +CONFIG_FAT_DEFAULT_CODEPAGE=437
 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 +# CONFIG_NTFS_FS is not set
@@ -60524,7 +61290,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_MAGIC_SYSRQ=y
 +CONFIG_UNUSED_SYMBOLS=y
 +CONFIG_DEBUG_KERNEL=y
-+CONFIG_LOG_BUF_SHIFT=15
++CONFIG_LOG_BUF_SHIFT=14
 +CONFIG_DETECT_SOFTLOCKUP=y
 +# CONFIG_SCHEDSTATS is not set
 +# CONFIG_DEBUG_SLAB is not set
@@ -60538,7 +61304,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 +# CONFIG_DEBUG_KOBJECT is not set
-+# CONFIG_DEBUG_INFO is not set
++CONFIG_DEBUG_INFO=y
 +# CONFIG_DEBUG_FS is not set
 +# CONFIG_DEBUG_VM is not set
 +CONFIG_FRAME_POINTER=y
@@ -60589,7 +61355,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Hardware crypto devices
 +#
 +CONFIG_XEN=y
-+CONFIG_XEN_INTERFACE_VERSION=0x00030206
++CONFIG_XEN_INTERFACE_VERSION=0x00030207
 +
 +#
 +# XEN
@@ -60603,6 +61369,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_BLKDEV_TAP=y
 +CONFIG_XEN_NETDEV_BACKEND=y
 +# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND is not set
 +# CONFIG_XEN_NETDEV_LOOPBACK is not set
 +CONFIG_XEN_PCIDEV_BACKEND=y
 +# CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
@@ -60610,9 +61378,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_XEN_PCIDEV_BACKEND_SLOT is not set
 +# CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER is not set
 +# CONFIG_XEN_PCIDEV_BE_DEBUG is not set
-+CONFIG_XEN_TPMDEV_BACKEND=m
++# CONFIG_XEN_TPMDEV_BACKEND is not set
 +CONFIG_XEN_BLKDEV_FRONTEND=y
 +CONFIG_XEN_NETDEV_FRONTEND=y
++CONFIG_XEN_GRANT_DEV=y
++# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
 +CONFIG_XEN_SCRUB_PAGES=y
 +CONFIG_XEN_DISABLE_SERIAL=y
 +CONFIG_XEN_SYSFS=y
@@ -60623,9 +61393,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_COMPAT=0x030002
 +CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y
 +CONFIG_NO_IDLE_HZ=y
++CONFIG_XEN_SMPBOOT=y
 +CONFIG_XEN_BALLOON=y
 +CONFIG_XEN_DEVMEM=y
-+CONFIG_XEN_GRANT_DEV=y
 +
 +#
 +# Library routines
@@ -60633,17 +61403,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_CRC_CCITT is not set
 +# CONFIG_CRC16 is not set
 +CONFIG_CRC32=y
-+CONFIG_LIBCRC32C=m
++CONFIG_LIBCRC32C=y
 +CONFIG_ZLIB_INFLATE=y
 +CONFIG_PLIST=y
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defconfig_xen_ia64 linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen_ia64
---- linux-2.6.18/buildconfigs/linux-defconfig_xen_ia64 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen_ia64  2007-12-23 11:15:00.709517947 +0100
-@@ -0,0 +1,1697 @@
+--- linux-2.6.18.8/buildconfigs/linux-defconfig_xenU_ia64      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xenU_ia64 2008-05-19 00:33:19.713282430 +0300
+@@ -0,0 +1,1510 @@
 +#
 +# Automatically generated make config: don't edit
 +# Linux kernel version: 2.6.18.8
-+# Mon Dec 17 13:38:29 2007
++# Tue Feb 19 11:20:14 2008
 +#
 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 +
@@ -60661,13 +61430,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_LOCALVERSION_AUTO=y
 +CONFIG_SWAP=y
 +CONFIG_SYSVIPC=y
-+CONFIG_POSIX_MQUEUE=y
++# CONFIG_POSIX_MQUEUE is not set
 +CONFIG_BSD_PROCESS_ACCT=y
 +# CONFIG_BSD_PROCESS_ACCT_V3 is not set
 +# CONFIG_TASKSTATS is not set
 +# CONFIG_AUDIT is not set
-+CONFIG_IKCONFIG=y
-+CONFIG_IKCONFIG_PROC=y
++# CONFIG_IKCONFIG is not set
 +# CONFIG_CPUSETS is not set
 +# CONFIG_RELAY is not set
 +CONFIG_INITRAMFS_SOURCE=""
@@ -60675,8 +61443,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_EMBEDDED is not set
 +CONFIG_SYSCTL=y
 +CONFIG_KALLSYMS=y
-+CONFIG_KALLSYMS_ALL=y
-+CONFIG_KALLSYMS_EXTRA_PASS=y
++# CONFIG_KALLSYMS_ALL is not set
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
 +CONFIG_HOTPLUG=y
 +CONFIG_PRINTK=y
 +CONFIG_BUG=y
@@ -60696,11 +61464,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Loadable module support
 +#
 +CONFIG_MODULES=y
-+CONFIG_MODULE_UNLOAD=y
-+# CONFIG_MODULE_FORCE_UNLOAD is not set
-+CONFIG_MODVERSIONS=y
-+CONFIG_MODULE_SRCVERSION_ALL=y
-+CONFIG_KMOD=y
++# CONFIG_MODULE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++# CONFIG_KMOD is not set
 +CONFIG_STOP_MACHINE=y
 +
 +#
@@ -60741,13 +61508,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
 +CONFIG_DMA_IS_DMA32=y
 +CONFIG_AUDIT_ARCH=y
-+CONFIG_IA64_GENERIC=y
++# CONFIG_IA64_GENERIC is not set
 +# CONFIG_IA64_DIG is not set
 +# CONFIG_IA64_HP_ZX1 is not set
 +# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
 +# CONFIG_IA64_SGI_SN2 is not set
 +# CONFIG_IA64_HP_SIM is not set
-+# CONFIG_IA64_XEN is not set
++CONFIG_IA64_XEN=y
 +# CONFIG_ITANIUM is not set
 +CONFIG_MCKINLEY=y
 +# CONFIG_IA64_PAGE_SIZE_4KB is not set
@@ -60761,9 +61528,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_HZ_1000 is not set
 +CONFIG_HZ=100
 +CONFIG_IA64_L1_CACHE_SHIFT=7
-+CONFIG_IA64_CYCLONE=y
++# CONFIG_IA64_CYCLONE is not set
 +CONFIG_IOSAPIC=y
-+# CONFIG_IA64_SGI_SN_XP is not set
 +CONFIG_FORCE_MAX_ZONEORDER=11
 +CONFIG_SMP=y
 +CONFIG_NR_CPUS=16
@@ -60773,38 +61539,26 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_PERMIT_BSP_REMOVE is not set
 +# CONFIG_PREEMPT is not set
 +CONFIG_SELECT_MEMORY_MODEL=y
-+# CONFIG_FLATMEM_MANUAL is not set
-+CONFIG_DISCONTIGMEM_MANUAL=y
++CONFIG_FLATMEM_MANUAL=y
++# CONFIG_DISCONTIGMEM_MANUAL is not set
 +# CONFIG_SPARSEMEM_MANUAL is not set
-+CONFIG_DISCONTIGMEM=y
++CONFIG_FLATMEM=y
 +CONFIG_FLAT_NODE_MEM_MAP=y
-+CONFIG_NEED_MULTIPLE_NODES=y
 +# CONFIG_SPARSEMEM_STATIC is not set
 +CONFIG_SPLIT_PTLOCK_CPUS=4
-+# CONFIG_MIGRATION is not set
 +CONFIG_RESOURCES_64BIT=y
 +CONFIG_ARCH_SELECT_MEMORY_MODEL=y
 +CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
 +CONFIG_ARCH_FLATMEM_ENABLE=y
 +CONFIG_ARCH_SPARSEMEM_ENABLE=y
-+CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
-+CONFIG_NUMA=y
-+CONFIG_NODES_SHIFT=10
 +CONFIG_VIRTUAL_MEM_MAP=y
 +CONFIG_HOLES_IN_ZONE=y
-+CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
-+CONFIG_HAVE_ARCH_NODEDATA_EXTENSION=y
 +# CONFIG_IA32_SUPPORT is not set
-+# CONFIG_IA64_MCA_RECOVERY is not set
++CONFIG_IA64_MCA_RECOVERY=y
 +CONFIG_PERFMON=y
 +CONFIG_IA64_PALINFO=y
-+CONFIG_SGI_SN=y
-+
-+#
-+# SN Devices
-+#
-+# CONFIG_SGI_IOC3 is not set
-+CONFIG_KEXEC=y
++# CONFIG_KEXEC is not set
++# CONFIG_CRASH_DUMP is not set
 +
 +#
 +# Firmware Drivers
@@ -60831,7 +61585,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_ACPI_PROCESSOR=y
 +CONFIG_ACPI_HOTPLUG_CPU=y
 +CONFIG_ACPI_THERMAL=y
-+CONFIG_ACPI_NUMA=y
 +CONFIG_ACPI_BLACKLIST_YEAR=0
 +# CONFIG_ACPI_DEBUG is not set
 +CONFIG_ACPI_EC=y
@@ -60863,7 +61616,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
 +# CONFIG_HOTPLUG_PCI_CPCI is not set
 +# CONFIG_HOTPLUG_PCI_SHPC is not set
-+# CONFIG_HOTPLUG_PCI_SGI is not set
 +
 +#
 +# PCCARD (PCMCIA/CardBus) support
@@ -60896,8 +61648,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_NET_IPIP is not set
 +# CONFIG_NET_IPGRE is not set
 +# CONFIG_IP_MROUTE is not set
-+CONFIG_ARPD=y
-+CONFIG_SYN_COOKIES=y
++# CONFIG_ARPD is not set
++# CONFIG_SYN_COOKIES is not set
 +# CONFIG_INET_AH is not set
 +# CONFIG_INET_ESP is not set
 +# CONFIG_INET_IPCOMP is not set
@@ -60920,7 +61672,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_NETWORK_SECMARK is not set
 +CONFIG_NETFILTER=y
 +# CONFIG_NETFILTER_DEBUG is not set
-+CONFIG_BRIDGE_NETFILTER=y
 +
 +#
 +# Core Netfilter Configuration
@@ -60936,11 +61687,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_IP_NF_QUEUE is not set
 +
 +#
-+# Bridge: Netfilter Configuration
-+#
-+# CONFIG_BRIDGE_NF_EBTABLES is not set
-+
-+#
 +# DCCP Configuration (EXPERIMENTAL)
 +#
 +# CONFIG_IP_DCCP is not set
@@ -60955,10 +61701,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# CONFIG_TIPC is not set
 +# CONFIG_ATM is not set
-+CONFIG_BRIDGE=y
++# CONFIG_BRIDGE is not set
 +# CONFIG_VLAN_8021Q is not set
 +# CONFIG_DECNET is not set
-+CONFIG_LLC=y
 +# CONFIG_LLC2 is not set
 +# CONFIG_IPX is not set
 +# CONFIG_ATALK is not set
@@ -60990,7 +61735,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +CONFIG_STANDALONE=y
 +CONFIG_PREVENT_FIRMWARE_BUILD=y
-+CONFIG_FW_LOADER=y
++# CONFIG_FW_LOADER is not set
 +# CONFIG_DEBUG_DRIVER is not set
 +CONFIG_SYS_HYPERVISOR=y
 +
@@ -61018,14 +61763,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Block devices
 +#
 +# CONFIG_BLK_CPQ_DA is not set
-+CONFIG_BLK_CPQ_CISS_DA=y
-+# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_CPQ_CISS_DA is not set
 +# CONFIG_BLK_DEV_DAC960 is not set
 +# CONFIG_BLK_DEV_UMEM is not set
 +# CONFIG_BLK_DEV_COW_COMMON is not set
 +CONFIG_BLK_DEV_LOOP=y
-+CONFIG_BLK_DEV_CRYPTOLOOP=y
-+CONFIG_BLK_DEV_NBD=m
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
 +# CONFIG_BLK_DEV_SX8 is not set
 +# CONFIG_BLK_DEV_UB is not set
 +CONFIG_BLK_DEV_RAM=y
@@ -61039,61 +61783,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# ATA/ATAPI/MFM/RLL support
 +#
-+CONFIG_IDE=y
-+CONFIG_IDE_MAX_HWIFS=4
-+CONFIG_BLK_DEV_IDE=y
-+
-+#
-+# Please see Documentation/ide.txt for help/info on IDE drives
-+#
-+# CONFIG_BLK_DEV_IDE_SATA is not set
-+CONFIG_BLK_DEV_IDEDISK=y
-+# CONFIG_IDEDISK_MULTI_MODE is not set
-+CONFIG_BLK_DEV_IDECD=y
-+# CONFIG_BLK_DEV_IDETAPE is not set
-+CONFIG_BLK_DEV_IDEFLOPPY=y
-+CONFIG_BLK_DEV_IDESCSI=y
-+# CONFIG_IDE_TASK_IOCTL is not set
-+
-+#
-+# IDE chipset support/bugfixes
-+#
-+# CONFIG_IDE_GENERIC is not set
-+CONFIG_BLK_DEV_IDEPCI=y
-+# CONFIG_IDEPCI_SHARE_IRQ is not set
-+# CONFIG_BLK_DEV_OFFBOARD is not set
-+CONFIG_BLK_DEV_GENERIC=y
-+# CONFIG_BLK_DEV_OPTI621 is not set
-+CONFIG_BLK_DEV_IDEDMA_PCI=y
-+# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
-+CONFIG_IDEDMA_PCI_AUTO=y
-+# CONFIG_IDEDMA_ONLYDISK is not set
-+# CONFIG_BLK_DEV_AEC62XX is not set
-+# CONFIG_BLK_DEV_ALI15X3 is not set
-+# CONFIG_BLK_DEV_AMD74XX is not set
-+CONFIG_BLK_DEV_CMD64X=y
-+# CONFIG_BLK_DEV_TRIFLEX is not set
-+# CONFIG_BLK_DEV_CY82C693 is not set
-+# CONFIG_BLK_DEV_CS5520 is not set
-+# CONFIG_BLK_DEV_CS5530 is not set
-+# CONFIG_BLK_DEV_HPT34X is not set
-+# CONFIG_BLK_DEV_HPT366 is not set
-+# CONFIG_BLK_DEV_SC1200 is not set
-+CONFIG_BLK_DEV_PIIX=y
-+# CONFIG_BLK_DEV_IT821X is not set
-+# CONFIG_BLK_DEV_NS87415 is not set
-+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
-+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
-+# CONFIG_BLK_DEV_SVWKS is not set
-+# CONFIG_BLK_DEV_SIIMAGE is not set
-+# CONFIG_BLK_DEV_SLC90E66 is not set
-+# CONFIG_BLK_DEV_TRM290 is not set
-+# CONFIG_BLK_DEV_VIA82CXXX is not set
-+# CONFIG_IDE_ARM is not set
-+CONFIG_BLK_DEV_IDEDMA=y
-+# CONFIG_IDEDMA_IVB is not set
-+CONFIG_IDEDMA_AUTO=y
-+# CONFIG_BLK_DEV_HD is not set
++# CONFIG_IDE is not set
 +
 +#
 +# SCSI device support
@@ -61124,7 +61814,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# SCSI Transport Attributes
 +#
 +CONFIG_SCSI_SPI_ATTRS=y
-+CONFIG_SCSI_FC_ATTRS=y
++# CONFIG_SCSI_FC_ATTRS is not set
 +# CONFIG_SCSI_ISCSI_ATTRS is not set
 +CONFIG_SCSI_SAS_ATTRS=y
 +
@@ -61165,15 +61855,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Multi-device support (RAID and LVM)
 +#
-+CONFIG_MD=y
-+# CONFIG_BLK_DEV_MD is not set
-+CONFIG_BLK_DEV_DM=y
-+CONFIG_DM_CRYPT=m
-+CONFIG_DM_SNAPSHOT=y
-+CONFIG_DM_MIRROR=m
-+CONFIG_DM_ZERO=m
-+CONFIG_DM_MULTIPATH=m
-+CONFIG_DM_MULTIPATH_EMC=m
++# CONFIG_MD is not set
 +
 +#
 +# Fusion MPT device support
@@ -61202,20 +61884,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_DUMMY=y
 +# CONFIG_BONDING is not set
 +# CONFIG_EQUALIZER is not set
-+CONFIG_TUN=y
++# CONFIG_TUN is not set
 +
 +#
 +# ARCnet devices
 +#
-+CONFIG_ARCNET=y
-+# CONFIG_ARCNET_1201 is not set
-+# CONFIG_ARCNET_1051 is not set
-+# CONFIG_ARCNET_RAW is not set
-+# CONFIG_ARCNET_CAP is not set
-+# CONFIG_ARCNET_COM90xx is not set
-+# CONFIG_ARCNET_COM90xxIO is not set
-+# CONFIG_ARCNET_RIM_I is not set
-+# CONFIG_ARCNET_COM20020 is not set
++# CONFIG_ARCNET is not set
 +
 +#
 +# PHY device support
@@ -61254,7 +61928,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_B44 is not set
 +# CONFIG_FORCEDETH is not set
 +# CONFIG_DGRS is not set
-+CONFIG_EEPRO100=y
++# CONFIG_EEPRO100 is not set
 +CONFIG_E100=y
 +# CONFIG_FEALNX is not set
 +# CONFIG_NATSEMI is not set
@@ -61293,6 +61967,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_IXGB is not set
 +# CONFIG_S2IO is not set
 +# CONFIG_MYRI10GE is not set
++# CONFIG_SFC is not set
 +
 +#
 +# Token Ring devices
@@ -61314,26 +61989,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_SLIP is not set
 +# CONFIG_NET_FC is not set
 +# CONFIG_SHAPER is not set
-+CONFIG_NETCONSOLE=y
-+CONFIG_NETPOLL=y
-+# CONFIG_NETPOLL_RX is not set
-+# CONFIG_NETPOLL_TRAP is not set
-+CONFIG_NET_POLL_CONTROLLER=y
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
 +
 +#
 +# ISDN subsystem
 +#
-+CONFIG_ISDN=m
-+
-+#
-+# Old ISDN4Linux
-+#
-+# CONFIG_ISDN_I4L is not set
-+
-+#
-+# CAPI subsystem
-+#
-+# CONFIG_ISDN_CAPI is not set
++# CONFIG_ISDN is not set
 +
 +#
 +# Telephony Support
@@ -61360,16 +62023,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Input Device Drivers
 +#
-+CONFIG_INPUT_KEYBOARD=y
-+CONFIG_KEYBOARD_ATKBD=y
-+# CONFIG_KEYBOARD_SUNKBD is not set
-+# CONFIG_KEYBOARD_LKKBD is not set
-+# CONFIG_KEYBOARD_XTKBD is not set
-+# CONFIG_KEYBOARD_NEWTON is not set
-+CONFIG_INPUT_MOUSE=y
-+CONFIG_MOUSE_PS2=y
-+# CONFIG_MOUSE_SERIAL is not set
-+# CONFIG_MOUSE_VSXXXAA is not set
++# CONFIG_INPUT_KEYBOARD is not set
++# CONFIG_INPUT_MOUSE is not set
 +# CONFIG_INPUT_JOYSTICK is not set
 +# CONFIG_INPUT_TOUCHSCREEN is not set
 +# CONFIG_INPUT_MISC is not set
@@ -61378,16 +62033,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Hardware I/O ports
 +#
 +CONFIG_SERIO=y
-+CONFIG_SERIO_I8042=y
++# CONFIG_SERIO_I8042 is not set
 +# CONFIG_SERIO_SERPORT is not set
 +# CONFIG_SERIO_PCIPS2 is not set
-+CONFIG_SERIO_LIBPS2=y
 +# CONFIG_SERIO_RAW is not set
-+CONFIG_GAMEPORT=y
-+# CONFIG_GAMEPORT_NS558 is not set
-+# CONFIG_GAMEPORT_L4 is not set
-+# CONFIG_GAMEPORT_EMU10K1 is not set
-+# CONFIG_GAMEPORT_FM801 is not set
++# CONFIG_GAMEPORT is not set
 +
 +#
 +# Character devices
@@ -61396,32 +62046,26 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_VT_CONSOLE=y
 +CONFIG_HW_CONSOLE=y
 +# CONFIG_VT_HW_CONSOLE_BINDING is not set
-+CONFIG_SERIAL_NONSTANDARD=y
-+# CONFIG_COMPUTONE is not set
-+# CONFIG_ROCKETPORT is not set
-+# CONFIG_CYCLADES is not set
-+# CONFIG_DIGIEPCA is not set
-+# CONFIG_MOXA_INTELLIO is not set
-+# CONFIG_MOXA_SMARTIO is not set
-+# CONFIG_ISI is not set
-+# CONFIG_SYNCLINKMP is not set
-+# CONFIG_SYNCLINK_GT is not set
-+# CONFIG_N_HDLC is not set
-+# CONFIG_SPECIALIX is not set
-+# CONFIG_SX is not set
-+# CONFIG_RIO is not set
-+# CONFIG_STALDRV is not set
-+# CONFIG_SGI_SNSC is not set
-+# CONFIG_SGI_TIOCX is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
 +
 +#
 +# Serial drivers
 +#
++CONFIG_SERIAL_8250=y
++CONFIG_SERIAL_8250_CONSOLE=y
++CONFIG_SERIAL_8250_PCI=y
++CONFIG_SERIAL_8250_NR_UARTS=8
++CONFIG_SERIAL_8250_RUNTIME_UARTS=4
++CONFIG_SERIAL_8250_EXTENDED=y
++CONFIG_SERIAL_8250_SHARE_IRQ=y
++# CONFIG_SERIAL_8250_DETECT_IRQ is not set
++# CONFIG_SERIAL_8250_RSA is not set
 +
 +#
 +# Non-8250 serial port support
 +#
-+# CONFIG_SERIAL_SGI_L1_CONSOLE is not set
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
 +# CONFIG_SERIAL_JSM is not set
 +CONFIG_UNIX98_PTYS=y
 +CONFIG_LEGACY_PTYS=y
@@ -61448,13 +62092,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_AGP=y
 +# CONFIG_AGP_SIS is not set
 +# CONFIG_AGP_VIA is not set
-+CONFIG_AGP_I460=y
-+# CONFIG_AGP_HP_ZX1 is not set
-+# CONFIG_AGP_SGI_TIOCA is not set
 +CONFIG_DRM=y
 +# CONFIG_DRM_TDFX is not set
 +# CONFIG_DRM_R128 is not set
-+# CONFIG_DRM_RADEON is not set
++CONFIG_DRM_RADEON=y
 +# CONFIG_DRM_MGA is not set
 +# CONFIG_DRM_SIS is not set
 +# CONFIG_DRM_VIA is not set
@@ -61462,7 +62103,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_RAW_DRIVER is not set
 +# CONFIG_HPET is not set
 +# CONFIG_HANGCHECK_TIMER is not set
-+# CONFIG_MMTIMER is not set
 +
 +#
 +# TPM devices
@@ -61731,7 +62371,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_SND_HWDEP=y
 +CONFIG_SND_RAWMIDI=y
 +CONFIG_SND_SEQUENCER=y
-+CONFIG_SND_SEQ_DUMMY=y
++# CONFIG_SND_SEQ_DUMMY is not set
 +CONFIG_SND_OSSEMUL=y
 +CONFIG_SND_MIXER_OSS=y
 +CONFIG_SND_PCM_OSS=y
@@ -61750,11 +62390,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_SND_OPL3_LIB=y
 +CONFIG_SND_AC97_CODEC=y
 +CONFIG_SND_AC97_BUS=y
-+CONFIG_SND_DUMMY=y
-+CONFIG_SND_VIRMIDI=y
++# CONFIG_SND_DUMMY is not set
++# CONFIG_SND_VIRMIDI is not set
 +# CONFIG_SND_MTPAV is not set
-+CONFIG_SND_SERIAL_U16550=y
-+CONFIG_SND_MPU401=y
++# CONFIG_SND_SERIAL_U16550 is not set
++# CONFIG_SND_MPU401 is not set
 +
 +#
 +# PCI devices
@@ -61762,7 +62402,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_SND_AD1889 is not set
 +# CONFIG_SND_ALS300 is not set
 +# CONFIG_SND_ALI5451 is not set
-+CONFIG_SND_ATIIXP=y
++# CONFIG_SND_ATIIXP is not set
 +# CONFIG_SND_ATIIXP_MODEM is not set
 +# CONFIG_SND_AU8810 is not set
 +# CONFIG_SND_AU8820 is not set
@@ -61773,18 +62413,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_SND_CMIPCI is not set
 +# CONFIG_SND_CS4281 is not set
 +# CONFIG_SND_CS46XX is not set
-+# CONFIG_SND_DARLA20 is not set
-+# CONFIG_SND_GINA20 is not set
-+# CONFIG_SND_LAYLA20 is not set
-+# CONFIG_SND_DARLA24 is not set
-+# CONFIG_SND_GINA24 is not set
-+# CONFIG_SND_LAYLA24 is not set
-+# CONFIG_SND_MONA is not set
-+# CONFIG_SND_MIA is not set
-+# CONFIG_SND_ECHO3G is not set
-+# CONFIG_SND_INDIGO is not set
-+# CONFIG_SND_INDIGOIO is not set
-+# CONFIG_SND_INDIGODJ is not set
 +# CONFIG_SND_EMU10K1 is not set
 +# CONFIG_SND_EMU10K1X is not set
 +# CONFIG_SND_ENS1370 is not set
@@ -61805,7 +62433,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_SND_MIXART is not set
 +# CONFIG_SND_NM256 is not set
 +# CONFIG_SND_PCXHR is not set
-+# CONFIG_SND_RIPTIDE is not set
 +# CONFIG_SND_RME32 is not set
 +# CONFIG_SND_RME96 is not set
 +# CONFIG_SND_RME9652 is not set
@@ -61824,16 +62451,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Open Sound System
 +#
-+CONFIG_SOUND_PRIME=y
-+# CONFIG_OSS_OBSOLETE_DRIVER is not set
-+# CONFIG_SOUND_BT878 is not set
-+# CONFIG_SOUND_ES1371 is not set
-+# CONFIG_SOUND_ICH is not set
-+# CONFIG_SOUND_TRIDENT is not set
-+# CONFIG_SOUND_MSNDCLAS is not set
-+# CONFIG_SOUND_MSNDPIN is not set
-+# CONFIG_SOUND_VIA82CXXX is not set
-+# CONFIG_SOUND_TVMIXER is not set
++# CONFIG_SOUND_PRIME is not set
 +
 +#
 +# USB support
@@ -61847,7 +62465,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Miscellaneous USB options
 +#
-+CONFIG_USB_DEVICEFS=y
++# CONFIG_USB_DEVICEFS is not set
 +CONFIG_USB_BANDWIDTH=y
 +# CONFIG_USB_DYNAMIC_MINORS is not set
 +# CONFIG_USB_SUSPEND is not set
@@ -61884,7 +62502,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_USB_STORAGE_DEBUG is not set
 +# CONFIG_USB_STORAGE_DATAFAB is not set
 +# CONFIG_USB_STORAGE_FREECOM is not set
-+# CONFIG_USB_STORAGE_ISD200 is not set
 +# CONFIG_USB_STORAGE_DPCM is not set
 +# CONFIG_USB_STORAGE_USBAT is not set
 +# CONFIG_USB_STORAGE_SDDR09 is not set
@@ -61957,7 +62574,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_USB_APPLEDISPLAY is not set
 +# CONFIG_USB_SISUSBVGA is not set
 +# CONFIG_USB_LD is not set
-+# CONFIG_USB_TEST is not set
 +
 +#
 +# USB DSL modem support
@@ -62018,29 +62634,20 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +CONFIG_EXT2_FS=y
 +CONFIG_EXT2_FS_XATTR=y
-+CONFIG_EXT2_FS_POSIX_ACL=y
-+CONFIG_EXT2_FS_SECURITY=y
++# CONFIG_EXT2_FS_POSIX_ACL is not set
++# CONFIG_EXT2_FS_SECURITY is not set
 +# CONFIG_EXT2_FS_XIP is not set
 +CONFIG_EXT3_FS=y
 +CONFIG_EXT3_FS_XATTR=y
-+CONFIG_EXT3_FS_POSIX_ACL=y
-+CONFIG_EXT3_FS_SECURITY=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
 +CONFIG_JBD=y
 +# CONFIG_JBD_DEBUG is not set
 +CONFIG_FS_MBCACHE=y
-+CONFIG_REISERFS_FS=y
-+# CONFIG_REISERFS_CHECK is not set
-+# CONFIG_REISERFS_PROC_INFO is not set
-+CONFIG_REISERFS_FS_XATTR=y
-+CONFIG_REISERFS_FS_POSIX_ACL=y
-+CONFIG_REISERFS_FS_SECURITY=y
++# CONFIG_REISERFS_FS is not set
 +# CONFIG_JFS_FS is not set
-+CONFIG_FS_POSIX_ACL=y
-+CONFIG_XFS_FS=y
-+# CONFIG_XFS_QUOTA is not set
-+# CONFIG_XFS_SECURITY is not set
-+# CONFIG_XFS_POSIX_ACL is not set
-+# CONFIG_XFS_RT is not set
++# CONFIG_FS_POSIX_ACL is not set
++# CONFIG_XFS_FS is not set
 +# CONFIG_OCFS2_FS is not set
 +# CONFIG_MINIX_FS is not set
 +# CONFIG_ROMFS_FS is not set
@@ -62049,7 +62656,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_QUOTA is not set
 +CONFIG_DNOTIFY=y
 +CONFIG_AUTOFS_FS=y
-+CONFIG_AUTOFS4_FS=y
++# CONFIG_AUTOFS4_FS is not set
 +# CONFIG_FUSE_FS is not set
 +
 +#
@@ -62076,7 +62683,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +CONFIG_PROC_FS=y
 +CONFIG_PROC_KCORE=y
-+CONFIG_PROC_IOMEM_MACHINE=y
 +CONFIG_SYSFS=y
 +CONFIG_TMPFS=y
 +# CONFIG_HUGETLB_PAGE is not set
@@ -62107,12 +62713,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_NFS_V3=y
 +# CONFIG_NFS_V3_ACL is not set
 +CONFIG_NFS_V4=y
-+CONFIG_NFS_DIRECTIO=y
++# CONFIG_NFS_DIRECTIO is not set
 +CONFIG_NFSD=y
 +CONFIG_NFSD_V3=y
 +# CONFIG_NFSD_V3_ACL is not set
-+CONFIG_NFSD_V4=y
-+CONFIG_NFSD_TCP=y
++# CONFIG_NFSD_V4 is not set
++# CONFIG_NFSD_TCP is not set
 +CONFIG_ROOT_NFS=y
 +CONFIG_LOCKD=y
 +CONFIG_LOCKD_V4=y
@@ -62122,15 +62728,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_SUNRPC_GSS=y
 +CONFIG_RPCSEC_GSS_KRB5=y
 +# CONFIG_RPCSEC_GSS_SPKM3 is not set
-+CONFIG_SMB_FS=y
-+CONFIG_SMB_NLS_DEFAULT=y
-+CONFIG_SMB_NLS_REMOTE="cp437"
-+CONFIG_CIFS=y
-+# CONFIG_CIFS_STATS is not set
-+# CONFIG_CIFS_WEAK_PW_HASH is not set
-+# CONFIG_CIFS_XATTR is not set
-+# CONFIG_CIFS_DEBUG2 is not set
-+# CONFIG_CIFS_EXPERIMENTAL is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
 +# CONFIG_NCP_FS is not set
 +# CONFIG_CODA_FS is not set
 +# CONFIG_AFS_FS is not set
@@ -62151,7 +62750,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_SOLARIS_X86_PARTITION is not set
 +# CONFIG_UNIXWARE_DISKLABEL is not set
 +# CONFIG_LDM_PARTITION is not set
-+CONFIG_SGI_PARTITION=y
++# CONFIG_SGI_PARTITION is not set
 +# CONFIG_ULTRIX_PARTITION is not set
 +# CONFIG_SUN_PARTITION is not set
 +# CONFIG_KARMA_PARTITION is not set
@@ -62215,13 +62814,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_IRQ_PER_CPU=y
 +
 +#
-+# HP Simulator drivers
-+#
-+# CONFIG_HP_SIMETH is not set
-+# CONFIG_HP_SIMSERIAL is not set
-+# CONFIG_HP_SIMSCSI is not set
-+
-+#
 +# Instrumentation Support
 +#
 +# CONFIG_PROFILING is not set
@@ -62234,7 +62826,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_MAGIC_SYSRQ=y
 +CONFIG_UNUSED_SYMBOLS=y
 +CONFIG_DEBUG_KERNEL=y
-+CONFIG_LOG_BUF_SHIFT=20
++CONFIG_LOG_BUF_SHIFT=17
 +CONFIG_DETECT_SOFTLOCKUP=y
 +# CONFIG_SCHEDSTATS is not set
 +# CONFIG_DEBUG_SLAB is not set
@@ -62303,30 +62895,20 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# XEN
 +#
-+CONFIG_XEN_PRIVILEGED_GUEST=y
-+# CONFIG_XEN_UNPRIVILEGED_GUEST is not set
++# CONFIG_XEN_PRIVILEGED_GUEST is not set
++CONFIG_XEN_UNPRIVILEGED_GUEST=y
 +CONFIG_XEN_PRIVCMD=y
 +CONFIG_XEN_XENBUS_DEV=y
-+CONFIG_XEN_BACKEND=y
-+CONFIG_XEN_BLKDEV_BACKEND=y
-+CONFIG_XEN_BLKDEV_TAP=y
-+CONFIG_XEN_NETDEV_BACKEND=y
-+# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
-+# CONFIG_XEN_NETDEV_LOOPBACK is not set
-+CONFIG_XEN_PCIDEV_BACKEND=y
-+# CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
-+# CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
-+# CONFIG_XEN_PCIDEV_BACKEND_SLOT is not set
-+CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER=y
-+# CONFIG_XEN_PCIDEV_BE_DEBUG is not set
-+CONFIG_XEN_TPMDEV_BACKEND=m
++# CONFIG_XEN_BACKEND is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
 +CONFIG_XEN_BLKDEV_FRONTEND=y
 +CONFIG_XEN_NETDEV_FRONTEND=y
-+CONFIG_XEN_GRANT_DEV=y
++# CONFIG_XEN_GRANT_DEV is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
 +CONFIG_XEN_FRAMEBUFFER=y
 +CONFIG_XEN_KEYBOARD=y
 +# CONFIG_XEN_SCRUB_PAGES is not set
-+CONFIG_XEN_DISABLE_SERIAL=y
++# CONFIG_XEN_DISABLE_SERIAL is not set
 +CONFIG_XEN_SYSFS=y
 +CONFIG_XEN_COMPAT_030002_AND_LATER=y
 +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set
@@ -62337,15 +62919,25 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_NO_IDLE_HZ=y
 +CONFIG_XEN_BALLOON=y
 +CONFIG_XEN_XENCOMM=y
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defconfig_xenU_ia64 linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xenU_ia64
---- linux-2.6.18/buildconfigs/linux-defconfig_xenU_ia64        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xenU_ia64 2007-12-23 11:15:00.662848831 +0100
-@@ -0,0 +1,1507 @@
+--- linux-2.6.18.8/buildconfigs/linux-defconfig_xenU_x86_32    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xenU_x86_32       2008-05-19 00:33:19.713282430 +0300
+@@ -0,0 +1,952 @@
 +#
 +# Automatically generated make config: don't edit
 +# Linux kernel version: 2.6.18.8
-+# Mon Dec 17 13:38:36 2007
++# Tue Oct 16 09:31:29 2007
 +#
++CONFIG_X86_32=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_SEMAPHORE_SLEEPERS=y
++CONFIG_X86=y
++CONFIG_MMU=y
++CONFIG_GENERIC_ISA_DMA=y
++CONFIG_GENERIC_IOMAP=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_ARCH_MAY_HAVE_PC_FDC=y
++CONFIG_DMI=y
 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 +
 +#
@@ -62359,20 +62951,20 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# General setup
 +#
 +CONFIG_LOCALVERSION=""
-+CONFIG_LOCALVERSION_AUTO=y
++# CONFIG_LOCALVERSION_AUTO is not set
 +CONFIG_SWAP=y
 +CONFIG_SYSVIPC=y
 +# CONFIG_POSIX_MQUEUE is not set
-+CONFIG_BSD_PROCESS_ACCT=y
-+# CONFIG_BSD_PROCESS_ACCT_V3 is not set
++# CONFIG_BSD_PROCESS_ACCT is not set
 +# CONFIG_TASKSTATS is not set
 +# CONFIG_AUDIT is not set
 +# CONFIG_IKCONFIG is not set
 +# CONFIG_CPUSETS is not set
 +# CONFIG_RELAY is not set
 +CONFIG_INITRAMFS_SOURCE=""
-+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
 +# CONFIG_EMBEDDED is not set
++CONFIG_UID16=y
 +CONFIG_SYSCTL=y
 +CONFIG_KALLSYMS=y
 +# CONFIG_KALLSYMS_ALL is not set
@@ -62396,16 +62988,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Loadable module support
 +#
 +CONFIG_MODULES=y
-+# CONFIG_MODULE_UNLOAD is not set
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
 +# CONFIG_MODVERSIONS is not set
 +# CONFIG_MODULE_SRCVERSION_ALL is not set
-+# CONFIG_KMOD is not set
++CONFIG_KMOD=y
 +CONFIG_STOP_MACHINE=y
 +
 +#
 +# Block layer
 +#
++# CONFIG_LBD is not set
 +# CONFIG_BLK_DEV_IO_TRACE is not set
++CONFIG_LSF=y
 +
 +#
 +# IO Schedulers
@@ -62423,53 +63018,77 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Processor type and features
 +#
-+CONFIG_IA64=y
-+CONFIG_64BIT=y
-+CONFIG_MMU=y
-+CONFIG_SWIOTLB=y
++CONFIG_SMP=y
++# CONFIG_X86_PC is not set
++CONFIG_X86_XEN=y
++# CONFIG_X86_ELAN is not set
++# CONFIG_X86_VOYAGER is not set
++# CONFIG_X86_NUMAQ is not set
++# CONFIG_X86_SUMMIT is not set
++# CONFIG_X86_BIGSMP is not set
++# CONFIG_X86_VISWS is not set
++# CONFIG_X86_GENERICARCH is not set
++# CONFIG_X86_ES7000 is not set
++# CONFIG_M386 is not set
++# CONFIG_M486 is not set
++# CONFIG_M586 is not set
++# CONFIG_M586TSC is not set
++# CONFIG_M586MMX is not set
++CONFIG_M686=y
++# CONFIG_MPENTIUMII is not set
++# CONFIG_MPENTIUMIII is not set
++# CONFIG_MPENTIUMM is not set
++# CONFIG_MPENTIUM4 is not set
++# CONFIG_MK6 is not set
++# CONFIG_MK7 is not set
++# CONFIG_MK8 is not set
++# CONFIG_MCRUSOE is not set
++# CONFIG_MEFFICEON is not set
++# CONFIG_MWINCHIPC6 is not set
++# CONFIG_MWINCHIP2 is not set
++# CONFIG_MWINCHIP3D is not set
++# CONFIG_MGEODEGX1 is not set
++# CONFIG_MGEODE_LX is not set
++# CONFIG_MCYRIXIII is not set
++# CONFIG_MVIAC3_2 is not set
++# CONFIG_X86_GENERIC is not set
++CONFIG_X86_CMPXCHG=y
++CONFIG_X86_XADD=y
++CONFIG_X86_L1_CACHE_SHIFT=5
 +CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-+CONFIG_GENERIC_FIND_NEXT_BIT=y
 +CONFIG_GENERIC_CALIBRATE_DELAY=y
-+CONFIG_TIME_INTERPOLATION=y
-+CONFIG_DMI=y
-+CONFIG_EFI=y
-+CONFIG_GENERIC_IOMAP=y
-+CONFIG_XEN=y
-+CONFIG_XEN_IA64_EXPOSE_P2M=y
-+CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR=y
-+CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
-+CONFIG_DMA_IS_DMA32=y
-+CONFIG_AUDIT_ARCH=y
-+# CONFIG_IA64_GENERIC is not set
-+# CONFIG_IA64_DIG is not set
-+# CONFIG_IA64_HP_ZX1 is not set
-+# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
-+# CONFIG_IA64_SGI_SN2 is not set
-+# CONFIG_IA64_HP_SIM is not set
-+CONFIG_IA64_XEN=y
-+# CONFIG_ITANIUM is not set
-+CONFIG_MCKINLEY=y
-+# CONFIG_IA64_PAGE_SIZE_4KB is not set
-+# CONFIG_IA64_PAGE_SIZE_8KB is not set
-+CONFIG_IA64_PAGE_SIZE_16KB=y
-+# CONFIG_IA64_PAGE_SIZE_64KB is not set
-+CONFIG_PGTABLE_3=y
-+# CONFIG_PGTABLE_4 is not set
-+CONFIG_HZ_100=y
-+# CONFIG_HZ_250 is not set
-+# CONFIG_HZ_1000 is not set
-+CONFIG_HZ=100
-+CONFIG_IA64_L1_CACHE_SHIFT=7
-+# CONFIG_IA64_CYCLONE is not set
-+CONFIG_IOSAPIC=y
-+CONFIG_FORCE_MAX_ZONEORDER=11
-+CONFIG_SMP=y
-+CONFIG_NR_CPUS=16
-+CONFIG_HOTPLUG_CPU=y
-+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-+# CONFIG_SCHED_SMT is not set
-+# CONFIG_PERMIT_BSP_REMOVE is not set
++CONFIG_X86_PPRO_FENCE=y
++CONFIG_X86_WP_WORKS_OK=y
++CONFIG_X86_INVLPG=y
++CONFIG_X86_BSWAP=y
++CONFIG_X86_POPAD_OK=y
++CONFIG_X86_CMPXCHG64=y
++CONFIG_X86_GOOD_APIC=y
++CONFIG_X86_USE_PPRO_CHECKSUM=y
++CONFIG_NR_CPUS=8
++CONFIG_PREEMPT_NONE=y
++# CONFIG_PREEMPT_VOLUNTARY is not set
 +# CONFIG_PREEMPT is not set
++CONFIG_PREEMPT_BKL=y
++CONFIG_VM86=y
++# CONFIG_TOSHIBA is not set
++# CONFIG_I8K is not set
++# CONFIG_X86_REBOOTFIXUPS is not set
++# CONFIG_X86_MSR is not set
++CONFIG_X86_CPUID=y
++CONFIG_SWIOTLB=y
++
++#
++# Firmware Drivers
++#
++# CONFIG_EDD is not set
++# CONFIG_DELL_RBU is not set
++# CONFIG_DCDBAS is not set
++# CONFIG_NOHIGHMEM is not set
++CONFIG_HIGHMEM4G=y
++# CONFIG_HIGHMEM64G is not set
++CONFIG_PAGE_OFFSET=0xC0000000
++CONFIG_HIGHMEM=y
 +CONFIG_SELECT_MEMORY_MODEL=y
 +CONFIG_FLATMEM_MANUAL=y
 +# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -62479,80 +63098,40 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_SPARSEMEM_STATIC is not set
 +CONFIG_SPLIT_PTLOCK_CPUS=4
 +CONFIG_RESOURCES_64BIT=y
-+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
-+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
-+CONFIG_ARCH_FLATMEM_ENABLE=y
-+CONFIG_ARCH_SPARSEMEM_ENABLE=y
-+CONFIG_VIRTUAL_MEM_MAP=y
-+CONFIG_HOLES_IN_ZONE=y
-+# CONFIG_IA32_SUPPORT is not set
-+CONFIG_IA64_MCA_RECOVERY=y
-+CONFIG_PERFMON=y
-+CONFIG_IA64_PALINFO=y
-+# CONFIG_KEXEC is not set
++# CONFIG_HIGHPTE is not set
++# CONFIG_REGPARM is not set
++CONFIG_SECCOMP=y
++CONFIG_HZ_100=y
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
 +# CONFIG_CRASH_DUMP is not set
++CONFIG_PHYSICAL_START=0x100000
++CONFIG_HOTPLUG_CPU=y
++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
 +
 +#
-+# Firmware Drivers
-+#
-+CONFIG_EFI_VARS=y
-+CONFIG_EFI_PCDP=y
-+CONFIG_BINFMT_ELF=y
-+CONFIG_BINFMT_MISC=y
-+
-+#
-+# Power management and ACPI
-+#
-+CONFIG_PM=y
-+CONFIG_PM_LEGACY=y
-+# CONFIG_PM_DEBUG is not set
-+
-+#
-+# ACPI (Advanced Configuration and Power Interface) Support
-+#
-+CONFIG_ACPI=y
-+CONFIG_ACPI_BUTTON=y
-+CONFIG_ACPI_FAN=y
-+# CONFIG_ACPI_DOCK is not set
-+CONFIG_ACPI_PROCESSOR=y
-+CONFIG_ACPI_HOTPLUG_CPU=y
-+CONFIG_ACPI_THERMAL=y
-+CONFIG_ACPI_BLACKLIST_YEAR=0
-+# CONFIG_ACPI_DEBUG is not set
-+CONFIG_ACPI_EC=y
-+CONFIG_ACPI_POWER=y
-+CONFIG_ACPI_SYSTEM=y
-+CONFIG_ACPI_CONTAINER=y
-+
-+#
-+# CPU Frequency scaling
++# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
 +#
-+# CONFIG_CPU_FREQ is not set
++# CONFIG_PCI is not set
++CONFIG_ISA_DMA_API=y
++# CONFIG_SCx200 is not set
 +
 +#
-+# Bus options (PCI, PCMCIA)
++# PCCARD (PCMCIA/CardBus) support
 +#
-+CONFIG_PCI=y
-+CONFIG_PCI_DOMAINS=y
-+CONFIG_XEN_PCIDEV_FRONTEND=y
-+# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
-+# CONFIG_PCIEPORTBUS is not set
-+# CONFIG_PCI_DEBUG is not set
++# CONFIG_PCCARD is not set
 +
 +#
 +# PCI Hotplug Support
 +#
-+CONFIG_HOTPLUG_PCI=y
-+# CONFIG_HOTPLUG_PCI_FAKE is not set
-+CONFIG_HOTPLUG_PCI_ACPI=y
-+# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
-+# CONFIG_HOTPLUG_PCI_CPCI is not set
-+# CONFIG_HOTPLUG_PCI_SHPC is not set
 +
 +#
-+# PCCARD (PCMCIA/CardBus) support
++# Executable file formats
 +#
-+# CONFIG_PCCARD is not set
++CONFIG_BINFMT_ELF=y
++# CONFIG_BINFMT_AOUT is not set
++# CONFIG_BINFMT_MISC is not set
 +
 +#
 +# Networking
@@ -62570,16 +63149,15 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_XFRM_USER is not set
 +# CONFIG_NET_KEY is not set
 +CONFIG_INET=y
-+CONFIG_IP_MULTICAST=y
++# CONFIG_IP_MULTICAST is not set
 +# CONFIG_IP_ADVANCED_ROUTER is not set
 +CONFIG_IP_FIB_HASH=y
 +CONFIG_IP_PNP=y
-+CONFIG_IP_PNP_DHCP=y
++# CONFIG_IP_PNP_DHCP is not set
 +# CONFIG_IP_PNP_BOOTP is not set
 +# CONFIG_IP_PNP_RARP is not set
 +# CONFIG_NET_IPIP is not set
 +# CONFIG_NET_IPGRE is not set
-+# CONFIG_IP_MROUTE is not set
 +# CONFIG_ARPD is not set
 +# CONFIG_SYN_COOKIES is not set
 +# CONFIG_INET_AH is not set
@@ -62589,34 +63167,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_INET_TUNNEL is not set
 +CONFIG_INET_XFRM_MODE_TRANSPORT=y
 +CONFIG_INET_XFRM_MODE_TUNNEL=y
-+CONFIG_INET_DIAG=y
-+CONFIG_INET_TCP_DIAG=y
++# CONFIG_INET_DIAG is not set
 +# CONFIG_TCP_CONG_ADVANCED is not set
 +CONFIG_TCP_CONG_BIC=y
-+
-+#
-+# IP: Virtual Server Configuration
-+#
-+# CONFIG_IP_VS is not set
 +# CONFIG_IPV6 is not set
 +# CONFIG_INET6_XFRM_TUNNEL is not set
 +# CONFIG_INET6_TUNNEL is not set
 +# CONFIG_NETWORK_SECMARK is not set
-+CONFIG_NETFILTER=y
-+# CONFIG_NETFILTER_DEBUG is not set
-+
-+#
-+# Core Netfilter Configuration
-+#
-+# CONFIG_NETFILTER_NETLINK is not set
-+# CONFIG_NF_CONNTRACK is not set
-+# CONFIG_NETFILTER_XTABLES is not set
-+
-+#
-+# IP: Netfilter Configuration
-+#
-+# CONFIG_IP_NF_CONNTRACK is not set
-+# CONFIG_IP_NF_QUEUE is not set
++# CONFIG_NETFILTER is not set
 +
 +#
 +# DCCP Configuration (EXPERIMENTAL)
@@ -62689,21 +63247,15 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Plug and Play support
 +#
-+# CONFIG_PNP is not set
 +
 +#
 +# Block devices
 +#
-+# CONFIG_BLK_CPQ_DA is not set
-+# CONFIG_BLK_CPQ_CISS_DA is not set
-+# CONFIG_BLK_DEV_DAC960 is not set
-+# CONFIG_BLK_DEV_UMEM is not set
++# CONFIG_BLK_DEV_FD is not set
 +# CONFIG_BLK_DEV_COW_COMMON is not set
-+CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_LOOP=m
 +# CONFIG_BLK_DEV_CRYPTOLOOP is not set
-+# CONFIG_BLK_DEV_NBD is not set
-+# CONFIG_BLK_DEV_SX8 is not set
-+# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_NBD=m
 +CONFIG_BLK_DEV_RAM=y
 +CONFIG_BLK_DEV_RAM_COUNT=16
 +CONFIG_BLK_DEV_RAM_SIZE=4096
@@ -62721,67 +63273,39 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# SCSI device support
 +#
 +# CONFIG_RAID_ATTRS is not set
-+CONFIG_SCSI=y
++CONFIG_SCSI=m
 +CONFIG_SCSI_PROC_FS=y
 +
 +#
 +# SCSI support type (disk, tape, CD-ROM)
 +#
-+CONFIG_BLK_DEV_SD=y
-+CONFIG_CHR_DEV_ST=y
-+CONFIG_CHR_DEV_OSST=y
-+CONFIG_BLK_DEV_SR=y
-+CONFIG_BLK_DEV_SR_VENDOR=y
-+CONFIG_CHR_DEV_SG=y
++CONFIG_BLK_DEV_SD=m
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
 +# CONFIG_CHR_DEV_SCH is not set
 +
 +#
 +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 +#
-+CONFIG_SCSI_MULTI_LUN=y
-+CONFIG_SCSI_CONSTANTS=y
-+CONFIG_SCSI_LOGGING=y
++# CONFIG_SCSI_MULTI_LUN is not set
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
 +
 +#
 +# SCSI Transport Attributes
 +#
-+CONFIG_SCSI_SPI_ATTRS=y
++# CONFIG_SCSI_SPI_ATTRS is not set
 +# CONFIG_SCSI_FC_ATTRS is not set
 +# CONFIG_SCSI_ISCSI_ATTRS is not set
-+CONFIG_SCSI_SAS_ATTRS=y
++# CONFIG_SCSI_SAS_ATTRS is not set
 +
 +#
 +# SCSI low-level drivers
 +#
 +# CONFIG_ISCSI_TCP is not set
-+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
-+# CONFIG_SCSI_3W_9XXX is not set
-+# CONFIG_SCSI_ACARD is not set
-+# CONFIG_SCSI_AACRAID is not set
-+# CONFIG_SCSI_AIC7XXX is not set
-+# CONFIG_SCSI_AIC7XXX_OLD is not set
-+# CONFIG_SCSI_AIC79XX is not set
-+# CONFIG_MEGARAID_NEWGEN is not set
-+# CONFIG_MEGARAID_LEGACY is not set
-+# CONFIG_MEGARAID_SAS is not set
 +# CONFIG_SCSI_SATA is not set
-+# CONFIG_SCSI_HPTIOP is not set
-+# CONFIG_SCSI_DMX3191D is not set
-+# CONFIG_SCSI_FUTURE_DOMAIN is not set
-+# CONFIG_SCSI_IPS is not set
-+# CONFIG_SCSI_INITIO is not set
-+# CONFIG_SCSI_INIA100 is not set
-+CONFIG_SCSI_SYM53C8XX_2=y
-+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
-+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
-+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
-+CONFIG_SCSI_SYM53C8XX_MMIO=y
-+# CONFIG_SCSI_IPR is not set
-+CONFIG_SCSI_QLOGIC_1280=y
-+# CONFIG_SCSI_QLA_FC is not set
-+# CONFIG_SCSI_LPFC is not set
-+# CONFIG_SCSI_DC395x is not set
-+# CONFIG_SCSI_DC390T is not set
 +# CONFIG_SCSI_DEBUG is not set
 +
 +#
@@ -62792,118 +63316,45 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Fusion MPT device support
 +#
-+CONFIG_FUSION=y
-+CONFIG_FUSION_SPI=y
-+# CONFIG_FUSION_FC is not set
-+CONFIG_FUSION_SAS=y
-+CONFIG_FUSION_MAX_SGE=128
-+# CONFIG_FUSION_CTL is not set
++# CONFIG_FUSION is not set
 +
 +#
 +# IEEE 1394 (FireWire) support
 +#
-+# CONFIG_IEEE1394 is not set
 +
 +#
 +# I2O device support
 +#
-+# CONFIG_I2O is not set
 +
 +#
 +# Network device support
 +#
 +CONFIG_NETDEVICES=y
-+CONFIG_DUMMY=y
++# CONFIG_DUMMY is not set
 +# CONFIG_BONDING is not set
 +# CONFIG_EQUALIZER is not set
 +# CONFIG_TUN is not set
 +
 +#
-+# ARCnet devices
-+#
-+# CONFIG_ARCNET is not set
-+
-+#
 +# PHY device support
 +#
-+# CONFIG_PHYLIB is not set
 +
 +#
 +# Ethernet (10 or 100Mbit)
 +#
-+CONFIG_NET_ETHERNET=y
-+CONFIG_MII=y
-+# CONFIG_HAPPYMEAL is not set
-+# CONFIG_SUNGEM is not set
-+# CONFIG_CASSINI is not set
-+# CONFIG_NET_VENDOR_3COM is not set
-+
-+#
-+# Tulip family network device support
-+#
-+CONFIG_NET_TULIP=y
-+# CONFIG_DE2104X is not set
-+CONFIG_TULIP=y
-+CONFIG_TULIP_MWI=y
-+CONFIG_TULIP_MMIO=y
-+CONFIG_TULIP_NAPI=y
-+CONFIG_TULIP_NAPI_HW_MITIGATION=y
-+# CONFIG_DE4X5 is not set
-+# CONFIG_WINBOND_840 is not set
-+# CONFIG_DM9102 is not set
-+# CONFIG_ULI526X is not set
-+# CONFIG_HP100 is not set
-+CONFIG_NET_PCI=y
-+# CONFIG_PCNET32 is not set
-+# CONFIG_AMD8111_ETH is not set
-+# CONFIG_ADAPTEC_STARFIRE is not set
-+# CONFIG_B44 is not set
-+# CONFIG_FORCEDETH is not set
-+# CONFIG_DGRS is not set
-+# CONFIG_EEPRO100 is not set
-+CONFIG_E100=y
-+# CONFIG_FEALNX is not set
-+# CONFIG_NATSEMI is not set
-+# CONFIG_NE2K_PCI is not set
-+# CONFIG_8139CP is not set
-+# CONFIG_8139TOO is not set
-+# CONFIG_SIS900 is not set
-+# CONFIG_EPIC100 is not set
-+# CONFIG_SUNDANCE is not set
-+# CONFIG_VIA_RHINE is not set
++# CONFIG_NET_ETHERNET is not set
 +
 +#
 +# Ethernet (1000 Mbit)
 +#
-+# CONFIG_ACENIC is not set
-+# CONFIG_DL2K is not set
-+CONFIG_E1000=y
-+# CONFIG_E1000_NAPI is not set
-+# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
-+# CONFIG_NS83820 is not set
-+# CONFIG_HAMACHI is not set
-+# CONFIG_YELLOWFIN is not set
-+# CONFIG_R8169 is not set
-+# CONFIG_SIS190 is not set
-+# CONFIG_SKGE is not set
-+# CONFIG_SKY2 is not set
-+# CONFIG_SK98LIN is not set
-+# CONFIG_VIA_VELOCITY is not set
-+CONFIG_TIGON3=y
-+# CONFIG_BNX2 is not set
 +
 +#
 +# Ethernet (10000 Mbit)
 +#
-+# CONFIG_CHELSIO_T1 is not set
-+# CONFIG_IXGB is not set
-+# CONFIG_S2IO is not set
-+# CONFIG_MYRI10GE is not set
 +
 +#
 +# Token Ring devices
 +#
-+# CONFIG_TR is not set
 +
 +#
 +# Wireless LAN (non-hamradio)
@@ -62914,11 +63365,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Wan interfaces
 +#
 +# CONFIG_WAN is not set
-+# CONFIG_FDDI is not set
-+# CONFIG_HIPPI is not set
 +# CONFIG_PPP is not set
 +# CONFIG_SLIP is not set
-+# CONFIG_NET_FC is not set
 +# CONFIG_SHAPER is not set
 +# CONFIG_NETCONSOLE is not set
 +# CONFIG_NETPOLL is not set
@@ -62943,18 +63391,23 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Userland interfaces
 +#
 +CONFIG_INPUT_MOUSEDEV=y
-+CONFIG_INPUT_MOUSEDEV_PSAUX=y
++# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
 +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-+CONFIG_INPUT_JOYDEV=y
++# CONFIG_INPUT_JOYDEV is not set
 +# CONFIG_INPUT_TSDEV is not set
-+CONFIG_INPUT_EVDEV=y
++# CONFIG_INPUT_EVDEV is not set
 +# CONFIG_INPUT_EVBUG is not set
 +
 +#
 +# Input Device Drivers
 +#
-+# CONFIG_INPUT_KEYBOARD is not set
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ATKBD is not set
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_NEWTON is not set
 +# CONFIG_INPUT_MOUSE is not set
 +# CONFIG_INPUT_JOYSTICK is not set
 +# CONFIG_INPUT_TOUCHSCREEN is not set
@@ -62964,9 +63417,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Hardware I/O ports
 +#
 +CONFIG_SERIO=y
-+# CONFIG_SERIO_I8042 is not set
-+# CONFIG_SERIO_SERPORT is not set
-+# CONFIG_SERIO_PCIPS2 is not set
++CONFIG_SERIO_I8042=y
++CONFIG_SERIO_SERPORT=y
++# CONFIG_SERIO_CT82C710 is not set
 +# CONFIG_SERIO_RAW is not set
 +# CONFIG_GAMEPORT is not set
 +
@@ -62982,22 +63435,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Serial drivers
 +#
-+CONFIG_SERIAL_8250=y
-+CONFIG_SERIAL_8250_CONSOLE=y
-+CONFIG_SERIAL_8250_PCI=y
-+CONFIG_SERIAL_8250_NR_UARTS=8
-+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-+CONFIG_SERIAL_8250_EXTENDED=y
-+CONFIG_SERIAL_8250_SHARE_IRQ=y
-+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
-+# CONFIG_SERIAL_8250_RSA is not set
 +
 +#
 +# Non-8250 serial port support
 +#
-+CONFIG_SERIAL_CORE=y
-+CONFIG_SERIAL_CORE_CONSOLE=y
-+# CONFIG_SERIAL_JSM is not set
 +CONFIG_UNIX98_PTYS=y
 +CONFIG_LEGACY_PTYS=y
 +CONFIG_LEGACY_PTY_COUNT=256
@@ -63011,28 +63452,22 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Watchdog Cards
 +#
 +# CONFIG_WATCHDOG is not set
-+# CONFIG_HW_RANDOM is not set
-+CONFIG_EFI_RTC=y
++CONFIG_HW_RANDOM=y
++CONFIG_HW_RANDOM_VIA=y
++# CONFIG_NVRAM is not set
++# CONFIG_RTC is not set
++# CONFIG_GEN_RTC is not set
 +# CONFIG_DTLK is not set
 +# CONFIG_R3964 is not set
-+# CONFIG_APPLICOM is not set
 +
 +#
 +# Ftape, the floppy tape device driver
 +#
-+CONFIG_AGP=y
-+# CONFIG_AGP_SIS is not set
-+# CONFIG_AGP_VIA is not set
-+CONFIG_DRM=y
-+# CONFIG_DRM_TDFX is not set
-+# CONFIG_DRM_R128 is not set
-+CONFIG_DRM_RADEON=y
-+# CONFIG_DRM_MGA is not set
-+# CONFIG_DRM_SIS is not set
-+# CONFIG_DRM_VIA is not set
-+# CONFIG_DRM_SAVAGE is not set
++# CONFIG_MWAVE is not set
++# CONFIG_PC8736x_GPIO is not set
++# CONFIG_NSC_GPIO is not set
++# CONFIG_CS5535_GPIO is not set
 +# CONFIG_RAW_DRIVER is not set
-+# CONFIG_HPET is not set
 +# CONFIG_HANGCHECK_TIMER is not set
 +
 +#
@@ -63044,55 +63479,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# I2C support
 +#
-+CONFIG_I2C=y
-+CONFIG_I2C_CHARDEV=y
-+
-+#
-+# I2C Algorithms
-+#
-+CONFIG_I2C_ALGOBIT=y
-+CONFIG_I2C_ALGOPCF=y
-+# CONFIG_I2C_ALGOPCA is not set
-+
-+#
-+# I2C Hardware Bus support
-+#
-+# CONFIG_I2C_ALI1535 is not set
-+# CONFIG_I2C_ALI1563 is not set
-+# CONFIG_I2C_ALI15X3 is not set
-+# CONFIG_I2C_AMD756 is not set
-+# CONFIG_I2C_AMD8111 is not set
-+# CONFIG_I2C_I801 is not set
-+# CONFIG_I2C_I810 is not set
-+# CONFIG_I2C_PIIX4 is not set
-+# CONFIG_I2C_NFORCE2 is not set
-+# CONFIG_I2C_OCORES is not set
-+# CONFIG_I2C_PARPORT_LIGHT is not set
-+# CONFIG_I2C_PROSAVAGE is not set
-+# CONFIG_I2C_SAVAGE4 is not set
-+# CONFIG_I2C_SIS5595 is not set
-+# CONFIG_I2C_SIS630 is not set
-+# CONFIG_I2C_SIS96X is not set
-+# CONFIG_I2C_STUB is not set
-+# CONFIG_I2C_VIA is not set
-+# CONFIG_I2C_VIAPRO is not set
-+# CONFIG_I2C_VOODOO3 is not set
-+# CONFIG_I2C_PCA_ISA is not set
-+
-+#
-+# Miscellaneous I2C Chip support
-+#
-+# CONFIG_SENSORS_DS1337 is not set
-+# CONFIG_SENSORS_DS1374 is not set
-+# CONFIG_SENSORS_EEPROM is not set
-+# CONFIG_SENSORS_PCF8574 is not set
-+# CONFIG_SENSORS_PCA9539 is not set
-+# CONFIG_SENSORS_PCF8591 is not set
-+# CONFIG_SENSORS_MAX6875 is not set
-+# CONFIG_I2C_DEBUG_CORE is not set
-+# CONFIG_I2C_DEBUG_ALGO is not set
-+# CONFIG_I2C_DEBUG_BUS is not set
-+# CONFIG_I2C_DEBUG_CHIP is not set
++# CONFIG_I2C is not set
 +
 +#
 +# SPI support
@@ -63107,48 +63494,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Hardware Monitoring support
 +#
-+CONFIG_HWMON=y
++# CONFIG_HWMON is not set
 +# CONFIG_HWMON_VID is not set
-+# CONFIG_SENSORS_ABITUGURU is not set
-+# CONFIG_SENSORS_ADM1021 is not set
-+# CONFIG_SENSORS_ADM1025 is not set
-+# CONFIG_SENSORS_ADM1026 is not set
-+# CONFIG_SENSORS_ADM1031 is not set
-+# CONFIG_SENSORS_ADM9240 is not set
-+# CONFIG_SENSORS_ASB100 is not set
-+# CONFIG_SENSORS_ATXP1 is not set
-+# CONFIG_SENSORS_DS1621 is not set
-+# CONFIG_SENSORS_F71805F is not set
-+# CONFIG_SENSORS_FSCHER is not set
-+# CONFIG_SENSORS_FSCPOS is not set
-+# CONFIG_SENSORS_GL518SM is not set
-+# CONFIG_SENSORS_GL520SM is not set
-+# CONFIG_SENSORS_IT87 is not set
-+# CONFIG_SENSORS_LM63 is not set
-+# CONFIG_SENSORS_LM75 is not set
-+# CONFIG_SENSORS_LM77 is not set
-+# CONFIG_SENSORS_LM78 is not set
-+# CONFIG_SENSORS_LM80 is not set
-+# CONFIG_SENSORS_LM83 is not set
-+# CONFIG_SENSORS_LM85 is not set
-+# CONFIG_SENSORS_LM87 is not set
-+# CONFIG_SENSORS_LM90 is not set
-+# CONFIG_SENSORS_LM92 is not set
-+# CONFIG_SENSORS_MAX1619 is not set
-+# CONFIG_SENSORS_PC87360 is not set
-+# CONFIG_SENSORS_SIS5595 is not set
-+# CONFIG_SENSORS_SMSC47M1 is not set
-+# CONFIG_SENSORS_SMSC47M192 is not set
-+# CONFIG_SENSORS_SMSC47B397 is not set
-+# CONFIG_SENSORS_VIA686A is not set
-+# CONFIG_SENSORS_VT8231 is not set
-+# CONFIG_SENSORS_W83781D is not set
-+# CONFIG_SENSORS_W83791D is not set
-+# CONFIG_SENSORS_W83792D is not set
-+# CONFIG_SENSORS_W83L785TS is not set
-+# CONFIG_SENSORS_W83627HF is not set
-+# CONFIG_SENSORS_W83627EHF is not set
-+# CONFIG_HWMON_DEBUG_CHIP is not set
 +
 +#
 +# Misc devices
@@ -63157,115 +63504,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Multimedia devices
 +#
-+CONFIG_VIDEO_DEV=y
-+CONFIG_VIDEO_V4L1=y
-+CONFIG_VIDEO_V4L1_COMPAT=y
-+CONFIG_VIDEO_V4L2=y
-+
-+#
-+# Video Capture Adapters
-+#
-+
-+#
-+# Video Capture Adapters
-+#
-+# CONFIG_VIDEO_ADV_DEBUG is not set
-+# CONFIG_VIDEO_VIVI is not set
-+# CONFIG_VIDEO_BT848 is not set
-+# CONFIG_VIDEO_CPIA is not set
-+# CONFIG_VIDEO_CPIA2 is not set
-+# CONFIG_VIDEO_SAA5246A is not set
-+# CONFIG_VIDEO_SAA5249 is not set
-+# CONFIG_TUNER_3036 is not set
-+# CONFIG_VIDEO_STRADIS is not set
-+# CONFIG_VIDEO_ZORAN is not set
-+# CONFIG_VIDEO_SAA7134 is not set
-+# CONFIG_VIDEO_MXB is not set
-+# CONFIG_VIDEO_DPC is not set
-+# CONFIG_VIDEO_HEXIUM_ORION is not set
-+# CONFIG_VIDEO_HEXIUM_GEMINI is not set
-+# CONFIG_VIDEO_CX88 is not set
-+
-+#
-+# Encoders and Decoders
-+#
-+# CONFIG_VIDEO_MSP3400 is not set
-+# CONFIG_VIDEO_CS53L32A is not set
-+# CONFIG_VIDEO_TLV320AIC23B is not set
-+# CONFIG_VIDEO_WM8775 is not set
-+# CONFIG_VIDEO_WM8739 is not set
-+# CONFIG_VIDEO_CX2341X is not set
-+# CONFIG_VIDEO_CX25840 is not set
-+# CONFIG_VIDEO_SAA711X is not set
-+# CONFIG_VIDEO_SAA7127 is not set
-+# CONFIG_VIDEO_UPD64031A is not set
-+# CONFIG_VIDEO_UPD64083 is not set
-+
-+#
-+# V4L USB devices
-+#
-+# CONFIG_VIDEO_PVRUSB2 is not set
-+# CONFIG_VIDEO_EM28XX is not set
-+# CONFIG_USB_VICAM is not set
-+# CONFIG_USB_IBMCAM is not set
-+# CONFIG_USB_KONICAWC is not set
-+# CONFIG_USB_QUICKCAM_MESSENGER is not set
-+# CONFIG_USB_ET61X251 is not set
-+# CONFIG_VIDEO_OVCAMCHIP is not set
-+# CONFIG_USB_W9968CF is not set
-+# CONFIG_USB_OV511 is not set
-+# CONFIG_USB_SE401 is not set
-+# CONFIG_USB_SN9C102 is not set
-+# CONFIG_USB_STV680 is not set
-+# CONFIG_USB_ZC0301 is not set
-+# CONFIG_USB_PWC is not set
-+
-+#
-+# Radio Adapters
-+#
-+# CONFIG_RADIO_GEMTEK_PCI is not set
-+# CONFIG_RADIO_MAXIRADIO is not set
-+# CONFIG_RADIO_MAESTRO is not set
-+# CONFIG_USB_DSBR is not set
++# CONFIG_VIDEO_DEV is not set
 +
 +#
 +# Digital Video Broadcasting Devices
 +#
 +# CONFIG_DVB is not set
-+# CONFIG_USB_DABUSB is not set
 +
 +#
 +# Graphics support
 +#
 +CONFIG_FIRMWARE_EDID=y
-+CONFIG_FB=y
-+CONFIG_FB_CFB_FILLRECT=y
-+CONFIG_FB_CFB_COPYAREA=y
-+CONFIG_FB_CFB_IMAGEBLIT=y
-+# CONFIG_FB_MACMODES is not set
-+# CONFIG_FB_BACKLIGHT is not set
-+CONFIG_FB_MODE_HELPERS=y
-+# CONFIG_FB_TILEBLITTING is not set
-+# CONFIG_FB_CIRRUS is not set
-+# CONFIG_FB_PM2 is not set
-+# CONFIG_FB_CYBER2000 is not set
-+# CONFIG_FB_ASILIANT is not set
-+# CONFIG_FB_IMSTT is not set
-+# CONFIG_FB_S1D13XXX is not set
-+# CONFIG_FB_NVIDIA is not set
-+# CONFIG_FB_RIVA is not set
-+# CONFIG_FB_MATROX is not set
-+# CONFIG_FB_RADEON is not set
-+# CONFIG_FB_ATY128 is not set
-+# CONFIG_FB_ATY is not set
-+# CONFIG_FB_SAVAGE is not set
-+# CONFIG_FB_SIS is not set
-+# CONFIG_FB_NEOMAGIC is not set
-+# CONFIG_FB_KYRO is not set
-+# CONFIG_FB_3DFX is not set
-+# CONFIG_FB_VOODOO1 is not set
-+# CONFIG_FB_TRIDENT is not set
-+# CONFIG_FB_VIRTUAL is not set
++# CONFIG_FB is not set
 +
 +#
 +# Console display driver support
@@ -63273,244 +63523,25 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_VGA_CONSOLE=y
 +# CONFIG_VGACON_SOFT_SCROLLBACK is not set
 +CONFIG_DUMMY_CONSOLE=y
-+CONFIG_FRAMEBUFFER_CONSOLE=y
-+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
-+# CONFIG_FONTS is not set
-+CONFIG_FONT_8x8=y
-+CONFIG_FONT_8x16=y
-+
-+#
-+# Logo configuration
-+#
-+CONFIG_LOGO=y
-+# CONFIG_LOGO_LINUX_MONO is not set
-+# CONFIG_LOGO_LINUX_VGA16 is not set
-+CONFIG_LOGO_LINUX_CLUT224=y
 +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 +
 +#
 +# Sound
 +#
-+CONFIG_SOUND=y
-+
-+#
-+# Advanced Linux Sound Architecture
-+#
-+CONFIG_SND=y
-+CONFIG_SND_TIMER=y
-+CONFIG_SND_PCM=y
-+CONFIG_SND_HWDEP=y
-+CONFIG_SND_RAWMIDI=y
-+CONFIG_SND_SEQUENCER=y
-+# CONFIG_SND_SEQ_DUMMY is not set
-+CONFIG_SND_OSSEMUL=y
-+CONFIG_SND_MIXER_OSS=y
-+CONFIG_SND_PCM_OSS=y
-+CONFIG_SND_PCM_OSS_PLUGINS=y
-+CONFIG_SND_SEQUENCER_OSS=y
-+# CONFIG_SND_DYNAMIC_MINORS is not set
-+CONFIG_SND_SUPPORT_OLD_API=y
-+CONFIG_SND_VERBOSE_PROCFS=y
-+# CONFIG_SND_VERBOSE_PRINTK is not set
-+# CONFIG_SND_DEBUG is not set
-+
-+#
-+# Generic devices
-+#
-+CONFIG_SND_MPU401_UART=y
-+CONFIG_SND_OPL3_LIB=y
-+CONFIG_SND_AC97_CODEC=y
-+CONFIG_SND_AC97_BUS=y
-+# CONFIG_SND_DUMMY is not set
-+# CONFIG_SND_VIRMIDI is not set
-+# CONFIG_SND_MTPAV is not set
-+# CONFIG_SND_SERIAL_U16550 is not set
-+# CONFIG_SND_MPU401 is not set
-+
-+#
-+# PCI devices
-+#
-+# CONFIG_SND_AD1889 is not set
-+# CONFIG_SND_ALS300 is not set
-+# CONFIG_SND_ALI5451 is not set
-+# CONFIG_SND_ATIIXP is not set
-+# CONFIG_SND_ATIIXP_MODEM is not set
-+# CONFIG_SND_AU8810 is not set
-+# CONFIG_SND_AU8820 is not set
-+# CONFIG_SND_AU8830 is not set
-+# CONFIG_SND_AZT3328 is not set
-+# CONFIG_SND_BT87X is not set
-+# CONFIG_SND_CA0106 is not set
-+# CONFIG_SND_CMIPCI is not set
-+# CONFIG_SND_CS4281 is not set
-+# CONFIG_SND_CS46XX is not set
-+# CONFIG_SND_EMU10K1 is not set
-+# CONFIG_SND_EMU10K1X is not set
-+# CONFIG_SND_ENS1370 is not set
-+# CONFIG_SND_ENS1371 is not set
-+# CONFIG_SND_ES1938 is not set
-+# CONFIG_SND_ES1968 is not set
-+CONFIG_SND_FM801=y
-+# CONFIG_SND_FM801_TEA575X_BOOL is not set
-+# CONFIG_SND_HDA_INTEL is not set
-+# CONFIG_SND_HDSP is not set
-+# CONFIG_SND_HDSPM is not set
-+# CONFIG_SND_ICE1712 is not set
-+# CONFIG_SND_ICE1724 is not set
-+# CONFIG_SND_INTEL8X0 is not set
-+# CONFIG_SND_INTEL8X0M is not set
-+# CONFIG_SND_KORG1212 is not set
-+# CONFIG_SND_MAESTRO3 is not set
-+# CONFIG_SND_MIXART is not set
-+# CONFIG_SND_NM256 is not set
-+# CONFIG_SND_PCXHR is not set
-+# CONFIG_SND_RME32 is not set
-+# CONFIG_SND_RME96 is not set
-+# CONFIG_SND_RME9652 is not set
-+# CONFIG_SND_SONICVIBES is not set
-+# CONFIG_SND_TRIDENT is not set
-+# CONFIG_SND_VIA82XX is not set
-+# CONFIG_SND_VIA82XX_MODEM is not set
-+# CONFIG_SND_VX222 is not set
-+# CONFIG_SND_YMFPCI is not set
-+
-+#
-+# USB devices
-+#
-+# CONFIG_SND_USB_AUDIO is not set
-+
-+#
-+# Open Sound System
-+#
-+# CONFIG_SOUND_PRIME is not set
++# CONFIG_SOUND is not set
 +
 +#
 +# USB support
 +#
-+CONFIG_USB_ARCH_HAS_HCD=y
-+CONFIG_USB_ARCH_HAS_OHCI=y
-+CONFIG_USB_ARCH_HAS_EHCI=y
-+CONFIG_USB=y
-+# CONFIG_USB_DEBUG is not set
-+
-+#
-+# Miscellaneous USB options
-+#
-+# CONFIG_USB_DEVICEFS is not set
-+CONFIG_USB_BANDWIDTH=y
-+# CONFIG_USB_DYNAMIC_MINORS is not set
-+# CONFIG_USB_SUSPEND is not set
-+# CONFIG_USB_OTG is not set
-+
-+#
-+# USB Host Controller Drivers
-+#
-+CONFIG_USB_EHCI_HCD=y
-+# CONFIG_USB_EHCI_SPLIT_ISO is not set
-+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
-+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
-+# CONFIG_USB_ISP116X_HCD is not set
-+CONFIG_USB_OHCI_HCD=y
-+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
-+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-+CONFIG_USB_UHCI_HCD=y
-+# CONFIG_USB_SL811_HCD is not set
-+
-+#
-+# USB Device Class drivers
-+#
-+# CONFIG_USB_ACM is not set
-+# CONFIG_USB_PRINTER is not set
++# CONFIG_USB_ARCH_HAS_HCD is not set
++# CONFIG_USB_ARCH_HAS_OHCI is not set
++# CONFIG_USB_ARCH_HAS_EHCI is not set
 +
 +#
 +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
 +#
 +
 +#
-+# may also be needed; see USB_STORAGE Help for more information
-+#
-+CONFIG_USB_STORAGE=y
-+# CONFIG_USB_STORAGE_DEBUG is not set
-+# CONFIG_USB_STORAGE_DATAFAB is not set
-+# CONFIG_USB_STORAGE_FREECOM is not set
-+# CONFIG_USB_STORAGE_DPCM is not set
-+# CONFIG_USB_STORAGE_USBAT is not set
-+# CONFIG_USB_STORAGE_SDDR09 is not set
-+# CONFIG_USB_STORAGE_SDDR55 is not set
-+# CONFIG_USB_STORAGE_JUMPSHOT is not set
-+# CONFIG_USB_STORAGE_ALAUDA is not set
-+# CONFIG_USB_LIBUSUAL is not set
-+
-+#
-+# USB Input Devices
-+#
-+CONFIG_USB_HID=y
-+CONFIG_USB_HIDINPUT=y
-+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-+# CONFIG_HID_FF is not set
-+CONFIG_USB_HIDDEV=y
-+# CONFIG_USB_AIPTEK is not set
-+# CONFIG_USB_WACOM is not set
-+# CONFIG_USB_ACECAD is not set
-+# CONFIG_USB_KBTAB is not set
-+# CONFIG_USB_POWERMATE is not set
-+# CONFIG_USB_TOUCHSCREEN is not set
-+# CONFIG_USB_YEALINK is not set
-+# CONFIG_USB_XPAD is not set
-+# CONFIG_USB_ATI_REMOTE is not set
-+# CONFIG_USB_ATI_REMOTE2 is not set
-+# CONFIG_USB_KEYSPAN_REMOTE is not set
-+# CONFIG_USB_APPLETOUCH is not set
-+
-+#
-+# USB Imaging devices
-+#
-+# CONFIG_USB_MDC800 is not set
-+# CONFIG_USB_MICROTEK is not set
-+
-+#
-+# USB Network Adapters
-+#
-+# CONFIG_USB_CATC is not set
-+# CONFIG_USB_KAWETH is not set
-+# CONFIG_USB_PEGASUS is not set
-+# CONFIG_USB_RTL8150 is not set
-+# CONFIG_USB_USBNET is not set
-+CONFIG_USB_MON=y
-+
-+#
-+# USB port drivers
-+#
-+
-+#
-+# USB Serial Converter support
-+#
-+# CONFIG_USB_SERIAL is not set
-+
-+#
-+# USB Miscellaneous drivers
-+#
-+# CONFIG_USB_EMI62 is not set
-+# CONFIG_USB_EMI26 is not set
-+# CONFIG_USB_AUERSWALD is not set
-+# CONFIG_USB_RIO500 is not set
-+# CONFIG_USB_LEGOTOWER is not set
-+# CONFIG_USB_LCD is not set
-+# CONFIG_USB_LED is not set
-+# CONFIG_USB_CYPRESS_CY7C63 is not set
-+# CONFIG_USB_CYTHERM is not set
-+# CONFIG_USB_PHIDGETKIT is not set
-+# CONFIG_USB_PHIDGETSERVO is not set
-+# CONFIG_USB_IDMOUSE is not set
-+# CONFIG_USB_APPLEDISPLAY is not set
-+# CONFIG_USB_SISUSBVGA is not set
-+# CONFIG_USB_LD is not set
-+
-+#
-+# USB DSL modem support
-+#
-+
-+#
 +# USB Gadget Support
 +#
 +# CONFIG_USB_GADGET is not set
@@ -63536,11 +63567,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# InfiniBand support
 +#
-+# CONFIG_INFINIBAND is not set
 +
 +#
 +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
 +#
++# CONFIG_EDAC is not set
 +
 +#
 +# Real Time Clock
@@ -63564,9 +63595,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# File systems
 +#
 +CONFIG_EXT2_FS=y
-+CONFIG_EXT2_FS_XATTR=y
-+# CONFIG_EXT2_FS_POSIX_ACL is not set
-+# CONFIG_EXT2_FS_SECURITY is not set
++# CONFIG_EXT2_FS_XATTR is not set
 +# CONFIG_EXT2_FS_XIP is not set
 +CONFIG_EXT3_FS=y
 +CONFIG_EXT3_FS_XATTR=y
@@ -63575,7 +63604,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_JBD=y
 +# CONFIG_JBD_DEBUG is not set
 +CONFIG_FS_MBCACHE=y
-+# CONFIG_REISERFS_FS is not set
++CONFIG_REISERFS_FS=y
++# CONFIG_REISERFS_CHECK is not set
++# CONFIG_REISERFS_PROC_INFO is not set
++# CONFIG_REISERFS_FS_XATTR is not set
 +# CONFIG_JFS_FS is not set
 +# CONFIG_FS_POSIX_ACL is not set
 +# CONFIG_XFS_FS is not set
@@ -63587,7 +63619,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_QUOTA is not set
 +CONFIG_DNOTIFY=y
 +CONFIG_AUTOFS_FS=y
-+# CONFIG_AUTOFS4_FS is not set
++CONFIG_AUTOFS4_FS=y
 +# CONFIG_FUSE_FS is not set
 +
 +#
@@ -63595,16 +63627,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +CONFIG_ISO9660_FS=y
 +CONFIG_JOLIET=y
-+# CONFIG_ZISOFS is not set
-+CONFIG_UDF_FS=y
-+CONFIG_UDF_NLS=y
++CONFIG_ZISOFS=y
++CONFIG_ZISOFS_FS=y
++# CONFIG_UDF_FS is not set
 +
 +#
 +# DOS/FAT/NT Filesystems
 +#
-+CONFIG_FAT_FS=y
-+CONFIG_MSDOS_FS=y
-+CONFIG_VFAT_FS=y
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++CONFIG_VFAT_FS=m
 +CONFIG_FAT_DEFAULT_CODEPAGE=437
 +CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 +# CONFIG_NTFS_FS is not set
@@ -63630,7 +63662,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_BEFS_FS is not set
 +# CONFIG_BFS_FS is not set
 +# CONFIG_EFS_FS is not set
-+# CONFIG_CRAMFS is not set
++CONFIG_CRAMFS=y
 +# CONFIG_VXFS_FS is not set
 +# CONFIG_HPFS_FS is not set
 +# CONFIG_QNX4FS_FS is not set
@@ -63643,21 +63675,15 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_NFS_FS=y
 +CONFIG_NFS_V3=y
 +# CONFIG_NFS_V3_ACL is not set
-+CONFIG_NFS_V4=y
++# CONFIG_NFS_V4 is not set
 +# CONFIG_NFS_DIRECTIO is not set
-+CONFIG_NFSD=y
-+CONFIG_NFSD_V3=y
-+# CONFIG_NFSD_V3_ACL is not set
-+# CONFIG_NFSD_V4 is not set
-+# CONFIG_NFSD_TCP is not set
++# CONFIG_NFSD is not set
 +CONFIG_ROOT_NFS=y
 +CONFIG_LOCKD=y
 +CONFIG_LOCKD_V4=y
-+CONFIG_EXPORTFS=y
 +CONFIG_NFS_COMMON=y
 +CONFIG_SUNRPC=y
-+CONFIG_SUNRPC_GSS=y
-+CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_KRB5 is not set
 +# CONFIG_RPCSEC_GSS_SPKM3 is not set
 +# CONFIG_SMB_FS is not set
 +# CONFIG_CIFS is not set
@@ -63669,23 +63695,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Partition Types
 +#
-+CONFIG_PARTITION_ADVANCED=y
-+# CONFIG_ACORN_PARTITION is not set
-+# CONFIG_OSF_PARTITION is not set
-+# CONFIG_AMIGA_PARTITION is not set
-+# CONFIG_ATARI_PARTITION is not set
-+# CONFIG_MAC_PARTITION is not set
++# CONFIG_PARTITION_ADVANCED is not set
 +CONFIG_MSDOS_PARTITION=y
-+# CONFIG_BSD_DISKLABEL is not set
-+# CONFIG_MINIX_SUBPARTITION is not set
-+# CONFIG_SOLARIS_X86_PARTITION is not set
-+# CONFIG_UNIXWARE_DISKLABEL is not set
-+# CONFIG_LDM_PARTITION is not set
-+# CONFIG_SGI_PARTITION is not set
-+# CONFIG_ULTRIX_PARTITION is not set
-+# CONFIG_SUN_PARTITION is not set
-+# CONFIG_KARMA_PARTITION is not set
-+CONFIG_EFI_PARTITION=y
 +
 +#
 +# Native Language Support
@@ -63693,59 +63704,46 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_NLS=y
 +CONFIG_NLS_DEFAULT="iso8859-1"
 +CONFIG_NLS_CODEPAGE_437=y
-+CONFIG_NLS_CODEPAGE_737=y
-+CONFIG_NLS_CODEPAGE_775=y
-+CONFIG_NLS_CODEPAGE_850=y
-+CONFIG_NLS_CODEPAGE_852=y
-+CONFIG_NLS_CODEPAGE_855=y
-+CONFIG_NLS_CODEPAGE_857=y
-+CONFIG_NLS_CODEPAGE_860=y
-+CONFIG_NLS_CODEPAGE_861=y
-+CONFIG_NLS_CODEPAGE_862=y
-+CONFIG_NLS_CODEPAGE_863=y
-+CONFIG_NLS_CODEPAGE_864=y
-+CONFIG_NLS_CODEPAGE_865=y
-+CONFIG_NLS_CODEPAGE_866=y
-+CONFIG_NLS_CODEPAGE_869=y
-+CONFIG_NLS_CODEPAGE_936=y
-+CONFIG_NLS_CODEPAGE_950=y
-+CONFIG_NLS_CODEPAGE_932=y
-+CONFIG_NLS_CODEPAGE_949=y
-+CONFIG_NLS_CODEPAGE_874=y
-+CONFIG_NLS_ISO8859_8=y
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++# CONFIG_NLS_CODEPAGE_850 is not set
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
 +# CONFIG_NLS_CODEPAGE_1250 is not set
-+CONFIG_NLS_CODEPAGE_1251=y
++# CONFIG_NLS_CODEPAGE_1251 is not set
 +# CONFIG_NLS_ASCII is not set
 +CONFIG_NLS_ISO8859_1=y
-+CONFIG_NLS_ISO8859_2=y
-+CONFIG_NLS_ISO8859_3=y
-+CONFIG_NLS_ISO8859_4=y
-+CONFIG_NLS_ISO8859_5=y
-+CONFIG_NLS_ISO8859_6=y
-+CONFIG_NLS_ISO8859_7=y
-+CONFIG_NLS_ISO8859_9=y
-+CONFIG_NLS_ISO8859_13=y
-+CONFIG_NLS_ISO8859_14=y
-+CONFIG_NLS_ISO8859_15=y
-+CONFIG_NLS_KOI8_R=y
-+CONFIG_NLS_KOI8_U=y
-+CONFIG_NLS_UTF8=y
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++# CONFIG_NLS_ISO8859_15 is not set
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++# CONFIG_NLS_UTF8 is not set
 +
 +#
-+# Library routines
-+#
-+# CONFIG_CRC_CCITT is not set
-+# CONFIG_CRC16 is not set
-+CONFIG_CRC32=y
-+# CONFIG_LIBCRC32C is not set
-+CONFIG_PLIST=y
-+CONFIG_GENERIC_HARDIRQS=y
-+CONFIG_GENERIC_IRQ_PROBE=y
-+CONFIG_GENERIC_PENDING_IRQ=y
-+CONFIG_IRQ_PER_CPU=y
-+
-+#
-+# Instrumentation Support
++# Instrumentation Support
 +#
 +# CONFIG_PROFILING is not set
 +# CONFIG_KPROBES is not set
@@ -63753,33 +63751,40 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Kernel hacking
 +#
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 +# CONFIG_PRINTK_TIME is not set
 +CONFIG_MAGIC_SYSRQ=y
 +CONFIG_UNUSED_SYMBOLS=y
 +CONFIG_DEBUG_KERNEL=y
-+CONFIG_LOG_BUF_SHIFT=17
++CONFIG_LOG_BUF_SHIFT=14
 +CONFIG_DETECT_SOFTLOCKUP=y
 +# CONFIG_SCHEDSTATS is not set
 +# CONFIG_DEBUG_SLAB is not set
 +# CONFIG_DEBUG_RT_MUTEXES is not set
 +# CONFIG_RT_MUTEX_TESTER is not set
 +# CONFIG_DEBUG_SPINLOCK is not set
-+CONFIG_DEBUG_MUTEXES=y
++# CONFIG_DEBUG_MUTEXES is not set
 +# CONFIG_DEBUG_RWSEMS is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
 +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 +# CONFIG_DEBUG_KOBJECT is not set
-+# CONFIG_DEBUG_INFO is not set
++# CONFIG_DEBUG_HIGHMEM is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++CONFIG_DEBUG_INFO=y
 +# CONFIG_DEBUG_FS is not set
 +# CONFIG_DEBUG_VM is not set
++CONFIG_FRAME_POINTER=y
++# CONFIG_UNWIND_INFO is not set
 +CONFIG_FORCED_INLINING=y
 +# CONFIG_RCU_TORTURE_TEST is not set
-+CONFIG_IA64_GRANULE_16MB=y
-+# CONFIG_IA64_GRANULE_64MB is not set
-+CONFIG_IA64_PRINT_HAZARDS=y
-+# CONFIG_DISABLE_VHPT is not set
-+# CONFIG_IA64_DEBUG_CMPXCHG is not set
-+# CONFIG_IA64_DEBUG_IRQ is not set
++CONFIG_EARLY_PRINTK=y
++# CONFIG_DEBUG_STACKOVERFLOW is not set
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_PAGEALLOC is not set
++# CONFIG_DEBUG_RODATA is not set
++# CONFIG_4KSTACKS is not set
 +
 +#
 +# Security options
@@ -63794,17 +63799,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_CRYPTO_HMAC is not set
 +# CONFIG_CRYPTO_NULL is not set
 +# CONFIG_CRYPTO_MD4 is not set
-+CONFIG_CRYPTO_MD5=y
++CONFIG_CRYPTO_MD5=m
 +# CONFIG_CRYPTO_SHA1 is not set
 +# CONFIG_CRYPTO_SHA256 is not set
 +# CONFIG_CRYPTO_SHA512 is not set
 +# CONFIG_CRYPTO_WP512 is not set
 +# CONFIG_CRYPTO_TGR192 is not set
-+CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_DES is not set
 +# CONFIG_CRYPTO_BLOWFISH is not set
 +# CONFIG_CRYPTO_TWOFISH is not set
 +# CONFIG_CRYPTO_SERPENT is not set
 +# CONFIG_CRYPTO_AES is not set
++# CONFIG_CRYPTO_AES_586 is not set
 +# CONFIG_CRYPTO_CAST5 is not set
 +# CONFIG_CRYPTO_CAST6 is not set
 +# CONFIG_CRYPTO_TEA is not set
@@ -63813,14 +63819,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_CRYPTO_ANUBIS is not set
 +# CONFIG_CRYPTO_DEFLATE is not set
 +# CONFIG_CRYPTO_MICHAEL_MIC is not set
-+# CONFIG_CRYPTO_CRC32C is not set
++CONFIG_CRYPTO_CRC32C=m
 +# CONFIG_CRYPTO_TEST is not set
 +
 +#
 +# Hardware crypto devices
 +#
-+# CONFIG_XEN_SMPBOOT is not set
-+# CONFIG_XEN_DEVMEM is not set
++# CONFIG_CRYPTO_DEV_PADLOCK is not set
++CONFIG_XEN=y
 +CONFIG_XEN_INTERFACE_VERSION=0x00030207
 +
 +#
@@ -63831,13 +63837,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_PRIVCMD=y
 +CONFIG_XEN_XENBUS_DEV=y
 +# CONFIG_XEN_BACKEND is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
 +CONFIG_XEN_BLKDEV_FRONTEND=y
 +CONFIG_XEN_NETDEV_FRONTEND=y
 +# CONFIG_XEN_GRANT_DEV is not set
-+CONFIG_XEN_FRAMEBUFFER=y
-+CONFIG_XEN_KEYBOARD=y
-+# CONFIG_XEN_SCRUB_PAGES is not set
-+# CONFIG_XEN_DISABLE_SERIAL is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
++CONFIG_XEN_SCRUB_PAGES=y
++CONFIG_XEN_DISABLE_SERIAL=y
 +CONFIG_XEN_SYSFS=y
 +CONFIG_XEN_COMPAT_030002_AND_LATER=y
 +# CONFIG_XEN_COMPAT_030004_AND_LATER is not set
@@ -63846,28 +63852,53 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_COMPAT=0x030002
 +CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y
 +CONFIG_NO_IDLE_HZ=y
++CONFIG_XEN_SMPBOOT=y
 +CONFIG_XEN_BALLOON=y
-+CONFIG_XEN_XENCOMM=y
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defconfig_xenU_x86_32 linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xenU_x86_32
---- linux-2.6.18/buildconfigs/linux-defconfig_xenU_x86_32      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xenU_x86_32       2007-12-23 11:15:00.706184434 +0100
-@@ -0,0 +1,950 @@
++CONFIG_XEN_DEVMEM=y
++
++#
++# Library routines
++#
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++# CONFIG_CRC32 is not set
++CONFIG_LIBCRC32C=m
++CONFIG_ZLIB_INFLATE=y
++CONFIG_PLIST=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_PENDING_IRQ=y
++CONFIG_X86_SMP=y
++CONFIG_X86_BIOS_REBOOT=y
++CONFIG_X86_TRAMPOLINE=y
++CONFIG_X86_NO_TSS=y
++CONFIG_X86_NO_IDT=y
++CONFIG_KTIME_SCALAR=y
+--- linux-2.6.18.8/buildconfigs/linux-defconfig_xenU_x86_64    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xenU_x86_64       2008-05-19 00:33:19.713282430 +0300
+@@ -0,0 +1,905 @@
 +#
 +# Automatically generated make config: don't edit
 +# Linux kernel version: 2.6.18.8
-+# Tue Oct 16 09:31:29 2007
++# Mon Feb 18 10:42:42 2008
 +#
-+CONFIG_X86_32=y
++CONFIG_X86_64=y
++CONFIG_64BIT=y
++CONFIG_X86=y
 +CONFIG_LOCKDEP_SUPPORT=y
 +CONFIG_STACKTRACE_SUPPORT=y
 +CONFIG_SEMAPHORE_SLEEPERS=y
-+CONFIG_X86=y
 +CONFIG_MMU=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_X86_CMPXCHG=y
++CONFIG_EARLY_PRINTK=y
 +CONFIG_GENERIC_ISA_DMA=y
 +CONFIG_GENERIC_IOMAP=y
-+CONFIG_GENERIC_HWEIGHT=y
 +CONFIG_ARCH_MAY_HAVE_PC_FDC=y
 +CONFIG_DMI=y
++CONFIG_AUDIT_ARCH=y
 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 +
 +#
@@ -63948,77 +63979,28 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Processor type and features
 +#
-+CONFIG_SMP=y
-+# CONFIG_X86_PC is not set
-+CONFIG_X86_XEN=y
-+# CONFIG_X86_ELAN is not set
-+# CONFIG_X86_VOYAGER is not set
-+# CONFIG_X86_NUMAQ is not set
-+# CONFIG_X86_SUMMIT is not set
-+# CONFIG_X86_BIGSMP is not set
-+# CONFIG_X86_VISWS is not set
-+# CONFIG_X86_GENERICARCH is not set
-+# CONFIG_X86_ES7000 is not set
-+# CONFIG_M386 is not set
-+# CONFIG_M486 is not set
-+# CONFIG_M586 is not set
-+# CONFIG_M586TSC is not set
-+# CONFIG_M586MMX is not set
-+CONFIG_M686=y
-+# CONFIG_MPENTIUMII is not set
-+# CONFIG_MPENTIUMIII is not set
-+# CONFIG_MPENTIUMM is not set
-+# CONFIG_MPENTIUM4 is not set
-+# CONFIG_MK6 is not set
-+# CONFIG_MK7 is not set
++CONFIG_X86_PC=y
++# CONFIG_X86_VSMP is not set
 +# CONFIG_MK8 is not set
-+# CONFIG_MCRUSOE is not set
-+# CONFIG_MEFFICEON is not set
-+# CONFIG_MWINCHIPC6 is not set
-+# CONFIG_MWINCHIP2 is not set
-+# CONFIG_MWINCHIP3D is not set
-+# CONFIG_MGEODEGX1 is not set
-+# CONFIG_MGEODE_LX is not set
-+# CONFIG_MCYRIXIII is not set
-+# CONFIG_MVIAC3_2 is not set
-+# CONFIG_X86_GENERIC is not set
-+CONFIG_X86_CMPXCHG=y
-+CONFIG_X86_XADD=y
-+CONFIG_X86_L1_CACHE_SHIFT=5
-+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
-+CONFIG_GENERIC_CALIBRATE_DELAY=y
-+CONFIG_X86_PPRO_FENCE=y
-+CONFIG_X86_WP_WORKS_OK=y
-+CONFIG_X86_INVLPG=y
-+CONFIG_X86_BSWAP=y
-+CONFIG_X86_POPAD_OK=y
-+CONFIG_X86_CMPXCHG64=y
++# CONFIG_MPSC is not set
++CONFIG_GENERIC_CPU=y
++CONFIG_X86_64_XEN=y
++CONFIG_X86_NO_TSS=y
++CONFIG_X86_NO_IDT=y
++CONFIG_X86_L1_CACHE_BYTES=128
++CONFIG_X86_L1_CACHE_SHIFT=7
++CONFIG_X86_INTERNODE_CACHE_BYTES=128
 +CONFIG_X86_GOOD_APIC=y
-+CONFIG_X86_USE_PPRO_CHECKSUM=y
-+CONFIG_NR_CPUS=8
++# CONFIG_MICROCODE is not set
++# CONFIG_X86_MSR is not set
++CONFIG_X86_CPUID=y
++CONFIG_X86_XEN_GENAPIC=y
++CONFIG_SMP=y
 +CONFIG_PREEMPT_NONE=y
 +# CONFIG_PREEMPT_VOLUNTARY is not set
 +# CONFIG_PREEMPT is not set
 +CONFIG_PREEMPT_BKL=y
-+CONFIG_VM86=y
-+# CONFIG_TOSHIBA is not set
-+# CONFIG_I8K is not set
-+# CONFIG_X86_REBOOTFIXUPS is not set
-+# CONFIG_X86_MSR is not set
-+CONFIG_X86_CPUID=y
-+CONFIG_SWIOTLB=y
-+
-+#
-+# Firmware Drivers
-+#
-+# CONFIG_EDD is not set
-+# CONFIG_DELL_RBU is not set
-+# CONFIG_DCDBAS is not set
-+# CONFIG_NOHIGHMEM is not set
-+CONFIG_HIGHMEM4G=y
-+# CONFIG_HIGHMEM64G is not set
-+CONFIG_PAGE_OFFSET=0xC0000000
-+CONFIG_HIGHMEM=y
++CONFIG_ARCH_FLATMEM_ENABLE=y
 +CONFIG_SELECT_MEMORY_MODEL=y
 +CONFIG_FLATMEM_MANUAL=y
 +# CONFIG_DISCONTIGMEM_MANUAL is not set
@@ -64028,24 +64010,27 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_SPARSEMEM_STATIC is not set
 +CONFIG_SPLIT_PTLOCK_CPUS=4
 +CONFIG_RESOURCES_64BIT=y
-+# CONFIG_HIGHPTE is not set
-+# CONFIG_REGPARM is not set
++CONFIG_NR_CPUS=8
++CONFIG_HOTPLUG_CPU=y
++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
++CONFIG_SWIOTLB=y
++# CONFIG_CRASH_DUMP is not set
++CONFIG_PHYSICAL_START=0x200000
 +CONFIG_SECCOMP=y
 +CONFIG_HZ_100=y
 +# CONFIG_HZ_250 is not set
 +# CONFIG_HZ_1000 is not set
 +CONFIG_HZ=100
-+# CONFIG_CRASH_DUMP is not set
-+CONFIG_PHYSICAL_START=0x100000
-+CONFIG_HOTPLUG_CPU=y
-+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
++# CONFIG_REORDER is not set
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_ISA_DMA_API=y
++CONFIG_GENERIC_PENDING_IRQ=y
 +
 +#
-+# Bus options (PCI, PCMCIA, EISA, MCA, ISA)
++# Bus options (PCI etc.)
 +#
 +# CONFIG_PCI is not set
-+CONFIG_ISA_DMA_API=y
-+# CONFIG_SCx200 is not set
 +
 +#
 +# PCCARD (PCMCIA/CardBus) support
@@ -64057,11 +64042,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +
 +#
-+# Executable file formats
++# Executable file formats / Emulations
 +#
 +CONFIG_BINFMT_ELF=y
-+# CONFIG_BINFMT_AOUT is not set
 +# CONFIG_BINFMT_MISC is not set
++CONFIG_IA32_EMULATION=y
++CONFIG_IA32_AOUT=y
++CONFIG_COMPAT=y
++CONFIG_SYSVIPC_COMPAT=y
 +
 +#
 +# Networking
@@ -64333,7 +64321,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Input Device Drivers
 +#
 +CONFIG_INPUT_KEYBOARD=y
-+# CONFIG_KEYBOARD_ATKBD is not set
++CONFIG_KEYBOARD_ATKBD=y
 +# CONFIG_KEYBOARD_SUNKBD is not set
 +# CONFIG_KEYBOARD_LKKBD is not set
 +# CONFIG_KEYBOARD_XTKBD is not set
@@ -64350,6 +64338,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_SERIO_I8042=y
 +CONFIG_SERIO_SERPORT=y
 +# CONFIG_SERIO_CT82C710 is not set
++CONFIG_SERIO_LIBPS2=y
 +# CONFIG_SERIO_RAW is not set
 +# CONFIG_GAMEPORT is not set
 +
@@ -64383,7 +64372,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# CONFIG_WATCHDOG is not set
 +CONFIG_HW_RANDOM=y
-+CONFIG_HW_RANDOM_VIA=y
 +# CONFIG_NVRAM is not set
 +# CONFIG_RTC is not set
 +# CONFIG_GEN_RTC is not set
@@ -64395,8 +64383,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# CONFIG_MWAVE is not set
 +# CONFIG_PC8736x_GPIO is not set
-+# CONFIG_NSC_GPIO is not set
-+# CONFIG_CS5535_GPIO is not set
 +# CONFIG_RAW_DRIVER is not set
 +# CONFIG_HANGCHECK_TIMER is not set
 +
@@ -64522,6 +64508,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +
 +#
++# Firmware Drivers
++#
++# CONFIG_EDD is not set
++# CONFIG_DELL_RBU is not set
++# CONFIG_DCDBAS is not set
++
++#
 +# File systems
 +#
 +CONFIG_EXT2_FS=y
@@ -64700,8 +64693,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 +# CONFIG_DEBUG_KOBJECT is not set
-+# CONFIG_DEBUG_HIGHMEM is not set
-+CONFIG_DEBUG_BUGVERBOSE=y
 +CONFIG_DEBUG_INFO=y
 +# CONFIG_DEBUG_FS is not set
 +# CONFIG_DEBUG_VM is not set
@@ -64709,12 +64700,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_UNWIND_INFO is not set
 +CONFIG_FORCED_INLINING=y
 +# CONFIG_RCU_TORTURE_TEST is not set
-+CONFIG_EARLY_PRINTK=y
++# CONFIG_DEBUG_RODATA is not set
 +# CONFIG_DEBUG_STACKOVERFLOW is not set
 +# CONFIG_DEBUG_STACK_USAGE is not set
-+# CONFIG_DEBUG_PAGEALLOC is not set
-+# CONFIG_DEBUG_RODATA is not set
-+# CONFIG_4KSTACKS is not set
 +
 +#
 +# Security options
@@ -64740,7 +64728,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_CRYPTO_TWOFISH is not set
 +# CONFIG_CRYPTO_SERPENT is not set
 +# CONFIG_CRYPTO_AES is not set
-+# CONFIG_CRYPTO_AES_586 is not set
++# CONFIG_CRYPTO_AES_X86_64 is not set
 +# CONFIG_CRYPTO_CAST5 is not set
 +# CONFIG_CRYPTO_CAST6 is not set
 +# CONFIG_CRYPTO_TEA is not set
@@ -64755,9 +64743,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Hardware crypto devices
 +#
-+# CONFIG_CRYPTO_DEV_PADLOCK is not set
 +CONFIG_XEN=y
-+CONFIG_XEN_INTERFACE_VERSION=0x00030206
++CONFIG_XEN_INTERFACE_VERSION=0x00030207
 +
 +#
 +# XEN
@@ -64767,8 +64754,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_PRIVCMD=y
 +CONFIG_XEN_XENBUS_DEV=y
 +# CONFIG_XEN_BACKEND is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
 +CONFIG_XEN_BLKDEV_FRONTEND=y
 +CONFIG_XEN_NETDEV_FRONTEND=y
++CONFIG_XEN_GRANT_DEV=y
++# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
 +CONFIG_XEN_SCRUB_PAGES=y
 +CONFIG_XEN_DISABLE_SERIAL=y
 +CONFIG_XEN_SYSFS=y
@@ -64782,7 +64772,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_SMPBOOT=y
 +CONFIG_XEN_BALLOON=y
 +CONFIG_XEN_DEVMEM=y
-+# CONFIG_XEN_GRANT_DEV is not set
 +
 +#
 +# Library routines
@@ -64793,41 +64782,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_LIBCRC32C=m
 +CONFIG_ZLIB_INFLATE=y
 +CONFIG_PLIST=y
-+CONFIG_GENERIC_HARDIRQS=y
-+CONFIG_GENERIC_IRQ_PROBE=y
-+CONFIG_GENERIC_PENDING_IRQ=y
-+CONFIG_X86_SMP=y
-+CONFIG_X86_BIOS_REBOOT=y
-+CONFIG_X86_TRAMPOLINE=y
-+CONFIG_X86_NO_TSS=y
-+CONFIG_X86_NO_IDT=y
-+CONFIG_KTIME_SCALAR=y
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defconfig_xenU_x86_64 linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xenU_x86_64
---- linux-2.6.18/buildconfigs/linux-defconfig_xenU_x86_64      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xenU_x86_64       2007-12-23 11:15:00.706184434 +0100
-@@ -0,0 +1,1241 @@
+--- linux-2.6.18.8/buildconfigs/linux-defconfig_xen_ia64       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen_ia64  2008-05-19 00:33:19.717282661 +0300
+@@ -0,0 +1,1701 @@
 +#
 +# Automatically generated make config: don't edit
 +# Linux kernel version: 2.6.18.8
-+# Tue Oct 16 09:32:52 2007
++# Tue Feb 19 11:20:00 2008
 +#
-+CONFIG_X86_64=y
-+CONFIG_64BIT=y
-+CONFIG_X86=y
-+CONFIG_LOCKDEP_SUPPORT=y
-+CONFIG_STACKTRACE_SUPPORT=y
-+CONFIG_SEMAPHORE_SLEEPERS=y
-+CONFIG_MMU=y
-+CONFIG_RWSEM_GENERIC_SPINLOCK=y
-+CONFIG_GENERIC_HWEIGHT=y
-+CONFIG_GENERIC_CALIBRATE_DELAY=y
-+CONFIG_X86_CMPXCHG=y
-+CONFIG_EARLY_PRINTK=y
-+CONFIG_GENERIC_ISA_DMA=y
-+CONFIG_GENERIC_IOMAP=y
-+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
-+CONFIG_DMI=y
-+CONFIG_AUDIT_ARCH=y
 +CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 +
 +#
@@ -64841,25 +64803,24 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# General setup
 +#
 +CONFIG_LOCALVERSION=""
-+# CONFIG_LOCALVERSION_AUTO is not set
++CONFIG_LOCALVERSION_AUTO=y
 +CONFIG_SWAP=y
 +CONFIG_SYSVIPC=y
 +CONFIG_POSIX_MQUEUE=y
 +CONFIG_BSD_PROCESS_ACCT=y
 +# CONFIG_BSD_PROCESS_ACCT_V3 is not set
 +# CONFIG_TASKSTATS is not set
-+CONFIG_AUDIT=y
-+CONFIG_AUDITSYSCALL=y
-+# CONFIG_IKCONFIG is not set
++# CONFIG_AUDIT is not set
++CONFIG_IKCONFIG=y
++CONFIG_IKCONFIG_PROC=y
 +# CONFIG_CPUSETS is not set
 +# CONFIG_RELAY is not set
 +CONFIG_INITRAMFS_SOURCE=""
-+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 +# CONFIG_EMBEDDED is not set
-+CONFIG_UID16=y
 +CONFIG_SYSCTL=y
 +CONFIG_KALLSYMS=y
-+# CONFIG_KALLSYMS_ALL is not set
++CONFIG_KALLSYMS_ALL=y
 +CONFIG_KALLSYMS_EXTRA_PASS=y
 +CONFIG_HOTPLUG=y
 +CONFIG_PRINTK=y
@@ -64883,16 +64844,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_MODULE_UNLOAD=y
 +# CONFIG_MODULE_FORCE_UNLOAD is not set
 +CONFIG_MODVERSIONS=y
-+# CONFIG_MODULE_SRCVERSION_ALL is not set
++CONFIG_MODULE_SRCVERSION_ALL=y
 +CONFIG_KMOD=y
 +CONFIG_STOP_MACHINE=y
 +
 +#
 +# Block layer
 +#
-+CONFIG_LBD=y
 +# CONFIG_BLK_DEV_IO_TRACE is not set
-+CONFIG_LSF=y
 +
 +#
 +# IO Schedulers
@@ -64910,77 +64869,151 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Processor type and features
 +#
-+CONFIG_X86_PC=y
-+# CONFIG_X86_VSMP is not set
-+# CONFIG_MK8 is not set
-+CONFIG_MPSC=y
-+# CONFIG_GENERIC_CPU is not set
-+CONFIG_X86_64_XEN=y
-+CONFIG_X86_NO_TSS=y
-+CONFIG_X86_NO_IDT=y
-+CONFIG_X86_L1_CACHE_BYTES=128
-+CONFIG_X86_L1_CACHE_SHIFT=7
-+CONFIG_X86_INTERNODE_CACHE_BYTES=128
-+CONFIG_X86_GOOD_APIC=y
-+# CONFIG_MICROCODE is not set
-+# CONFIG_X86_MSR is not set
-+CONFIG_X86_CPUID=y
-+CONFIG_X86_XEN_GENAPIC=y
++CONFIG_IA64=y
++CONFIG_64BIT=y
++CONFIG_MMU=y
++CONFIG_SWIOTLB=y
++CONFIG_RWSEM_XCHGADD_ALGORITHM=y
++CONFIG_GENERIC_FIND_NEXT_BIT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_TIME_INTERPOLATION=y
++CONFIG_DMI=y
++CONFIG_EFI=y
++CONFIG_GENERIC_IOMAP=y
++CONFIG_XEN=y
++CONFIG_XEN_IA64_EXPOSE_P2M=y
++CONFIG_XEN_IA64_EXPOSE_P2M_USE_DTR=y
++CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER=y
++CONFIG_DMA_IS_DMA32=y
++CONFIG_AUDIT_ARCH=y
++CONFIG_IA64_GENERIC=y
++# CONFIG_IA64_DIG is not set
++# CONFIG_IA64_HP_ZX1 is not set
++# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
++# CONFIG_IA64_SGI_SN2 is not set
++# CONFIG_IA64_HP_SIM is not set
++# CONFIG_IA64_XEN is not set
++# CONFIG_ITANIUM is not set
++CONFIG_MCKINLEY=y
++# CONFIG_IA64_PAGE_SIZE_4KB is not set
++# CONFIG_IA64_PAGE_SIZE_8KB is not set
++CONFIG_IA64_PAGE_SIZE_16KB=y
++# CONFIG_IA64_PAGE_SIZE_64KB is not set
++CONFIG_PGTABLE_3=y
++# CONFIG_PGTABLE_4 is not set
++CONFIG_HZ_100=y
++# CONFIG_HZ_250 is not set
++# CONFIG_HZ_1000 is not set
++CONFIG_HZ=100
++CONFIG_IA64_L1_CACHE_SHIFT=7
++CONFIG_IA64_CYCLONE=y
++CONFIG_IOSAPIC=y
++# CONFIG_IA64_SGI_SN_XP is not set
++CONFIG_FORCE_MAX_ZONEORDER=11
 +CONFIG_SMP=y
-+CONFIG_PREEMPT_NONE=y
-+# CONFIG_PREEMPT_VOLUNTARY is not set
++CONFIG_NR_CPUS=16
++CONFIG_HOTPLUG_CPU=y
++CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
++# CONFIG_SCHED_SMT is not set
++# CONFIG_PERMIT_BSP_REMOVE is not set
 +# CONFIG_PREEMPT is not set
-+CONFIG_PREEMPT_BKL=y
-+CONFIG_ARCH_FLATMEM_ENABLE=y
 +CONFIG_SELECT_MEMORY_MODEL=y
-+CONFIG_FLATMEM_MANUAL=y
-+# CONFIG_DISCONTIGMEM_MANUAL is not set
++# CONFIG_FLATMEM_MANUAL is not set
++CONFIG_DISCONTIGMEM_MANUAL=y
 +# CONFIG_SPARSEMEM_MANUAL is not set
-+CONFIG_FLATMEM=y
++CONFIG_DISCONTIGMEM=y
 +CONFIG_FLAT_NODE_MEM_MAP=y
++CONFIG_NEED_MULTIPLE_NODES=y
 +# CONFIG_SPARSEMEM_STATIC is not set
 +CONFIG_SPLIT_PTLOCK_CPUS=4
++# CONFIG_MIGRATION is not set
 +CONFIG_RESOURCES_64BIT=y
-+CONFIG_NR_CPUS=16
-+# CONFIG_HOTPLUG_CPU is not set
-+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
-+CONFIG_SWIOTLB=y
-+# CONFIG_CRASH_DUMP is not set
-+CONFIG_PHYSICAL_START=0x200000
-+CONFIG_SECCOMP=y
-+CONFIG_HZ_100=y
-+# CONFIG_HZ_250 is not set
-+# CONFIG_HZ_1000 is not set
-+CONFIG_HZ=100
-+# CONFIG_REORDER is not set
-+CONFIG_GENERIC_HARDIRQS=y
-+CONFIG_GENERIC_IRQ_PROBE=y
-+CONFIG_ISA_DMA_API=y
-+CONFIG_GENERIC_PENDING_IRQ=y
++CONFIG_ARCH_SELECT_MEMORY_MODEL=y
++CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
++CONFIG_ARCH_FLATMEM_ENABLE=y
++CONFIG_ARCH_SPARSEMEM_ENABLE=y
++CONFIG_ARCH_DISCONTIGMEM_DEFAULT=y
++CONFIG_NUMA=y
++CONFIG_NODES_SHIFT=10
++CONFIG_VIRTUAL_MEM_MAP=y
++CONFIG_HOLES_IN_ZONE=y
++CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID=y
++CONFIG_HAVE_ARCH_NODEDATA_EXTENSION=y
++# CONFIG_IA32_SUPPORT is not set
++# CONFIG_IA64_MCA_RECOVERY is not set
++CONFIG_PERFMON=y
++CONFIG_IA64_PALINFO=y
++CONFIG_SGI_SN=y
 +
 +#
-+# Bus options (PCI etc.)
++# SN Devices
 +#
-+# CONFIG_PCI is not set
++# CONFIG_SGI_IOC3 is not set
++CONFIG_KEXEC=y
 +
 +#
-+# PCCARD (PCMCIA/CardBus) support
++# Firmware Drivers
 +#
-+# CONFIG_PCCARD is not set
++CONFIG_EFI_VARS=y
++CONFIG_EFI_PCDP=y
++CONFIG_BINFMT_ELF=y
++CONFIG_BINFMT_MISC=y
++
++#
++# Power management and ACPI
++#
++CONFIG_PM=y
++CONFIG_PM_LEGACY=y
++# CONFIG_PM_DEBUG is not set
++
++#
++# ACPI (Advanced Configuration and Power Interface) Support
++#
++CONFIG_ACPI=y
++CONFIG_ACPI_BUTTON=y
++CONFIG_ACPI_FAN=y
++# CONFIG_ACPI_DOCK is not set
++CONFIG_ACPI_PROCESSOR=y
++CONFIG_ACPI_HOTPLUG_CPU=y
++CONFIG_ACPI_THERMAL=y
++CONFIG_ACPI_NUMA=y
++CONFIG_ACPI_BLACKLIST_YEAR=0
++# CONFIG_ACPI_DEBUG is not set
++CONFIG_ACPI_EC=y
++CONFIG_ACPI_POWER=y
++CONFIG_ACPI_SYSTEM=y
++CONFIG_ACPI_CONTAINER=y
++
++#
++# CPU Frequency scaling
++#
++# CONFIG_CPU_FREQ is not set
++
++#
++# Bus options (PCI, PCMCIA)
++#
++CONFIG_PCI=y
++CONFIG_PCI_DOMAINS=y
++CONFIG_XEN_PCIDEV_FRONTEND=y
++# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
++# CONFIG_PCIEPORTBUS is not set
++# CONFIG_PCI_DEBUG is not set
 +
 +#
 +# PCI Hotplug Support
 +#
++CONFIG_HOTPLUG_PCI=y
++# CONFIG_HOTPLUG_PCI_FAKE is not set
++CONFIG_HOTPLUG_PCI_ACPI=y
++# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
++# CONFIG_HOTPLUG_PCI_CPCI is not set
++# CONFIG_HOTPLUG_PCI_SHPC is not set
++# CONFIG_HOTPLUG_PCI_SGI is not set
 +
 +#
-+# Executable file formats / Emulations
++# PCCARD (PCMCIA/CardBus) support
 +#
-+CONFIG_BINFMT_ELF=y
-+CONFIG_BINFMT_MISC=y
-+CONFIG_IA32_EMULATION=y
-+# CONFIG_IA32_AOUT is not set
-+CONFIG_COMPAT=y
-+CONFIG_SYSVIPC_COMPAT=y
++# CONFIG_PCCARD is not set
 +
 +#
 +# Networking
@@ -64992,89 +65025,43 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# CONFIG_NETDEBUG is not set
 +CONFIG_PACKET=y
-+CONFIG_PACKET_MMAP=y
++# CONFIG_PACKET_MMAP is not set
 +CONFIG_UNIX=y
 +CONFIG_XFRM=y
-+CONFIG_XFRM_USER=y
-+CONFIG_NET_KEY=m
++# CONFIG_XFRM_USER is not set
++# CONFIG_NET_KEY is not set
 +CONFIG_INET=y
 +CONFIG_IP_MULTICAST=y
-+CONFIG_IP_ADVANCED_ROUTER=y
-+CONFIG_ASK_IP_FIB_HASH=y
-+# CONFIG_IP_FIB_TRIE is not set
++# CONFIG_IP_ADVANCED_ROUTER is not set
 +CONFIG_IP_FIB_HASH=y
-+CONFIG_IP_MULTIPLE_TABLES=y
-+CONFIG_IP_ROUTE_FWMARK=y
-+CONFIG_IP_ROUTE_MULTIPATH=y
-+# CONFIG_IP_ROUTE_MULTIPATH_CACHED is not set
-+CONFIG_IP_ROUTE_VERBOSE=y
 +CONFIG_IP_PNP=y
 +CONFIG_IP_PNP_DHCP=y
-+CONFIG_IP_PNP_BOOTP=y
-+CONFIG_IP_PNP_RARP=y
-+CONFIG_NET_IPIP=m
-+CONFIG_NET_IPGRE=m
-+CONFIG_NET_IPGRE_BROADCAST=y
-+CONFIG_IP_MROUTE=y
-+CONFIG_IP_PIMSM_V1=y
-+CONFIG_IP_PIMSM_V2=y
-+# CONFIG_ARPD is not set
++# CONFIG_IP_PNP_BOOTP is not set
++# CONFIG_IP_PNP_RARP is not set
++# CONFIG_NET_IPIP is not set
++# CONFIG_NET_IPGRE is not set
++# CONFIG_IP_MROUTE is not set
++CONFIG_ARPD=y
 +CONFIG_SYN_COOKIES=y
-+CONFIG_INET_AH=m
-+CONFIG_INET_ESP=m
-+CONFIG_INET_IPCOMP=m
-+CONFIG_INET_XFRM_TUNNEL=m
-+CONFIG_INET_TUNNEL=m
++# CONFIG_INET_AH is not set
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
 +CONFIG_INET_XFRM_MODE_TRANSPORT=y
 +CONFIG_INET_XFRM_MODE_TUNNEL=y
-+# CONFIG_INET_DIAG is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
 +# CONFIG_TCP_CONG_ADVANCED is not set
 +CONFIG_TCP_CONG_BIC=y
 +
 +#
 +# IP: Virtual Server Configuration
 +#
-+CONFIG_IP_VS=m
-+# CONFIG_IP_VS_DEBUG is not set
-+CONFIG_IP_VS_TAB_BITS=12
-+
-+#
-+# IPVS transport protocol load balancing support
-+#
-+CONFIG_IP_VS_PROTO_TCP=y
-+CONFIG_IP_VS_PROTO_UDP=y
-+CONFIG_IP_VS_PROTO_ESP=y
-+CONFIG_IP_VS_PROTO_AH=y
-+
-+#
-+# IPVS scheduler
-+#
-+CONFIG_IP_VS_RR=m
-+CONFIG_IP_VS_WRR=m
-+CONFIG_IP_VS_LC=m
-+CONFIG_IP_VS_WLC=m
-+CONFIG_IP_VS_LBLC=m
-+CONFIG_IP_VS_LBLCR=m
-+CONFIG_IP_VS_DH=m
-+CONFIG_IP_VS_SH=m
-+CONFIG_IP_VS_SED=m
-+CONFIG_IP_VS_NQ=m
-+
-+#
-+# IPVS application helper
-+#
-+CONFIG_IP_VS_FTP=m
-+CONFIG_IPV6=m
-+CONFIG_IPV6_PRIVACY=y
-+# CONFIG_IPV6_ROUTER_PREF is not set
-+CONFIG_INET6_AH=m
-+CONFIG_INET6_ESP=m
-+CONFIG_INET6_IPCOMP=m
-+CONFIG_INET6_XFRM_TUNNEL=m
-+CONFIG_INET6_TUNNEL=m
-+CONFIG_INET6_XFRM_MODE_TRANSPORT=m
-+CONFIG_INET6_XFRM_MODE_TUNNEL=m
-+CONFIG_IPV6_TUNNEL=m
++# CONFIG_IP_VS is not set
++# CONFIG_IPV6 is not set
++# CONFIG_INET6_XFRM_TUNNEL is not set
++# CONFIG_INET6_TUNNEL is not set
 +# CONFIG_NETWORK_SECMARK is not set
 +CONFIG_NETFILTER=y
 +# CONFIG_NETFILTER_DEBUG is not set
@@ -65084,54 +65071,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Core Netfilter Configuration
 +#
 +# CONFIG_NETFILTER_NETLINK is not set
++# CONFIG_NF_CONNTRACK is not set
 +# CONFIG_NETFILTER_XTABLES is not set
 +
 +#
 +# IP: Netfilter Configuration
 +#
-+CONFIG_IP_NF_CONNTRACK=m
-+CONFIG_IP_NF_CT_ACCT=y
-+# CONFIG_IP_NF_CONNTRACK_MARK is not set
-+# CONFIG_IP_NF_CONNTRACK_EVENTS is not set
-+CONFIG_IP_NF_CT_PROTO_SCTP=m
-+CONFIG_IP_NF_FTP=m
-+CONFIG_IP_NF_IRC=m
-+# CONFIG_IP_NF_NETBIOS_NS is not set
-+CONFIG_IP_NF_TFTP=m
-+CONFIG_IP_NF_AMANDA=m
-+# CONFIG_IP_NF_PPTP is not set
-+# CONFIG_IP_NF_H323 is not set
-+# CONFIG_IP_NF_SIP is not set
-+CONFIG_IP_NF_QUEUE=m
-+
-+#
-+# IPv6: Netfilter Configuration (EXPERIMENTAL)
-+#
-+# CONFIG_IP6_NF_QUEUE is not set
++# CONFIG_IP_NF_CONNTRACK is not set
++# CONFIG_IP_NF_QUEUE is not set
 +
 +#
 +# Bridge: Netfilter Configuration
 +#
-+CONFIG_BRIDGE_NF_EBTABLES=m
-+CONFIG_BRIDGE_EBT_BROUTE=m
-+CONFIG_BRIDGE_EBT_T_FILTER=m
-+CONFIG_BRIDGE_EBT_T_NAT=m
-+CONFIG_BRIDGE_EBT_802_3=m
-+CONFIG_BRIDGE_EBT_AMONG=m
-+CONFIG_BRIDGE_EBT_ARP=m
-+CONFIG_BRIDGE_EBT_IP=m
-+CONFIG_BRIDGE_EBT_LIMIT=m
-+CONFIG_BRIDGE_EBT_MARK=m
-+CONFIG_BRIDGE_EBT_PKTTYPE=m
-+CONFIG_BRIDGE_EBT_STP=m
-+CONFIG_BRIDGE_EBT_VLAN=m
-+CONFIG_BRIDGE_EBT_ARPREPLY=m
-+CONFIG_BRIDGE_EBT_DNAT=m
-+CONFIG_BRIDGE_EBT_MARK_T=m
-+CONFIG_BRIDGE_EBT_REDIRECT=m
-+CONFIG_BRIDGE_EBT_SNAT=m
-+CONFIG_BRIDGE_EBT_LOG=m
-+# CONFIG_BRIDGE_EBT_ULOG is not set
++# CONFIG_BRIDGE_NF_EBTABLES is not set
 +
 +#
 +# DCCP Configuration (EXPERIMENTAL)
@@ -65141,167 +65093,38 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# SCTP Configuration (EXPERIMENTAL)
 +#
-+CONFIG_IP_SCTP=m
-+# CONFIG_SCTP_DBG_MSG is not set
-+# CONFIG_SCTP_DBG_OBJCNT is not set
-+# CONFIG_SCTP_HMAC_NONE is not set
-+# CONFIG_SCTP_HMAC_SHA1 is not set
-+CONFIG_SCTP_HMAC_MD5=y
++# CONFIG_IP_SCTP is not set
 +
 +#
 +# TIPC Configuration (EXPERIMENTAL)
 +#
 +# CONFIG_TIPC is not set
-+CONFIG_ATM=m
-+CONFIG_ATM_CLIP=m
-+# CONFIG_ATM_CLIP_NO_ICMP is not set
-+CONFIG_ATM_LANE=m
-+# CONFIG_ATM_MPOA is not set
-+CONFIG_ATM_BR2684=m
-+# CONFIG_ATM_BR2684_IPFILTER is not set
-+CONFIG_BRIDGE=m
-+CONFIG_VLAN_8021Q=m
++# CONFIG_ATM is not set
++CONFIG_BRIDGE=y
++# CONFIG_VLAN_8021Q is not set
 +# CONFIG_DECNET is not set
-+CONFIG_LLC=m
++CONFIG_LLC=y
 +# CONFIG_LLC2 is not set
-+CONFIG_IPX=m
-+# CONFIG_IPX_INTERN is not set
-+CONFIG_ATALK=m
-+CONFIG_DEV_APPLETALK=m
-+CONFIG_IPDDP=m
-+CONFIG_IPDDP_ENCAP=y
-+CONFIG_IPDDP_DECAP=y
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
 +# CONFIG_X25 is not set
 +# CONFIG_LAPB is not set
 +# CONFIG_ECONET is not set
-+CONFIG_WAN_ROUTER=m
++# CONFIG_WAN_ROUTER is not set
 +
 +#
 +# QoS and/or fair queueing
 +#
-+CONFIG_NET_SCHED=y
-+CONFIG_NET_SCH_CLK_JIFFIES=y
-+# CONFIG_NET_SCH_CLK_GETTIMEOFDAY is not set
-+# CONFIG_NET_SCH_CLK_CPU is not set
-+
-+#
-+# Queueing/Scheduling
-+#
-+CONFIG_NET_SCH_CBQ=m
-+CONFIG_NET_SCH_HTB=m
-+CONFIG_NET_SCH_HFSC=m
-+CONFIG_NET_SCH_ATM=m
-+CONFIG_NET_SCH_PRIO=m
-+CONFIG_NET_SCH_RED=m
-+CONFIG_NET_SCH_SFQ=m
-+CONFIG_NET_SCH_TEQL=m
-+CONFIG_NET_SCH_TBF=m
-+CONFIG_NET_SCH_GRED=m
-+CONFIG_NET_SCH_DSMARK=m
-+CONFIG_NET_SCH_NETEM=m
-+CONFIG_NET_SCH_INGRESS=m
-+
-+#
-+# Classification
-+#
-+CONFIG_NET_CLS=y
-+# CONFIG_NET_CLS_BASIC is not set
-+CONFIG_NET_CLS_TCINDEX=m
-+CONFIG_NET_CLS_ROUTE4=m
-+CONFIG_NET_CLS_ROUTE=y
-+CONFIG_NET_CLS_FW=m
-+CONFIG_NET_CLS_U32=m
-+CONFIG_CLS_U32_PERF=y
-+# CONFIG_CLS_U32_MARK is not set
-+CONFIG_NET_CLS_RSVP=m
-+CONFIG_NET_CLS_RSVP6=m
-+# CONFIG_NET_EMATCH is not set
-+# CONFIG_NET_CLS_ACT is not set
-+CONFIG_NET_CLS_POLICE=y
-+CONFIG_NET_CLS_IND=y
-+CONFIG_NET_ESTIMATOR=y
++# CONFIG_NET_SCHED is not set
 +
 +#
 +# Network testing
 +#
 +# CONFIG_NET_PKTGEN is not set
 +# CONFIG_HAMRADIO is not set
-+CONFIG_IRDA=m
-+
-+#
-+# IrDA protocols
-+#
-+CONFIG_IRLAN=m
-+CONFIG_IRNET=m
-+CONFIG_IRCOMM=m
-+# CONFIG_IRDA_ULTRA is not set
-+
-+#
-+# IrDA options
-+#
-+CONFIG_IRDA_CACHE_LAST_LSAP=y
-+CONFIG_IRDA_FAST_RR=y
-+# CONFIG_IRDA_DEBUG is not set
-+
-+#
-+# Infrared-port device drivers
-+#
-+
-+#
-+# SIR device drivers
-+#
-+CONFIG_IRTTY_SIR=m
-+
-+#
-+# Dongle support
-+#
-+CONFIG_DONGLE=y
-+CONFIG_ESI_DONGLE=m
-+CONFIG_ACTISYS_DONGLE=m
-+CONFIG_TEKRAM_DONGLE=m
-+# CONFIG_TOIM3232_DONGLE is not set
-+CONFIG_LITELINK_DONGLE=m
-+CONFIG_MA600_DONGLE=m
-+CONFIG_GIRBIL_DONGLE=m
-+CONFIG_MCP2120_DONGLE=m
-+CONFIG_OLD_BELKIN_DONGLE=m
-+CONFIG_ACT200L_DONGLE=m
-+
-+#
-+# Old SIR device drivers
-+#
-+
-+#
-+# Old Serial dongle support
-+#
-+
-+#
-+# FIR device drivers
-+#
-+# CONFIG_NSC_FIR is not set
-+# CONFIG_WINBOND_FIR is not set
-+# CONFIG_SMC_IRCC_FIR is not set
-+# CONFIG_ALI_FIR is not set
-+# CONFIG_VIA_FIR is not set
-+CONFIG_BT=m
-+CONFIG_BT_L2CAP=m
-+CONFIG_BT_SCO=m
-+CONFIG_BT_RFCOMM=m
-+CONFIG_BT_RFCOMM_TTY=y
-+CONFIG_BT_BNEP=m
-+CONFIG_BT_BNEP_MC_FILTER=y
-+CONFIG_BT_BNEP_PROTO_FILTER=y
-+CONFIG_BT_HIDP=m
-+
-+#
-+# Bluetooth device drivers
-+#
-+CONFIG_BT_HCIUART=m
-+CONFIG_BT_HCIUART_H4=y
-+CONFIG_BT_HCIUART_BCSP=y
-+CONFIG_BT_HCIVHCI=m
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
 +# CONFIG_IEEE80211 is not set
-+CONFIG_WIRELESS_EXT=y
 +
 +#
 +# Device Drivers
@@ -65334,18 +65157,25 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Plug and Play support
 +#
++# CONFIG_PNP is not set
 +
 +#
 +# Block devices
 +#
-+CONFIG_BLK_DEV_FD=m
++# CONFIG_BLK_CPQ_DA is not set
++CONFIG_BLK_CPQ_CISS_DA=y
++# CONFIG_CISS_SCSI_TAPE is not set
++# CONFIG_BLK_DEV_DAC960 is not set
++# CONFIG_BLK_DEV_UMEM is not set
 +# CONFIG_BLK_DEV_COW_COMMON is not set
-+CONFIG_BLK_DEV_LOOP=m
-+CONFIG_BLK_DEV_CRYPTOLOOP=m
++CONFIG_BLK_DEV_LOOP=y
++CONFIG_BLK_DEV_CRYPTOLOOP=y
 +CONFIG_BLK_DEV_NBD=m
++# CONFIG_BLK_DEV_SX8 is not set
++# CONFIG_BLK_DEV_UB is not set
 +CONFIG_BLK_DEV_RAM=y
 +CONFIG_BLK_DEV_RAM_COUNT=16
-+CONFIG_BLK_DEV_RAM_SIZE=16384
++CONFIG_BLK_DEV_RAM_SIZE=4096
 +CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 +CONFIG_BLK_DEV_INITRD=y
 +# CONFIG_CDROM_PKTCDVD is not set
@@ -65354,88 +65184,183 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# ATA/ATAPI/MFM/RLL support
 +#
-+# CONFIG_IDE is not set
++CONFIG_IDE=y
++CONFIG_IDE_MAX_HWIFS=4
++CONFIG_BLK_DEV_IDE=y
++
++#
++# Please see Documentation/ide.txt for help/info on IDE drives
++#
++# CONFIG_BLK_DEV_IDE_SATA is not set
++CONFIG_BLK_DEV_IDEDISK=y
++# CONFIG_IDEDISK_MULTI_MODE is not set
++CONFIG_BLK_DEV_IDECD=y
++# CONFIG_BLK_DEV_IDETAPE is not set
++CONFIG_BLK_DEV_IDEFLOPPY=y
++CONFIG_BLK_DEV_IDESCSI=y
++# CONFIG_IDE_TASK_IOCTL is not set
++
++#
++# IDE chipset support/bugfixes
++#
++# CONFIG_IDE_GENERIC is not set
++CONFIG_BLK_DEV_IDEPCI=y
++# CONFIG_IDEPCI_SHARE_IRQ is not set
++# CONFIG_BLK_DEV_OFFBOARD is not set
++CONFIG_BLK_DEV_GENERIC=y
++# CONFIG_BLK_DEV_OPTI621 is not set
++CONFIG_BLK_DEV_IDEDMA_PCI=y
++# CONFIG_BLK_DEV_IDEDMA_FORCED is not set
++CONFIG_IDEDMA_PCI_AUTO=y
++# CONFIG_IDEDMA_ONLYDISK is not set
++# CONFIG_BLK_DEV_AEC62XX is not set
++# CONFIG_BLK_DEV_ALI15X3 is not set
++# CONFIG_BLK_DEV_AMD74XX is not set
++CONFIG_BLK_DEV_CMD64X=y
++# CONFIG_BLK_DEV_TRIFLEX is not set
++# CONFIG_BLK_DEV_CY82C693 is not set
++# CONFIG_BLK_DEV_CS5520 is not set
++# CONFIG_BLK_DEV_CS5530 is not set
++# CONFIG_BLK_DEV_HPT34X is not set
++# CONFIG_BLK_DEV_HPT366 is not set
++# CONFIG_BLK_DEV_SC1200 is not set
++CONFIG_BLK_DEV_PIIX=y
++# CONFIG_BLK_DEV_IT821X is not set
++# CONFIG_BLK_DEV_NS87415 is not set
++# CONFIG_BLK_DEV_PDC202XX_OLD is not set
++# CONFIG_BLK_DEV_PDC202XX_NEW is not set
++# CONFIG_BLK_DEV_SVWKS is not set
++# CONFIG_BLK_DEV_SIIMAGE is not set
++# CONFIG_BLK_DEV_SLC90E66 is not set
++# CONFIG_BLK_DEV_TRM290 is not set
++# CONFIG_BLK_DEV_VIA82CXXX is not set
++# CONFIG_IDE_ARM is not set
++CONFIG_BLK_DEV_IDEDMA=y
++# CONFIG_IDEDMA_IVB is not set
++CONFIG_IDEDMA_AUTO=y
++# CONFIG_BLK_DEV_HD is not set
 +
 +#
 +# SCSI device support
 +#
 +# CONFIG_RAID_ATTRS is not set
-+CONFIG_SCSI=m
++CONFIG_SCSI=y
 +CONFIG_SCSI_PROC_FS=y
 +
 +#
 +# SCSI support type (disk, tape, CD-ROM)
 +#
-+CONFIG_BLK_DEV_SD=m
-+CONFIG_CHR_DEV_ST=m
-+CONFIG_CHR_DEV_OSST=m
-+CONFIG_BLK_DEV_SR=m
++CONFIG_BLK_DEV_SD=y
++CONFIG_CHR_DEV_ST=y
++CONFIG_CHR_DEV_OSST=y
++CONFIG_BLK_DEV_SR=y
 +CONFIG_BLK_DEV_SR_VENDOR=y
-+CONFIG_CHR_DEV_SG=m
++CONFIG_CHR_DEV_SG=y
 +# CONFIG_CHR_DEV_SCH is not set
 +
 +#
 +# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 +#
-+# CONFIG_SCSI_MULTI_LUN is not set
++CONFIG_SCSI_MULTI_LUN=y
 +CONFIG_SCSI_CONSTANTS=y
 +CONFIG_SCSI_LOGGING=y
 +
 +#
 +# SCSI Transport Attributes
 +#
-+CONFIG_SCSI_SPI_ATTRS=m
-+CONFIG_SCSI_FC_ATTRS=m
++CONFIG_SCSI_SPI_ATTRS=y
++CONFIG_SCSI_FC_ATTRS=y
 +# CONFIG_SCSI_ISCSI_ATTRS is not set
-+# CONFIG_SCSI_SAS_ATTRS is not set
++CONFIG_SCSI_SAS_ATTRS=y
 +
 +#
 +# SCSI low-level drivers
 +#
 +# CONFIG_ISCSI_TCP is not set
-+CONFIG_SCSI_SATA=m
++# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
++# CONFIG_SCSI_3W_9XXX is not set
++# CONFIG_SCSI_ACARD is not set
++# CONFIG_SCSI_AACRAID is not set
++# CONFIG_SCSI_AIC7XXX is not set
++# CONFIG_SCSI_AIC7XXX_OLD is not set
++# CONFIG_SCSI_AIC79XX is not set
++# CONFIG_MEGARAID_NEWGEN is not set
++# CONFIG_MEGARAID_LEGACY is not set
++# CONFIG_MEGARAID_SAS is not set
++# CONFIG_SCSI_SATA is not set
++# CONFIG_SCSI_HPTIOP is not set
++# CONFIG_SCSI_DMX3191D is not set
++# CONFIG_SCSI_FUTURE_DOMAIN is not set
++# CONFIG_SCSI_IPS is not set
++# CONFIG_SCSI_INITIO is not set
++# CONFIG_SCSI_INIA100 is not set
++CONFIG_SCSI_SYM53C8XX_2=y
++CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
++CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
++CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
++CONFIG_SCSI_SYM53C8XX_MMIO=y
++# CONFIG_SCSI_IPR is not set
++CONFIG_SCSI_QLOGIC_1280=y
++# CONFIG_SCSI_QLA_FC is not set
++# CONFIG_SCSI_LPFC is not set
++# CONFIG_SCSI_DC395x is not set
++# CONFIG_SCSI_DC390T is not set
 +# CONFIG_SCSI_DEBUG is not set
 +
 +#
 +# Multi-device support (RAID and LVM)
 +#
 +CONFIG_MD=y
-+CONFIG_BLK_DEV_MD=y
-+CONFIG_MD_LINEAR=m
-+CONFIG_MD_RAID0=m
-+CONFIG_MD_RAID1=m
-+CONFIG_MD_RAID10=m
-+# CONFIG_MD_RAID456 is not set
-+CONFIG_MD_MULTIPATH=m
-+# CONFIG_MD_FAULTY is not set
-+CONFIG_BLK_DEV_DM=m
++# CONFIG_BLK_DEV_MD is not set
++CONFIG_BLK_DEV_DM=y
 +CONFIG_DM_CRYPT=m
-+CONFIG_DM_SNAPSHOT=m
++CONFIG_DM_SNAPSHOT=y
 +CONFIG_DM_MIRROR=m
 +CONFIG_DM_ZERO=m
-+# CONFIG_DM_MULTIPATH is not set
++CONFIG_DM_MULTIPATH=m
++CONFIG_DM_MULTIPATH_EMC=m
 +
 +#
 +# Fusion MPT device support
 +#
-+# CONFIG_FUSION is not set
++CONFIG_FUSION=y
++CONFIG_FUSION_SPI=y
++# CONFIG_FUSION_FC is not set
++CONFIG_FUSION_SAS=y
++CONFIG_FUSION_MAX_SGE=128
++# CONFIG_FUSION_CTL is not set
 +
 +#
 +# IEEE 1394 (FireWire) support
 +#
++# CONFIG_IEEE1394 is not set
 +
 +#
 +# I2O device support
 +#
++# CONFIG_I2O is not set
 +
 +#
 +# Network device support
 +#
 +CONFIG_NETDEVICES=y
-+CONFIG_DUMMY=m
-+CONFIG_BONDING=m
-+CONFIG_EQUALIZER=m
-+CONFIG_TUN=m
++CONFIG_DUMMY=y
++# CONFIG_BONDING is not set
++# CONFIG_EQUALIZER is not set
++CONFIG_TUN=y
++
++#
++# ARCnet devices
++#
++CONFIG_ARCNET=y
++# CONFIG_ARCNET_1201 is not set
++# CONFIG_ARCNET_1051 is not set
++# CONFIG_ARCNET_RAW is not set
++# CONFIG_ARCNET_CAP is not set
++# CONFIG_ARCNET_COM90xx is not set
++# CONFIG_ARCNET_COM90xxIO is not set
++# CONFIG_ARCNET_RIM_I is not set
++# CONFIG_ARCNET_COM20020 is not set
 +
 +#
 +# PHY device support
@@ -65446,64 +65371,115 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Ethernet (10 or 100Mbit)
 +#
 +CONFIG_NET_ETHERNET=y
-+CONFIG_MII=m
++CONFIG_MII=y
++# CONFIG_HAPPYMEAL is not set
++# CONFIG_SUNGEM is not set
++# CONFIG_CASSINI is not set
++# CONFIG_NET_VENDOR_3COM is not set
++
++#
++# Tulip family network device support
++#
++CONFIG_NET_TULIP=y
++# CONFIG_DE2104X is not set
++CONFIG_TULIP=y
++CONFIG_TULIP_MWI=y
++CONFIG_TULIP_MMIO=y
++CONFIG_TULIP_NAPI=y
++CONFIG_TULIP_NAPI_HW_MITIGATION=y
++# CONFIG_DE4X5 is not set
++# CONFIG_WINBOND_840 is not set
++# CONFIG_DM9102 is not set
++# CONFIG_ULI526X is not set
++# CONFIG_HP100 is not set
++CONFIG_NET_PCI=y
++# CONFIG_PCNET32 is not set
++# CONFIG_AMD8111_ETH is not set
++# CONFIG_ADAPTEC_STARFIRE is not set
++# CONFIG_B44 is not set
++# CONFIG_FORCEDETH is not set
++# CONFIG_DGRS is not set
++CONFIG_EEPRO100=y
++CONFIG_E100=y
++# CONFIG_FEALNX is not set
++# CONFIG_NATSEMI is not set
++# CONFIG_NE2K_PCI is not set
++# CONFIG_8139CP is not set
++# CONFIG_8139TOO is not set
++# CONFIG_SIS900 is not set
++# CONFIG_EPIC100 is not set
++# CONFIG_SUNDANCE is not set
++# CONFIG_VIA_RHINE is not set
 +
 +#
 +# Ethernet (1000 Mbit)
 +#
++# CONFIG_ACENIC is not set
++# CONFIG_DL2K is not set
++CONFIG_E1000=y
++# CONFIG_E1000_NAPI is not set
++# CONFIG_E1000_DISABLE_PACKET_SPLIT is not set
++# CONFIG_NS83820 is not set
++# CONFIG_HAMACHI is not set
++# CONFIG_YELLOWFIN is not set
++# CONFIG_R8169 is not set
++# CONFIG_SIS190 is not set
++# CONFIG_SKGE is not set
++# CONFIG_SKY2 is not set
++# CONFIG_SK98LIN is not set
++# CONFIG_VIA_VELOCITY is not set
++CONFIG_TIGON3=y
++# CONFIG_BNX2 is not set
 +
 +#
 +# Ethernet (10000 Mbit)
 +#
++# CONFIG_CHELSIO_T1 is not set
++# CONFIG_IXGB is not set
++# CONFIG_S2IO is not set
++# CONFIG_MYRI10GE is not set
++# CONFIG_SFC is not set
 +
 +#
 +# Token Ring devices
 +#
++# CONFIG_TR is not set
 +
 +#
 +# Wireless LAN (non-hamradio)
 +#
-+CONFIG_NET_RADIO=y
-+# CONFIG_NET_WIRELESS_RTNETLINK is not set
-+
-+#
-+# Obsolete Wireless cards support (pre-802.11)
-+#
-+# CONFIG_STRIP is not set
-+# CONFIG_HOSTAP is not set
++# CONFIG_NET_RADIO is not set
 +
 +#
 +# Wan interfaces
 +#
 +# CONFIG_WAN is not set
-+
-+#
-+# ATM drivers
-+#
-+# CONFIG_ATM_DUMMY is not set
-+CONFIG_ATM_TCP=m
-+CONFIG_PPP=m
-+CONFIG_PPP_MULTILINK=y
-+CONFIG_PPP_FILTER=y
-+CONFIG_PPP_ASYNC=m
-+CONFIG_PPP_SYNC_TTY=m
-+CONFIG_PPP_DEFLATE=m
-+# CONFIG_PPP_BSDCOMP is not set
-+# CONFIG_PPP_MPPE is not set
-+CONFIG_PPPOE=m
-+CONFIG_PPPOATM=m
++# CONFIG_FDDI is not set
++# CONFIG_HIPPI is not set
++# CONFIG_PPP is not set
 +# CONFIG_SLIP is not set
++# CONFIG_NET_FC is not set
 +# CONFIG_SHAPER is not set
-+CONFIG_NETCONSOLE=m
++CONFIG_NETCONSOLE=y
 +CONFIG_NETPOLL=y
 +# CONFIG_NETPOLL_RX is not set
-+CONFIG_NETPOLL_TRAP=y
++# CONFIG_NETPOLL_TRAP is not set
 +CONFIG_NET_POLL_CONTROLLER=y
 +
 +#
 +# ISDN subsystem
 +#
-+# CONFIG_ISDN is not set
++CONFIG_ISDN=m
++
++#
++# Old ISDN4Linux
++#
++# CONFIG_ISDN_I4L is not set
++
++#
++# CAPI subsystem
++#
++# CONFIG_ISDN_CAPI is not set
 +
 +#
 +# Telephony Support
@@ -65519,12 +65495,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Userland interfaces
 +#
 +CONFIG_INPUT_MOUSEDEV=y
-+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
++CONFIG_INPUT_MOUSEDEV_PSAUX=y
 +CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
 +CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
-+# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_JOYDEV=y
 +# CONFIG_INPUT_TSDEV is not set
-+# CONFIG_INPUT_EVDEV is not set
++CONFIG_INPUT_EVDEV=y
 +# CONFIG_INPUT_EVBUG is not set
 +
 +#
@@ -65536,7 +65512,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_KEYBOARD_LKKBD is not set
 +# CONFIG_KEYBOARD_XTKBD is not set
 +# CONFIG_KEYBOARD_NEWTON is not set
-+# CONFIG_INPUT_MOUSE is not set
++CONFIG_INPUT_MOUSE=y
++CONFIG_MOUSE_PS2=y
++# CONFIG_MOUSE_SERIAL is not set
++# CONFIG_MOUSE_VSXXXAA is not set
 +# CONFIG_INPUT_JOYSTICK is not set
 +# CONFIG_INPUT_TOUCHSCREEN is not set
 +# CONFIG_INPUT_MISC is not set
@@ -65546,11 +65525,15 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +CONFIG_SERIO=y
 +CONFIG_SERIO_I8042=y
-+CONFIG_SERIO_SERPORT=y
-+# CONFIG_SERIO_CT82C710 is not set
++# CONFIG_SERIO_SERPORT is not set
++# CONFIG_SERIO_PCIPS2 is not set
 +CONFIG_SERIO_LIBPS2=y
 +# CONFIG_SERIO_RAW is not set
-+# CONFIG_GAMEPORT is not set
++CONFIG_GAMEPORT=y
++# CONFIG_GAMEPORT_NS558 is not set
++# CONFIG_GAMEPORT_L4 is not set
++# CONFIG_GAMEPORT_EMU10K1 is not set
++# CONFIG_GAMEPORT_FM801 is not set
 +
 +#
 +# Character devices
@@ -65559,7 +65542,23 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_VT_CONSOLE=y
 +CONFIG_HW_CONSOLE=y
 +# CONFIG_VT_HW_CONSOLE_BINDING is not set
-+# CONFIG_SERIAL_NONSTANDARD is not set
++CONFIG_SERIAL_NONSTANDARD=y
++# CONFIG_COMPUTONE is not set
++# CONFIG_ROCKETPORT is not set
++# CONFIG_CYCLADES is not set
++# CONFIG_DIGIEPCA is not set
++# CONFIG_MOXA_INTELLIO is not set
++# CONFIG_MOXA_SMARTIO is not set
++# CONFIG_ISI is not set
++# CONFIG_SYNCLINKMP is not set
++# CONFIG_SYNCLINK_GT is not set
++# CONFIG_N_HDLC is not set
++# CONFIG_SPECIALIX is not set
++# CONFIG_SX is not set
++# CONFIG_RIO is not set
++# CONFIG_STALDRV is not set
++# CONFIG_SGI_SNSC is not set
++# CONFIG_SGI_TIOCX is not set
 +
 +#
 +# Serial drivers
@@ -65568,6 +65567,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Non-8250 serial port support
 +#
++# CONFIG_SERIAL_SGI_L1_CONSOLE is not set
++# CONFIG_SERIAL_JSM is not set
 +CONFIG_UNIX98_PTYS=y
 +CONFIG_LEGACY_PTYS=y
 +CONFIG_LEGACY_PTY_COUNT=256
@@ -65581,31 +65582,92 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Watchdog Cards
 +#
 +# CONFIG_WATCHDOG is not set
-+CONFIG_HW_RANDOM=y
-+# CONFIG_NVRAM is not set
-+# CONFIG_RTC is not set
-+# CONFIG_GEN_RTC is not set
++# CONFIG_HW_RANDOM is not set
++CONFIG_EFI_RTC=y
 +# CONFIG_DTLK is not set
 +# CONFIG_R3964 is not set
++# CONFIG_APPLICOM is not set
 +
 +#
 +# Ftape, the floppy tape device driver
 +#
-+# CONFIG_MWAVE is not set
-+# CONFIG_PC8736x_GPIO is not set
-+# CONFIG_RAW_DRIVER is not set
-+# CONFIG_HANGCHECK_TIMER is not set
-+
-+#
-+# TPM devices
-+#
-+# CONFIG_TCG_TPM is not set
-+# CONFIG_TELCLOCK is not set
++CONFIG_AGP=y
++# CONFIG_AGP_SIS is not set
++# CONFIG_AGP_VIA is not set
++CONFIG_AGP_I460=y
++# CONFIG_AGP_HP_ZX1 is not set
++# CONFIG_AGP_SGI_TIOCA is not set
++CONFIG_DRM=y
++# CONFIG_DRM_TDFX is not set
++# CONFIG_DRM_R128 is not set
++# CONFIG_DRM_RADEON is not set
++# CONFIG_DRM_MGA is not set
++# CONFIG_DRM_SIS is not set
++# CONFIG_DRM_VIA is not set
++# CONFIG_DRM_SAVAGE is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_HPET is not set
++# CONFIG_HANGCHECK_TIMER is not set
++# CONFIG_MMTIMER is not set
++
++#
++# TPM devices
++#
++# CONFIG_TCG_TPM is not set
++# CONFIG_TELCLOCK is not set
 +
 +#
 +# I2C support
 +#
-+# CONFIG_I2C is not set
++CONFIG_I2C=y
++CONFIG_I2C_CHARDEV=y
++
++#
++# I2C Algorithms
++#
++CONFIG_I2C_ALGOBIT=y
++CONFIG_I2C_ALGOPCF=y
++# CONFIG_I2C_ALGOPCA is not set
++
++#
++# I2C Hardware Bus support
++#
++# CONFIG_I2C_ALI1535 is not set
++# CONFIG_I2C_ALI1563 is not set
++# CONFIG_I2C_ALI15X3 is not set
++# CONFIG_I2C_AMD756 is not set
++# CONFIG_I2C_AMD8111 is not set
++# CONFIG_I2C_I801 is not set
++# CONFIG_I2C_I810 is not set
++# CONFIG_I2C_PIIX4 is not set
++# CONFIG_I2C_NFORCE2 is not set
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_PROSAVAGE is not set
++# CONFIG_I2C_SAVAGE4 is not set
++# CONFIG_I2C_SIS5595 is not set
++# CONFIG_I2C_SIS630 is not set
++# CONFIG_I2C_SIS96X is not set
++# CONFIG_I2C_STUB is not set
++# CONFIG_I2C_VIA is not set
++# CONFIG_I2C_VIAPRO is not set
++# CONFIG_I2C_VOODOO3 is not set
++# CONFIG_I2C_PCA_ISA is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_SENSORS_DS1337 is not set
++# CONFIG_SENSORS_DS1374 is not set
++# CONFIG_SENSORS_EEPROM is not set
++# CONFIG_SENSORS_PCF8574 is not set
++# CONFIG_SENSORS_PCA9539 is not set
++# CONFIG_SENSORS_PCF8591 is not set
++# CONFIG_SENSORS_MAX6875 is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
 +
 +#
 +# SPI support
@@ -65620,8 +65682,48 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Hardware Monitoring support
 +#
-+# CONFIG_HWMON is not set
++CONFIG_HWMON=y
 +# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_ABITUGURU is not set
++# CONFIG_SENSORS_ADM1021 is not set
++# CONFIG_SENSORS_ADM1025 is not set
++# CONFIG_SENSORS_ADM1026 is not set
++# CONFIG_SENSORS_ADM1031 is not set
++# CONFIG_SENSORS_ADM9240 is not set
++# CONFIG_SENSORS_ASB100 is not set
++# CONFIG_SENSORS_ATXP1 is not set
++# CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_FSCHER is not set
++# CONFIG_SENSORS_FSCPOS is not set
++# CONFIG_SENSORS_GL518SM is not set
++# CONFIG_SENSORS_GL520SM is not set
++# CONFIG_SENSORS_IT87 is not set
++# CONFIG_SENSORS_LM63 is not set
++# CONFIG_SENSORS_LM75 is not set
++# CONFIG_SENSORS_LM77 is not set
++# CONFIG_SENSORS_LM78 is not set
++# CONFIG_SENSORS_LM80 is not set
++# CONFIG_SENSORS_LM83 is not set
++# CONFIG_SENSORS_LM85 is not set
++# CONFIG_SENSORS_LM87 is not set
++# CONFIG_SENSORS_LM90 is not set
++# CONFIG_SENSORS_LM92 is not set
++# CONFIG_SENSORS_MAX1619 is not set
++# CONFIG_SENSORS_PC87360 is not set
++# CONFIG_SENSORS_SIS5595 is not set
++# CONFIG_SENSORS_SMSC47M1 is not set
++# CONFIG_SENSORS_SMSC47M192 is not set
++# CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_VIA686A is not set
++# CONFIG_SENSORS_VT8231 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
 +
 +#
 +# Misc devices
@@ -65630,18 +65732,115 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Multimedia devices
 +#
-+# CONFIG_VIDEO_DEV is not set
++CONFIG_VIDEO_DEV=y
++CONFIG_VIDEO_V4L1=y
++CONFIG_VIDEO_V4L1_COMPAT=y
++CONFIG_VIDEO_V4L2=y
++
++#
++# Video Capture Adapters
++#
++
++#
++# Video Capture Adapters
++#
++# CONFIG_VIDEO_ADV_DEBUG is not set
++# CONFIG_VIDEO_VIVI is not set
++# CONFIG_VIDEO_BT848 is not set
++# CONFIG_VIDEO_CPIA is not set
++# CONFIG_VIDEO_CPIA2 is not set
++# CONFIG_VIDEO_SAA5246A is not set
++# CONFIG_VIDEO_SAA5249 is not set
++# CONFIG_TUNER_3036 is not set
++# CONFIG_VIDEO_STRADIS is not set
++# CONFIG_VIDEO_ZORAN is not set
++# CONFIG_VIDEO_SAA7134 is not set
++# CONFIG_VIDEO_MXB is not set
++# CONFIG_VIDEO_DPC is not set
++# CONFIG_VIDEO_HEXIUM_ORION is not set
++# CONFIG_VIDEO_HEXIUM_GEMINI is not set
++# CONFIG_VIDEO_CX88 is not set
++
++#
++# Encoders and Decoders
++#
++# CONFIG_VIDEO_MSP3400 is not set
++# CONFIG_VIDEO_CS53L32A is not set
++# CONFIG_VIDEO_TLV320AIC23B is not set
++# CONFIG_VIDEO_WM8775 is not set
++# CONFIG_VIDEO_WM8739 is not set
++# CONFIG_VIDEO_CX2341X is not set
++# CONFIG_VIDEO_CX25840 is not set
++# CONFIG_VIDEO_SAA711X is not set
++# CONFIG_VIDEO_SAA7127 is not set
++# CONFIG_VIDEO_UPD64031A is not set
++# CONFIG_VIDEO_UPD64083 is not set
++
++#
++# V4L USB devices
++#
++# CONFIG_VIDEO_PVRUSB2 is not set
++# CONFIG_VIDEO_EM28XX is not set
++# CONFIG_USB_VICAM is not set
++# CONFIG_USB_IBMCAM is not set
++# CONFIG_USB_KONICAWC is not set
++# CONFIG_USB_QUICKCAM_MESSENGER is not set
++# CONFIG_USB_ET61X251 is not set
++# CONFIG_VIDEO_OVCAMCHIP is not set
++# CONFIG_USB_W9968CF is not set
++# CONFIG_USB_OV511 is not set
++# CONFIG_USB_SE401 is not set
++# CONFIG_USB_SN9C102 is not set
++# CONFIG_USB_STV680 is not set
++# CONFIG_USB_ZC0301 is not set
++# CONFIG_USB_PWC is not set
++
++#
++# Radio Adapters
++#
++# CONFIG_RADIO_GEMTEK_PCI is not set
++# CONFIG_RADIO_MAXIRADIO is not set
++# CONFIG_RADIO_MAESTRO is not set
++# CONFIG_USB_DSBR is not set
 +
 +#
 +# Digital Video Broadcasting Devices
 +#
 +# CONFIG_DVB is not set
++# CONFIG_USB_DABUSB is not set
 +
 +#
 +# Graphics support
 +#
 +CONFIG_FIRMWARE_EDID=y
-+# CONFIG_FB is not set
++CONFIG_FB=y
++CONFIG_FB_CFB_FILLRECT=y
++CONFIG_FB_CFB_COPYAREA=y
++CONFIG_FB_CFB_IMAGEBLIT=y
++# CONFIG_FB_MACMODES is not set
++# CONFIG_FB_BACKLIGHT is not set
++CONFIG_FB_MODE_HELPERS=y
++# CONFIG_FB_TILEBLITTING is not set
++# CONFIG_FB_CIRRUS is not set
++# CONFIG_FB_PM2 is not set
++# CONFIG_FB_CYBER2000 is not set
++# CONFIG_FB_ASILIANT is not set
++# CONFIG_FB_IMSTT is not set
++# CONFIG_FB_S1D13XXX is not set
++# CONFIG_FB_NVIDIA is not set
++# CONFIG_FB_RIVA is not set
++# CONFIG_FB_MATROX is not set
++# CONFIG_FB_RADEON is not set
++# CONFIG_FB_ATY128 is not set
++# CONFIG_FB_ATY is not set
++# CONFIG_FB_SAVAGE is not set
++# CONFIG_FB_SIS is not set
++# CONFIG_FB_NEOMAGIC is not set
++# CONFIG_FB_KYRO is not set
++# CONFIG_FB_3DFX is not set
++# CONFIG_FB_VOODOO1 is not set
++# CONFIG_FB_TRIDENT is not set
++# CONFIG_FB_VIRTUAL is not set
 +
 +#
 +# Console display driver support
@@ -65649,25 +65848,268 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_VGA_CONSOLE=y
 +# CONFIG_VGACON_SOFT_SCROLLBACK is not set
 +CONFIG_DUMMY_CONSOLE=y
++CONFIG_FRAMEBUFFER_CONSOLE=y
++# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
++# CONFIG_FONTS is not set
++CONFIG_FONT_8x8=y
++CONFIG_FONT_8x16=y
++
++#
++# Logo configuration
++#
++CONFIG_LOGO=y
++# CONFIG_LOGO_LINUX_MONO is not set
++# CONFIG_LOGO_LINUX_VGA16 is not set
++CONFIG_LOGO_LINUX_CLUT224=y
 +# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 +
 +#
 +# Sound
 +#
-+# CONFIG_SOUND is not set
++CONFIG_SOUND=y
++
++#
++# Advanced Linux Sound Architecture
++#
++CONFIG_SND=y
++CONFIG_SND_TIMER=y
++CONFIG_SND_PCM=y
++CONFIG_SND_HWDEP=y
++CONFIG_SND_RAWMIDI=y
++CONFIG_SND_SEQUENCER=y
++CONFIG_SND_SEQ_DUMMY=y
++CONFIG_SND_OSSEMUL=y
++CONFIG_SND_MIXER_OSS=y
++CONFIG_SND_PCM_OSS=y
++CONFIG_SND_PCM_OSS_PLUGINS=y
++CONFIG_SND_SEQUENCER_OSS=y
++# CONFIG_SND_DYNAMIC_MINORS is not set
++CONFIG_SND_SUPPORT_OLD_API=y
++CONFIG_SND_VERBOSE_PROCFS=y
++# CONFIG_SND_VERBOSE_PRINTK is not set
++# CONFIG_SND_DEBUG is not set
++
++#
++# Generic devices
++#
++CONFIG_SND_MPU401_UART=y
++CONFIG_SND_OPL3_LIB=y
++CONFIG_SND_AC97_CODEC=y
++CONFIG_SND_AC97_BUS=y
++CONFIG_SND_DUMMY=y
++CONFIG_SND_VIRMIDI=y
++# CONFIG_SND_MTPAV is not set
++CONFIG_SND_SERIAL_U16550=y
++CONFIG_SND_MPU401=y
++
++#
++# PCI devices
++#
++# CONFIG_SND_AD1889 is not set
++# CONFIG_SND_ALS300 is not set
++# CONFIG_SND_ALI5451 is not set
++CONFIG_SND_ATIIXP=y
++# CONFIG_SND_ATIIXP_MODEM is not set
++# CONFIG_SND_AU8810 is not set
++# CONFIG_SND_AU8820 is not set
++# CONFIG_SND_AU8830 is not set
++# CONFIG_SND_AZT3328 is not set
++# CONFIG_SND_BT87X is not set
++# CONFIG_SND_CA0106 is not set
++# CONFIG_SND_CMIPCI is not set
++# CONFIG_SND_CS4281 is not set
++# CONFIG_SND_CS46XX is not set
++# CONFIG_SND_DARLA20 is not set
++# CONFIG_SND_GINA20 is not set
++# CONFIG_SND_LAYLA20 is not set
++# CONFIG_SND_DARLA24 is not set
++# CONFIG_SND_GINA24 is not set
++# CONFIG_SND_LAYLA24 is not set
++# CONFIG_SND_MONA is not set
++# CONFIG_SND_MIA is not set
++# CONFIG_SND_ECHO3G is not set
++# CONFIG_SND_INDIGO is not set
++# CONFIG_SND_INDIGOIO is not set
++# CONFIG_SND_INDIGODJ is not set
++# CONFIG_SND_EMU10K1 is not set
++# CONFIG_SND_EMU10K1X is not set
++# CONFIG_SND_ENS1370 is not set
++# CONFIG_SND_ENS1371 is not set
++# CONFIG_SND_ES1938 is not set
++# CONFIG_SND_ES1968 is not set
++CONFIG_SND_FM801=y
++# CONFIG_SND_FM801_TEA575X_BOOL is not set
++# CONFIG_SND_HDA_INTEL is not set
++# CONFIG_SND_HDSP is not set
++# CONFIG_SND_HDSPM is not set
++# CONFIG_SND_ICE1712 is not set
++# CONFIG_SND_ICE1724 is not set
++# CONFIG_SND_INTEL8X0 is not set
++# CONFIG_SND_INTEL8X0M is not set
++# CONFIG_SND_KORG1212 is not set
++# CONFIG_SND_MAESTRO3 is not set
++# CONFIG_SND_MIXART is not set
++# CONFIG_SND_NM256 is not set
++# CONFIG_SND_PCXHR is not set
++# CONFIG_SND_RIPTIDE is not set
++# CONFIG_SND_RME32 is not set
++# CONFIG_SND_RME96 is not set
++# CONFIG_SND_RME9652 is not set
++# CONFIG_SND_SONICVIBES is not set
++# CONFIG_SND_TRIDENT is not set
++# CONFIG_SND_VIA82XX is not set
++# CONFIG_SND_VIA82XX_MODEM is not set
++# CONFIG_SND_VX222 is not set
++# CONFIG_SND_YMFPCI is not set
++
++#
++# USB devices
++#
++# CONFIG_SND_USB_AUDIO is not set
++
++#
++# Open Sound System
++#
++CONFIG_SOUND_PRIME=y
++# CONFIG_OSS_OBSOLETE_DRIVER is not set
++# CONFIG_SOUND_BT878 is not set
++# CONFIG_SOUND_ES1371 is not set
++# CONFIG_SOUND_ICH is not set
++# CONFIG_SOUND_TRIDENT is not set
++# CONFIG_SOUND_MSNDCLAS is not set
++# CONFIG_SOUND_MSNDPIN is not set
++# CONFIG_SOUND_VIA82CXXX is not set
++# CONFIG_SOUND_TVMIXER is not set
 +
 +#
 +# USB support
 +#
-+# CONFIG_USB_ARCH_HAS_HCD is not set
-+# CONFIG_USB_ARCH_HAS_OHCI is not set
-+# CONFIG_USB_ARCH_HAS_EHCI is not set
++CONFIG_USB_ARCH_HAS_HCD=y
++CONFIG_USB_ARCH_HAS_OHCI=y
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB=y
++# CONFIG_USB_DEBUG is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++CONFIG_USB_BANDWIDTH=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++# CONFIG_USB_SUSPEND is not set
++# CONFIG_USB_OTG is not set
++
++#
++# USB Host Controller Drivers
++#
++CONFIG_USB_EHCI_HCD=y
++# CONFIG_USB_EHCI_SPLIT_ISO is not set
++# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
++# CONFIG_USB_EHCI_TT_NEWSCHED is not set
++# CONFIG_USB_ISP116X_HCD is not set
++CONFIG_USB_OHCI_HCD=y
++# CONFIG_USB_OHCI_BIG_ENDIAN is not set
++CONFIG_USB_OHCI_LITTLE_ENDIAN=y
++CONFIG_USB_UHCI_HCD=y
++# CONFIG_USB_SL811_HCD is not set
++
++#
++# USB Device Class drivers
++#
++# CONFIG_USB_ACM is not set
++# CONFIG_USB_PRINTER is not set
 +
 +#
 +# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
 +#
 +
 +#
++# may also be needed; see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=y
++# CONFIG_USB_STORAGE_DEBUG is not set
++# CONFIG_USB_STORAGE_DATAFAB is not set
++# CONFIG_USB_STORAGE_FREECOM is not set
++# CONFIG_USB_STORAGE_ISD200 is not set
++# CONFIG_USB_STORAGE_DPCM is not set
++# CONFIG_USB_STORAGE_USBAT is not set
++# CONFIG_USB_STORAGE_SDDR09 is not set
++# CONFIG_USB_STORAGE_SDDR55 is not set
++# CONFIG_USB_STORAGE_JUMPSHOT is not set
++# CONFIG_USB_STORAGE_ALAUDA is not set
++# CONFIG_USB_LIBUSUAL is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=y
++CONFIG_USB_HIDINPUT=y
++# CONFIG_USB_HIDINPUT_POWERBOOK is not set
++# CONFIG_HID_FF is not set
++CONFIG_USB_HIDDEV=y
++# CONFIG_USB_AIPTEK is not set
++# CONFIG_USB_WACOM is not set
++# CONFIG_USB_ACECAD is not set
++# CONFIG_USB_KBTAB is not set
++# CONFIG_USB_POWERMATE is not set
++# CONFIG_USB_TOUCHSCREEN is not set
++# CONFIG_USB_YEALINK is not set
++# CONFIG_USB_XPAD is not set
++# CONFIG_USB_ATI_REMOTE is not set
++# CONFIG_USB_ATI_REMOTE2 is not set
++# CONFIG_USB_KEYSPAN_REMOTE is not set
++# CONFIG_USB_APPLETOUCH is not set
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++# CONFIG_USB_USBNET is not set
++CONFIG_USB_MON=y
++
++#
++# USB port drivers
++#
++
++#
++# USB Serial Converter support
++#
++# CONFIG_USB_SERIAL is not set
++
++#
++# USB Miscellaneous drivers
++#
++# CONFIG_USB_EMI62 is not set
++# CONFIG_USB_EMI26 is not set
++# CONFIG_USB_AUERSWALD is not set
++# CONFIG_USB_RIO500 is not set
++# CONFIG_USB_LEGOTOWER is not set
++# CONFIG_USB_LCD is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGETKIT is not set
++# CONFIG_USB_PHIDGETSERVO is not set
++# CONFIG_USB_IDMOUSE is not set
++# CONFIG_USB_APPLEDISPLAY is not set
++# CONFIG_USB_SISUSBVGA is not set
++# CONFIG_USB_LD is not set
++# CONFIG_USB_TEST is not set
++
++#
++# USB DSL modem support
++#
++
++#
 +# USB Gadget Support
 +#
 +# CONFIG_USB_GADGET is not set
@@ -65693,11 +66135,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# InfiniBand support
 +#
++# CONFIG_INFINIBAND is not set
 +
 +#
 +# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
 +#
-+# CONFIG_EDAC is not set
 +
 +#
 +# Real Time Clock
@@ -65718,13 +66160,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +
 +#
-+# Firmware Drivers
-+#
-+# CONFIG_EDD is not set
-+# CONFIG_DELL_RBU is not set
-+# CONFIG_DCDBAS is not set
-+
-+#
 +# File systems
 +#
 +CONFIG_EXT2_FS=y
@@ -65734,40 +66169,33 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# CONFIG_EXT2_FS_XIP is not set
 +CONFIG_EXT3_FS=y
 +CONFIG_EXT3_FS_XATTR=y
-+# CONFIG_EXT3_FS_POSIX_ACL is not set
-+# CONFIG_EXT3_FS_SECURITY is not set
++CONFIG_EXT3_FS_POSIX_ACL=y
++CONFIG_EXT3_FS_SECURITY=y
 +CONFIG_JBD=y
 +# CONFIG_JBD_DEBUG is not set
 +CONFIG_FS_MBCACHE=y
 +CONFIG_REISERFS_FS=y
 +# CONFIG_REISERFS_CHECK is not set
-+CONFIG_REISERFS_PROC_INFO=y
++# CONFIG_REISERFS_PROC_INFO is not set
 +CONFIG_REISERFS_FS_XATTR=y
 +CONFIG_REISERFS_FS_POSIX_ACL=y
 +CONFIG_REISERFS_FS_SECURITY=y
-+CONFIG_JFS_FS=m
-+CONFIG_JFS_POSIX_ACL=y
-+# CONFIG_JFS_SECURITY is not set
-+# CONFIG_JFS_DEBUG is not set
-+# CONFIG_JFS_STATISTICS is not set
++# CONFIG_JFS_FS is not set
 +CONFIG_FS_POSIX_ACL=y
-+CONFIG_XFS_FS=m
++CONFIG_XFS_FS=y
 +# CONFIG_XFS_QUOTA is not set
-+CONFIG_XFS_SECURITY=y
-+CONFIG_XFS_POSIX_ACL=y
++# CONFIG_XFS_SECURITY is not set
++# CONFIG_XFS_POSIX_ACL is not set
 +# CONFIG_XFS_RT is not set
 +# CONFIG_OCFS2_FS is not set
-+CONFIG_MINIX_FS=m
-+CONFIG_ROMFS_FS=m
++# CONFIG_MINIX_FS is not set
++# CONFIG_ROMFS_FS is not set
 +CONFIG_INOTIFY=y
 +CONFIG_INOTIFY_USER=y
-+CONFIG_QUOTA=y
-+# CONFIG_QFMT_V1 is not set
-+CONFIG_QFMT_V2=y
-+CONFIG_QUOTACTL=y
++# CONFIG_QUOTA is not set
 +CONFIG_DNOTIFY=y
-+CONFIG_AUTOFS_FS=m
-+CONFIG_AUTOFS4_FS=m
++CONFIG_AUTOFS_FS=y
++CONFIG_AUTOFS4_FS=y
 +# CONFIG_FUSE_FS is not set
 +
 +#
@@ -65775,19 +66203,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +CONFIG_ISO9660_FS=y
 +CONFIG_JOLIET=y
-+CONFIG_ZISOFS=y
-+CONFIG_ZISOFS_FS=y
-+CONFIG_UDF_FS=m
++# CONFIG_ZISOFS is not set
++CONFIG_UDF_FS=y
 +CONFIG_UDF_NLS=y
 +
 +#
 +# DOS/FAT/NT Filesystems
 +#
-+CONFIG_FAT_FS=m
-+CONFIG_MSDOS_FS=m
-+CONFIG_VFAT_FS=m
++CONFIG_FAT_FS=y
++CONFIG_MSDOS_FS=y
++CONFIG_VFAT_FS=y
 +CONFIG_FAT_DEFAULT_CODEPAGE=437
-+CONFIG_FAT_DEFAULT_IOCHARSET="ascii"
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
 +# CONFIG_NTFS_FS is not set
 +
 +#
@@ -65795,6 +66222,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +CONFIG_PROC_FS=y
 +CONFIG_PROC_KCORE=y
++CONFIG_PROC_IOMEM_MACHINE=y
 +CONFIG_SYSFS=y
 +CONFIG_TMPFS=y
 +# CONFIG_HUGETLB_PAGE is not set
@@ -65805,61 +66233,51 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Miscellaneous filesystems
 +#
 +# CONFIG_ADFS_FS is not set
-+CONFIG_AFFS_FS=m
-+CONFIG_HFS_FS=m
-+CONFIG_HFSPLUS_FS=m
-+CONFIG_BEFS_FS=m
-+# CONFIG_BEFS_DEBUG is not set
-+CONFIG_BFS_FS=m
-+CONFIG_EFS_FS=m
-+CONFIG_CRAMFS=y
-+CONFIG_VXFS_FS=m
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++# CONFIG_CRAMFS is not set
++# CONFIG_VXFS_FS is not set
 +# CONFIG_HPFS_FS is not set
-+CONFIG_QNX4FS_FS=m
-+CONFIG_SYSV_FS=m
-+CONFIG_UFS_FS=m
-+# CONFIG_UFS_FS_WRITE is not set
-+# CONFIG_UFS_DEBUG is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
 +
 +#
 +# Network File Systems
 +#
-+CONFIG_NFS_FS=m
++CONFIG_NFS_FS=y
 +CONFIG_NFS_V3=y
 +# CONFIG_NFS_V3_ACL is not set
 +CONFIG_NFS_V4=y
 +CONFIG_NFS_DIRECTIO=y
-+CONFIG_NFSD=m
++CONFIG_NFSD=y
 +CONFIG_NFSD_V3=y
 +# CONFIG_NFSD_V3_ACL is not set
 +CONFIG_NFSD_V4=y
 +CONFIG_NFSD_TCP=y
-+CONFIG_LOCKD=m
++CONFIG_ROOT_NFS=y
++CONFIG_LOCKD=y
 +CONFIG_LOCKD_V4=y
-+CONFIG_EXPORTFS=m
++CONFIG_EXPORTFS=y
 +CONFIG_NFS_COMMON=y
-+CONFIG_SUNRPC=m
-+CONFIG_SUNRPC_GSS=m
-+CONFIG_RPCSEC_GSS_KRB5=m
-+CONFIG_RPCSEC_GSS_SPKM3=m
-+CONFIG_SMB_FS=m
-+# CONFIG_SMB_NLS_DEFAULT is not set
-+CONFIG_CIFS=m
++CONFIG_SUNRPC=y
++CONFIG_SUNRPC_GSS=y
++CONFIG_RPCSEC_GSS_KRB5=y
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++CONFIG_SMB_FS=y
++CONFIG_SMB_NLS_DEFAULT=y
++CONFIG_SMB_NLS_REMOTE="cp437"
++CONFIG_CIFS=y
 +# CONFIG_CIFS_STATS is not set
 +# CONFIG_CIFS_WEAK_PW_HASH is not set
-+CONFIG_CIFS_XATTR=y
-+CONFIG_CIFS_POSIX=y
++# CONFIG_CIFS_XATTR is not set
 +# CONFIG_CIFS_DEBUG2 is not set
 +# CONFIG_CIFS_EXPERIMENTAL is not set
-+CONFIG_NCP_FS=m
-+CONFIG_NCPFS_PACKET_SIGNING=y
-+CONFIG_NCPFS_IOCTL_LOCKING=y
-+CONFIG_NCPFS_STRONG=y
-+CONFIG_NCPFS_NFS_NS=y
-+CONFIG_NCPFS_OS2_NS=y
-+CONFIG_NCPFS_SMALLDOS=y
-+CONFIG_NCPFS_NLS=y
-+CONFIG_NCPFS_EXTRAS=y
++# CONFIG_NCP_FS is not set
 +# CONFIG_CODA_FS is not set
 +# CONFIG_AFS_FS is not set
 +# CONFIG_9P_FS is not set
@@ -65869,19 +66287,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +CONFIG_PARTITION_ADVANCED=y
 +# CONFIG_ACORN_PARTITION is not set
-+CONFIG_OSF_PARTITION=y
++# CONFIG_OSF_PARTITION is not set
 +# CONFIG_AMIGA_PARTITION is not set
 +# CONFIG_ATARI_PARTITION is not set
-+CONFIG_MAC_PARTITION=y
++# CONFIG_MAC_PARTITION is not set
 +CONFIG_MSDOS_PARTITION=y
-+CONFIG_BSD_DISKLABEL=y
-+CONFIG_MINIX_SUBPARTITION=y
-+CONFIG_SOLARIS_X86_PARTITION=y
-+CONFIG_UNIXWARE_DISKLABEL=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
 +# CONFIG_LDM_PARTITION is not set
 +CONFIG_SGI_PARTITION=y
 +# CONFIG_ULTRIX_PARTITION is not set
-+CONFIG_SUN_PARTITION=y
++# CONFIG_SUN_PARTITION is not set
 +# CONFIG_KARMA_PARTITION is not set
 +CONFIG_EFI_PARTITION=y
 +
@@ -65889,45 +66307,65 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Native Language Support
 +#
 +CONFIG_NLS=y
-+CONFIG_NLS_DEFAULT="utf8"
++CONFIG_NLS_DEFAULT="iso8859-1"
 +CONFIG_NLS_CODEPAGE_437=y
-+CONFIG_NLS_CODEPAGE_737=m
-+CONFIG_NLS_CODEPAGE_775=m
-+CONFIG_NLS_CODEPAGE_850=m
-+CONFIG_NLS_CODEPAGE_852=m
-+CONFIG_NLS_CODEPAGE_855=m
-+CONFIG_NLS_CODEPAGE_857=m
-+CONFIG_NLS_CODEPAGE_860=m
-+CONFIG_NLS_CODEPAGE_861=m
-+CONFIG_NLS_CODEPAGE_862=m
-+CONFIG_NLS_CODEPAGE_863=m
-+CONFIG_NLS_CODEPAGE_864=m
-+CONFIG_NLS_CODEPAGE_865=m
-+CONFIG_NLS_CODEPAGE_866=m
-+CONFIG_NLS_CODEPAGE_869=m
-+CONFIG_NLS_CODEPAGE_936=m
-+CONFIG_NLS_CODEPAGE_950=m
-+CONFIG_NLS_CODEPAGE_932=m
-+CONFIG_NLS_CODEPAGE_949=m
-+CONFIG_NLS_CODEPAGE_874=m
-+CONFIG_NLS_ISO8859_8=m
-+CONFIG_NLS_CODEPAGE_1250=m
-+CONFIG_NLS_CODEPAGE_1251=m
-+CONFIG_NLS_ASCII=y
-+CONFIG_NLS_ISO8859_1=m
-+CONFIG_NLS_ISO8859_2=m
-+CONFIG_NLS_ISO8859_3=m
-+CONFIG_NLS_ISO8859_4=m
-+CONFIG_NLS_ISO8859_5=m
-+CONFIG_NLS_ISO8859_6=m
-+CONFIG_NLS_ISO8859_7=m
-+CONFIG_NLS_ISO8859_9=m
-+CONFIG_NLS_ISO8859_13=m
-+CONFIG_NLS_ISO8859_14=m
-+CONFIG_NLS_ISO8859_15=m
-+CONFIG_NLS_KOI8_R=m
-+CONFIG_NLS_KOI8_U=m
-+CONFIG_NLS_UTF8=m
++CONFIG_NLS_CODEPAGE_737=y
++CONFIG_NLS_CODEPAGE_775=y
++CONFIG_NLS_CODEPAGE_850=y
++CONFIG_NLS_CODEPAGE_852=y
++CONFIG_NLS_CODEPAGE_855=y
++CONFIG_NLS_CODEPAGE_857=y
++CONFIG_NLS_CODEPAGE_860=y
++CONFIG_NLS_CODEPAGE_861=y
++CONFIG_NLS_CODEPAGE_862=y
++CONFIG_NLS_CODEPAGE_863=y
++CONFIG_NLS_CODEPAGE_864=y
++CONFIG_NLS_CODEPAGE_865=y
++CONFIG_NLS_CODEPAGE_866=y
++CONFIG_NLS_CODEPAGE_869=y
++CONFIG_NLS_CODEPAGE_936=y
++CONFIG_NLS_CODEPAGE_950=y
++CONFIG_NLS_CODEPAGE_932=y
++CONFIG_NLS_CODEPAGE_949=y
++CONFIG_NLS_CODEPAGE_874=y
++CONFIG_NLS_ISO8859_8=y
++# CONFIG_NLS_CODEPAGE_1250 is not set
++CONFIG_NLS_CODEPAGE_1251=y
++# CONFIG_NLS_ASCII is not set
++CONFIG_NLS_ISO8859_1=y
++CONFIG_NLS_ISO8859_2=y
++CONFIG_NLS_ISO8859_3=y
++CONFIG_NLS_ISO8859_4=y
++CONFIG_NLS_ISO8859_5=y
++CONFIG_NLS_ISO8859_6=y
++CONFIG_NLS_ISO8859_7=y
++CONFIG_NLS_ISO8859_9=y
++CONFIG_NLS_ISO8859_13=y
++CONFIG_NLS_ISO8859_14=y
++CONFIG_NLS_ISO8859_15=y
++CONFIG_NLS_KOI8_R=y
++CONFIG_NLS_KOI8_U=y
++CONFIG_NLS_UTF8=y
++
++#
++# Library routines
++#
++# CONFIG_CRC_CCITT is not set
++# CONFIG_CRC16 is not set
++CONFIG_CRC32=y
++# CONFIG_LIBCRC32C is not set
++CONFIG_PLIST=y
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_GENERIC_PENDING_IRQ=y
++CONFIG_IRQ_PER_CPU=y
++
++#
++# HP Simulator drivers
++#
++# CONFIG_HP_SIMETH is not set
++# CONFIG_HP_SIMSERIAL is not set
++# CONFIG_HP_SIMSCSI is not set
 +
 +#
 +# Instrumentation Support
@@ -65938,35 +66376,33 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# Kernel hacking
 +#
-+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
 +# CONFIG_PRINTK_TIME is not set
 +CONFIG_MAGIC_SYSRQ=y
 +CONFIG_UNUSED_SYMBOLS=y
 +CONFIG_DEBUG_KERNEL=y
-+CONFIG_LOG_BUF_SHIFT=15
++CONFIG_LOG_BUF_SHIFT=20
 +CONFIG_DETECT_SOFTLOCKUP=y
 +# CONFIG_SCHEDSTATS is not set
 +# CONFIG_DEBUG_SLAB is not set
 +# CONFIG_DEBUG_RT_MUTEXES is not set
 +# CONFIG_RT_MUTEX_TESTER is not set
 +# CONFIG_DEBUG_SPINLOCK is not set
-+# CONFIG_DEBUG_MUTEXES is not set
++CONFIG_DEBUG_MUTEXES=y
 +# CONFIG_DEBUG_RWSEMS is not set
-+# CONFIG_DEBUG_LOCK_ALLOC is not set
-+# CONFIG_PROVE_LOCKING is not set
 +# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 +# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
 +# CONFIG_DEBUG_KOBJECT is not set
-+CONFIG_DEBUG_INFO=y
++# CONFIG_DEBUG_INFO is not set
 +# CONFIG_DEBUG_FS is not set
 +# CONFIG_DEBUG_VM is not set
-+CONFIG_FRAME_POINTER=y
-+# CONFIG_UNWIND_INFO is not set
 +CONFIG_FORCED_INLINING=y
 +# CONFIG_RCU_TORTURE_TEST is not set
-+# CONFIG_DEBUG_RODATA is not set
-+# CONFIG_DEBUG_STACKOVERFLOW is not set
-+# CONFIG_DEBUG_STACK_USAGE is not set
++CONFIG_IA64_GRANULE_16MB=y
++# CONFIG_IA64_GRANULE_64MB is not set
++CONFIG_IA64_PRINT_HAZARDS=y
++# CONFIG_DISABLE_VHPT is not set
++# CONFIG_IA64_DEBUG_CMPXCHG is not set
++# CONFIG_IA64_DEBUG_IRQ is not set
 +
 +#
 +# Security options
@@ -65978,49 +66414,67 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Cryptographic options
 +#
 +CONFIG_CRYPTO=y
-+CONFIG_CRYPTO_HMAC=y
-+CONFIG_CRYPTO_NULL=m
-+CONFIG_CRYPTO_MD4=m
++# CONFIG_CRYPTO_HMAC is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_MD4 is not set
 +CONFIG_CRYPTO_MD5=y
-+CONFIG_CRYPTO_SHA1=y
-+CONFIG_CRYPTO_SHA256=m
-+CONFIG_CRYPTO_SHA512=m
-+CONFIG_CRYPTO_WP512=m
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_WP512 is not set
 +# CONFIG_CRYPTO_TGR192 is not set
-+CONFIG_CRYPTO_DES=m
-+CONFIG_CRYPTO_BLOWFISH=m
-+CONFIG_CRYPTO_TWOFISH=m
-+CONFIG_CRYPTO_SERPENT=m
++CONFIG_CRYPTO_DES=y
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++# CONFIG_CRYPTO_SERPENT is not set
 +# CONFIG_CRYPTO_AES is not set
-+# CONFIG_CRYPTO_AES_X86_64 is not set
-+CONFIG_CRYPTO_CAST5=m
-+CONFIG_CRYPTO_CAST6=m
-+CONFIG_CRYPTO_TEA=m
-+CONFIG_CRYPTO_ARC4=m
-+CONFIG_CRYPTO_KHAZAD=m
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_ARC4 is not set
++# CONFIG_CRYPTO_KHAZAD is not set
 +# CONFIG_CRYPTO_ANUBIS is not set
-+CONFIG_CRYPTO_DEFLATE=m
-+CONFIG_CRYPTO_MICHAEL_MIC=m
-+CONFIG_CRYPTO_CRC32C=m
++# CONFIG_CRYPTO_DEFLATE is not set
++# CONFIG_CRYPTO_MICHAEL_MIC is not set
++# CONFIG_CRYPTO_CRC32C is not set
 +# CONFIG_CRYPTO_TEST is not set
 +
 +#
 +# Hardware crypto devices
 +#
-+CONFIG_XEN=y
-+CONFIG_XEN_INTERFACE_VERSION=0x00030206
++# CONFIG_XEN_SMPBOOT is not set
++# CONFIG_XEN_DEVMEM is not set
++CONFIG_XEN_INTERFACE_VERSION=0x00030207
 +
 +#
 +# XEN
 +#
-+# CONFIG_XEN_PRIVILEGED_GUEST is not set
-+CONFIG_XEN_UNPRIVILEGED_GUEST=y
++CONFIG_XEN_PRIVILEGED_GUEST=y
++# CONFIG_XEN_UNPRIVILEGED_GUEST is not set
 +CONFIG_XEN_PRIVCMD=y
 +CONFIG_XEN_XENBUS_DEV=y
-+# CONFIG_XEN_BACKEND is not set
++CONFIG_XEN_BACKEND=y
++CONFIG_XEN_BLKDEV_BACKEND=y
++CONFIG_XEN_BLKDEV_TAP=y
++CONFIG_XEN_NETDEV_BACKEND=y
++# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND is not set
++# CONFIG_XEN_NETDEV_LOOPBACK is not set
++CONFIG_XEN_PCIDEV_BACKEND=y
++# CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
++# CONFIG_XEN_PCIDEV_BACKEND_PASS is not set
++# CONFIG_XEN_PCIDEV_BACKEND_SLOT is not set
++CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER=y
++# CONFIG_XEN_PCIDEV_BE_DEBUG is not set
++CONFIG_XEN_TPMDEV_BACKEND=m
 +CONFIG_XEN_BLKDEV_FRONTEND=y
 +CONFIG_XEN_NETDEV_FRONTEND=y
-+CONFIG_XEN_SCRUB_PAGES=y
++CONFIG_XEN_GRANT_DEV=y
++# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
++CONFIG_XEN_FRAMEBUFFER=y
++CONFIG_XEN_KEYBOARD=y
++# CONFIG_XEN_SCRUB_PAGES is not set
 +CONFIG_XEN_DISABLE_SERIAL=y
 +CONFIG_XEN_SYSFS=y
 +CONFIG_XEN_COMPAT_030002_AND_LATER=y
@@ -66030,27 +66484,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_COMPAT=0x030002
 +CONFIG_HAVE_IRQ_IGNORE_UNHANDLED=y
 +CONFIG_NO_IDLE_HZ=y
-+CONFIG_XEN_SMPBOOT=y
 +CONFIG_XEN_BALLOON=y
-+CONFIG_XEN_DEVMEM=y
-+# CONFIG_XEN_GRANT_DEV is not set
-+
-+#
-+# Library routines
-+#
-+CONFIG_CRC_CCITT=m
-+# CONFIG_CRC16 is not set
-+CONFIG_CRC32=y
-+CONFIG_LIBCRC32C=m
-+CONFIG_ZLIB_INFLATE=y
-+CONFIG_ZLIB_DEFLATE=m
-+CONFIG_TEXTSEARCH=y
-+CONFIG_TEXTSEARCH_KMP=m
-+CONFIG_PLIST=y
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defconfig_xen_x86_32 linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen_x86_32
---- linux-2.6.18/buildconfigs/linux-defconfig_xen_x86_32       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen_x86_32        2007-12-23 11:15:00.746186534 +0100
-@@ -0,0 +1,3318 @@
++CONFIG_XEN_XENCOMM=y
+--- linux-2.6.18.8/buildconfigs/linux-defconfig_xen_x86_32     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen_x86_32        2008-05-19 00:33:19.717282661 +0300
+@@ -0,0 +1,3324 @@
 +#
 +# Automatically generated make config: don't edit
 +# Linux kernel version: 2.6.18.8
@@ -66307,6 +66745,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_PCIDEV_FRONTEND=y
 +# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
 +# CONFIG_PCIEPORTBUS is not set
++# CONFIG_PCI_MSI is not set
 +# CONFIG_PCI_DEBUG is not set
 +CONFIG_ISA_DMA_API=y
 +CONFIG_SCx200=m
@@ -67329,6 +67768,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_I2O=m
 +CONFIG_I2O_LCT_NOTIFY_ON_CHANGES=y
 +CONFIG_I2O_EXT_ADAPTEC=y
++CONFIG_I2O_EXT_ADAPTEC_DMA64=y
 +CONFIG_I2O_CONFIG=m
 +CONFIG_I2O_CONFIG_OLD_IOCTL=y
 +CONFIG_I2O_BUS=m
@@ -67471,6 +67911,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_S2IO=m
 +CONFIG_S2IO_NAPI=y
 +CONFIG_MYRI10GE=m
++# CONFIG_SFC is not set
 +
 +#
 +# Token Ring devices
@@ -69302,7 +69743,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +#
 +# CONFIG_CRYPTO_DEV_PADLOCK is not set
 +CONFIG_XEN=y
-+CONFIG_XEN_INTERFACE_VERSION=0x00030206
++CONFIG_XEN_INTERFACE_VERSION=0x00030207
 +
 +#
 +# XEN
@@ -69316,6 +69757,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_BLKDEV_TAP=y
 +CONFIG_XEN_NETDEV_BACKEND=y
 +# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND is not set
 +# CONFIG_XEN_NETDEV_LOOPBACK is not set
 +CONFIG_XEN_PCIDEV_BACKEND=m
 +CONFIG_XEN_PCIDEV_BACKEND_VPCI=y
@@ -69326,8 +69769,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_TPMDEV_BACKEND=m
 +CONFIG_XEN_BLKDEV_FRONTEND=y
 +CONFIG_XEN_NETDEV_FRONTEND=y
-+CONFIG_XEN_FRAMEBUFFER=y
 +CONFIG_XEN_GRANT_DEV=y
++# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
++CONFIG_XEN_FRAMEBUFFER=y
 +CONFIG_XEN_KEYBOARD=y
 +CONFIG_XEN_SCRUB_PAGES=y
 +CONFIG_XEN_DISABLE_SERIAL=y
@@ -69369,14 +69813,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_X86_NO_TSS=y
 +CONFIG_X86_NO_IDT=y
 +CONFIG_KTIME_SCALAR=y
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defconfig_xen_x86_64 linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen_x86_64
---- linux-2.6.18/buildconfigs/linux-defconfig_xen_x86_64       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen_x86_64        2007-12-23 11:15:00.746186534 +0100
-@@ -0,0 +1,3139 @@
+--- linux-2.6.18.8/buildconfigs/linux-defconfig_xen_x86_64     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/buildconfigs/linux-defconfig_xen_x86_64        2008-05-19 00:33:19.769285658 +0300
+@@ -0,0 +1,3144 @@
 +#
 +# Automatically generated make config: don't edit
 +# Linux kernel version: 2.6.18.8
-+# Tue Oct 16 09:32:25 2007
++# Mon Feb 18 10:38:24 2008
 +#
 +CONFIG_X86_64=y
 +CONFIG_64BIT=y
@@ -69584,6 +70027,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_PCIDEV_FRONTEND=y
 +# CONFIG_XEN_PCIDEV_FE_DEBUG is not set
 +# CONFIG_PCIEPORTBUS is not set
++# CONFIG_PCI_MSI is not set
 +# CONFIG_PCI_DEBUG is not set
 +
 +#
@@ -70733,6 +71177,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_S2IO=m
 +CONFIG_S2IO_NAPI=y
 +CONFIG_MYRI10GE=m
++# CONFIG_SFC is not set
 +
 +#
 +# Token Ring devices
@@ -72455,7 +72900,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +# Hardware crypto devices
 +#
 +CONFIG_XEN=y
-+CONFIG_XEN_INTERFACE_VERSION=0x00030206
++CONFIG_XEN_INTERFACE_VERSION=0x00030207
 +
 +#
 +# XEN
@@ -72469,6 +72914,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_BLKDEV_TAP=y
 +CONFIG_XEN_NETDEV_BACKEND=y
 +# CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL is not set
++# CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND is not set
 +# CONFIG_XEN_NETDEV_LOOPBACK is not set
 +CONFIG_XEN_PCIDEV_BACKEND=m
 +# CONFIG_XEN_PCIDEV_BACKEND_VPCI is not set
@@ -72479,8 +72926,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_XEN_TPMDEV_BACKEND=m
 +CONFIG_XEN_BLKDEV_FRONTEND=y
 +CONFIG_XEN_NETDEV_FRONTEND=y
-+CONFIG_XEN_FRAMEBUFFER=y
 +CONFIG_XEN_GRANT_DEV=y
++# CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND is not set
++CONFIG_XEN_FRAMEBUFFER=y
 +CONFIG_XEN_KEYBOARD=y
 +CONFIG_XEN_SCRUB_PAGES=y
 +CONFIG_XEN_DISABLE_SERIAL=y
@@ -72512,36 +72960,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/buildconfigs/linux-defco
 +CONFIG_TEXTSEARCH_BM=m
 +CONFIG_TEXTSEARCH_FSM=m
 +CONFIG_PLIST=y
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/acpi/hardware/hwsleep.c linux-2.6.18-xen.hg/drivers/acpi/hardware/hwsleep.c
---- linux-2.6.18/drivers/acpi/hardware/hwsleep.c       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/acpi/hardware/hwsleep.c        2007-12-23 11:15:01.949583064 +0100
-@@ -327,6 +327,7 @@
-       ACPI_FLUSH_CPU_CACHE();
-+#ifndef CONFIG_ACPI_PV_SLEEP
-       status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
-                                       ACPI_REGISTER_PM1A_CONTROL,
-                                       PM1Acontrol);
-@@ -378,6 +379,15 @@
-       } while (!in_value);
-       return_ACPI_STATUS(AE_OK);
-+#else
-+      /* PV ACPI just need check hypercall return value */
-+      status = acpi_notify_hypervisor_state(sleep_state,
-+                      PM1Acontrol, PM1Bcontrol);
-+      if (ACPI_FAILURE(status))
-+              return_ACPI_STATUS(status);
-+      else
-+              return_ACPI_STATUS(AE_OK);
-+#endif
- }
- ACPI_EXPORT_SYMBOL(acpi_enter_sleep_state)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/acpi/Kconfig linux-2.6.18-xen.hg/drivers/acpi/Kconfig
---- linux-2.6.18/drivers/acpi/Kconfig  2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/acpi/Kconfig   2007-12-23 11:15:01.496225920 +0100
+--- linux-2.6.18.8/drivers/Makefile    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/Makefile       2008-05-19 00:33:19.861290962 +0300
+@@ -31,6 +31,7 @@
+ obj-$(CONFIG_NUBUS)           += nubus/
+ obj-$(CONFIG_ATM)             += atm/
+ obj-$(CONFIG_PPC_PMAC)                += macintosh/
++obj-$(CONFIG_XEN)             += xen/
+ obj-$(CONFIG_IDE)             += ide/
+ obj-$(CONFIG_FC4)             += fc4/
+ obj-$(CONFIG_SCSI)            += scsi/
+--- linux-2.6.18.8/drivers/acpi/Kconfig        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/acpi/Kconfig   2008-05-19 00:33:19.877291884 +0300
 @@ -305,6 +305,7 @@
  config X86_PM_TIMER
        bool "Power Management Timer Support" if EMBEDDED
@@ -72550,20 +72980,748 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/acpi/Kconfig lin
        default y
        help
          The Power Management Timer is available on all ACPI-capable,
-@@ -362,6 +363,10 @@
+@@ -362,6 +363,16 @@
          A "Smart Battery" is quite old and quite rare compared
          to today's ACPI "Control Method" battery.
  
 +config ACPI_PV_SLEEP
 +      bool
 +      depends on X86 && XEN && ACPI_SLEEP
++      default y
++
++config PROCESSOR_EXTERNAL_CONTROL
++      bool
++      depends on X86 && XEN
++      select ACPI_PROCESSOR
 +      default y
  endif # ACPI
  
  endmenu
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/acpi/sleep/main.c linux-2.6.18-xen.hg/drivers/acpi/sleep/main.c
---- linux-2.6.18/drivers/acpi/sleep/main.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/acpi/sleep/main.c      2007-12-23 11:15:01.989585156 +0100
+--- linux-2.6.18.8/drivers/acpi/Makefile       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/acpi/Makefile  2008-05-19 00:33:19.877291884 +0300
+@@ -34,6 +34,9 @@
+ ifdef CONFIG_CPU_FREQ
+ processor-objs        += processor_perflib.o                  
+ endif
++ifdef CONFIG_PROCESSOR_EXTERNAL_CONTROL
++processor-objs        += processor_extcntl.o
++endif
+ obj-y                         += sleep/
+ obj-y                         += bus.o glue.o
+--- linux-2.6.18.8/drivers/acpi/dispatcher/dsobject.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/acpi/dispatcher/dsobject.c     2008-05-19 00:33:19.893292806 +0300
+@@ -137,6 +137,71 @@
+                               return_ACPI_STATUS(status);
+                       }
+               }
++
++              /* Special object resolution for elements of a package */
++
++              if ((op->common.parent->common.aml_opcode == AML_PACKAGE_OP) ||
++                  (op->common.parent->common.aml_opcode ==
++                   AML_VAR_PACKAGE_OP)) {
++                      /*
++                       * Attempt to resolve the node to a value before we insert it into
++                       * the package. If this is a reference to a common data type,
++                       * resolve it immediately. According to the ACPI spec, package
++                       * elements can only be "data objects" or method references.
++                       * Attempt to resolve to an Integer, Buffer, String or Package.
++                       * If cannot, return the named reference (for things like Devices,
++                       * Methods, etc.) Buffer Fields and Fields will resolve to simple
++                       * objects (int/buf/str/pkg).
++                       *
++                       * NOTE: References to things like Devices, Methods, Mutexes, etc.
++                       * will remain as named references. This behavior is not described
++                       * in the ACPI spec, but it appears to be an oversight.
++                       */
++                      obj_desc = (union acpi_operand_object *)op->common.node;
++
++                      status =
++                          acpi_ex_resolve_node_to_value(ACPI_CAST_INDIRECT_PTR
++                                                        (struct
++                                                         acpi_namespace_node,
++                                                         &obj_desc),
++                                                        walk_state);
++                      if (ACPI_FAILURE(status)) {
++                              return_ACPI_STATUS(status);
++                      }
++
++                      switch (op->common.node->type) {
++                              /*
++                               * For these types, we need the actual node, not the subobject.
++                               * However, the subobject got an extra reference count above.
++                               */
++                      case ACPI_TYPE_MUTEX:
++                      case ACPI_TYPE_METHOD:
++                      case ACPI_TYPE_POWER:
++                      case ACPI_TYPE_PROCESSOR:
++                      case ACPI_TYPE_EVENT:
++                      case ACPI_TYPE_REGION:
++                      case ACPI_TYPE_DEVICE:
++                      case ACPI_TYPE_THERMAL:
++
++                              obj_desc =
++                                  (union acpi_operand_object *)op->common.
++                                  node;
++                              break;
++
++                      default:
++                              break;
++                      }
++
++                      /*
++                       * If above resolved to an operand object, we are done. Otherwise,
++                       * we have a NS node, we must create the package entry as a named
++                       * reference.
++                       */
++                      if (ACPI_GET_DESCRIPTOR_TYPE(obj_desc) !=
++                          ACPI_DESC_TYPE_NAMED) {
++                              goto exit;
++                      }
++              }
+       }
+       /* Create and init a new internal ACPI object */
+@@ -156,6 +221,7 @@
+               return_ACPI_STATUS(status);
+       }
++      exit:
+       *obj_desc_ptr = obj_desc;
+       return_ACPI_STATUS(AE_OK);
+ }
+@@ -358,12 +424,25 @@
+       arg = arg->common.next;
+       for (i = 0; arg; i++) {
+               if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) {
+-
+-                      /* Object (package or buffer) is already built */
++                      if (arg->common.node->type == ACPI_TYPE_METHOD) {
++                              /*
++                               * A method reference "looks" to the parser to be a method
++                               * invocation, so we special case it here
++                               */
++                              arg->common.aml_opcode = AML_INT_NAMEPATH_OP;
++                              status =
++                                  acpi_ds_build_internal_object(walk_state,
++                                                                arg,
++                                                                &obj_desc->
++                                                                package.
++                                                                elements[i]);
++                      } else {
++                              /* This package element is already built, just get it */
+                       obj_desc->package.elements[i] =
+                           ACPI_CAST_PTR(union acpi_operand_object,
+                                         arg->common.node);
++                      }
+               } else {
+                       status = acpi_ds_build_internal_object(walk_state, arg,
+                                                              &obj_desc->
+--- linux-2.6.18.8/drivers/acpi/hardware/hwsleep.c     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/acpi/hardware/hwsleep.c        2008-05-19 00:33:19.949296034 +0300
+@@ -227,7 +227,11 @@
+       u32 PM1Bcontrol;
+       struct acpi_bit_register_info *sleep_type_reg_info;
+       struct acpi_bit_register_info *sleep_enable_reg_info;
++#if !(defined(CONFIG_XEN) && defined(CONFIG_X86))
+       u32 in_value;
++#else
++      int err;
++#endif
+       acpi_status status;
+       ACPI_FUNCTION_TRACE(acpi_enter_sleep_state);
+@@ -327,6 +331,7 @@
+       ACPI_FLUSH_CPU_CACHE();
++#if !(defined(CONFIG_XEN) && defined(CONFIG_X86))
+       status = acpi_hw_register_write(ACPI_MTX_DO_NOT_LOCK,
+                                       ACPI_REGISTER_PM1A_CONTROL,
+                                       PM1Acontrol);
+@@ -376,6 +381,16 @@
+               /* Spin until we wake */
+       } while (!in_value);
++#else
++      /* PV ACPI just need check hypercall return value */
++      err = acpi_notify_hypervisor_state(sleep_state,
++                      PM1Acontrol, PM1Bcontrol);
++      if (err) {
++              ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
++                                "Hypervisor failure [%d]\n", err));
++              return_ACPI_STATUS(AE_ERROR);
++      }
++#endif
+       return_ACPI_STATUS(AE_OK);
+ }
+--- linux-2.6.18.8/drivers/acpi/processor_core.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/acpi/processor_core.c  2008-05-19 00:33:20.461325548 +0300
+@@ -474,8 +474,14 @@
+        *  they are physically not present.
+        */
+       if (cpu_index == -1) {
++#ifdef CONFIG_XEN
++              if (ACPI_FAILURE
++                  (acpi_processor_hotadd_init(pr->handle, &pr->id)) &&
++                  !processor_cntl_external()) {
++#else
+               if (ACPI_FAILURE
+                   (acpi_processor_hotadd_init(pr->handle, &pr->id))) {
++#endif /* CONFIG_XEN */
+                       printk(KERN_ERR PREFIX
+                                   "Getting cpuindex for acpiid 0x%x\n",
+                                   pr->acpi_id);
+@@ -517,7 +523,11 @@
+       return 0;
+ }
++#ifdef CONFIG_XEN
++static void *processor_device_array[NR_ACPI_CPUS];
++#else
+ static void *processor_device_array[NR_CPUS];
++#endif /* CONFIG_XEN */
+ static int acpi_processor_start(struct acpi_device *device)
+ {
+@@ -529,27 +539,48 @@
+       pr = acpi_driver_data(device);
+       result = acpi_processor_get_info(pr);
++#ifdef CONFIG_XEN
++      if (result || 
++          ((pr->id == -1) && !processor_cntl_external())) {
++#else
+       if (result) {
++#endif /* CONFIG_XEN */
+               /* Processor is physically not present */
+               return 0;
+       }
++#ifdef CONFIG_XEN
++      BUG_ON(!processor_cntl_external() &&
++             ((pr->id >= NR_CPUS) || (pr->id < 0)));
++#else
+       BUG_ON((pr->id >= NR_CPUS) || (pr->id < 0));
++#endif /* CONFIG_XEN */
+       /*
+        * Buggy BIOS check
+        * ACPI id of processors can be reported wrongly by the BIOS.
+        * Don't trust it blindly
+        */
++#ifdef CONFIG_XEN
++      if (processor_device_array[pr->acpi_id] != NULL &&
++          processor_device_array[pr->acpi_id] != (void *)device) {
++#else
+       if (processor_device_array[pr->id] != NULL &&
+           processor_device_array[pr->id] != (void *)device) {
++#endif /* CONFIG_XEN */
+               printk(KERN_WARNING "BIOS reported wrong ACPI id"
+                       "for the processor\n");
+               return -ENODEV;
+       }
++#ifdef CONFIG_XEN
++      processor_device_array[pr->acpi_id] = (void *)device;
++      if (pr->id != -1)
++              processors[pr->id] = pr;
++#else
+       processor_device_array[pr->id] = (void *)device;
+       processors[pr->id] = pr;
++#endif /* CONFIG_XEN */
+       result = acpi_processor_add_fs(device);
+       if (result)
+@@ -564,6 +595,10 @@
+       acpi_processor_power_init(pr, device);
++#ifdef CONFIG_PROCESSOR_EXTERNAL_CONTROL
++      processor_extcntl_init(pr);
++#endif
++
+       if (pr->flags.throttling) {
+               printk(KERN_INFO PREFIX "%s [%s] (supports",
+                      acpi_device_name(device), acpi_device_bid(device));
+@@ -656,7 +691,13 @@
+       acpi_processor_remove_fs(device);
++#ifdef CONFIG_XEN
++      if (pr->id != -1)
+       processors[pr->id] = NULL;
++#else
++      processors[pr->id] = NULL;
++#endif /* CONFIG_XEN */
++
+       kfree(pr);
+@@ -710,6 +751,12 @@
+       if (!pr)
+               return -ENODEV;
++#ifdef CONFIG_XEN
++      if (processor_cntl_external())
++              processor_notify_external(pr,
++                      PROCESSOR_HOTPLUG, HOTPLUG_TYPE_ADD);
++#endif /* CONFIG_XEN */
++
+       if ((pr->id >= 0) && (pr->id < NR_CPUS)) {
+               kobject_uevent(&(*device)->kobj, KOBJ_ONLINE);
+       }
+@@ -748,6 +795,12 @@
+                       break;
+               }
++#ifdef CONFIG_XEN
++              if (processor_cntl_external())
++                      processor_notify_external(pr,
++                                      PROCESSOR_HOTPLUG, HOTPLUG_TYPE_ADD);
++#endif /* CONFIG_XEN */
++
+               if (pr->id >= 0 && (pr->id < NR_CPUS)) {
+                       kobject_uevent(&device->kobj, KOBJ_OFFLINE);
+                       break;
+@@ -777,8 +830,20 @@
+                       return;
+               }
++#ifdef CONFIG_XEN
++              if ((pr->id >= 0) && (pr->id < NR_CPUS)
++                  && (cpu_present(pr->id)))
++#else
+               if ((pr->id < NR_CPUS) && (cpu_present(pr->id)))
++#endif /* CONFIG_XEN */
+                       kobject_uevent(&device->kobj, KOBJ_OFFLINE);
++
++#ifdef CONFIG_XEN
++              if (processor_cntl_external())
++                      processor_notify_external(pr, PROCESSOR_HOTPLUG,
++                                                      HOTPLUG_TYPE_REMOVE);
++#endif /* CONFIG_XEN */
++
+               break;
+       default:
+               ACPI_DEBUG_PRINT((ACPI_DB_INFO,
+@@ -843,6 +908,11 @@
+ static int acpi_processor_handle_eject(struct acpi_processor *pr)
+ {
++#ifdef CONFIG_XEN
++      if (pr->id == -1)
++              return (0);
++#endif /* CONFIG_XEN */
++
+       if (cpu_online(pr->id)) {
+               return (-EINVAL);
+       }
+--- linux-2.6.18.8/drivers/acpi/processor_extcntl.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/acpi/processor_extcntl.c       2008-05-19 00:33:20.465325778 +0300
+@@ -0,0 +1,248 @@
++/*
++ * processor_extcntl.c - channel to external control logic
++ *
++ *  Copyright (C) 2008, Intel corporation
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License as published by
++ *  the Free Software Foundation; either version 2 of the License, or (at
++ *  your option) any later version.
++ *
++ *  This program is distributed in the hope that it will be useful, but
++ *  WITHOUT ANY WARRANTY; without even the implied warranty of
++ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
++ *  General Public License for more details.
++ *
++ *  You should have received a copy of the GNU General Public License along
++ *  with this program; if not, write to the Free Software Foundation, Inc.,
++ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/types.h>
++#include <linux/acpi.h>
++#include <linux/pm.h>
++#include <linux/cpu.h>
++
++#include <acpi/processor.h>
++
++static int processor_extcntl_parse_csd(struct acpi_processor *pr);
++static int processor_extcntl_get_performance(struct acpi_processor *pr);
++/*
++ * External processor control logic may register with its own set of
++ * ops to get ACPI related notification. One example is like VMM.
++ */
++struct processor_extcntl_ops *processor_extcntl_ops;
++
++static int processor_notify_smm(void)
++{
++      acpi_status status;
++      static int is_done = 0;
++
++      /* only need successfully notify BIOS once */
++      /* avoid double notification which may lead to unexpected result */
++      if (is_done)
++              return 0;
++
++      /* Can't write pstate_cnt to smi_cmd if either value is zero */
++      if ((!acpi_fadt.smi_cmd) || (!acpi_fadt.pstate_cnt)) {
++              ACPI_DEBUG_PRINT((ACPI_DB_INFO,"No SMI port or pstate_cnt\n"));
++              return 0;
++      }
++
++      ACPI_DEBUG_PRINT((ACPI_DB_INFO,
++              "Writing pstate_cnt [0x%x] to smi_cmd [0x%x]\n",
++              acpi_fadt.pstate_cnt, acpi_fadt.smi_cmd));
++
++      /* FADT v1 doesn't support pstate_cnt, many BIOS vendors use
++       * it anyway, so we need to support it... */
++      if (acpi_fadt_is_v1) {
++              ACPI_DEBUG_PRINT((ACPI_DB_INFO,
++                      "Using v1.0 FADT reserved value for pstate_cnt\n"));
++      }
++
++      status = acpi_os_write_port(acpi_fadt.smi_cmd,
++                                  (u32) acpi_fadt.pstate_cnt, 8);
++      if (ACPI_FAILURE(status)) 
++              return status;
++
++      is_done = 1;
++
++      return 0;
++}
++
++int processor_notify_external(struct acpi_processor *pr, int event, int type)
++{
++      int ret = -EINVAL;
++
++      if (!processor_cntl_external())
++              return -EINVAL;
++
++      switch (event) {
++      case PROCESSOR_PM_INIT:
++      case PROCESSOR_PM_CHANGE:
++              if ((type >= PM_TYPE_MAX) ||
++                      !processor_extcntl_ops->pm_ops[type])
++                      break;
++
++              ret = processor_extcntl_ops->pm_ops[type](pr, event);
++              break;
++      case PROCESSOR_HOTPLUG:
++              if (processor_extcntl_ops->hotplug)
++                      ret = processor_extcntl_ops->hotplug(pr, type);
++              break;
++      default:
++              printk(KERN_ERR "Unsupport processor events %d.\n", event);
++              break;
++      }
++
++      return ret;
++}
++
++/*
++ * External control logic can decide to grab full or part of physical
++ * processor control bits. Take a VMM for example, physical processors
++ * are owned by VMM and thus existence information like hotplug is
++ * always required to be notified to VMM. Similar is processor idle
++ * state which is also necessarily controlled by VMM. But for other
++ * control bits like performance/throttle states, VMM may choose to
++ * control or not upon its own policy.
++ *
++ * Such ownership is unlikely to be switched in the fly, and thus
++ * not sure unregister interface is required or not. Being same reason,
++ * lock is not forced now.
++ */
++int processor_register_extcntl(struct processor_extcntl_ops *ops)
++{
++      if (!ops)
++              return -EINVAL;
++
++      if (processor_extcntl_ops &&
++              (processor_extcntl_ops != ops))
++              return -EBUSY;
++
++      processor_extcntl_ops = ops;
++      return 0;
++}
++
++int processor_unregister_extcntl(struct processor_extcntl_ops *ops)
++{
++      if (processor_extcntl_ops == ops)
++              processor_extcntl_ops = NULL;
++
++      return 0;
++}
++
++/*
++ * This is called from ACPI processor init, and targeted to hold
++ * some tricky housekeeping jobs to satisfy external control model.
++ * For example, we may put dependency parse stub here for idle
++ * and performance state. Those information may be not available
++ * if splitting from dom0 control logic like cpufreq driver.
++ */
++int processor_extcntl_init(struct acpi_processor *pr)
++{
++      /* parse cstate dependency information */
++      if (processor_pm_external())
++              processor_extcntl_parse_csd(pr);
++
++      /* Initialize performance states */
++      if (processor_pmperf_external())
++              processor_extcntl_get_performance(pr);
++
++      return 0;
++}
++
++/*
++ * Currently no _CSD is implemented which is why existing ACPI code
++ * doesn't parse _CSD at all. But to keep interface complete with
++ * external control logic, we put a placeholder here for future
++ * compatibility.
++ */
++static int processor_extcntl_parse_csd(struct acpi_processor *pr)
++{
++      int i;
++
++      for (i = 0; i < pr->power.count; i++) {
++              if (!pr->power.states[i].valid)
++                      continue;
++
++              /* No dependency by default */
++              pr->power.states[i].domain_info = NULL;
++              pr->power.states[i].csd_count = 0;
++      }
++
++      return 0;
++}
++
++/*
++ * Existing ACPI module does parse performance states at some point,
++ * when acpi-cpufreq driver is loaded which however is something
++ * we'd like to disable to avoid confliction with external control
++ * logic. So we have to collect raw performance information here 
++ * when ACPI processor object is found and started.
++ */
++#ifdef CONFIG_CPU_FREQ
++static int processor_extcntl_get_performance(struct acpi_processor *pr)
++{
++      int ret;
++      struct acpi_processor_performance *perf;
++      struct acpi_psd_package *pdomain;
++
++      if (pr->performance)
++              return -EBUSY;
++
++      perf = kzalloc(sizeof(struct acpi_processor_performance), GFP_KERNEL);
++      if (!perf)
++              return -ENOMEM;
++
++      pr->performance = perf;
++      /* Get basic performance state information */
++      ret = acpi_processor_get_performance_info(pr);
++      if (ret < 0)
++              goto err_out;
++
++      /*
++       * Well, here we need retrieve performance dependency information
++       * from _PSD object. The reason why existing interface is not used
++       * is due to the reason that existing interface sticks to Linux cpu
++       * id to construct some bitmap, however we want to split ACPI 
++       * processor objects from Linux cpu id logic. For example, even
++       * when Linux is configured as UP, we still want to parse all ACPI
++       * processor objects to external logic. In this case, it's preferred
++       * to use ACPI ID instead.
++       */
++      pr->performance->domain_info.num_processors = 0;
++      ret = acpi_processor_get_psd(pr);
++      if (ret < 0)
++              goto err_out;
++
++      /* Some sanity check */
++      pdomain = &pr->performance->domain_info;
++      if ((pdomain->revision != ACPI_PSD_REV0_REVISION) ||
++          (pdomain->num_entries != ACPI_PSD_REV0_ENTRIES) ||
++          ((pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ALL) &&
++           (pdomain->coord_type != DOMAIN_COORD_TYPE_SW_ANY) &&
++           (pdomain->coord_type != DOMAIN_COORD_TYPE_HW_ALL))) {
++              ret = -EINVAL;
++              goto err_out;
++      }
++
++      /* Last step is to notify BIOS that external logic exists */
++      processor_notify_smm();
++
++      processor_notify_external(pr, PROCESSOR_PM_INIT, PM_TYPE_PERF);
++
++      return 0;
++err_out:
++      pr->performance = NULL;
++      kfree(perf);
++      return ret;
++}
++#else
++static int processor_extcntl_get_performance(struct acpi_processor *pr) { return 0; }
++#endif
+--- linux-2.6.18.8/drivers/acpi/processor_idle.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/acpi/processor_idle.c  2008-05-19 00:33:20.465325778 +0300
+@@ -714,8 +714,17 @@
+                   (reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
+                       continue;
++#ifdef CONFIG_XEN
++              if (!processor_pm_external())
++                      cx.address = (reg->space_id ==
++                                    ACPI_ADR_SPACE_FIXED_HARDWARE) ?
++                                    0 : reg->address;
++              else
++                      cx.address = reg->address;
++#else
+               cx.address = (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) ?
+                   0 : reg->address;
++#endif /* CONFIG_XEN */
+               /* There should be an easy way to extract an integer... */
+               obj = (union acpi_object *)&(element->package.elements[1]);
+@@ -724,9 +733,17 @@
+               cx.type = obj->integer.value;
++#ifdef CONFIG_XEN
++              /* Following check doesn't apply to external control case */
++              if (!processor_pm_external())
++                      if ((cx.type != ACPI_STATE_C1) &&
++                          (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
++                              continue;
++#else
+               if ((cx.type != ACPI_STATE_C1) &&
+                   (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO))
+                       continue;
++#endif /* CONFIG_XEN */
+               if ((cx.type < ACPI_STATE_C2) || (cx.type > ACPI_STATE_C3))
+                       continue;
+@@ -743,6 +760,12 @@
+               cx.power = obj->integer.value;
++#ifdef CONFIG_PROCESSOR_EXTERNAL_CONTROL
++              /* cache control methods to notify external logic */
++              if (processor_pm_external())
++                      memcpy(&cx.reg, reg, sizeof(*reg));
++#endif
++
+               current_count++;
+               memcpy(&(pr->power.states[current_count]), &cx, sizeof(cx));
+@@ -985,12 +1008,24 @@
+               return -ENODEV;
+       /* Fall back to the default idle loop */
++#ifdef CONFIG_XEN
++      if (!processor_pm_external())
++              pm_idle = pm_idle_save;
++#else
+       pm_idle = pm_idle_save;
++#endif /* CONFIG_XEN */
+       synchronize_sched();    /* Relies on interrupts forcing exit from idle. */
+       pr->flags.power = 0;
+       result = acpi_processor_get_power_info(pr);
++#ifdef CONFIG_XEN
++      if (processor_pm_external())
++              processor_notify_external(pr,
++                      PROCESSOR_PM_CHANGE, PM_TYPE_IDLE);
++      else if ((pr->flags.power == 1) && (pr->flags.power_setup_done))
++#else
+       if ((pr->flags.power == 1) && (pr->flags.power_setup_done))
++#endif /* CONFIG_XEN */
+               pm_idle = acpi_processor_idle;
+       return result;
+@@ -1122,7 +1157,11 @@
+                                      pr->power.states[i].type);
+               printk(")\n");
++#ifdef CONFIG_XEN
++              if (!processor_pm_external() && (pr->id == 0)) {
++#else
+               if (pr->id == 0) {
++#endif /* CONFIG_XEN */
+                       pm_idle_save = pm_idle;
+                       pm_idle = acpi_processor_idle;
+               }
+@@ -1141,6 +1180,11 @@
+       pr->flags.power_setup_done = 1;
++#ifdef CONFIG_XEN
++      if (processor_pm_external())
++              processor_notify_external(pr,
++                      PROCESSOR_PM_INIT, PM_TYPE_IDLE);
++#endif /* CONFIG_XEN */
+       return 0;
+ }
+--- linux-2.6.18.8/drivers/acpi/processor_perflib.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/acpi/processor_perflib.c       2008-05-19 00:33:20.465325778 +0300
+@@ -136,6 +136,11 @@
+       int ret = acpi_processor_get_platform_limit(pr);
+       if (ret < 0)
+               return (ret);
++#ifdef CONFIG_XEN
++      else if (processor_pmperf_external())
++              return processor_notify_external(pr,
++                              PROCESSOR_PM_CHANGE, PM_TYPE_PERF);
++#endif /* CONFIG_XEN */
+       else
+               return cpufreq_update_policy(pr->id);
+ }
+@@ -299,7 +304,11 @@
+       return result;
+ }
++#ifndef CONFIG_PROCESSOR_EXTERNAL_CONTROL
+ static int acpi_processor_get_performance_info(struct acpi_processor *pr)
++#else
++int acpi_processor_get_performance_info(struct acpi_processor *pr)
++#endif
+ {
+       int result = 0;
+       acpi_status status = AE_OK;
+@@ -538,7 +547,11 @@
+ }
+ #endif                                /* CONFIG_X86_ACPI_CPUFREQ_PROC_INTF */
++#ifndef CONFIG_PROCESSOR_EXTERNAL_CONTROL
+ static int acpi_processor_get_psd(struct acpi_processor       *pr)
++#else
++int acpi_processor_get_psd(struct acpi_processor *pr)
++#endif
+ {
+       int result = 0;
+       acpi_status status = AE_OK;
+--- linux-2.6.18.8/drivers/acpi/resources/rsxface.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/acpi/resources/rsxface.c       2008-05-19 00:33:20.481326701 +0300
+@@ -476,8 +476,6 @@
+       return (AE_CTRL_TERMINATE);
+ }
+-ACPI_EXPORT_SYMBOL(acpi_rs_match_vendor_resource)
+-
+ /*******************************************************************************
+  *
+  * FUNCTION:    acpi_walk_resources
+--- linux-2.6.18.8/drivers/acpi/sleep/main.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/acpi/sleep/main.c      2008-05-19 00:33:20.485326931 +0300
 @@ -91,7 +91,14 @@
                break;
  
@@ -72592,9 +73750,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/acpi/sleep/main.
        return 0;
  }
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/acpi/sleep/poweroff.c linux-2.6.18-xen.hg/drivers/acpi/sleep/poweroff.c
---- linux-2.6.18/drivers/acpi/sleep/poweroff.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/acpi/sleep/poweroff.c  2007-12-23 11:15:01.989585156 +0100
+--- linux-2.6.18.8/drivers/acpi/sleep/poweroff.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/acpi/sleep/poweroff.c  2008-05-19 00:33:20.485326931 +0300
 @@ -20,6 +20,7 @@
  int acpi_sleep_prepare(u32 acpi_state)
  {
@@ -72611,9 +73768,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/acpi/sleep/power
        ACPI_FLUSH_CPU_CACHE();
        acpi_enable_wakeup_device_prep(acpi_state);
  #endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/block/floppy.c linux-2.6.18-xen.hg/drivers/block/floppy.c
---- linux-2.6.18/drivers/block/floppy.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/block/floppy.c 2007-12-23 11:15:02.082923396 +0100
+--- linux-2.6.18.8/drivers/block/floppy.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/block/floppy.c 2008-05-19 00:33:20.765343071 +0300
 @@ -4392,12 +4392,16 @@
        if (fd_request_dma()) {
                DPRINT("Unable to grab DMA%d for the floppy driver\n",
@@ -72631,9 +73787,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/block/floppy.c l
  
        for (fdc = 0; fdc < N_FDC; fdc++) {
                if (FDCS->address != -1) {
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/agp/amd64-agp.c linux-2.6.18-xen.hg/drivers/char/agp/amd64-agp.c
---- linux-2.6.18/drivers/char/agp/amd64-agp.c  2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/char/agp/amd64-agp.c   2007-12-23 11:15:02.149593567 +0100
+--- linux-2.6.18.8/drivers/char/agp/amd64-agp.c        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/char/agp/amd64-agp.c   2008-05-19 00:33:21.213368896 +0300
 @@ -15,6 +15,7 @@
  #include <linux/mmzone.h>
  #include <asm/page.h>         /* PAGE_SIZE */
@@ -72667,9 +73822,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/agp/amd64-a
  
        /* Request the Aperture. This catches cases when someone else
           already put a mapping in there - happens with some very broken BIOS
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/agp/generic.c linux-2.6.18-xen.hg/drivers/char/agp/generic.c
---- linux-2.6.18/drivers/char/agp/generic.c    2007-12-23 11:26:51.070123757 +0100
-+++ linux-2.6.18-xen.hg/drivers/char/agp/generic.c     2007-12-23 11:15:02.152927074 +0100
+--- linux-2.6.18.8/drivers/char/agp/generic.c  2008-05-19 00:42:33.913230658 +0300
++++ linux-2.6.18-xen.hg/drivers/char/agp/generic.c     2008-05-19 00:33:21.305374199 +0300
 @@ -51,28 +51,6 @@
   */
  EXPORT_SYMBOL_GPL(agp_memory_reserved);
@@ -72699,9 +73853,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/agp/generic
  /*
   * Generic routines for handling agp_memory structures -
   * They use the basic page allocation routines to do the brunt of the work.
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/agp/intel-agp.c linux-2.6.18-xen.hg/drivers/char/agp/intel-agp.c
---- linux-2.6.18/drivers/char/agp/intel-agp.c  2007-12-23 11:26:51.070123757 +0100
-+++ linux-2.6.18-xen.hg/drivers/char/agp/intel-agp.c   2007-12-23 11:15:02.152927074 +0100
+--- linux-2.6.18.8/drivers/char/agp/intel-agp.c        2008-05-19 00:42:33.965233656 +0300
++++ linux-2.6.18-xen.hg/drivers/char/agp/intel-agp.c   2008-05-19 00:33:21.309374430 +0300
 @@ -164,9 +164,17 @@
        if (page == NULL)
                return NULL;
@@ -72735,9 +73888,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/agp/intel-a
        atomic_dec(&agp_bridge->current_memory_agp);
  }
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/mem.c linux-2.6.18-xen.hg/drivers/char/mem.c
---- linux-2.6.18/drivers/char/mem.c    2007-12-23 11:26:51.073457266 +0100
-+++ linux-2.6.18-xen.hg/drivers/char/mem.c     2007-12-23 11:15:04.043026325 +0100
+--- linux-2.6.18.8/drivers/char/mem.c  2008-05-19 00:42:33.969233887 +0300
++++ linux-2.6.18-xen.hg/drivers/char/mem.c     2008-05-19 00:33:22.273429998 +0300
 @@ -101,6 +101,7 @@
  }
  #endif
@@ -72754,7 +73906,31 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/mem.c linux
  
  #ifndef __HAVE_PHYS_MEM_ACCESS_PROT
  static pgprot_t phys_mem_access_prot(struct file *file, unsigned long pfn,
-@@ -780,6 +782,7 @@
+@@ -262,6 +264,9 @@
+ static int mmap_kmem(struct file * file, struct vm_area_struct * vma)
+ {
+       unsigned long pfn;
++#ifdef CONFIG_XEN
++      unsigned long i, count;
++#endif
+       /* Turn a kernel-virtual address into a physical page frame */
+       pfn = __pa((u64)vma->vm_pgoff << PAGE_SHIFT) >> PAGE_SHIFT;
+@@ -276,6 +281,13 @@
+       if (!pfn_valid(pfn))
+               return -EIO;
++#ifdef CONFIG_XEN
++      count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
++      for (i = 0; i < count; i++)
++              if ((pfn + i) != mfn_to_local_pfn(pfn_to_mfn(pfn + i)))
++                      return -EIO;
++#endif
++
+       vma->vm_pgoff = pfn;
+       return mmap_mem(file, vma);
+ }
+@@ -780,6 +792,7 @@
  #define open_kmem     open_mem
  #define open_oldmem   open_mem
  
@@ -72762,7 +73938,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/mem.c linux
  static const struct file_operations mem_fops = {
        .llseek         = memory_lseek,
        .read           = read_mem,
-@@ -787,6 +790,9 @@
+@@ -787,6 +800,9 @@
        .mmap           = mmap_mem,
        .open           = open_mem,
  };
@@ -72772,9 +73948,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/mem.c linux
  
  static const struct file_operations kmem_fops = {
        .llseek         = memory_lseek,
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/Kconfig linux-2.6.18-xen.hg/drivers/char/tpm/Kconfig
---- linux-2.6.18/drivers/char/tpm/Kconfig      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/char/tpm/Kconfig       2007-12-23 11:15:05.833120324 +0100
+--- linux-2.6.18.8/drivers/char/tpm/Kconfig    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/char/tpm/Kconfig       2008-05-19 00:33:22.477441757 +0300
 @@ -58,5 +58,13 @@
          Further information on this driver and the supported hardware
          can be found at http://www.prosec.rub.de/tpm
@@ -72790,18 +73965,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/Kconfig
 +        will be called tpm_xenu.
  
 +endmenu
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/Makefile linux-2.6.18-xen.hg/drivers/char/tpm/Makefile
---- linux-2.6.18/drivers/char/tpm/Makefile     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/char/tpm/Makefile      2007-12-23 11:15:05.836453833 +0100
+--- linux-2.6.18.8/drivers/char/tpm/Makefile   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/char/tpm/Makefile      2008-05-19 00:33:22.477441757 +0300
 @@ -9,3 +9,5 @@
  obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
  obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
  obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
 +obj-$(CONFIG_TCG_XEN) += tpm_xenu.o
 +tpm_xenu-y = tpm_xen.o tpm_vtpm.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/tpm.h linux-2.6.18-xen.hg/drivers/char/tpm/tpm.h
---- linux-2.6.18/drivers/char/tpm/tpm.h        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/char/tpm/tpm.h 2007-12-23 11:15:05.836453833 +0100
+--- linux-2.6.18.8/drivers/char/tpm/tpm.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/char/tpm/tpm.h 2008-05-19 00:33:22.481441988 +0300
 @@ -105,6 +105,9 @@
        struct dentry **bios_dir;
  
@@ -72831,9 +74004,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/tpm.h l
  extern void tpm_get_timeouts(struct tpm_chip *);
  extern void tpm_gen_interrupt(struct tpm_chip *);
  extern void tpm_continue_selftest(struct tpm_chip *);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/tpm_vtpm.c linux-2.6.18-xen.hg/drivers/char/tpm/tpm_vtpm.c
---- linux-2.6.18/drivers/char/tpm/tpm_vtpm.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/char/tpm/tpm_vtpm.c    2007-12-23 11:15:05.839787342 +0100
+--- linux-2.6.18.8/drivers/char/tpm/tpm_vtpm.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/char/tpm/tpm_vtpm.c    2008-05-19 00:33:22.485442218 +0300
 @@ -0,0 +1,542 @@
 +/*
 + * Copyright (C) 2006 IBM Corporation
@@ -73377,9 +74549,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/tpm_vtp
 +      tpm_remove_hardware(dev);
 +      kfree(vtpms);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/tpm_vtpm.h linux-2.6.18-xen.hg/drivers/char/tpm/tpm_vtpm.h
---- linux-2.6.18/drivers/char/tpm/tpm_vtpm.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/char/tpm/tpm_vtpm.h    2007-12-23 11:15:05.839787342 +0100
+--- linux-2.6.18.8/drivers/char/tpm/tpm_vtpm.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/char/tpm/tpm_vtpm.h    2008-05-19 00:33:22.485442218 +0300
 @@ -0,0 +1,55 @@
 +#ifndef TPM_VTPM_H
 +#define TPM_VTPM_H
@@ -73436,10 +74607,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/tpm_vtp
 +}
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/tpm_xen.c linux-2.6.18-xen.hg/drivers/char/tpm/tpm_xen.c
---- linux-2.6.18/drivers/char/tpm/tpm_xen.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/char/tpm/tpm_xen.c     2007-12-23 11:15:05.839787342 +0100
-@@ -0,0 +1,719 @@
+--- linux-2.6.18.8/drivers/char/tpm/tpm_xen.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/char/tpm/tpm_xen.c     2008-05-19 00:33:22.489442449 +0300
+@@ -0,0 +1,722 @@
 +/*
 + * Copyright (c) 2005, IBM Corporation
 + *
@@ -73789,6 +74959,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/tpm_xen
 +      case XenbusStateInitialising:
 +      case XenbusStateInitWait:
 +      case XenbusStateInitialised:
++      case XenbusStateReconfiguring:
++      case XenbusStateReconfigured:
 +      case XenbusStateUnknown:
 +              break;
 +
@@ -74059,6 +75231,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/tpm_xen
 +              tx = &tp->tx->ring[i].req;
 +              tx->addr = virt_to_machine(txb->data);
 +              tx->size = txb->len;
++              tx->unused = 0;
 +
 +              DPRINTK("First 4 characters sent by TPM-FE are "
 +                      "0x%02x 0x%02x 0x%02x 0x%02x\n",
@@ -74159,9 +75332,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tpm/tpm_xen
 +module_init(tpmif_init);
 +
 +MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tty_io.c linux-2.6.18-xen.hg/drivers/char/tty_io.c
---- linux-2.6.18/drivers/char/tty_io.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/char/tty_io.c  2007-12-23 11:15:05.843120852 +0100
+--- linux-2.6.18.8/drivers/char/tty_io.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/char/tty_io.c  2008-05-19 00:33:22.489442449 +0300
 @@ -130,6 +130,8 @@
     vt.c for deeply disgusting hack reasons */
  DEFINE_MUTEX(tty_mutex);
@@ -74197,9 +75369,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/char/tty_io.c li
  #endif
        return 0;
  }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/cpufreq/cpufreq_ondemand.c linux-2.6.18-xen.hg/drivers/cpufreq/cpufreq_ondemand.c
---- linux-2.6.18/drivers/cpufreq/cpufreq_ondemand.c    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/cpufreq/cpufreq_ondemand.c     2007-12-23 11:15:06.203139758 +0100
+--- linux-2.6.18.8/drivers/cpufreq/cpufreq_ondemand.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/cpufreq/cpufreq_ondemand.c     2008-05-19 00:33:22.565446830 +0300
 @@ -96,6 +96,7 @@
        return retval;
  }
@@ -74322,9 +75493,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/cpufreq/cpufreq_
  
        /* Check for frequency increase */
        if (load > dbs_tuners_ins.up_threshold) {
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/cpufreq/cpufreq_stats.c linux-2.6.18-xen.hg/drivers/cpufreq/cpufreq_stats.c
---- linux-2.6.18/drivers/cpufreq/cpufreq_stats.c       2007-12-23 11:26:51.073457266 +0100
-+++ linux-2.6.18-xen.hg/drivers/cpufreq/cpufreq_stats.c        2007-12-23 11:15:06.356481136 +0100
+--- linux-2.6.18.8/drivers/cpufreq/cpufreq_stats.c     2008-05-19 00:42:33.973234117 +0300
++++ linux-2.6.18-xen.hg/drivers/cpufreq/cpufreq_stats.c        2008-05-19 00:33:22.569447060 +0300
 @@ -292,6 +292,9 @@
        if (old_index == new_index)
                return 0;
@@ -74335,39 +75505,41 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/cpufreq/cpufreq_
        spin_lock(&cpufreq_stats_lock);
        stat->last_index = new_index;
  #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/i2c/busses/i2c-i801.c linux-2.6.18-xen.hg/drivers/i2c/busses/i2c-i801.c
---- linux-2.6.18/drivers/i2c/busses/i2c-i801.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/i2c/busses/i2c-i801.c  2007-12-23 11:15:07.589879240 +0100
-@@ -33,6 +33,7 @@
+--- linux-2.6.18.8/drivers/i2c/busses/Kconfig  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/i2c/busses/Kconfig     2008-05-19 00:33:22.929467812 +0300
+@@ -125,6 +125,8 @@
+           ICH7
+           ESB2
+           ICH8
++          ICH9
++          ICH10
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-i801.
+--- linux-2.6.18.8/drivers/i2c/busses/i2c-i801.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/i2c/busses/i2c-i801.c  2008-05-19 00:33:22.953469196 +0300
+@@ -33,6 +33,9 @@
      ICH7              27DA
      ESB2              269B
      ICH8              283E
 +    ICH9              2930
++    ICH10             3A30
++    ICH10             3A60
      This driver supports several versions of Intel's I/O Controller Hubs (ICH).
      For SMBus support, they are similar to the PIIX4 and are part
      of Intel's '810' and other chipsets.
-@@ -457,6 +458,7 @@
+@@ -457,6 +460,9 @@
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH7_17) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB2_17) },
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH8_5) },
 +      { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH9_6) },
++      { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) },
++      { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) },
        { 0, }
  };
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/i2c/busses/Kconfig linux-2.6.18-xen.hg/drivers/i2c/busses/Kconfig
---- linux-2.6.18/drivers/i2c/busses/Kconfig    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/i2c/busses/Kconfig     2007-12-23 11:15:07.583212226 +0100
-@@ -125,6 +125,7 @@
-           ICH7
-           ESB2
-           ICH8
-+          ICH9
-         This driver can also be built as a module.  If so, the module
-         will be called i2c-i801.
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/ide/ide-lib.c linux-2.6.18-xen.hg/drivers/ide/ide-lib.c
---- linux-2.6.18/drivers/ide/ide-lib.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/ide/ide-lib.c  2007-12-23 11:15:07.633214851 +0100
+--- linux-2.6.18.8/drivers/ide/ide-lib.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/ide/ide-lib.c  2008-05-19 00:33:23.037474038 +0300
 @@ -408,10 +408,10 @@
  {
        u64 addr = BLK_BOUNCE_HIGH;     /* dma64_addr_t */
@@ -74382,20 +75554,38 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/ide/ide-lib.c li
                        addr = HWIF(drive)->pci_dev->dma_mask;
        }
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/Makefile linux-2.6.18-xen.hg/drivers/Makefile
---- linux-2.6.18/drivers/Makefile      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/Makefile       2007-12-23 11:15:01.252879806 +0100
-@@ -31,6 +31,7 @@
- obj-$(CONFIG_NUBUS)           += nubus/
- obj-$(CONFIG_ATM)             += atm/
- obj-$(CONFIG_PPC_PMAC)                += macintosh/
-+obj-$(CONFIG_XEN)             += xen/
- obj-$(CONFIG_IDE)             += ide/
- obj-$(CONFIG_FC4)             += fc4/
- obj-$(CONFIG_SCSI)            += scsi/
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/net/r8169.c linux-2.6.18-xen.hg/drivers/net/r8169.c
---- linux-2.6.18/drivers/net/r8169.c   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/net/r8169.c    2007-12-23 11:15:19.093816661 +0100
+--- linux-2.6.18.8/drivers/input/gameport/gameport.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/input/gameport/gameport.c      2008-05-19 00:33:23.781516925 +0300
+@@ -37,8 +37,6 @@
+ EXPORT_SYMBOL(gameport_open);
+ EXPORT_SYMBOL(gameport_close);
+ EXPORT_SYMBOL(gameport_rescan);
+-EXPORT_SYMBOL(gameport_cooked_read);
+-EXPORT_SYMBOL(gameport_set_name);
+ EXPORT_SYMBOL(gameport_set_phys);
+ EXPORT_SYMBOL(gameport_start_polling);
+ EXPORT_SYMBOL(gameport_stop_polling);
+--- linux-2.6.18.8/drivers/net/Kconfig 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/Kconfig    2008-05-19 00:33:28.081764793 +0300
+@@ -2399,6 +2399,8 @@
+         <file:Documentation/networking/net-modules.txt>.  The module
+         will be called myri10ge.
++source "drivers/net/sfc/Kconfig"
++
+ endmenu
+ source "drivers/net/tokenring/Kconfig"
+--- linux-2.6.18.8/drivers/net/Makefile        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/Makefile   2008-05-19 00:33:28.085765023 +0300
+@@ -219,3 +219,5 @@
+ obj-$(CONFIG_FS_ENET) += fs_enet/
++obj-$(CONFIG_SFC) += sfc/
++
+--- linux-2.6.18.8/drivers/net/r8169.c 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/r8169.c    2008-05-19 00:33:28.801806296 +0300
 @@ -81,7 +81,7 @@
  
  #ifdef RTL8169_DEBUG
@@ -75523,23301 +76713,84525 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/net/r8169.c linu
  }
  
  static void __exit
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/oprofile/buffer_sync.c linux-2.6.18-xen.hg/drivers/oprofile/buffer_sync.c
---- linux-2.6.18/drivers/oprofile/buffer_sync.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/oprofile/buffer_sync.c 2007-12-23 11:15:23.417377030 +0100
-@@ -6,6 +6,10 @@
-  *
-  * @author John Levon <levon@movementarian.org>
-  *
-+ * Modified by Aravind Menon for Xen
-+ * These modifications are:
-+ * Copyright (C) 2005 Hewlett-Packard Co.
+--- linux-2.6.18.8/drivers/net/sfc/Kconfig     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/Kconfig        2008-05-19 00:33:28.825807680 +0300
+@@ -0,0 +1,35 @@
++config SFC
++      tristate "Solarflare Solarstorm SFC4000 support"
++      depends on PCI && INET
++      select MII
++      help
++        This driver supports 10-gigabit Ethernet cards based on
++        the Solarflare Communications Solarstorm SFC4000 controller.
++
++        To compile this driver as a module, choose M here.  The module
++        will be called sfc.
++
++config SFC_DEBUGFS
++      bool "Solarflare Solarstorm SFC4000 debugging support"
++      depends on SFC && DEBUG_FS
++      default N
++      help
++        This option creates an "sfc" subdirectory of debugfs with
++        debugging information for the SFC4000 driver.
++
++        If unsure, say N.
++
++config SFC_MTD
++      depends on SFC && MTD && MTD_PARTITIONS
++      tristate "Solarflare Solarstorm SFC4000 flash/EEPROM support"
++      help
++        This module exposes the on-board flash and/or EEPROM memory as
++        MTD devices (e.g. /dev/mtd1).  This makes it possible to upload a
++        new boot ROM to the NIC.
++
++config SFC_RESOURCE
++      depends on SFC && X86
++      tristate "Solarflare Solarstorm SFC4000 resource driver"
++      help
++        This module provides the SFC resource manager driver.
++
+--- linux-2.6.18.8/drivers/net/sfc/Makefile    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/Makefile       2008-05-19 00:33:28.825807680 +0300
+@@ -0,0 +1,43 @@
++
++# Final objects
++sfc_o = sfc.o
++sfc_mtd_o = sfc_mtd.o
++
++# Constituent objects
++sfc_elements_o :=
++sfc_elements_o += efx.o
++sfc_elements_o += falcon.o
++sfc_elements_o += tx.o
++sfc_elements_o += rx.o
++sfc_elements_o += mentormac.o
++sfc_elements_o += falcon_gmac.o
++sfc_elements_o += falcon_xmac.o
++sfc_elements_o += alaska.o
++sfc_elements_o += i2c-direct.o
++sfc_elements_o += selftest.o
++sfc_elements_o += driverlink.o
++ifeq ($(CONFIG_SFC_DEBUGFS),y)
++sfc_elements_o += debugfs.o
++endif
++sfc_elements_o += ethtool.o
++sfc_elements_o += xfp_phy.o
++sfc_elements_o += mdio_10g.o
++sfc_elements_o += txc43128_phy.o
++sfc_elements_o += tenxpress.o
++sfc_elements_o += lm87_support.o
++sfc_elements_o += boards.o
++sfc_elements_o += sfe4001.o
++sfc_elements_o += pm8358_phy.o
++sfc_elements_o += null_phy.o
++sfc_elements_o += phy.o
++sfc_elements_o += kernel_compat.o
++
++sfc_mtd_elements_o := mtd.o
++
++obj-$(CONFIG_SFC) += $(sfc_o)
++obj-$(CONFIG_SFC_MTD) += $(sfc_mtd_o)
++
++sfc-objs = $(sfc_elements_o)
++sfc_mtd-objs = $(sfc_mtd_elements_o)
++
++obj-$(CONFIG_SFC_RESOURCE) += sfc_resource/
+--- linux-2.6.18.8/drivers/net/sfc/alaska.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/alaska.c       2008-05-19 00:33:28.825807680 +0300
+@@ -0,0 +1,159 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
 + *
-  * This is the core of the buffer management. Each
-  * CPU buffer is processed and entered into the
-  * global event buffer. Such processing is necessary
-@@ -38,6 +42,7 @@
- static DEFINE_SPINLOCK(task_mortuary);
- static void process_task_mortuary(void);
-+static int cpu_current_domain[NR_CPUS];
- /* Take ownership of the task struct and place it on the
-  * list for processing. Only after two full buffer syncs
-@@ -146,6 +151,11 @@
- int sync_start(void)
- {
-       int err;
-+      int i;
++ * Copyright 2005:      Fen Systems Ltd.
++ * Copyright 2006-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      for (i = 0; i < NR_CPUS; i++) {
-+              cpu_current_domain[i] = COORDINATOR_DOMAIN;
++#include "net_driver.h"
++#include <linux/ethtool.h>
++#include "gmii.h"
++#include "phy.h"
++
++/* Marvell 88E1111 "Alaska" PHY control */
++#define ALASKA_PHY_SPECIFIC 16
++#define ALASKA_ALLOW_SLEEP 0x0200
++
++#define ALASKA_EXTENDED_CONTROL 20
++#define EXTENDED_LINE_LOOPBACK 0x8000
++
++#define ALASKA_LED_CONTROL 24
++#define LED_BLINK_MASK 0x0700
++#define LED_BLINK_FAST 0x0100
++#define LED_BLINK_SLOW 0x0300
++#define LED_TX_CTRL_MASK 0x0041
++#define LED_TX_CTRL_LINK_AND_ACTIVITY 0x0001
++
++#define ALASKA_LED_OVERRIDE 25
++#define LED_LINK1000_MASK 0x0030
++#define LED_LINK1000_BLINK 0x0010
++#define LED_TX_MASK 0x0003
++#define LED_TX_BLINK 0x0001
++
++static void alaska_reconfigure(struct efx_nic *efx)
++{
++      struct mii_if_info *gmii = &efx->mii;
++      u32 bmcr, phy_ext;
++
++      /* Configure line loopback if requested */
++      phy_ext = gmii->mdio_read(gmii->dev, gmii->phy_id,
++                                ALASKA_EXTENDED_CONTROL);
++      if (efx->loopback_mode == LOOPBACK_NETWORK)
++              phy_ext |= EXTENDED_LINE_LOOPBACK;
++      else
++              phy_ext &= ~EXTENDED_LINE_LOOPBACK;
++      gmii->mdio_write(gmii->dev, gmii->phy_id, ALASKA_EXTENDED_CONTROL,
++                       phy_ext);
++
++      /* Configure PHY loopback if requested */
++      bmcr = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_BMCR);
++      if (efx->loopback_mode == LOOPBACK_PHY)
++              bmcr |= BMCR_LOOPBACK;
++      else
++              bmcr &= ~BMCR_LOOPBACK;
++      gmii->mdio_write(gmii->dev, gmii->phy_id, MII_BMCR, bmcr);
++
++      /* Read link up status */
++      if (efx->loopback_mode == LOOPBACK_NONE)
++              efx->link_up = mii_link_ok(gmii);
++      else
++              efx->link_up = 1;
++
++      /* Determine link options from PHY */
++      if (gmii->force_media) {
++              efx->link_options = gmii_forced_result(bmcr);
++      } else {
++              int lpa = gmii_lpa(gmii);
++              int adv = gmii_advertised(gmii);
++              efx->link_options = gmii_nway_result(adv & lpa);
 +      }
-       start_cpu_work();
-@@ -275,13 +285,29 @@
-       last_cookie = INVALID_COOKIE;
- }
--static void add_kernel_ctx_switch(unsigned int in_kernel)
-+static void add_cpu_mode_switch(unsigned int cpu_mode)
- {
-       add_event_entry(ESCAPE_CODE);
--      if (in_kernel)
-+      switch (cpu_mode) {
-+      case CPU_MODE_USER:
-+              add_event_entry(USER_ENTER_SWITCH_CODE);
-+              break;
-+      case CPU_MODE_KERNEL:
-               add_event_entry(KERNEL_ENTER_SWITCH_CODE); 
--      else
--              add_event_entry(KERNEL_EXIT_SWITCH_CODE); 
-+              break;
-+      case CPU_MODE_XEN:
-+              add_event_entry(XEN_ENTER_SWITCH_CODE);
-+              break;
-+      default:
-+              break;
++}
++
++static void alaska_clear_interrupt(struct efx_nic *efx)
++{
++      struct mii_if_info *gmii = &efx->mii;
++
++      /* Read interrupt status register to clear */
++      gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_ISR);
++}
++
++static int alaska_init(struct efx_nic *efx)
++{
++      struct mii_if_info *gmii = &efx->mii;
++      u32 ier, leds, ctrl_1g, phy_spec;
++
++      /* Read ISR to clear any outstanding PHY interrupts */
++      gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_ISR);
++
++      /* Enable PHY interrupts */
++      ier = gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_IER);
++      ier |= IER_LINK_CHG;
++      gmii->mdio_write(gmii->dev, gmii->phy_id, GMII_IER, ier);
++
++      /* Remove 1G half-duplex as unsupported in Mentor MAC */
++      ctrl_1g = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000);
++      ctrl_1g &= ~(ADVERTISE_1000HALF);
++      gmii->mdio_write(gmii->dev, gmii->phy_id, MII_CTRL1000, ctrl_1g);
++
++      /*
++       * The PHY can save power when there is no external connection
++       * (sleep mode).  However, this is incompatible with PHY
++       * loopback, and if enable and disable it quickly the PHY can
++       * go to sleep even when sleep mode is disabled.  (SFC bug
++       * 9309.)  Therefore we disable it all the time.
++       */
++      phy_spec = gmii->mdio_read(gmii->dev, gmii->phy_id,
++                                 ALASKA_PHY_SPECIFIC);
++      phy_spec &= ~ALASKA_ALLOW_SLEEP;
++      gmii->mdio_write(gmii->dev, gmii->phy_id, ALASKA_PHY_SPECIFIC,
++                       phy_spec);
++
++      /* Configure LEDs */
++      leds = gmii->mdio_read(gmii->dev, gmii->phy_id, ALASKA_LED_CONTROL);
++      leds &= ~(LED_BLINK_MASK | LED_TX_CTRL_MASK);
++      leds |= (LED_BLINK_FAST | LED_TX_CTRL_LINK_AND_ACTIVITY);
++      gmii->mdio_write(gmii->dev, gmii->phy_id, ALASKA_LED_CONTROL, leds);
++
++      return 0;
++}
++
++static void alaska_fini(struct efx_nic *efx)
++{
++      struct mii_if_info *gmii = &efx->mii;
++      u32 ier;
++
++      /* Disable PHY interrupts */
++      ier = gmii->mdio_read(gmii->dev, gmii->phy_id, GMII_IER);
++      ier &= ~IER_LINK_CHG;
++      gmii->mdio_write(gmii->dev, gmii->phy_id, GMII_IER, ier);
++}
++
++
++struct efx_phy_operations alaska_phy_operations = {
++      .init            = alaska_init,
++      .fini            = alaska_fini,
++      .reconfigure     = alaska_reconfigure,
++      .clear_interrupt = alaska_clear_interrupt,
++      .loopbacks       = (1 << LOOPBACK_PHY) | (1 << LOOPBACK_NETWORK),
++      .startup_loopback = LOOPBACK_PHY,
++};
+--- linux-2.6.18.8/drivers/net/sfc/bitfield.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/bitfield.h     2008-05-19 00:33:28.829807910 +0300
+@@ -0,0 +1,544 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef EFX_BITFIELD_H
++#define EFX_BITFIELD_H
++
++/*
++ * Efx bitfield access
++ *
++ * Efx NICs make extensive use of bitfields up to 128 bits
++ * wide.  Since there is no native 128-bit datatype on most systems,
++ * and since 64-bit datatypes are inefficient on 32-bit systems and
++ * vice versa, we wrap accesses in a way that uses the most efficient
++ * datatype.
++ *
++ * The NICs are PCI devices and therefore little-endian.  Since most
++ * of the quantities that we deal with are DMAed to/from host memory,
++ * we define our datatypes (efx_oword_t, efx_qword_t and
++ * efx_dword_t) to be little-endian.
++ */
++
++/* Lowest bit numbers and widths */
++#define EFX_DUMMY_FIELD_LBN 0
++#define EFX_DUMMY_FIELD_WIDTH 0
++#define EFX_DWORD_0_LBN 0
++#define EFX_DWORD_0_WIDTH 32
++#define EFX_DWORD_1_LBN 32
++#define EFX_DWORD_1_WIDTH 32
++#define EFX_DWORD_2_LBN 64
++#define EFX_DWORD_2_WIDTH 32
++#define EFX_DWORD_3_LBN 96
++#define EFX_DWORD_3_WIDTH 32
++
++#define EFX_BYTE  1
++#define EFX_WORD  2
++#define EFX_DWORD 4
++#define EFX_OWORD 8
++
++/* Specified attribute (e.g. LBN) of the specified field */
++#define EFX_VAL(field, attribute) field ## _ ## attribute
++/* Low bit number of the specified field */
++#define EFX_LOW_BIT(field) EFX_VAL(field, LBN)
++/* Bit width of the specified field */
++#define EFX_WIDTH(field) EFX_VAL(field, WIDTH)
++/* High bit number of the specified field */
++#define EFX_HIGH_BIT(field) (EFX_LOW_BIT(field) + EFX_WIDTH(field) - 1)
++/* Mask equal in width to the specified field.
++ *
++ * For example, a field with width 5 would have a mask of 0x1f.
++ *
++ * The maximum width mask that can be generated is 64 bits.
++ */
++#define EFX_MASK64(field)                                     \
++      (EFX_WIDTH(field) == 64 ? ~((u64) 0) :          \
++       (((((u64) 1) << EFX_WIDTH(field))) - 1))
++
++/* Mask equal in width to the specified field.
++ *
++ * For example, a field with width 5 would have a mask of 0x1f.
++ *
++ * The maximum width mask that can be generated is 32 bits.  Use
++ * EFX_MASK64 for higher width fields.
++ */
++#define EFX_MASK32(field)                                     \
++      (EFX_WIDTH(field) == 32 ? ~((u32) 0) :          \
++       (((((u32) 1) << EFX_WIDTH(field))) - 1))
++
++/* A doubleword (i.e. 4 byte) datatype - little-endian in HW */
++typedef union efx_dword {
++      __le32 u32[1];
++} efx_dword_t;
++
++/* A quadword (i.e. 8 byte) datatype - little-endian in HW */
++typedef union efx_qword {
++      __le64 u64[1];
++      __le32 u32[2];
++      efx_dword_t dword[2];
++} efx_qword_t;
++
++/* An octword (eight-word, i.e. 16 byte) datatype - little-endian in HW */
++typedef union efx_oword {
++      __le64 u64[2];
++      efx_qword_t qword[2];
++      __le32 u32[4];
++      efx_dword_t dword[4];
++} efx_oword_t;
++
++/* Format string and value expanders for printk */
++#define EFX_DWORD_FMT "%08x"
++#define EFX_QWORD_FMT "%08x:%08x"
++#define EFX_OWORD_FMT "%08x:%08x:%08x:%08x"
++#define EFX_DWORD_VAL(dword)                          \
++      ((unsigned int) le32_to_cpu((dword).u32[0]))
++#define EFX_QWORD_VAL(qword)                          \
++      ((unsigned int) le32_to_cpu((qword).u32[1])),   \
++      ((unsigned int) le32_to_cpu((qword).u32[0]))
++#define EFX_OWORD_VAL(oword)                          \
++      ((unsigned int) le32_to_cpu((oword).u32[3])),   \
++      ((unsigned int) le32_to_cpu((oword).u32[2])),   \
++      ((unsigned int) le32_to_cpu((oword).u32[1])),   \
++      ((unsigned int) le32_to_cpu((oword).u32[0]))
++
++/*
++ * Extract bit field portion [low,high) from the native-endian element
++ * which contains bits [min,max).
++ *
++ * For example, suppose "element" represents the high 32 bits of a
++ * 64-bit value, and we wish to extract the bits belonging to the bit
++ * field occupying bits 28-45 of this 64-bit value.
++ *
++ * Then EFX_EXTRACT ( element, 32, 63, 28, 45 ) would give
++ *
++ *   ( element ) << 4
++ *
++ * The result will contain the relevant bits filled in in the range
++ * [0,high-low), with garbage in bits [high-low+1,...).
++ */
++#define EFX_EXTRACT_NATIVE(native_element, min, max, low, high)               \
++      (((low > max) || (high < min)) ? 0 :                            \
++       ((low > min) ?                                                 \
++        ((native_element) >> (low - min)) :                           \
++        ((native_element) << (min - low))))
++
++/*
++ * Extract bit field portion [low,high) from the 64-bit little-endian
++ * element which contains bits [min,max)
++ */
++#define EFX_EXTRACT64(element, min, max, low, high)                   \
++      EFX_EXTRACT_NATIVE(le64_to_cpu(element), min, max, low, high)
++
++/*
++ * Extract bit field portion [low,high) from the 32-bit little-endian
++ * element which contains bits [min,max)
++ */
++#define EFX_EXTRACT32(element, min, max, low, high)                   \
++      EFX_EXTRACT_NATIVE(le32_to_cpu(element), min, max, low, high)
++
++#define EFX_EXTRACT_OWORD64(oword, low, high)                         \
++      (EFX_EXTRACT64((oword).u64[0], 0, 63, low, high) |              \
++       EFX_EXTRACT64((oword).u64[1], 64, 127, low, high))
++
++#define EFX_EXTRACT_QWORD64(qword, low, high)                         \
++      EFX_EXTRACT64((qword).u64[0], 0, 63, low, high)
++
++#define EFX_EXTRACT_OWORD32(oword, low, high)                         \
++      (EFX_EXTRACT32((oword).u32[0], 0, 31, low, high) |              \
++       EFX_EXTRACT32((oword).u32[1], 32, 63, low, high) |             \
++       EFX_EXTRACT32((oword).u32[2], 64, 95, low, high) |             \
++       EFX_EXTRACT32((oword).u32[3], 96, 127, low, high))
++
++#define EFX_EXTRACT_QWORD32(qword, low, high)                         \
++      (EFX_EXTRACT32((qword).u32[0], 0, 31, low, high) |              \
++       EFX_EXTRACT32((qword).u32[1], 32, 63, low, high))
++
++#define EFX_EXTRACT_DWORD(dword, low, high)                           \
++      EFX_EXTRACT32((dword).u32[0], 0, 31, low, high)
++
++#define EFX_OWORD_FIELD64(oword, field)                                       \
++      (EFX_EXTRACT_OWORD64(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
++       & EFX_MASK64(field))
++
++#define EFX_QWORD_FIELD64(qword, field)                                       \
++      (EFX_EXTRACT_QWORD64(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
++       & EFX_MASK64(field))
++
++#define EFX_OWORD_FIELD32(oword, field)                                       \
++      (EFX_EXTRACT_OWORD32(oword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
++       & EFX_MASK32(field))
++
++#define EFX_QWORD_FIELD32(qword, field)                                       \
++      (EFX_EXTRACT_QWORD32(qword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
++       & EFX_MASK32(field))
++
++#define EFX_DWORD_FIELD(dword, field)                                    \
++      (EFX_EXTRACT_DWORD(dword, EFX_LOW_BIT(field), EFX_HIGH_BIT(field)) \
++       & EFX_MASK32(field))
++
++#define EFX_OWORD_IS_ZERO64(oword)                                    \
++      (((oword).u64[0] | (oword).u64[1]) == (__force __le64) 0)
++
++#define EFX_QWORD_IS_ZERO64(qword)                                    \
++      (((qword).u64[0]) == (__force __le64) 0)
++
++#define EFX_OWORD_IS_ZERO32(oword)                                         \
++      (((oword).u32[0] | (oword).u32[1] | (oword).u32[2] | (oword).u32[3]) \
++       == (__force __le32) 0)
++
++#define EFX_QWORD_IS_ZERO32(qword)                                    \
++      (((qword).u32[0] | (qword).u32[1]) == (__force __le32) 0)
++
++#define EFX_DWORD_IS_ZERO(dword)                                      \
++      (((dword).u32[0]) == (__force __le32) 0)
++
++#define EFX_OWORD_IS_ALL_ONES64(oword)                                        \
++      (((oword).u64[0] & (oword).u64[1]) == ~((__force __le64) 0))
++
++#define EFX_QWORD_IS_ALL_ONES64(qword)                                        \
++      ((qword).u64[0] == ~((__force __le64) 0))
++
++#define EFX_OWORD_IS_ALL_ONES32(oword)                                        \
++      (((oword).u32[0] & (oword).u32[1] & (oword).u32[2] & (oword).u32[3]) \
++       == ~((__force __le32) 0))
++
++#define EFX_QWORD_IS_ALL_ONES32(qword)                                        \
++      (((qword).u32[0] & (qword).u32[1]) == ~((__force __le32) 0))
++
++#define EFX_DWORD_IS_ALL_ONES(dword)                                  \
++      ((dword).u32[0] == ~((__force __le32) 0))
++
++#if BITS_PER_LONG == 64
++#define EFX_OWORD_FIELD               EFX_OWORD_FIELD64
++#define EFX_QWORD_FIELD               EFX_QWORD_FIELD64
++#define EFX_OWORD_IS_ZERO     EFX_OWORD_IS_ZERO64
++#define EFX_QWORD_IS_ZERO     EFX_QWORD_IS_ZERO64
++#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES64
++#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES64
++#else
++#define EFX_OWORD_FIELD               EFX_OWORD_FIELD32
++#define EFX_QWORD_FIELD               EFX_QWORD_FIELD32
++#define EFX_OWORD_IS_ZERO     EFX_OWORD_IS_ZERO32
++#define EFX_QWORD_IS_ZERO     EFX_QWORD_IS_ZERO32
++#define EFX_OWORD_IS_ALL_ONES EFX_OWORD_IS_ALL_ONES32
++#define EFX_QWORD_IS_ALL_ONES EFX_QWORD_IS_ALL_ONES32
++#endif
++
++/*
++ * Construct bit field portion
++ *
++ * Creates the portion of the bit field [low,high) that lies within
++ * the range [min,max).
++ */
++#define EFX_INSERT_NATIVE64(min, max, low, high, value)               \
++      (((low > max) || (high < min)) ? 0 :                    \
++       ((low > min) ?                                         \
++        (((u64) (value)) << (low - min)) :            \
++        (((u64) (value)) >> (min - low))))
++
++#define EFX_INSERT_NATIVE32(min, max, low, high, value)               \
++      (((low > max) || (high < min)) ? 0 :                    \
++       ((low > min) ?                                         \
++        (((u32) (value)) << (low - min)) :            \
++        (((u32) (value)) >> (min - low))))
++
++#define EFX_INSERT_NATIVE(min, max, low, high, value)         \
++      ((((max - min) >= 32) || ((high - low) >= 32)) ?        \
++       EFX_INSERT_NATIVE64(min, max, low, high, value) :      \
++       EFX_INSERT_NATIVE32(min, max, low, high, value))
++
++/*
++ * Construct bit field portion
++ *
++ * Creates the portion of the named bit field that lies within the
++ * range [min,max).
++ */
++#define EFX_INSERT_FIELD_NATIVE(min, max, field, value)               \
++      EFX_INSERT_NATIVE(min, max, EFX_LOW_BIT(field),         \
++                        EFX_HIGH_BIT(field), value)
++
++/*
++ * Construct bit field
++ *
++ * Creates the portion of the named bit fields that lie within the
++ * range [min,max).
++ */
++#define EFX_INSERT_FIELDS_NATIVE(min, max,                            \
++                               field1, value1,                        \
++                               field2, value2,                        \
++                               field3, value3,                        \
++                               field4, value4,                        \
++                               field5, value5,                        \
++                               field6, value6,                        \
++                               field7, value7,                        \
++                               field8, value8,                        \
++                               field9, value9,                        \
++                               field10, value10)                      \
++      (EFX_INSERT_FIELD_NATIVE((min), (max), field1, (value1)) |      \
++       EFX_INSERT_FIELD_NATIVE((min), (max), field2, (value2)) |      \
++       EFX_INSERT_FIELD_NATIVE((min), (max), field3, (value3)) |      \
++       EFX_INSERT_FIELD_NATIVE((min), (max), field4, (value4)) |      \
++       EFX_INSERT_FIELD_NATIVE((min), (max), field5, (value5)) |      \
++       EFX_INSERT_FIELD_NATIVE((min), (max), field6, (value6)) |      \
++       EFX_INSERT_FIELD_NATIVE((min), (max), field7, (value7)) |      \
++       EFX_INSERT_FIELD_NATIVE((min), (max), field8, (value8)) |      \
++       EFX_INSERT_FIELD_NATIVE((min), (max), field9, (value9)) |      \
++       EFX_INSERT_FIELD_NATIVE((min), (max), field10, (value10)))
++
++#define EFX_INSERT_FIELDS64(...)                              \
++      cpu_to_le64(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
++
++#define EFX_INSERT_FIELDS32(...)                              \
++      cpu_to_le32(EFX_INSERT_FIELDS_NATIVE(__VA_ARGS__))
++
++#define EFX_POPULATE_OWORD64(oword, ...) do {                         \
++      (oword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__);       \
++      (oword).u64[1] = EFX_INSERT_FIELDS64(64, 127, __VA_ARGS__);     \
++      } while (0)
++
++#define EFX_POPULATE_QWORD64(qword, ...) do {                         \
++      (qword).u64[0] = EFX_INSERT_FIELDS64(0, 63, __VA_ARGS__);       \
++      } while (0)
++
++#define EFX_POPULATE_OWORD32(oword, ...) do {                         \
++      (oword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__);       \
++      (oword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__);      \
++      (oword).u32[2] = EFX_INSERT_FIELDS32(64, 95, __VA_ARGS__);      \
++      (oword).u32[3] = EFX_INSERT_FIELDS32(96, 127, __VA_ARGS__);     \
++      } while (0)
++
++#define EFX_POPULATE_QWORD32(qword, ...) do {                         \
++      (qword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__);       \
++      (qword).u32[1] = EFX_INSERT_FIELDS32(32, 63, __VA_ARGS__);      \
++      } while (0)
++
++#define EFX_POPULATE_DWORD(dword, ...) do {                           \
++      (dword).u32[0] = EFX_INSERT_FIELDS32(0, 31, __VA_ARGS__);       \
++      } while (0)
++
++#if BITS_PER_LONG == 64
++#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD64
++#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD64
++#else
++#define EFX_POPULATE_OWORD EFX_POPULATE_OWORD32
++#define EFX_POPULATE_QWORD EFX_POPULATE_QWORD32
++#endif
++
++/* Populate an octword field with various numbers of arguments */
++#define EFX_POPULATE_OWORD_10 EFX_POPULATE_OWORD
++#define EFX_POPULATE_OWORD_9(oword, ...) \
++      EFX_POPULATE_OWORD_10(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_OWORD_8(oword, ...) \
++      EFX_POPULATE_OWORD_9(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_OWORD_7(oword, ...) \
++      EFX_POPULATE_OWORD_8(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_OWORD_6(oword, ...) \
++      EFX_POPULATE_OWORD_7(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_OWORD_5(oword, ...) \
++      EFX_POPULATE_OWORD_6(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_OWORD_4(oword, ...) \
++      EFX_POPULATE_OWORD_5(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_OWORD_3(oword, ...) \
++      EFX_POPULATE_OWORD_4(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_OWORD_2(oword, ...) \
++      EFX_POPULATE_OWORD_3(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_OWORD_1(oword, ...) \
++      EFX_POPULATE_OWORD_2(oword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_ZERO_OWORD(oword) \
++      EFX_POPULATE_OWORD_1(oword, EFX_DUMMY_FIELD, 0)
++#define EFX_SET_OWORD(oword) \
++      EFX_POPULATE_OWORD_4(oword, \
++                           EFX_DWORD_0, 0xffffffff, \
++                           EFX_DWORD_1, 0xffffffff, \
++                           EFX_DWORD_2, 0xffffffff, \
++                           EFX_DWORD_3, 0xffffffff)
++
++/* Populate a quadword field with various numbers of arguments */
++#define EFX_POPULATE_QWORD_10 EFX_POPULATE_QWORD
++#define EFX_POPULATE_QWORD_9(qword, ...) \
++      EFX_POPULATE_QWORD_10(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_QWORD_8(qword, ...) \
++      EFX_POPULATE_QWORD_9(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_QWORD_7(qword, ...) \
++      EFX_POPULATE_QWORD_8(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_QWORD_6(qword, ...) \
++      EFX_POPULATE_QWORD_7(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_QWORD_5(qword, ...) \
++      EFX_POPULATE_QWORD_6(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_QWORD_4(qword, ...) \
++      EFX_POPULATE_QWORD_5(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_QWORD_3(qword, ...) \
++      EFX_POPULATE_QWORD_4(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_QWORD_2(qword, ...) \
++      EFX_POPULATE_QWORD_3(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_QWORD_1(qword, ...) \
++      EFX_POPULATE_QWORD_2(qword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_ZERO_QWORD(qword) \
++      EFX_POPULATE_QWORD_1(qword, EFX_DUMMY_FIELD, 0)
++#define EFX_SET_QWORD(qword) \
++      EFX_POPULATE_QWORD_2(qword, \
++                           EFX_DWORD_0, 0xffffffff, \
++                           EFX_DWORD_1, 0xffffffff)
++
++/* Populate a dword field with various numbers of arguments */
++#define EFX_POPULATE_DWORD_10 EFX_POPULATE_DWORD
++#define EFX_POPULATE_DWORD_9(dword, ...) \
++      EFX_POPULATE_DWORD_10(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_DWORD_8(dword, ...) \
++      EFX_POPULATE_DWORD_9(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_DWORD_7(dword, ...) \
++      EFX_POPULATE_DWORD_8(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_DWORD_6(dword, ...) \
++      EFX_POPULATE_DWORD_7(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_DWORD_5(dword, ...) \
++      EFX_POPULATE_DWORD_6(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_DWORD_4(dword, ...) \
++      EFX_POPULATE_DWORD_5(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_DWORD_3(dword, ...) \
++      EFX_POPULATE_DWORD_4(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_DWORD_2(dword, ...) \
++      EFX_POPULATE_DWORD_3(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_POPULATE_DWORD_1(dword, ...) \
++      EFX_POPULATE_DWORD_2(dword, EFX_DUMMY_FIELD, 0, __VA_ARGS__)
++#define EFX_ZERO_DWORD(dword) \
++      EFX_POPULATE_DWORD_1(dword, EFX_DUMMY_FIELD, 0)
++#define EFX_SET_DWORD(dword) \
++      EFX_POPULATE_DWORD_1(dword, EFX_DWORD_0, 0xffffffff)
++
++/*
++ * Modify a named field within an already-populated structure.  Used
++ * for read-modify-write operations.
++ *
++ */
++
++#define EFX_INVERT_OWORD(oword) do {          \
++      (oword).u64[0] = ~((oword).u64[0]);     \
++      (oword).u64[1] = ~((oword).u64[1]);     \
++      } while (0)
++
++#define EFX_INSERT_FIELD64(...)                                       \
++      cpu_to_le64(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
++
++#define EFX_INSERT_FIELD32(...)                                       \
++      cpu_to_le32(EFX_INSERT_FIELD_NATIVE(__VA_ARGS__))
++
++#define EFX_INPLACE_MASK64(min, max, field)                   \
++      EFX_INSERT_FIELD64(min, max, field, EFX_MASK64(field))
++
++#define EFX_INPLACE_MASK32(min, max, field)                   \
++      EFX_INSERT_FIELD32(min, max, field, EFX_MASK32(field))
++
++#define EFX_SET_OWORD_FIELD64(oword, field, value) do {                       \
++      (oword).u64[0] = (((oword).u64[0]                               \
++                         & ~EFX_INPLACE_MASK64(0,  63, field))        \
++                        | EFX_INSERT_FIELD64(0,  63, field, value));  \
++      (oword).u64[1] = (((oword).u64[1]                               \
++                         & ~EFX_INPLACE_MASK64(64, 127, field))       \
++                        | EFX_INSERT_FIELD64(64, 127, field, value)); \
++      } while (0)
++
++#define EFX_SET_QWORD_FIELD64(qword, field, value) do {                       \
++      (qword).u64[0] = (((qword).u64[0]                               \
++                         & ~EFX_INPLACE_MASK64(0, 63, field))         \
++                        | EFX_INSERT_FIELD64(0, 63, field, value));   \
++      } while (0)
++
++#define EFX_SET_OWORD_FIELD32(oword, field, value) do {                       \
++      (oword).u32[0] = (((oword).u32[0]                               \
++                         & ~EFX_INPLACE_MASK32(0, 31, field))         \
++                        | EFX_INSERT_FIELD32(0, 31, field, value));   \
++      (oword).u32[1] = (((oword).u32[1]                               \
++                         & ~EFX_INPLACE_MASK32(32, 63, field))        \
++                        | EFX_INSERT_FIELD32(32, 63, field, value));  \
++      (oword).u32[2] = (((oword).u32[2]                               \
++                         & ~EFX_INPLACE_MASK32(64, 95, field))        \
++                        | EFX_INSERT_FIELD32(64, 95, field, value));  \
++      (oword).u32[3] = (((oword).u32[3]                               \
++                         & ~EFX_INPLACE_MASK32(96, 127, field))       \
++                        | EFX_INSERT_FIELD32(96, 127, field, value)); \
++      } while (0)
++
++#define EFX_SET_QWORD_FIELD32(qword, field, value) do {                       \
++      (qword).u32[0] = (((qword).u32[0]                               \
++                         & ~EFX_INPLACE_MASK32(0, 31, field))         \
++                        | EFX_INSERT_FIELD32(0, 31, field, value));   \
++      (qword).u32[1] = (((qword).u32[1]                               \
++                         & ~EFX_INPLACE_MASK32(32, 63, field))        \
++                        | EFX_INSERT_FIELD32(32, 63, field, value));  \
++      } while (0)
++
++#define EFX_SET_DWORD_FIELD(dword, field, value) do {                 \
++      (dword).u32[0] = (((dword).u32[0]                               \
++                         & ~EFX_INPLACE_MASK32(0, 31, field))         \
++                        | EFX_INSERT_FIELD32(0, 31, field, value));   \
++      } while (0)
++
++#if BITS_PER_LONG == 64
++#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD64
++#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD64
++#else
++#define EFX_SET_OWORD_FIELD EFX_SET_OWORD_FIELD32
++#define EFX_SET_QWORD_FIELD EFX_SET_QWORD_FIELD32
++#endif
++
++#define EFX_SET_OWORD_FIELD_VER(efx, oword, field, value) do { \
++      if (FALCON_REV(efx) == FALCON_REV_B0) {                    \
++              EFX_SET_OWORD_FIELD((oword), field##_B0, (value)); \
++      } else { \
++              EFX_SET_OWORD_FIELD((oword), field##_A1, (value)); \
++      } \
++} while (0)
++
++#define EFX_QWORD_FIELD_VER(efx, qword, field)        \
++      (FALCON_REV(efx) == FALCON_REV_B0 ?     \
++       EFX_QWORD_FIELD((qword), field##_B0) : \
++       EFX_QWORD_FIELD((qword), field##_A1))
++
++/* Used to avoid compiler warnings about shift range exceeding width
++ * of the data types when dma_addr_t is only 32 bits wide.
++ */
++#define DMA_ADDR_T_WIDTH      (8 * sizeof(dma_addr_t))
++#define EFX_DMA_TYPE_WIDTH(width) \
++      (((width) < DMA_ADDR_T_WIDTH) ? (width) : DMA_ADDR_T_WIDTH)
++#define EFX_DMA_MAX_MASK ((DMA_ADDR_T_WIDTH == 64) ? \
++                        ~((u64) 0) : ~((u32) 0))
++#define EFX_DMA_MASK(mask) ((mask) & EFX_DMA_MAX_MASK)
++
++/*
++ * Determine if a DMA address is over the 4GB threshold
++ *
++ * Defined in a slightly tortuous way to avoid compiler warnings.
++ */
++static inline int efx_is_over_4gb(dma_addr_t address)
++{
++      if (DMA_ADDR_T_WIDTH > 32)
++              return (((u64) address) >> 32) ? 1 : 0;
++      else
++              /* Can never be true */
++              return 0;
++}
++
++#endif /* EFX_BITFIELD_H */
+--- linux-2.6.18.8/drivers/net/sfc/boards.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/boards.c       2008-05-19 00:33:28.829807910 +0300
+@@ -0,0 +1,528 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2007:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include "net_driver.h"
++#include "phy.h"
++#include "lm87_support.h"
++#include "boards.h"
++#include "efx.h"
++
++/* Macros for unpacking the board revision */
++/* The revision info is in host byte order. */
++#define BOARD_TYPE(_rev) (_rev >> 8)
++#define BOARD_MAJOR(_rev) ((_rev >> 4) & 0xf)
++#define BOARD_MINOR(_rev) (_rev & 0xf)
++
++/* Blink support. If the PHY has no auto-blink mode so we hang it off a timer */
++#define BLINK_INTERVAL (HZ/2)
++
++static void blink_led_timer(unsigned long context)
++{
++      struct efx_nic *efx = (struct efx_nic *)context;
++      struct efx_blinker *bl = &efx->board_info.blinker;
++      efx->board_info.set_fault_led(efx, bl->state);
++      bl->state = !bl->state;
++      if (bl->resubmit) {
++              bl->timer.expires = jiffies + BLINK_INTERVAL;
++              add_timer(&bl->timer);
 +      }
 +}
 +
-+static void add_domain_switch(unsigned long domain_id)
++static void board_blink(struct efx_nic *efx, int blink)
 +{
-+      add_event_entry(ESCAPE_CODE);
-+      add_event_entry(DOMAIN_SWITCH_CODE);
-+      add_event_entry(domain_id);
- }
-  
- static void
-@@ -348,9 +374,9 @@
-  * for later lookup from userspace.
-  */
- static int
--add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
-+add_sample(struct mm_struct * mm, struct op_sample * s, int cpu_mode)
- {
--      if (in_kernel) {
-+      if (cpu_mode >= CPU_MODE_KERNEL) {
-               add_sample_entry(s->eip, s->event);
-               return 1;
-       } else if (mm) {
-@@ -496,15 +522,21 @@
-       struct mm_struct *mm = NULL;
-       struct task_struct * new;
-       unsigned long cookie = 0;
--      int in_kernel = 1;
-+      int cpu_mode = 1;
-       unsigned int i;
-       sync_buffer_state state = sb_buffer_start;
-       unsigned long available;
-+      int domain_switch = 0;
-       mutex_lock(&buffer_mutex);
-  
-       add_cpu_switch(cpu);
-+      /* We need to assign the first samples in this CPU buffer to the
-+         same domain that we were processing at the last sync_buffer */
-+      if (cpu_current_domain[cpu] != COORDINATOR_DOMAIN) {
-+              add_domain_switch(cpu_current_domain[cpu]);
++      struct efx_blinker *blinker = &efx->board_info.blinker;
++
++      /* The rtnl mutex serialises all ethtool ioctls, so
++       * nothing special needs doing here. */
++      if (blink) {
++              blinker->resubmit = 1;
++              blinker->state = 0;
++              setup_timer(&blinker->timer, blink_led_timer,
++                          (unsigned long)efx);
++              blinker->timer.expires = jiffies + BLINK_INTERVAL;
++              add_timer(&blinker->timer);
++      } else {
++              blinker->resubmit = 0;
++              if (blinker->timer.function)
++                      del_timer_sync(&blinker->timer);
++              efx->board_info.set_fault_led(efx, 0);
 +      }
-       /* Remember, only we can modify tail_pos */
-       available = get_slots(cpu_buf);
-@@ -512,16 +544,18 @@
-       for (i = 0; i < available; ++i) {
-               struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos];
-  
--              if (is_code(s->eip)) {
--                      if (s->event <= CPU_IS_KERNEL) {
--                              /* kernel/userspace switch */
--                              in_kernel = s->event;
-+              if (is_code(s->eip) && !domain_switch) {
-+                      if (s->event <= CPU_MODE_XEN) {
-+                              /* xen/kernel/userspace switch */
-+                              cpu_mode = s->event;
-                               if (state == sb_buffer_start)
-                                       state = sb_sample_start;
--                              add_kernel_ctx_switch(s->event);
-+                              add_cpu_mode_switch(s->event);
-                       } else if (s->event == CPU_TRACE_BEGIN) {
-                               state = sb_bt_start;
-                               add_trace_begin();
-+                      } else if (s->event == CPU_DOMAIN_SWITCH) {
-+                                      domain_switch = 1;                              
-                       } else {
-                               struct mm_struct * oldmm = mm;
-@@ -535,19 +569,34 @@
-                               add_user_ctx_switch(new, cookie);
-                       }
-               } else {
--                      if (state >= sb_bt_start &&
--                          !add_sample(mm, s, in_kernel)) {
-+                      if (domain_switch) {
-+                              cpu_current_domain[cpu] = s->eip;
-+                              add_domain_switch(s->eip);
-+                              domain_switch = 0;
-+                      } else {
-+                              if (cpu_current_domain[cpu] !=
-+                                  COORDINATOR_DOMAIN) {
-+                                      add_sample_entry(s->eip, s->event);
-+                              }
-+                              else  if (state >= sb_bt_start &&
-+                                  !add_sample(mm, s, cpu_mode)) {
-                               if (state == sb_bt_start) {
-                                       state = sb_bt_ignore;
-                                       atomic_inc(&oprofile_stats.bt_lost_no_mapping);
-                               }
-                       }
-               }
++}
++
++
++struct sensor_conf {
++      const char *name;
++      const unsigned high;
++      const unsigned low;
++};
++
++#define NO_LIMIT      ((unsigned)-1)
++
++#define LM87_SENSOR_BYTES     (18)
++
++static int sensor_limits_to_bytes(const struct sensor_conf *limits,
++                                int nlimits, u8 *bytes, int maxbytes)
++{
++      int i, nbytes;
++      nbytes = 0;
++      for (i = 0; i < nlimits; i++) {
++              bytes[nbytes++] = limits[i].high;
++              if (limits[i].low != NO_LIMIT)
++                      bytes[nbytes++] = limits[i].low;
++              /* We may have overrun by one at this point, but this test
++               * should only trigger in development drivers as the sizes
++               * are not dynamic. */
++              if (nbytes > maxbytes) {
++                      printk(KERN_ERR "%s: out of space!\n", __func__);
++                      break;
 +              }
-               increment_tail(cpu_buf);
-       }
-       release_mm(mm);
-+      /* We reset domain to COORDINATOR at each CPU switch */
-+      if (cpu_current_domain[cpu] != COORDINATOR_DOMAIN) {
-+              add_domain_switch(COORDINATOR_DOMAIN);
 +      }
++      return nbytes;
++}
 +
-       mark_done(cpu);
-       mutex_unlock(&buffer_mutex);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/oprofile/cpu_buffer.c linux-2.6.18-xen.hg/drivers/oprofile/cpu_buffer.c
---- linux-2.6.18/drivers/oprofile/cpu_buffer.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/oprofile/cpu_buffer.c  2007-12-23 11:15:23.420710539 +0100
-@@ -6,6 +6,10 @@
-  *
-  * @author John Levon <levon@movementarian.org>
-  *
-+ * Modified by Aravind Menon for Xen
-+ * These modifications are:
-+ * Copyright (C) 2005 Hewlett-Packard Co.
-+ *
-  * Each CPU has a local buffer that stores PC value/event
-  * pairs. We also log context switches when we notice them.
-  * Eventually each CPU's buffer is processed into the global
-@@ -34,6 +38,8 @@
- #define DEFAULT_TIMER_EXPIRE (HZ / 10)
- static int work_enabled;
-+static int32_t current_domain = COORDINATOR_DOMAIN;
++/*****************************************************************************
++ * Support for the SFE4002
++ *
++ */
++/* LM87 configuration data for the sensor on the SFE4002 board */
++static const struct sensor_conf sfe4002_lm87_limits[] = {
++      {"1.8V line", 0x91, 0x83},      /* 2.5V sensor, scaled for 1.8V */
++      {"1.2V line", 0x5a, 0x51},      /* Vccp1 */
++      {"3.3V line", 0xca, 0xb6},
++      {"5V line", 0xc9, 0xb6},
++      {"12V line", 0xe0, 0xb0},
++      {"1V line", 0x4b, 0x44},        /* vccp2 */
++      {"Ext. temp.", 0x46, 0x0a},     /* ASIC temp. */
++      {"Int. temp.", 0x3c, 0x0a},     /* Board temp. */
++      {"1.66V line", 0xb2, NO_LIMIT}, /* AIN1 only takes 1 value */
++      {"1.5V line", 0xa1, NO_LIMIT}   /* AIN2 only takes 1 value */
++};
++
++static const int sfe4002_lm87_nlimits = ARRAY_SIZE(sfe4002_lm87_limits);
++
++static u16 sfe4002_lm87_irq_mask = EFX_LM87_NO_INTS;
++
++/* I2C ID of the onboard LM87 chip. This is board-specific as the bottom two
++ * bits are set by strap pins */
++#define SFE4002_LM87_I2C_ID (0x2e)
++
++/****************************************************************************/
++/* LED allocations. Note that on rev A0 boards the schematic and the reality
++ * differ: red and green are swapped. Below is the fixed (A1) layout (there
++ * are only 3 A0 boards in existence, so no real reason to make this
++ * conditional).
++ */
++#define SFE4002_FAULT_LED (2) /* Red */
++#define SFE4002_RX_LED    (0) /* Green */
++#define SFE4002_TX_LED    (1) /* Amber */
++
++static int sfe4002_init_leds(struct efx_nic *efx)
++{
++      /* Set the TX and RX LEDs to reflect status and activity, and the
++       * fault LED off */
++      xfp_set_led(efx, SFE4002_TX_LED,
++                  QUAKE_LED_TXLINK | QUAKE_LED_LINK_ACTSTAT);
++      xfp_set_led(efx, SFE4002_RX_LED,
++                  QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
++      xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
++      efx->board_info.blinker.led_num = SFE4002_FAULT_LED;
++      return 0;
++}
 +
- void free_cpu_buffers(void)
- {
-       int i;
-@@ -57,7 +63,7 @@
-                       goto fail;
-  
-               b->last_task = NULL;
--              b->last_is_kernel = -1;
-+              b->last_cpu_mode = -1;
-               b->tracing = 0;
-               b->buffer_size = buffer_size;
-               b->tail_pos = 0;
-@@ -113,7 +119,7 @@
-        * collected will populate the buffer with proper
-        * values to initialize the buffer
-        */
--      cpu_buf->last_is_kernel = -1;
-+      cpu_buf->last_cpu_mode = -1;
-       cpu_buf->last_task = NULL;
- }
-@@ -163,13 +169,13 @@
-  * because of the head/tail separation of the writer and reader
-  * of the CPU buffer.
-  *
-- * is_kernel is needed because on some architectures you cannot
-+ * cpu_mode is needed because on some architectures you cannot
-  * tell if you are in kernel or user space simply by looking at
-- * pc. We tag this in the buffer by generating kernel enter/exit
-- * events whenever is_kernel changes
-+ * pc. We tag this in the buffer by generating kernel/user (and xen)
-+ *  enter events whenever cpu_mode changes
-  */
- static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc,
--                    int is_kernel, unsigned long event)
-+                    int cpu_mode, unsigned long event)
- {
-       struct task_struct * task;
-@@ -180,18 +186,18 @@
-               return 0;
-       }
--      is_kernel = !!is_kernel;
--
-       task = current;
-       /* notice a switch from user->kernel or vice versa */
--      if (cpu_buf->last_is_kernel != is_kernel) {
--              cpu_buf->last_is_kernel = is_kernel;
--              add_code(cpu_buf, is_kernel);
-+      if (cpu_buf->last_cpu_mode != cpu_mode) {
-+              cpu_buf->last_cpu_mode = cpu_mode;
-+              add_code(cpu_buf, cpu_mode);
-       }
-       /* notice a task switch */
--      if (cpu_buf->last_task != task) {
-+      /* if not processing other domain samples */
-+      if ((cpu_buf->last_task != task) &&
-+          (current_domain == COORDINATOR_DOMAIN)) {
-               cpu_buf->last_task = task;
-               add_code(cpu_buf, (unsigned long)task);
-       }
-@@ -275,6 +281,25 @@
-       add_sample(cpu_buf, pc, 0);
- }
-+int oprofile_add_domain_switch(int32_t domain_id)
++static void sfe4002_fault_led(struct efx_nic *efx, int state)
 +{
-+      struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()];
++      xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON :
++                      QUAKE_LED_OFF);
++}
 +
-+      /* should have space for switching into and out of domain 
-+         (2 slots each) plus one sample and one cpu mode switch */
-+      if (((nr_available_slots(cpu_buf) < 6) && 
-+           (domain_id != COORDINATOR_DOMAIN)) ||
-+          (nr_available_slots(cpu_buf) < 2))
-+              return 0;
++static int sfe4002_sensor_meaning(struct efx_nic *efx, int limit_num,
++                                unsigned val)
++{
++      const struct sensor_conf *lim = &sfe4002_lm87_limits[limit_num];
++      if (lim->low == NO_LIMIT)
++              EFX_ERR(efx, "%10s  0x%02x (nominal value 0x%02x)\n", lim->name,
++                      val, lim->high);
++      else
++              EFX_ERR(efx, "%10s  0x%02x (nominal range 0x%02x - 0x%02x)\n",
++                      lim->name, val, lim->high, lim->low);
++      return 1;
++}
 +
-+      add_code(cpu_buf, CPU_DOMAIN_SWITCH);
-+      add_sample(cpu_buf, domain_id, 0);
++static int sfe4002_check_hw(struct efx_nic *efx)
++{
++      int rc;
 +
-+      current_domain = domain_id;
++      /* A0 board rev. 4002s  report a temperature fault the whole time
++       * (bad sensor) so we mask it out. */
++      unsigned alarm_mask = (efx->board_info.minor > 0) ?
++              0 : ~EFX_LM87_ETMP_INT;
 +
-+      return 1;
++      /* Check the sensor (NOP if not present). */
++      rc = efx_check_lm87(efx, alarm_mask);
++
++      /* We treat both lm87 interrupts and failure to talk to the lm87
++       * as problems (since failure will only be reported if we did
++       * find the sensor at probe time. */
++      if (rc)
++              EFX_ERR(efx, "sensor alert!\n");
++      return rc;
 +}
 +
- /*
-  * This serves to avoid cpu buffer overflow, and makes sure
-  * the task mortuary progresses
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/oprofile/cpu_buffer.h linux-2.6.18-xen.hg/drivers/oprofile/cpu_buffer.h
---- linux-2.6.18/drivers/oprofile/cpu_buffer.h 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/oprofile/cpu_buffer.h  2007-12-23 11:15:23.420710539 +0100
-@@ -36,7 +36,7 @@
-       volatile unsigned long tail_pos;
-       unsigned long buffer_size;
-       struct task_struct * last_task;
--      int last_is_kernel;
-+      int last_cpu_mode;
-       int tracing;
-       struct op_sample * buffer;
-       unsigned long sample_received;
-@@ -51,7 +51,10 @@
- void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf);
- /* transient events for the CPU buffer -> event buffer */
--#define CPU_IS_KERNEL 1
--#define CPU_TRACE_BEGIN 2
-+#define CPU_MODE_USER           0
-+#define CPU_MODE_KERNEL         1
-+#define CPU_MODE_XEN            2
-+#define CPU_TRACE_BEGIN         3
-+#define CPU_DOMAIN_SWITCH       4
- #endif /* OPROFILE_CPU_BUFFER_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/oprofile/event_buffer.h linux-2.6.18-xen.hg/drivers/oprofile/event_buffer.h
---- linux-2.6.18/drivers/oprofile/event_buffer.h       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/oprofile/event_buffer.h        2007-12-23 11:15:23.420710539 +0100
-@@ -29,15 +29,20 @@
- #define CPU_SWITCH_CODE               2
- #define COOKIE_SWITCH_CODE            3
- #define KERNEL_ENTER_SWITCH_CODE      4
--#define KERNEL_EXIT_SWITCH_CODE               5
-+#define USER_ENTER_SWITCH_CODE                5
- #define MODULE_LOADED_CODE            6
- #define CTX_TGID_CODE                 7
- #define TRACE_BEGIN_CODE              8
- #define TRACE_END_CODE                        9
-+#define XEN_ENTER_SWITCH_CODE         10
-+#define DOMAIN_SWITCH_CODE            11
-  
- #define INVALID_COOKIE ~0UL
- #define NO_COOKIE 0UL
-+/* Constant used to refer to coordinator domain (Xen) */
-+#define COORDINATOR_DOMAIN -1
++static int sfe4002_init(struct efx_nic *efx)
++{
++      u8 lm87_bytes[LM87_SENSOR_BYTES];
++      int nbytes;
++      int rc;
 +
- /* add data to the event buffer */
- void add_event_entry(unsigned long data);
-  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/oprofile/oprof.c linux-2.6.18-xen.hg/drivers/oprofile/oprof.c
---- linux-2.6.18/drivers/oprofile/oprof.c      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/oprofile/oprof.c       2007-12-23 11:15:23.420710539 +0100
-@@ -5,6 +5,10 @@
-  * @remark Read the file COPYING
-  *
-  * @author John Levon <levon@movementarian.org>
++      efx->board_info.monitor = sfe4002_check_hw;
++      efx->board_info.interpret_sensor = sfe4002_sensor_meaning;
++      efx->board_info.init_leds = sfe4002_init_leds;
++      efx->board_info.set_fault_led = sfe4002_fault_led;
++      efx->board_info.blink = board_blink;
++      /* To clean up shut down the lm87 (NOP if not present) */
++      efx->board_info.fini = efx_remove_lm87;
++
++      nbytes = sensor_limits_to_bytes(sfe4002_lm87_limits,
++                                      sfe4002_lm87_nlimits, lm87_bytes,
++                                      LM87_SENSOR_BYTES);
++
++      /* Activate the lm87 sensor if present (succeeds if nothing there) */
++      rc = efx_probe_lm87(efx, SFE4002_LM87_I2C_ID,
++                          lm87_bytes, nbytes, sfe4002_lm87_irq_mask);
++
++      return rc;
++}
++
++/*****************************************************************************
++ * Support for the SFE4003
 + *
-+ * Modified by Aravind Menon for Xen
-+ * These modifications are:
-+ * Copyright (C) 2005 Hewlett-Packard Co.
-  */
- #include <linux/kernel.h>
-@@ -33,6 +37,32 @@
-  */
- static int timer = 0;
-+int oprofile_set_active(int active_domains[], unsigned int adomains)
-+{
-+      int err;
++ */
++/* LM87 configuration data for the sensor on the SFE4003 board */
++static const struct sensor_conf sfe4003_lm87_limits[] = {
++      {"1.5V line", 0x78, 0x6d},      /* 2.5V input, values scaled for 1.5V */
++      {"1.2V line", 0x5a, 0x51},      /* Vccp1 */
++      {"3.3V line", 0xca, 0xb6},
++      {"5V line", 0xc0, 0x00},        /* Sensor not connected. */
++      {"12V line", 0xe0, 0xb0},
++      {"1V line", 0x4b, 0x44},        /* Vccp2 */
++      {"Ext. temp.", 0x46, 0x0a},     /* ASIC temp. */
++      {"Int. temp.", 0x3c, 0x0a},     /* Board temp. */
++      {"", 0xff, NO_LIMIT},           /* FAN1/AIN1 unused */
++      {"", 0xff, NO_LIMIT}            /* FAN2/AIN2 unused */
++};
 +
-+      if (!oprofile_ops.set_active)
-+              return -EINVAL;
++static const int sfe4003_lm87_nlimits = ARRAY_SIZE(sfe4003_lm87_limits);
 +
-+      mutex_lock(&start_mutex);
-+      err = oprofile_ops.set_active(active_domains, adomains);
-+      mutex_unlock(&start_mutex);
-+      return err;
++static u16 sfe4003_lm87_irq_mask = EFX_LM87_NO_INTS;
++
++
++static int sfe4003_sensor_meaning(struct efx_nic *efx, int limit_num,
++                                unsigned val)
++{
++      const struct sensor_conf *lim = &sfe4003_lm87_limits[limit_num];
++      if (lim->low == NO_LIMIT)
++              return 0; /* Neither AIN1 nor AIN2 mean anything to us */
++      else
++              EFX_ERR(efx, "%10s  0x%02x (nominal range 0x%02x - 0x%02x)\n",
++                      lim->name, val, lim->high, lim->low);
++      return 1;
 +}
 +
-+int oprofile_set_passive(int passive_domains[], unsigned int pdomains)
++/* I2C ID of the onboard LM87 chip. This is board-specific as the bottom two
++ * bits are set by strap pins */
++#define SFE4003_LM87_I2C_ID (0x2e)
++
++/* Board-specific LED info. */
++#define SFE4003_RED_LED_GPIO  (11)
++#define SFE4003_LED_ON                (1)
++#define SFE4003_LED_OFF               (0)
++
++static void sfe4003_fault_led(struct efx_nic *efx, int state)
 +{
-+      int err;
++      /* The LEDs were not wired to GPIOs before A3 */
++      if (efx->board_info.minor < 3 && efx->board_info.major == 0)
++              return;
 +
-+      if (!oprofile_ops.set_passive)
-+              return -EINVAL;
++      txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO,
++                       state ? SFE4003_LED_ON : SFE4003_LED_OFF);
++}
 +
-+      mutex_lock(&start_mutex);
-+      err = oprofile_ops.set_passive(passive_domains, pdomains);
-+      mutex_unlock(&start_mutex);
-+      return err;
++static int sfe4003_init_leds(struct efx_nic *efx)
++{
++      /* The LEDs were not wired to GPIOs before A3 */
++      if (efx->board_info.minor < 3 && efx->board_info.major == 0)
++              return 0;
++
++      txc_set_gpio_dir(efx, SFE4003_RED_LED_GPIO, TXC_GPIO_DIR_OUTPUT);
++      txc_set_gpio_val(efx, SFE4003_RED_LED_GPIO, SFE4003_LED_OFF);
++      return 0;
 +}
 +
- int oprofile_setup(void)
- {
-       int err;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/oprofile/oprof.h linux-2.6.18-xen.hg/drivers/oprofile/oprof.h
---- linux-2.6.18/drivers/oprofile/oprof.h      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/oprofile/oprof.h       2007-12-23 11:15:23.420710539 +0100
-@@ -36,4 +36,7 @@
- int oprofile_set_backtrace(unsigned long depth);
-  
-+int oprofile_set_active(int active_domains[], unsigned int adomains);
-+int oprofile_set_passive(int passive_domains[], unsigned int pdomains);
-+ 
- #endif /* OPROF_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/oprofile/oprofile_files.c linux-2.6.18-xen.hg/drivers/oprofile/oprofile_files.c
---- linux-2.6.18/drivers/oprofile/oprofile_files.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/oprofile/oprofile_files.c      2007-12-23 11:15:23.420710539 +0100
-@@ -5,10 +5,16 @@
-  * @remark Read the file COPYING
-  *
-  * @author John Levon <levon@movementarian.org>
-+ *
-+ * Modified by Aravind Menon for Xen
-+ * These modifications are:
-+ * Copyright (C) 2005 Hewlett-Packard Co.     
-  */
- #include <linux/fs.h>
- #include <linux/oprofile.h>
-+#include <asm/uaccess.h>
-+#include <linux/ctype.h>
- #include "event_buffer.h"
- #include "oprofile_stats.h"
-@@ -118,10 +124,201 @@
-       .write          = dump_write,
- };
-  
-+#define TMPBUFSIZE 512
++static int sfe4003_check_hw(struct efx_nic *efx)
++{
++      int rc;
++      /* A0/A1/A2 board rev. 4003s  report a temperature fault the whole time
++       * (bad sensor) so we mask it out. */
++      unsigned alarm_mask =
++              ~(EFX_LM87_ETMP_INT | EFX_LM87_FAN1_INT | EFX_LM87_FAN2_INT);
 +
-+static unsigned int adomains = 0;
-+static int active_domains[MAX_OPROF_DOMAINS + 1];
-+static DEFINE_MUTEX(adom_mutex);
++      /* Check the sensor (NOP if not present). */
 +
-+static ssize_t adomain_write(struct file * file, char const __user * buf, 
-+                           size_t count, loff_t * offset)
++      rc = efx_check_lm87(efx, alarm_mask);
++      /* We treat both lm87 interrupts and failure to talk to the lm87
++       * as problems (since failure will only be reported if we did
++       * find the sensor at probe time. */
++      if (rc)
++              EFX_ERR(efx, "sensor alert!\n");
++
++      return rc;
++}
++
++static int sfe4003_init(struct efx_nic *efx)
 +{
-+      char *tmpbuf;
-+      char *startp, *endp;
-+      int i;
-+      unsigned long val;
-+      ssize_t retval = count;
-+      
-+      if (*offset)
-+              return -EINVAL; 
-+      if (count > TMPBUFSIZE - 1)
-+              return -EINVAL;
++      u8 lm87_bytes[LM87_SENSOR_BYTES];
++      int nbytes;
++      int rc;
++      efx->board_info.monitor = sfe4003_check_hw;
++      efx->board_info.interpret_sensor = sfe4003_sensor_meaning;
++      efx->board_info.init_leds = sfe4003_init_leds;
++      efx->board_info.set_fault_led = sfe4003_fault_led;
++      efx->board_info.blink = board_blink;
++      /* To clean up shut down the lm87 (NOP if not present) */
++      efx->board_info.fini = efx_remove_lm87;
++
++      nbytes = sensor_limits_to_bytes(sfe4003_lm87_limits,
++                                      sfe4003_lm87_nlimits, lm87_bytes,
++                                      LM87_SENSOR_BYTES);
++
++      /* Activate the lm87 sensor if present (succeeds if nothing there) */
++      rc = efx_probe_lm87(efx, SFE4003_LM87_I2C_ID,
++                          lm87_bytes, nbytes, sfe4003_lm87_irq_mask);
 +
-+      if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
-+              return -ENOMEM;
++      if (rc < 0)
++              EFX_ERR(efx, "Temperature sensor probe failure: "
++                      "please check the jumper position\n");
++      return rc;
++}
 +
-+      if (copy_from_user(tmpbuf, buf, count)) {
-+              kfree(tmpbuf);
-+              return -EFAULT;
++/*****************************************************************************
++ * Support for the SFE4005
++ *
++ */
++/* LM87 configuration data for the sensor on the SFE4005 board */
++static const u8 sfe4005_lm87_limits[] = {
++      0x51, /* 2.5V high lim. (actually monitor 1.0V line, so 1050mV)  */
++      0x49, /* 2.5V low lim. (950mV) */
++      0xf6, /* Vccp1 high lim. (3.3V rail, 3465 mV) */
++      0xde, /* Vcpp1 low lim. (3.3V rail, 3135 mV) */
++      0xca, /* 3.3V AUX high lim. (3465 mV)  */
++      0xb6, /* 3.3V AUX low lim. (3135mV) */
++      0xc0, /* 5V high lim. not connected) */
++      0x00, /* 5V low lim. (not connected) */
++      0xd0, /* 12V high lim. (13000mV) */
++      0xb0, /* 12V low lim. (11000mV) */
++      0xc0, /* Vccp2 high lim. (unused) */
++      0x00, /* Vccp2 low lim. (unused) */
++      0x46, /* Ext temp 1 (ASIC) high lim. */
++      0x0a, /* Ext temp 1 low lim. */
++      0x3c, /* Int temp (board) high lim. */
++      0x0a, /* Int temp 1 low lim. */
++      0xff, /* Fan 1 high (unused) */
++      0xff, /* Fan 2 high (unused) */
++};
++
++#define SFE4005_LM87_I2C_ID (0x2e)
++
++/* Until the LM87 monitoring is interrupt driven. */
++#define SFE4005_LM87_IRQMASK  EFX_LM87_NO_INTS
++
++#define SFE4005_PCF8575_I2C_ID        (0x20)
++/* Definitions for the I/O expander that controls the CX4 chip:
++ * which PCF8575 pin maps to which function */
++#define SFE4005_PORT0_EXTLOOP (1 << 0)
++#define SFE4005_PORT1_EXTLOOP (1 << 1)
++#define SFE4005_HOSTPROT_LOOP (1 << 2)
++#define SFE4005_BCAST         (1 << 3) /* TX on both ports */
++#define SFE4005_PORT0_EQ      (1 << 4)
++#define SFE4005_PORT1_EQ      (1 << 5)
++#define SFE4005_HOSTPORT_EQ   (1 << 6)
++#define       SFE4005_PORTSEL         (1 << 7) /* Which port (for RX in BCAST mode) */
++#define SFE4005_PORT0_PRE_LBN (8)      /* Preemphasis on port 0 (2 bits)*/
++#define SFE4005_PORT1_PRE_LBN (10)     /* Preemphasis on port 1 (2 bits)*/
++#define SFE4005_HOSTPORT_PRE_LBN (12)    /* Preemphasis on host port (2 bits) */
++#define SFE4005_UNUSED                (1 << 14)
++#define SFE4005_CX4uC_nRESET  (1 << 15) /* Reset the controller on CX4 chip */
++
++
++/* By default only turn on host port EQ. Can also OR in SFE4005_PORT0_EQ,
++ * SFE4005_PORT1_EQ but this hasn't been seen to make a difference. */
++#define SFE4005_CX4_DEFAULTS (SFE4005_CX4uC_nRESET | SFE4005_HOSTPORT_EQ)
++
++static int sfe4005_write_ioexpander(struct efx_nic *efx)
++{
++      unsigned long iobits = (unsigned long)efx->phy_data;
++      struct efx_i2c_interface *i2c = &efx->i2c;
++      u8 send[2], check[2];
++      int rc;
++      /* Do not, EVER, deassert nRESET as that will reset Falcon too,
++       * and the driver won't know to repush the configuration, so
++       * nothing will work until the next power cycle. */
++      BUG_ON(!(iobits & SFE4005_CX4uC_nRESET));
++      send[0] = (iobits & 0xff);
++      send[1] = ((iobits >> 8) & 0xff);
++      rc = efx_i2c_send_bytes(i2c, SFE4005_PCF8575_I2C_ID, send, 2);
++      if (rc) {
++              EFX_ERR(efx, "failed to write to I/O expander: %d\n", rc);
++              return rc;
 +      }
-+      tmpbuf[count] = 0;
++      /* Paranoia: just check what the I/O expander reads back */
++      rc = efx_i2c_recv_bytes(i2c, SFE4005_PCF8575_I2C_ID, check, 2);
++      if (rc)
++              EFX_ERR(efx, "failed to read back from I/O expander: %d\n", rc);
++      else if (check[0] != send[0] || check[1] != send[1])
++              EFX_ERR(efx, "read back wrong value from I/O expander: "
++                      "wanted %.2x%.2x, got %.2x%.2x\n",
++                      send[1], send[0], check[1], check[0]);
++      return rc;
++}
 +
-+      mutex_lock(&adom_mutex);
++static int sfe4005_init(struct efx_nic *efx)
++{
++      unsigned long iobits = SFE4005_CX4_DEFAULTS;
++      int rc;
 +
-+      startp = tmpbuf;
-+      /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
-+      for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
-+              val = simple_strtoul(startp, &endp, 0);
-+              if (endp == startp)
++      /* There is no PHY as such on the SFE4005 so phy_data is ours. */
++      efx->phy_data = (void *)iobits;
++
++      /* Push the values */
++      rc = sfe4005_write_ioexpander(efx);
++      if (rc)
++              return rc;
++
++      /* Activate the lm87 sensor if present (succeeds if nothing there) */
++      rc = efx_probe_lm87(efx, SFE4005_LM87_I2C_ID,
++                          sfe4005_lm87_limits,
++                          sizeof(sfe4005_lm87_limits), SFE4005_LM87_IRQMASK);
++
++      /* To clean up shut down the lm87 (NOP if not present) */
++      efx->board_info.fini = efx_remove_lm87;
++
++      return rc;
++}
++
++/* This will get expanded as board-specific details get moved out of the
++ * PHY drivers. */
++struct efx_board_data {
++      const char *ref_model;
++      const char *gen_type;
++      int (*init) (struct efx_nic *nic);
++      unsigned mwatts;
++};
++
++static void dummy_fini(struct efx_nic *nic)
++{
++}
++
++static int dummy_init(struct efx_nic *nic)
++{
++      nic->board_info.fini = dummy_fini;
++      return 0;
++}
++
++/* Maximum board power (mW)
++ * Falcon controller ASIC accounts for 2.2W
++ * 10Xpress PHY accounts for 12W
++ *
++ */
++#define SFE4001_POWER 18000
++#define SFE4002_POWER 7500
++#define SFE4003_POWER 4500
++#define SFE4005_POWER 4500
++
++static struct efx_board_data board_data[] = {
++      [EFX_BOARD_INVALID] =
++      {NULL,      NULL,                  dummy_init,      0},
++      [EFX_BOARD_SFE4001] =
++      {"SFE4001", "10GBASE-T adapter",   sfe4001_poweron, SFE4001_POWER },
++      [EFX_BOARD_SFE4002] =
++      {"SFE4002", "XFP adapter",         sfe4002_init,    SFE4002_POWER },
++      [EFX_BOARD_SFE4003] =
++      {"SFE4003", "10GBASE-CX4 adapter", sfe4003_init,    SFE4003_POWER },
++      [EFX_BOARD_SFE4005] =
++      {"SFE4005", "10G blade adapter",   sfe4005_init,    SFE4005_POWER },
++};
++
++int efx_set_board_info(struct efx_nic *efx, u16 revision_info)
++{
++      int rc = 0;
++      struct efx_board_data *data;
++
++      if (BOARD_TYPE(revision_info) >= EFX_BOARD_MAX) {
++              EFX_ERR(efx, "squashing unknown board type %d\n",
++                      BOARD_TYPE(revision_info));
++              revision_info = 0;
++      }
++
++      if (BOARD_TYPE(revision_info) == 0) {
++              efx->board_info.major = 0;
++              efx->board_info.minor = 0;
++              /* For early boards that don't have revision info. there is
++               * only 1 board for each PHY type, so we can work it out, with
++               * the exception of the PHY-less boards. */
++              switch (efx->phy_type) {
++              case PHY_TYPE_10XPRESS:
++                      efx->board_info.type = EFX_BOARD_SFE4001;
 +                      break;
-+              while (ispunct(*endp) || isspace(*endp))
-+                      endp++;
-+              active_domains[i] = val;
-+              if (active_domains[i] != val)
-+                      /* Overflow, force error below */
-+                      i = MAX_OPROF_DOMAINS + 1;
-+              startp = endp;
++              case PHY_TYPE_XFP:
++                      efx->board_info.type = EFX_BOARD_SFE4002;
++                      break;
++              case PHY_TYPE_CX4_RTMR:
++                      efx->board_info.type = EFX_BOARD_SFE4003;
++                      break;
++              default:
++                      efx->board_info.type = 0;
++                      break;
++              }
++      } else {
++              efx->board_info.type = BOARD_TYPE(revision_info);
++              efx->board_info.major = BOARD_MAJOR(revision_info);
++              efx->board_info.minor = BOARD_MINOR(revision_info);
 +      }
-+      /* Force error on trailing junk */
-+      adomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
 +
-+      kfree(tmpbuf);
++      data = &board_data[efx->board_info.type];
 +
-+      if (adomains > MAX_OPROF_DOMAINS
-+          || oprofile_set_active(active_domains, adomains)) {
-+              adomains = 0;
-+              retval = -EINVAL;
-+      }
++      /* Report the board model number or generic type for recognisable
++       * boards. */
++      if (efx->board_info.type != 0)
++              EFX_INFO(efx, "board is %s rev %c%d\n",
++                       (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC)
++                       ? data->ref_model : data->gen_type,
++                       'A' + efx->board_info.major, efx->board_info.minor);
 +
-+      mutex_unlock(&adom_mutex);
-+      return retval;
++      efx->board_info.init = data->init;
++      efx->board_info.mwatts = data->mwatts;
++
++      return rc;
 +}
+--- linux-2.6.18.8/drivers/net/sfc/boards.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/boards.h       2008-05-19 00:33:28.829807910 +0300
+@@ -0,0 +1,51 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2007:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static ssize_t adomain_read(struct file * file, char __user * buf, 
-+                          size_t count, loff_t * offset)
-+{
-+      char * tmpbuf;
-+      size_t len;
-+      int i;
-+      ssize_t retval;
++#ifndef EFX_BOARDS_H
++#define EFX_BOARDS_H
 +
-+      if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
-+              return -ENOMEM;
++/* Board IDs (must fit in 8 bits). Note that 0 must never be assigned because
++ * on early boards it means there is no revision info. Board types pre 400x
++ * are not covered here, but this is not a problem because:
++ * - the early Falcon boards (FPGA, 401, 403) don't have any extra H/W we
++ * need care about and aren't being updated.
++ */
++enum efx_board_type {
++      EFX_BOARD_INVALID = 0, /* Early boards do not have board rev. info. */
++      EFX_BOARD_SFE4001 = 1,
++      EFX_BOARD_SFE4002 = 2,
++      EFX_BOARD_SFE4003 = 3,
++      EFX_BOARD_SFE4005 = 4,
++      /* Insert new types before here */
++      EFX_BOARD_MAX
++};
 +
-+      mutex_lock(&adom_mutex);
++extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info);
 +
-+      len = 0;
-+      for (i = 0; i < adomains; i++)
-+              len += snprintf(tmpbuf + len,
-+                              len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
-+                              "%u ", active_domains[i]);
-+      WARN_ON(len > TMPBUFSIZE);
-+      if (len != 0 && len <= TMPBUFSIZE)
-+              tmpbuf[len-1] = '\n';
++/* SFE4001 (10GBASE-T) */
++extern int sfe4001_poweron(struct efx_nic *efx);
++extern void sfe4001_poweroff(struct efx_nic *efx);
 +
-+      mutex_unlock(&adom_mutex);
++#endif
+--- linux-2.6.18.8/drivers/net/sfc/config.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/config.h       2008-05-19 00:33:28.829807910 +0300
+@@ -0,0 +1 @@
++/* SFC config options can go here */
+--- linux-2.6.18.8/drivers/net/sfc/debugfs.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/debugfs.c      2008-05-19 00:33:28.829807910 +0300
+@@ -0,0 +1,924 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
++#include <linux/module.h>
++#include <linux/pci.h>
++/* For out-of-tree builds we always need procfs, if only for a compatibility
++ * symlink.
++ */
++#include <linux/proc_fs.h>
++#include <linux/dcache.h>
++#include <linux/seq_file.h>
++#include "net_driver.h"
++#include "efx.h"
++#include "debugfs.h"
++#include "falcon.h"
 +
-+      kfree(tmpbuf);
-+      return retval;
++/* EFX_USE_DEBUGFS is defined by kernel_compat.h so we can't decide whether to
++ * include this earlier.
++ */
++#ifdef EFX_USE_DEBUGFS
++#include <linux/debugfs.h>
++#endif
++
++#ifndef PRIu64
++#     if (BITS_PER_LONG == 64)
++#             define PRIu64 "lu"
++#     else
++#             define PRIu64 "llu"
++#     endif
++#endif
++
++#ifndef EFX_USE_DEBUGFS
++
++static void efx_debugfs_remove(struct proc_dir_entry *entry)
++{
++      if (entry)
++              remove_proc_entry(entry->name, entry->parent);
 +}
++#define debugfs_remove efx_debugfs_remove
 +
++#define debugfs_create_dir proc_mkdir
++#define debugfs_create_symlink proc_symlink
 +
-+static struct file_operations active_domain_ops = {
-+      .read           = adomain_read,
-+      .write          = adomain_write,
++#endif /* !EFX_USE_DEBUGFS */
++
++/* Parameter definition bound to a structure - each file has one of these */
++struct efx_debugfs_bound_param {
++      const struct efx_debugfs_parameter *param;
++      void *structure;
 +};
 +
-+static unsigned int pdomains = 0;
-+static int passive_domains[MAX_OPROF_DOMAINS];
-+static DEFINE_MUTEX(pdom_mutex);
 +
-+static ssize_t pdomain_write(struct file * file, char const __user * buf, 
-+                           size_t count, loff_t * offset)
++/* Maximum length for a name component or symlink target */
++#define EFX_DEBUGFS_NAME_LEN 32
++
++
++/* Top-level debug directory ([/sys/kernel]/debug/sfc) */
++static struct dentry *efx_debug_root;
++
++/* "cards" directory ([/sys/kernel]/debug/sfc/cards) */
++static struct dentry *efx_debug_cards;
++
++
++/* Sequential file interface to bound parameters */
++
++#if defined(EFX_USE_DEBUGFS)
++
++static int efx_debugfs_seq_show(struct seq_file *file, void *v)
 +{
-+      char *tmpbuf;
-+      char *startp, *endp;
-+      int i;
-+      unsigned long val;
-+      ssize_t retval = count;
-+      
-+      if (*offset)
-+              return -EINVAL; 
-+      if (count > TMPBUFSIZE - 1)
-+              return -EINVAL;
++      struct efx_debugfs_bound_param *binding =
++              (struct efx_debugfs_bound_param *)file->private;
 +
-+      if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
-+              return -ENOMEM;
++      return binding->param->reader(file,
++                                    binding->structure +
++                                    binding->param->offset);
++}
 +
-+      if (copy_from_user(tmpbuf, buf, count)) {
-+              kfree(tmpbuf);
-+              return -EFAULT;
-+      }
-+      tmpbuf[count] = 0;
++static int efx_debugfs_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, efx_debugfs_seq_show, inode->i_private);
++}
 +
-+      mutex_lock(&pdom_mutex);
++#else /* EFX_NOT_UPSTREAM && !EFX_USE_DEBUGFS */
 +
-+      startp = tmpbuf;
-+      /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
-+      for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
-+              val = simple_strtoul(startp, &endp, 0);
-+              if (endp == startp)
-+                      break;
-+              while (ispunct(*endp) || isspace(*endp))
-+                      endp++;
-+              passive_domains[i] = val;
-+              if (passive_domains[i] != val)
-+                      /* Overflow, force error below */
-+                      i = MAX_OPROF_DOMAINS + 1;
-+              startp = endp;
++static int efx_debugfs_seq_show(struct seq_file *file, void *v)
++{
++      struct proc_dir_entry *entry = (struct proc_dir_entry *)file->private;
++      struct efx_debugfs_parameter *param =
++              (struct efx_debugfs_parameter *)entry->data;
++      void *structure = (void *)entry->read_proc;
++
++      if (!structure)
++              return -EIO;
++
++      return param->reader(file, structure + param->offset);
++}
++
++static int efx_debugfs_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, efx_debugfs_seq_show, PROC_I(inode)->pde);
++}
++
++#endif /* !EFX_NOT_UPSTREAM || EFX_USE_DEBUGFS */
++
++
++static struct file_operations efx_debugfs_file_ops = {
++      .owner   = THIS_MODULE,
++      .open    = efx_debugfs_open,
++      .read    = seq_read,
++      .llseek  = seq_lseek,
++      .release = seq_release
++};
++
++
++#if defined(EFX_USE_DEBUGFS)
++
++/**
++ * efx_fini_debugfs_child - remove a named child of a debugfs directory
++ * @dir:              Directory
++ * @name:             Name of child
++ *
++ * This removes the named child from the directory, if it exists.
++ */
++void efx_fini_debugfs_child(struct dentry *dir, const char *name)
++{
++      struct qstr child_name;
++      struct dentry *child;
++
++      child_name.len = strlen(name);
++      child_name.name = name;
++      child_name.hash = full_name_hash(child_name.name, child_name.len);
++      child = d_lookup(dir, &child_name);
++      if (child) {
++              /* If it's a "regular" file, free its parameter binding */
++              if (S_ISREG(child->d_inode->i_mode))
++                      kfree(child->d_inode->i_private);
++              debugfs_remove(child);
++              dput(child);
 +      }
-+      /* Force error on trailing junk */
-+      pdomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
++}
 +
-+      kfree(tmpbuf);
++#else /* EFX_NOT_UPSTREAM && !EFX_USE_DEBUGFS */
 +
-+      if (pdomains > MAX_OPROF_DOMAINS
-+          || oprofile_set_passive(passive_domains, pdomains)) {
-+              pdomains = 0;
-+              retval = -EINVAL;
++void efx_fini_debugfs_child(struct proc_dir_entry *dir, const char *name)
++{
++      remove_proc_entry(name, dir);
++}
++
++#endif /* !EFX_NOT_UPSTREAM || EFX_USE_DEBUGFS */
++
++/*
++ * Remove a debugfs directory.
++ *
++ * This removes the named parameter-files and sym-links from the
++ * directory, and the directory itself.  It does not do any recursion
++ * to subdirectories.
++ */
++static void efx_fini_debugfs_dir(struct dentry *dir,
++                               struct efx_debugfs_parameter *params,
++                               const char *const *symlink_names)
++{
++      if (!dir)
++              return;
++
++      while (params->name) {
++              efx_fini_debugfs_child(dir, params->name);
++              params++;
 +      }
++      while (symlink_names && *symlink_names) {
++              efx_fini_debugfs_child(dir, *symlink_names);
++              symlink_names++;
++      }
++      debugfs_remove(dir);
++}
 +
-+      mutex_unlock(&pdom_mutex);
-+      return retval;
++/* Functions for printing various types of parameter. */
++
++int efx_debugfs_read_uint(struct seq_file *file, void *data)
++{
++      return seq_printf(file, "%#x\n", *(unsigned int *)data);
 +}
 +
-+static ssize_t pdomain_read(struct file * file, char __user * buf, 
-+                          size_t count, loff_t * offset)
++int efx_debugfs_read_int(struct seq_file *file, void *data)
 +{
-+      char * tmpbuf;
-+      size_t len;
-+      int i;
-+      ssize_t retval;
++      return seq_printf(file, "%d\n", *(int *)data);
++}
 +
-+      if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
-+              return -ENOMEM;
++int efx_debugfs_read_atomic(struct seq_file *file, void *data)
++{
++      unsigned int value = atomic_read((atomic_t *) data);
 +
-+      mutex_lock(&pdom_mutex);
++      return seq_printf(file, "%#x\n", value);
++}
 +
-+      len = 0;
-+      for (i = 0; i < pdomains; i++)
-+              len += snprintf(tmpbuf + len,
-+                              len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
-+                              "%u ", passive_domains[i]);
-+      WARN_ON(len > TMPBUFSIZE);
-+      if (len != 0 && len <= TMPBUFSIZE)
-+              tmpbuf[len-1] = '\n';
++int efx_debugfs_read_dword(struct seq_file *file, void *data)
++{
++      unsigned int value = EFX_DWORD_FIELD(*(efx_dword_t *) data,
++                                           EFX_DWORD_0);
 +
-+      mutex_unlock(&pdom_mutex);
++      return seq_printf(file, "%#x\n", value);
++}
 +
-+      retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
++static int efx_debugfs_read_int_mode(struct seq_file *file, void *data)
++{
++      unsigned int value = *(enum efx_int_mode *) data;
 +
-+      kfree(tmpbuf);
-+      return retval;
++      return seq_printf(file, "%d => %s\n", value,
++                        STRING_TABLE_LOOKUP(value, efx_interrupt_mode));
 +}
 +
-+static struct file_operations passive_domain_ops = {
-+      .read           = pdomain_read,
-+      .write          = pdomain_write,
-+};
++#define EFX_INT_MODE_PARAMETER(container_type, parameter)             \
++      EFX_PARAMETER(container_type, parameter,                        \
++                    enum efx_int_mode, efx_debugfs_read_int_mode)
 +
- void oprofile_create_files(struct super_block * sb, struct dentry * root)
- {
-       oprofilefs_create_file(sb, root, "enable", &enable_fops);
-       oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666);
-+      oprofilefs_create_file(sb, root, "active_domains", &active_domain_ops);
-+      oprofilefs_create_file(sb, root, "passive_domains", &passive_domain_ops);
-       oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops);
-       oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size);
-       oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/pci/bus.c linux-2.6.18-xen.hg/drivers/pci/bus.c
---- linux-2.6.18/drivers/pci/bus.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/pci/bus.c      2007-12-23 11:15:23.454045623 +0100
-@@ -17,6 +17,8 @@
- #include "pci.h"
-+extern int pci_mem_align;
++static int efx_debugfs_read_loop_mode(struct seq_file *file, void *data)
++{
++      unsigned int value = *(enum efx_loopback_mode *)data;
 +
- /**
-  * pci_bus_alloc_resource - allocate a resource from a parent bus
-  * @bus: PCI bus
-@@ -44,6 +46,11 @@
-       type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
-+      /* If the boot parameter 'pci-mem-align' was specified then we need to 
-+         align the memory addresses, at page size alignment. */
-+      if (pci_mem_align && (align < (PAGE_SIZE-1)))
-+              align = PAGE_SIZE - 1;
++      return seq_printf(file, "%d => %s\n", value,
++                        STRING_TABLE_LOOKUP(value, efx_loopback_mode));
++}
 +
-       for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
-               struct resource *r = bus->resource[i];
-               if (!r)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/pci/Kconfig linux-2.6.18-xen.hg/drivers/pci/Kconfig
---- linux-2.6.18/drivers/pci/Kconfig   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/pci/Kconfig    2007-12-23 11:15:23.454045623 +0100
-@@ -5,6 +5,7 @@
-       bool "Message Signaled Interrupts (MSI and MSI-X)"
-       depends on PCI
-       depends on (X86_LOCAL_APIC && X86_IO_APIC) || IA64
-+      depends on !XEN
-       help
-          This allows device drivers to enable MSI (Message Signaled
-          Interrupts).  Message Signaled Interrupts enable a device to
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/pci/quirks.c linux-2.6.18-xen.hg/drivers/pci/quirks.c
---- linux-2.6.18/drivers/pci/quirks.c  2007-12-23 11:26:51.163461987 +0100
-+++ linux-2.6.18-xen.hg/drivers/pci/quirks.c   2007-12-23 11:15:23.664056653 +0100
-@@ -23,6 +23,40 @@
- #include <linux/acpi.h>
- #include "pci.h"
-+/* A global flag which signals if we should page-align PCI mem windows. */
-+int pci_mem_align = 0;
++#define EFX_LOOPBACK_MODE_PARAMETER(container_type, parameter)                \
++      EFX_PARAMETER(container_type, parameter,                        \
++                    enum efx_loopback_mode, efx_debugfs_read_loop_mode)
 +
-+static int __init set_pci_mem_align(char *str)
++static int efx_debugfs_read_phy_type(struct seq_file *file, void *data)
 +{
-+      pci_mem_align = 1;
-+      return 1;
++      unsigned int value = *(enum phy_type *) data;
++
++      return seq_printf(file, "%d => %s\n", value,
++                        STRING_TABLE_LOOKUP(value, efx_phy_type));
 +}
-+__setup("pci-mem-align", set_pci_mem_align);
 +
-+/* This quirk function enables us to force all memory resources which are 
-+ * assigned to PCI devices, to be page-aligned.
++#define EFX_PHY_TYPE_PARAMETER(container_type, parameter)             \
++      EFX_PARAMETER(container_type, parameter,                        \
++                    enum phy_type, efx_debugfs_read_phy_type)
++
++int efx_debugfs_read_string(struct seq_file *file, void *data)
++{
++      return seq_puts(file, (const char *)data);
++}
++
++
++/**
++ * efx_init_debugfs_files - create parameter-files in a debugfs directory
++ * @parent:           Containing directory
++ * @params:           Pointer to zero-terminated parameter definition array
++ * @structure:                Structure containing parameters
++ *
++ * Add parameter-files to the given debugfs directory.  Return a
++ * negative error code or 0 on success.
 + */
-+static void __devinit quirk_align_mem_resources(struct pci_dev *dev)
++static int efx_init_debugfs_files(struct dentry *parent,
++                                struct efx_debugfs_parameter *params,
++                                void *structure)
 +{
-+      int i;
-+      struct resource *r;
-+      resource_size_t old_start;
++      struct efx_debugfs_parameter *param = params;
 +
-+      if (!pci_mem_align)
-+              return;
++      while (param->name) {
++              struct dentry *entry;
++#if defined(EFX_USE_DEBUGFS)
++              struct efx_debugfs_bound_param *binding;
 +
-+      for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
-+              r = &dev->resource[i];
-+              if ((r == NULL) || !(r->flags & IORESOURCE_MEM))
-+                      continue;
++              binding = kmalloc(sizeof(*binding), GFP_KERNEL);
++              if (!binding)
++                      goto err;
++              binding->param = param;
++              binding->structure = structure;
 +
-+              old_start = r->start;
-+              r->start = (r->start + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
-+              r->end = r->end - (old_start - r->start);
++              entry = debugfs_create_file(param->name, S_IRUGO, parent,
++                                          binding, &efx_debugfs_file_ops);
++              if (!entry) {
++                      kfree(binding);
++                      goto err;
++              }
++#else
++              entry = create_proc_entry(param->name, S_IRUGO, parent);
++              if (!entry)
++                      goto err;
++              /*
++               * We have no good way to free a binding created here.
++               * However, once we install our file_operations the
++               * read_proc pointer becomes redundant and we can
++               * abuse it as a structure pointer.
++               */
++              entry->data = param;
++              entry->read_proc = NULL;
++              smp_wmb();
++              entry->proc_fops = &efx_debugfs_file_ops;
++              smp_wmb();
++              entry->read_proc = (read_proc_t *) structure;
++#endif
++
++              param++;
++      }
++
++      return 0;
++
++ err:
++      while (param != params) {
++              param--;
++              efx_fini_debugfs_child(parent, param->name);
 +      }
++      return -ENOMEM;
 +}
-+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_align_mem_resources);
 +
- /* The Mellanox Tavor device gives false positive parity errors
-  * Mark this device with a broken_parity_status, to allow
-  * PCI scanning code to "skip" this now blacklisted device.
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/pnp/manager.c linux-2.6.18-xen.hg/drivers/pnp/manager.c
---- linux-2.6.18/drivers/pnp/manager.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/pnp/manager.c  2007-12-23 11:15:24.564103912 +0100
-@@ -168,7 +168,7 @@
-       return 0;
- }
--static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
-+static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
- {
-       resource_size_t *start, *end;
-       unsigned long *flags;
-@@ -179,18 +179,14 @@
-               1, 3, 5, 6, 7, 0, 2, 4
-       };
--      if (!dev || !rule)
--              return -EINVAL;
--
-       if (idx >= PNP_MAX_DMA) {
-               pnp_err("More than 2 dmas is incompatible with pnp specifications.");
--              /* pretend we were successful so at least the manager won't try again */
--              return 1;
-+              return;
-       }
-       /* check if this resource has been manually set, if so skip */
-       if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
--              return 1;
-+              return;
-       start = &dev->res.dma_resource[idx].start;
-       end = &dev->res.dma_resource[idx].end;
-@@ -200,19 +196,17 @@
-       *flags |= rule->flags | IORESOURCE_DMA;
-       *flags &=  ~IORESOURCE_UNSET;
--      if (!rule->map) {
--              *flags |= IORESOURCE_DISABLED;
--              return 1; /* skip disabled resource requests */
--      }
--
-       for (i = 0; i < 8; i++) {
-               if(rule->map & (1<<xtab[i])) {
-                       *start = *end = xtab[i];
-                       if(pnp_check_dma(dev, idx))
--                              return 1;
-+                              return;
-               }
-       }
--      return 0;
-+#ifdef MAX_DMA_CHANNELS
-+      *start = *end = MAX_DMA_CHANNELS;
-+#endif
-+      *flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
- }
- /**
-@@ -331,8 +325,7 @@
-                       irq = irq->next;
-               }
-               while (dma) {
--                      if (!pnp_assign_dma(dev, dma, ndma))
--                              goto fail;
-+                      pnp_assign_dma(dev, dma, ndma);
-                       ndma++;
-                       dma = dma->next;
-               }
-@@ -367,8 +360,7 @@
-                       irq = irq->next;
-               }
-               while (dma) {
--                      if (!pnp_assign_dma(dev, dma, ndma))
--                              goto fail;
-+                      pnp_assign_dma(dev, dma, ndma);
-                       ndma++;
-                       dma = dma->next;
-               }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/scsi/ahci.c linux-2.6.18-xen.hg/drivers/scsi/ahci.c
---- linux-2.6.18/drivers/scsi/ahci.c   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/scsi/ahci.c    2007-12-23 11:15:25.537488366 +0100
-@@ -317,6 +317,28 @@
-         board_ahci }, /* ICH8M */
-       { PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-         board_ahci }, /* ICH8M */
-+      { PCI_VENDOR_ID_INTEL, 0x2922, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+        board_ahci }, /* ICH9 */
-+      { PCI_VENDOR_ID_INTEL, 0x2923, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+        board_ahci }, /* ICH9 */
-+      { PCI_VENDOR_ID_INTEL, 0x2924, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+        board_ahci }, /* ICH9 */
-+      { PCI_VENDOR_ID_INTEL, 0x2925, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+        board_ahci }, /* ICH9 */
-+      { PCI_VENDOR_ID_INTEL, 0x2927, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+        board_ahci }, /* ICH9 */
-+      { PCI_VENDOR_ID_INTEL, 0x2929, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+        board_ahci }, /* ICH9M */
-+      { PCI_VENDOR_ID_INTEL, 0x292a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+        board_ahci }, /* ICH9M */
-+      { PCI_VENDOR_ID_INTEL, 0x292b, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+        board_ahci }, /* ICH9M */
-+      { PCI_VENDOR_ID_INTEL, 0x292f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+        board_ahci }, /* ICH9M */
-+      { PCI_VENDOR_ID_INTEL, 0x294d, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+        board_ahci }, /* ICH9 */
-+      { PCI_VENDOR_ID_INTEL, 0x294e, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-+        board_ahci }, /* ICH9M */
-       /* JMicron */
-       { 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/scsi/ata_piix.c linux-2.6.18-xen.hg/drivers/scsi/ata_piix.c
---- linux-2.6.18/drivers/scsi/ata_piix.c       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/scsi/ata_piix.c        2007-12-23 11:15:26.444202639 +0100
-@@ -125,6 +125,7 @@
-       ich6m_sata_ahci         = 6,
-       ich7m_sata_ahci         = 7,
-       ich8_sata_ahci          = 8,
-+      ich9_sata_ahci          = 9,
-       /* constants for mapping table */
-       P0                      = 0,  /* port 0 */
-@@ -198,6 +199,18 @@
-       { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
-       /* Mobile SATA Controller IDE (ICH8M, ditto) */
-       { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
-+      /* SATA Controller 1 IDE (ICH9) */
-+      { 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
-+      /* SATA Controller 1 IDE (ICH9) */
-+      { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
-+      /* SATA Controller 2 IDE (ICH9) */
-+      { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
-+      /* Mobile SATA Controller 1 IDE (ICH9M) */
-+      { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
-+      /* Mobile SATA Controller 2 IDE (ICH9M) */
-+      { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
-+      /* Mobile SATA Controller 2 IDE (ICH9M) */
-+      { 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
-       { }     /* terminate list */
- };
-@@ -361,9 +374,22 @@
-       .present_shift = 8,
-       .map = {
-               /* PM   PS   SM   SS       MAP */
--              {  P0,  NA,  P1,  NA }, /* 00b (hardwired) */
-+              {  P0,  P2,  P1,  P3 }, /* 00b (hardwired when in AHCI) */
-               {  RV,  RV,  RV,  RV },
--              {  RV,  RV,  RV,  RV }, /* 10b (never) */
-+              {  IDE,  IDE,  NA,  NA }, /* 10b (IDE mode) */
-+              {  RV,  RV,  RV,  RV },
-+      },
-+};
++/**
++ * efx_init_debugfs_netdev - create debugfs sym-links for net device
++ * @net_dev:          Net device
++ *
++ * Create sym-links named after @net_dev to the debugfs directories for
++ * the corresponding NIC and  port.  Return a negative error code or 0 on
++ * success.  The sym-links must be cleaned up using
++ * efx_fini_debugfs_netdev().
++ */
++int efx_init_debugfs_netdev(struct net_device *net_dev)
++{
++      struct efx_nic *efx = net_dev->priv;
++      char name[EFX_DEBUGFS_NAME_LEN];
++      char target[EFX_DEBUGFS_NAME_LEN];
++      size_t len;
 +
-+static const struct piix_map_db ich9_map_db = {
-+      .mask = 0x3,
-+      .port_enable = 0x3,
-+      .present_shift = 8,
-+      .map = {
-+              /* PM   PS   SM   SS       MAP */
-+              {  P0,  P2,  P1,  P3 }, /* 00b (hardwired when in AHCI) */
-+              {  RV,  RV,  RV,  RV },
-+              {  IDE,  IDE,  NA,  NA }, /* 10b (IDE mode) */
-               {  RV,  RV,  RV,  RV },
-       },
- };
-@@ -376,6 +402,7 @@
-       [ich6m_sata_ahci]       = &ich6m_map_db,
-       [ich7m_sata_ahci]       = &ich7m_map_db,
-       [ich8_sata_ahci]        = &ich8_map_db,
-+      [ich9_sata_ahci]        = &ich9_map_db,
- };
- static struct ata_port_info piix_port_info[] = {
-@@ -487,6 +514,18 @@
-               .udma_mask      = 0x7f, /* udma0-6 */
-               .port_ops       = &piix_sata_ops,
-       },
++      if (snprintf(name, sizeof(name), "nic_%s", net_dev->name) >=
++          sizeof(name))
++              return -ENAMETOOLONG;
++      if (snprintf(target, sizeof(target), "cards/%s", pci_name(efx->pci_dev))
++          >= sizeof(target))
++              return -ENAMETOOLONG;
++      efx->debug_symlink = debugfs_create_symlink(name,
++                                                  efx_debug_root, target);
++      if (!efx->debug_symlink)
++              return -ENOMEM;
 +
-+      /* ich9_sata_ahci */
-+      {
-+              .sht            = &piix_sht,
-+              .host_flags     = ATA_FLAG_SATA |
-+                                PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
-+                                PIIX_FLAG_AHCI,
-+              .pio_mask       = 0x1f, /* pio0-4 */
-+              .mwdma_mask     = 0x07, /* mwdma0-2 */
-+              .udma_mask      = 0x7f, /* udma0-6 */
-+              .port_ops       = &piix_sata_ops,
-+      },
- };
- static struct pci_bits piix_enable_bits[] = {
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/serial/Kconfig linux-2.6.18-xen.hg/drivers/serial/Kconfig
---- linux-2.6.18/drivers/serial/Kconfig        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/serial/Kconfig 2007-12-23 11:15:29.281018269 +0100
-@@ -11,6 +11,7 @@
- config SERIAL_8250
-       tristate "8250/16550 and compatible serial support"
-       depends on (BROKEN || !SPARC)
-+      depends on !XEN_DISABLE_SERIAL
-       select SERIAL_CORE
-       ---help---
-         This selects whether you want to include the driver for the standard
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/video/console/Kconfig linux-2.6.18-xen.hg/drivers/video/console/Kconfig
---- linux-2.6.18/drivers/video/console/Kconfig 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/drivers/video/console/Kconfig  2007-12-23 11:15:32.451184741 +0100
-@@ -53,6 +53,7 @@
- config VIDEO_SELECT
-       bool "Video mode selection support"
-       depends on  X86 && VGA_CONSOLE
-+      depends on !XEN
-       ---help---
-         This enables support for text mode selection on kernel startup. If
-         you want to take advantage of some high-resolution text mode your
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/balloon/balloon.c linux-2.6.18-xen.hg/drivers/xen/balloon/balloon.c
---- linux-2.6.18/drivers/xen/balloon/balloon.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/balloon/balloon.c  2007-12-23 11:15:33.537908474 +0100
-@@ -0,0 +1,675 @@
-+/******************************************************************************
-+ * balloon.c
++      if (snprintf(name, sizeof(name), "if_%s", net_dev->name) >=
++          sizeof(name))
++              return -ENAMETOOLONG;
++      len = snprintf(target, sizeof(target),
++                     "cards/%s/port0", pci_name(efx->pci_dev));
++      if (len >= sizeof(target))
++              return -ENAMETOOLONG;
++      efx->debug_port_symlink = debugfs_create_symlink(name,
++                                                       efx_debug_root,
++                                                       target);
++      if (!efx->debug_port_symlink)
++              return -ENOMEM;
++
++      return 0;
++}
++
++/**
++ * efx_fini_debugfs_netdev - remove debugfs sym-links for net device
++ * @net_dev:          Net device
 + *
-+ * Xen balloon driver - enables returning/claiming memory to/from Xen.
++ * Remove sym-links created for @net_dev by efx_init_debugfs_netdev().
++ */
++void efx_fini_debugfs_netdev(struct net_device *net_dev)
++{
++      struct efx_nic *efx = net_dev->priv;
++
++      debugfs_remove(efx->debug_port_symlink);
++      efx->debug_port_symlink = NULL;
++      debugfs_remove(efx->debug_symlink);
++      efx->debug_symlink = NULL;
++}
++
++/* Per-port parameters */
++static struct efx_debugfs_parameter efx_debugfs_port_parameters[] = {
++      EFX_NAMED_PARAMETER(enabled, struct efx_nic, port_enabled,
++                          int, efx_debugfs_read_int),
++      EFX_INT_PARAMETER(struct efx_nic, net_dev_registered),
++      EFX_INT_PARAMETER(struct efx_nic, rx_checksum_enabled),
++      EFX_ATOMIC_PARAMETER(struct efx_nic, netif_stop_count),
++      EFX_INT_PARAMETER(struct efx_nic, link_up),
++      EFX_UINT_PARAMETER(struct efx_nic, link_options),
++      EFX_INT_PARAMETER(struct efx_nic, promiscuous),
++      EFX_UINT_PARAMETER(struct efx_nic, loopback_modes),
++      EFX_LOOPBACK_MODE_PARAMETER(struct efx_nic, loopback_mode),
++      EFX_PHY_TYPE_PARAMETER(struct efx_nic, phy_type),
++      EFX_NAMED_PARAMETER(phy_id, struct efx_nic, mii.phy_id,
++                          int, efx_debugfs_read_int),
++      EFX_UINT_PARAMETER(struct efx_nic, n_link_state_changes),
++      {NULL},
++};
++
++/**
++ * efx_init_debugfs_port - create debugfs directory for port
++ * @efx:              Efx NIC
 + *
-+ * Copyright (c) 2003, B Dragovic
-+ * Copyright (c) 2003-2004, M Williamson, K Fraser
-+ * Copyright (c) 2005 Dan M. Smith, IBM Corporation
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++ * Create a debugfs directory containing parameter-files for @efx.
++ * Return a negative error code or 0 on success.  The directory must be
++ * cleaned up using efx_fini_debugfs_port().
 + */
++int efx_init_debugfs_port(struct efx_nic *efx)
++{
++      int rc;
 +
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/errno.h>
-+#include <linux/mm.h>
-+#include <linux/mman.h>
-+#include <linux/smp_lock.h>
-+#include <linux/pagemap.h>
-+#include <linux/bootmem.h>
-+#include <linux/highmem.h>
-+#include <linux/vmalloc.h>
-+#include <linux/mutex.h>
-+#include <xen/xen_proc.h>
-+#include <asm/hypervisor.h>
-+#include <xen/balloon.h>
-+#include <xen/interface/memory.h>
-+#include <asm/maddr.h>
-+#include <asm/page.h>
-+#include <asm/pgalloc.h>
-+#include <asm/pgtable.h>
-+#include <asm/uaccess.h>
-+#include <asm/tlb.h>
-+#include <linux/highmem.h>
-+#include <linux/list.h>
-+#include <xen/xenbus.h>
-+#include "common.h"
++      /* Create directory */
++      efx->debug_port_dir = debugfs_create_dir("port0", efx->debug_dir);
++      if (!efx->debug_port_dir)
++              return -ENOMEM;
 +
-+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
-+#include <xen/platform-compat.h>
-+#endif
++      /* Create files */
++      rc = efx_init_debugfs_files(efx->debug_port_dir,
++                                  efx_debugfs_port_parameters,
++                                  (void *)efx);
++      if (rc)
++              efx_fini_debugfs_port(efx);
 +
-+#ifdef CONFIG_PROC_FS
-+static struct proc_dir_entry *balloon_pde;
-+#endif
++      return rc;
++}
 +
-+static DEFINE_MUTEX(balloon_mutex);
++/**
++ * efx_fini_debugfs_port - remove debugfs directory for port
++ * @efx:              Efx NIC
++ *
++ * Remove directory created for @efx by efx_init_debugfs_port().
++ */
++void efx_fini_debugfs_port(struct efx_nic *efx)
++{
++      efx_fini_debugfs_dir(efx->debug_port_dir,
++                           efx_debugfs_port_parameters, NULL);
++      efx->debug_port_dir = NULL;
++}
 +
-+/*
-+ * Protects atomic reservation decrease/increase against concurrent increases.
-+ * Also protects non-atomic updates of current_pages and driver_pages, and
-+ * balloon lists.
++/**
++ * efx_extend_debugfs_port - add parameter-files to directory for port
++ * @efx:              Efx NIC
++ * @structure:                Structure containing parameters
++ * @params:           Pointer to zero-terminated parameter definition array
++ *
++ * Add parameter-files to the debugfs directory for @efx.  Return
++ * a negative error code or 0 on success.  This is intended for
++ * PHY-specific parameters.  The files must be cleaned up using
++ * efx_trim_debugfs_port().
 + */
-+DEFINE_SPINLOCK(balloon_lock);
++int efx_extend_debugfs_port(struct efx_nic *efx,
++                          void *structure,
++                          struct efx_debugfs_parameter *params)
++{
++      return efx_init_debugfs_files(efx->debug_port_dir, params, structure);
++}
 +
-+struct balloon_stats balloon_stats;
++/**
++ * efx_trim_debugfs_port - remove parameter-files from directory for port
++ * @efx:              Efx NIC
++ * @params:           Pointer to zero-terminated parameter definition array
++ *
++ * Remove parameter-files previously added to the debugfs directory
++ * for @efx using efx_extend_debugfs_port().
++ */
++void efx_trim_debugfs_port(struct efx_nic *efx,
++                         struct efx_debugfs_parameter *params)
++{
++      struct dentry *dir = efx->debug_port_dir;
 +
-+/* We increase/decrease in batches which fit in a page */
-+static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)];
++      if (dir) {
++              struct efx_debugfs_parameter *field;
++              for (field = params; field->name; field++)
++                      efx_fini_debugfs_child(dir, field->name);
++      }
++}
 +
-+/* VM /proc information for memory */
-+extern unsigned long totalram_pages;
++/* Per-TX-queue parameters */
++static struct efx_debugfs_parameter efx_debugfs_tx_queue_parameters[] = {
++      EFX_UINT_PARAMETER(struct efx_tx_queue, insert_count),
++      EFX_UINT_PARAMETER(struct efx_tx_queue, write_count),
++      EFX_UINT_PARAMETER(struct efx_tx_queue, read_count),
++      EFX_INT_PARAMETER(struct efx_tx_queue, stopped),
++      {NULL},
++};
 +
-+#ifndef MODULE
-+extern unsigned long totalhigh_pages;
-+#define inc_totalhigh_pages() (totalhigh_pages++)
-+#define dec_totalhigh_pages() (totalhigh_pages--)
-+#else
-+#define inc_totalhigh_pages() ((void)0)
-+#define dec_totalhigh_pages() ((void)0)
-+#endif
++static void efx_fini_debugfs_tx_queue(struct efx_tx_queue *tx_queue);
 +
-+/* List of ballooned pages, threaded through the mem_map array. */
-+static LIST_HEAD(ballooned_pages);
++/**
++ * efx_init_debugfs_tx_queue - create debugfs directory for TX queue
++ * @tx_queue:         Efx TX queue
++ *
++ * Create a debugfs directory containing parameter-files for @tx_queue.
++ * Return a negative error code or 0 on success.  The directory must be
++ * cleaned up using efx_fini_debugfs_tx_queue().
++ */
++static int efx_init_debugfs_tx_queue(struct efx_tx_queue *tx_queue)
++{
++      char name[EFX_DEBUGFS_NAME_LEN];
++      char target[EFX_DEBUGFS_NAME_LEN];
++      int rc;
 +
-+/* Main work function, always executed in process context. */
-+static void balloon_process(void *unused);
-+static DECLARE_WORK(balloon_worker, balloon_process, NULL);
-+static struct timer_list balloon_timer;
++      /* Create directory */
++      if (snprintf(name, sizeof(name), EFX_TX_QUEUE_NAME(tx_queue))
++          >= sizeof(name))
++              goto err_len;
++      tx_queue->debug_dir = debugfs_create_dir(name,
++                                               tx_queue->efx->debug_dir);
++      if (!tx_queue->debug_dir)
++              goto err_mem;
++
++      /* Create files */
++      rc = efx_init_debugfs_files(tx_queue->debug_dir,
++                                  efx_debugfs_tx_queue_parameters,
++                                  (void *)tx_queue);
++      if (rc)
++              goto err;
 +
-+/* When ballooning out (allocating memory to return to Xen) we don't really 
-+   want the kernel to try too hard since that can trigger the oom killer. */
-+#define GFP_BALLOON \
-+      (GFP_HIGHUSER | __GFP_NOWARN | __GFP_NORETRY | __GFP_NOMEMALLOC)
++      /* Create symlink to channel */
++      if (snprintf(target, sizeof(target),
++                   "../" EFX_CHANNEL_NAME(tx_queue->channel)) >=
++          sizeof(target))
++              goto err_len;
++      if (!debugfs_create_symlink("channel", tx_queue->debug_dir, target))
++              goto err_mem;
 +
-+#define PAGE_TO_LIST(p) (&(p)->lru)
-+#define LIST_TO_PAGE(l) list_entry((l), struct page, lru)
-+#define UNLIST_PAGE(p)                                \
-+      do {                                    \
-+              list_del(PAGE_TO_LIST(p));      \
-+              PAGE_TO_LIST(p)->next = NULL;   \
-+              PAGE_TO_LIST(p)->prev = NULL;   \
-+      } while(0)
++      /* Create symlink to port */
++      if (!debugfs_create_symlink("port", tx_queue->debug_dir, "../port0"))
++              goto err_mem;
 +
-+#define IPRINTK(fmt, args...) \
-+      printk(KERN_INFO "xen_mem: " fmt, ##args)
-+#define WPRINTK(fmt, args...) \
-+      printk(KERN_WARNING "xen_mem: " fmt, ##args)
++      return 0;
 +
-+/* balloon_append: add the given page to the balloon. */
-+static void balloon_append(struct page *page)
++ err_len:
++      rc = -ENAMETOOLONG;
++      goto err;
++ err_mem:
++      rc = -ENOMEM;
++ err:
++      efx_fini_debugfs_tx_queue(tx_queue);
++      return rc;
++}
++
++/**
++ * efx_fini_debugfs_tx_queue - remove debugfs directory for TX queue
++ * @tx_queue:         Efx TX queue
++ *
++ * Remove directory created for @tx_queue by efx_init_debugfs_tx_queue().
++ */
++static void efx_fini_debugfs_tx_queue(struct efx_tx_queue *tx_queue)
 +{
-+      /* Lowmem is re-populated first, so highmem pages go at list tail. */
-+      if (PageHighMem(page)) {
-+              list_add_tail(PAGE_TO_LIST(page), &ballooned_pages);
-+              bs.balloon_high++;
-+              dec_totalhigh_pages();
-+      } else {
-+              list_add(PAGE_TO_LIST(page), &ballooned_pages);
-+              bs.balloon_low++;
-+      }
++      static const char *const symlink_names[] = {
++              "channel", "port", NULL
++      };
++
++      efx_fini_debugfs_dir(tx_queue->debug_dir,
++                           efx_debugfs_tx_queue_parameters, symlink_names);
++      tx_queue->debug_dir = NULL;
 +}
 +
-+/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
-+static struct page *balloon_retrieve(void)
++/* Per-RX-queue parameters */
++static struct efx_debugfs_parameter efx_debugfs_rx_queue_parameters[] = {
++      EFX_INT_PARAMETER(struct efx_rx_queue, added_count),
++      EFX_INT_PARAMETER(struct efx_rx_queue, removed_count),
++      EFX_UINT_PARAMETER(struct efx_rx_queue, max_fill),
++      EFX_UINT_PARAMETER(struct efx_rx_queue, fast_fill_trigger),
++      EFX_UINT_PARAMETER(struct efx_rx_queue, fast_fill_limit),
++      EFX_UINT_PARAMETER(struct efx_rx_queue, min_fill),
++      EFX_UINT_PARAMETER(struct efx_rx_queue, min_overfill),
++      EFX_UINT_PARAMETER(struct efx_rx_queue, alloc_page_count),
++      EFX_UINT_PARAMETER(struct efx_rx_queue, alloc_skb_count),
++      EFX_UINT_PARAMETER(struct efx_rx_queue, slow_fill_count),
++      {NULL},
++};
++
++static void efx_fini_debugfs_rx_queue(struct efx_rx_queue *rx_queue);
++
++/**
++ * efx_init_debugfs_rx_queue - create debugfs directory for RX queue
++ * @rx_queue:         Efx RX queue
++ *
++ * Create a debugfs directory containing parameter-files for @rx_queue.
++ * Return a negative error code or 0 on success.  The directory must be
++ * cleaned up using efx_fini_debugfs_rx_queue().
++ */
++static int efx_init_debugfs_rx_queue(struct efx_rx_queue *rx_queue)
 +{
-+      struct page *page;
++      char name[EFX_DEBUGFS_NAME_LEN];
++      char target[EFX_DEBUGFS_NAME_LEN];
++      int rc;
 +
-+      if (list_empty(&ballooned_pages))
-+              return NULL;
++      /* Create directory */
++      if (snprintf(name, sizeof(name), EFX_RX_QUEUE_NAME(rx_queue))
++          >= sizeof(name))
++              goto err_len;
++      rx_queue->debug_dir = debugfs_create_dir(name,
++                                               rx_queue->efx->debug_dir);
++      if (!rx_queue->debug_dir)
++              goto err_mem;
++
++      /* Create files */
++      rc = efx_init_debugfs_files(rx_queue->debug_dir,
++                                  efx_debugfs_rx_queue_parameters,
++                                  (void *)rx_queue);
++      if (rc)
++              goto err;
 +
-+      page = LIST_TO_PAGE(ballooned_pages.next);
-+      UNLIST_PAGE(page);
++      /* Create symlink to channel */
++      if (snprintf(target, sizeof(target),
++                   "../" EFX_CHANNEL_NAME(rx_queue->channel)) >=
++          sizeof(target))
++              goto err_len;
++      if (!debugfs_create_symlink("channel", rx_queue->debug_dir, target))
++              goto err_mem;
 +
-+      if (PageHighMem(page)) {
-+              bs.balloon_high--;
-+              inc_totalhigh_pages();
-+      }
-+      else
-+              bs.balloon_low--;
++      return 0;
 +
-+      return page;
++ err_len:
++      rc = -ENAMETOOLONG;
++      goto err;
++ err_mem:
++      rc = -ENOMEM;
++ err:
++      efx_fini_debugfs_rx_queue(rx_queue);
++      return rc;
 +}
 +
-+static struct page *balloon_first_page(void)
++/**
++ * efx_fini_debugfs_rx_queue - remove debugfs directory for RX queue
++ * @rx_queue:         Efx RX queue
++ *
++ * Remove directory created for @rx_queue by efx_init_debugfs_rx_queue().
++ */
++static void efx_fini_debugfs_rx_queue(struct efx_rx_queue *rx_queue)
 +{
-+      if (list_empty(&ballooned_pages))
-+              return NULL;
-+      return LIST_TO_PAGE(ballooned_pages.next);
-+}
++      const char *const symlink_names[] = {
++              "channel", NULL
++      };
 +
-+static struct page *balloon_next_page(struct page *page)
-+{
-+      struct list_head *next = PAGE_TO_LIST(page)->next;
-+      if (next == &ballooned_pages)
-+              return NULL;
-+      return LIST_TO_PAGE(next);
-+}
++      efx_fini_debugfs_dir(rx_queue->debug_dir,
++                           efx_debugfs_rx_queue_parameters, symlink_names);
++      rx_queue->debug_dir = NULL;
++}
++
++/* Per-channel parameters */
++static struct efx_debugfs_parameter efx_debugfs_channel_parameters[] = {
++      EFX_INT_PARAMETER(struct efx_channel, enabled),
++      EFX_INT_PARAMETER(struct efx_channel, irq),
++      EFX_UINT_PARAMETER(struct efx_channel, has_interrupt),
++      EFX_UINT_PARAMETER(struct efx_channel, irq_moderation),
++      EFX_UINT_PARAMETER(struct efx_channel, eventq_read_ptr),
++      EFX_UINT_PARAMETER(struct efx_channel, n_rx_tobe_disc),
++      EFX_UINT_PARAMETER(struct efx_channel, n_rx_ip_frag_err),
++      EFX_UINT_PARAMETER(struct efx_channel, n_rx_ip_hdr_chksum_err),
++      EFX_UINT_PARAMETER(struct efx_channel, n_rx_tcp_udp_chksum_err),
++      EFX_UINT_PARAMETER(struct efx_channel, n_rx_frm_trunc),
++      EFX_UINT_PARAMETER(struct efx_channel, n_rx_overlength),
++      EFX_UINT_PARAMETER(struct efx_channel, n_skbuff_leaks),
++      EFX_INT_PARAMETER(struct efx_channel, rx_alloc_level),
++      EFX_INT_PARAMETER(struct efx_channel, rx_alloc_push_pages),
++      EFX_INT_PARAMETER(struct efx_channel, rx_alloc_pop_pages),
++      {NULL},
++};
++
++static void efx_fini_debugfs_channel(struct efx_channel *channel);
 +
-+static void balloon_alarm(unsigned long unused)
++/**
++ * efx_init_debugfs_channel - create debugfs directory for channel
++ * @channel:          Efx channel
++ *
++ * Create a debugfs directory containing parameter-files for @channel.
++ * Return a negative error code or 0 on success.  The directory must be
++ * cleaned up using efx_fini_debugfs_channel().
++ */
++static int efx_init_debugfs_channel(struct efx_channel *channel)
 +{
-+      schedule_work(&balloon_worker);
++      char name[EFX_DEBUGFS_NAME_LEN];
++      int rc;
++
++      /* Create directory */
++      if (snprintf(name, sizeof(name), EFX_CHANNEL_NAME(channel))
++          >= sizeof(name))
++              goto err_len;
++      channel->debug_dir = debugfs_create_dir(name, channel->efx->debug_dir);
++      if (!channel->debug_dir)
++              goto err_mem;
++
++      /* Create files */
++      rc = efx_init_debugfs_files(channel->debug_dir,
++                                  efx_debugfs_channel_parameters,
++                                  (void *)channel);
++      if (rc)
++              goto err;
++
++      return 0;
++
++ err_len:
++      rc = -ENAMETOOLONG;
++      goto err;
++ err_mem:
++      rc = -ENOMEM;
++ err:
++      efx_fini_debugfs_channel(channel);
++      return rc;
 +}
 +
-+static unsigned long current_target(void)
++/**
++ * efx_fini_debugfs_channel - remove debugfs directory for channel
++ * @channel:          Efx channel
++ *
++ * Remove directory created for @channel by efx_init_debugfs_channel().
++ */
++static void efx_fini_debugfs_channel(struct efx_channel *channel)
 +{
-+      unsigned long target = min(bs.target_pages, bs.hard_limit);
-+      if (target > (bs.current_pages + bs.balloon_low + bs.balloon_high))
-+              target = bs.current_pages + bs.balloon_low + bs.balloon_high;
-+      return target;
++      efx_fini_debugfs_dir(channel->debug_dir,
++                           efx_debugfs_channel_parameters, NULL);
++      channel->debug_dir = NULL;
 +}
 +
-+static int increase_reservation(unsigned long nr_pages)
-+{
-+      unsigned long  pfn, i, flags;
-+      struct page   *page;
-+      long           rc;
-+      struct xen_memory_reservation reservation = {
-+              .address_bits = 0,
-+              .extent_order = 0,
-+              .domid        = DOMID_SELF
-+      };
++/* Per-NIC parameters */
++static struct efx_debugfs_parameter efx_debugfs_nic_parameters[] = {
++      EFX_INT_PARAMETER(struct efx_nic, legacy_irq),
++      EFX_INT_PARAMETER(struct efx_nic, rss_queues),
++      EFX_UINT_PARAMETER(struct efx_nic, rx_buffer_len),
++      EFX_INT_MODE_PARAMETER(struct efx_nic, interrupt_mode),
++      {.name = "hardware_desc",
++       .offset = 0,
++       .reader = falcon_debugfs_read_hardware_desc},
++      {NULL},
++};
 +
-+      if (nr_pages > ARRAY_SIZE(frame_list))
-+              nr_pages = ARRAY_SIZE(frame_list);
++/* Per-NIC error counts */
++static struct efx_debugfs_parameter efx_debugfs_nic_error_parameters[] = {
++      EFX_ATOMIC_PARAMETER(struct efx_nic_errors, missing_event),
++      EFX_ATOMIC_PARAMETER(struct efx_nic_errors, rx_reset),
++      EFX_ATOMIC_PARAMETER(struct efx_nic_errors, rx_desc_fetch),
++      EFX_ATOMIC_PARAMETER(struct efx_nic_errors, tx_desc_fetch),
++      EFX_ATOMIC_PARAMETER(struct efx_nic_errors, spurious_tx),
++      {NULL},
++};
 +
-+      balloon_lock(flags);
++/**
++ * efx_init_debugfs_channels - create debugfs directories for NIC channels
++ * @efx:              Efx NIC
++ *
++ * Create subdirectories of @efx's debugfs directory for all the
++ * channels, RX queues and TX queues used by this driver.  Return a
++ * negative error code or 0 on success.  The subdirectories must be
++ * cleaned up using efx_fini_debugfs_channels().
++ */
++int efx_init_debugfs_channels(struct efx_nic *efx)
++{
++      struct efx_channel *channel;
++      struct efx_rx_queue *rx_queue;
++      struct efx_tx_queue *tx_queue;
++      int rc;
 +
-+      page = balloon_first_page();
-+      for (i = 0; i < nr_pages; i++) {
-+              BUG_ON(page == NULL);
-+              frame_list[i] = page_to_pfn(page);;
-+              page = balloon_next_page(page);
++      efx_for_each_channel(channel, efx) {
++              rc = efx_init_debugfs_channel(channel);
++              if (rc)
++                      goto err;
 +      }
 +
-+      set_xen_guest_handle(reservation.extent_start, frame_list);
-+      reservation.nr_extents   = nr_pages;
-+      rc = HYPERVISOR_memory_op(
-+              XENMEM_populate_physmap, &reservation);
-+      if (rc < nr_pages) {
-+              if (rc > 0) {
-+                      int ret;
-+
-+                      /* We hit the Xen hard limit: reprobe. */
-+                      reservation.nr_extents = rc;
-+                      ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
-+                                      &reservation);
-+                      BUG_ON(ret != rc);
-+              }
-+              if (rc >= 0)
-+                      bs.hard_limit = (bs.current_pages + rc -
-+                                       bs.driver_pages);
-+              goto out;
++      efx_for_each_rx_queue(rx_queue, efx) {
++              rc = efx_init_debugfs_rx_queue(rx_queue);
++              if (rc)
++                      goto err;
 +      }
 +
-+      for (i = 0; i < nr_pages; i++) {
-+              page = balloon_retrieve();
-+              BUG_ON(page == NULL);
-+
-+              pfn = page_to_pfn(page);
-+              BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap) &&
-+                     phys_to_machine_mapping_valid(pfn));
++      efx_for_each_tx_queue(tx_queue, efx) {
++              rc = efx_init_debugfs_tx_queue(tx_queue);
++              if (rc)
++                      goto err;
++      }
 +
-+              set_phys_to_machine(pfn, frame_list[i]);
++      return 0;
 +
-+#ifdef CONFIG_XEN
-+              /* Link back into the page tables if not highmem. */
-+              if (pfn < max_low_pfn) {
-+                      int ret;
-+                      ret = HYPERVISOR_update_va_mapping(
-+                              (unsigned long)__va(pfn << PAGE_SHIFT),
-+                              pfn_pte_ma(frame_list[i], PAGE_KERNEL),
-+                              0);
-+                      BUG_ON(ret);
-+              }
-+#endif
++ err:
++      efx_fini_debugfs_channels(efx);
++      return rc;
++}
 +
-+              /* Relinquish the page back to the allocator. */
-+              ClearPageReserved(page);
-+              init_page_count(page);
-+              __free_page(page);
-+      }
++/**
++ * efx_fini_debugfs_channels - remove debugfs directories for NIC queues
++ * @efx:              Efx NIC
++ *
++ * Remove subdirectories of @efx's debugfs directory created by
++ * efx_init_debugfs_channels().
++ */
++void efx_fini_debugfs_channels(struct efx_nic *efx)
++{
++      struct efx_channel *channel;
++      struct efx_rx_queue *rx_queue;
++      struct efx_tx_queue *tx_queue;
 +
-+      bs.current_pages += nr_pages;
-+      totalram_pages = bs.current_pages;
++      efx_for_each_tx_queue(tx_queue, efx)
++              efx_fini_debugfs_tx_queue(tx_queue);
 +
-+ out:
-+      balloon_unlock(flags);
++      efx_for_each_rx_queue(rx_queue, efx)
++              efx_fini_debugfs_rx_queue(rx_queue);
 +
-+      return 0;
++      efx_for_each_channel(channel, efx)
++              efx_fini_debugfs_channel(channel);
 +}
 +
-+static int decrease_reservation(unsigned long nr_pages)
++/**
++ * efx_init_debugfs_nic - create debugfs directory for NIC
++ * @efx:              Efx NIC
++ *
++ * Create debugfs directory containing parameter-files for @efx,
++ * and a subdirectory "errors" containing per-NIC error counts.
++ * Return a negative error code or 0 on success.  The directories
++ * must be cleaned up using efx_fini_debugfs_nic().
++ */
++int efx_init_debugfs_nic(struct efx_nic *efx)
 +{
-+      unsigned long  pfn, i, flags;
-+      struct page   *page;
-+      void          *v;
-+      int            need_sleep = 0;
-+      int ret;
-+      struct xen_memory_reservation reservation = {
-+              .address_bits = 0,
-+              .extent_order = 0,
-+              .domid        = DOMID_SELF
-+      };
++      int rc;
 +
-+      if (nr_pages > ARRAY_SIZE(frame_list))
-+              nr_pages = ARRAY_SIZE(frame_list);
++      /* Create directory */
++      efx->debug_dir = debugfs_create_dir(pci_name(efx->pci_dev),
++                                          efx_debug_cards);
++      if (!efx->debug_dir)
++              goto err_mem;
 +
-+      for (i = 0; i < nr_pages; i++) {
-+              if ((page = alloc_page(GFP_BALLOON)) == NULL) {
-+                      nr_pages = i;
-+                      need_sleep = 1;
-+                      break;
-+              }
++      /* Create errors directory */
++      efx->errors.debug_dir = debugfs_create_dir("errors", efx->debug_dir);
++      if (!efx->errors.debug_dir)
++              goto err_mem;
 +
-+              pfn = page_to_pfn(page);
-+              frame_list[i] = pfn_to_mfn(pfn);
++      /* Create files */
++      rc = efx_init_debugfs_files(efx->debug_dir,
++                                  efx_debugfs_nic_parameters, (void *)efx);
++      if (rc)
++              goto err;
++      rc = efx_init_debugfs_files(efx->errors.debug_dir,
++                                  efx_debugfs_nic_error_parameters,
++                                  (void *)&efx->errors);
++      if (rc)
++              goto err;
 +
-+              if (!PageHighMem(page)) {
-+                      v = phys_to_virt(pfn << PAGE_SHIFT);
-+                      scrub_pages(v, 1);
-+#ifdef CONFIG_XEN
-+                      ret = HYPERVISOR_update_va_mapping(
-+                              (unsigned long)v, __pte_ma(0), 0);
-+                      BUG_ON(ret);
-+#endif
-+              }
-+#ifdef CONFIG_XEN_SCRUB_PAGES
-+              else {
-+                      v = kmap(page);
-+                      scrub_pages(v, 1);
-+                      kunmap(page);
-+              }
++      return 0;
++
++ err_mem:
++      rc = -ENOMEM;
++ err:
++      efx_fini_debugfs_nic(efx);
++      return rc;
++}
++
++/**
++ * efx_fini_debugfs_nic - remove debugfs directories for NIC
++ * @efx:              Efx NIC
++ *
++ * Remove debugfs directories created for @efx by efx_init_debugfs_nic().
++ */
++void efx_fini_debugfs_nic(struct efx_nic *efx)
++{
++      efx_fini_debugfs_dir(efx->errors.debug_dir,
++                           efx_debugfs_nic_error_parameters, NULL);
++      efx->errors.debug_dir = NULL;
++      efx_fini_debugfs_dir(efx->debug_dir, efx_debugfs_nic_parameters, NULL);
++      efx->debug_dir = NULL;
++}
++
++/**
++ * efx_init_debugfs - create debugfs directories for sfc driver
++ *
++ * Create debugfs directories "sfc" and "sfc/cards".  This must be
++ * called before any of the other functions that create debugfs
++ * directories.  Return a negative error code or 0 on success.  The
++ * directories must be cleaned up using efx_fini_debugfs().
++ */
++int efx_init_debugfs(void)
++{
++      /* Create top-level directory */
++#if defined(EFX_USE_DEBUGFS)
++      efx_debug_root = debugfs_create_dir("sfc", NULL);
++#else
++      efx_debug_root = proc_mkdir("sfc", proc_root_driver);
 +#endif
-+      }
++      if (!efx_debug_root)
++              goto err;
 +
-+#ifdef CONFIG_XEN
-+      /* Ensure that ballooned highmem pages don't have kmaps. */
-+      kmap_flush_unused();
-+      flush_tlb_all();
++      /* Create "cards" directory */
++      efx_debug_cards = debugfs_create_dir("cards", efx_debug_root);
++      if (!efx_debug_cards)
++              goto err;
++
++#if defined(EFX_USE_DEBUGFS)
++      /* Create compatibility sym-link */
++      if (!proc_symlink("sfc", proc_root_driver, "/sys/kernel/debug/sfc"))
++              goto err;
 +#endif
++      return 0;
 +
-+      balloon_lock(flags);
++ err:
++      efx_fini_debugfs();
++      return -ENOMEM;
++}
 +
-+      /* No more mappings: invalidate P2M and add to balloon. */
-+      for (i = 0; i < nr_pages; i++) {
-+              pfn = mfn_to_pfn(frame_list[i]);
-+              set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
-+              balloon_append(pfn_to_page(pfn));
-+      }
++/**
++ * efx_fini_debugfs - remove debugfs directories for sfc driver
++ *
++ * Remove directories created by efx_init_debugfs().
++ */
++void efx_fini_debugfs(void)
++{
++#if defined(EFX_USE_DEBUGFS)
++      remove_proc_entry("sfc", proc_root_driver);
++#endif
++      debugfs_remove(efx_debug_cards);
++      efx_debug_cards = NULL;
++      debugfs_remove(efx_debug_root);
++      efx_debug_root = NULL;
++}
+--- linux-2.6.18.8/drivers/net/sfc/debugfs.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/debugfs.h      2008-05-19 00:33:28.833808141 +0300
+@@ -0,0 +1,172 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      set_xen_guest_handle(reservation.extent_start, frame_list);
-+      reservation.nr_extents   = nr_pages;
-+      ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
-+      BUG_ON(ret != nr_pages);
++#ifndef EFX_DEBUGFS_H
++#define EFX_DEBUGFS_H
 +
-+      bs.current_pages -= nr_pages;
-+      totalram_pages = bs.current_pages;
++#ifdef CONFIG_SFC_DEBUGFS
 +
-+      balloon_unlock(flags);
++struct seq_file;
 +
-+      return need_sleep;
++struct efx_debugfs_parameter {
++      const char *name;
++      size_t offset;
++      int (*reader)(struct seq_file *, void *);
++};
++
++extern void efx_fini_debugfs_child(struct dentry *dir, const char *name);
++extern int efx_init_debugfs_netdev(struct net_device *net_dev);
++extern void efx_fini_debugfs_netdev(struct net_device *net_dev);
++extern int efx_init_debugfs_port(struct efx_nic *efx);
++extern void efx_fini_debugfs_port(struct efx_nic *efx);
++extern int efx_init_debugfs_nic(struct efx_nic *efx);
++extern void efx_fini_debugfs_nic(struct efx_nic *efx);
++extern int efx_init_debugfs_channels(struct efx_nic *efx);
++extern void efx_fini_debugfs_channels(struct efx_nic *efx);
++extern int efx_init_debugfs(void);
++extern void efx_fini_debugfs(void);
++extern int efx_extend_debugfs_port(struct efx_nic *efx,
++                                 void *context,
++                                 struct efx_debugfs_parameter *params);
++extern void efx_trim_debugfs_port(struct efx_nic *efx,
++                                struct efx_debugfs_parameter *params);
++
++/* Helpers for handling debugfs entry reads */
++extern int efx_debugfs_read_uint(struct seq_file *, void *);
++extern int efx_debugfs_read_string(struct seq_file *, void *);
++extern int efx_debugfs_read_int(struct seq_file *, void *);
++extern int efx_debugfs_read_atomic(struct seq_file *, void *);
++extern int efx_debugfs_read_dword(struct seq_file *, void *);
++
++/* Handy macros for filling out parameters */
++
++/* Initialiser for a struct efx_debugfs_parameter with type-checking */
++#define EFX_PARAMETER(container_type, parameter, field_type,          \
++                      reader_function) {                              \
++      .name = #parameter,                                             \
++      .offset = ((((field_type *) 0) ==                               \
++                  &((container_type *) 0)->parameter) ?               \
++                 offsetof(container_type, parameter) :                \
++                 offsetof(container_type, parameter)),                \
++      .reader = reader_function,                                      \
++}
++
++/* Likewise, but the file name is not taken from the field name */
++#define EFX_NAMED_PARAMETER(_name, container_type, parameter, field_type, \
++                              reader_function) {                      \
++      .name = #_name,                                                 \
++      .offset = ((((field_type *) 0) ==                               \
++                  &((container_type *) 0)->parameter) ?               \
++                 offsetof(container_type, parameter) :                \
++                 offsetof(container_type, parameter)),                \
++      .reader = reader_function,                                      \
++}
++
++/* Likewise, but with one file for each of 4 lanes */
++#define EFX_PER_LANE_PARAMETER(prefix, suffix, container_type, parameter, \
++                              field_type, reader_function) {          \
++      .name = prefix "0" suffix,                                      \
++      .offset = ((((field_type *) 0) ==                               \
++                    ((container_type *) 0)->parameter) ?              \
++                  offsetof(container_type, parameter[0]) :            \
++                  offsetof(container_type, parameter[0])),            \
++      .reader = reader_function,                                      \
++},  {                                                                 \
++      .name = prefix "1" suffix,                                      \
++      .offset = offsetof(container_type, parameter[1]),               \
++      .reader = reader_function,                                      \
++}, {                                                                  \
++      .name = prefix "2" suffix,                                      \
++      .offset = offsetof(container_type, parameter[2]),               \
++      .reader = reader_function,                                      \
++}, {                                                                  \
++      .name = prefix "3" suffix,                                      \
++      .offset = offsetof(container_type, parameter[3]),               \
++      .reader = reader_function,                                      \
++}
++
++/* A string parameter (string embedded in the structure) */
++#define EFX_STRING_PARAMETER(container_type, parameter) {     \
++      .name = #parameter,                                     \
++      .offset = ((((char *) 0) ==                             \
++                  ((container_type *) 0)->parameter) ?        \
++                 offsetof(container_type, parameter) :        \
++                 offsetof(container_type, parameter)),        \
++      .reader = efx_debugfs_read_string,                      \
++}
++
++/* An unsigned integer parameter */
++#define EFX_UINT_PARAMETER(container_type, parameter)         \
++      EFX_PARAMETER(container_type, parameter,                \
++                    unsigned int, efx_debugfs_read_uint)
++
++/* A dword parameter */
++#define EFX_DWORD_PARAMETER(container_type, parameter)                \
++      EFX_PARAMETER(container_type, parameter,                \
++                    efx_dword_t, efx_debugfs_read_dword)
++
++/* An atomic_t parameter */
++#define EFX_ATOMIC_PARAMETER(container_type, parameter)               \
++      EFX_PARAMETER(container_type, parameter,                \
++                    atomic_t, efx_debugfs_read_atomic)
++
++/* An integer parameter */
++#define EFX_INT_PARAMETER(container_type, parameter)          \
++      EFX_PARAMETER(container_type, parameter,                \
++                    int, efx_debugfs_read_int)
++
++#else /* !CONFIG_SFC_DEBUGFS */
++
++static inline int efx_init_debugfs_netdev(struct net_device *net_dev)
++{
++      return 0;
++}
++static inline void efx_fini_debugfs_netdev(struct net_device *net_dev) {}
++static inline int efx_init_debugfs_port(struct efx_nic *efx)
++{
++      return 0;
++}
++static inline void efx_fini_debugfs_port(struct efx_nic *efx) {}
++static inline int efx_init_debugfs_nic(struct efx_nic *efx)
++{
++      return 0;
++}
++static inline void efx_fini_debugfs_nic(struct efx_nic *efx) {}
++static inline int efx_init_debugfs_channels(struct efx_nic *efx)
++{
++      return 0;
++}
++static inline void efx_fini_debugfs_channels(struct efx_nic *efx) {}
++static inline int efx_init_debugfs(void)
++{
++      return 0;
 +}
++static inline void efx_fini_debugfs(void) {}
 +
-+/*
-+ * We avoid multiple worker processes conflicting via the balloon mutex.
-+ * We may of course race updates of the target counts (which are protected
-+ * by the balloon lock), or with changes to the Xen hard limit, but we will
-+ * recover from these in time.
++#endif /* CONFIG_SFC_DEBUGFS */
++
++#endif /* EFX_DEBUGFS_H */
+--- linux-2.6.18.8/drivers/net/sfc/driverlink.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/driverlink.c   2008-05-19 00:33:28.833808141 +0300
+@@ -0,0 +1,544 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005:      Fen Systems Ltd.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
-+static void balloon_process(void *unused)
-+{
-+      int need_sleep = 0;
-+      long credit;
 +
-+      mutex_lock(&balloon_mutex);
++#include <linux/module.h>
++#include <linux/list.h>
++#include <linux/skbuff.h>
++#include <linux/rtnetlink.h>
++#include "net_driver.h"
++#include "efx.h"
++#include "driverlink.h"
 +
-+      do {
-+              credit = current_target() - bs.current_pages;
-+              if (credit > 0)
-+                      need_sleep = (increase_reservation(credit) != 0);
-+              if (credit < 0)
-+                      need_sleep = (decrease_reservation(-credit) != 0);
++/* Driverlink semaphore
++ * This semaphore must be held for any operation that modifies any of
++ * the driverlink lists.
++ */
++static DEFINE_MUTEX(efx_driverlink_lock);
 +
-+#ifndef CONFIG_PREEMPT
-+              if (need_resched())
-+                      schedule();
-+#endif
-+      } while ((credit != 0) && !need_sleep);
++/* List of all registered drivers */
++static LIST_HEAD(efx_driver_list);
 +
-+      /* Schedule more work if there is some still to be done. */
-+      if (current_target() != bs.current_pages)
-+              mod_timer(&balloon_timer, jiffies + HZ);
++/* List of all registered Efx ports */
++static LIST_HEAD(efx_port_list);
 +
-+      mutex_unlock(&balloon_mutex);
-+}
++/* Driver link handle used internally to track devices */
++struct efx_dl_handle {
++      /* The efx_dl_device consumers see */
++      struct efx_dl_device efx_dev;
++      /* The efx_nic providers provide */
++      struct efx_nic *efx;
++      /* Per-device list */
++      struct list_head port_node;
++      /* Per-driver list */
++      struct list_head driver_node;
++};
 +
-+/* Resets the Xen limit, sets new target, and kicks off processing. */
-+void balloon_set_new_target(unsigned long target)
++/* Get the handle for an efx_dl_device */
++static struct efx_dl_handle *efx_dl_handle(struct efx_dl_device *efx_dev)
 +{
-+      /* No need for lock. Not read-modify-write updates. */
-+      bs.hard_limit   = ~0UL;
-+      bs.target_pages = target;
-+      schedule_work(&balloon_worker);
++      return container_of(efx_dev, struct efx_dl_handle, efx_dev);
 +}
 +
-+static struct xenbus_watch target_watch =
++/* Remove an Efx device
++ * You must hold the efx_driverlink_lock before calling this
++ * function.
++ */
++static void efx_dl_del_device(struct efx_dl_device *efx_dev)
 +{
-+      .node = "memory/target"
-+};
++      struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev);
 +
-+/* React to a change in the target key */
-+static void watch_target(struct xenbus_watch *watch,
-+                       const char **vec, unsigned int len)
-+{
-+      unsigned long long new_target;
-+      int err;
++      EFX_INFO(efx_handle->efx, "%s driverlink client unregistering\n",
++               efx_dev->driver->name);
 +
-+      err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target);
-+      if (err != 1) {
-+              /* This is ok (for domain0 at least) - so just return */
-+              return;
-+      }
++      /* Call driver's remove() routine */
++      if (efx_dev->driver->remove)
++              efx_dev->driver->remove(efx_dev);
 +
-+      /* The given memory/target value is in KiB, so it needs converting to
-+       * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10.
-+       */
-+      balloon_set_new_target(new_target >> (PAGE_SHIFT - 10));
++      /* Remove handle from per-driver and per-NIC lists */
++      list_del(&efx_handle->driver_node);
++      list_del(&efx_handle->port_node);
++
++      /* Free efx_handle structure */
++      kfree(efx_handle);
 +}
 +
-+static int balloon_init_watcher(struct notifier_block *notifier,
-+                              unsigned long event,
-+                              void *data)
++/* Try to add an Efx device
++ * Attempt to probe the given device with the driver, creating a
++ * new efx_dl_device. If the probe routine fails, because the driver
++ * doesn't support this port, then the efx_dl_device is destroyed,
++ */
++static void efx_dl_try_add_device(struct efx_nic *efx,
++                                struct efx_dl_driver *driver)
 +{
-+      int err;
++      struct efx_dl_handle *efx_handle;
++      struct efx_dl_device *efx_dev;
++      int rc;
 +
-+      err = register_xenbus_watch(&target_watch);
-+      if (err)
-+              printk(KERN_ERR "Failed to set balloon watcher\n");
++      /* Allocate and initialise new efx_dl_device structure */
++      efx_handle = kzalloc(sizeof(*efx_handle), GFP_KERNEL);
++      efx_dev = &efx_handle->efx_dev;
++      efx_handle->efx = efx;
++      efx_dev->driver = driver;
++      efx_dev->pci_dev = efx->pci_dev;
++      INIT_LIST_HEAD(&efx_handle->port_node);
++      INIT_LIST_HEAD(&efx_handle->driver_node);
++
++      /* Attempt driver probe */
++      rc = driver->probe(efx_dev, efx->net_dev,
++                         efx->dl_info, efx->silicon_rev);
++      if (rc)
++              goto fail;
 +
-+      return NOTIFY_DONE;
++      /* Add device to per-driver and per-NIC lists */
++      list_add_tail(&efx_handle->driver_node, &driver->device_list);
++      list_add_tail(&efx_handle->port_node, &efx->dl_device_list);
++
++      EFX_INFO(efx, "%s driverlink client registered\n", driver->name);
++      return;
++
++ fail:
++      EFX_INFO(efx, "%s driverlink client skipped\n", driver->name);
++
++      kfree(efx_dev);
 +}
 +
-+#ifdef CONFIG_PROC_FS
-+static int balloon_write(struct file *file, const char __user *buffer,
-+                       unsigned long count, void *data)
++/**
++ * efx_dl_unregister_driver - unregister an Efx device driver
++ * @driver:           Efx driverlink driver
++ *
++ * Unregisters an Efx driver.  The driver's remove() method will be
++ * called for all Efx devices currently claimed by the driver.
++ */
++void efx_dl_unregister_driver(struct efx_dl_driver *driver)
 +{
-+      char memstring[64], *endchar;
-+      unsigned long long target_bytes;
++      struct efx_dl_handle *efx_handle, *efx_handle_n;
 +
-+      if (!capable(CAP_SYS_ADMIN))
-+              return -EPERM;
++      printk(KERN_INFO "Efx driverlink unregistering %s driver\n",
++               driver->name);
 +
-+      if (count <= 1)
-+              return -EBADMSG; /* runt */
-+      if (count > sizeof(memstring))
-+              return -EFBIG;   /* too long */
++      /* Acquire lock.  We can't return failure, so have to use
++       * down() instead of down_interruptible()
++       */
++      mutex_lock(&efx_driverlink_lock);
 +
-+      if (copy_from_user(memstring, buffer, count))
-+              return -EFAULT;
-+      memstring[sizeof(memstring)-1] = '\0';
++      /* Remove all devices claimed by the driver */
++      list_for_each_entry_safe(efx_handle, efx_handle_n,
++                               &driver->device_list, driver_node)
++              efx_dl_del_device(&efx_handle->efx_dev);
 +
-+      target_bytes = memparse(memstring, &endchar);
-+      balloon_set_new_target(target_bytes >> PAGE_SHIFT);
++      /* Remove driver from driver list */
++      list_del(&driver->node);
 +
-+      return count;
++      /* Release lock */
++      mutex_unlock(&efx_driverlink_lock);
 +}
++EXPORT_SYMBOL(efx_dl_unregister_driver);
 +
-+static int balloon_read(char *page, char **start, off_t off,
-+                      int count, int *eof, void *data)
++/**
++ * efx_dl_register_driver - register an Efx device driver
++ * @driver:           Efx driverlink driver
++ *
++ * Registers a new Efx driver.  The driver's probe() method will be
++ * called for all Efx NICs currently registered.
++ *
++ * Return a negative error code or 0 on success.
++ */
++int efx_dl_register_driver(struct efx_dl_driver *driver)
 +{
-+      int len;
++      struct efx_nic *efx;
++      int rc;
 +
-+      len = sprintf(
-+              page,
-+              "Current allocation: %8lu kB\n"
-+              "Requested target:   %8lu kB\n"
-+              "Low-mem balloon:    %8lu kB\n"
-+              "High-mem balloon:   %8lu kB\n"
-+              "Driver pages:       %8lu kB\n"
-+              "Xen hard limit:     ",
-+              PAGES2KB(bs.current_pages), PAGES2KB(bs.target_pages), 
-+              PAGES2KB(bs.balloon_low), PAGES2KB(bs.balloon_high),
-+              PAGES2KB(bs.driver_pages));
++      printk(KERN_INFO "Efx driverlink registering %s driver\n",
++               driver->name);
 +
-+      if (bs.hard_limit != ~0UL)
-+              len += sprintf(page + len, "%8lu kB\n",
-+                             PAGES2KB(bs.hard_limit));
-+      else
-+              len += sprintf(page + len, "     ??? kB\n");
++      /* Initialise driver list structures */
++      INIT_LIST_HEAD(&driver->node);
++      INIT_LIST_HEAD(&driver->device_list);
 +
-+      *eof = 1;
-+      return len;
-+}
-+#endif
++      /* Acquire lock */
++      rc = mutex_lock_interruptible(&efx_driverlink_lock);
++      if (rc)
++              return rc;
 +
-+static struct notifier_block xenstore_notifier;
++      /* Add driver to driver list */
++      list_add_tail(&driver->node, &efx_driver_list);
 +
-+static int __init balloon_init(void)
++      /* Feed all existing devices to driver */
++      list_for_each_entry(efx, &efx_port_list, dl_node)
++              efx_dl_try_add_device(efx, driver);
++
++      /* Release locks */
++      mutex_unlock(&efx_driverlink_lock);
++
++      return 0;
++}
++EXPORT_SYMBOL(efx_dl_register_driver);
++
++void efx_dl_unregister_nic(struct efx_nic *efx)
 +{
-+#if defined(CONFIG_X86) && defined(CONFIG_XEN) 
-+      unsigned long pfn;
-+      struct page *page;
-+#endif
++      struct efx_dl_handle *efx_handle, *efx_handle_n;
 +
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++      if (!efx)
++              return;
 +
-+      IPRINTK("Initialising balloon driver.\n");
++      /* Acquire lock.  We can't return failure, so have to use
++       * down() instead of down_interruptible()
++       */
++      mutex_lock(&efx_driverlink_lock);
 +
-+#ifdef CONFIG_XEN
-+      bs.current_pages = min(xen_start_info->nr_pages, max_pfn);
-+      totalram_pages   = bs.current_pages;
-+#else 
-+      bs.current_pages = totalram_pages; 
-+#endif
-+      bs.target_pages  = bs.current_pages;
-+      bs.balloon_low   = 0;
-+      bs.balloon_high  = 0;
-+      bs.driver_pages  = 0UL;
-+      bs.hard_limit    = ~0UL;
++      /* Remove all devices related to this NIC */
++      list_for_each_entry_safe_reverse(efx_handle, efx_handle_n,
++                                       &efx->dl_device_list,
++                                       port_node)
++              efx_dl_del_device(&efx_handle->efx_dev);
 +
-+      init_timer(&balloon_timer);
-+      balloon_timer.data = 0;
-+      balloon_timer.function = balloon_alarm;
-+    
-+#ifdef CONFIG_PROC_FS
-+      if ((balloon_pde = create_xen_proc_entry("balloon", 0644)) == NULL) {
-+              WPRINTK("Unable to create /proc/xen/balloon.\n");
-+              return -1;
-+      }
++      /* Remove port from port list */
++      list_del(&efx->dl_node);
 +
-+      balloon_pde->read_proc  = balloon_read;
-+      balloon_pde->write_proc = balloon_write;
-+#endif
-+      balloon_sysfs_init();
++      /* Release lock */
++      mutex_unlock(&efx_driverlink_lock);
++}
 +
-+#if defined(CONFIG_X86) && defined(CONFIG_XEN) 
-+      /* Initialise the balloon with excess memory space. */
-+      for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
-+              page = pfn_to_page(pfn);
-+              if (!PageReserved(page))
-+                      balloon_append(page);
-+      }
-+#endif
++int efx_dl_register_nic(struct efx_nic *efx)
++{
++      struct efx_dl_driver *driver;
++      int rc;
 +
-+      target_watch.callback = watch_target;
-+      xenstore_notifier.notifier_call = balloon_init_watcher;
++      /* Acquire lock */
++      rc = mutex_lock_interruptible(&efx_driverlink_lock);
++      if (rc)
++              return rc;
++
++      /* Add port to port list */
++      list_add_tail(&efx->dl_node, &efx_port_list);
++
++      /* Feed port to all existing drivers */
++      list_for_each_entry(driver, &efx_driver_list, node)
++              efx_dl_try_add_device(efx, driver);
++
++      /* Release lock */
++      mutex_unlock(&efx_driverlink_lock);
 +
-+      register_xenstore_notifier(&xenstore_notifier);
-+    
 +      return 0;
 +}
 +
-+subsys_initcall(balloon_init);
-+
-+static void __exit balloon_exit(void)
++/*
++ * Dummy callback implementations.
++ *
++ * To avoid a branch point on the fast-path, the callbacks are always
++ * implemented - they are never NULL.
++ */
++#if defined(EFX_USE_FASTCALL)
++static enum efx_veto fastcall
++#else
++static enum efx_veto
++#endif
++efx_dummy_tx_packet_callback(struct efx_dl_device *efx_dev, struct sk_buff *skb)
 +{
-+    /* XXX - release balloon here */
-+    return; 
++      /* Never veto the packet */
++      return EFX_ALLOW_PACKET;
 +}
 +
-+module_exit(balloon_exit); 
-+
-+void balloon_update_driver_allowance(long delta)
++#if defined(EFX_USE_FASTCALL)
++static enum efx_veto fastcall
++#else
++static enum efx_veto
++#endif
++efx_dummy_rx_packet_callback(struct efx_dl_device *efx_dev,
++                           const char *pkt_buf, int len)
 +{
-+      unsigned long flags;
++      /* Never veto the packet */
++      return EFX_ALLOW_PACKET;
++}
 +
-+      balloon_lock(flags);
-+      bs.driver_pages += delta;
-+      balloon_unlock(flags);
++static void
++efx_dummy_link_change_callback(struct efx_dl_device *efx_dev, int link_up)
++{
 +}
 +
-+#ifdef CONFIG_XEN
-+static int dealloc_pte_fn(
-+      pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
++static int
++efx_dummy_request_mtu_callback(struct efx_dl_device *efx_dev, int new_mtu)
 +{
-+      unsigned long mfn = pte_mfn(*pte);
-+      int ret;
-+      struct xen_memory_reservation reservation = {
-+              .nr_extents   = 1,
-+              .extent_order = 0,
-+              .domid        = DOMID_SELF
-+      };
-+      set_xen_guest_handle(reservation.extent_start, &mfn);
-+      set_pte_at(&init_mm, addr, pte, __pte_ma(0));
-+      set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY);
-+      ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
-+      BUG_ON(ret != 1);
++      /* Always allow */
 +      return 0;
 +}
-+#endif
 +
-+struct page **alloc_empty_pages_and_pagevec(int nr_pages)
++static void
++efx_dummy_mtu_changed_callback(struct efx_dl_device *efx_dev, int mtu)
 +{
-+      unsigned long vaddr, flags;
-+      struct page *page, **pagevec;
-+      int i, ret;
++      return;
++}
 +
-+      pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL);
-+      if (pagevec == NULL)
-+              return NULL;
++static void efx_dummy_event_callback(struct efx_dl_device *efx_dev, void *event)
++{
++      return;
++}
 +
-+      for (i = 0; i < nr_pages; i++) {
-+              page = pagevec[i] = alloc_page(GFP_KERNEL);
-+              if (page == NULL)
-+                      goto err;
++struct efx_dl_callbacks efx_default_callbacks = {
++      .tx_packet      = efx_dummy_tx_packet_callback,
++      .rx_packet      = efx_dummy_rx_packet_callback,
++      .link_change    = efx_dummy_link_change_callback,
++      .request_mtu    = efx_dummy_request_mtu_callback,
++      .mtu_changed    = efx_dummy_mtu_changed_callback,
++      .event          = efx_dummy_event_callback,
++};
 +
-+              vaddr = (unsigned long)page_address(page);
++#define EFX_DL_UNREGISTER_CALLBACK(_port, _dev, _member)              \
++      do {                                                            \
++              BUG_ON((_port)->dl_cb_dev._member != (_dev));           \
++              (_port)->dl_cb._member =                                \
++                      efx_default_callbacks._member;                  \
++              (_port)->dl_cb_dev._member = NULL;                      \
++      } while (0)
 +
-+              scrub_pages(vaddr, 1);
 +
-+              balloon_lock(flags);
++#define EFX_DL_REGISTER_CALLBACK(_port, _dev, _from, _member)         \
++      if ((_from)->_member) {                                         \
++              BUG_ON((_port)->dl_cb_dev._member != NULL);             \
++              (_port)->dl_cb._member = (_from)->_member;              \
++              (_port)->dl_cb_dev._member = _dev;                      \
++      }
 +
-+              if (xen_feature(XENFEAT_auto_translated_physmap)) {
-+                      unsigned long gmfn = page_to_pfn(page);
-+                      struct xen_memory_reservation reservation = {
-+                              .nr_extents   = 1,
-+                              .extent_order = 0,
-+                              .domid        = DOMID_SELF
-+                      };
-+                      set_xen_guest_handle(reservation.extent_start, &gmfn);
-+                      ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
-+                                                 &reservation);
-+                      if (ret == 1)
-+                              ret = 0; /* success */
-+              } else {
-+#ifdef CONFIG_XEN
-+                      ret = apply_to_page_range(&init_mm, vaddr, PAGE_SIZE,
-+                                                dealloc_pte_fn, NULL);
-+#else
-+                      /* Cannot handle non-auto translate mode. */
-+                      ret = 1;
-+#endif
-+              }
++/**
++ * efx_dl_unregister_callbacks - unregister callbacks for an Efx NIC
++ * @efx_dev:          Efx driverlink device
++ * @callbacks:                Callback list
++ *
++ * This removes a set of callbacks registered with
++ * efx_dl_register_callbacks().  It should be called as part of the
++ * client's remove() method.
++ *
++ * The net driver will ensure that all callback functions have
++ * returned to the net driver before efx_dl_unregister_callbacks()
++ * returns.  Note that the device itself may still be running when the
++ * client's remove() method is called.  The client must therefore
++ * unhook its callbacks using efx_dl_unregister_callbacks() and only
++ * then ensure that any delayed tasks triggered by callback methods
++ * (e.g. scheduled tasklets) have completed.
++ */
++void efx_dl_unregister_callbacks(struct efx_dl_device *efx_dev,
++                               struct efx_dl_callbacks *callbacks)
++{
++      struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev);
++      struct efx_nic *efx = efx_handle->efx;
 +
-+              if (ret != 0) {
-+                      balloon_unlock(flags);
-+                      __free_page(page);
-+                      goto err;
-+              }
++      /* Suspend net driver operations */
++      efx_suspend(efx);
 +
-+              totalram_pages = --bs.current_pages;
++      EFX_INFO(efx, "removing callback hooks into %s driver\n",
++               efx_dev->driver->name);
 +
-+              balloon_unlock(flags);
-+      }
++      if (callbacks->tx_packet)
++              EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, tx_packet);
 +
-+ out:
-+      schedule_work(&balloon_worker);
-+#ifdef CONFIG_XEN
-+      flush_tlb_all();
-+#endif
-+      return pagevec;
++      if (callbacks->rx_packet)
++              EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, rx_packet);
 +
-+ err:
-+      balloon_lock(flags);
-+      while (--i >= 0)
-+              balloon_append(pagevec[i]);
-+      balloon_unlock(flags);
-+      kfree(pagevec);
-+      pagevec = NULL;
-+      goto out;
++      if (callbacks->link_change)
++              EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, link_change);
++
++      if (callbacks->request_mtu)
++              EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, request_mtu);
++
++      if (callbacks->mtu_changed)
++              EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, mtu_changed);
++
++      if (callbacks->event)
++              EFX_DL_UNREGISTER_CALLBACK(efx, efx_dev, event);
++
++      /* Resume net driver operations */
++      efx_resume(efx);
 +}
++EXPORT_SYMBOL(efx_dl_unregister_callbacks);
 +
-+void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages)
++/**
++ * efx_dl_register_callbacks - register callbacks for an Efx NIC
++ * @efx_dev:          Efx driverlink device
++ * @callbacks:                Callback list
++ *
++ * This registers a set of callback functions with the net driver.
++ * These functions will be called at various key points to allow
++ * external code to monitor and/or modify the behaviour of the network
++ * driver.  Any of the callback function pointers may be %NULL if a
++ * callback is not required.  The intended user of this mechanism is
++ * the SFC char driver.
++ *
++ * This client should call efx_dl_register_callbacks() during its
++ * probe() method.  The client must ensure that it also calls
++ * efx_dl_unregister_callbacks() as part of its remove() method.
++ *
++ * Only one function may be registered for each callback per NIC.
++ * If a requested callback is already registered for this NIC, this
++ * function will return -%EBUSY.
++ *
++ * The device may already be running, so the client must be prepared
++ * for callbacks to be triggered immediately after calling
++ * efx_dl_register_callbacks().
++ *
++ * Return a negative error code or 0 on success.
++ */
++int efx_dl_register_callbacks(struct efx_dl_device *efx_dev,
++                            struct efx_dl_callbacks *callbacks)
 +{
-+      unsigned long flags;
-+      int i;
++      struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev);
++      struct efx_nic *efx = efx_handle->efx;
++      int rc = 0;
 +
-+      if (pagevec == NULL)
-+              return;
++      /* Suspend net driver operations */
++      efx_suspend(efx);
 +
-+      balloon_lock(flags);
-+      for (i = 0; i < nr_pages; i++) {
-+              BUG_ON(page_count(pagevec[i]) != 1);
-+              balloon_append(pagevec[i]);
++      /* Check that the requested callbacks are not already hooked. */
++      if ((callbacks->tx_packet && efx->dl_cb_dev.tx_packet) ||
++          (callbacks->rx_packet && efx->dl_cb_dev.rx_packet) ||
++          (callbacks->link_change && efx->dl_cb_dev.link_change) ||
++          (callbacks->request_mtu && efx->dl_cb_dev.request_mtu) ||
++          (callbacks->mtu_changed && efx->dl_cb_dev.mtu_changed) ||
++          (callbacks->event && efx->dl_cb_dev.event)) {
++              rc = -EBUSY;
++              goto out;
 +      }
-+      balloon_unlock(flags);
 +
-+      kfree(pagevec);
++      EFX_INFO(efx, "adding callback hooks to %s driver\n",
++               efx_dev->driver->name);
 +
-+      schedule_work(&balloon_worker);
++      /* Hook in callbacks.  For maximum speed, we never check to
++       * see whether these are NULL before calling; therefore we
++       * must ensure that they are never NULL.  If the set we're
++       * being asked to hook in is sparse, we leave the default
++       * values in place for the empty hooks.
++       */
++      EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, tx_packet);
++      EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, rx_packet);
++      EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, link_change);
++      EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, request_mtu);
++      EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, mtu_changed);
++      EFX_DL_REGISTER_CALLBACK(efx, efx_dev, callbacks, event);
++
++ out:
++      /* Resume net driver operations */
++      efx_resume(efx);
++
++      return rc;
 +}
++EXPORT_SYMBOL(efx_dl_register_callbacks);
 +
-+void balloon_release_driver_page(struct page *page)
++/**
++ * efx_dl_schedule_reset - schedule an Efx NIC reset
++ * @efx_dev:          Efx driverlink device
++ *
++ * This schedules a hardware reset for a short time in the future.  It
++ * can be called from any context, and so can be used when
++ * efx_dl_reset() cannot be called.
++ */
++void efx_dl_schedule_reset(struct efx_dl_device *efx_dev)
 +{
-+      unsigned long flags;
-+
-+      balloon_lock(flags);
-+      balloon_append(page);
-+      bs.driver_pages--;
-+      balloon_unlock(flags);
++      struct efx_dl_handle *efx_handle = efx_dl_handle(efx_dev);
++      struct efx_nic *efx = efx_handle->efx;
 +
-+      schedule_work(&balloon_worker);
++      efx_schedule_reset(efx, RESET_TYPE_ALL);
 +}
++EXPORT_SYMBOL(efx_dl_schedule_reset);
 +
-+EXPORT_SYMBOL_GPL(balloon_update_driver_allowance);
-+EXPORT_SYMBOL_GPL(alloc_empty_pages_and_pagevec);
-+EXPORT_SYMBOL_GPL(free_empty_pages_and_pagevec);
-+EXPORT_SYMBOL_GPL(balloon_release_driver_page);
-+
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/balloon/common.h linux-2.6.18-xen.hg/drivers/xen/balloon/common.h
---- linux-2.6.18/drivers/xen/balloon/common.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/balloon/common.h   2007-12-23 11:15:33.541241984 +0100
-@@ -0,0 +1,58 @@
-+/******************************************************************************
-+ * balloon/common.h
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++/*
++ * Lock the driverlink layer before a reset
++ * To avoid deadlock, efx_driverlink_lock needs to be acquired before
++ * efx->suspend_lock.
 + */
++void efx_dl_reset_lock(void)
++{
++      /* Acquire lock */
++      mutex_lock(&efx_driverlink_lock);
++}
 +
-+#ifndef __XEN_BALLOON_COMMON_H__
-+#define __XEN_BALLOON_COMMON_H__
++/*
++ * Unlock the driverlink layer after a reset
++ * This call must be matched against efx_dl_reset_lock.
++ */
++void efx_dl_reset_unlock(void)
++{
++      /* Acquire lock */
++      mutex_unlock(&efx_driverlink_lock);
++}
 +
-+#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
++/*
++ * Suspend ready for reset
++ * This calls the reset_suspend method of all drivers registered to
++ * the specified NIC.  It must only be called between
++ * efx_dl_reset_lock and efx_dl_reset_unlock.
++ */
++void efx_dl_reset_suspend(struct efx_nic *efx)
++{
++      struct efx_dl_handle *efx_handle;
++      struct efx_dl_device *efx_dev;
 +
-+struct balloon_stats {
-+      /* We aim for 'current allocation' == 'target allocation'. */
-+      unsigned long current_pages;
-+      unsigned long target_pages;
-+      /* We may hit the hard limit in Xen. If we do then we remember it. */
-+      unsigned long hard_limit;
-+      /*
-+       * Drivers may alter the memory reservation independently, but they
-+       * must inform the balloon driver so we avoid hitting the hard limit.
-+       */
-+      unsigned long driver_pages;
-+      /* Number of pages in high- and low-memory balloons. */
-+      unsigned long balloon_low;
-+      unsigned long balloon_high;
-+};
++      BUG_ON(!mutex_is_locked(&efx_driverlink_lock));
 +
-+extern struct balloon_stats balloon_stats;
-+#define bs balloon_stats
++      /* Call suspend method of each driver in turn */
++      list_for_each_entry_reverse(efx_handle,
++                                  &efx->dl_device_list,
++                                  port_node) {
++              efx_dev = &efx_handle->efx_dev;
++              if (efx_dev->driver->reset_suspend)
++                      efx_dev->driver->reset_suspend(efx_dev);
++      }
++}
 +
-+int balloon_sysfs_init(void);
-+void balloon_sysfs_exit(void);
++/*
++ * Resume after a reset
++ * This calls the reset_resume method of all drivers registered to the
++ * specified NIC.  It must only be called between efx_dl_reset_lock
++ * and efx_dl_reset_unlock.
++ */
++void efx_dl_reset_resume(struct efx_nic *efx, int ok)
++{
++      struct efx_dl_handle *efx_handle;
++      struct efx_dl_device *efx_dev;
 +
-+void balloon_set_new_target(unsigned long target);
++      BUG_ON(!mutex_is_locked(&efx_driverlink_lock));
 +
-+#endif /* __XEN_BALLOON_COMMON_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/balloon/Makefile linux-2.6.18-xen.hg/drivers/xen/balloon/Makefile
---- linux-2.6.18/drivers/xen/balloon/Makefile  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/balloon/Makefile   2007-12-23 11:15:33.537908474 +0100
-@@ -0,0 +1,2 @@
++      /* Call resume method of each driver in turn */
++      list_for_each_entry(efx_handle, &efx->dl_device_list,
++                          port_node) {
++              efx_dev = &efx_handle->efx_dev;
++              if (efx_dev->driver->reset_resume)
++                      efx_dev->driver->reset_resume(efx_dev, ok);
++      }
++}
 +
-+obj-y := balloon.o sysfs.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/balloon/sysfs.c linux-2.6.18-xen.hg/drivers/xen/balloon/sysfs.c
---- linux-2.6.18/drivers/xen/balloon/sysfs.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/balloon/sysfs.c    2007-12-23 11:15:33.541241984 +0100
-@@ -0,0 +1,170 @@
-+/******************************************************************************
-+ * balloon/sysfs.c
++/**
++ * efx_dl_get_nic - obtain the Efx NIC for the given driverlink device
++ * @efx_dev:          Efx driverlink device
 + *
-+ * Xen balloon driver - sysfs interfaces.
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++ * Get a pointer to the &struct efx_nic corresponding to
++ * @efx_dev.  This can be used by driverlink clients built along with
++ * the sfc driver, which may have intimate knowledge of its internals.
++ */
++struct efx_nic *efx_dl_get_nic(struct efx_dl_device *efx_dev)
++{
++      return efx_dl_handle(efx_dev)->efx;
++}
++EXPORT_SYMBOL(efx_dl_get_nic);
+--- linux-2.6.18.8/drivers/net/sfc/driverlink.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/driverlink.h   2008-05-19 00:33:28.833808141 +0300
+@@ -0,0 +1,93 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005:      Fen Systems Ltd.
++ * Copyright 2006:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <linux/capability.h>
-+#include <linux/errno.h>
-+#include <linux/stat.h>
-+#include <linux/string.h>
-+#include <linux/sysdev.h>
-+#include "common.h"
++#ifndef EFX_DRIVERLINK_H
++#define EFX_DRIVERLINK_H
 +
-+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
-+#include <xen/platform-compat.h>
++/* Forward declarations */
++struct efx_dl_device;
++struct efx_nic;
++
++/*
++ * Efx driverlink
++ *
++ * This header file defines the portions of the Efx driverlink
++ * interface that are used only within the sfc module.  It also
++ * declares efx_dl_get_nic(), which may be used by sfc_mtd
++ * and any other module built along with sfc.
++ */
++
++
++/* Efx callback devices
++ *
++ * A list of the devices that own each callback. The partner to
++ * struct efx_dl_callbacks
++ */
++struct efx_dl_cb_devices {
++      /* Device owning the tx_packet callback */
++      struct efx_dl_device *tx_packet;
++      /* Device owning the rx_packet callback */
++      struct efx_dl_device *rx_packet;
++      /* Device owning the link_change callback. */
++      struct efx_dl_device *link_change;
++      /* Device owning the request_mtu callback. */
++      struct efx_dl_device *request_mtu;
++      /* Device owning the mtu_changed callback. */
++      struct efx_dl_device *mtu_changed;
++      /* Device owning the event callback. */
++      struct efx_dl_device *event;
++};
++
++/* No-op callbacks used for initialisation */
++extern struct efx_dl_callbacks efx_default_callbacks;
++
++/* Macro used to invoke callbacks */
++#define EFX_DL_CALLBACK(_port, _name, ...)                            \
++      (_port)->dl_cb._name((_port)->dl_cb_dev._name, __VA_ARGS__)
++
++/* Register an Efx NIC */
++extern int efx_dl_register_nic(struct efx_nic *efx);
++
++/* Unregister an Efx NIC */
++extern void efx_dl_unregister_nic(struct efx_nic *efx);
++
++/* Lock the driverlink layer prior to a reset */
++extern void efx_dl_reset_lock(void);
++
++/* Unlock the driverlink layer following a reset */
++extern void efx_dl_reset_unlock(void);
++
++/* Suspend all drivers prior to a hardware reset */
++extern void efx_dl_reset_suspend(struct efx_nic *efx);
++
++/* Resume all drivers after a hardware reset */
++extern void efx_dl_reset_resume(struct efx_nic *efx, int ok);
++
++/* Obtain the Efx NIC for the given driverlink device. */
++extern struct efx_nic *efx_dl_get_nic(struct efx_dl_device *efx_dev);
++
++#endif /* EFX_DRIVERLINK_H */
+--- linux-2.6.18.8/drivers/net/sfc/driverlink_api.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/driverlink_api.h       2008-05-19 00:33:28.833808141 +0300
+@@ -0,0 +1,612 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef EFX_DRIVERLINK_API_H
++#define EFX_DRIVERLINK_API_H
++
++#include <linux/list.h> /* for struct list_head */
++#if !defined(EFX_USE_FASTCALL)
++      #include <linux/version.h>
++      #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++              #define EFX_USE_FASTCALL yes
++              #include <linux/linkage.h>
++      #endif
 +#endif
 +
-+#define BALLOON_CLASS_NAME "memory"
++/**
++ * DOC: Efx driverlink API
++ *
++ * This file must be included by any driver that wishes to attach to
++ * devices claimed by the Solarflare NIC driver (sfc). It allows separate
++ * kernel modules to expose other functionality offered by the NIC, with
++ * the sfc driver remaining in overall control.
++ *
++ * Overview:
++ *
++ * Driverlink clients define a &struct efx_dl_driver, and register
++ * this structure with the driverlink layer using
++ * efx_dl_register_driver(), which is exported by the sfc driver.
++ *
++ * The probe() routine of each driverlink client driver is called by
++ * the driverlink layer for each physical port in the system, after
++ * the sfc driver has performed start-of-day hardware initialisation
++ * and self-test. If ports are added or removed via pci hotplug then
++ * the &struct efx_dl_driver probe() or remove() routines are called
++ * as appropriate.
++ *
++ * If the port doesn't provide the necessary hardware resources for a
++ * client, then that client can return failure from its probe()
++ * routine. Information provided to the client driver at probe time
++ * includes
++ *
++ * Each probe() routine is given a unique &struct efx_dl_device per
++ * port, which means it can safely use the @priv member to store any
++ * useful state it needs. The probe routine also has the opportunity
++ * to provide a &struct efx_dl_callbacks via
++ * efx_dl_register_callbacks(), which allows the client to intercept
++ * the sfc driver's operations at strategic points.
++ *
++ * Occasionally, the underlying Efx device may need to be reset to
++ * recover from an error condition.  The client's reset_suspend() and
++ * reset_resume() methods [if provided] will be called to enable the
++ * client to suspend operations and preserve any state before the
++ * reset.  The client can itself request a reset using efx_dl_reset()
++ * or efx_dl_schedule_reset(), should it detect an error condition
++ * necessitating a reset.
++ *
++ * Example:
++ *
++ * The MTD driver (mtd.c) uses the driverlink layer.
++ */
 +
-+#define BALLOON_SHOW(name, format, args...)                   \
-+      static ssize_t show_##name(struct sys_device *dev,      \
-+                                 char *buf)                   \
-+      {                                                       \
-+              return sprintf(buf, format, ##args);            \
-+      }                                                       \
-+      static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
++/* Forward declarations */
++struct pci_dev;
++struct net_device;
++struct sk_buff;
++struct efx_dl_device;
++struct efx_dl_device_info;
 +
-+BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(bs.current_pages));
-+BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(bs.balloon_low));
-+BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(bs.balloon_high));
-+BALLOON_SHOW(hard_limit_kb,
-+           (bs.hard_limit!=~0UL) ? "%lu\n" : "???\n",
-+           (bs.hard_limit!=~0UL) ? PAGES2KB(bs.hard_limit) : 0);
-+BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(bs.driver_pages));
++/*
++ * This is used to guard against the registration of driverlink
++ * clients using an incorrect version of the API.
++ */
++#define EFX_DRIVERLINK_API_VERSION 1
 +
-+static ssize_t show_target_kb(struct sys_device *dev, char *buf)
-+{
-+      return sprintf(buf, "%lu\n", PAGES2KB(bs.target_pages));
-+}
 +
-+static ssize_t store_target_kb(struct sys_device *dev,
-+                             const char *buf,
-+                             size_t count)
-+{
-+      char memstring[64], *endchar;
-+      unsigned long long target_bytes;
++/**
++ * struct efx_dl_driver - An Efx driverlink device driver
++ *
++ * This is the analogue of a struct pci_driver for a normal PCI
++ * driver.  Driverlink clients should register themselves using
++ * efx_dl_register_driver() at module initialisation, and deregister
++ * themselves using efx_dl_unregister_driver() at module exit.
++ *
++ * All calls to members of efx_dl_driver are serialised by a single
++ * semaphore, so you are allowed to sleep in these functions. Take care
++ * to not call driverlink methods from within these callbacks, otherwise
++ * a deadlock is possible.
++ *
++ * @name: Name of the driver
++ * @probe: Called when device added
++ * @remove: Called when device removed
++ * @reset_suspend: Called before device is reset
++ * @reset_resume: Called after device is reset
++ */
++struct efx_dl_driver {
++      const char *name;
 +
-+      if (!capable(CAP_SYS_ADMIN))
-+              return -EPERM;
-+      
-+      if (count <= 1)
-+              return -EBADMSG; /* runt */
-+      if (count > sizeof(memstring))
-+              return -EFBIG;   /* too long */
-+      strcpy(memstring, buf);
-+      
-+      target_bytes = memparse(memstring, &endchar);
-+      balloon_set_new_target(target_bytes >> PAGE_SHIFT);
-+      
-+      return count;
-+}
++      /*
++       * probe - Handle device addition.
++       * @efx_dev:            Efx driverlink device
++       * @net_dev:            The net_dev relevant to this port
++       * @dev_info:           A linked list of device information.
++       * @silicon_rev:        Silicon revision name.
++       *
++       * This will be called after driverlink client registration for
++       * every port on the system, and for every port that appears
++       * thereafter via hotplug.
++       *
++       * The client may use either @efx_dev->pci_dev, the dev_info linked
++       * list of available driver information, or the silicon revision
++       * name to determine if they can support this port. If they can,
++       * they should return 0 to indicate the probe was successful. Any
++       * other return code indicates that the probe failed, and the
++       * @efx_dl_dev will be invalidated.
++       *
++       * The client should perform whatever initialisation it
++       * requires, and store a pointer to its private data in
++       * @efx_dl_dev->priv (which is not shared between clients).
++       * It may also wish to hook in a callbacks table using
++       * efx_dl_register_callbacks().
++       *
++       * Return a negative error code or 0 on success.
++       */
++      int (*probe) (struct efx_dl_device *efx_dl_dev,
++                    const struct net_device *net_dev,
++                    const struct efx_dl_device_info *dev_info,
++                    const char *silicon_rev);
 +
-+static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR,
-+                 show_target_kb, store_target_kb);
++      /*
++       * remove - Handle device removal.
++       * @efx_dev:            Efx driverlink device
++       *
++       * This will be called at driver exit (or hotplug removal) for
++       * each registered driverlink client.
++       *
++       * The client must ensure that it has finished all operations
++       * using this device before returning from this method.  If it
++       * has hooked in a callbacks table using
++       * efx_dl_register_callbacks(), it must unhook it using
++       * efx_dl_unregister_callbacks(), and then ensure that all
++       * callback-triggered operations (e.g. scheduled tasklets)
++       * have completed before returning.  (It does not need to
++       * explicitly wait for callback methods to finish executing,
++       * since efx_dl_unregister_callbacks() will sleep until all
++       * callbacks have returned anyway.)
++       *
++       * Note that the device itself may not have been removed; it
++       * may be simply that the client is being unloaded
++       * via efx_dl_unregister_driver(). In this case other clients
++       * (and the sfc driver itself) will still be using the device,
++       * so the client cannot assume that the device itself is quiescent.
++       * In particular, callbacks may continue to be triggered at any
++       * point until efx_dl_unregister_callbacks() is called.
++       */
++      void (*remove) (struct efx_dl_device *efx_dev);
 +
-+static struct sysdev_attribute *balloon_attrs[] = {
-+      &attr_target_kb,
++      /*
++       * reset_suspend - Suspend ready for reset.
++       * @efx_dev:            Efx driverlink device
++       *
++       * This method will be called immediately before a hardware
++       * reset (which may or may not have been initiated by the
++       * driverlink client).  This client must save any state that it
++       * will need to restore after the reset, and suspend all
++       * operations that might access the hardware.  It must not
++       * return until the client can guarantee to have stopped
++       * touching the hardware.
++       *
++       * It is guaranteed that callbacks will be inactive by the
++       * time this method is called; the driverlink layer will
++       * already have prevented new callbacks being made and waited
++       * for all callbacks functions to return before calling
++       * reset_suspend().  However, any delayed work scheduled by
++       * the callback functions (e.g. tasklets) may not yet have
++       * completed.
++       *
++       * This method is allowed to sleep, so waiting on tasklets,
++       * work queues etc. is permitted.  There will always be a
++       * corresponding call to the reset_resume() method, so it is
++       * safe to e.g. down a semaphore within reset_suspend() and up
++       * it within reset_resume().  (However, you obviously cannot
++       * do the same with a spinlock).
++       *
++       * Note that the reset operation may be being carried out in
++       * the context of scheduled work, so you cannot use
++       * flush_scheduled_work() to ensure that any work you may have
++       * scheduled has completed.
++       *
++       * During hardware reset, there is a chance of receiving
++       * spurious interrupts, so the client's ISR (if any) should be
++       * unhooked or otherwise disabled.
++       */
++      void (*reset_suspend) (struct efx_dl_device *efx_dev);
++
++      /*
++       * reset_resume - Restore after a reset.
++       * @efx_dev:            Efx driverlink device
++       * @ok:                 Reset success indicator
++       *
++       * This method will be called after a hardware reset.  There
++       * will always have been a corresponding call to the
++       * reset_suspend() method beforehand.
++       *
++       * If @ok is non-zero, the client should restore the state
++       * that it saved during the call to reset_suspend() and resume
++       * normal operations.
++       *
++       * If @ok is zero, the reset operation has failed and the
++       * hardware is currently in an unusable state.  In this case,
++       * the client should release any locks taken out by
++       * reset_suspend(), but should not take any other action; in
++       * particular, it must not access the hardware, nor resume
++       * normal operations.  The hardware is effectively dead at
++       * this point, and our sole aim is to avoid deadlocking or
++       * crashing the host.
++       *
++       * The driverlink layer will still be locked when
++       * reset_resume() is called, so the client may not call
++       * driverlink functions.  In particular, if the reset failed,
++       * the client must not call efx_dl_unregister_callbacks() at
++       * this point; it should wait until remove() is called.
++       */
++      void (*reset_resume) (struct efx_dl_device *efx_dev, int ok);
++
++/* private: */
++      struct list_head node;
++      struct list_head device_list;
 +};
 +
-+static struct attribute *balloon_info_attrs[] = {
-+      &attr_current_kb.attr,
-+      &attr_low_kb.attr,
-+      &attr_high_kb.attr,
-+      &attr_hard_limit_kb.attr,
-+      &attr_driver_kb.attr,
-+      NULL
++/**
++ * DOC: Efx driverlink device information
++ *
++ * Each &struct efx_dl_device makes certain hardware resources visible
++ * to driverlink clients, and they describe which resources are
++ * available by passing a linked list of &struct efx_dl_device_info
++ * into the probe() routine.
++ *
++ * The driverlink client's probe function can iterate through the linked list,
++ * and provided that it understands the resources that are exported, it can
++ * choose to make use of them through an external interface.
++ */
++
++/**
++ * enum efx_dl_device_info_type - Device information identifier.
++ *
++ * Each distinct hardware resource API will have a member in this
++ * enumeration.
++ *
++ * @EFX_DL_FALCON_RESOURCES: Information type is &struct efx_dl_falcon_resources
++ */
++enum efx_dl_device_info_type {
++      /** Falcon resources available for export */
++      EFX_DL_FALCON_RESOURCES = 0,
 +};
 +
-+static struct attribute_group balloon_info_group = {
-+      .name = "info",
-+      .attrs = balloon_info_attrs,
++/**
++ * struct efx_dl_device_info - device information structure
++ * @next: Link to next structure, if any
++ * @type: Type code for this structure
++ *
++ * This structure is embedded in other structures provided by the
++ * driverlink device provider, and implements a linked list of
++ * resources pertinent to a driverlink client.
++ *
++ * Example: &struct efx_dl_falcon_resources
++ */
++struct efx_dl_device_info {
++      struct efx_dl_device_info *next;
++      enum efx_dl_device_info_type type;
 +};
 +
-+static struct sysdev_class balloon_sysdev_class = {
-+      set_kset_name(BALLOON_CLASS_NAME),
++/**
++ * enum efx_dl_falcon_resource_flags - Falcon resource information flags.
++ *
++ * Flags that describe hardware variations for the described Falcon based port.
++ *
++ * @EFX_DL_FALCON_DUAL_FUNC: Port is dual-function.
++ *    Certain silicon revisions have two pci functions, and require
++ *    certain hardware resources to be accessed via the secondary
++ *    function. See the discussion of @pci_dev in &struct efx_dl_device
++ *    below.
++ * @EFX_DL_FALCON_USE_MSI: Port is initialised to use MSI/MSI-X interrupts.
++ *    Falcon supports traditional legacy interrupts and MSI/MSI-X
++ *    interrupts. Since the sfc driver supports either, as a run
++ *    time configuration, driverlink drivers need to be aware of which
++ *    one to use for their interrupting resources.
++ */
++enum efx_dl_falcon_resource_flags {
++      EFX_DL_FALCON_DUAL_FUNC = 0x1,
++      EFX_DL_FALCON_USE_MSI = 0x2,
 +};
 +
-+static struct sys_device balloon_sysdev;
++/**
++ * struct efx_dl_falcon_resources - Falcon resource information.
++ *
++ * This structure describes Falcon hardware resources available for
++ * use by a driverlink driver.
++ *
++ * @hdr: Resource linked list header
++ * @biu_lock: Register access lock.
++ *    Some Falcon revisions require register access for configuration
++ *    registers to be serialised between ports and PCI functions.
++ *    The sfc driver will provide the appropriate lock semantics for
++ *    the underlying hardware.
++ * @buffer_table_min: First available buffer table entry
++ * @buffer_table_max: Last available buffer table entry + 1
++ * @evq_timer_min: First available event queue with timer
++ * @evq_timer_max: Last available event queue with timer + 1
++ * @evq_int_min: First available event queue with interrupt
++ * @evq_int_max: Last available event queue with interrupt + 1
++ * @rxq_min: First available RX queue
++ * @rxq_max: Last available RX queue + 1
++ * @txq_min: First available TX queue
++ * @txq_max: Last available TX queue + 1
++ * @flags: Hardware variation flags
++ */
++struct efx_dl_falcon_resources {
++      struct efx_dl_device_info hdr;
++      spinlock_t *biu_lock;
++      unsigned buffer_table_min, buffer_table_max;
++      unsigned evq_timer_min, evq_timer_max;
++      unsigned evq_int_min, evq_int_max;
++      unsigned rxq_min, rxq_max;
++      unsigned txq_min, txq_max;
++      enum efx_dl_falcon_resource_flags flags;
++};
 +
-+static int register_balloon(struct sys_device *sysdev)
-+{
-+      int i, error;
++/**
++ * struct efx_dl_device - An Efx driverlink device.
++ *
++ * @pci_dev: Underlying PCI device.
++ *    This is the PCI device used by the sfc driver.  It will
++ *    already have been enabled for bus-mastering DMA etc.
++ * @priv: Driver private data
++ *    Driverlink clients can use this to store a pointer to their
++ *    internal per-device data structure. Each (driver, device)
++ *    tuple has a separate &struct efx_dl_device, so clients can use
++ *    this @priv field independently.
++ * @driver: Efx driverlink driver for this device
++ */
++struct efx_dl_device {
++      struct pci_dev *pci_dev;
++      void *priv;
++      struct efx_dl_driver *driver;
++};
 +
-+      error = sysdev_class_register(&balloon_sysdev_class);
-+      if (error)
-+              return error;
++/**
++ * enum efx_veto - Packet veto request flag.
++ *
++ * This is the return type for the rx_packet() and tx_packet() methods
++ * in &struct efx_dl_callbacks.
++ *
++ * @EFX_ALLOW_PACKET: Packet may be transmitted/received
++ * @EFX_VETO_PACKET: Packet must not be transmitted/received
++ */
++enum efx_veto {
++      EFX_ALLOW_PACKET = 0,
++      EFX_VETO_PACKET = 1,
++};
 +
-+      sysdev->id = 0;
-+      sysdev->cls = &balloon_sysdev_class;
++/**
++ * struct efx_dl_callbacks - Efx callbacks
++ *
++ * These methods can be hooked in to the sfc driver via
++ * efx_dl_register_callbacks().  They allow clients to intercept and/or
++ * modify the behaviour of the sfc driver at predetermined points.
++ *
++ * For efficiency, only one client can hook each callback.
++ *
++ * Since these callbacks are called on packet transmit and reception
++ * paths, clients should avoid acquiring locks or allocating memory.
++ *
++ * @tx_packet: Called when packet is about to be transmitted
++ * @rx_packet: Called when packet is received
++ * @link_change: Called when link status has changed
++ * @request_mtu: Called to request MTU change
++ * @mtu_changed: Called when MTU has been changed
++ * @event: Called when NIC event is not handled by the sfc driver
++ */
++struct efx_dl_callbacks {
++      /*
++       * tx_packet - Packet about to be transmitted.
++       * @efx_dev:            Efx driverlink device
++       * @skb:                Socket buffer containing the packet to be sent
++       *
++       * This method is called for every packet about to be
++       * transmitted.  It allows the client to snoop on traffic sent
++       * via the kernel queues.
++       *
++       * The method may return %EFX_VETO_PACKET in order to prevent
++       * the sfc driver from transmitting the packet.  The net
++       * driver will then discard the packet.  If the client wishes
++       * to retain a reference to the packet data after returning
++       * %EFX_VETO_PACKET, it must obtain its own copy of the
++       * packet (e.g. by calling skb_get(), or by copying out the
++       * packet data to an external buffer).
++       *
++       * This method must return quickly, since it will have a
++       * direct performance impact upon the sfc driver.  It will be
++       * called with interrupts disabled (and may be called in
++       * interrupt context), so may not sleep. Since the sfc driver
++       * may have multiple TX queues, running in parallel, please avoid
++       * the need for locking if it all possible.
++       */
++#if defined(EFX_USE_FASTCALL)
++      enum efx_veto fastcall (*tx_packet) (struct efx_dl_device *efx_dev,
++                                           struct sk_buff *skb);
++#else
++      enum efx_veto (*tx_packet) (struct efx_dl_device *efx_dev,
++                                  struct sk_buff *skb);
++#endif
 +
-+      error = sysdev_register(sysdev);
-+      if (error) {
-+              sysdev_class_unregister(&balloon_sysdev_class);
-+              return error;
-+      }
++      /*
++       * rx_packet - Packet received.
++       * @efx_dev:            Efx driverlink device
++       * @pkt_hdr:            Pointer to received packet
++       * @pkt_len:            Length of received packet
++       *
++       * This method is called for every received packet.  It allows
++       * the client to snoop on traffic received by the kernel
++       * queues.
++       *
++       * The method may return %EFX_VETO_PACKET in order to prevent
++       * the sfc driver from passing the packet to the kernel.  The net
++       * driver will then discard the packet.
++       *
++       * This method must return quickly, since it will have a
++       * direct performance impact upon the sfc driver.  It is
++       * called in tasklet context, so may not sleep.  Note that
++       * there are per-channel tasklets in the sfc driver, so
++       * rx_packet() may be called simultaneously on different CPUs
++       * and must lock appropriately.  The design of the sfc driver
++       * allows for lockless operation between receive channels, so
++       * please avoid the need for locking if at all possible.
++       */
++#if defined(EFX_USE_FASTCALL)
++      enum efx_veto fastcall (*rx_packet) (struct efx_dl_device *efx_dev,
++                                           const char *pkt_hdr, int pkt_len);
++#else
++      enum efx_veto (*rx_packet) (struct efx_dl_device *efx_dev,
++                                  const char *pkt_hdr, int pkt_len);
++#endif
 +
-+      for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) {
-+              error = sysdev_create_file(sysdev, balloon_attrs[i]);
-+              if (error)
-+                      goto fail;
-+      }
++      /*
++       * link_change - Link status change.
++       * @efx_dev:            Efx driverlink device
++       * @link_up:            Link up indicator
++       *
++       * This method is called to inform the driverlink client
++       * whenever the PHY link status changes.  By the time this
++       * function is called, the MAC has already been reconfigured
++       * with the new autonegotiation settings from the PHY.
++       *
++       * This method is called from tasklet context and may not
++       * sleep.
++       */
++      void (*link_change) (struct efx_dl_device *efx_dev, int link_up);
 +
-+      error = sysfs_create_group(&sysdev->kobj, &balloon_info_group);
-+      if (error)
-+              goto fail;
-+      
-+      return 0;
++      /*
++       * request_mtu: Request MTU change.
++       * @efx_dev:            Efx driverlink device
++       * @new_mtu:            Requested new MTU
++       *
++       * This method is called whenever the user requests an MTU
++       * change on an interface.  The client may return an error, in
++       * which case the MTU change request will be denied.  If the
++       * client returns success, the MAC will be reconfigured with a
++       * new maxmimum frame length equal to
++       * EFX_MAX_FRAME_LEN(new_mtu).  The client will be notified
++       * via the mtu_changed() method once the MAC has been
++       * reconfigured.
++       *
++       * The current MTU for the port can be obtained via
++       * efx_dl_get_netdev(efx_dl_device)->mtu.
++       *
++       * The sfc driver guarantees that no other callback functions
++       * are in progress when this method is called.  This function
++       * is called in process context and may sleep.
++       *
++       * Return a negative error code or 0 on success.
++       */
++      int (*request_mtu) (struct efx_dl_device *efx_dev, int new_mtu);
 +
-+ fail:
-+      while (--i >= 0)
-+              sysdev_remove_file(sysdev, balloon_attrs[i]);
-+      sysdev_unregister(sysdev);
-+      sysdev_class_unregister(&balloon_sysdev_class);
-+      return error;
-+}
++      /*
++       * mtu_changed - MTU has been changed.
++       * @efx_dev:            Efx driverlink device
++       * @mtu:                The new MTU
++       *
++       * This method is called once the MAC has been reconfigured
++       * with a new MTU.  There will have been a preceding call to
++       * request_mtu().
++       *
++       * The sfc driver guarantees that no other callback functions
++       * are in progress when this method is called.  This function
++       * is called in process context and may sleep.
++       */
++      void (*mtu_changed) (struct efx_dl_device *efx_dev, int mtu);
 +
-+static void unregister_balloon(struct sys_device *sysdev)
-+{
-+      int i;
++      /*
++       * event - Event callback.
++       * @efx_dev:            Efx driverlink device
++       * @p_event:            Pointer to event
++       *
++       * This method is called for each event that is not handled by the
++       * sfc driver.
++       */
++      void (*event) (struct efx_dl_device *efx_dev, void *p_event);
++};
 +
-+      sysfs_remove_group(&sysdev->kobj, &balloon_info_group);
-+      for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++)
-+              sysdev_remove_file(sysdev, balloon_attrs[i]);
-+      sysdev_unregister(sysdev);
-+      sysdev_class_unregister(&balloon_sysdev_class);
-+}
++/* Include API version number in symbol used for efx_dl_register_driver */
++#define efx_dl_stringify_1(x, y) x ## y
++#define efx_dl_stringify_2(x, y) efx_dl_stringify_1(x, y)
++#define efx_dl_register_driver                                        \
++      efx_dl_stringify_2(efx_dl_register_driver_api_ver_,     \
++                         EFX_DRIVERLINK_API_VERSION)
 +
-+int balloon_sysfs_init(void)
-+{
-+      return register_balloon(&balloon_sysdev);
-+}
++extern int efx_dl_register_driver(struct efx_dl_driver *driver);
 +
-+void balloon_sysfs_exit(void)
-+{
-+      unregister_balloon(&balloon_sysdev);
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blkback/blkback.c linux-2.6.18-xen.hg/drivers/xen/blkback/blkback.c
---- linux-2.6.18/drivers/xen/blkback/blkback.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blkback/blkback.c  2007-12-23 11:15:33.541241984 +0100
-@@ -0,0 +1,617 @@
-+/******************************************************************************
-+ * arch/xen/drivers/blkif/backend/main.c
-+ * 
-+ * Back-end of the driver for virtual block devices. This portion of the
-+ * driver exports a 'unified' block-device interface that can be accessed
-+ * by any operating system that implements a compatible front end. A 
-+ * reference front-end implementation can be found in:
-+ *  arch/xen/drivers/blkif/frontend
-+ * 
-+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
-+ * Copyright (c) 2005, Christopher Clark
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++extern void efx_dl_unregister_driver(struct efx_dl_driver *driver);
++
++extern int efx_dl_register_callbacks(struct efx_dl_device *efx_dev,
++                                   struct efx_dl_callbacks *callbacks);
++
++extern void efx_dl_unregister_callbacks(struct efx_dl_device *efx_dev,
++                                      struct efx_dl_callbacks *callbacks);
++
++extern void efx_dl_schedule_reset(struct efx_dl_device *efx_dev);
++
++/**
++ * efx_dl_for_each_device_info_matching - iterate an efx_dl_device_info list
++ * @_dev_info: Pointer to first &struct efx_dl_device_info
++ * @_type: Type code to look for
++ * @_info_type: Structure type corresponding to type code
++ * @_field: Name of &struct efx_dl_device_info field in the type
++ * @_p: Iterator variable
++ *
++ * Example:
++ *
++ * static int driver_dl_probe(... const struct efx_dl_device_info *dev_info ...)
++ * {
++ *        struct efx_dl_falcon_resources *res;
++ *
++ *        efx_dl_for_each_device_info_matching(dev_info,EFX_DL_FALCON_RESOURCES,
++ *                                             struct efx_dl_falcon_resources,
++ *                                             hdr, res) {
++ *                if (res->flags & EFX_DL_FALCON_DUAL_FUNC) {
++ *                          .....
++ *                }
++ *        }
++ * }
++ */
++#define efx_dl_for_each_device_info_matching(_dev_info, _type,                \
++                                           _info_type, _field, _p)    \
++      for ((_p) = container_of((_dev_info), _info_type, _field);      \
++           (_p) != NULL;                                              \
++           (_p) = container_of((_p)->_field.next, _info_type, _field))\
++              if ((_p)->_field.type != _type)                         \
++                      continue;                                       \
++              else
++
++/**
++ * efx_dl_search_device_info - search an efx_dl_device_info list
++ * @_dev_info: Pointer to first &struct efx_dl_device_info
++ * @_type: Type code to look for
++ * @_info_type: Structure type corresponding to type code
++ * @_field: Name of &struct efx_dl_device_info member in this type
++ * @_p: Result variable
++ *
++ * Example:
++ *
++ * static int driver_dl_probe(... const struct efx_dl_device_info *dev_info ...)
++ * {
++ *        struct efx_dl_falcon_resources *res;
++ *
++ *        efx_dl_search_device_info(dev_info, EFX_DL_FALCON_RESOURCES,
++ *                                  struct efx_dl_falcon_resources, hdr, res);
++ *        if (res != NULL) {
++ *                 ....
++ *        }
++ * }
++ */
++#define efx_dl_search_device_info(_dev_info, _type, _info_type,               \
++                                _field, _p)                           \
++      efx_dl_for_each_device_info_matching((_dev_info), (_type),      \
++                                           _info_type, _field, (_p))  \
++              break;
++
++#endif /* EFX_DRIVERLINK_API_H */
+--- linux-2.6.18.8/drivers/net/sfc/efx.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/efx.c  2008-05-19 00:33:28.837808372 +0300
+@@ -0,0 +1,2783 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <linux/spinlock.h>
-+#include <linux/kthread.h>
-+#include <linux/list.h>
-+#include <xen/balloon.h>
-+#include <asm/hypervisor.h>
-+#include "common.h"
++#include <linux/module.h>
++#include <linux/pci.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/delay.h>
++#include <linux/notifier.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/in.h>
++#include <linux/crc32.h>
++#include <linux/ethtool.h>
++#include <asm/uaccess.h>
++#include "net_driver.h"
++#include "gmii.h"
++#include "driverlink.h"
++#include "selftest.h"
++#include "debugfs.h"
++#include "ethtool.h"
++#include "tx.h"
++#include "rx.h"
++#include "efx.h"
++#include "mdio_10g.h"
++#include "falcon.h"
++#include "workarounds.h"
 +
-+/*
-+ * These are rather arbitrary. They are fairly large because adjacent requests
-+ * pulled from a communication ring are quite likely to end up being part of
-+ * the same scatter/gather request at the disc.
-+ * 
-+ * ** TRY INCREASING 'blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW **
-+ * 
-+ * This will increase the chances of being able to write whole tracks.
-+ * 64 should be enough to keep us competitive with Linux.
++/**************************************************************************
++ *
++ * Type name strings
++ *
++ **************************************************************************
 + */
-+static int blkif_reqs = 64;
-+module_param_named(reqs, blkif_reqs, int, 0);
-+MODULE_PARM_DESC(reqs, "Number of blkback requests to allocate");
 +
-+/* Run-time switchable: /sys/module/blkback/parameters/ */
-+static unsigned int log_stats = 0;
-+static unsigned int debug_lvl = 0;
-+module_param(log_stats, int, 0644);
-+module_param(debug_lvl, int, 0644);
++/* Loopback mode names (see LOOPBACK_MODE()) */
++const unsigned int efx_loopback_mode_max = LOOPBACK_MAX;
++const char *efx_loopback_mode_names[] = {
++      [LOOPBACK_NONE]    = "NONE",
++      [LOOPBACK_MAC]     = "MAC",
++      [LOOPBACK_XGMII]   = "XGMII",
++      [LOOPBACK_XGXS]    = "XGXS",
++      [LOOPBACK_XAUI]    = "XAUI",
++      [LOOPBACK_PHY]     = "PHY",
++      [LOOPBACK_PHYXS]   = "PHY(XS)",
++      [LOOPBACK_PCS]     = "PHY(PCS)",
++      [LOOPBACK_PMAPMD]  = "PHY(PMAPMD)",
++      [LOOPBACK_NETWORK] = "NETWORK",
++};
++
++/* Interrupt mode names (see INT_MODE())) */
++const unsigned int efx_interrupt_mode_max = EFX_INT_MODE_MAX;
++const char *efx_interrupt_mode_names[] = {
++      [EFX_INT_MODE_MSIX]   = "MSI-X",
++      [EFX_INT_MODE_MSI]    = "MSI",
++      [EFX_INT_MODE_LEGACY] = "legacy",
++};
++
++/* PHY type names (see PHY_TYPE())) */
++const unsigned int efx_phy_type_max = PHY_TYPE_MAX;
++const char *efx_phy_type_names[] = {
++      [PHY_TYPE_NONE]        = "none",
++      [PHY_TYPE_CX4_RTMR]    = "Mysticom CX4",
++      [PHY_TYPE_1G_ALASKA]   = "1G Alaska",
++      [PHY_TYPE_10XPRESS]    = "SFC 10Xpress",
++      [PHY_TYPE_XFP]         = "Quake XFP",
++      [PHY_TYPE_PM8358]      = "PM8358 XAUI",
++};
++
++const unsigned int efx_reset_type_max = RESET_TYPE_MAX;
++const char *efx_reset_type_names[] = {
++      [RESET_TYPE_INVISIBLE]    = "INVISIBLE",
++      [RESET_TYPE_ALL]          = "ALL",
++      [RESET_TYPE_WORLD]        = "WORLD",
++      [RESET_TYPE_DISABLE]      = "DISABLE",
++      [RESET_TYPE_MONITOR]      = "MONITOR",
++      [RESET_TYPE_INT_ERROR]    = "INT_ERROR",
++      [RESET_TYPE_RX_RECOVERY]  = "RX_RECOVERY",
++};
++
++const unsigned int efx_nic_state_max = STATE_MAX;
++const char *efx_nic_state_names[] = {
++      [STATE_INIT]          = "INIT",
++      [STATE_RUNNING]       = "RUNNING",
++      [STATE_FINI]          = "FINI",
++      [STATE_RESETTING]     = "RESETTING",
++      [STATE_DISABLED]      = "DISABLED",
++};
++
++#define EFX_MAX_MTU (9 * 1024)
++
++
++/**************************************************************************
++ *
++ * Configurable values
++ *
++ *************************************************************************/
 +
 +/*
-+ * Each outstanding request that we've passed to the lower device layers has a 
-+ * 'pending_req' allocated to it. Each buffer_head that completes decrements 
-+ * the pendcnt towards zero. When it hits zero, the specified domain has a 
-+ * response queued for it, with the saved 'id' passed back.
++ * Use separate channels for TX and RX events
++ *
++ * Set this to 1 to use separate channels for TX and RX. It allows us to
++ * apply a higher level of interrupt moderation to TX events.
++ *
++ * This is forced to 0 for MSI interrupt mode as the interrupt vector
++ * is not written
 + */
-+typedef struct {
-+      blkif_t       *blkif;
-+      u64            id;
-+      int            nr_pages;
-+      atomic_t       pendcnt;
-+      unsigned short operation;
-+      int            status;
-+      struct list_head free_list;
-+} pending_req_t;
++static unsigned int separate_tx_and_rx_channels = 1;
 +
-+static pending_req_t *pending_reqs;
-+static struct list_head pending_free;
-+static DEFINE_SPINLOCK(pending_free_lock);
-+static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
++/* This is the weight assigned to each of the (per-channel) virtual
++ * NAPI devices.
++ */
++static int napi_weight = 64;
 +
-+#define BLKBACK_INVALID_HANDLE (~0)
++/* This is the time (in jiffies) between invocations of the hardware
++ * monitor, which checks for known hardware bugs and resets the
++ * hardware and driver as necessary.
++ */
++unsigned int efx_monitor_interval = 1 * HZ;
 +
-+static struct page **pending_pages;
-+static grant_handle_t *pending_grant_handles;
++/* This controls whether or not the hardware monitor will trigger a
++ * reset when it detects an error condition.
++ */
++static unsigned int monitor_reset = 1;
 +
-+static inline int vaddr_pagenr(pending_req_t *req, int seg)
++/* This controls whether or not the driver will initialise devices
++ * with invalid MAC addresses stored in the EEPROM or flash.  If true,
++ * such devices will be initialised with a random locally-generated
++ * MAC address.  This allows for loading the efx_mtd driver to
++ * reprogram the flash, even if the flash contents (including the MAC
++ * address) have previously been erased.
++ */
++static unsigned int allow_bad_hwaddr;
++
++/* Initial interrupt moderation settings.  They can be modified after
++ * module load with ethtool.
++ *
++ * The default for RX should strike a balance between increasing the
++ * round-trip latency and reducing overhead.
++ */
++static unsigned int rx_irq_mod_usec = 60;
++
++/* Initial interrupt moderation settings.  They can be modified after
++ * module load with ethtool.
++ *
++ * This default is chosen to ensure that a 10G link does not go idle
++ * while a TX queue is stopped after it has become full.  A queue is
++ * restarted when it drops below half full.  The time this takes (assuming
++ * worst case 3 descriptors per packet and 1024 descriptors) is
++ *   512 / 3 * 1.2 = 205 usec.
++ */
++static unsigned int tx_irq_mod_usec = 150;
++
++/* Ignore online self-test failures at load
++ *
++ * If set to 1, then the driver will not fail to load
++ * if the online self-test fails. Useful only during testing
++ */
++static unsigned int allow_load_on_failure;
++
++/* Set to 1 to enable the use of Message-Signalled Interrupts (MSI).
++ * MSI will not work on some motherboards due to limitations of the
++ * chipset, so the default is off.
++ *
++ * This is the highest capability interrupt mode to use
++ * 0 => MSI-X
++ * 1 => MSI
++ * 2 => legacy
++ */
++static unsigned int interrupt_mode;
++
++/* If set to 1, then the driver will perform an offline self test
++ * when each interface first comes up. This will appear like the
++ * interface bounces up and down
++ */
++static unsigned int onload_offline_selftest = 1;
++
++/* This is the requested number of CPUs to use for Receive-Side Scaling (RSS),
++ * i.e. the number of CPUs among which we may distribute simultaneous
++ * interrupt handling.
++ *
++ * Cards without MSI-X will only target one CPU
++ *
++ * Default (0) means to use all CPUs in the system.  This parameter
++ * can be set using "rss_cpus=xxx" when loading the module.
++ */
++static unsigned int rss_cpus;
++module_param(rss_cpus, uint, 0444);
++MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling");
++
++/**************************************************************************
++ *
++ * Utility functions and prototypes
++ *
++ *************************************************************************/
++static void efx_remove_channel(struct efx_channel *channel);
++static void efx_remove_port(struct efx_nic *efx);
++static void efx_fini_napi(struct efx_nic *efx);
++static void efx_fini_channels(struct efx_nic *efx);
++
++/**************************************************************************
++ *
++ * Event queue processing
++ *
++ *************************************************************************/
++
++/* Process channel's event queue
++ *
++ * This function is responsible for processing the event queue of a
++ * single channel.  The caller must guarantee that this function will
++ * never be concurrently called more than once on the same channel,
++ * though different channels may be being processed concurrently.
++ */
++static inline int efx_process_channel(struct efx_channel *channel, int rx_quota)
 +{
-+      return (req - pending_reqs) * BLKIF_MAX_SEGMENTS_PER_REQUEST + seg;
++      int rxdmaqs;
++      struct efx_rx_queue *rx_queue;
++
++      if (unlikely(channel->efx->reset_pending != RESET_TYPE_NONE ||
++                   !channel->enabled))
++              return rx_quota;
++
++      rxdmaqs = falcon_process_eventq(channel, &rx_quota);
++
++      /* Deliver last RX packet. */
++      if (channel->rx_pkt) {
++              __efx_rx_packet(channel, channel->rx_pkt,
++                              channel->rx_pkt_csummed);
++              channel->rx_pkt = NULL;
++      }
++
++      efx_rx_strategy(channel);
++
++      /* Refill descriptor rings as necessary */
++      rx_queue = &channel->efx->rx_queue[0];
++      while (rxdmaqs) {
++              if (rxdmaqs & 0x01)
++                      efx_fast_push_rx_descriptors(rx_queue);
++              rx_queue++;
++              rxdmaqs >>= 1;
++      }
++
++      return rx_quota;
 +}
 +
-+static inline unsigned long vaddr(pending_req_t *req, int seg)
++/* Mark channel as finished processing
++ *
++ * Note that since we will not receive further interrupts for this
++ * channel before we finish processing and call the eventq_read_ack()
++ * method, there is no need to use the interrupt hold-off timers.
++ */
++static inline void efx_channel_processed(struct efx_channel *channel)
 +{
-+      unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]);
-+      return (unsigned long)pfn_to_kaddr(pfn);
++      /* Write to EVQ_RPTR_REG.  If a new event arrived in a race
++       * with finishing processing, a new interrupt will be raised.
++       */
++      channel->work_pending = 0;
++      smp_wmb(); /* Ensure channel updated before any new interrupt. */
++      falcon_eventq_read_ack(channel);
 +}
 +
-+#define pending_handle(_req, _seg) \
-+      (pending_grant_handles[vaddr_pagenr(_req, _seg)])
++/* NAPI poll handler
++ *
++ * NAPI guarantees serialisation of polls of the same device, which
++ * provides the guarantee required by efx_process_channel().
++ */
++#if !defined(EFX_HAVE_OLD_NAPI)
++static int efx_poll(struct napi_struct *napi, int budget)
++{
++      struct efx_channel *channel =
++              container_of(napi, struct efx_channel, napi_str);
++      struct net_device *napi_dev = channel->napi_dev;
++#else
++static int efx_poll(struct net_device *napi, int *budget_ret)
++{
++      struct net_device *napi_dev = napi;
++      struct efx_channel *channel = napi_dev->priv;
++      int budget = min(napi_dev->quota, *budget_ret);
++#endif
++      int unused;
++      int rx_packets;
 +
++      EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n",
++                channel->channel, raw_smp_processor_id());
 +
-+static int do_block_io_op(blkif_t *blkif);
-+static void dispatch_rw_block_io(blkif_t *blkif,
-+                               blkif_request_t *req,
-+                               pending_req_t *pending_req);
-+static void make_response(blkif_t *blkif, u64 id,
-+                        unsigned short op, int st);
++      unused = efx_process_channel(channel, budget);
++      rx_packets = (budget - unused);
++#if defined(EFX_HAVE_OLD_NAPI)
++      napi_dev->quota -= rx_packets;
++      *budget_ret -= rx_packets;
++#endif
 +
-+/******************************************************************
-+ * misc small helpers
++      if (rx_packets < budget) {
++              /* There is no race here; although napi_disable() will
++               * only wait for netif_rx_complete(), this isn't a problem
++               * since efx_channel_processed() will have no effect if
++               * interrupts have already been disabled.
++               */
++              netif_rx_complete(napi_dev, napi);
++              efx_channel_processed(channel);
++      }
++
++#if !defined(EFX_HAVE_OLD_NAPI)
++      return rx_packets;
++#else
++      return (rx_packets >= budget);
++#endif
++}
++
++/* Process the eventq of the specified channel immediately on this CPU
++ *
++ * Disable hardware generated interrupts, wait for any existing
++ * processing to finish, then directly poll (and ack ) the eventq.
++ * Finally reenable NAPI and interrupts.
++ *
++ * Since we are touching interrupts the caller should hold the suspend lock
 + */
-+static pending_req_t* alloc_req(void)
++void efx_process_channel_now(struct efx_channel *channel)
 +{
-+      pending_req_t *req = NULL;
-+      unsigned long flags;
++      struct efx_nic *efx = channel->efx;
 +
-+      spin_lock_irqsave(&pending_free_lock, flags);
-+      if (!list_empty(&pending_free)) {
-+              req = list_entry(pending_free.next, pending_req_t, free_list);
-+              list_del(&req->free_list);
-+      }
-+      spin_unlock_irqrestore(&pending_free_lock, flags);
-+      return req;
++      BUG_ON(!channel->used_flags);
++      BUG_ON(!channel->enabled);
++
++      /* Disable interrupts and wait for ISRs to complete */
++      falcon_disable_interrupts(efx);
++      if (efx->legacy_irq)
++              synchronize_irq(efx->legacy_irq);
++      if (channel->has_interrupt && channel->irq)
++              synchronize_irq(channel->irq);
++
++      /* Wait for any NAPI processing to complete */
++      napi_disable(&channel->napi_str);
++
++      /* Poll the channel */
++      (void) efx_process_channel(channel, efx->type->evq_size);
++
++      /* Ack the eventq. This may cause an interrupt to be generated
++       * when they are reenabled */
++      efx_channel_processed(channel);
++
++      /* Reenable NAPI polling */
++      napi_enable(&channel->napi_str);
++
++      /* Reenable interrupts */
++      falcon_enable_interrupts(efx);
 +}
 +
-+static void free_req(pending_req_t *req)
++/* Create event queue
++ * Event queue memory allocations are done only once.  If the channel
++ * is reset, the memory buffer will be reused; this guards against
++ * errors during channel reset and also simplifies interrupt handling.
++ */
++static int efx_probe_eventq(struct efx_channel *channel)
 +{
-+      unsigned long flags;
-+      int was_empty;
++      EFX_LOG(channel->efx, "chan %d create event queue\n", channel->channel);
 +
-+      spin_lock_irqsave(&pending_free_lock, flags);
-+      was_empty = list_empty(&pending_free);
-+      list_add(&req->free_list, &pending_free);
-+      spin_unlock_irqrestore(&pending_free_lock, flags);
-+      if (was_empty)
-+              wake_up(&pending_free_wq);
++      return falcon_probe_eventq(channel);
 +}
 +
-+static void unplug_queue(blkif_t *blkif)
++/* Prepare channel's event queue */
++static int efx_init_eventq(struct efx_channel *channel)
 +{
-+      if (blkif->plug == NULL)
-+              return;
-+      if (blkif->plug->unplug_fn)
-+              blkif->plug->unplug_fn(blkif->plug);
-+      blk_put_queue(blkif->plug);
-+      blkif->plug = NULL;
++      EFX_LOG(channel->efx, "chan %d init event queue\n", channel->channel);
++
++      ASSERT_RTNL();
++
++      /* Initialise fields */
++      channel->eventq_read_ptr = 0;
++
++      return falcon_init_eventq(channel);
 +}
 +
-+static void plug_queue(blkif_t *blkif, struct bio *bio)
++static void efx_fini_eventq(struct efx_channel *channel)
 +{
-+      request_queue_t *q = bdev_get_queue(bio->bi_bdev);
++      EFX_LOG(channel->efx, "chan %d fini event queue\n", channel->channel);
 +
-+      if (q == blkif->plug)
-+              return;
-+      unplug_queue(blkif);
-+      blk_get_queue(q);
-+      blkif->plug = q;
++      ASSERT_RTNL();
++
++      falcon_fini_eventq(channel);
 +}
 +
-+static void fast_flush_area(pending_req_t *req)
++static void efx_remove_eventq(struct efx_channel *channel)
 +{
-+      struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-+      unsigned int i, invcount = 0;
-+      grant_handle_t handle;
-+      int ret;
++      EFX_LOG(channel->efx, "chan %d remove event queue\n", channel->channel);
 +
-+      for (i = 0; i < req->nr_pages; i++) {
-+              handle = pending_handle(req, i);
-+              if (handle == BLKBACK_INVALID_HANDLE)
-+                      continue;
-+              gnttab_set_unmap_op(&unmap[i], vaddr(req, i), GNTMAP_host_map,
-+                                  handle);
-+              pending_handle(req, i) = BLKBACK_INVALID_HANDLE;
-+              invcount++;
-+      }
-+
-+      ret = HYPERVISOR_grant_table_op(
-+              GNTTABOP_unmap_grant_ref, unmap, invcount);
-+      BUG_ON(ret);
++      falcon_remove_eventq(channel);
 +}
 +
-+/******************************************************************
-+ * SCHEDULER FUNCTIONS
++/**************************************************************************
++ *
++ * Channel handling
++ *
++ *************************************************************************/
++
++/* Setup per-NIC RX buffer parameters.
++ * Calculate the rx buffer allocation parameters required to support
++ * the current MTU, including padding for header alignment and overruns.
 + */
++static void efx_calc_rx_buffer_params(struct efx_nic *efx)
++{
++      unsigned int order, len;
 +
-+static void print_stats(blkif_t *blkif)
++      len = (max(EFX_PAGE_IP_ALIGN, NET_IP_ALIGN) +
++             EFX_MAX_FRAME_LEN(efx->net_dev->mtu) +
++             efx->type->rx_buffer_padding);
++
++      /* Page-based allocation page-order */
++      for (order = 0; ((1u << order) * PAGE_SIZE) < len; ++order)
++              ;
++
++      efx->rx_buffer_len = len;
++      efx->rx_buffer_order = order;
++}
++
++static int efx_probe_channel(struct efx_channel *channel)
 +{
-+      printk(KERN_DEBUG "%s: oo %3d  |  rd %4d  |  wr %4d  |  br %4d\n",
-+             current->comm, blkif->st_oo_req,
-+             blkif->st_rd_req, blkif->st_wr_req, blkif->st_br_req);
-+      blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
-+      blkif->st_rd_req = 0;
-+      blkif->st_wr_req = 0;
-+      blkif->st_oo_req = 0;
++      struct efx_tx_queue *tx_queue;
++      struct efx_rx_queue *rx_queue;
++      int rc;
++
++      EFX_LOG(channel->efx, "creating channel %d\n", channel->channel);
++
++      rc = efx_probe_eventq(channel);
++      if (rc)
++              goto fail1;
++
++      efx_for_each_channel_tx_queue(tx_queue, channel) {
++              rc = efx_probe_tx_queue(tx_queue);
++              if (rc)
++                      goto fail2;
++      }
++
++      efx_for_each_channel_rx_queue(rx_queue, channel) {
++              rc = efx_probe_rx_queue(rx_queue);
++              if (rc)
++                      goto fail3;
++      }
++
++      channel->n_rx_frm_trunc = 0;
++
++      return 0;
++
++ fail3:
++      efx_for_each_channel_rx_queue(rx_queue, channel)
++              efx_remove_rx_queue(rx_queue);
++ fail2:
++      efx_for_each_channel_tx_queue(tx_queue, channel)
++              efx_remove_tx_queue(tx_queue);
++ fail1:
++      return rc;
 +}
 +
-+int blkif_schedule(void *arg)
++
++/* Channels are shutdown and reinitialised whilst the NIC is running
++ * to propagate configuration changes (mtu, checksum offload), or
++ * to clear hardware error conditions
++ */
++static int efx_init_channels(struct efx_nic *efx)
 +{
-+      blkif_t *blkif = arg;
++      struct efx_tx_queue *tx_queue;
++      struct efx_rx_queue *rx_queue;
++      struct efx_channel *channel;
++      int rc = 0;
 +
-+      blkif_get(blkif);
++      /* Recalculate the rx buffer parameters */
++      efx_calc_rx_buffer_params(efx);
 +
-+      if (debug_lvl)
-+              printk(KERN_DEBUG "%s: started\n", current->comm);
++      /* Initialise the channels */
++      efx_for_each_channel(channel, efx) {
++              EFX_LOG(channel->efx, "init chan %d\n", channel->channel);
 +
-+      while (!kthread_should_stop()) {
-+              if (try_to_freeze())
-+                      continue;
++              rc = efx_init_eventq(channel);
++              if (rc)
++                      goto err;
 +
-+              wait_event_interruptible(
-+                      blkif->wq,
-+                      blkif->waiting_reqs || kthread_should_stop());
-+              wait_event_interruptible(
-+                      pending_free_wq,
-+                      !list_empty(&pending_free) || kthread_should_stop());
++              efx_for_each_channel_tx_queue(tx_queue, channel) {
++                      rc = efx_init_tx_queue(tx_queue);
++                      if (rc)
++                              goto err;
++              }
 +
-+              blkif->waiting_reqs = 0;
-+              smp_mb(); /* clear flag *before* checking for work */
++              /* The rx buffer allocation strategy is MTU dependent */
++              efx_rx_strategy(channel);
 +
-+              if (do_block_io_op(blkif))
-+                      blkif->waiting_reqs = 1;
-+              unplug_queue(blkif);
++              efx_for_each_channel_rx_queue(rx_queue, channel) {
++                      rc = efx_init_rx_queue(rx_queue);
++                      if (rc)
++                              goto err;
++              }
 +
-+              if (log_stats && time_after(jiffies, blkif->st_print))
-+                      print_stats(blkif);
++              WARN_ON(channel->rx_pkt != NULL);
++              efx_rx_strategy(channel);
 +      }
 +
-+      if (log_stats)
-+              print_stats(blkif);
-+      if (debug_lvl)
-+              printk(KERN_DEBUG "%s: exiting\n", current->comm);
++      return 0;
 +
-+      blkif->xenblkd = NULL;
-+      blkif_put(blkif);
++ err:
++      EFX_ERR(efx, "failed to initialise channel %d\n",
++              channel ? channel->channel : -1);
++      efx_fini_channels(efx);
++      return rc;
++}
 +
-+      return 0;
++/* This enables event queue processing and packet transmission.
++ *
++ * Note that this function is not allowed to fail, since that would
++ * introduce too much complexity into the suspend/resume path.
++ */
++static void efx_start_channel(struct efx_channel *channel)
++{
++      struct efx_rx_queue *rx_queue;
++
++      EFX_LOG(channel->efx, "starting chan %d\n", channel->channel);
++
++      if (!(channel->efx->net_dev->flags & IFF_UP))
++              netif_napi_add(channel->napi_dev, &channel->napi_str,
++                             efx_poll, napi_weight);
++
++      /* Mark channel as enabled */
++      channel->work_pending = 0;
++      channel->enabled = 1;
++      smp_wmb(); /* ensure channel updated before first interrupt */
++
++      /* Enable NAPI poll handler */
++      napi_enable(&channel->napi_str);
++
++      /* Load up RX descriptors */
++      efx_for_each_channel_rx_queue(rx_queue, channel)
++              efx_fast_push_rx_descriptors(rx_queue);
 +}
 +
-+/******************************************************************
-+ * COMPLETION CALLBACK -- Called as bh->b_end_io()
++/* This disables event queue processing and packet transmission.
++ * This function does not guarantee that all queue processing
++ * (e.g. RX refill) is complete.
 + */
++static void efx_stop_channel(struct efx_channel *channel)
++{
++      struct efx_rx_queue *rx_queue;
 +
-+static void __end_block_io_op(pending_req_t *pending_req, int error)
++      if (!channel->enabled)
++              return;
++
++      EFX_LOG(channel->efx, "stop chan %d\n", channel->channel);
++
++      /* Mark channel as disabled */
++      channel->enabled = 0;
++
++      /* Wait for any NAPI processing to complete */
++      napi_disable(&channel->napi_str);
++
++      /* Ensure that any worker threads have exited or will be
++       * no-ops.
++       */
++      efx_for_each_channel_rx_queue(rx_queue, channel) {
++              spin_lock_bh(&rx_queue->add_lock);
++              spin_unlock_bh(&rx_queue->add_lock);
++      }
++}
++
++static void efx_fini_channels(struct efx_nic *efx)
 +{
-+      /* An error fails the entire request. */
-+      if ((pending_req->operation == BLKIF_OP_WRITE_BARRIER) &&
-+          (error == -EOPNOTSUPP)) {
-+              DPRINTK("blkback: write barrier op failed, not supported\n");
-+              blkback_barrier(XBT_NIL, pending_req->blkif->be, 0);
-+              pending_req->status = BLKIF_RSP_EOPNOTSUPP;
-+      } else if (error) {
-+              DPRINTK("Buffer not up-to-date at end of operation, "
-+                      "error=%d\n", error);
-+              pending_req->status = BLKIF_RSP_ERROR;
++      struct efx_channel *channel;
++      struct efx_tx_queue *tx_queue;
++      struct efx_rx_queue *rx_queue;
++
++      ASSERT_RTNL();
++
++      efx_for_each_channel(channel, efx) {
++              EFX_LOG(channel->efx, "shut down chan %d\n", channel->channel);
++
++              efx_for_each_channel_rx_queue(rx_queue, channel)
++                      efx_fini_rx_queue(rx_queue);
++              efx_for_each_channel_tx_queue(tx_queue, channel)
++                      efx_fini_tx_queue(tx_queue);
 +      }
 +
-+      if (atomic_dec_and_test(&pending_req->pendcnt)) {
-+              fast_flush_area(pending_req);
-+              make_response(pending_req->blkif, pending_req->id,
-+                            pending_req->operation, pending_req->status);
-+              blkif_put(pending_req->blkif);
-+              free_req(pending_req);
++      /* Do the event queues last so that we can handle flush events
++       * for all DMA queues. */
++      efx_for_each_channel(channel, efx) {
++              EFX_LOG(channel->efx, "shut down evq %d\n", channel->channel);
++
++              efx_fini_eventq(channel);
 +      }
 +}
 +
-+static int end_block_io_op(struct bio *bio, unsigned int done, int error)
++static void efx_remove_channel(struct efx_channel *channel)
 +{
-+      if (bio->bi_size != 0)
-+              return 1;
-+      __end_block_io_op(bio->bi_private, error);
-+      bio_put(bio);
-+      return error;
-+}
++      struct efx_tx_queue *tx_queue;
++      struct efx_rx_queue *rx_queue;
 +
++      EFX_LOG(channel->efx, "destroy chan %d\n", channel->channel);
 +
-+/******************************************************************************
-+ * NOTIFICATION FROM GUEST OS.
-+ */
++      efx_for_each_channel_rx_queue(rx_queue, channel)
++              efx_remove_rx_queue(rx_queue);
++      efx_for_each_channel_tx_queue(tx_queue, channel)
++              efx_remove_tx_queue(tx_queue);
++      efx_remove_eventq(channel);
 +
-+static void blkif_notify_work(blkif_t *blkif)
-+{
-+      blkif->waiting_reqs = 1;
-+      wake_up(&blkif->wq);
++      channel->used_flags = 0;
 +}
 +
-+irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
++/**************************************************************************
++ *
++ * Port handling
++ *
++ **************************************************************************/
++
++/* This ensures that the kernel is kept informed (via
++ * netif_carrier_on/off) of the link status, and also maintains the
++ * link status's stop on the port's TX queue.
++ */
++static void efx_link_status_changed(struct efx_nic *efx)
 +{
-+      blkif_notify_work(dev_id);
-+      return IRQ_HANDLED;
-+}
++      unsigned long flags __attribute__ ((unused));
++      int carrier_ok;
 +
++      /* Ensure no link status notifications get sent to the OS after the net
++       * device has been unregistered. */
++      if (!efx->net_dev_registered)
++              return;
 +
++      carrier_ok = netif_carrier_ok(efx->net_dev) ? 1 : 0;
++      if (efx->link_up != carrier_ok) {
++              efx->n_link_state_changes++;
 +
-+/******************************************************************
-+ * DOWNWARD CALLS -- These interface with the block-device layer proper.
-+ */
++              if (efx->link_up)
++                      netif_carrier_on(efx->net_dev);
++              else
++                      netif_carrier_off(efx->net_dev);
++      }
 +
-+static int do_block_io_op(blkif_t *blkif)
++      /* Inform driverlink client */
++      EFX_DL_CALLBACK(efx, link_change, efx->link_up);
++
++      /* Status message for kernel log */
++      if (efx->link_up) {
++              struct mii_if_info *gmii = &efx->mii;
++              unsigned adv, lpa;
++              /* NONE here means direct XAUI from the controller, with no
++               * MDIO-attached device we can query. */
++              if (efx->phy_type != PHY_TYPE_NONE) {
++                      adv = gmii_advertised(gmii);
++                      lpa = gmii_lpa(gmii);
++              } else {
++                      lpa = GM_LPA_10000 | LPA_DUPLEX;
++                      adv = lpa;
++              }
++              EFX_INFO(efx, "link up at %dMbps %s-duplex "
++                       "(adv %04x lpa %04x) (MTU %d)%s%s%s%s\n",
++                       (efx->link_options & GM_LPA_10000 ? 10000 :
++                        (efx->link_options & GM_LPA_1000 ? 1000 :
++                         (efx->link_options & GM_LPA_100 ? 100 :
++                          10))),
++                       (efx->link_options & GM_LPA_DUPLEX ?
++                        "full" : "half"),
++                       adv, lpa,
++                       efx->net_dev->mtu,
++                       (efx->loopback_mode ? " [" : ""),
++                       (efx->loopback_mode ? LOOPBACK_MODE(efx) : ""),
++                       (efx->loopback_mode ? " LOOPBACK]" : ""),
++                       (efx->promiscuous ? " [PROMISC]" : ""));
++      } else {
++              EFX_INFO(efx, "link down\n");
++      }
++
++}
++
++/* This call reinitialises the MAC to pick up new PHY settings
++ * To call from a context that cannot sleep use reconfigure_work work item
++ * For on_disabled=1 the caller must be serialised against efx_reset,
++ * ideally by holding the rtnl lock.
++ */
++void efx_reconfigure_port(struct efx_nic *efx, int on_disabled)
 +{
-+      blkif_back_rings_t *blk_rings = &blkif->blk_rings;
-+      blkif_request_t req;
-+      pending_req_t *pending_req;
-+      RING_IDX rc, rp;
-+      int more_to_do = 0;
++      mutex_lock(&efx->mac_lock);
 +
-+      rc = blk_rings->common.req_cons;
-+      rp = blk_rings->common.sring->req_prod;
-+      rmb(); /* Ensure we see queued requests up to 'rp'. */
++      EFX_LOG(efx, "reconfiguring MAC from PHY settings\n");
 +
-+      while ((rc != rp)) {
++      if (on_disabled)
++              ASSERT_RTNL();
++      else if (!efx->port_enabled)
++              goto out;
 +
-+              if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc))
-+                      break;
++      efx->mac_op->reconfigure(efx);
 +
-+              pending_req = alloc_req();
-+              if (NULL == pending_req) {
-+                      blkif->st_oo_req++;
-+                      more_to_do = 1;
-+                      break;
-+              }
++out:
++      /* Inform kernel of loss/gain of carrier */
++      efx_link_status_changed(efx);
 +
-+              switch (blkif->blk_protocol) {
-+              case BLKIF_PROTOCOL_NATIVE:
-+                      memcpy(&req, RING_GET_REQUEST(&blk_rings->native, rc), sizeof(req));
-+                      break;
-+              case BLKIF_PROTOCOL_X86_32:
-+                      blkif_get_x86_32_req(&req, RING_GET_REQUEST(&blk_rings->x86_32, rc));
-+                      break;
-+              case BLKIF_PROTOCOL_X86_64:
-+                      blkif_get_x86_64_req(&req, RING_GET_REQUEST(&blk_rings->x86_64, rc));
-+                      break;
-+              default:
-+                      BUG();
-+              }
-+              blk_rings->common.req_cons = ++rc; /* before make_response() */
++      mutex_unlock(&efx->mac_lock);
++}
 +
-+              switch (req.operation) {
-+              case BLKIF_OP_READ:
-+                      blkif->st_rd_req++;
-+                      dispatch_rw_block_io(blkif, &req, pending_req);
-+                      break;
-+              case BLKIF_OP_WRITE_BARRIER:
-+                      blkif->st_br_req++;
-+                      /* fall through */
-+              case BLKIF_OP_WRITE:
-+                      blkif->st_wr_req++;
-+                      dispatch_rw_block_io(blkif, &req, pending_req);
-+                      break;
-+              default:
-+                      DPRINTK("error: unknown block io operation [%d]\n",
-+                              req.operation);
-+                      make_response(blkif, req.id, req.operation,
-+                                    BLKIF_RSP_ERROR);
-+                      free_req(pending_req);
-+                      break;
-+              }
-+      }
-+      return more_to_do;
++static void efx_reconfigure_work(struct work_struct *data)
++{
++      struct efx_nic *efx = container_of(data, struct efx_nic,
++                                         reconfigure_work);
++
++      EFX_LOG(efx, "MAC reconfigure executing on CPU %d\n",
++              raw_smp_processor_id());
++
++      /* Reinitialise MAC to activate new PHY parameters */
++      efx_reconfigure_port(efx, 0);
 +}
 +
-+static void dispatch_rw_block_io(blkif_t *blkif,
-+                               blkif_request_t *req,
-+                               pending_req_t *pending_req)
++static int efx_probe_port(struct efx_nic *efx)
 +{
-+      extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
-+      struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-+      struct phys_req preq;
-+      struct { 
-+              unsigned long buf; unsigned int nsec;
-+      } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-+      unsigned int nseg;
-+      struct bio *bio = NULL, *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-+      int ret, i, nbio = 0;
-+      int operation;
++      unsigned char *dev_addr;
++      int rc;
 +
-+      switch (req->operation) {
-+      case BLKIF_OP_READ:
-+              operation = READ;
-+              break;
-+      case BLKIF_OP_WRITE:
-+              operation = WRITE;
-+              break;
-+      case BLKIF_OP_WRITE_BARRIER:
-+              operation = WRITE_BARRIER;
-+              break;
-+      default:
-+              operation = 0; /* make gcc happy */
-+              BUG();
-+      }
++      EFX_LOG(efx, "create port\n");
 +
-+      /* Check that number of segments is sane. */
-+      nseg = req->nr_segments;
-+      if (unlikely(nseg == 0) || 
-+          unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
-+              DPRINTK("Bad number of segments in request (%d)\n", nseg);
-+              goto fail_response;
++      /* Connect up MAC/PHY operations table and read MAC address */
++      rc = falcon_probe_port(efx);
++      if (rc)
++              goto err;
++
++      /* Sanity check MAC address */
++      dev_addr = efx->mac_address;
++      if (!is_valid_ether_addr(dev_addr)) {
++              DECLARE_MAC_BUF(mac);
++
++              EFX_ERR(efx, "invalid MAC address %s\n",
++                      print_mac(mac, dev_addr));
++              if (!allow_bad_hwaddr) {
++                      rc = -EINVAL;
++                      goto err;
++              }
++              random_ether_addr(dev_addr);
++              EFX_INFO(efx, "using locally-generated MAC %s\n",
++                       print_mac(mac, dev_addr));
 +      }
 +
-+      preq.dev           = req->handle;
-+      preq.sector_number = req->sector_number;
-+      preq.nr_sects      = 0;
++      /* Register debugfs entries */
++      rc = efx_init_debugfs_port(efx);
++      if (rc)
++              goto err;
 +
-+      pending_req->blkif     = blkif;
-+      pending_req->id        = req->id;
-+      pending_req->operation = req->operation;
-+      pending_req->status    = BLKIF_RSP_OKAY;
-+      pending_req->nr_pages  = nseg;
++      return 0;
 +
-+      for (i = 0; i < nseg; i++) {
-+              uint32_t flags;
++ err:
++      efx_remove_port(efx);
++      return rc;
++}
 +
-+              seg[i].nsec = req->seg[i].last_sect -
-+                      req->seg[i].first_sect + 1;
++static int efx_init_port(struct efx_nic *efx)
++{
++      int rc;
 +
-+              if ((req->seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
-+                  (req->seg[i].last_sect < req->seg[i].first_sect))
-+                      goto fail_response;
-+              preq.nr_sects += seg[i].nsec;
++      EFX_LOG(efx, "init port\n");
 +
-+              flags = GNTMAP_host_map;
-+              if (operation != READ)
-+                      flags |= GNTMAP_readonly;
-+              gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
-+                                req->seg[i].gref, blkif->domid);
-+      }
++      /* The default power state is ON */
++      efx->phy_powered = 1;
 +
-+      ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg);
-+      BUG_ON(ret);
++      /* Initialise the MAC and PHY */
++      rc = efx->mac_op->init(efx);
++      if (rc)
++              return rc;
 +
-+      for (i = 0; i < nseg; i++) {
-+              if (unlikely(map[i].status != 0)) {
-+                      DPRINTK("invalid buffer -- could not remap it\n");
-+                      map[i].handle = BLKBACK_INVALID_HANDLE;
-+                      ret |= 1;
-+              }
++      efx->port_initialized = 1;
 +
-+              pending_handle(pending_req, i) = map[i].handle;
++      /* Reconfigure port to program MAC registers */
++      efx->mac_op->reconfigure(efx);
 +
-+              if (ret)
-+                      continue;
++      return 0;
++}
 +
-+              set_phys_to_machine(__pa(vaddr(
-+                      pending_req, i)) >> PAGE_SHIFT,
-+                      FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
-+              seg[i].buf  = map[i].dev_bus_addr | 
-+                      (req->seg[i].first_sect << 9);
-+      }
++/* Allow efx_reconfigure_port() to run, and propagate delayed changes
++ * to the promiscuous flag to the MAC if needed */
++static void efx_start_port(struct efx_nic *efx)
++{
++      EFX_LOG(efx, "start port\n");
++      ASSERT_RTNL();
 +
-+      if (ret)
-+              goto fail_flush;
++      BUG_ON(efx->port_enabled);
 +
-+      if (vbd_translate(&preq, blkif, operation) != 0) {
-+              DPRINTK("access denied: %s of [%llu,%llu] on dev=%04x\n", 
-+                      operation == READ ? "read" : "write",
-+                      preq.sector_number,
-+                      preq.sector_number + preq.nr_sects, preq.dev);
-+              goto fail_flush;
-+      }
++      mutex_lock(&efx->mac_lock);
++      efx->port_enabled = 1;
++      mutex_unlock(&efx->mac_lock);
 +
-+      for (i = 0; i < nseg; i++) {
-+              if (((int)preq.sector_number|(int)seg[i].nsec) &
-+                  ((bdev_hardsect_size(preq.bdev) >> 9) - 1)) {
-+                      DPRINTK("Misaligned I/O request from domain %d",
-+                              blkif->domid);
-+                      goto fail_put_bio;
++      if (efx->net_dev_registered) {
++              int promiscuous;
++
++              netif_tx_lock_bh(efx->net_dev);
++              promiscuous = (efx->net_dev->flags & IFF_PROMISC) ? 1 : 0;
++              if (efx->promiscuous != promiscuous) {
++                      efx->promiscuous = promiscuous;
++                      queue_work(efx->workqueue, &efx->reconfigure_work);
 +              }
++              netif_tx_unlock_bh(efx->net_dev);
++      }
++}
 +
-+              while ((bio == NULL) ||
-+                     (bio_add_page(bio,
-+                                   virt_to_page(vaddr(pending_req, i)),
-+                                   seg[i].nsec << 9,
-+                                   seg[i].buf & ~PAGE_MASK) == 0)) {
-+                      bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, nseg-i);
-+                      if (unlikely(bio == NULL))
-+                              goto fail_put_bio;
++/* Prevents efx_reconfigure_port() from executing, and prevents
++ * efx_set_multicast_list() from scheduling efx_reconfigure_work.
++ * efx_reconfigure_work can still be scheduled via NAPI processing
++ * until efx_flush_all() is called */
++static void efx_stop_port(struct efx_nic *efx)
++{
++      EFX_LOG(efx, "stop port\n");
++      ASSERT_RTNL();
 +
-+                      bio->bi_bdev    = preq.bdev;
-+                      bio->bi_private = pending_req;
-+                      bio->bi_end_io  = end_block_io_op;
-+                      bio->bi_sector  = preq.sector_number;
-+              }
++      mutex_lock(&efx->mac_lock);
++      efx->port_enabled = 0;
++      mutex_unlock(&efx->mac_lock);
 +
-+              preq.sector_number += seg[i].nsec;
++      /* Serialise against efx_set_multicast_list() */
++      if (efx->net_dev_registered) {
++              netif_tx_lock_bh(efx->net_dev);
++              netif_tx_unlock_bh(efx->net_dev);
 +      }
++}
 +
-+      plug_queue(blkif, bio);
-+      atomic_set(&pending_req->pendcnt, nbio);
-+      blkif_get(blkif);
++static void efx_fini_port(struct efx_nic *efx)
++{
++      EFX_LOG(efx, "shut down port\n");
 +
-+      for (i = 0; i < nbio; i++)
-+              submit_bio(operation, biolist[i]);
++      if (!efx->port_initialized)
++              return;
 +
-+      if (operation == READ)
-+              blkif->st_rd_sect += preq.nr_sects;
-+      else if (operation == WRITE)
-+              blkif->st_wr_sect += preq.nr_sects;
++      efx->mac_op->fini(efx);
++      efx->port_initialized = 0;
 +
-+      return;
++      /* Mark the link down */
++      efx->link_up = 0;
++      efx_link_status_changed(efx);
++}
 +
-+ fail_put_bio:
-+      for (i = 0; i < (nbio-1); i++)
-+              bio_put(biolist[i]);
-+ fail_flush:
-+      fast_flush_area(pending_req);
-+ fail_response:
-+      make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
-+      free_req(pending_req);
-+} 
++static void efx_remove_port(struct efx_nic *efx)
++{
++      EFX_LOG(efx, "destroying port\n");
 +
++      efx_fini_debugfs_port(efx);
++      falcon_remove_port(efx);
++}
 +
++/**************************************************************************
++ *
++ * NIC handling
++ *
++ **************************************************************************/
 +
-+/******************************************************************
-+ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
-+ */
++/* This configures the PCI device to enable I/O and DMA. */
++static int efx_init_io(struct efx_nic *efx)
++{
++      struct pci_dev *pci_dev = efx->pci_dev;
++      int rc;
 +
++      EFX_LOG(efx, "initialising I/O\n");
 +
-+static void make_response(blkif_t *blkif, u64 id,
-+                        unsigned short op, int st)
-+{
-+      blkif_response_t  resp;
-+      unsigned long     flags;
-+      blkif_back_rings_t *blk_rings = &blkif->blk_rings;
-+      int more_to_do = 0;
-+      int notify;
++      /* Generic device-enabling code */
++      rc = pci_enable_device(pci_dev);
++      if (rc) {
++              EFX_ERR(efx, "failed to enable PCI device\n");
++              goto fail1;
++      }
 +
-+      resp.id        = id;
-+      resp.operation = op;
-+      resp.status    = st;
++      pci_set_master(pci_dev);
 +
-+      spin_lock_irqsave(&blkif->blk_ring_lock, flags);
-+      /* Place on the response ring for the relevant domain. */
-+      switch (blkif->blk_protocol) {
-+      case BLKIF_PROTOCOL_NATIVE:
-+              memcpy(RING_GET_RESPONSE(&blk_rings->native, blk_rings->native.rsp_prod_pvt),
-+                     &resp, sizeof(resp));
-+              break;
-+      case BLKIF_PROTOCOL_X86_32:
-+              memcpy(RING_GET_RESPONSE(&blk_rings->x86_32, blk_rings->x86_32.rsp_prod_pvt),
-+                     &resp, sizeof(resp));
-+              break;
-+      case BLKIF_PROTOCOL_X86_64:
-+              memcpy(RING_GET_RESPONSE(&blk_rings->x86_64, blk_rings->x86_64.rsp_prod_pvt),
-+                     &resp, sizeof(resp));
-+              break;
-+      default:
-+              BUG();
++      /* Set the PCI DMA mask.  Try all possibilities from our
++       * genuine mask down to 32 bits, because some architectures
++       * (e.g. x86_64 with iommu_sac_force set) will allow 40 bit
++       * masks event though they reject 46 bit masks.
++       */
++      efx->dma_mask = efx->type->max_dma_mask;
++      while (efx->dma_mask > 0x7fffffffUL) {
++              if (pci_dma_supported(pci_dev, efx->dma_mask) &&
++                  ((rc = pci_set_dma_mask(pci_dev, efx->dma_mask)) == 0))
++                      break;
++              efx->dma_mask >>= 1;
 +      }
-+      blk_rings->common.rsp_prod_pvt++;
-+      RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify);
-+      if (blk_rings->common.rsp_prod_pvt == blk_rings->common.req_cons) {
-+              /*
-+               * Tail check for pending requests. Allows frontend to avoid
-+               * notifications if requests are already in flight (lower
-+               * overheads and promotes batching).
++      if (rc) {
++              EFX_ERR(efx, "could not find a suitable DMA mask\n");
++              goto fail2;
++      }
++      EFX_LOG(efx, "using DMA mask %llx\n",
++              (unsigned long long)efx->dma_mask);
++      rc = pci_set_consistent_dma_mask(pci_dev, efx->dma_mask);
++      if (rc) {
++              /* pci_set_consistent_dma_mask() is not *allowed* to
++               * fail with a mask that pci_set_dma_mask() accepted,
++               * but just in case...
 +               */
-+              RING_FINAL_CHECK_FOR_REQUESTS(&blk_rings->common, more_to_do);
++              EFX_ERR(efx, "failed to set consistent DMA mask\n");
++              goto fail2;
++      }
 +
-+      } else if (RING_HAS_UNCONSUMED_REQUESTS(&blk_rings->common)) {
-+              more_to_do = 1;
++      /* Get memory base address */
++      efx->membase_phys = pci_resource_start(efx->pci_dev,
++                                             efx->type->mem_bar);
++#if !defined(EFX_HAVE_MSIX_TABLE_RESERVED)
++      rc = pci_request_region(pci_dev, efx->type->mem_bar, "sfc");
++#else
++      if (!request_mem_region(efx->membase_phys, efx->type->mem_map_size,
++                              "sfc"))
++              rc = -EIO;
++#endif
++      if (rc) {
++              EFX_ERR(efx, "request for memory BAR failed\n");
++              rc = -EIO;
++              goto fail3;
++      }
++      efx->membase = ioremap_nocache(efx->membase_phys,
++                                     efx->type->mem_map_size);
++      if (!efx->membase) {
++              EFX_ERR(efx, "could not map memory BAR %d at %lx+%x\n",
++                      efx->type->mem_bar, efx->membase_phys,
++                      efx->type->mem_map_size);
++              rc = -ENOMEM;
++              goto fail4;
 +      }
++      EFX_LOG(efx, "memory BAR %u at %lx+%x (virtual %p)\n",
++              efx->type->mem_bar, efx->membase_phys, efx->type->mem_map_size,
++              efx->membase);
 +
-+      spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
++      return 0;
 +
-+      if (more_to_do)
-+              blkif_notify_work(blkif);
-+      if (notify)
-+              notify_remote_via_irq(blkif->irq);
++ fail4:
++      release_mem_region(efx->membase_phys, efx->type->mem_map_size);
++ fail3:
++      efx->membase_phys = 0UL;
++      /* fall-thru */
++ fail2:
++      pci_disable_device(efx->pci_dev);
++ fail1:
++      return rc;
 +}
 +
-+static int __init blkif_init(void)
++static void efx_fini_io(struct efx_nic *efx)
 +{
-+      int i, mmap_pages;
-+
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++      EFX_LOG(efx, "shutting down I/O\n");
 +
-+      mmap_pages = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
++      if (efx->membase) {
++              iounmap(efx->membase);
++              efx->membase = NULL;
++      }
 +
-+      pending_reqs          = kmalloc(sizeof(pending_reqs[0]) *
-+                                      blkif_reqs, GFP_KERNEL);
-+      pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
-+                                      mmap_pages, GFP_KERNEL);
-+      pending_pages         = alloc_empty_pages_and_pagevec(mmap_pages);
++      if (efx->membase_phys) {
++#if !defined(EFX_HAVE_MSIX_TABLE_RESERVED)
++              pci_release_region(efx->pci_dev, efx->type->mem_bar);
++#else
++              release_mem_region(efx->membase_phys, efx->type->mem_map_size);
++#endif
++              efx->membase_phys = 0UL;
++      }
 +
-+      if (!pending_reqs || !pending_grant_handles || !pending_pages)
-+              goto out_of_memory;
++      pci_disable_device(efx->pci_dev);
++}
 +
-+      for (i = 0; i < mmap_pages; i++)
-+              pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
++/* Probe the number and type of interrupts we are able to obtain. */
++static int efx_probe_interrupts(struct efx_nic *efx)
++{
++      struct msix_entry xentries[EFX_MAX_CHANNELS];
++      int rc, i;
 +
-+      blkif_interface_init();
++      /* Select number of used RSS queues */
++      /* TODO: Can we react to CPU hotplug? */
++      if (rss_cpus == 0)
++              rss_cpus = num_online_cpus();
 +
-+      memset(pending_reqs, 0, sizeof(pending_reqs));
-+      INIT_LIST_HEAD(&pending_free);
++      efx->rss_queues = 1;
++      if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
++              unsigned int max_channel = efx->type->phys_addr_channels - 1;
 +
-+      for (i = 0; i < blkif_reqs; i++)
-+              list_add_tail(&pending_reqs[i].free_list, &pending_free);
++              BUG_ON(!pci_find_capability(efx->pci_dev, PCI_CAP_ID_MSIX));
++              efx->rss_queues = min(max_channel + 1, rss_cpus);
++              efx->rss_queues = min(efx->rss_queues, EFX_MAX_CHANNELS);
++      }
 +
-+      blkif_xenbus_init();
++      /* Determine how many RSS queues we can use, and mark channels
++       * with the appropriate interrupt state */
++      if (efx->interrupt_mode == EFX_INT_MODE_MSIX) {
++              /* Build MSI request structure */
++              for (i = 0; i < efx->rss_queues; i++)
++                      xentries[i].entry = i;
 +
-+      return 0;
++              /* Request maximum number of MSI interrupts */
++              rc = pci_enable_msix(efx->pci_dev, xentries, efx->rss_queues);
++              if (rc > 0) {
++                      EFX_BUG_ON_PARANOID(rc >= efx->rss_queues);
++                      efx->rss_queues = rc;
++                      rc = pci_enable_msix(efx->pci_dev, xentries,
++                                           efx->rss_queues);
++              }
++              if (rc == 0) {
++                      for (i = 0; i < efx->rss_queues; i++) {
++                              efx->channel[i].has_interrupt = 1;
++                              efx->channel[i].irq = xentries[i].vector;
++                      }
++              } else {
++                      /* Fall back to single channel MSI */
++                      efx->interrupt_mode = EFX_INT_MODE_MSI;
++                      EFX_ERR(efx, "could not enable MSI-X\n");
++              }
++      }
 +
-+ out_of_memory:
-+      kfree(pending_reqs);
-+      kfree(pending_grant_handles);
-+      free_empty_pages_and_pagevec(pending_pages, mmap_pages);
-+      printk("%s: out of memory\n", __FUNCTION__);
-+      return -ENOMEM;
++      /* Try single interrupt MSI */
++      if (efx->interrupt_mode == EFX_INT_MODE_MSI) {
++              efx->rss_queues = 1;
++              rc = pci_enable_msi(efx->pci_dev);
++              if (rc == 0) {
++                      efx->channel[0].irq = efx->pci_dev->irq;
++                      efx->channel[0].has_interrupt = 1;
++              } else {
++                      EFX_ERR(efx, "could not enable MSI\n");
++                      efx->interrupt_mode = EFX_INT_MODE_LEGACY;
++              }
++      }
++
++      /* Assume legacy interrupts */
++      if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) {
++              /* Every channel is interruptible */
++              for (i = 0; i < EFX_MAX_CHANNELS; i++)
++                      efx->channel[i].has_interrupt = 1;
++              efx->legacy_irq = efx->pci_dev->irq;
++      }
++
++      return 0;
 +}
 +
-+module_init(blkif_init);
++static void efx_remove_interrupts(struct efx_nic *efx)
++{
++      struct efx_channel *channel;
 +
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blkback/common.h linux-2.6.18-xen.hg/drivers/xen/blkback/common.h
---- linux-2.6.18/drivers/xen/blkback/common.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blkback/common.h   2007-12-23 11:15:33.541241984 +0100
-@@ -0,0 +1,139 @@
-+/* 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++      /* Remove MSI/MSI-X interrupts */
++      efx_for_each_channel_with_interrupt(channel, efx)
++              channel->irq = 0;
++      pci_disable_msi(efx->pci_dev);
++      pci_disable_msix(efx->pci_dev);
++
++      /* Remove legacy interrupt */
++      efx->legacy_irq = 0;
++}
++
++/* Select number of used resources
++ * Should be called after probe_interrupts()
 + */
++static int efx_select_used(struct efx_nic *efx)
++{
++      struct efx_tx_queue *tx_queue;
++      struct efx_rx_queue *rx_queue;
++      int i;
 +
-+#ifndef __BLKIF__BACKEND__COMMON_H__
-+#define __BLKIF__BACKEND__COMMON_H__
++      /* TX queues.  One per port per channel with TX capability
++       * (more than one per port won't work on Linux, due to out
++       *  of order issues... but will be fine on Solaris)
++       */
++      tx_queue = &efx->tx_queue[0];
 +
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/slab.h>
-+#include <linux/blkdev.h>
-+#include <linux/vmalloc.h>
-+#include <linux/wait.h>
-+#include <asm/io.h>
-+#include <asm/setup.h>
-+#include <asm/pgalloc.h>
-+#include <xen/evtchn.h>
-+#include <asm/hypervisor.h>
-+#include <xen/blkif.h>
-+#include <xen/gnttab.h>
-+#include <xen/driver_util.h>
-+#include <xen/xenbus.h>
++      /* Perform this for each channel with TX capabilities.
++       * At the moment, we only support a single TX queue
++       */
++      tx_queue->used = 1;
++      if ((!EFX_INT_MODE_USE_MSI(efx)) && separate_tx_and_rx_channels)
++              tx_queue->channel = &efx->channel[1];
++      else
++              tx_queue->channel = &efx->channel[0];
++      tx_queue->channel->used_flags |= EFX_USED_BY_TX;
++      tx_queue++;
++
++      /* RX queues.  Each has a dedicated channel. */
++      for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
++              rx_queue = &efx->rx_queue[i];
++
++              if (i < efx->rss_queues) {
++                      rx_queue->used = 1;
++                      /* If we allow multiple RX queues per channel
++                       * we need to decide that here
++                       */
++                      rx_queue->channel = &efx->channel[rx_queue->queue];
++                      rx_queue->channel->used_flags |= EFX_USED_BY_RX;
++                      rx_queue++;
++              }
++      }
++      return 0;
++}
 +
-+#define DPRINTK(_f, _a...)                    \
-+      pr_debug("(file=%s, line=%d) " _f,      \
-+               __FILE__ , __LINE__ , ## _a )
++static int efx_probe_nic(struct efx_nic *efx)
++{
++      int rc;
 +
-+struct vbd {
-+      blkif_vdev_t   handle;      /* what the domain refers to this vbd as */
-+      unsigned char  readonly;    /* Non-zero -> read-only */
-+      unsigned char  type;        /* VDISK_xxx */
-+      u32            pdevice;     /* phys device that this vbd maps to */
-+      struct block_device *bdev;
-+};
++      EFX_LOG(efx, "creating NIC\n");
 +
-+struct backend_info;
++      /* Carry out hardware-type specific initialisation */
++      rc = falcon_probe_nic(efx);
++      if (rc)
++              goto fail1;
 +
-+typedef struct blkif_st {
-+      /* Unique identifier for this interface. */
-+      domid_t           domid;
-+      unsigned int      handle;
-+      /* Physical parameters of the comms window. */
-+      unsigned int      irq;
-+      /* Comms information. */
-+      enum blkif_protocol blk_protocol;
-+      blkif_back_rings_t blk_rings;
-+      struct vm_struct *blk_ring_area;
-+      /* The VBD attached to this interface. */
-+      struct vbd        vbd;
-+      /* Back pointer to the backend_info. */
-+      struct backend_info *be;
-+      /* Private fields. */
-+      spinlock_t       blk_ring_lock;
-+      atomic_t         refcnt;
++      /* Determine the number of channels and RX queues by trying to hook
++       * in MSI-X interrupts. */
++      rc = efx_probe_interrupts(efx);
++      if (rc)
++              goto fail2;
 +
-+      wait_queue_head_t   wq;
-+      struct task_struct  *xenblkd;
-+      unsigned int        waiting_reqs;
-+      request_queue_t     *plug;
++      /* Determine number of RX queues and TX queues */
++      rc = efx_select_used(efx);
++      if (rc)
++              goto fail3;
 +
-+      /* statistics */
-+      unsigned long       st_print;
-+      int                 st_rd_req;
-+      int                 st_wr_req;
-+      int                 st_oo_req;
-+      int                 st_br_req;
-+      int                 st_rd_sect;
-+      int                 st_wr_sect;
++      /* Register debugfs entries */
++      rc = efx_init_debugfs_nic(efx);
++      if (rc)
++              goto fail4;
++      /* Initialise the interrupt moderation settings */
++      efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec);
 +
-+      wait_queue_head_t waiting_to_free;
++      return 0;
 +
-+      grant_handle_t shmem_handle;
-+      grant_ref_t    shmem_ref;
-+} blkif_t;
++ fail4:
++      /* fall-thru */
++ fail3:
++      efx_remove_interrupts(efx);
++ fail2:
++      falcon_remove_nic(efx);
++ fail1:
++      return rc;
++}
 +
-+blkif_t *blkif_alloc(domid_t domid);
-+void blkif_disconnect(blkif_t *blkif);
-+void blkif_free(blkif_t *blkif);
-+int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn);
++static void efx_remove_nic(struct efx_nic *efx)
++{
++      EFX_LOG(efx, "destroying NIC\n");
 +
-+#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
-+#define blkif_put(_b)                                 \
-+      do {                                            \
-+              if (atomic_dec_and_test(&(_b)->refcnt)) \
-+                      wake_up(&(_b)->waiting_to_free);\
-+      } while (0)
++      efx_remove_interrupts(efx);
++      falcon_remove_nic(efx);
 +
-+/* Create a vbd. */
-+int vbd_create(blkif_t *blkif, blkif_vdev_t vdevice, unsigned major,
-+             unsigned minor, int readonly);
-+void vbd_free(struct vbd *vbd);
++      efx_fini_debugfs_nic(efx);
++}
 +
-+unsigned long long vbd_size(struct vbd *vbd);
-+unsigned int vbd_info(struct vbd *vbd);
-+unsigned long vbd_secsize(struct vbd *vbd);
++/**************************************************************************
++ *
++ * NIC startup/shutdown
++ *
++ *************************************************************************/
 +
-+struct phys_req {
-+      unsigned short       dev;
-+      unsigned short       nr_sects;
-+      struct block_device *bdev;
-+      blkif_sector_t       sector_number;
-+};
++static int efx_probe_all(struct efx_nic *efx)
++{
++      struct efx_channel *channel;
++      int rc;
 +
-+int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation);
++      /* Create NIC */
++      rc = efx_probe_nic(efx);
++      if (rc) {
++              EFX_ERR(efx, "failed to create NIC\n");
++              goto fail1;
++      }
 +
-+void blkif_interface_init(void);
++      /* Create port */
++      rc = efx_probe_port(efx);
++      if (rc) {
++              EFX_ERR(efx, "failed to create port\n");
++              goto fail2;
++      }
 +
-+void blkif_xenbus_init(void);
++      /* Create channels */
++      efx_for_each_channel(channel, efx) {
++              rc = efx_probe_channel(channel);
++              if (rc) {
++                      EFX_ERR(efx, "failed to create channel %d\n",
++                              channel->channel);
++                      goto fail3;
++              }
++      }
 +
-+irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
-+int blkif_schedule(void *arg);
++      return 0;
 +
-+int blkback_barrier(struct xenbus_transaction xbt,
-+                  struct backend_info *be, int state);
++ fail3:
++      efx_for_each_channel(channel, efx)
++              efx_remove_channel(channel);
++ fail2:
++      efx_remove_port(efx);
++ fail1:
++      return rc;
++}
 +
-+#endif /* __BLKIF__BACKEND__COMMON_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blkback/interface.c linux-2.6.18-xen.hg/drivers/xen/blkback/interface.c
---- linux-2.6.18/drivers/xen/blkback/interface.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blkback/interface.c        2007-12-23 11:15:33.541241984 +0100
-@@ -0,0 +1,181 @@
-+/******************************************************************************
-+ * arch/xen/drivers/blkif/backend/interface.c
-+ * 
-+ * Block-device interface management.
-+ * 
-+ * Copyright (c) 2004, Keir Fraser
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
++/* Called after previous invocation(s) of efx_stop_all, restarts the
++ * port, kernel transmit queue, NAPI processing and hardware interrupts.
++ * This function is safe to call multiple times when the NIC is in any
++ * state. */
++static void efx_start_all(struct efx_nic *efx)
++{
++      struct efx_channel *channel;
 +
-+#include "common.h"
-+#include <xen/evtchn.h>
-+#include <linux/kthread.h>
++      ASSERT_RTNL();
 +
-+static kmem_cache_t *blkif_cachep;
++      /* Check that it is appropriate to restart the interface. All
++       * of these flags are safe to read under just the rtnl lock */
++      if (efx->port_enabled)
++              return;
++      if ((efx->state != STATE_RUNNING) && (efx->state != STATE_INIT))
++              return;
++      if (efx->net_dev_registered && !netif_running(efx->net_dev))
++              return;
 +
-+blkif_t *blkif_alloc(domid_t domid)
++      /* Mark the port as enabled so port reconfigurations can start, then
++       * restart the transmit interface early so the watchdog timer stops */
++      efx_start_port(efx);
++      efx_wake_queue(efx);
++
++      efx_for_each_channel(channel, efx)
++              efx_start_channel(channel);
++
++      falcon_enable_interrupts(efx);
++
++      /* Start hardware monitor if we're in RUNNING */
++      if (efx->state == STATE_RUNNING)
++              queue_delayed_work(efx->workqueue, &efx->monitor_work,
++                                 efx_monitor_interval);
++}
++
++/* Flush all delayed work. Should only be called when no more delayed work
++ * will be scheduled. This doesn't flush pending online resets (efx_reset),
++ * since we're holding the rtnl_lock at this point. */
++static void efx_flush_all(struct efx_nic *efx)
 +{
-+      blkif_t *blkif;
++#if defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
++      struct efx_rx_queue *rx_queue;
 +
-+      blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
-+      if (!blkif)
-+              return ERR_PTR(-ENOMEM);
++      /* Make sure the hardware monitor is stopped */
++      cancel_delayed_work_sync(&efx->monitor_work);
 +
-+      memset(blkif, 0, sizeof(*blkif));
-+      blkif->domid = domid;
-+      spin_lock_init(&blkif->blk_ring_lock);
-+      atomic_set(&blkif->refcnt, 1);
-+      init_waitqueue_head(&blkif->wq);
-+      blkif->st_print = jiffies;
-+      init_waitqueue_head(&blkif->waiting_to_free);
++      /* Ensure that all RX slow refills are complete. */
++      efx_for_each_rx_queue(rx_queue, efx) {
++              cancel_delayed_work_sync(&rx_queue->work);
++      }
++#endif
 +
-+      return blkif;
++#if defined(EFX_USE_CANCEL_WORK_SYNC)
++      /* Stop scheduled port reconfigurations */
++      cancel_work_sync(&efx->reconfigure_work);
++#endif
++
++#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
++      /* Ensure that the hardware monitor and asynchronous port
++       * reconfigurations are complete, which are the only two consumers
++       * of efx->workqueue. Since the hardware monitor runs on a long period,
++       * we put in some effort to cancel the delayed work safely rather
++       * than just flushing the queue twice (which is guaranteed to flush
++       * all the work since both efx_monitor and efx_reconfigure_work disarm
++       * if !efx->port_enabled. */
++      if (timer_pending(&efx->monitor_work.timer))
++              cancel_delayed_work(&efx->monitor_work);
++      flush_workqueue(efx->workqueue);
++      if (timer_pending(&efx->monitor_work.timer))
++              cancel_delayed_work(&efx->monitor_work);
++      flush_workqueue(efx->workqueue);
++
++      /* efx_rx_work will disarm if !channel->enabled, so we can just
++       * flush the refill workqueue twice as well. */
++      flush_workqueue(efx->refill_workqueue);
++      flush_workqueue(efx->refill_workqueue);
++#endif
 +}
 +
-+static int map_frontend_page(blkif_t *blkif, unsigned long shared_page)
++/* Quiesce hardware and software without bringing the link down.
++ * Safe to call multiple times, when the nic and interface is in any
++ * state. The caller is guaranteed to subsequently be in a position
++ * to modify any hardware and software state they see fit without
++ * taking locks. */
++static void efx_stop_all(struct efx_nic *efx)
 +{
-+      struct gnttab_map_grant_ref op;
++      struct efx_channel *channel;
 +
-+      gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
-+                        GNTMAP_host_map, shared_page, blkif->domid);
++      ASSERT_RTNL();
 +
-+      if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
-+              BUG();
++      /* port_enabled can be read safely under the rtnl lock */
++      if (!efx->port_enabled)
++              return;
 +
-+      if (op.status) {
-+              DPRINTK(" Grant table operation failure !\n");
-+              return op.status;
++      /* Disable interrupts and wait for ISR to complete */
++      falcon_disable_interrupts(efx);
++      if (efx->legacy_irq)
++              synchronize_irq(efx->legacy_irq);
++      efx_for_each_channel_with_interrupt(channel, efx)
++              if (channel->irq)
++                      synchronize_irq(channel->irq);
++
++      /* Stop all synchronous port reconfigurations. */
++      efx_stop_port(efx);
++
++      /* Stop all NAPI processing and synchronous rx refills */
++      efx_for_each_channel(channel, efx)
++              efx_stop_channel(channel);
++
++      /* Flush reconfigure_work, refill_workqueue, monitor_work */
++      efx_flush_all(efx);
++
++      /* Stop the kernel transmit interface late, so the watchdog
++       * timer isn't ticking over the flush */
++      efx_stop_queue(efx);
++      if (efx->net_dev_registered) {
++              netif_tx_lock_bh(efx->net_dev);
++              netif_tx_unlock_bh(efx->net_dev);
 +      }
++}
 +
-+      blkif->shmem_ref = shared_page;
-+      blkif->shmem_handle = op.handle;
++static void efx_remove_all(struct efx_nic *efx)
++{
++      struct efx_channel *channel;
++
++      efx_for_each_channel(channel, efx)
++              efx_remove_channel(channel);
++      efx_remove_port(efx);
++      efx_remove_nic(efx);
++}
++
++static int efx_run_selftests(struct efx_nic *efx)
++{
++      struct efx_self_tests tests;
++      unsigned modes = efx->startup_loopbacks & efx->loopback_modes;
++      int rc;
++
++      rc = efx_online_test(efx, &tests);
++      if (rc) {
++              EFX_ERR(efx, "failed self-tests with interrupt_mode of %s\n",
++                      INT_MODE(efx));
++              goto fail;
++      }
++
++      if (onload_offline_selftest && modes) {
++              /* Run offline self test */
++              EFX_LOG(efx, "performing on-load offline self-tests\n");
++              rc = efx_offline_test(efx, &tests, modes);
++              EFX_LOG(efx, "%s on-load offline self-tests\n",
++                      rc ? "FAILED" : "PASSED");
++              if (rc)
++                      goto fail;
++      }
 +
 +      return 0;
++
++ fail:
++      EFX_ERR(efx, "self-tests failed. Given up!\n");
++      if (allow_load_on_failure)
++              rc = 0;
++
++      return rc;
 +}
 +
-+static void unmap_frontend_page(blkif_t *blkif)
++int efx_flush_queues(struct efx_nic *efx)
 +{
-+      struct gnttab_unmap_grant_ref op;
++      int rc;
 +
-+      gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
-+                          GNTMAP_host_map, blkif->shmem_handle);
++      ASSERT_RTNL();
 +
-+      if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
-+              BUG();
++      efx_stop_all(efx);
++
++      /* We can't just flush the tx queues because the event queues
++       * may contain tx completions from that queue. Just flush everything */
++      efx_fini_channels(efx);
++      rc = efx_init_channels(efx);
++      if (rc) {
++              efx_schedule_reset(efx, RESET_TYPE_DISABLE);
++              return rc;
++      }
++
++      efx_start_all(efx);
++
++      return 0;
 +}
 +
-+int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
++/**************************************************************************
++ *
++ * Interrupt moderation
++ *
++ **************************************************************************/
++
++/* Set interrupt moderation parameters */
++void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs)
 +{
-+      int err;
++      struct efx_tx_queue *tx_queue;
++      struct efx_rx_queue *rx_queue;
 +
-+      /* Already connected through? */
-+      if (blkif->irq)
-+              return 0;
++      ASSERT_RTNL();
 +
-+      if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
-+              return -ENOMEM;
++      efx_for_each_tx_queue(tx_queue, efx)
++              tx_queue->channel->irq_moderation = tx_usecs;
 +
-+      err = map_frontend_page(blkif, shared_page);
-+      if (err) {
-+              free_vm_area(blkif->blk_ring_area);
-+              return err;
++      efx_for_each_rx_queue(rx_queue, efx)
++              rx_queue->channel->irq_moderation = rx_usecs;
++}
++
++/**************************************************************************
++ *
++ * Hardware monitor
++ *
++ **************************************************************************/
++
++/* Run periodically off the general workqueue. Serialised against
++ * efx_reconfigure_port via the mac_lock */
++static void efx_monitor(struct work_struct *data)
++{
++#if !defined(EFX_NEED_WORK_API_WRAPPERS)
++      struct efx_nic *efx = container_of(data, struct efx_nic,
++                                         monitor_work.work);
++#else
++      struct efx_nic *efx = container_of(data, struct efx_nic,
++                                         monitor_work);
++#endif
++      int rc = 0;
++
++      EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
++                raw_smp_processor_id());
++
++
++#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
++      /* Without cancel_delayed_work_sync(), we have to make sure that
++       * we don't rearm when port_enabled == 0 */
++      mutex_lock(&efx->mac_lock);
++      if (!efx->port_enabled) {
++              mutex_unlock(&efx->mac_lock);
++              return;
 +      }
 +
-+      switch (blkif->blk_protocol) {
-+      case BLKIF_PROTOCOL_NATIVE:
-+      {
-+              blkif_sring_t *sring;
-+              sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
-+              BACK_RING_INIT(&blkif->blk_rings.native, sring, PAGE_SIZE);
-+              break;
++      rc = efx->mac_op->check_hw(efx);
++#else
++      /* If the mac_lock is already held then it is likely a port
++       * reconfiguration is already in place, which will likely do
++       * most of the work of check_hw() anyway. */
++      if (!mutex_trylock(&efx->mac_lock)) {
++              queue_delayed_work(efx->workqueue, &efx->monitor_work,
++                                 efx_monitor_interval);
++              return;
 +      }
-+      case BLKIF_PROTOCOL_X86_32:
-+      {
-+              blkif_x86_32_sring_t *sring_x86_32;
-+              sring_x86_32 = (blkif_x86_32_sring_t *)blkif->blk_ring_area->addr;
-+              BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32, PAGE_SIZE);
-+              break;
++
++      if (efx->port_enabled)
++              rc = efx->mac_op->check_hw(efx);
++#endif
++      mutex_unlock(&efx->mac_lock);
++
++      if (rc) {
++              if (monitor_reset) {
++                      EFX_ERR(efx, "hardware monitor detected a fault: "
++                              "triggering reset\n");
++                      efx_schedule_reset(efx, RESET_TYPE_MONITOR);
++              } else {
++                      EFX_ERR(efx, "hardware monitor detected a fault, "
++                              "skipping reset\n");
++              }
 +      }
-+      case BLKIF_PROTOCOL_X86_64:
-+      {
-+              blkif_x86_64_sring_t *sring_x86_64;
-+              sring_x86_64 = (blkif_x86_64_sring_t *)blkif->blk_ring_area->addr;
-+              BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64, PAGE_SIZE);
++
++      queue_delayed_work(efx->workqueue, &efx->monitor_work,
++                         efx_monitor_interval);
++}
++
++/**************************************************************************
++ *
++ * ioctls
++ *
++ *************************************************************************/
++
++/* Net device ioctl
++ * Context: process, rtnl_lock() held.
++ */
++static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
++{
++      struct efx_nic *efx = net_dev->priv;
++      int rc;
++
++      ASSERT_RTNL();
++
++      switch (cmd) {
++      case SIOCGMIIPHY:
++      case SIOCGMIIREG:
++              rc = generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL);
++              break;
++      case SIOCSMIIREG:
++              rc = generic_mii_ioctl(&efx->mii, if_mii(ifr), cmd, NULL);
++              efx_reconfigure_port(efx, 0);
 +              break;
-+      }
 +      default:
-+              BUG();
++              rc = -EOPNOTSUPP;
 +      }
 +
-+      err = bind_interdomain_evtchn_to_irqhandler(
-+              blkif->domid, evtchn, blkif_be_int, 0, "blkif-backend", blkif);
-+      if (err < 0)
-+      {
-+              unmap_frontend_page(blkif);
-+              free_vm_area(blkif->blk_ring_area);
-+              blkif->blk_rings.common.sring = NULL;
-+              return err;
++      return rc;
++}
++
++/**************************************************************************
++ *
++ * NAPI interface
++ *
++ **************************************************************************/
++
++/* Allocate the NAPI dev's.
++ * Called after we know how many channels there are.
++ */
++static int efx_init_napi(struct efx_nic *efx)
++{
++      struct efx_channel *channel;
++      int rc;
++
++      ASSERT_RTNL();
++
++      /* Allocate the NAPI dev for the port */
++      efx->net_dev = alloc_etherdev(0);
++      if (!efx->net_dev) {
++              rc = -ENOMEM;
++              goto err;
++      }
++      efx->net_dev->priv = efx;
++      efx->mii.dev = efx->net_dev;
++
++      /* Set features based on module parameters and DMA mask.
++       * Enable DMA to ZONE_HIGHMEM if the NIC can access all memory
++       * directly.  This only has an effect on 32-bit systems and
++       * PAE on x86 limits memory to 64GB so 40 bits is plenty to
++       * address everything.  If the device can't address 40 bits
++       * then it's safest to turn NETIF_F_HIGHDMA off because this
++       * might be a PAE system with more than 4G of RAM and a 32-bit
++       * NIC.  The use of EFX_DMA_MASK is to eliminate compiler
++       * warnings on platforms where dma_addr_t is 32-bit.  We
++       * assume that in those cases we can access all memory
++       * directly if our DMA mask is all ones. */
++      efx->net_dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
++      if (efx->dma_mask >= EFX_DMA_MASK(DMA_40BIT_MASK))
++              efx->net_dev->features |= NETIF_F_HIGHDMA;
++
++      /* Copy MAC address */
++      memcpy(&efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN);
++
++      /* Allocate the per channel devs */
++      efx_for_each_channel(channel, efx) {
++#if !defined(EFX_HAVE_OLD_NAPI)
++              channel->napi_dev = efx->net_dev;
++#else
++              channel->napi_dev = alloc_etherdev(0);
++              if (!channel->napi_dev) {
++                      rc = -ENOMEM;
++                      goto err;
++              }
++              channel->napi_dev->priv = channel;
++              atomic_set(&channel->napi_dev->refcnt, 1);
++#endif
 +      }
-+      blkif->irq = err;
 +
 +      return 0;
++ err:
++      efx_fini_napi(efx);
++      return rc;
 +}
 +
-+void blkif_disconnect(blkif_t *blkif)
++/* Free the NAPI state for the port and channels */
++static void efx_fini_napi(struct efx_nic *efx)
 +{
-+      if (blkif->xenblkd) {
-+              kthread_stop(blkif->xenblkd);
-+              blkif->xenblkd = NULL;
-+      }
++      struct efx_channel *channel;
 +
-+      atomic_dec(&blkif->refcnt);
-+      wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
-+      atomic_inc(&blkif->refcnt);
++      ASSERT_RTNL();
 +
-+      if (blkif->irq) {
-+              unbind_from_irqhandler(blkif->irq, blkif);
-+              blkif->irq = 0;
++      efx_for_each_channel(channel, efx) {
++              /* Finish per channel NAPI */
++#if defined(EFX_HAVE_OLD_NAPI)
++              if (channel->napi_dev) {
++                      channel->napi_dev->priv = NULL;
++                      free_netdev(channel->napi_dev);
++              }
++#endif
++              channel->napi_dev = NULL;
 +      }
 +
-+      if (blkif->blk_rings.common.sring) {
-+              unmap_frontend_page(blkif);
-+              free_vm_area(blkif->blk_ring_area);
-+              blkif->blk_rings.common.sring = NULL;
++      /* Finish port NAPI */
++      if (efx->net_dev) {
++              efx->net_dev->priv = NULL;
++              free_netdev(efx->net_dev);
++              efx->net_dev = NULL;
 +      }
 +}
 +
-+void blkif_free(blkif_t *blkif)
++/**************************************************************************
++ *
++ * Kernel netpoll interface
++ *
++ *************************************************************************/
++
++#ifdef CONFIG_NET_POLL_CONTROLLER
++
++/* Although in the common case interrupts will be disabled, this is not
++ * guaranteed. However, all our work happens inside the NAPI callback,
++ * so no locking is required.
++ */
++static void efx_netpoll(struct net_device *net_dev)
 +{
-+      if (!atomic_dec_and_test(&blkif->refcnt))
-+              BUG();
-+      kmem_cache_free(blkif_cachep, blkif);
++      struct efx_nic *efx = net_dev->priv;
++      struct efx_channel *channel;
++
++      efx_for_each_channel_with_interrupt(channel, efx)
++              efx_schedule_channel(channel);
 +}
 +
-+void __init blkif_interface_init(void)
++#endif
++
++/**************************************************************************
++ *
++ * Kernel net device interface
++ *
++ *************************************************************************/
++
++/* Context: process, rtnl_lock() held. */
++static int efx_net_open(struct net_device *net_dev)
 +{
-+      blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t), 
-+                                       0, 0, NULL, NULL);
++      struct efx_nic *efx = net_dev->priv;
++      ASSERT_RTNL();
++
++      EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name,
++              raw_smp_processor_id());
++      efx_start_all(efx);
++      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blkback/Makefile linux-2.6.18-xen.hg/drivers/xen/blkback/Makefile
---- linux-2.6.18/drivers/xen/blkback/Makefile  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blkback/Makefile   2007-12-23 11:15:33.541241984 +0100
-@@ -0,0 +1,3 @@
-+obj-$(CONFIG_XEN_BLKDEV_BACKEND) := blkbk.o
 +
-+blkbk-y       := blkback.o xenbus.o interface.o vbd.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blkback/vbd.c linux-2.6.18-xen.hg/drivers/xen/blkback/vbd.c
---- linux-2.6.18/drivers/xen/blkback/vbd.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blkback/vbd.c      2007-12-23 11:15:33.541241984 +0100
-@@ -0,0 +1,118 @@
-+/******************************************************************************
-+ * blkback/vbd.c
-+ * 
-+ * Routines for managing virtual block devices (VBDs).
-+ * 
-+ * Copyright (c) 2003-2005, Keir Fraser & Steve Hand
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++/* Context: process, rtnl_lock() held.
++ * Note that the kernel will ignore our return code; this method
++ * should really be a void.
 + */
++static int efx_net_stop(struct net_device *net_dev)
++{
++      struct efx_nic *efx = net_dev->priv;
++      int rc;
 +
-+#include "common.h"
++      EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name,
++              raw_smp_processor_id());
 +
-+#define vbd_sz(_v)   ((_v)->bdev->bd_part ?                           \
-+      (_v)->bdev->bd_part->nr_sects : (_v)->bdev->bd_disk->capacity)
++      /* Stop device and flush all the channels */
++      efx_stop_all(efx);
++      efx_fini_channels(efx);
++      rc = efx_init_channels(efx);
++      if (rc)
++              efx_schedule_reset(efx, RESET_TYPE_DISABLE);
 +
-+unsigned long long vbd_size(struct vbd *vbd)
-+{
-+      return vbd_sz(vbd);
++      return 0;
 +}
 +
-+unsigned int vbd_info(struct vbd *vbd)
++/* Context: process, dev_base_lock held, non-blocking.
++ * Statistics are taken directly from the MAC.
++ */
++static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
 +{
-+      return vbd->type | (vbd->readonly?VDISK_READONLY:0);
++      struct efx_nic *efx = net_dev->priv;
++      struct efx_mac_stats *mac_stats = &efx->mac_stats;
++      struct net_device_stats *stats = &efx->stats;
++
++      if (!spin_trylock(&efx->stats_lock))
++              return stats;
++      if (efx->state == STATE_RUNNING)
++              efx->mac_op->update_stats(efx);
++      spin_unlock(&efx->stats_lock);
++
++      stats->rx_packets = mac_stats->rx_packets;
++      stats->tx_packets = mac_stats->tx_packets;
++      stats->rx_bytes = mac_stats->rx_bytes;
++      stats->tx_bytes = mac_stats->tx_bytes;
++      stats->tx_errors = mac_stats->tx_bad;
++      stats->multicast = mac_stats->rx_multicast;
++      stats->collisions = mac_stats->tx_collision;
++      stats->rx_length_errors = mac_stats->rx_gtjumbo;
++      stats->rx_over_errors = mac_stats->rx_overflow;
++      stats->rx_crc_errors = mac_stats->rx_bad;
++      stats->rx_frame_errors = mac_stats->rx_align_error;
++      stats->rx_fifo_errors = 0;
++      stats->rx_missed_errors = mac_stats->rx_missed;
++      stats->rx_errors = (stats->rx_length_errors +
++                          stats->rx_over_errors +
++                          stats->rx_crc_errors +
++                          stats->rx_frame_errors +
++                          stats->rx_fifo_errors +
++                          stats->rx_missed_errors +
++                          mac_stats->rx_symbol_error);
++      stats->tx_aborted_errors = 0;
++      stats->tx_carrier_errors = 0;
++      stats->tx_fifo_errors = 0;
++      stats->tx_heartbeat_errors = 0;
++      stats->tx_window_errors = 0;
++
++      return stats;
 +}
 +
-+unsigned long vbd_secsize(struct vbd *vbd)
++/* Context: netif_tx_lock held, BHs disabled. */
++static void efx_watchdog(struct net_device *net_dev)
 +{
-+      return bdev_hardsect_size(vbd->bdev);
++      struct efx_nic *efx = net_dev->priv;
++
++      EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n",
++              atomic_read(&efx->netif_stop_count), efx->port_enabled,
++              monitor_reset ? "resetting channels" : "skipping reset");
++
++      if (monitor_reset)
++              efx_schedule_reset(efx, RESET_TYPE_MONITOR);
 +}
 +
-+int vbd_create(blkif_t *blkif, blkif_vdev_t handle, unsigned major,
-+             unsigned minor, int readonly)
++
++/* Context: process, rtnl_lock() held. */
++static int efx_change_mtu(struct net_device *net_dev, int new_mtu)
 +{
-+      struct vbd *vbd;
-+      struct block_device *bdev;
++      struct efx_nic *efx = net_dev->priv;
++      int rc = 0;
 +
-+      vbd = &blkif->vbd;
-+      vbd->handle   = handle; 
-+      vbd->readonly = readonly;
-+      vbd->type     = 0;
++      ASSERT_RTNL();
 +
-+      vbd->pdevice  = MKDEV(major, minor);
++      if (new_mtu > EFX_MAX_MTU)
++              return -EINVAL;
 +
-+      bdev = open_by_devnum(vbd->pdevice,
-+                            vbd->readonly ? FMODE_READ : FMODE_WRITE);
++      efx_stop_all(efx);
 +
-+      if (IS_ERR(bdev)) {
-+              DPRINTK("vbd_creat: device %08x could not be opened.\n",
-+                      vbd->pdevice);
-+              return -ENOENT;
++      /* Ask driverlink client if we can change MTU */
++      rc = EFX_DL_CALLBACK(efx, request_mtu, new_mtu);
++      if (rc) {
++              EFX_ERR(efx, "MTU change vetoed by driverlink %s driver\n",
++                      efx->dl_cb_dev.request_mtu->driver->name);
++              goto out;
 +      }
 +
-+      vbd->bdev = bdev;
++      EFX_LOG(efx, "changing MTU to %d\n", new_mtu);
 +
-+      if (vbd->bdev->bd_disk == NULL) {
-+              DPRINTK("vbd_creat: device %08x doesn't exist.\n",
-+                      vbd->pdevice);
-+              vbd_free(vbd);
-+              return -ENOENT;
-+      }
++      efx_fini_channels(efx);
++      net_dev->mtu = new_mtu;
++      rc = efx_init_channels(efx);
++      if (rc)
++              goto fail;
 +
-+      if (vbd->bdev->bd_disk->flags & GENHD_FL_CD)
-+              vbd->type |= VDISK_CDROM;
-+      if (vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE)
-+              vbd->type |= VDISK_REMOVABLE;
++      /* Reconfigure the MAC */
++      efx_reconfigure_port(efx, 1);
 +
-+      DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
-+              handle, blkif->domid);
-+      return 0;
++      /* Notify driverlink client of new MTU */
++      EFX_DL_CALLBACK(efx, mtu_changed, new_mtu);
++
++      efx_start_all(efx);
++
++ out:
++      return rc;
++
++ fail:
++      efx_schedule_reset(efx, RESET_TYPE_DISABLE);
++      return rc;
 +}
 +
-+void vbd_free(struct vbd *vbd)
++static int efx_set_mac_address(struct net_device *net_dev, void *data)
 +{
-+      if (vbd->bdev)
-+              blkdev_put(vbd->bdev);
-+      vbd->bdev = NULL;
++      struct efx_nic *efx = net_dev->priv;
++      struct sockaddr *addr = data;
++      char *new_addr = addr->sa_data;
++
++      ASSERT_RTNL();
++
++      if (!is_valid_ether_addr(new_addr)) {
++              DECLARE_MAC_BUF(mac);
++              EFX_ERR(efx, "invalid ethernet MAC address requested: %s\n",
++                      print_mac(mac, new_addr));
++              return -EINVAL;
++      }
++
++      memcpy(net_dev->dev_addr, new_addr, net_dev->addr_len);
++
++      /* Reconfigure the MAC */
++      efx_reconfigure_port(efx, 1);
++
++      return 0;
 +}
 +
-+int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation)
++/* Context: netif_tx_lock held, BHs disabled. */
++static void efx_set_multicast_list(struct net_device *net_dev)
 +{
-+      struct vbd *vbd = &blkif->vbd;
-+      int rc = -EACCES;
-+
-+      if ((operation != READ) && vbd->readonly)
-+              goto out;
++      struct efx_nic *efx = net_dev->priv;
++      struct dev_mc_list *mc_list = net_dev->mc_list;
++      union efx_multicast_hash *mc_hash = &efx->multicast_hash;
++      unsigned long flags __attribute__ ((unused));
++      int promiscuous;
++      u32 crc;
++      int bit;
++      int i;
 +
-+      if (unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd)))
-+              goto out;
++      /* Set per-MAC promiscuity flag and reconfigure MAC if necessary */
++      promiscuous = (net_dev->flags & IFF_PROMISC) ? 1 : 0;
++      if (efx->promiscuous != promiscuous) {
++              if (efx->port_enabled) {
++                      efx->promiscuous = promiscuous;
++                      queue_work(efx->workqueue, &efx->reconfigure_work);
++              }
++      }
 +
-+      req->dev  = vbd->pdevice;
-+      req->bdev = vbd->bdev;
-+      rc = 0;
++      /* Build multicast hash table */
++      if (promiscuous || (net_dev->flags & IFF_ALLMULTI)) {
++              memset(mc_hash, 0xff, sizeof(*mc_hash));
++      } else {
++              memset(mc_hash, 0x00, sizeof(*mc_hash));
++              for (i = 0; i < net_dev->mc_count; i++) {
++                      crc = ether_crc_le(ETH_ALEN, mc_list->dmi_addr);
++                      bit = (crc & ((1 << EFX_MCAST_HASH_BITS) - 1));
++                      set_bit_le(bit, (void *)mc_hash);
++                      mc_list = mc_list->next;
++              }
++      }
 +
-+ out:
-+      return rc;
++      /* Create and activate new global multicast hash table */
++      falcon_set_multicast_hash(efx);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blkback/xenbus.c linux-2.6.18-xen.hg/drivers/xen/blkback/xenbus.c
---- linux-2.6.18/drivers/xen/blkback/xenbus.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blkback/xenbus.c   2007-12-23 11:15:33.544575492 +0100
-@@ -0,0 +1,533 @@
-+/*  Xenbus code for blkif backend
-+    Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
-+    Copyright (C) 2005 XenSource Ltd
 +
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 2 of the License, or
-+    (at your option) any later version.
++/* Handle net device notifier events */
++static int efx_netdev_event(struct notifier_block *this,
++                          unsigned long event, void *ptr)
++{
++      struct net_device *net_dev = (struct net_device *)ptr;
 +
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
++      if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) {
++              struct efx_nic *efx = net_dev->priv;
 +
-+    You should have received a copy of the GNU General Public License
-+    along with this program; if not, write to the Free Software
-+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-+*/
++              strcpy(efx->name, net_dev->name);
++              efx_fini_debugfs_netdev(net_dev);
++              efx_init_debugfs_netdev(net_dev);
++      }
 +
-+#include <stdarg.h>
-+#include <linux/module.h>
-+#include <linux/kthread.h>
-+#include "common.h"
++      return NOTIFY_DONE;
++}
 +
-+#undef DPRINTK
-+#define DPRINTK(fmt, args...)                         \
-+      pr_debug("blkback/xenbus (%s:%d) " fmt ".\n",   \
-+               __FUNCTION__, __LINE__, ##args)
++static struct notifier_block efx_netdev_notifier = {
++      .notifier_call = efx_netdev_event,
++};
 +
-+struct backend_info
++static int efx_register_netdev(struct efx_nic *efx)
 +{
-+      struct xenbus_device *dev;
-+      blkif_t *blkif;
-+      struct xenbus_watch backend_watch;
-+      unsigned major;
-+      unsigned minor;
-+      char *mode;
-+};
++      struct net_device *net_dev = efx->net_dev;
++      int rc;
 +
-+static void connect(struct backend_info *);
-+static int connect_ring(struct backend_info *);
-+static void backend_changed(struct xenbus_watch *, const char **,
-+                          unsigned int);
++      net_dev->watchdog_timeo = 5 * HZ;
++      net_dev->irq = efx->pci_dev->irq;
++      net_dev->open = efx_net_open;
++      net_dev->stop = efx_net_stop;
++      net_dev->get_stats = efx_net_stats;
++      net_dev->tx_timeout = &efx_watchdog;
++      net_dev->hard_start_xmit = efx_hard_start_xmit;
++      net_dev->do_ioctl = efx_ioctl;
++      net_dev->change_mtu = efx_change_mtu;
++      net_dev->set_mac_address = efx_set_mac_address;
++      net_dev->set_multicast_list = efx_set_multicast_list;
++#ifdef CONFIG_NET_POLL_CONTROLLER
++      net_dev->poll_controller = efx_netpoll;
++#endif
++      SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev);
++      SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops);
++
++      /* Always start with carrier off; PHY events will detect the link */
++      netif_carrier_off(efx->net_dev);
++
++      BUG_ON(efx->net_dev_registered);
++
++      /* Clear MAC statistics */
++      efx->mac_op->update_stats(efx);
++      memset(&efx->mac_stats, 0, sizeof(efx->mac_stats));
++
++      rc = register_netdev(net_dev);
++      if (rc) {
++              EFX_ERR(efx, "could not register net dev\n");
++              return rc;
++      }
++      strcpy(efx->name, net_dev->name);
 +
-+static int blkback_name(blkif_t *blkif, char *buf)
-+{
-+      char *devpath, *devname;
-+      struct xenbus_device *dev = blkif->be->dev;
++      /* Create debugfs symlinks */
++      rc = efx_init_debugfs_netdev(net_dev);
++      if (rc) {
++              EFX_ERR(efx, "failed to init net dev debugfs\n");
++              unregister_netdev(efx->net_dev);
++              return rc;
++      }
 +
-+      devpath = xenbus_read(XBT_NIL, dev->nodename, "dev", NULL);
-+      if (IS_ERR(devpath)) 
-+              return PTR_ERR(devpath);
-+      
-+      if ((devname = strstr(devpath, "/dev/")) != NULL)
-+              devname += strlen("/dev/");
-+      else
-+              devname  = devpath;
++      /* Allow link change notifications to be sent to the operating
++       * system.  The must happen after register_netdev so that
++       * there are no outstanding link changes if that call fails.
++       * It must happen before efx_reconfigure_port so that the
++       * initial state of the link is reported. */
++      mutex_lock(&efx->mac_lock);
++      efx->net_dev_registered = 1;
++      mutex_unlock(&efx->mac_lock);
++
++      /* Safety net: in case we don't get a PHY event */
++      rtnl_lock();
++      efx_reconfigure_port(efx, 1);
++      rtnl_unlock();
++
++      EFX_LOG(efx, "registered\n");
 +
-+      snprintf(buf, TASK_COMM_LEN, "blkback.%d.%s", blkif->domid, devname);
-+      kfree(devpath);
-+      
 +      return 0;
 +}
 +
-+static void update_blkif_status(blkif_t *blkif)
-+{ 
-+      int err;
-+      char name[TASK_COMM_LEN];
++static void efx_unregister_netdev(struct efx_nic *efx)
++{
++      int was_registered = efx->net_dev_registered;
++      struct efx_tx_queue *tx_queue;
 +
-+      /* Not ready to connect? */
-+      if (!blkif->irq || !blkif->vbd.bdev)
++      if (!efx->net_dev)
 +              return;
 +
-+      /* Already connected? */
-+      if (blkif->be->dev->state == XenbusStateConnected)
-+              return;
++      BUG_ON(efx->net_dev->priv != efx);
 +
-+      /* Attempt to connect: exit if we fail to. */
-+      connect(blkif->be);
-+      if (blkif->be->dev->state != XenbusStateConnected)
-+              return;
++      /* SFC Bug 5356: Ensure that no more link status notifications get
++       * sent to the stack.  Bad things happen if there's an
++       * outstanding notification after the net device is freed, but
++       * they only get flushed out by unregister_netdev, not by
++       * free_netdev. */
++      mutex_lock(&efx->mac_lock);
++      efx->net_dev_registered = 0;
++      mutex_unlock(&efx->mac_lock);
 +
-+      err = blkback_name(blkif, name);
-+      if (err) {
-+              xenbus_dev_error(blkif->be->dev, err, "get blkback dev name");
-+              return;
-+      }
++      /* Free up any skbs still remaining. This has to happen before
++       * we try to unregister the netdev as running their destructors
++       * may be needed to get the device ref. count to 0. */
++      efx_for_each_tx_queue(tx_queue, efx)
++              efx_release_tx_buffers(tx_queue);
 +
-+      blkif->xenblkd = kthread_run(blkif_schedule, blkif, name);
-+      if (IS_ERR(blkif->xenblkd)) {
-+              err = PTR_ERR(blkif->xenblkd);
-+              blkif->xenblkd = NULL;
-+              xenbus_dev_error(blkif->be->dev, err, "start xenblkd");
++      if (was_registered) {
++              strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name));
++              efx_fini_debugfs_netdev(efx->net_dev);
++              unregister_netdev(efx->net_dev);
 +      }
 +}
 +
++/**************************************************************************
++ *
++ * Device reset and suspend
++ *
++ **************************************************************************/
 +
-+/****************************************************************
-+ *  sysfs interface for VBD I/O requests
++/* This suspends the device (and acquires the suspend lock) without
++ * flushing the descriptor queues.  It is included for the convenience
++ * of the driverlink layer.
 + */
++void efx_suspend(struct efx_nic *efx)
++{
++      EFX_LOG(efx, "suspending operations\n");
 +
-+#define VBD_SHOW(name, format, args...)                                       \
-+      static ssize_t show_##name(struct device *_dev,                 \
-+                                 struct device_attribute *attr,       \
-+                                 char *buf)                           \
-+      {                                                               \
-+              struct xenbus_device *dev = to_xenbus_device(_dev);     \
-+              struct backend_info *be = dev->dev.driver_data;         \
-+                                                                      \
-+              return sprintf(buf, format, ##args);                    \
-+      }                                                               \
-+      static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
++      down(&efx->suspend_lock);
 +
-+VBD_SHOW(oo_req,  "%d\n", be->blkif->st_oo_req);
-+VBD_SHOW(rd_req,  "%d\n", be->blkif->st_rd_req);
-+VBD_SHOW(wr_req,  "%d\n", be->blkif->st_wr_req);
-+VBD_SHOW(br_req,  "%d\n", be->blkif->st_br_req);
-+VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect);
-+VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect);
++      rtnl_lock();
++      efx_stop_all(efx);
++}
 +
-+static struct attribute *vbdstat_attrs[] = {
-+      &dev_attr_oo_req.attr,
-+      &dev_attr_rd_req.attr,
-+      &dev_attr_wr_req.attr,
-+      &dev_attr_br_req.attr,
-+      &dev_attr_rd_sect.attr,
-+      &dev_attr_wr_sect.attr,
-+      NULL
-+};
++void efx_resume(struct efx_nic *efx)
++{
++      EFX_LOG(efx, "resuming operations\n");
 +
-+static struct attribute_group vbdstat_group = {
-+      .name = "statistics",
-+      .attrs = vbdstat_attrs,
-+};
++      efx_start_all(efx);
++      rtnl_unlock();
 +
-+VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor);
-+VBD_SHOW(mode, "%s\n", be->mode);
++      up(&efx->suspend_lock);
++}
 +
-+int xenvbd_sysfs_addif(struct xenbus_device *dev)
++/* The final hardware and software finalisation before reset.
++ * This function does not handle serialisation with the kernel, it
++ * assumes the caller has done this */
++static int efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 +{
-+      int error;
-+      
-+      error = device_create_file(&dev->dev, &dev_attr_physical_device);
-+      if (error)
-+              goto fail1;
++      int rc;
 +
-+      error = device_create_file(&dev->dev, &dev_attr_mode);
-+      if (error)
-+              goto fail2;
++      ASSERT_RTNL();
 +
-+      error = sysfs_create_group(&dev->dev.kobj, &vbdstat_group);
-+      if (error)
-+              goto fail3;
++      rc = efx->mac_op->get_settings(efx, ecmd);
++      if (rc) {
++              EFX_ERR(efx, "could not back up PHY settings\n");
++              goto fail;
++      }
 +
++      efx_fini_channels(efx);
 +      return 0;
 +
-+fail3:        sysfs_remove_group(&dev->dev.kobj, &vbdstat_group);
-+fail2:        device_remove_file(&dev->dev, &dev_attr_mode);
-+fail1:        device_remove_file(&dev->dev, &dev_attr_physical_device);
-+      return error;
-+}
-+
-+void xenvbd_sysfs_delif(struct xenbus_device *dev)
-+{
-+      sysfs_remove_group(&dev->dev.kobj, &vbdstat_group);
-+      device_remove_file(&dev->dev, &dev_attr_mode);
-+      device_remove_file(&dev->dev, &dev_attr_physical_device);
++ fail:
++      return rc;
 +}
 +
-+static int blkback_remove(struct xenbus_device *dev)
++/* The first part of software initialisation after a hardware reset
++ * This function does not handle serialisation with the kernel, it
++ * assumes the caller has done this */
++static int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 +{
-+      struct backend_info *be = dev->dev.driver_data;
-+
-+      DPRINTK("");
++      int rc;
 +
-+      if (be->major || be->minor)
-+              xenvbd_sysfs_delif(dev);
++      rc = efx_init_channels(efx);
++      if (rc)
++              goto fail1;
 +
-+      if (be->backend_watch.node) {
-+              unregister_xenbus_watch(&be->backend_watch);
-+              kfree(be->backend_watch.node);
-+              be->backend_watch.node = NULL;
-+      }
++      /* In an INVISIBLE_RESET there might not be a link state transition,
++       * so we push the multicast list here. */
++      falcon_set_multicast_hash(efx);
 +
-+      if (be->blkif) {
-+              blkif_disconnect(be->blkif);
-+              vbd_free(&be->blkif->vbd);
-+              blkif_free(be->blkif);
-+              be->blkif = NULL;
++      /* Restore MAC and PHY settings. */
++      rc = efx->mac_op->set_settings(efx, ecmd);
++      if (rc) {
++              EFX_ERR(efx, "could not restore PHY settings\n");
++              goto fail2;
 +      }
 +
-+      kfree(be);
-+      dev->dev.driver_data = NULL;
 +      return 0;
-+}
-+
-+int blkback_barrier(struct xenbus_transaction xbt,
-+                  struct backend_info *be, int state)
-+{
-+      struct xenbus_device *dev = be->dev;
-+      int err;
-+
-+      err = xenbus_printf(xbt, dev->nodename, "feature-barrier",
-+                          "%d", state);
-+      if (err)
-+              xenbus_dev_fatal(dev, err, "writing feature-barrier");
 +
-+      return err;
++ fail2:
++      efx_fini_channels(efx);
++ fail1:
++      return rc;
 +}
 +
-+/**
-+ * Entry point to this code when a new device is created.  Allocate the basic
-+ * structures, and watch the store waiting for the hotplug scripts to tell us
-+ * the device's physical major and minor numbers.  Switch to InitWait.
++/* Reset the NIC as transparently as possible. Do not reset the PHY
++ * Note that the reset may fail, in which case the card will be left
++ * in a most-probably-unusable state.
++ *
++ * This function will sleep.  You cannot reset from within an atomic
++ * state; use efx_schedule_reset() instead.
 + */
-+static int blkback_probe(struct xenbus_device *dev,
-+                       const struct xenbus_device_id *id)
++static int efx_reset(struct efx_nic *efx)
 +{
-+      int err;
-+      struct backend_info *be = kzalloc(sizeof(struct backend_info),
-+                                        GFP_KERNEL);
-+      if (!be) {
-+              xenbus_dev_fatal(dev, -ENOMEM,
-+                               "allocating backend structure");
-+              return -ENOMEM;
++      struct ethtool_cmd ecmd;
++      unsigned long flags __attribute__ ((unused));
++      enum reset_type method = efx->reset_pending;
++      int rc;
++
++      efx_dl_reset_lock();
++
++      rc = down_interruptible(&efx->suspend_lock);
++      if (rc) {
++              EFX_ERR(efx, "reset aborted by signal\n");
++              goto unlock_dl_lock;
 +      }
-+      be->dev = dev;
-+      dev->dev.driver_data = be;
 +
-+      be->blkif = blkif_alloc(dev->otherend_id);
-+      if (IS_ERR(be->blkif)) {
-+              err = PTR_ERR(be->blkif);
-+              be->blkif = NULL;
-+              xenbus_dev_fatal(dev, err, "creating block interface");
-+              goto fail;
++      /* We've got suspend_lock, which means we can only be in
++       * STATE_RUNNING or STATE_FINI. Don't clear
++       * efx->reset_pending, since this flag indicates that we
++       * should retry device initialisation.
++       */
++      if (efx->state != STATE_RUNNING) {
++              EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n");
++              goto unlock_suspend_lock;
 +      }
 +
-+      /* setup back pointer */
-+      be->blkif->be = be;
++      /* Notify driverlink clients of imminent reset. */
++      efx_dl_reset_suspend(efx);
++      rtnl_lock();
 +
-+      err = xenbus_watch_path2(dev, dev->nodename, "physical-device",
-+                               &be->backend_watch, backend_changed);
-+      if (err)
-+              goto fail;
++      efx->state = STATE_RESETTING;
++      EFX_INFO(efx, "resetting (%s)\n", RESET_TYPE(method));
 +
-+      err = xenbus_switch_state(dev, XenbusStateInitWait);
-+      if (err)
-+              goto fail;
++      /* The net_dev->get_stats handler is quite slow, and will fail
++       * if a fetch is pending over reset. Serialise against it. */
++      spin_lock(&efx->stats_lock);
++      spin_unlock(&efx->stats_lock);
 +
-+      return 0;
++      efx_stop_all(efx);
++      mutex_lock(&efx->mac_lock);
 +
-+fail:
-+      DPRINTK("failed");
-+      blkback_remove(dev);
-+      return err;
-+}
++      rc = efx_reset_down(efx, &ecmd);
++      if (rc)
++              goto fail1;
++      falcon_fini_nic(efx);
 +
++      rc = falcon_reset_hw(efx, method);
++      if (rc) {
++              EFX_ERR(efx, "failed to reset hardware\n");
++              goto fail2;
++      }
 +
-+/**
-+ * Callback received when the hotplug scripts have placed the physical-device
-+ * node.  Read it and the mode node, and create a vbd.  If the frontend is
-+ * ready, connect.
-+ */
-+static void backend_changed(struct xenbus_watch *watch,
-+                          const char **vec, unsigned int len)
-+{
-+      int err;
-+      unsigned major;
-+      unsigned minor;
-+      struct backend_info *be
-+              = container_of(watch, struct backend_info, backend_watch);
-+      struct xenbus_device *dev = be->dev;
++      /* Allow resets to be rescheduled. */
++      efx->reset_pending = RESET_TYPE_NONE;
 +
-+      DPRINTK("");
++      /* Reinitialise bus-mastering, which may have been turned off before
++       * the reset was scheduled. This is still appropriate, even in the
++       * RESET_TYPE_DISABLE since this driver generally assumes the hardware
++       * can respond to requests. */
++      pci_set_master(efx->pci_dev);
 +
-+      err = xenbus_scanf(XBT_NIL, dev->nodename, "physical-device", "%x:%x",
-+                         &major, &minor);
-+      if (XENBUS_EXIST_ERR(err)) {
-+              /* Since this watch will fire once immediately after it is
-+                 registered, we expect this.  Ignore it, and wait for the
-+                 hotplug scripts. */
-+              return;
-+      }
-+      if (err != 2) {
-+              xenbus_dev_fatal(dev, err, "reading physical-device");
-+              return;
++      /* Reinitialise device. This is appropriate in the RESET_TYPE_DISABLE
++       * case so the driver can talk to external SRAM */
++      rc = falcon_init_nic(efx);
++      if (rc) {
++              EFX_ERR(efx, "failed to initialise NIC\n");
++              goto fail3;
 +      }
 +
-+      if ((be->major || be->minor) &&
-+          ((be->major != major) || (be->minor != minor))) {
-+              printk(KERN_WARNING
-+                     "blkback: changing physical device (from %x:%x to "
-+                     "%x:%x) not supported.\n", be->major, be->minor,
-+                     major, minor);
-+              return;
++      /* Leave device stopped if necessary */
++      if (method == RESET_TYPE_DISABLE) {
++              /* Reinitialise the device anyway so the driver unload sequence
++               * can talk to the external SRAM */
++              (void) falcon_init_nic(efx);
++              rc = -EIO;
++              goto fail4;
 +      }
 +
-+      be->mode = xenbus_read(XBT_NIL, dev->nodename, "mode", NULL);
-+      if (IS_ERR(be->mode)) {
-+              err = PTR_ERR(be->mode);
-+              be->mode = NULL;
-+              xenbus_dev_fatal(dev, err, "reading mode");
-+              return;
-+      }
++      rc = efx_reset_up(efx, &ecmd);
++      if (rc)
++              goto fail5;
 +
-+      if (be->major == 0 && be->minor == 0) {
-+              /* Front end dir is a number, which is used as the handle. */
++      mutex_unlock(&efx->mac_lock);
++      efx_reconfigure_port(efx, 1);
++      EFX_LOG(efx, "reset complete\n");
 +
-+              char *p = strrchr(dev->otherend, '/') + 1;
-+              long handle = simple_strtoul(p, NULL, 0);
++      efx->state = STATE_RUNNING;
++      efx_start_all(efx);
 +
-+              be->major = major;
-+              be->minor = minor;
++      rtnl_unlock();
 +
-+              err = vbd_create(be->blkif, handle, major, minor,
-+                               (NULL == strchr(be->mode, 'w')));
-+              if (err) {
-+                      be->major = be->minor = 0;
-+                      xenbus_dev_fatal(dev, err, "creating vbd structure");
-+                      return;
-+              }
++      goto notify;
 +
-+              err = xenvbd_sysfs_addif(dev);
-+              if (err) {
-+                      vbd_free(&be->blkif->vbd);
-+                      be->major = be->minor = 0;
-+                      xenbus_dev_fatal(dev, err, "creating sysfs entries");
-+                      return;
-+              }
++ fail5:
++ fail4:
++ fail3:
++ fail2:
++ fail1:
++      EFX_ERR(efx, "has been disabled\n");
++      efx->state = STATE_DISABLED;
 +
-+              /* We're potentially connected now */
-+              update_blkif_status(be->blkif);
-+      }
-+}
++      /* Remove the net_dev */
++      mutex_unlock(&efx->mac_lock);
++      rtnl_unlock();
++      efx_unregister_netdev(efx);
++      efx_fini_port(efx);
 +
++ notify:
++      /* Notify driverlink clients of completed reset */
++      efx_dl_reset_resume(efx, (rc == 0));
 +
-+/**
-+ * Callback received when the frontend's state changes.
++ unlock_suspend_lock:
++      up(&efx->suspend_lock);
++
++ unlock_dl_lock:
++      efx_dl_reset_unlock();
++
++      return rc;
++}
++
++/* The worker thread exists so that code that cannot sleep can
++ * schedule a reset for later.
 + */
-+static void frontend_changed(struct xenbus_device *dev,
-+                           enum xenbus_state frontend_state)
++static void efx_reset_work(struct work_struct *data)
 +{
-+      struct backend_info *be = dev->dev.driver_data;
-+      int err;
-+
-+      DPRINTK("%s", xenbus_strstate(frontend_state));
++      struct efx_nic *nic = container_of(data, struct efx_nic, reset_work);
 +
-+      switch (frontend_state) {
-+      case XenbusStateInitialising:
-+              if (dev->state == XenbusStateClosed) {
-+                      printk(KERN_INFO "%s: %s: prepare for reconnect\n",
-+                             __FUNCTION__, dev->nodename);
-+                      xenbus_switch_state(dev, XenbusStateInitWait);
-+              }
-+              break;
++      efx_reset(nic);
++}
 +
-+      case XenbusStateInitialised:
-+      case XenbusStateConnected:
-+              /* Ensure we connect even when two watches fire in 
-+                 close successsion and we miss the intermediate value 
-+                 of frontend_state. */
-+              if (dev->state == XenbusStateConnected)
-+                      break;
++void efx_schedule_reset(struct efx_nic *efx, enum reset_type type)
++{
++      enum reset_type method;
 +
-+              err = connect_ring(be);
-+              if (err)
-+                      break;
-+              update_blkif_status(be->blkif);
-+              break;
++      if (efx->reset_pending != RESET_TYPE_NONE) {
++              EFX_INFO(efx, "quenching already scheduled reset\n");
++              return;
++      }
 +
-+      case XenbusStateClosing:
-+              blkif_disconnect(be->blkif);
-+              xenbus_switch_state(dev, XenbusStateClosing);
++      switch (type) {
++      case RESET_TYPE_INVISIBLE:
++      case RESET_TYPE_ALL:
++      case RESET_TYPE_WORLD:
++      case RESET_TYPE_DISABLE:
++              method = type;
 +              break;
-+
-+      case XenbusStateClosed:
-+              xenbus_switch_state(dev, XenbusStateClosed);
-+              if (xenbus_dev_is_online(dev))
-+                      break;
-+              /* fall through if not online */
-+      case XenbusStateUnknown:
-+              device_unregister(&dev->dev);
++      case RESET_TYPE_RX_RECOVERY:
++      case RESET_TYPE_RX_DESC_FETCH:
++      case RESET_TYPE_TX_DESC_FETCH:
++              method = RESET_TYPE_INVISIBLE;
 +              break;
-+
 +      default:
-+              xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
-+                               frontend_state);
++              method = RESET_TYPE_ALL;
 +              break;
 +      }
++
++      if (method != type)
++              EFX_LOG(efx, "scheduling %s reset for %s\n",
++                      RESET_TYPE(method), RESET_TYPE(type));
++      else
++              EFX_LOG(efx, "scheduling %s reset\n", RESET_TYPE(method));
++
++      efx->reset_pending = method;
++
++#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
++      queue_work(efx->reset_workqueue, &efx->reset_work);
++#else
++      queue_work(efx->workqueue, &efx->reset_work);
++#endif
 +}
 +
++/**************************************************************************
++ *
++ * List of NICs we support
++ *
++ **************************************************************************/
++
++enum efx_type_index {
++      EFX_TYPE_FALCON_A = 0,
++      EFX_TYPE_FALCON_B = 1,
++};
 +
-+/* ** Connection ** */
++static struct efx_nic_type *efx_nic_types[] = {
++      [EFX_TYPE_FALCON_A] = &falcon_a_nic_type,
++      [EFX_TYPE_FALCON_B] = &falcon_b_nic_type,
++};
 +
 +
-+/**
-+ * Write the physical details regarding the block device to the store, and
-+ * switch to Connected state.
-+ */
-+static void connect(struct backend_info *be)
++/* PCI device ID table */
++static struct pci_device_id efx_pci_table[] __devinitdata = {
++      {EFX_VENDID_SFC, FALCON_A_P_DEVID, PCI_ANY_ID, PCI_ANY_ID,
++       0, 0, EFX_TYPE_FALCON_A},
++      {EFX_VENDID_SFC, FALCON_B_P_DEVID, PCI_ANY_ID, PCI_ANY_ID,
++       0, 0, EFX_TYPE_FALCON_B},
++      {0}                     /* end of list */
++};
++
++/**************************************************************************
++ *
++ * Dummy PHY/MAC/Board operations
++ *
++ * Can be used where the MAC does not implement this operation
++ * Needed so all function pointers are valid and do not have to be tested
++ * before use
++ *
++ **************************************************************************/
++int efx_port_dummy_op_int(struct efx_nic *efx)
 +{
-+      struct xenbus_transaction xbt;
-+      int err;
-+      struct xenbus_device *dev = be->dev;
++      return 0;
++}
++void efx_port_dummy_op_void(struct efx_nic *efx) {}
++void efx_port_dummy_op_blink(struct efx_nic *efx, int blink) {}
 +
-+      DPRINTK("%s", dev->otherend);
++static struct efx_mac_operations efx_dummy_mac_operations = {
++      .init           = efx_port_dummy_op_int,
++      .reconfigure    = efx_port_dummy_op_void,
++      .fini           = efx_port_dummy_op_void,
++};
 +
-+      /* Supply the information about the device the frontend needs */
-+again:
-+      err = xenbus_transaction_start(&xbt);
-+      if (err) {
-+              xenbus_dev_fatal(dev, err, "starting transaction");
-+              return;
-+      }
++static struct efx_phy_operations efx_dummy_phy_operations = {
++      .init            = efx_port_dummy_op_int,
++      .reconfigure     = efx_port_dummy_op_void,
++      .check_hw        = efx_port_dummy_op_int,
++      .fini            = efx_port_dummy_op_void,
++      .clear_interrupt = efx_port_dummy_op_void,
++      .reset_xaui      = efx_port_dummy_op_void,
++};
 +
-+      err = blkback_barrier(xbt, be, 1);
-+      if (err)
-+              goto abort;
++/* Dummy board operations */
++static int efx_nic_dummy_op_int(struct efx_nic *nic)
++{
++      return 0;
++}
 +
-+      err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
-+                          vbd_size(&be->blkif->vbd));
-+      if (err) {
-+              xenbus_dev_fatal(dev, err, "writing %s/sectors",
-+                               dev->nodename);
-+              goto abort;
++static void efx_nic_dummy_op_void(struct efx_nic *nic) {}
++
++static struct efx_board efx_dummy_board_info = {
++      .init    = efx_nic_dummy_op_int,
++      .init_leds = efx_port_dummy_op_int,
++      .set_fault_led = efx_port_dummy_op_blink,
++      .monitor = efx_nic_dummy_op_int,
++      .blink = efx_port_dummy_op_blink,
++      .fini    = efx_nic_dummy_op_void,
++};
++
++/**************************************************************************
++ *
++ * Data housekeeping
++ *
++ **************************************************************************/
++
++/* This zeroes out and then fills in the invariants in a struct
++ * efx_nic (including all sub-structures).
++ */
++static int efx_init_struct(struct efx_nic *efx, enum efx_type_index type,
++                         struct pci_dev *pci_dev)
++{
++      struct efx_channel *channel;
++      struct efx_tx_queue *tx_queue;
++      struct efx_rx_queue *rx_queue;
++      int i, rc;
++
++      /* Initialise common structures */
++      memset(efx, 0, sizeof(*efx));
++      spin_lock_init(&efx->biu_lock);
++      spin_lock_init(&efx->phy_lock);
++      mutex_init(&efx->spi_lock);
++      sema_init(&efx->suspend_lock, 1);
++      INIT_WORK(&efx->reset_work, efx_reset_work);
++      INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor);
++      efx->pci_dev = pci_dev;
++      efx->state = STATE_INIT;
++      efx->reset_pending = RESET_TYPE_NONE;
++      strlcpy(efx->name, pci_name(pci_dev), sizeof(efx->name));
++      efx->board_info = efx_dummy_board_info;
++
++      efx->rx_checksum_enabled = 1;
++      spin_lock_init(&efx->netif_stop_lock);
++      spin_lock_init(&efx->stats_lock);
++      mutex_init(&efx->mac_lock);
++      efx->mac_op = &efx_dummy_mac_operations;
++      efx->phy_op = &efx_dummy_phy_operations;
++      INIT_LIST_HEAD(&efx->dl_node);
++      INIT_LIST_HEAD(&efx->dl_device_list);
++      efx->dl_cb = efx_default_callbacks;
++      INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work);
++      atomic_set(&efx->netif_stop_count, 1);
++
++      for (i = 0; i < EFX_MAX_CHANNELS; i++) {
++              channel = &efx->channel[i];
++              channel->efx = efx;
++              channel->channel = i;
++              channel->evqnum = i;
++              channel->work_pending = 0;
++      }
++      for (i = 0; i < EFX_MAX_TX_QUEUES; i++) {
++              tx_queue = &efx->tx_queue[i];
++              tx_queue->efx = efx;
++              tx_queue->queue = i;
++              tx_queue->buffer = NULL;
++              tx_queue->channel = &efx->channel[0]; /* for safety */
++      }
++      for (i = 0; i < EFX_MAX_RX_QUEUES; i++) {
++              rx_queue = &efx->rx_queue[i];
++              rx_queue->efx = efx;
++              rx_queue->queue = i;
++              rx_queue->channel = &efx->channel[0]; /* for safety */
++              rx_queue->buffer = NULL;
++              spin_lock_init(&rx_queue->add_lock);
++              INIT_DELAYED_WORK(&rx_queue->work, efx_rx_work);
++      }
++
++      efx->type = efx_nic_types[type];
++
++      /* Sanity-check NIC type */
++      EFX_BUG_ON_PARANOID(efx->type->txd_ring_mask &
++                          (efx->type->txd_ring_mask + 1));
++      EFX_BUG_ON_PARANOID(efx->type->rxd_ring_mask &
++                          (efx->type->rxd_ring_mask + 1));
++      EFX_BUG_ON_PARANOID(efx->type->evq_size &
++                          (efx->type->evq_size - 1));
++      /* As close as we can get to guaranteeing that we don't overflow */
++      EFX_BUG_ON_PARANOID(efx->type->evq_size <
++                          (efx->type->txd_ring_mask + 1 +
++                           efx->type->rxd_ring_mask + 1));
++
++      EFX_BUG_ON_PARANOID(efx->type->phys_addr_channels > EFX_MAX_CHANNELS);
++
++      /* Higher numbered interrupt modes are less capable! */
++      efx->interrupt_mode = max(efx->type->max_interrupt_mode,
++                                interrupt_mode);
++#if defined(EFX_NEED_DUMMY_MSIX)
++      if (efx->interrupt_mode == EFX_INT_MODE_MSIX)
++              efx->interrupt_mode = EFX_INT_MODE_MSI;
++#endif
++
++      /* Tasks that can fail are last */
++      efx->refill_workqueue = create_workqueue("sfc_refill");
++      if (!efx->refill_workqueue) {
++              rc = -ENOMEM;
++              goto fail1;
 +      }
 +
-+      /* FIXME: use a typename instead */
-+      err = xenbus_printf(xbt, dev->nodename, "info", "%u",
-+                          vbd_info(&be->blkif->vbd));
-+      if (err) {
-+              xenbus_dev_fatal(dev, err, "writing %s/info",
-+                               dev->nodename);
-+              goto abort;
++      efx->workqueue = create_singlethread_workqueue("sfc_work");
++      if (!efx->workqueue) {
++              rc = -ENOMEM;
++              goto fail2;
 +      }
-+      err = xenbus_printf(xbt, dev->nodename, "sector-size", "%lu",
-+                          vbd_secsize(&be->blkif->vbd));
-+      if (err) {
-+              xenbus_dev_fatal(dev, err, "writing %s/sector-size",
-+                               dev->nodename);
-+              goto abort;
++
++#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
++      efx->reset_workqueue = create_singlethread_workqueue("sfc_reset");
++      if (!efx->reset_workqueue) {
++              rc = -ENOMEM;
++              goto fail3;
 +      }
++#endif
 +
-+      err = xenbus_transaction_end(xbt, 0);
-+      if (err == -EAGAIN)
-+              goto again;
-+      if (err)
-+              xenbus_dev_fatal(dev, err, "ending transaction");
++      return 0;
 +
-+      err = xenbus_switch_state(dev, XenbusStateConnected);
-+      if (err)
-+              xenbus_dev_fatal(dev, err, "switching to Connected state",
-+                               dev->nodename);
++#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
++ fail3:
++      destroy_workqueue(efx->workqueue);
++      efx->workqueue = NULL;
++#endif
 +
-+      return;
-+ abort:
-+      xenbus_transaction_end(xbt, 1);
++ fail2:
++      destroy_workqueue(efx->refill_workqueue);
++      efx->refill_workqueue = NULL;
++ fail1:
++      return rc;
 +}
 +
-+
-+static int connect_ring(struct backend_info *be)
++static void efx_fini_struct(struct efx_nic *efx)
 +{
-+      struct xenbus_device *dev = be->dev;
-+      unsigned long ring_ref;
-+      unsigned int evtchn;
-+      char protocol[64] = "";
-+      int err;
++#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
++      if (efx->reset_workqueue) {
++              destroy_workqueue(efx->reset_workqueue);
++              efx->reset_workqueue = NULL;
++      }
++#endif
++      if (efx->workqueue) {
++              destroy_workqueue(efx->workqueue);
++              efx->workqueue = NULL;
++      }
++      if (efx->refill_workqueue) {
++              destroy_workqueue(efx->refill_workqueue);
++              efx->refill_workqueue = NULL;
++      }
++}
 +
-+      DPRINTK("%s", dev->otherend);
-+
-+      err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", &ring_ref,
-+                          "event-channel", "%u", &evtchn, NULL);
-+      if (err) {
-+              xenbus_dev_fatal(dev, err,
-+                               "reading %s/ring-ref and event-channel",
-+                               dev->otherend);
-+              return err;
-+      }
++/**************************************************************************
++ *
++ * PCI interface
++ *
++ **************************************************************************/
 +
-+      be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
-+      err = xenbus_gather(XBT_NIL, dev->otherend, "protocol",
-+                          "%63s", protocol, NULL);
-+      if (err)
-+              strcpy(protocol, "unspecified, assuming native");
-+      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE))
-+              be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
-+      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
-+              be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32;
-+      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64))
-+              be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64;
-+      else {
-+              xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol);
-+              return -1;
-+      }
-+      printk(KERN_INFO
-+             "blkback: ring-ref %ld, event-channel %d, protocol %d (%s)\n",
-+             ring_ref, evtchn, be->blkif->blk_protocol, protocol);
++/* Main body of final NIC shutdown code
++ * This is called only at module unload (or hotplug removal).
++ */
++static void efx_pci_remove_main(struct efx_nic *efx)
++{
++      ASSERT_RTNL();
 +
-+      /* Map the shared frame, irq etc. */
-+      err = blkif_map(be->blkif, ring_ref, evtchn);
-+      if (err) {
-+              xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
-+                               ring_ref, evtchn);
-+              return err;
-+      }
++      /* Skip everything if we never obtained a valid membase */
++      if (!efx->membase)
++              return;
 +
-+      return 0;
-+}
++      efx_fini_channels(efx);
++      efx_fini_port(efx);
 +
++      /* Shutdown the board, then the NIC and board state */
++      efx->board_info.fini(efx);
++      falcon_fini_nic(efx);
++      falcon_fini_interrupt(efx);
++      efx->board_info.fini(efx);
 +
-+/* ** Driver Registration ** */
++      /* Tear down NAPI and LRO */
++      efx_fini_napi(efx);
++      efx_remove_all(efx);
++}
 +
++/* Final NIC shutdown
++ * This is called only at module unload (or hotplug removal).
++ */
++static void efx_pci_remove(struct pci_dev *pci_dev)
++{
++      struct efx_nic *efx;
 +
-+static struct xenbus_device_id blkback_ids[] = {
-+      { "vbd" },
-+      { "" }
-+};
++      efx = pci_get_drvdata(pci_dev);
++      if (!efx)
++              return;
 +
++      /* Unregister driver from driverlink layer */
++      efx_dl_unregister_nic(efx);
 +
-+static struct xenbus_driver blkback = {
-+      .name = "vbd",
-+      .owner = THIS_MODULE,
-+      .ids = blkback_ids,
-+      .probe = blkback_probe,
-+      .remove = blkback_remove,
-+      .otherend_changed = frontend_changed
-+};
++      /* Mark the NIC as fini under both suspend_lock and
++       * rtnl_lock */
++      down(&efx->suspend_lock);
++      rtnl_lock();
++      efx->state = STATE_FINI;
++      up(&efx->suspend_lock);
 +
++      if (efx->membase) {
++              /* Stop the NIC. Since we're in STATE_FINI, this
++               * won't be reversed. */
++              if (efx->net_dev_registered)
++                      dev_close(efx->net_dev);
 +
-+void blkif_xenbus_init(void)
-+{
-+      xenbus_register_backend(&blkback);
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blkfront/blkfront.c linux-2.6.18-xen.hg/drivers/xen/blkfront/blkfront.c
---- linux-2.6.18/drivers/xen/blkfront/blkfront.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blkfront/blkfront.c        2007-12-23 11:15:33.544575492 +0100
-@@ -0,0 +1,920 @@
-+/******************************************************************************
-+ * blkfront.c
-+ * 
-+ * XenLinux virtual block-device driver.
-+ * 
-+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
-+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
-+ * Copyright (c) 2004, Christian Limpach
-+ * Copyright (c) 2004, Andrew Warfield
-+ * Copyright (c) 2005, Christopher Clark
-+ * Copyright (c) 2005, XenSource Ltd
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
++              /* Release the rtnl lock. Any queued efx_resets()
++               * can now return early [we're in STATE_FINI]. */
++              rtnl_unlock();
 +
-+#include <linux/version.h>
-+#include "block.h"
-+#include <linux/cdrom.h>
-+#include <linux/sched.h>
-+#include <linux/interrupt.h>
-+#include <scsi/scsi.h>
-+#include <xen/evtchn.h>
-+#include <xen/xenbus.h>
-+#include <xen/interface/grant_table.h>
-+#include <xen/interface/io/protocols.h>
-+#include <xen/gnttab.h>
-+#include <asm/hypervisor.h>
-+#include <asm/maddr.h>
++              efx_unregister_netdev(efx);
++              efx_fini_debugfs_channels(efx);
 +
-+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
-+#include <xen/platform-compat.h>
++              /* Wait for any scheduled resets to complete. No more will be
++               * scheduled from this point because efx_stop_all() has been
++               * called, we are no longer registered with driverlink, and
++               * the net_device's have been removed. */
++#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
++              flush_workqueue(efx->reset_workqueue);
++#else
++              flush_workqueue(efx->workqueue);
 +#endif
 +
-+#define BLKIF_STATE_DISCONNECTED 0
-+#define BLKIF_STATE_CONNECTED    1
-+#define BLKIF_STATE_SUSPENDED    2
-+
-+#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
-+    (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
-+#define GRANT_INVALID_REF     0
-+
-+static void connect(struct blkfront_info *);
-+static void blkfront_closing(struct xenbus_device *);
-+static int blkfront_remove(struct xenbus_device *);
-+static int talk_to_backend(struct xenbus_device *, struct blkfront_info *);
-+static int setup_blkring(struct xenbus_device *, struct blkfront_info *);
++              /* Fini and remove all the software state */
++              rtnl_lock();
++              efx_pci_remove_main(efx);
++      }
 +
-+static void kick_pending_request_queues(struct blkfront_info *);
++      rtnl_unlock();
 +
-+static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs);
-+static void blkif_restart_queue(void *arg);
-+static void blkif_recover(struct blkfront_info *);
-+static void blkif_completion(struct blk_shadow *);
-+static void blkif_free(struct blkfront_info *, int);
++      efx_fini_io(efx);
++      EFX_LOG(efx, "shutdown successful\n");
 +
++      pci_set_drvdata(pci_dev, NULL);
++      efx_fini_struct(efx);
++      kfree(efx);
++};
 +
-+/**
-+ * Entry point to this code when a new device is created.  Allocate the basic
-+ * structures and the ring buffer for communication with the backend, and
-+ * inform the backend of the appropriate details for those.  Switch to
-+ * Initialised state.
++/* Main body of NIC initialisation
++ * This is called at module load (or hotplug insertion, theoretically).
 + */
-+static int blkfront_probe(struct xenbus_device *dev,
-+                        const struct xenbus_device_id *id)
++static int efx_pci_probe_main(struct efx_nic *efx)
 +{
-+      int err, vdevice, i;
-+      struct blkfront_info *info;
++      int rc;
 +
-+      /* FIXME: Use dynamic device id if this is not set. */
-+      err = xenbus_scanf(XBT_NIL, dev->nodename,
-+                         "virtual-device", "%i", &vdevice);
-+      if (err != 1) {
-+              xenbus_dev_fatal(dev, err, "reading virtual-device");
-+              return err;
++      /* Do start-of-day initialisation */
++      rc = efx_probe_all(efx);
++      if (rc)
++              goto fail1;
++
++      /* Initialise port/channel net_dev's  */
++      rc = efx_init_napi(efx);
++      if (rc)
++              goto fail2;
++
++      /* Initialise the board */
++      rc = efx->board_info.init(efx);
++      if (rc) {
++              EFX_ERR(efx, "failed to initialise board\n");
++              goto fail3;
 +      }
 +
-+      info = kzalloc(sizeof(*info), GFP_KERNEL);
-+      if (!info) {
-+              xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
-+              return -ENOMEM;
++      /* Initialise device */
++      rc = falcon_init_nic(efx);
++      if (rc) {
++              EFX_ERR(efx, "failed to initialise NIC\n");
++              goto fail4;
 +      }
 +
-+      info->xbdev = dev;
-+      info->vdevice = vdevice;
-+      info->connected = BLKIF_STATE_DISCONNECTED;
-+      INIT_WORK(&info->work, blkif_restart_queue, (void *)info);
++      /* Initialise port */
++      rc = efx_init_port(efx);
++      if (rc) {
++              EFX_ERR(efx, "failed to initialise port\n");
++              goto fail5;
++      }
 +
-+      for (i = 0; i < BLK_RING_SIZE; i++)
-+              info->shadow[i].req.id = i+1;
-+      info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
++      /* Initialise channels */
++      rc = efx_init_channels(efx);
++      if (rc)
++              goto fail6;
 +
-+      /* Front end dir is a number, which is used as the id. */
-+      info->handle = simple_strtoul(strrchr(dev->nodename,'/')+1, NULL, 0);
-+      dev->dev.driver_data = info;
++      rc = falcon_init_interrupt(efx);
++      if (rc)
++              goto fail7;
 +
-+      err = talk_to_backend(dev, info);
-+      if (err) {
-+              kfree(info);
-+              dev->dev.driver_data = NULL;
-+              return err;
-+      }
++      /* Start up device - interrupts can occur from this point */
++      efx_start_all(efx);
++
++      /* Check basic functionality and set interrupt mode */
++      rc = efx_run_selftests(efx);
++      if (rc)
++              goto fail8;
++
++      /* Stop the NIC */
++      efx_stop_all(efx);
 +
 +      return 0;
-+}
 +
++ fail8:
++      efx_stop_all(efx);
++      falcon_fini_interrupt(efx);
++ fail7:
++      efx_fini_channels(efx);
++ fail6:
++      efx_fini_port(efx);
++ fail5:
++      falcon_fini_nic(efx);
++ fail4:
++      efx->board_info.fini(efx);
++ fail3:
++      efx_fini_napi(efx);
++ fail2:
++      efx_remove_all(efx);
++ fail1:
++      return rc;
++}
 +
-+/**
-+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
-+ * driver restart.  We tear down our blkif structure and recreate it, but
-+ * leave the device-layer structures intact so that this is transparent to the
-+ * rest of the kernel.
++/* NIC initialisation
++ *
++ * This is called at module load (or hotplug insertion,
++ * theoretically).  It sets up PCI mappings, tests and resets the NIC,
++ * sets up and registers the network devices with the kernel and hooks
++ * the interrupt service routine.  It does not prepare the device for
++ * transmission; this is left to the first time one of the network
++ * interfaces is brought up (i.e. efx_net_open).
 + */
-+static int blkfront_resume(struct xenbus_device *dev)
++static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
++                                 const struct pci_device_id *entry)
 +{
-+      struct blkfront_info *info = dev->dev.driver_data;
-+      int err;
++      struct efx_nic *efx;
++      enum efx_type_index type = entry->driver_data;
++      int i, rc;
 +
-+      DPRINTK("blkfront_resume: %s\n", dev->nodename);
++      /* Allocate and initialise a struct efx_nic */
++      efx = kmalloc(sizeof(*efx), GFP_KERNEL);
++      if (!efx) {
++              rc = -ENOMEM;
++              goto fail1;
++      }
++      pci_set_drvdata(pci_dev, efx);
++      rc = efx_init_struct(efx, type, pci_dev);
++      if (rc)
++              goto fail2;
 +
-+      blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
++      EFX_INFO(efx, "Solarflare Communications NIC detected\n");
 +
-+      err = talk_to_backend(dev, info);
-+      if (info->connected == BLKIF_STATE_SUSPENDED && !err)
-+              blkif_recover(info);
++      /* Set up basic I/O (BAR mappings etc) */
++      rc = efx_init_io(efx);
++      if (rc)
++              goto fail3;
 +
-+      return err;
-+}
++      /* From this point on we begin to expose the driver to the OS
++       * to varying degrees, so lets grab the suspend_lock and
++       * rtnl_lock to serialise against efx_reset() and
++       * friends. efx->state is not STATE_RUNNING yet, but we don't
++       * want these tasks to fail, just to block until we drop the
++       * lock
++       */
++      rc = down_interruptible(&efx->suspend_lock);
++      if (rc) {
++              EFX_ERR(efx, "suspend interrupted - aborting\n");
++              goto fail4;
++      }
 +
++      rtnl_lock();
 +
-+/* Common code used when first setting up, and when resuming. */
-+static int talk_to_backend(struct xenbus_device *dev,
-+                         struct blkfront_info *info)
-+{
-+      const char *message = NULL;
-+      struct xenbus_transaction xbt;
-+      int err;
++      /* Probe, initialise and start everything. Run self-test */
++      for (i = 0; i < 5; i++) {
++              rc = efx_pci_probe_main(efx);
++              if (rc == 0)
++                      break;
 +
-+      /* Create shared ring, alloc event channel. */
-+      err = setup_blkring(dev, info);
-+      if (err)
-+              goto out;
++              /* Retry if a recoverably reset event has been scheduled */
++              if ((efx->reset_pending != RESET_TYPE_INVISIBLE) &&
++                  (efx->reset_pending != RESET_TYPE_ALL))
++                      goto fail5;
 +
-+again:
-+      err = xenbus_transaction_start(&xbt);
-+      if (err) {
-+              xenbus_dev_fatal(dev, err, "starting transaction");
-+              goto destroy_blkring;
-+      }
++              /* Serialise against efx_reset(). No more resets will be
++               * scheduled since efx_stop_all() has been called, and we
++               * have not and never have been registered with either
++               * the rtnetlink or driverlink layers. */
++              rtnl_unlock();
++              up(&efx->suspend_lock);
 +
-+      err = xenbus_printf(xbt, dev->nodename,
-+                          "ring-ref","%u", info->ring_ref);
-+      if (err) {
-+              message = "writing ring-ref";
-+              goto abort_transaction;
-+      }
-+      err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
-+                          irq_to_evtchn_port(info->irq));
-+      if (err) {
-+              message = "writing event-channel";
-+              goto abort_transaction;
-+      }
-+      err = xenbus_printf(xbt, dev->nodename, "protocol", "%s",
-+                          XEN_IO_PROTO_ABI_NATIVE);
-+      if (err) {
-+              message = "writing protocol";
-+              goto abort_transaction;
-+      }
++#if defined(EFX_USE_CANCEL_WORK_SYNC)
++              cancel_work_sync(&efx->reset_work);
++#else
++              flush_workqueue(efx->reset_workqueue);
++#endif
 +
-+      err = xenbus_transaction_end(xbt, 0);
-+      if (err) {
-+              if (err == -EAGAIN)
-+                      goto again;
-+              xenbus_dev_fatal(dev, err, "completing transaction");
-+              goto destroy_blkring;
++              down(&efx->suspend_lock);
++              rtnl_lock();
++
++              efx->reset_pending = RESET_TYPE_NONE;
++      };
++      if (rc) {
++              EFX_ERR(efx, "Could not reset NIC\n");
++              goto fail5;
 +      }
 +
-+      xenbus_switch_state(dev, XenbusStateInitialised);
++      /* Self-tests have all passed */
++      rc = efx_init_debugfs_channels(efx);
++      if (rc)
++              goto fail6;
++
++      /* Switch to the running state before we expose the device to
++       * the OS.  This is to ensure that the initial gathering of
++       * MAC stats succeeds. */
++      efx->state = STATE_RUNNING;
++
++      rtnl_unlock();
++
++      rc = efx_register_netdev(efx);
++      if (rc)
++              goto fail7;
++
++      up(&efx->suspend_lock);
++
++      EFX_LOG(efx, "initialisation successful\n");
++
++      /* Register with driverlink layer */
++      rc = efx_dl_register_nic(efx);
++      if (rc)
++              goto fail8;
 +
 +      return 0;
 +
-+ abort_transaction:
-+      xenbus_transaction_end(xbt, 1);
-+      if (message)
-+              xenbus_dev_fatal(dev, err, "%s", message);
-+ destroy_blkring:
-+      blkif_free(info, 0);
-+ out:
-+      return err;
++ fail8:
++      down(&efx->suspend_lock);
++      efx_unregister_netdev(efx);
++ fail7:
++      /* Re-acquire the rtnl lock around pci_remove_main() */
++      rtnl_lock();
++      efx_fini_debugfs_channels(efx);
++ fail6:
++      efx_pci_remove_main(efx);
++ fail5:
++      /* Drop the locks before fini */
++      rtnl_unlock();
++      up(&efx->suspend_lock);
++ fail4:
++      efx_fini_io(efx);
++ fail3:
++      efx_fini_struct(efx);
++ fail2:
++      kfree(efx);
++ fail1:
++      EFX_LOG(efx, "initialisation failed. rc=%d\n", rc);
++      return rc;
 +}
 +
++/* PCI driver definition */
++static struct pci_driver efx_pci_driver = {
++      .name           = EFX_DRIVER_NAME,
++      .id_table       = efx_pci_table,
++      .probe          = efx_pci_probe,
++      .remove         = efx_pci_remove,
++};
 +
-+static int setup_blkring(struct xenbus_device *dev,
-+                       struct blkfront_info *info)
++/**************************************************************************
++ *
++ * Kernel module interface
++ *
++ *************************************************************************/
++
++module_param(interrupt_mode, uint, 0444);
++MODULE_PARM_DESC(interrupt_mode,
++               "Interrupt mode (0=>MSIX 1=>MSI 2=>legacy)");
++
++module_param(onload_offline_selftest, uint, 0444);
++MODULE_PARM_DESC(onload_offline_selftest, "Perform offline selftest on load");
++
++static int __init efx_init_module(void)
 +{
-+      blkif_sring_t *sring;
-+      int err;
++      int rc;
 +
-+      info->ring_ref = GRANT_INVALID_REF;
++      printk(KERN_INFO "Solarflare NET driver v" EFX_DRIVER_VERSION "\n");
 +
-+      sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL);
-+      if (!sring) {
-+              xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
-+              return -ENOMEM;
-+      }
-+      SHARED_RING_INIT(sring);
-+      FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
++      rc = efx_init_debugfs();
++      if (rc)
++              goto err_debugfs;
 +
-+      err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
-+      if (err < 0) {
-+              free_page((unsigned long)sring);
-+              info->ring.sring = NULL;
-+              goto fail;
-+      }
-+      info->ring_ref = err;
++      rc = register_netdevice_notifier(&efx_netdev_notifier);
++      if (rc)
++              goto err_notifier;
 +
-+      err = bind_listening_port_to_irqhandler(
-+              dev->otherend_id, blkif_int, SA_SAMPLE_RANDOM, "blkif", info);
-+      if (err <= 0) {
-+              xenbus_dev_fatal(dev, err,
-+                               "bind_listening_port_to_irqhandler");
-+              goto fail;
-+      }
-+      info->irq = err;
++      rc = pci_register_driver(&efx_pci_driver);
++      if (rc < 0)
++              goto err_pci;
 +
 +      return 0;
-+fail:
-+      blkif_free(info, 0);
-+      return err;
++
++ err_pci:
++      unregister_netdevice_notifier(&efx_netdev_notifier);
++ err_notifier:
++      efx_fini_debugfs();
++ err_debugfs:
++      return rc;
 +}
 +
++static void __exit efx_exit_module(void)
++{
++      printk(KERN_INFO "Solarflare NET driver unloading\n");
 +
-+/**
-+ * Callback received when the backend's state changes.
++      pci_unregister_driver(&efx_pci_driver);
++      unregister_netdevice_notifier(&efx_netdev_notifier);
++      efx_fini_debugfs();
++
++}
++
++module_init(efx_init_module);
++module_exit(efx_exit_module);
++
++MODULE_AUTHOR("Michael Brown <mbrown@fensystems.co.uk> and "
++            "Solarflare Communications");
++MODULE_DESCRIPTION("Solarflare Communications network driver");
++MODULE_LICENSE("GPL");
++MODULE_DEVICE_TABLE(pci, efx_pci_table);
+--- linux-2.6.18.8/drivers/net/sfc/efx.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/efx.h  2008-05-19 00:33:28.837808372 +0300
+@@ -0,0 +1,103 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
-+static void backend_changed(struct xenbus_device *dev,
-+                          enum xenbus_state backend_state)
-+{
-+      struct blkfront_info *info = dev->dev.driver_data;
-+      struct block_device *bd;
 +
-+      DPRINTK("blkfront:backend_changed.\n");
++#ifndef EFX_EFX_H
++#define EFX_EFX_H
 +
-+      switch (backend_state) {
-+      case XenbusStateInitialising:
-+      case XenbusStateInitWait:
-+      case XenbusStateInitialised:
-+      case XenbusStateUnknown:
-+      case XenbusStateClosed:
-+              break;
++#include "net_driver.h"
 +
-+      case XenbusStateConnected:
-+              connect(info);
-+              break;
++/* PCI IDs */
++#define EFX_VENDID_SFC                0x1924
++#define FALCON_A_P_DEVID      0x0703
++#define FALCON_A_S_DEVID        0x6703
++#define FALCON_B_P_DEVID        0x0710
 +
-+      case XenbusStateClosing:
-+              bd = bdget(info->dev);
-+              if (bd == NULL)
-+                      xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
++/* TX */
++extern int efx_xmit(struct efx_nic *efx,
++                  struct efx_tx_queue *tx_queue, struct sk_buff *skb);
++extern void efx_stop_queue(struct efx_nic *efx);
++extern void efx_wake_queue(struct efx_nic *efx);
 +
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-+              down(&bd->bd_sem);
++/* RX */
++#if defined(EFX_USE_FASTCALL)
++extern void fastcall efx_xmit_done(struct efx_tx_queue *tx_queue,
++                                 unsigned int index);
 +#else
-+              mutex_lock(&bd->bd_mutex);
++extern void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index);
 +#endif
-+              if (info->users > 0)
-+                      xenbus_dev_error(dev, -EBUSY,
-+                                       "Device in use; refusing to close");
-+              else
-+                      blkfront_closing(dev);
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
-+              up(&bd->bd_sem);
++#if defined(EFX_USE_FASTCALL)
++extern void fastcall efx_rx_packet(struct efx_rx_queue *rx_queue,
++                                 unsigned int index, unsigned int len,
++                                 int checksummed, int discard);
 +#else
-+              mutex_unlock(&bd->bd_mutex);
++extern void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
++                        unsigned int len, int checksummed, int discard);
 +#endif
-+              bdput(bd);
-+              break;
-+      }
-+}
-+
++extern void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
++                             struct efx_rx_buffer *rx_buf);
 +
-+/* ** Connection ** */
++/* Channels */
++extern void efx_process_channel_now(struct efx_channel *channel);
++extern int efx_flush_queues(struct efx_nic *efx);
 +
++/* Ports */
++extern void efx_reconfigure_port(struct efx_nic *efx,
++                               int on_disabled);
 +
-+/*
-+ * Invoked when the backend is finally 'ready' (and has told produced
-+ * the details about the physical device - #sectors, size, etc).
-+ */
-+static void connect(struct blkfront_info *info)
-+{
-+      unsigned long long sectors;
-+      unsigned long sector_size;
-+      unsigned int binfo;
-+      int err;
++/* Global */
++extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
++extern void efx_suspend(struct efx_nic *efx);
++extern void efx_resume(struct efx_nic *efx);
++extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs,
++                                  int rx_usecs);
++extern int efx_request_power(struct efx_nic *efx, int mw, const char *name);
++extern void efx_hex_dump(const u8 *, unsigned int, const char *);
 +
-+      if ((info->connected == BLKIF_STATE_CONNECTED) ||
-+          (info->connected == BLKIF_STATE_SUSPENDED) )
-+              return;
++/* Dummy PHY ops for PHY drivers */
++extern int efx_port_dummy_op_int(struct efx_nic *efx);
++extern void efx_port_dummy_op_void(struct efx_nic *efx);
++extern void efx_port_dummy_op_blink(struct efx_nic *efx, int blink);
 +
-+      DPRINTK("blkfront.c:connect:%s.\n", info->xbdev->otherend);
 +
-+      err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-+                          "sectors", "%Lu", &sectors,
-+                          "info", "%u", &binfo,
-+                          "sector-size", "%lu", &sector_size,
-+                          NULL);
-+      if (err) {
-+              xenbus_dev_fatal(info->xbdev, err,
-+                               "reading backend fields at %s",
-+                               info->xbdev->otherend);
-+              return;
-+      }
++extern unsigned int efx_monitor_interval;
 +
-+      err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
-+                          "feature-barrier", "%lu", &info->feature_barrier,
-+                          NULL);
-+      if (err)
-+              info->feature_barrier = 0;
++static inline void efx_schedule_channel(struct efx_channel *channel)
++{
++      EFX_TRACE(channel->efx, "channel %d scheduling NAPI poll on CPU%d\n",
++                channel->channel, raw_smp_processor_id());
++      channel->work_pending = 1;
 +
-+      err = xlvbd_add(sectors, info->vdevice, binfo, sector_size, info);
-+      if (err) {
-+              xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
-+                               info->xbdev->otherend);
-+              return;
-+      }
++#if defined(EFX_HAVE_OLD_NAPI)
++      if (!test_and_set_bit(__LINK_STATE_RX_SCHED, &channel->napi_dev->state))
++              __netif_rx_schedule(channel->napi_dev);
++#else
++      netif_rx_schedule(channel->napi_dev, &channel->napi_str);
++#endif
++}
 +
-+      (void)xenbus_switch_state(info->xbdev, XenbusStateConnected);
 +
-+      /* Kick pending requests. */
-+      spin_lock_irq(&blkif_io_lock);
-+      info->connected = BLKIF_STATE_CONNECTED;
-+      kick_pending_request_queues(info);
-+      spin_unlock_irq(&blkif_io_lock);
++#endif /* EFX_EFX_H */
+--- linux-2.6.18.8/drivers/net/sfc/enum.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/enum.h 2008-05-19 00:33:28.837808372 +0300
+@@ -0,0 +1,117 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2007:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      add_disk(info->gd);
++#ifndef EFX_ENUM_H
++#define EFX_ENUM_H
 +
-+      info->is_ready = 1;
-+}
++/**
++ * enum efx_loopback_mode - loopback modes
++ * @LOOPBACK_NONE: no loopback
++ * @LOOPBACK_NEAR: loopback nearest to bus
++ * @LOOPBACK_MAC: loopback within MAC unspecified level
++ * @LOOPBACK_XGMII: loopback within MAC at XGMII level
++ * @LOOPBACK_XGXS: loopback within MAC at XGXS level
++ * @LOOPBACK_XAUI: loopback within MAC at XAUI level
++ * @LOOPBACK_PHY: loopback within PHY unspecified level
++ * @LOOPBACK_PHYXS: loopback within PHY at PHYXS level
++ * @LOOPBACK_PCS: loopback within PHY at PCS level
++ * @LOOPBACK_PMAPMD: loopback within PHY at PMAPMD level
++ * @LOOPBACK_FAR: loopback furthest from bus
++ * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!)
++ */
++/* Please keep in order and up-to-date w.r.t the following two #defines */
++enum efx_loopback_mode {
++      LOOPBACK_NONE = 0,
++      LOOPBACK_NEAR = 1,
++      LOOPBACK_MAC = 2,
++      LOOPBACK_XGMII = 3,
++      LOOPBACK_XGXS = 4,
++      LOOPBACK_XAUI = 5,
++      LOOPBACK_PHY = 6,
++      LOOPBACK_PHYXS = 7,
++      LOOPBACK_PCS = 8,
++      LOOPBACK_PMAPMD = 9,
++      LOOPBACK_FAR = 10,
++      LOOPBACK_NETWORK = 11,
++      LOOPBACK_MAX
++};
++#define LOOPBACK_TEST_MAX LOOPBACK_FAR
++
++/* These loopbacks occur within the controller */
++#define LOOPBACKS_10G_INTERNAL ((1 << LOOPBACK_XGMII)| \
++                              (1 << LOOPBACK_XGXS) | \
++                              (1 << LOOPBACK_XAUI))
++
++#define LOOPBACKS_1G_INTERNAL (1 << LOOPBACK_MAC)
++
++#define LOOPBACK_MASK(_efx)                   \
++      (1 << (_efx)->loopback_mode)
++
++#define LOOPBACK_INTERNAL(_efx)                                       \
++      (((LOOPBACKS_10G_INTERNAL | LOOPBACKS_1G_INTERNAL) &    \
++        LOOPBACK_MASK(_efx)) ? 1 : 0)
++
++#define LOOPBACK_CHANGED(_from, _to, _mask)           \
++      ((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) &  \
++       (_mask) ? 1 : 0)
++
++#define LOOPBACK_OUT_OF(_from, _to, _mask)            \
++      (((LOOPBACK_MASK(_from) & (_mask)) &&           \
++        ((LOOPBACK_MASK(_to) & (_mask)) == 0)) ? 1 : 0)
++
++/*****************************************************************************/
 +
 +/**
-+ * Handle the change of state of the backend to Closing.  We must delete our
-+ * device-layer structures now, to ensure that writes are flushed through to
-+ * the backend.  Once is this done, we can switch to Closed in
-+ * acknowledgement.
++ * enum reset_type - reset types
++ *
++ * %RESET_TYPE_INVSIBLE, %RESET_TYPE_ALL, %RESET_TYPE_WORLD and
++ * %RESET_TYPE_DISABLE specify the method/scope of the reset.  The
++ * other valuesspecify reasons, which efx_schedule_reset() will choose
++ * a method for.
++ *
++ * @RESET_TYPE_INVISIBLE: don't reset the PHYs or interrupts
++ * @RESET_TYPE_ALL: reset everything but PCI core blocks
++ * @RESET_TYPE_WORLD: reset everything, save & restore PCI config
++ * @RESET_TYPE_DISABLE: disable NIC
++ * @RESET_TYPE_MONITOR: reset due to hardware monitor
++ * @RESET_TYPE_INT_ERROR: reset due to internal error
++ * @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors
++ */
++enum reset_type {
++      RESET_TYPE_NONE = -1,
++      RESET_TYPE_INVISIBLE = 0,
++      RESET_TYPE_ALL = 1,
++      RESET_TYPE_WORLD = 2,
++      RESET_TYPE_DISABLE = 3,
++      RESET_TYPE_MAX_METHOD,
++      RESET_TYPE_MONITOR,
++      RESET_TYPE_INT_ERROR,
++      RESET_TYPE_RX_RECOVERY,
++      RESET_TYPE_RX_DESC_FETCH,
++      RESET_TYPE_TX_DESC_FETCH,
++      RESET_TYPE_MAX,
++};
++
++#endif /* EFX_ENUM_H */
+--- linux-2.6.18.8/drivers/net/sfc/ethtool.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/ethtool.c      2008-05-19 00:33:28.841808602 +0300
+@@ -0,0 +1,734 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
-+static void blkfront_closing(struct xenbus_device *dev)
-+{
-+      struct blkfront_info *info = dev->dev.driver_data;
-+      unsigned long flags;
 +
-+      DPRINTK("blkfront_closing: %s removed\n", dev->nodename);
++#include <linux/netdevice.h>
++#include <linux/ethtool.h>
++#include <linux/rtnetlink.h>
++#include <asm/uaccess.h>
++#include "net_driver.h"
++#include "selftest.h"
++#include "efx.h"
++#include "ethtool.h"
++#include "falcon.h"
++#include "gmii.h"
 +
-+      if (info->rq == NULL)
-+              goto out;
++static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable);
 +
-+      spin_lock_irqsave(&blkif_io_lock, flags);
-+      /* No more blkif_request(). */
-+      blk_stop_queue(info->rq);
-+      /* No more gnttab callback work. */
-+      gnttab_cancel_free_callback(&info->callback);
-+      spin_unlock_irqrestore(&blkif_io_lock, flags);
++struct ethtool_string {
++      char name[ETH_GSTRING_LEN];
++};
 +
-+      /* Flush gnttab callback work. Must be done with no locks held. */
-+      flush_scheduled_work();
++struct efx_ethtool_stat {
++      const char *name;
++      enum {
++              EFX_ETHTOOL_STAT_SOURCE_mac_stats,
++              EFX_ETHTOOL_STAT_SOURCE_nic,
++              EFX_ETHTOOL_STAT_SOURCE_channel
++      } source;
++      unsigned offset;
++      u64(*get_stat) (void *field); /* Reader function */
++};
++
++/* Initialiser for a struct #efx_ethtool_stat with type-checking */
++#define EFX_ETHTOOL_STAT(stat_name, source_name, field, field_type, \
++                              get_stat_function) {                    \
++      .name = #stat_name,                                             \
++      .source = EFX_ETHTOOL_STAT_SOURCE_##source_name,                \
++      .offset = ((((field_type *) 0) ==                               \
++                    &((struct efx_##source_name *)0)->field) ?        \
++                  offsetof(struct efx_##source_name, field) :         \
++                  offsetof(struct efx_##source_name, field)),         \
++      .get_stat = get_stat_function,                                  \
++}
++
++static u64 efx_get_uint_stat(void *field)
++{
++      return *(unsigned int *)field;
++}
++
++static u64 efx_get_ulong_stat(void *field)
++{
++      return *(unsigned long *)field;
++}
++
++static u64 efx_get_u64_stat(void *field)
++{
++      return *(u64 *) field;
++}
++
++static u64 efx_get_atomic_stat(void *field)
++{
++      return atomic_read((atomic_t *) field);
++}
++
++#define EFX_ETHTOOL_ULONG_MAC_STAT(field)                     \
++      EFX_ETHTOOL_STAT(field, mac_stats, field,               \
++                        unsigned long, efx_get_ulong_stat)
++
++#define EFX_ETHTOOL_U64_MAC_STAT(field)                               \
++      EFX_ETHTOOL_STAT(field, mac_stats, field,               \
++                        u64, efx_get_u64_stat)
++
++#define EFX_ETHTOOL_UINT_NIC_STAT(name)                               \
++      EFX_ETHTOOL_STAT(name, nic, n_##name,                   \
++                       unsigned int, efx_get_uint_stat)
++
++#define EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(field)              \
++      EFX_ETHTOOL_STAT(field, nic, errors.field,              \
++                       atomic_t, efx_get_atomic_stat)
++
++#define EFX_ETHTOOL_UINT_CHANNEL_STAT(field)                  \
++      EFX_ETHTOOL_STAT(field, channel, n_##field,             \
++                       unsigned int, efx_get_uint_stat)
++
++static struct efx_ethtool_stat efx_ethtool_stats[] = {
++      EFX_ETHTOOL_U64_MAC_STAT(tx_bytes),
++      EFX_ETHTOOL_U64_MAC_STAT(tx_good_bytes),
++      EFX_ETHTOOL_U64_MAC_STAT(tx_bad_bytes),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_packets),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_bad),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_pause),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_control),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_unicast),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_multicast),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_broadcast),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_lt64),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_64),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_65_to_127),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_128_to_255),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_256_to_511),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_512_to_1023),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_1024_to_15xx),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_15xx_to_jumbo),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_gtjumbo),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_collision),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_single_collision),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_multiple_collision),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_collision),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_deferred),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_late_collision),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_excessive_deferred),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_non_tcpudp),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_mac_src_error),
++      EFX_ETHTOOL_ULONG_MAC_STAT(tx_ip_src_error),
++      EFX_ETHTOOL_U64_MAC_STAT(rx_bytes),
++      EFX_ETHTOOL_U64_MAC_STAT(rx_good_bytes),
++      EFX_ETHTOOL_U64_MAC_STAT(rx_bad_bytes),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_packets),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_good),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_pause),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_control),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_unicast),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_multicast),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_broadcast),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_lt64),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_64),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_65_to_127),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_128_to_255),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_256_to_511),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_512_to_1023),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_1024_to_15xx),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_15xx_to_jumbo),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_gtjumbo),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_lt64),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_64_to_15xx),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_15xx_to_jumbo),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_bad_gtjumbo),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_overflow),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_missed),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_false_carrier),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_symbol_error),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_align_error),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_length_error),
++      EFX_ETHTOOL_ULONG_MAC_STAT(rx_internal_error),
++      EFX_ETHTOOL_UINT_NIC_STAT(rx_nodesc_drop_cnt),
++      EFX_ETHTOOL_ATOMIC_NIC_ERROR_STAT(rx_reset),
++      EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tobe_disc),
++      EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_ip_hdr_chksum_err),
++      EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_tcp_udp_chksum_err),
++      EFX_ETHTOOL_UINT_CHANNEL_STAT(rx_frm_trunc),
++};
++
++/* Number of ethtool statistics */
++#define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats)
++
++/**************************************************************************
++ *
++ * Ethtool operations
++ *
++ **************************************************************************
++ */
++
++/* Identify device by flashing LEDs */
++static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds)
++{
++      struct efx_nic *efx = net_dev->priv;
++
++      efx->board_info.blink(efx, 1);
++      schedule_timeout_interruptible(seconds * HZ);
++      efx->board_info.blink(efx, 0);
++      return 0;
++}
 +
-+      xlvbd_del(info);
++/* This must be called with rtnl_lock held. */
++int efx_ethtool_get_settings(struct net_device *net_dev,
++                           struct ethtool_cmd *ecmd)
++{
++      struct efx_nic *efx = net_dev->priv;
 +
-+ out:
-+      xenbus_frontend_closed(dev);
++      return efx->mac_op->get_settings(efx, ecmd);
 +}
 +
-+
-+static int blkfront_remove(struct xenbus_device *dev)
++/* This must be called with rtnl_lock held. */
++int efx_ethtool_set_settings(struct net_device *net_dev,
++                           struct ethtool_cmd *ecmd)
 +{
-+      struct blkfront_info *info = dev->dev.driver_data;
-+
-+      DPRINTK("blkfront_remove: %s removed\n", dev->nodename);
++      struct efx_nic *efx = net_dev->priv;
++      int rc;
 +
-+      blkif_free(info, 0);
++      rc = efx->mac_op->set_settings(efx, ecmd);
++      if (rc)
++              return rc;
 +
-+      kfree(info);
++      /* Push the settings to the MAC */
++      efx_reconfigure_port(efx, 0);
 +
 +      return 0;
 +}
 +
-+
-+static inline int GET_ID_FROM_FREELIST(
-+      struct blkfront_info *info)
++static void efx_ethtool_get_drvinfo(struct net_device *net_dev,
++                                  struct ethtool_drvinfo *info)
 +{
-+      unsigned long free = info->shadow_free;
-+      BUG_ON(free > BLK_RING_SIZE);
-+      info->shadow_free = info->shadow[free].req.id;
-+      info->shadow[free].req.id = 0x0fffffee; /* debug */
-+      return free;
-+}
++      struct efx_nic *efx = net_dev->priv;
 +
-+static inline void ADD_ID_TO_FREELIST(
-+      struct blkfront_info *info, unsigned long id)
-+{
-+      info->shadow[id].req.id  = info->shadow_free;
-+      info->shadow[id].request = 0;
-+      info->shadow_free = id;
++      strlcpy(info->driver, EFX_DRIVER_NAME, sizeof(info->driver));
++      strlcpy(info->version, EFX_DRIVER_VERSION, sizeof(info->version));
++      strlcpy(info->bus_info, pci_name(efx->pci_dev), sizeof(info->bus_info));
 +}
 +
-+static inline void flush_requests(struct blkfront_info *info)
++/**
++ * efx_fill_test - fill in an individual self-test entry
++ * @test_index:               Index of the test
++ * @strings:          Ethtool strings, or %NULL
++ * @data:             Ethtool test results, or %NULL
++ * @test:             Pointer to test result (used only if data != %NULL)
++ * @unit_format:      Unit name format (e.g. "channel\%d")
++ * @unit_id:          Unit id (e.g. 0 for "channel0")
++ * @test_format:      Test name format (e.g. "loopback.\%s.tx.sent")
++ * @test_id:          Test id (e.g. "PHY" for "loopback.PHY.tx_sent")
++ *
++ * Fill in an individual self-test entry.
++ */
++static void efx_fill_test(unsigned int test_index,
++                        struct ethtool_string *strings, u64 *data,
++                        int *test, const char *unit_format, int unit_id,
++                        const char *test_format, const char *test_id)
 +{
-+      int notify;
++      struct ethtool_string unit_str, test_str;
 +
-+      RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
++      /* Fill data value, if applicable */
++      if (data)
++              data[test_index] = *test;
 +
-+      if (notify)
-+              notify_remote_via_irq(info->irq);
++      /* Fill string, if applicable */
++      if (strings) {
++              snprintf(unit_str.name, sizeof(unit_str.name),
++                       unit_format, unit_id);
++              snprintf(test_str.name, sizeof(test_str.name),
++                       test_format, test_id);
++              snprintf(strings[test_index].name,
++                       sizeof(strings[test_index].name),
++                       "%-9s%-17s", unit_str.name, test_str.name);
++      }
 +}
 +
-+static void kick_pending_request_queues(struct blkfront_info *info)
-+{
-+      if (!RING_FULL(&info->ring)) {
-+              /* Re-enable calldowns. */
-+              blk_start_queue(info->rq);
-+              /* Kick things off immediately. */
-+              do_blkif_request(info->rq);
-+      }
++#define EFX_PORT_NAME "port%d", 0
++
++/**
++ * efx_fill_loopback_test - fill in a block of loopback self-test entries
++ * @efx:              Efx NIC
++ * @lb_tests:         Efx loopback self-test results structure
++ * @mode:             Loopback test mode
++ * @test_index:               Starting index of the test
++ * @strings:          Ethtool strings, or %NULL
++ * @data:             Ethtool test results, or %NULL
++ *
++ * Fill in a block of loopback self-test entries.  Return new test
++ * index.
++ */
++static int efx_fill_loopback_test(struct efx_nic *efx,
++                                struct efx_loopback_self_tests *lb_tests,
++                                enum efx_loopback_mode mode,
++                                unsigned int test_index,
++                                struct ethtool_string *strings, u64 *data)
++{
++      struct efx_tx_queue *tx_queue;
++
++      efx_for_each_tx_queue(tx_queue, efx) {
++              efx_fill_test(test_index++, strings, data,
++                            &lb_tests->tx_sent[tx_queue->queue],
++                            EFX_TX_QUEUE_NAME(tx_queue),
++                            "loopback.%s.tx_sent",
++                            efx_loopback_mode_names[mode]);
++              efx_fill_test(test_index++, strings, data,
++                            &lb_tests->tx_done[tx_queue->queue],
++                            EFX_TX_QUEUE_NAME(tx_queue),
++                            "loopback.%s.tx_done",
++                            efx_loopback_mode_names[mode]);
++      }
++      efx_fill_test(test_index++, strings, data,
++                    &lb_tests->rx_good,
++                    EFX_PORT_NAME,
++                    "loopback.%s.rx_good",
++                    efx_loopback_mode_names[mode]);
++      efx_fill_test(test_index++, strings, data,
++                    &lb_tests->rx_bad,
++                    EFX_PORT_NAME,
++                    "loopback.%s.rx_bad",
++                    efx_loopback_mode_names[mode]);
++
++      return test_index;
 +}
 +
-+static void blkif_restart_queue(void *arg)
-+{
-+      struct blkfront_info *info = (struct blkfront_info *)arg;
-+      spin_lock_irq(&blkif_io_lock);
-+      if (info->connected == BLKIF_STATE_CONNECTED)
-+              kick_pending_request_queues(info);
-+      spin_unlock_irq(&blkif_io_lock);
++/**
++ * efx_ethtool_fill_self_tests - get self-test details
++ * @efx:              Efx NIC
++ * @tests:            Efx self-test results structure, or %NULL
++ * @strings:          Ethtool strings, or %NULL
++ * @data:             Ethtool test results, or %NULL
++ *
++ * Get self-test number of strings, strings, and/or test results.
++ * Return number of strings (== number of test results).
++ *
++ * The reason for merging these three functions is to make sure that
++ * they can never be inconsistent.
++ */
++static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
++                                     struct efx_self_tests *tests,
++                                     struct ethtool_string *strings,
++                                     u64 *data)
++{
++      struct efx_channel *channel;
++      unsigned int n = 0;
++      enum efx_loopback_mode mode;
++
++      /* Interrupt */
++      efx_fill_test(n++, strings, data, &tests->interrupt,
++                    "core", 0, "interrupt", NULL);
++
++      /* Event queues */
++      efx_for_each_channel(channel, efx) {
++              efx_fill_test(n++, strings, data,
++                            &tests->eventq_dma[channel->channel],
++                            EFX_CHANNEL_NAME(channel),
++                            "eventq.dma", NULL);
++              efx_fill_test(n++, strings, data,
++                            &tests->eventq_int[channel->channel],
++                            EFX_CHANNEL_NAME(channel),
++                            "eventq.int", NULL);
++              efx_fill_test(n++, strings, data,
++                            &tests->eventq_poll[channel->channel],
++                            EFX_CHANNEL_NAME(channel),
++                            "eventq.poll", NULL);
++      }
++
++      /* PHY presence */
++      efx_fill_test(n++, strings, data, &tests->phy_ok,
++                    EFX_PORT_NAME, "phy_ok", NULL);
++
++      /* Loopback tests */
++      efx_fill_test(n++, strings, data, &tests->loopback_speed,
++                    EFX_PORT_NAME, "loopback.speed", NULL);
++      efx_fill_test(n++, strings, data, &tests->loopback_full_duplex,
++                    EFX_PORT_NAME, "loopback.full_duplex", NULL);
++      for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) {
++              if (!(efx->loopback_modes & (1 << mode)))
++                      continue;
++              n = efx_fill_loopback_test(efx,
++                                         &tests->loopback[mode], mode, n,
++                                         strings, data);
++      }
++
++      return n;
 +}
 +
-+static void blkif_restart_queue_callback(void *arg)
++static int efx_ethtool_get_stats_count(struct net_device *net_dev)
 +{
-+      struct blkfront_info *info = (struct blkfront_info *)arg;
-+      schedule_work(&info->work);
++      return EFX_ETHTOOL_NUM_STATS;
 +}
 +
-+int blkif_open(struct inode *inode, struct file *filep)
++static int efx_ethtool_self_test_count(struct net_device *net_dev)
 +{
-+      struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
-+      info->users++;
-+      return 0;
-+}
++      struct efx_nic *efx = net_dev->priv;
 +
++      return efx_ethtool_fill_self_tests(efx, NULL, NULL, NULL);
++}
 +
-+int blkif_release(struct inode *inode, struct file *filep)
++static void efx_ethtool_get_strings(struct net_device *net_dev,
++                                  u32 string_set, u8 *strings)
 +{
-+      struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
-+      info->users--;
-+      if (info->users == 0) {
-+              /* Check whether we have been instructed to close.  We will
-+                 have ignored this request initially, as the device was
-+                 still mounted. */
-+              struct xenbus_device * dev = info->xbdev;
-+              enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
++      struct efx_nic *efx = net_dev->priv;
++      struct ethtool_string *ethtool_strings =
++              (struct ethtool_string *)strings;
++      int i;
 +
-+              if (state == XenbusStateClosing && info->is_ready)
-+                      blkfront_closing(dev);
++      switch (string_set) {
++      case ETH_SS_STATS:
++              for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++)
++                      strncpy(ethtool_strings[i].name,
++                              efx_ethtool_stats[i].name,
++                              sizeof(ethtool_strings[i].name));
++              break;
++      case ETH_SS_TEST:
++              efx_ethtool_fill_self_tests(efx, NULL,
++                                          ethtool_strings, NULL);
++              break;
++      default:
++              /* No other string sets */
++              break;
 +      }
-+      return 0;
 +}
 +
-+
-+int blkif_ioctl(struct inode *inode, struct file *filep,
-+              unsigned command, unsigned long argument)
++static void efx_ethtool_get_stats(struct net_device *net_dev,
++                                struct ethtool_stats *stats
++                                __attribute__ ((unused)), u64 *data)
 +{
++      unsigned long flags __attribute__ ((unused));
++      struct efx_nic *efx = net_dev->priv;
++      struct efx_mac_stats *mac_stats = &efx->mac_stats;
++      struct efx_ethtool_stat *stat;
++      struct efx_channel *channel;
 +      int i;
 +
-+      DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
-+                    command, (long)argument, inode->i_rdev);
++      EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS);
 +
-+      switch (command) {
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
-+      case HDIO_GETGEO: {
-+              struct block_device *bd = inode->i_bdev;
-+              struct hd_geometry geo;
-+              int ret;
++      /* Update MAC and NIC statistics */
++      net_dev->get_stats(net_dev);
++      falcon_update_nic_stats(efx);
 +
-+                if (!argument)
-+                        return -EINVAL;
++      /* Fill detailed statistics buffer */
++      for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) {
++              stat = &efx_ethtool_stats[i];
++              switch (stat->source) {
++              case EFX_ETHTOOL_STAT_SOURCE_mac_stats:
++                      data[i] = stat->get_stat((void *)mac_stats +
++                                               stat->offset);
++                      break;
++              case EFX_ETHTOOL_STAT_SOURCE_nic:
++                      data[i] = stat->get_stat((void *)efx + stat->offset);
++                      break;
++              case EFX_ETHTOOL_STAT_SOURCE_channel:
++                      data[i] = 0;
++                      efx_for_each_channel(channel, efx)
++                              data[i] += stat->get_stat((void *)channel +
++                                                        stat->offset);
++                      break;
++              }
++      }
++}
 +
-+              geo.start = get_start_sect(bd);
-+              ret = blkif_getgeo(bd, &geo);
-+              if (ret)
-+                      return ret;
++static int efx_ethtool_set_tx_csum(struct net_device *net_dev, u32 enable)
++{
++      struct efx_nic *efx = net_dev->priv;
++      int rc;
 +
-+              if (copy_to_user((struct hd_geometry __user *)argument, &geo,
-+                               sizeof(geo)))
-+                        return -EFAULT;
++      rc = ethtool_op_set_tx_csum(net_dev, enable);
++      if (rc)
++              return rc;
 +
-+                return 0;
-+      }
-+#endif
-+      case CDROMMULTISESSION:
-+              DPRINTK("FIXME: support multisession CDs later\n");
-+              for (i = 0; i < sizeof(struct cdrom_multisession); i++)
-+                      if (put_user(0, (char __user *)(argument + i)))
-+                              return -EFAULT;
-+              return 0;
 +
-+      case CDROM_GET_CAPABILITY: {
-+              struct blkfront_info *info =
-+                      inode->i_bdev->bd_disk->private_data;
-+              struct gendisk *gd = info->gd;
-+              if (gd->flags & GENHD_FL_CD)
-+                      return 0;
-+              return -EINVAL;
-+      }
-+      default:
-+              /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n",
-+                command);*/
-+              return -EINVAL; /* same return as native Linux */
-+      }
++      efx_flush_queues(efx);
 +
 +      return 0;
 +}
 +
-+
-+int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
++static int efx_ethtool_set_rx_csum(struct net_device *net_dev, u32 enable)
 +{
-+      /* We don't have real geometry info, but let's at least return
-+         values consistent with the size of the device */
-+      sector_t nsect = get_capacity(bd->bd_disk);
-+      sector_t cylinders = nsect;
++      struct efx_nic *efx = net_dev->priv;
++
++      /* No way to stop the hardware doing the checks; we just
++       * ignore the result.
++       */
++      efx->rx_checksum_enabled = (enable ? 1 : 0);
 +
-+      hg->heads = 0xff;
-+      hg->sectors = 0x3f;
-+      sector_div(cylinders, hg->heads * hg->sectors);
-+      hg->cylinders = cylinders;
-+      if ((sector_t)(hg->cylinders + 1) * hg->heads * hg->sectors < nsect)
-+              hg->cylinders = 0xffff;
 +      return 0;
 +}
 +
-+
-+/*
-+ * blkif_queue_request
-+ *
-+ * request block io
-+ *
-+ * id: for guest use only.
-+ * operation: BLKIF_OP_{READ,WRITE,PROBE}
-+ * buffer: buffer to read/write into. this should be a
-+ *   virtual address in the guest os.
-+ */
-+static int blkif_queue_request(struct request *req)
++static u32 efx_ethtool_get_rx_csum(struct net_device *net_dev)
 +{
-+      struct blkfront_info *info = req->rq_disk->private_data;
-+      unsigned long buffer_mfn;
-+      blkif_request_t *ring_req;
-+      struct bio *bio;
-+      struct bio_vec *bvec;
-+      int idx;
-+      unsigned long id;
-+      unsigned int fsect, lsect;
-+      int ref;
-+      grant_ref_t gref_head;
++      struct efx_nic *efx = net_dev->priv;
 +
-+      if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
-+              return 1;
++      return efx->rx_checksum_enabled;
++}
 +
-+      if (gnttab_alloc_grant_references(
-+              BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) {
-+              gnttab_request_free_callback(
-+                      &info->callback,
-+                      blkif_restart_queue_callback,
-+                      info,
-+                      BLKIF_MAX_SEGMENTS_PER_REQUEST);
-+              return 1;
-+      }
++static void efx_ethtool_self_test(struct net_device *net_dev,
++                                struct ethtool_test *test, u64 *data)
++{
++      struct efx_nic *efx = net_dev->priv;
++      struct efx_self_tests efx_tests;
++      int offline, already_up;
++      int rc;
 +
-+      /* Fill out a communications ring structure. */
-+      ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
-+      id = GET_ID_FROM_FREELIST(info);
-+      info->shadow[id].request = (unsigned long)req;
++      /* Make sure we've got rtnl lock since we're playing with
++       * interrupts, and calling efx_process_channel_now and others
++       */
++      ASSERT_RTNL();
 +
-+      ring_req->id = id;
-+      ring_req->sector_number = (blkif_sector_t)req->sector;
-+      ring_req->handle = info->handle;
++      /* If the NIC isn't in the RUNNING state then exit */
++      if (efx->state != STATE_RUNNING) {
++              rc = -EIO;
++              goto fail1;
++      }
 +
-+      ring_req->operation = rq_data_dir(req) ?
-+              BLKIF_OP_WRITE : BLKIF_OP_READ;
-+      if (blk_barrier_rq(req))
-+              ring_req->operation = BLKIF_OP_WRITE_BARRIER;
++      /* Make sure the interface is up. We need interrupts, NAPI
++       * and some RX buffers so this is helpful.  NB. The caller has
++       * rtnl_lock so nobody else can call dev_open. */
++      already_up = (efx->net_dev->flags & IFF_UP);
++      if (!already_up) {
++              rc = dev_open(efx->net_dev);
++              if (rc) {
++                      EFX_ERR(efx, "failed opening device.\n");
++                      goto fail2;
++              }
++      }
 +
-+      ring_req->nr_segments = 0;
-+      rq_for_each_bio (bio, req) {
-+              bio_for_each_segment (bvec, bio, idx) {
-+                      BUG_ON(ring_req->nr_segments
-+                             == BLKIF_MAX_SEGMENTS_PER_REQUEST);
-+                      buffer_mfn = page_to_phys(bvec->bv_page) >> PAGE_SHIFT;
-+                      fsect = bvec->bv_offset >> 9;
-+                      lsect = fsect + (bvec->bv_len >> 9) - 1;
-+                      /* install a grant reference. */
-+                      ref = gnttab_claim_grant_reference(&gref_head);
-+                      BUG_ON(ref == -ENOSPC);
++      memset(&efx_tests, 0, sizeof(efx_tests));
++      offline = (test->flags & ETH_TEST_FL_OFFLINE);
 +
-+                      gnttab_grant_foreign_access_ref(
-+                              ref,
-+                              info->xbdev->otherend_id,
-+                              buffer_mfn,
-+                              rq_data_dir(req) ? GTF_readonly : 0 );
++      /* Perform online self tests first */
++      rc = efx_online_test(efx, &efx_tests);
++      if (rc)
++              goto out;
 +
-+                      info->shadow[id].frame[ring_req->nr_segments] =
-+                              mfn_to_pfn(buffer_mfn);
++      /* Perform offline tests only if online tests passed */
++      if (offline) {
++              /* Stop the kernel from sending packets during the test. The
++               * selftest will be consistently bringing the port up and down
++               * as it moves between loopback modes, so the watchdog timer
++               * probably won't run anyway */
++              efx_stop_queue(efx);
 +
-+                      ring_req->seg[ring_req->nr_segments] =
-+                              (struct blkif_request_segment) {
-+                                      .gref       = ref,
-+                                      .first_sect = fsect,
-+                                      .last_sect  = lsect };
++              rc = efx_flush_queues(efx);
++              if (rc != 0)
++                      goto out_offline;
 +
-+                      ring_req->nr_segments++;
-+              }
++              rc = efx_offline_test(efx, &efx_tests,
++                                    efx->loopback_modes);
++ out_offline:
++              efx_wake_queue(efx);
 +      }
 +
-+      info->ring.req_prod_pvt++;
-+
-+      /* Keep a private copy so we can reissue requests when recovering. */
-+      info->shadow[id].req = *ring_req;
++      /* fall-thru */
++ out:
++      if (!already_up)
++              dev_close(efx->net_dev);
 +
-+      gnttab_free_grant_references(gref_head);
++      EFX_LOG(efx, "%s all %sline self-tests\n",
++              rc == 0 ? "passed" : "failed", offline ? "off" : "on");
 +
-+      return 0;
++ fail2:
++ fail1:
++      /* Fill ethtool results structures */
++      efx_ethtool_fill_self_tests(efx, &efx_tests, NULL, data);
++      if (rc)
++              test->flags |= ETH_TEST_FL_FAILED;
 +}
 +
-+/*
-+ * do_blkif_request
-+ *  read a block; request is in a request queue
-+ */
-+void do_blkif_request(request_queue_t *rq)
++/* Restart autonegotiation */
++static int efx_ethtool_nway_reset(struct net_device *net_dev)
 +{
-+      struct blkfront_info *info = NULL;
-+      struct request *req;
-+      int queued;
-+
-+      DPRINTK("Entered do_blkif_request\n");
++      struct efx_nic *efx = net_dev->priv;
 +
-+      queued = 0;
++      return mii_nway_restart(&efx->mii);
++}
 +
-+      while ((req = elv_next_request(rq)) != NULL) {
-+              info = req->rq_disk->private_data;
-+              if (!blk_fs_request(req)) {
-+                      end_request(req, 0);
-+                      continue;
-+              }
++static u32 efx_ethtool_get_link(struct net_device *net_dev)
++{
++      struct efx_nic *efx = net_dev->priv;
 +
-+              if (RING_FULL(&info->ring))
-+                      goto wait;
++      return efx->link_up;
++}
 +
-+              DPRINTK("do_blk_req %p: cmd %p, sec %llx, "
-+                      "(%u/%li) buffer:%p [%s]\n",
-+                      req, req->cmd, (long long)req->sector,
-+                      req->current_nr_sectors,
-+                      req->nr_sectors, req->buffer,
-+                      rq_data_dir(req) ? "write" : "read");
++static int efx_ethtool_get_coalesce(struct net_device *net_dev,
++                                  struct ethtool_coalesce *coalesce)
++{
++      struct efx_nic *efx = net_dev->priv;
++      struct efx_tx_queue *tx_queue;
++      struct efx_rx_queue *rx_queue;
++      struct efx_channel *channel;
 +
++      memset(coalesce, 0, sizeof(*coalesce));
 +
-+              blkdev_dequeue_request(req);
-+              if (blkif_queue_request(req)) {
-+                      blk_requeue_request(rq, req);
-+              wait:
-+                      /* Avoid pointless unplugs. */
-+                      blk_stop_queue(rq);
-+                      break;
++      /* Find lowest IRQ moderation across all used TX queues */
++      coalesce->tx_coalesce_usecs_irq = ~((u32) 0);
++      efx_for_each_tx_queue(tx_queue, efx) {
++              channel = tx_queue->channel;
++              if (channel->irq_moderation < coalesce->tx_coalesce_usecs_irq) {
++                      if (channel->used_flags != EFX_USED_BY_RX_TX)
++                              coalesce->tx_coalesce_usecs_irq =
++                                      channel->irq_moderation;
++                      else
++                              coalesce->tx_coalesce_usecs_irq = 0;
 +              }
++      }
 +
-+              queued++;
++      /* Find lowest IRQ moderation across all used RX queues */
++      coalesce->rx_coalesce_usecs_irq = ~((u32) 0);
++      efx_for_each_rx_queue(rx_queue, efx) {
++              channel = rx_queue->channel;
++              if (channel->irq_moderation < coalesce->rx_coalesce_usecs_irq)
++                      coalesce->rx_coalesce_usecs_irq =
++                              channel->irq_moderation;
 +      }
 +
-+      if (queued != 0)
-+              flush_requests(info);
++      return 0;
 +}
 +
-+
-+static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
++/* Set coalescing parameters
++ * The difficulties occur for shared channels
++ */
++static int efx_ethtool_set_coalesce(struct net_device *net_dev,
++                                  struct ethtool_coalesce *coalesce)
 +{
-+      struct request *req;
-+      blkif_response_t *bret;
-+      RING_IDX i, rp;
-+      unsigned long flags;
-+      struct blkfront_info *info = (struct blkfront_info *)dev_id;
-+      int uptodate;
++      struct efx_nic *efx = net_dev->priv;
++      struct efx_channel *channel;
++      struct efx_tx_queue *tx_queue;
++      unsigned tx_usecs, rx_usecs;
 +
-+      spin_lock_irqsave(&blkif_io_lock, flags);
++      if (coalesce->use_adaptive_rx_coalesce ||
++          coalesce->use_adaptive_tx_coalesce)
++              return -EOPNOTSUPP;
 +
-+      if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
-+              spin_unlock_irqrestore(&blkif_io_lock, flags);
-+              return IRQ_HANDLED;
++      if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
++              EFX_ERR(efx, "invalid coalescing setting. "
++                      "Only rx/tx_coalesce_usecs_irq are supported\n");
++              return -EOPNOTSUPP;
 +      }
 +
-+ again:
-+      rp = info->ring.sring->rsp_prod;
-+      rmb(); /* Ensure we see queued responses up to 'rp'. */
++      rx_usecs = coalesce->rx_coalesce_usecs_irq;
++      tx_usecs = coalesce->tx_coalesce_usecs_irq;
 +
-+      for (i = info->ring.rsp_cons; i != rp; i++) {
-+              unsigned long id;
-+              int ret;
++      /* If the channel is shared only allow RX parameters to be set */
++      efx_for_each_tx_queue(tx_queue, efx) {
++              if ((tx_queue->channel->used_flags == EFX_USED_BY_RX_TX) &&
++                  tx_usecs) {
++                      EFX_ERR(efx, "Channel is shared. "
++                              "Only RX coalescing may be set\n");
++                      return -EOPNOTSUPP;
++              }
++      }
 +
-+              bret = RING_GET_RESPONSE(&info->ring, i);
-+              id   = bret->id;
-+              req  = (struct request *)info->shadow[id].request;
++      efx_init_irq_moderation(efx, tx_usecs, rx_usecs);
 +
-+              blkif_completion(&info->shadow[id]);
++      /* Reset channel to pick up new moderation value.  Note that
++       * this may change the value of the irq_moderation field
++       * (e.g. to allow for hardware timer granularity).
++       */
++      efx_for_each_channel(channel, efx)
++              falcon_set_int_moderation(channel);
 +
-+              ADD_ID_TO_FREELIST(info, id);
++      return 0;
++}
 +
-+              uptodate = (bret->status == BLKIF_RSP_OKAY);
-+              switch (bret->operation) {
-+              case BLKIF_OP_WRITE_BARRIER:
-+                      if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
-+                              printk("blkfront: %s: write barrier op failed\n",
-+                                     info->gd->disk_name);
-+                              uptodate = -EOPNOTSUPP;
-+                              info->feature_barrier = 0;
-+                              xlvbd_barrier(info);
-+                      }
-+                      /* fall through */
-+              case BLKIF_OP_READ:
-+              case BLKIF_OP_WRITE:
-+                      if (unlikely(bret->status != BLKIF_RSP_OKAY))
-+                              DPRINTK("Bad return from blkdev data "
-+                                      "request: %x\n", bret->status);
++static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
++                                    struct ethtool_pauseparam *pause)
++{
++      struct efx_nic *efx = net_dev->priv;
++      enum efx_fc_type flow_control = efx->flow_control;
++      int rc;
 +
-+                      ret = end_that_request_first(req, uptodate,
-+                              req->hard_nr_sectors);
-+                      BUG_ON(ret);
-+                      end_that_request_last(req, uptodate);
-+                      break;
-+              default:
-+                      BUG();
-+              }
-+      }
++      flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO);
++      flow_control |= pause->rx_pause ? EFX_FC_RX : 0;
++      flow_control |= pause->tx_pause ? EFX_FC_TX : 0;
++      flow_control |= pause->autoneg ? EFX_FC_AUTO : 0;
 +
-+      info->ring.rsp_cons = i;
++      /* Try to push the pause parameters */
++      rc = efx->mac_op->set_pause(efx, flow_control);
++      if (rc)
++              return rc;
 +
-+      if (i != info->ring.req_prod_pvt) {
-+              int more_to_do;
-+              RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
-+              if (more_to_do)
-+                      goto again;
-+      } else
-+              info->ring.sring->rsp_event = i + 1;
++      /* Push the settings to the MAC */
++      efx_reconfigure_port(efx, 0);
 +
-+      kick_pending_request_queues(info);
++      return 0;
++}
 +
-+      spin_unlock_irqrestore(&blkif_io_lock, flags);
++static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
++                                     struct ethtool_pauseparam *pause)
++{
++      struct efx_nic *efx = net_dev->priv;
 +
-+      return IRQ_HANDLED;
++      pause->rx_pause = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
++      pause->tx_pause = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
++      pause->autoneg = (efx->flow_control & EFX_FC_AUTO) ? 1 : 0;
 +}
 +
-+static void blkif_free(struct blkfront_info *info, int suspend)
++
++#if defined(EFX_USE_ETHTOOL_GET_PERM_ADDR)
++static int efx_ethtool_op_get_perm_addr(struct net_device *net_dev,
++                                      struct ethtool_perm_addr *addr,
++                                      u8 *data)
 +{
-+      /* Prevent new requests being issued until we fix things up. */
-+      spin_lock_irq(&blkif_io_lock);
-+      info->connected = suspend ?
-+              BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED;
-+      /* No more blkif_request(). */
-+      if (info->rq)
-+              blk_stop_queue(info->rq);
-+      /* No more gnttab callback work. */
-+      gnttab_cancel_free_callback(&info->callback);
-+      spin_unlock_irq(&blkif_io_lock);
++      struct efx_nic *efx = net_dev->priv;
 +
-+      /* Flush gnttab callback work. Must be done with no locks held. */
-+      flush_scheduled_work();
++      memcpy(data, efx->mac_address, ETH_ALEN);
 +
-+      /* Free resources associated with old device channel. */
-+      if (info->ring_ref != GRANT_INVALID_REF) {
-+              gnttab_end_foreign_access(info->ring_ref, 
-+                                        (unsigned long)info->ring.sring);
-+              info->ring_ref = GRANT_INVALID_REF;
-+              info->ring.sring = NULL;
-+      }
-+      if (info->irq)
-+              unbind_from_irqhandler(info->irq, info);
-+      info->irq = 0;
++      return 0;
 +}
++#endif
 +
-+static void blkif_completion(struct blk_shadow *s)
-+{
-+      int i;
-+      for (i = 0; i < s->req.nr_segments; i++)
-+              gnttab_end_foreign_access(s->req.seg[i].gref, 0UL);
-+}
++struct ethtool_ops efx_ethtool_ops = {
++      .get_settings           = efx_ethtool_get_settings,
++      .set_settings           = efx_ethtool_set_settings,
++      .get_drvinfo            = efx_ethtool_get_drvinfo,
++      .nway_reset             = efx_ethtool_nway_reset,
++      .get_link               = efx_ethtool_get_link,
++      .get_coalesce           = efx_ethtool_get_coalesce,
++      .set_coalesce           = efx_ethtool_set_coalesce,
++      .get_pauseparam         = efx_ethtool_get_pauseparam,
++      .set_pauseparam         = efx_ethtool_set_pauseparam,
++      .get_rx_csum            = efx_ethtool_get_rx_csum,
++      .set_rx_csum            = efx_ethtool_set_rx_csum,
++      .get_tx_csum            = ethtool_op_get_tx_csum,
++      .set_tx_csum            = efx_ethtool_set_tx_csum,
++      .get_sg                 = ethtool_op_get_sg,
++      .set_sg                 = ethtool_op_set_sg,
++#if defined(EFX_USE_ETHTOOL_FLAGS)
++      .get_flags              = ethtool_op_get_flags,
++      .set_flags              = ethtool_op_set_flags,
++#endif
++      .self_test_count        = efx_ethtool_self_test_count,
++      .self_test              = efx_ethtool_self_test,
++      .get_strings            = efx_ethtool_get_strings,
++      .phys_id                = efx_ethtool_phys_id,
++      .get_stats_count        = efx_ethtool_get_stats_count,
++      .get_ethtool_stats      = efx_ethtool_get_stats,
++#if defined(EFX_USE_ETHTOOL_GET_PERM_ADDR)
++      .get_perm_addr          = efx_ethtool_op_get_perm_addr,
++#endif
++};
+--- linux-2.6.18.8/drivers/net/sfc/ethtool.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/ethtool.h      2008-05-19 00:33:28.841808602 +0300
+@@ -0,0 +1,44 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005:      Fen Systems Ltd.
++ * Copyright 2006:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static void blkif_recover(struct blkfront_info *info)
-+{
-+      int i;
-+      blkif_request_t *req;
-+      struct blk_shadow *copy;
-+      int j;
++#ifndef EFX_ETHTOOL_H
++#define EFX_ETHTOOL_H
 +
-+      /* Stage 1: Make a safe copy of the shadow state. */
-+      copy = kmalloc(sizeof(info->shadow), GFP_KERNEL | __GFP_NOFAIL);
-+      memcpy(copy, info->shadow, sizeof(info->shadow));
++#include "net_driver.h"
 +
-+      /* Stage 2: Set up free list. */
-+      memset(&info->shadow, 0, sizeof(info->shadow));
-+      for (i = 0; i < BLK_RING_SIZE; i++)
-+              info->shadow[i].req.id = i+1;
-+      info->shadow_free = info->ring.req_prod_pvt;
-+      info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
++/*
++ * Ethtool support
++ */
 +
-+      /* Stage 3: Find pending requests and requeue them. */
-+      for (i = 0; i < BLK_RING_SIZE; i++) {
-+              /* Not in use? */
-+              if (copy[i].request == 0)
-+                      continue;
++extern int efx_ethtool_get_settings(struct net_device *net_dev,
++                                  struct ethtool_cmd *ecmd);
++extern int efx_ethtool_set_settings(struct net_device *net_dev,
++                                  struct ethtool_cmd *ecmd);
 +
-+              /* Grab a request slot and copy shadow state into it. */
-+              req = RING_GET_REQUEST(
-+                      &info->ring, info->ring.req_prod_pvt);
-+              *req = copy[i].req;
++extern struct ethtool_ops efx_ethtool_ops;
 +
-+              /* We get a new request id, and must reset the shadow state. */
-+              req->id = GET_ID_FROM_FREELIST(info);
-+              memcpy(&info->shadow[req->id], &copy[i], sizeof(copy[i]));
++#endif /* EFX_ETHTOOL_H */
+--- linux-2.6.18.8/drivers/net/sfc/extraversion.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/extraversion.h 2008-05-19 00:33:28.841808602 +0300
+@@ -0,0 +1,4 @@
++/*
++ * If compiling on kernels with backported features you may need to
++ * define EFX_DIST_KVER_ symbols here
++ */
+--- linux-2.6.18.8/drivers/net/sfc/falcon.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/falcon.c       2008-05-19 00:33:28.845808833 +0300
+@@ -0,0 +1,3708 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+              /* Rewrite any grant references invalidated by susp/resume. */
-+              for (j = 0; j < req->nr_segments; j++)
-+                      gnttab_grant_foreign_access_ref(
-+                              req->seg[j].gref,
-+                              info->xbdev->otherend_id,
-+                              pfn_to_mfn(info->shadow[req->id].frame[j]),
-+                              rq_data_dir((struct request *)
-+                                          info->shadow[req->id].request) ?
-+                              GTF_readonly : 0);
-+              info->shadow[req->id].req = *req;
++#include <asm/io.h>
++#include <asm/bitops.h>
++#include <linux/delay.h>
++#include <linux/pci.h>
++#include <linux/module.h>
++#include <linux/seq_file.h>
++#include "net_driver.h"
++#include "bitfield.h"
++#include "efx.h"
++#include "mac.h"
++#include "gmii.h"
++#include "spi.h"
++#include "falcon.h"
++#include "falcon_hwdefs.h"
++#include "falcon_io.h"
++#include "mdio_10g.h"
++#include "phy.h"
++#include "boards.h"
++#include "driverlink.h"
++#include "workarounds.h"
 +
-+              info->ring.req_prod_pvt++;
-+      }
++/* Falcon hardware control.
++ * Falcon is the internal codename for the SFC4000 controller that is
++ * present in SFE400X evaluation boards
++ */
 +
-+      kfree(copy);
++struct falcon_nic_data {
++      /* Number of entries in each TX queue descriptor cache. */
++      unsigned tx_dc_entries;
++      /* Number of entries in each RX queue descriptor cache. */
++      unsigned rx_dc_entries;
++      /* Base address in SRAM of TX queue descriptor caches. */
++      unsigned tx_dc_base;
++      /* Base address in SRAM of RX queue descriptor caches. */
++      unsigned rx_dc_base;
 +
-+      (void)xenbus_switch_state(info->xbdev, XenbusStateConnected);
++      /* Previous loopback mode used in deconfigure_mac_wrapper */
++      enum efx_loopback_mode old_loopback_mode;
 +
-+      spin_lock_irq(&blkif_io_lock);
++      /* Driverlink parameters */
++      struct efx_dl_falcon_resources resources;
++};
 +
-+      /* Now safe for us to use the shared ring */
-+      info->connected = BLKIF_STATE_CONNECTED;
++/**************************************************************************
++ *
++ * Configurable values
++ *
++ **************************************************************************
++ */
 +
-+      /* Send off requeued requests */
-+      flush_requests(info);
++static int disable_dma_stats;
 +
-+      /* Kick any other new requests queued since we resumed */
-+      kick_pending_request_queues(info);
++/* Specify the size of the RX descriptor cache */
++static int descriptor_cache_size = 64;
 +
-+      spin_unlock_irq(&blkif_io_lock);
-+}
++/*
++ * Override EEPROM/flash type from non-volatile configuration or GPIO;
++ * may need to be specified if bootstrapping from blank flash.
++ */
++static unsigned int eeprom_type = -1;
++static unsigned int flash_type = -1;
 +
-+int blkfront_is_ready(struct xenbus_device *dev)
-+{
-+      struct blkfront_info *info = dev->dev.driver_data;
++/* RX FIFO XOFF watermark
++ *
++ * When the amount of the RX FIFO increases used increases past this
++ * watermark send XOFF. Only used if RX flow control is enabled (ethtool -A)
++ * This also has an effect on RX/TX arbitration
++ */
++static int rx_xoff_thresh_bytes = -1;
++module_param(rx_xoff_thresh_bytes, int, 0644);
++MODULE_PARM_DESC(rx_xoff_thresh_bytes, "RX fifo XOFF threshold");
 +
-+      return info->is_ready;
-+}
++/* RX FIFO XON watermark
++ *
++ * When the amount of the RX FIFO used decreases below this
++ * watermark send XON. Only used if TX flow control is enabled (ethtool -A)
++ * This also has an effect on RX/TX arbitration
++ */
++static int rx_xon_thresh_bytes = -1;
++module_param(rx_xon_thresh_bytes, int, 0644);
++MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
 +
++/* TX descriptor ring size - min 512 max 4k */
++#define FALCON_TXD_RING_ORDER TX_DESCQ_SIZE_1K
++#define FALCON_TXD_RING_SIZE 1024
++#define FALCON_TXD_RING_MASK (FALCON_TXD_RING_SIZE - 1)
 +
-+/* ** Driver Registration ** */
++/* RX descriptor ring size - min 512 max 4k */
++#define FALCON_RXD_RING_ORDER RX_DESCQ_SIZE_1K
++#define FALCON_RXD_RING_SIZE 1024
++#define FALCON_RXD_RING_MASK (FALCON_RXD_RING_SIZE - 1)
 +
++/* Event queue size - max 32k */
++#define FALCON_EVQ_ORDER EVQ_SIZE_4K
++#define FALCON_EVQ_SIZE 4096
++#define FALCON_EVQ_MASK (FALCON_EVQ_SIZE - 1)
 +
-+static struct xenbus_device_id blkfront_ids[] = {
-+      { "vbd" },
-+      { "" }
-+};
-+MODULE_ALIAS("xen:vbd");
++/* Max number of internal errors. After this resets will not be performed */
++#define FALCON_MAX_INT_ERRORS 4
 +
-+static struct xenbus_driver blkfront = {
-+      .name = "vbd",
-+      .owner = THIS_MODULE,
-+      .ids = blkfront_ids,
-+      .probe = blkfront_probe,
-+      .remove = blkfront_remove,
-+      .resume = blkfront_resume,
-+      .otherend_changed = backend_changed,
-+      .is_ready = blkfront_is_ready,
-+};
++/* Maximum period that we wait for flush events. If the flush event
++ * doesn't arrive in this period of time then we check if the queue
++ * was disabled anyway. */
++#define FALCON_FLUSH_TIMEOUT 10 /* 10ms */
 +
++/**************************************************************************
++ *
++ * Falcon constants
++ *
++ **************************************************************************
++ */
 +
-+static int __init xlblk_init(void)
-+{
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++/* DMA address mask (up to 46-bit, avoiding compiler warnings)
++ *
++ * Note that it is possible to have a platform with 64-bit longs and
++ * 32-bit DMA addresses, or vice versa.  EFX_DMA_MASK takes care of the
++ * platform DMA mask.
++ */
++#if BITS_PER_LONG == 64
++#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffUL)
++#else
++#define FALCON_DMA_MASK EFX_DMA_MASK(0x00003fffffffffffULL)
++#endif
 +
-+      return xenbus_register_frontend(&blkfront);
-+}
-+module_init(xlblk_init);
++/* TX DMA length mask (13-bit) */
++#define FALCON_TX_DMA_MASK (8192 - 1)
 +
++/* Alignment of special buffers (4KB) */
++#define FALCON_BUF_ALIGN 4096
 +
-+static void __exit xlblk_exit(void)
++/* Dummy SRAM size code */
++#define SRM_NB_BSZ_ONCHIP_ONLY (-1)
++
++/* Be nice if these (or equiv.) were in linux/pci_regs.h, but they're not. */
++#define PCI_EXP_DEVCAP_PWR_VAL_LBN    (18)
++/* This field takes up bits 26 and 27. */
++#define PCI_EXP_DEVCAP_PWR_SCL_LBN    (26)
++#define PCI_EXP_LNKSTA_LNK_WID                (0x3f0)
++#define PCI_EXP_LNKSTA_LNK_WID_LBN    (4)
++
++
++/**************************************************************************
++ *
++ * Falcon hardware access
++ *
++ **************************************************************************/
++
++/* Read the current event from the event queue */
++static inline efx_qword_t *falcon_event(struct efx_channel *channel,
++                                      unsigned int index)
 +{
-+      return xenbus_unregister_driver(&blkfront);
++      return (((efx_qword_t *) (channel->eventq.addr)) + index);
 +}
-+module_exit(xlblk_exit);
 +
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blkfront/block.h linux-2.6.18-xen.hg/drivers/xen/blkfront/block.h
---- linux-2.6.18/drivers/xen/blkfront/block.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blkfront/block.h   2007-12-23 11:15:33.544575492 +0100
-@@ -0,0 +1,143 @@
-+/******************************************************************************
-+ * block.h
-+ * 
-+ * Shared definitions between all levels of XenLinux Virtual block devices.
-+ * 
-+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
-+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
-+ * Copyright (c) 2004-2005, Christian Limpach
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++/* See if an event is present
++ *
++ * We check both the high and low dword of the event for all ones.  We
++ * wrote all ones when we cleared the event, and no valid event can
++ * have all ones in either its high or low dwords.  This approach is
++ * robust against reordering.
++ *
++ * Note that using a single 64-bit comparison is incorrect; even
++ * though the CPU read will be atomic, the DMA write may not be.
 + */
++static inline int falcon_event_present(efx_qword_t *event)
++{
++      return (!(EFX_DWORD_IS_ALL_ONES(event->dword[0]) |
++                EFX_DWORD_IS_ALL_ONES(event->dword[1])));
++}
 +
-+#ifndef __XEN_DRIVERS_BLOCK_H__
-+#define __XEN_DRIVERS_BLOCK_H__
-+
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+#include <linux/errno.h>
-+#include <linux/fs.h>
-+#include <linux/hdreg.h>
-+#include <linux/blkdev.h>
-+#include <linux/major.h>
-+#include <asm/hypervisor.h>
-+#include <xen/xenbus.h>
-+#include <xen/gnttab.h>
-+#include <xen/interface/xen.h>
-+#include <xen/interface/io/blkif.h>
-+#include <xen/interface/io/ring.h>
-+#include <asm/io.h>
-+#include <asm/atomic.h>
-+#include <asm/uaccess.h>
++/* Read dword from a Falcon PCIE core register */
++static void falcon_pcie_core_read_reg(struct efx_nic *efx, int address,
++                                    efx_dword_t *result)
++{
++      efx_oword_t temp;
 +
-+#define DPRINTK(_f, _a...) pr_debug(_f, ## _a)
++      BUG_ON(FALCON_REV(efx) < FALCON_REV_B0);
++      BUG_ON(address & 3 || address < 0);
 +
-+#if 0
-+#define DPRINTK_IOCTL(_f, _a...) printk(KERN_ALERT _f, ## _a)
-+#else
-+#define DPRINTK_IOCTL(_f, _a...) ((void)0)
-+#endif
++      EFX_POPULATE_OWORD_1(temp, PCIE_CORE_ADDR, address);
 +
-+struct xlbd_type_info
-+{
-+      int partn_shift;
-+      int disks_per_major;
-+      char *devname;
-+      char *diskname;
-+};
++      falcon_write(efx, &temp, PCIE_CORE_INDIRECT_REG);
++      falcon_read(efx, &temp, PCIE_CORE_INDIRECT_REG);
++      /* Extract PCIE_CORE_VALUE without byte-swapping */
++      BUILD_BUG_ON(PCIE_CORE_VALUE_LBN != 32 ||
++                   PCIE_CORE_VALUE_WIDTH != 32);
++      result->u32[0] = temp.u32[1];
++}
 +
-+struct xlbd_major_info
++/* Write dword to a Falcon PCIE core register */
++static void falcon_pcie_core_write_reg(struct efx_nic *efx, int address,
++                                     efx_dword_t value)
 +{
-+      int major;
-+      int index;
-+      int usage;
-+      struct xlbd_type_info *type;
-+};
++      efx_oword_t temp;
 +
-+struct blk_shadow {
-+      blkif_request_t req;
-+      unsigned long request;
-+      unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
-+};
++      BUG_ON(FALCON_REV(efx) < FALCON_REV_B0);
++      BUG_ON(address & 0x3 || address < 0);
 +
-+#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE)
++      EFX_POPULATE_OWORD_2(temp,
++                           PCIE_CORE_ADDR, address,
++                           PCIE_CORE_RW, 1);
++      /* Fill PCIE_CORE_VALUE without byte-swapping */
++      BUILD_BUG_ON(PCIE_CORE_VALUE_LBN != 32 ||
++                   PCIE_CORE_VALUE_WIDTH != 32);
++      temp.u32[1] = value.u32[0];
++      falcon_write(efx, &temp, PCIE_CORE_INDIRECT_REG);
++}
 +
-+/*
-+ * We have one of these per vbd, whether ide, scsi or 'other'.  They
-+ * hang in private_data off the gendisk structure. We may end up
-+ * putting all kinds of interesting stuff here :-)
++/**************************************************************************
++ *
++ * I2C bus - this is a bit-bashing interface using GPIO pins
++ * Note that it uses the output enables to tristate the outputs
++ * SDA is the data pin and SCL is the clock
++ *
++ **************************************************************************
 + */
-+struct blkfront_info
++static void falcon_setsdascl(struct efx_i2c_interface *i2c)
 +{
-+      struct xenbus_device *xbdev;
-+      dev_t dev;
-+      struct gendisk *gd;
-+      int vdevice;
-+      blkif_vdev_t handle;
-+      int connected;
-+      int ring_ref;
-+      blkif_front_ring_t ring;
-+      unsigned int irq;
-+      struct xlbd_major_info *mi;
-+      request_queue_t *rq;
-+      struct work_struct work;
-+      struct gnttab_free_callback callback;
-+      struct blk_shadow shadow[BLK_RING_SIZE];
-+      unsigned long shadow_free;
-+      int feature_barrier;
-+      int is_ready;
++      efx_oword_t reg;
 +
-+      /**
-+       * The number of people holding this device open.  We won't allow a
-+       * hot-unplug unless this is 0.
-+       */
-+      int users;
-+};
++      falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
++      EFX_SET_OWORD_FIELD(reg, GPIO0_OEN, (i2c->scl ? 0 : 1));
++      EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, (i2c->sda ? 0 : 1));
++      falcon_write(i2c->efx, &reg, GPIO_CTL_REG_KER);
++}
 +
-+extern spinlock_t blkif_io_lock;
++static int falcon_getsda(struct efx_i2c_interface *i2c)
++{
++      efx_oword_t reg;
 +
-+extern int blkif_open(struct inode *inode, struct file *filep);
-+extern int blkif_release(struct inode *inode, struct file *filep);
-+extern int blkif_ioctl(struct inode *inode, struct file *filep,
-+                     unsigned command, unsigned long argument);
-+extern int blkif_getgeo(struct block_device *, struct hd_geometry *);
-+extern int blkif_check(dev_t dev);
-+extern int blkif_revalidate(dev_t dev);
-+extern void do_blkif_request (request_queue_t *rq);
++      falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
++      return EFX_OWORD_FIELD(reg, GPIO3_IN);
++}
 +
-+/* Virtual block-device subsystem. */
-+/* Note that xlvbd_add doesn't call add_disk for you: you're expected
-+   to call add_disk on info->gd once the disk is properly connected
-+   up. */
-+int xlvbd_add(blkif_sector_t capacity, int device,
-+            u16 vdisk_info, u16 sector_size, struct blkfront_info *info);
-+void xlvbd_del(struct blkfront_info *info);
-+int xlvbd_barrier(struct blkfront_info *info);
++static int falcon_getscl(struct efx_i2c_interface *i2c)
++{
++      efx_oword_t reg;
 +
-+#endif /* __XEN_DRIVERS_BLOCK_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blkfront/Makefile linux-2.6.18-xen.hg/drivers/xen/blkfront/Makefile
---- linux-2.6.18/drivers/xen/blkfront/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blkfront/Makefile  2007-12-23 11:15:33.544575492 +0100
-@@ -0,0 +1,5 @@
++      falcon_read(i2c->efx, &reg, GPIO_CTL_REG_KER);
++      return EFX_DWORD_FIELD(reg, GPIO0_IN);
++}
 +
-+obj-$(CONFIG_XEN_BLKDEV_FRONTEND)     := xenblk.o
++static struct efx_i2c_bit_operations falcon_i2c_bit_operations = {
++      .setsda         = falcon_setsdascl,
++      .setscl         = falcon_setsdascl,
++      .getsda         = falcon_getsda,
++      .getscl         = falcon_getscl,
++      .udelay         = 100,
++      .mdelay         = 10,
++};
 +
-+xenblk-objs := blkfront.o vbd.o
++/**************************************************************************
++ *
++ * Falcon special buffer handling
++ * Special buffers are used for event queues and the TX and RX
++ * descriptor rings.
++ *
++ *************************************************************************/
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blkfront/vbd.c linux-2.6.18-xen.hg/drivers/xen/blkfront/vbd.c
---- linux-2.6.18/drivers/xen/blkfront/vbd.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blkfront/vbd.c     2007-12-23 11:15:33.544575492 +0100
-@@ -0,0 +1,375 @@
-+/******************************************************************************
-+ * vbd.c
-+ * 
-+ * XenLinux virtual block-device driver (xvd).
-+ * 
-+ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
-+ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
-+ * Copyright (c) 2004-2005, Christian Limpach
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
++/* Adds the relevant entries to the full-mode buffer table. */
++static int
++falcon_pin_special_buffer_full(struct efx_nic *efx,
++                             struct efx_special_buffer *buffer)
++{
++      efx_qword_t buf_desc;
++      int index;
++      dma_addr_t dma_addr;
++      int i;
 +
-+#include "block.h"
-+#include <linux/blkdev.h>
-+#include <linux/list.h>
++      /* Write buffer descriptors to NIC */
++      for (i = 0; i < buffer->entries; i++) {
++              index = buffer->index + i;
++              dma_addr = buffer->dma_addr + (i * 4096);
++              EFX_LOG(efx, "mapping special buffer %d at %llx\n",
++                      index, (unsigned long long)dma_addr);
++              EFX_POPULATE_QWORD_4(buf_desc,
++                                   IP_DAT_BUF_SIZE, IP_DAT_BUF_SIZE_4K,
++                                   BUF_ADR_REGION, 0,
++                                   BUF_ADR_FBUF, (dma_addr >> 12),
++                                   BUF_OWNER_ID_FBUF, 0);
++              falcon_write_sram(efx, &buf_desc, index);
++      }
 +
-+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
-+#include <xen/platform-compat.h>
-+#endif
++      return 0;
++}
 +
-+#define BLKIF_MAJOR(dev) ((dev)>>8)
-+#define BLKIF_MINOR(dev) ((dev) & 0xff)
++/* Clears the relevant entries from the buffer table */
++static void
++falcon_clear_special_buffer_full(struct efx_nic *efx,
++                               struct efx_special_buffer *buffer)
++{
++      efx_oword_t buf_tbl_upd;
++      unsigned int start = buffer->index;
++      unsigned int end = (buffer->index + buffer->entries - 1);
 +
-+/*
-+ * For convenience we distinguish between ide, scsi and 'other' (i.e.,
-+ * potentially combinations of the two) in the naming scheme and in a few other
-+ * places.
-+ */
++      EFX_LOG(efx, "unmapping special buffers %d-%d\n",
++              buffer->index, buffer->index + buffer->entries - 1);
 +
-+#define NUM_IDE_MAJORS 10
-+#define NUM_SCSI_MAJORS 17
-+#define NUM_VBD_MAJORS 1
++      EFX_POPULATE_OWORD_4(buf_tbl_upd,
++                           BUF_UPD_CMD, 0,
++                           BUF_CLR_CMD, 1,
++                           BUF_CLR_END_ID, end,
++                           BUF_CLR_START_ID, start);
++      falcon_write(efx, &buf_tbl_upd, BUF_TBL_UPD_REG_KER);
++}
 +
-+static struct xlbd_type_info xlbd_ide_type = {
-+      .partn_shift = 6,
-+      .disks_per_major = 2,
-+      .devname = "ide",
-+      .diskname = "hd",
-+};
++/*
++ * Allocate a new Falcon special buffer
++ *
++ * This allocates memory for a new buffer, clears it and allocates a
++ * new buffer ID range.  It does not write into Falcon's buffer table.
++ *
++ * This call will allocate 4kB buffers, since Falcon can't use 8kB
++ * buffers for event queues and descriptor rings.  It will always
++ * allocate an even number of 4kB buffers, since when we're in
++ * half-entry mode for the buffer table we can only deal with pairs of
++ * buffers.
++ */
++static int falcon_alloc_special_buffer(struct efx_nic *efx,
++                                     struct efx_special_buffer *buffer,
++                                     unsigned int len)
++{
++      struct falcon_nic_data *nic_data = efx->nic_data;
 +
-+static struct xlbd_type_info xlbd_scsi_type = {
-+      .partn_shift = 4,
-+      .disks_per_major = 16,
-+      .devname = "sd",
-+      .diskname = "sd",
-+};
++      /* Round size up to an 8kB boundary (i.e. pairs of 4kB buffers) */
++      len = (len + 8192 - 1) & ~(8192 - 1);
 +
-+static struct xlbd_type_info xlbd_vbd_type = {
-+      .partn_shift = 4,
-+      .disks_per_major = 16,
-+      .devname = "xvd",
-+      .diskname = "xvd",
-+};
++      /* Allocate buffer as consistent PCI DMA space */
++      buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
++                                          &buffer->dma_addr);
++      if (!buffer->addr)
++              return -ENOMEM;
++      buffer->len = len;
++      buffer->entries = len / 4096;
++      BUG_ON(buffer->dma_addr & (FALCON_BUF_ALIGN - 1));
 +
-+static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS +
-+                                       NUM_VBD_MAJORS];
++      /* All zeros is a potentially valid event so memset to 0xff */
++      memset(buffer->addr, 0xff, len);
 +
-+#define XLBD_MAJOR_IDE_START  0
-+#define XLBD_MAJOR_SCSI_START (NUM_IDE_MAJORS)
-+#define XLBD_MAJOR_VBD_START  (NUM_IDE_MAJORS + NUM_SCSI_MAJORS)
++      /* Select new buffer ID */
++      buffer->index = nic_data->resources.buffer_table_min;
++      nic_data->resources.buffer_table_min += buffer->entries;
 +
-+#define XLBD_MAJOR_IDE_RANGE  XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SCSI_START - 1
-+#define XLBD_MAJOR_SCSI_RANGE XLBD_MAJOR_SCSI_START ... XLBD_MAJOR_VBD_START - 1
-+#define XLBD_MAJOR_VBD_RANGE  XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START + NUM_VBD_MAJORS - 1
++      EFX_LOG(efx, "allocating special buffers %d-%d at %llx+%x "
++              "(virt %p phys %lx)\n", buffer->index,
++              buffer->index + buffer->entries - 1,
++              (unsigned long long)buffer->dma_addr, len,
++              buffer->addr, virt_to_phys(buffer->addr));
 +
-+/* Information about our VBDs. */
-+#define MAX_VBDS 64
-+static LIST_HEAD(vbds_list);
++      return 0;
++}
 +
-+static struct block_device_operations xlvbd_block_fops =
++/*
++ * Initialise a Falcon special buffer
++ *
++ * This will define a buffer (previously allocated via
++ * falcon_alloc_special_buffer()) in Falcon's buffer table, allowing
++ * it to be used for event queues, descriptor rings etc.
++ */
++static int falcon_init_special_buffer(struct efx_nic *efx,
++                                    struct efx_special_buffer *buffer)
 +{
-+      .owner = THIS_MODULE,
-+      .open = blkif_open,
-+      .release = blkif_release,
-+      .ioctl  = blkif_ioctl,
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
-+      .getgeo = blkif_getgeo
-+#endif
-+};
++      EFX_BUG_ON_PARANOID(!buffer->addr);
 +
-+DEFINE_SPINLOCK(blkif_io_lock);
++      /* Write buffer descriptors to NIC */
++      return falcon_pin_special_buffer_full(efx, buffer);
++}
 +
-+static struct xlbd_major_info *
-+xlbd_alloc_major_info(int major, int minor, int index)
++/* Unmaps a buffer from Falcon and clears the buffer table
++ * entries */
++static void falcon_fini_special_buffer(struct efx_nic *efx,
++                                     struct efx_special_buffer *buffer)
 +{
-+      struct xlbd_major_info *ptr;
 +
-+      ptr = kzalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
-+      if (ptr == NULL)
-+              return NULL;
++      if (!buffer->entries)
++              return;
 +
-+      ptr->major = major;
++      falcon_clear_special_buffer_full(efx, buffer);
++}
 +
-+      switch (index) {
-+      case XLBD_MAJOR_IDE_RANGE:
-+              ptr->type = &xlbd_ide_type;
-+              ptr->index = index - XLBD_MAJOR_IDE_START;
-+              break;
-+      case XLBD_MAJOR_SCSI_RANGE:
-+              ptr->type = &xlbd_scsi_type;
-+              ptr->index = index - XLBD_MAJOR_SCSI_START;
-+              break;
-+      case XLBD_MAJOR_VBD_RANGE:
-+              ptr->type = &xlbd_vbd_type;
-+              ptr->index = index - XLBD_MAJOR_VBD_START;
-+              break;
-+      }
++/* Release the buffer memory. */
++static void falcon_free_special_buffer(struct efx_nic *efx,
++                                     struct efx_special_buffer *buffer)
++{
++      if (!buffer->addr)
++              return;
 +
-+      if (register_blkdev(ptr->major, ptr->type->devname)) {
-+              kfree(ptr);
-+              return NULL;
-+      }
++      EFX_LOG(efx, "deallocating special buffers %d-%d at %llx+%x "
++              "(virt %p phys %lx)\n", buffer->index,
++              buffer->index + buffer->entries - 1,
++              (unsigned long long)buffer->dma_addr, buffer->len,
++              buffer->addr, virt_to_phys(buffer->addr));
 +
-+      printk("xen-vbd: registered block device major %i\n", ptr->major);
-+      major_info[index] = ptr;
-+      return ptr;
++      pci_free_consistent(efx->pci_dev, buffer->len, buffer->addr,
++                          buffer->dma_addr);
++      buffer->addr = NULL;
++      buffer->entries = 0;
 +}
 +
-+static struct xlbd_major_info *
-+xlbd_get_major_info(int vdevice)
-+{
-+      struct xlbd_major_info *mi;
-+      int major, minor, index;
++/**************************************************************************
++ *
++ * Falcon generic buffer handling
++ * These buffers are used for interrupt status and MAC stats
++ *
++ **************************************************************************/
 +
-+      major = BLKIF_MAJOR(vdevice);
-+      minor = BLKIF_MINOR(vdevice);
++static int falcon_alloc_buffer(struct efx_nic *efx,
++                             struct efx_buffer *buffer, unsigned int len)
++{
++      buffer->addr = pci_alloc_consistent(efx->pci_dev, len,
++                                          &buffer->dma_addr);
++      if (!buffer->addr)
++              return -ENOMEM;
++      buffer->len = len;
++      memset(buffer->addr, 0, len);
++      return 0;
++}
 +
-+      switch (major) {
-+      case IDE0_MAJOR: index = 0; break;
-+      case IDE1_MAJOR: index = 1; break;
-+      case IDE2_MAJOR: index = 2; break;
-+      case IDE3_MAJOR: index = 3; break;
-+      case IDE4_MAJOR: index = 4; break;
-+      case IDE5_MAJOR: index = 5; break;
-+      case IDE6_MAJOR: index = 6; break;
-+      case IDE7_MAJOR: index = 7; break;
-+      case IDE8_MAJOR: index = 8; break;
-+      case IDE9_MAJOR: index = 9; break;
-+      case SCSI_DISK0_MAJOR: index = 10; break;
-+      case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
-+              index = 11 + major - SCSI_DISK1_MAJOR;
-+              break;
-+        case SCSI_DISK8_MAJOR ... SCSI_DISK15_MAJOR:
-+                index = 18 + major - SCSI_DISK8_MAJOR;
-+                break;
-+        case SCSI_CDROM_MAJOR: index = 26; break;
-+        default: index = 27; break;
++static void falcon_free_buffer(struct efx_nic *efx, struct efx_buffer *buffer)
++{
++      if (buffer->addr) {
++              pci_free_consistent(efx->pci_dev, buffer->len,
++                                  buffer->addr, buffer->dma_addr);
++              buffer->addr = NULL;
 +      }
-+
-+      mi = ((major_info[index] != NULL) ? major_info[index] :
-+            xlbd_alloc_major_info(major, minor, index));
-+      if (mi)
-+              mi->usage++;
-+      return mi;
 +}
 +
-+static void
-+xlbd_put_major_info(struct xlbd_major_info *mi)
++/**************************************************************************
++ *
++ * Falcon TX path
++ *
++ **************************************************************************/
++
++/* Returns a pointer to the specified transmit descriptor in the TX
++ * descriptor queue belonging to the specified channel.
++ */
++static inline efx_qword_t *falcon_tx_desc(struct efx_tx_queue *tx_queue,
++                                             unsigned int index)
 +{
-+      mi->usage--;
-+      /* XXX: release major if 0 */
++      return (((efx_qword_t *) (tx_queue->txd.addr)) + index);
 +}
 +
-+static int
-+xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
++/* Update TX descriptor write pointer
++ * This writes to the TX_DESC_WPTR register for the specified
++ * channel's transmit descriptor ring.
++ */
++static inline void falcon_notify_tx_desc(struct efx_tx_queue *tx_queue)
 +{
-+      request_queue_t *rq;
++      unsigned write_ptr;
++      efx_dword_t reg;
 +
-+      rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
-+      if (rq == NULL)
-+              return -1;
++      write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK;
++      EFX_POPULATE_DWORD_1(reg, TX_DESC_WPTR_DWORD, write_ptr);
++      falcon_writel_page(tx_queue->efx, &reg,
++                         TX_DESC_UPD_REG_KER_DWORD, tx_queue->queue);
++}
 +
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
-+      elevator_init(rq, "noop");
++
++/* For each entry inserted into the software descriptor ring, create a
++ * descriptor in the hardware TX descriptor ring (in host memory), and
++ * write a doorbell.
++ */
++#if defined(EFX_USE_FASTCALL)
++void fastcall falcon_push_buffers(struct efx_tx_queue *tx_queue)
 +#else
-+      elevator_init(rq, &elevator_noop);
++void falcon_push_buffers(struct efx_tx_queue *tx_queue)
 +#endif
++{
 +
-+      /* Hard sector size and max sectors impersonate the equiv. hardware. */
-+      blk_queue_hardsect_size(rq, sector_size);
-+      blk_queue_max_sectors(rq, 512);
++      struct efx_tx_buffer *buffer;
++      efx_qword_t *txd;
++      unsigned write_ptr;
 +
-+      /* Each segment in a request is up to an aligned page in size. */
-+      blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
-+      blk_queue_max_segment_size(rq, PAGE_SIZE);
++      BUG_ON(tx_queue->write_count == tx_queue->insert_count);
 +
-+      /* Ensure a merged request will fit in a single I/O ring slot. */
-+      blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
-+      blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
++      do {
++              write_ptr = tx_queue->write_count & FALCON_TXD_RING_MASK;
++              buffer = &tx_queue->buffer[write_ptr];
++              txd = falcon_tx_desc(tx_queue, write_ptr);
++              ++tx_queue->write_count;
 +
-+      /* Make sure buffer addresses are sector-aligned. */
-+      blk_queue_dma_alignment(rq, 511);
++              /* Create TX descriptor ring entry */
++              EFX_POPULATE_QWORD_5(*txd,
++                                   TX_KER_PORT, 0,
++                                   TX_KER_CONT, buffer->continuation,
++                                   TX_KER_BYTE_CNT, buffer->len,
++                                   TX_KER_BUF_REGION, 0,
++                                   TX_KER_BUF_ADR, buffer->dma_addr);
++      } while (tx_queue->write_count != tx_queue->insert_count);
 +
-+      /* Make sure we don't use bounce buffers. */
-+      blk_queue_bounce_limit(rq, BLK_BOUNCE_ANY);
++      wmb(); /* Ensure descriptors are written before they are fetched */
++      falcon_notify_tx_desc(tx_queue);
++}
 +
-+      gd->queue = rq;
++/* Allocate hardware resources for a TX queue */
++int falcon_probe_tx(struct efx_tx_queue *tx_queue)
++{
++      struct efx_nic *efx = tx_queue->efx;
++      struct falcon_nic_data *nic_data = efx->nic_data;
++      int rc;
++
++      rc = falcon_alloc_special_buffer(efx, &tx_queue->txd,
++                                       FALCON_TXD_RING_SIZE *
++                                       sizeof(efx_qword_t));
++      if (rc)
++              return rc;
++
++      nic_data->resources.txq_min = max(nic_data->resources.txq_min,
++                                        (unsigned)tx_queue->queue + 1);
 +
 +      return 0;
 +}
 +
-+static int
-+xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
-+                  u16 vdisk_info, u16 sector_size,
-+                  struct blkfront_info *info)
++/* Prepare channel's TX datapath. */
++int falcon_init_tx(struct efx_tx_queue *tx_queue)
 +{
-+      struct gendisk *gd;
-+      struct xlbd_major_info *mi;
-+      int nr_minors = 1;
-+      int err = -ENODEV;
-+      unsigned int offset;
++      efx_oword_t tx_desc_ptr;
++      struct efx_nic *efx = tx_queue->efx;
++      int rc;
 +
-+      BUG_ON(info->gd != NULL);
-+      BUG_ON(info->mi != NULL);
-+      BUG_ON(info->rq != NULL);
++      /* Pin TX descriptor ring */
++      rc = falcon_init_special_buffer(efx, &tx_queue->txd);
++      if (rc)
++              return rc;
 +
-+      mi = xlbd_get_major_info(vdevice);
-+      if (mi == NULL)
-+              goto out;
-+      info->mi = mi;
++      /* Push TX descriptor ring to card */
++      EFX_POPULATE_OWORD_10(tx_desc_ptr,
++                            TX_DESCQ_EN, 1,
++                            TX_ISCSI_DDIG_EN, 0,
++                            TX_ISCSI_HDIG_EN, 0,
++                            TX_DESCQ_BUF_BASE_ID, tx_queue->txd.index,
++                            TX_DESCQ_EVQ_ID, tx_queue->channel->evqnum,
++                            TX_DESCQ_OWNER_ID, 0,
++                            TX_DESCQ_LABEL, tx_queue->queue,
++                            TX_DESCQ_SIZE, FALCON_TXD_RING_ORDER,
++                            TX_DESCQ_TYPE, 0, /* kernel queue */
++                            TX_NON_IP_DROP_DIS_B0, 1);
++
++      if (FALCON_REV(efx) >= FALCON_REV_B0) {
++              int csum = !(efx->net_dev->features & NETIF_F_IP_CSUM);
++              EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_IP_CHKSM_DIS_B0, csum);
++              EFX_SET_OWORD_FIELD(tx_desc_ptr, TX_TCP_CHKSM_DIS_B0, csum);
++      }
++
++      falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
++                         tx_queue->queue);
++
++      if (FALCON_REV(efx) < FALCON_REV_B0) {
++              efx_oword_t reg;
++
++              /* Only 128 bits in this register */
++              BUG_ON(tx_queue->queue >= 128);
++
++              falcon_read(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
++              if (efx->net_dev->features & NETIF_F_IP_CSUM)
++                      clear_bit_le(tx_queue->queue, (void *)&reg);
++              else
++                      set_bit_le(tx_queue->queue, (void *)&reg);
++              falcon_write(efx, &reg, TX_CHKSM_CFG_REG_KER_A1);
++      }
 +
-+      if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
-+              nr_minors = 1 << mi->type->partn_shift;
++      return 0;
++}
 +
-+      gd = alloc_disk(nr_minors);
-+      if (gd == NULL)
-+              goto out;
++static int falcon_flush_tx_queue(struct efx_tx_queue *tx_queue)
++{
++      struct efx_nic *efx = tx_queue->efx;
++      struct efx_channel *channel = &efx->channel[0];
++      efx_oword_t tx_flush_descq;
++      unsigned int read_ptr, i;
 +
-+      offset =  mi->index * mi->type->disks_per_major +
-+                      (minor >> mi->type->partn_shift);
-+      if (nr_minors > 1) {
-+              if (offset < 26) {
-+                      sprintf(gd->disk_name, "%s%c",
-+                               mi->type->diskname, 'a' + offset );
-+              }
-+              else {
-+                      sprintf(gd->disk_name, "%s%c%c",
-+                              mi->type->diskname,
-+                              'a' + ((offset/26)-1), 'a' + (offset%26) );
-+              }
-+      }
-+      else {
-+              if (offset < 26) {
-+                      sprintf(gd->disk_name, "%s%c%d",
-+                              mi->type->diskname,
-+                              'a' + offset,
-+                              minor & ((1 << mi->type->partn_shift) - 1));
-+              }
-+              else {
-+                      sprintf(gd->disk_name, "%s%c%c%d",
-+                              mi->type->diskname,
-+                              'a' + ((offset/26)-1), 'a' + (offset%26),
-+                              minor & ((1 << mi->type->partn_shift) - 1));
++      /* Post a flush command */
++      EFX_POPULATE_OWORD_2(tx_flush_descq,
++                           TX_FLUSH_DESCQ_CMD, 1,
++                           TX_FLUSH_DESCQ, tx_queue->queue);
++      falcon_write(efx, &tx_flush_descq, TX_FLUSH_DESCQ_REG_KER);
++      msleep(FALCON_FLUSH_TIMEOUT);
++
++      /* If the NIC is resetting then don't bother checking */
++      if (EFX_WORKAROUND_7803(efx) || (efx->state == STATE_RESETTING))
++              return 0;
++
++      /* Look for a flush completed event */
++      read_ptr = channel->eventq_read_ptr;
++      for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
++              efx_qword_t *event = falcon_event(channel, read_ptr);
++              int ev_code, ev_sub_code, ev_queue;
++              if (!falcon_event_present(event))
++                      break;
++
++              ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
++              ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
++              ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_TX_DESCQ_ID);
++              if ((ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) &&
++                  (ev_queue == tx_queue->queue)) {
++                      EFX_LOG(efx, "tx queue %d flush command succesful\n",
++                              tx_queue->queue);
++                      return 0;
 +              }
++
++              read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
 +      }
 +
-+      gd->major = mi->major;
-+      gd->first_minor = minor;
-+      gd->fops = &xlvbd_block_fops;
-+      gd->private_data = info;
-+      gd->driverfs_dev = &(info->xbdev->dev);
-+      set_capacity(gd, capacity);
++      if (EFX_WORKAROUND_11557(efx)) {
++              efx_oword_t reg;
++              int enabled;
 +
-+      if (xlvbd_init_blk_queue(gd, sector_size)) {
-+              del_gendisk(gd);
-+              goto out;
++              falcon_read_table(efx, &reg, efx->type->txd_ptr_tbl_base,
++                                tx_queue->queue);
++              enabled = EFX_OWORD_FIELD(reg, TX_DESCQ_EN);
++              if (!enabled) {
++                      EFX_LOG(efx, "tx queue %d disabled without a "
++                              "flush event seen\n", tx_queue->queue);
++                      return 0;
++              }
 +      }
 +
-+      info->rq = gd->queue;
-+      info->gd = gd;
++      EFX_ERR(efx, "tx queue %d flush command timed out\n", tx_queue->queue);
++      return -ETIMEDOUT;
++}
 +
-+      if (info->feature_barrier)
-+              xlvbd_barrier(info);
++void falcon_fini_tx(struct efx_tx_queue *tx_queue)
++{
++      struct efx_nic *efx = tx_queue->efx;
++      efx_oword_t tx_desc_ptr;
 +
-+      if (vdisk_info & VDISK_READONLY)
-+              set_disk_ro(gd, 1);
++      /* Stop the hardware using the queue */
++      if (falcon_flush_tx_queue(tx_queue))
++              EFX_ERR(efx, "failed to flush tx queue %d\n", tx_queue->queue);
 +
-+      if (vdisk_info & VDISK_REMOVABLE)
-+              gd->flags |= GENHD_FL_REMOVABLE;
++      /* Remove TX descriptor ring from card */
++      EFX_ZERO_OWORD(tx_desc_ptr);
++      falcon_write_table(efx, &tx_desc_ptr, efx->type->txd_ptr_tbl_base,
++                         tx_queue->queue);
 +
-+      if (vdisk_info & VDISK_CDROM)
-+              gd->flags |= GENHD_FL_CD;
++      /* Unpin TX descriptor ring */
++      falcon_fini_special_buffer(efx, &tx_queue->txd);
++}
 +
-+      return 0;
++/* Free buffers backing TX queue */
++void falcon_remove_tx(struct efx_tx_queue *tx_queue)
++{
++      falcon_free_special_buffer(tx_queue->efx, &tx_queue->txd);
++}
 +
-+ out:
-+      if (mi)
-+              xlbd_put_major_info(mi);
-+      info->mi = NULL;
-+      return err;
++/**************************************************************************
++ *
++ * Falcon RX path
++ *
++ **************************************************************************/
++
++/* Returns a pointer to the specified transmit descriptor in the RX
++ * descriptor queue.
++ */
++static inline efx_qword_t *falcon_rx_desc(struct efx_rx_queue *rx_queue,
++                                             unsigned int index)
++{
++      return (((efx_qword_t *) (rx_queue->rxd.addr)) + index);
 +}
 +
-+int
-+xlvbd_add(blkif_sector_t capacity, int vdevice, u16 vdisk_info,
-+        u16 sector_size, struct blkfront_info *info)
++/* This creates an entry in the RX descriptor queue corresponding to
++ * the receive buffer.
++ */
++static inline void falcon_build_rx_desc(struct efx_rx_queue *rx_queue,
++                                      unsigned index)
 +{
-+      struct block_device *bd;
-+      int err = 0;
++      struct efx_rx_buffer *rx_buf;
++      efx_qword_t *rxd;
 +
-+      info->dev = MKDEV(BLKIF_MAJOR(vdevice), BLKIF_MINOR(vdevice));
++      rxd = falcon_rx_desc(rx_queue, index);
++      rx_buf = efx_rx_buffer(rx_queue, index);
++      EFX_POPULATE_QWORD_3(*rxd,
++                           RX_KER_BUF_SIZE,
++                           rx_buf->len -
++                           rx_queue->efx->type->rx_buffer_padding,
++                           RX_KER_BUF_REGION, 0,
++                           RX_KER_BUF_ADR, rx_buf->dma_addr);
++}
 +
-+      bd = bdget(info->dev);
-+      if (bd == NULL)
-+              return -ENODEV;
++/* This writes to the RX_DESC_WPTR register for the specified receive
++ * descriptor ring.
++ */
++#if defined(EFX_USE_FASTCALL)
++void fastcall falcon_notify_rx_desc(struct efx_rx_queue *rx_queue)
++#else
++void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue)
++#endif
++{
++      efx_dword_t reg;
++      unsigned write_ptr;
 +
-+      err = xlvbd_alloc_gendisk(BLKIF_MINOR(vdevice), capacity, vdevice,
-+                                vdisk_info, sector_size, info);
++      while (rx_queue->notified_count != rx_queue->added_count) {
++              falcon_build_rx_desc(rx_queue,
++                                   rx_queue->notified_count &
++                                   FALCON_RXD_RING_MASK);
++              ++rx_queue->notified_count;
++      }
 +
-+      bdput(bd);
-+      return err;
++      wmb();
++      write_ptr = rx_queue->added_count & FALCON_RXD_RING_MASK;
++      EFX_POPULATE_DWORD_1(reg, RX_DESC_WPTR_DWORD, write_ptr);
++      falcon_writel_page(rx_queue->efx, &reg,
++                         RX_DESC_UPD_REG_KER_DWORD, rx_queue->queue);
 +}
 +
-+void
-+xlvbd_del(struct blkfront_info *info)
++int falcon_probe_rx(struct efx_rx_queue *rx_queue)
 +{
-+      if (info->mi == NULL)
-+              return;
++      struct efx_nic *efx = rx_queue->efx;
++      struct falcon_nic_data *nic_data = efx->nic_data;
++      int rc;
 +
-+      BUG_ON(info->gd == NULL);
-+      del_gendisk(info->gd);
-+      put_disk(info->gd);
-+      info->gd = NULL;
++      rc = falcon_alloc_special_buffer(efx, &rx_queue->rxd,
++                                       FALCON_RXD_RING_SIZE *
++                                       sizeof(efx_qword_t));
++      if (rc)
++              return rc;
 +
-+      xlbd_put_major_info(info->mi);
-+      info->mi = NULL;
++      /* Increment the rxq_min counter */
++      nic_data->resources.rxq_min = max(nic_data->resources.rxq_min,
++                                        (unsigned)rx_queue->queue + 1);
 +
-+      BUG_ON(info->rq == NULL);
-+      blk_cleanup_queue(info->rq);
-+      info->rq = NULL;
++      return 0;
 +}
 +
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
-+int
-+xlvbd_barrier(struct blkfront_info *info)
++int falcon_init_rx(struct efx_rx_queue *rx_queue)
 +{
-+      int err;
++      efx_oword_t rx_desc_ptr;
++      struct efx_nic *efx = rx_queue->efx;
++      int rc;
++      int is_b0 = FALCON_REV(efx) >= FALCON_REV_B0;
++      int iscsi_digest_en = is_b0;
 +
-+      err = blk_queue_ordered(info->rq,
-+              info->feature_barrier ? QUEUE_ORDERED_DRAIN : QUEUE_ORDERED_NONE, NULL);
-+      if (err)
-+              return err;
-+      printk(KERN_INFO "blkfront: %s: barriers %s\n",
-+             info->gd->disk_name, info->feature_barrier ? "enabled" : "disabled");
++      EFX_LOG(efx, "RX queue %d ring in special buffers %d-%d\n",
++              rx_queue->queue, rx_queue->rxd.index,
++              rx_queue->rxd.index + rx_queue->rxd.entries - 1);
++
++      /* Pin RX descriptor ring */
++      rc = falcon_init_special_buffer(efx, &rx_queue->rxd);
++      if (rc)
++              return rc;
++
++      /* Push RX descriptor ring to card */
++      EFX_POPULATE_OWORD_10(rx_desc_ptr,
++                            RX_ISCSI_DDIG_EN, iscsi_digest_en,
++                            RX_ISCSI_HDIG_EN, iscsi_digest_en,
++                            RX_DESCQ_BUF_BASE_ID, rx_queue->rxd.index,
++                            RX_DESCQ_EVQ_ID, rx_queue->channel->evqnum,
++                            RX_DESCQ_OWNER_ID, 0,
++                            RX_DESCQ_LABEL, rx_queue->queue,
++                            RX_DESCQ_SIZE, FALCON_RXD_RING_ORDER,
++                            RX_DESCQ_TYPE, 0 /* kernel queue */ ,
++                            /* For >=B0 this is scatter so disable */
++                            RX_DESCQ_JUMBO, !is_b0,
++                            RX_DESCQ_EN, 1);
++      falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
++                         rx_queue->queue);
 +      return 0;
 +}
-+#else
-+int
-+xlvbd_barrier(struct blkfront_info *info)
++
++static int falcon_flush_rx_queue(struct efx_rx_queue *rx_queue)
 +{
-+      printk(KERN_INFO "blkfront: %s: barriers disabled\n", info->gd->disk_name);
-+      return -ENOSYS;
++      struct efx_nic *efx = rx_queue->efx;
++      struct efx_channel *channel = &efx->channel[0];
++      unsigned int read_ptr, i;
++      efx_oword_t rx_flush_descq;
++
++      /* Post a flush command */
++      EFX_POPULATE_OWORD_2(rx_flush_descq,
++                           RX_FLUSH_DESCQ_CMD, 1,
++                           RX_FLUSH_DESCQ, rx_queue->queue);
++
++      falcon_write(efx, &rx_flush_descq, RX_FLUSH_DESCQ_REG_KER);
++      msleep(FALCON_FLUSH_TIMEOUT);
++
++      /* If the NIC is resetting then don't bother checking */
++      if (EFX_WORKAROUND_7803(efx) || (efx->state == STATE_RESETTING))
++              return 0;
++
++      /* Look for a flush completed event */
++      read_ptr = channel->eventq_read_ptr;
++      for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
++              efx_qword_t *event = falcon_event(channel, read_ptr);
++              int ev_code, ev_sub_code, ev_queue, ev_failed;
++              if (!falcon_event_present(event))
++                      break;
++
++              ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
++              ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
++              ev_queue = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_DESCQ_ID);
++              ev_failed = EFX_QWORD_FIELD(*event, DRIVER_EV_RX_FLUSH_FAIL);
++
++              if ((ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) &&
++                  (ev_queue == rx_queue->queue)) {
++                      if (ev_failed) {
++                              EFX_INFO(efx, "rx queue %d flush command "
++                                       "failed\n", rx_queue->queue);
++                              return -EAGAIN;
++                      } else {
++                              EFX_LOG(efx, "rx queue %d flush command "
++                                      "succesful\n", rx_queue->queue);
++                              return 0;
++                      }
++              }
++
++              read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
++      }
++
++      if (EFX_WORKAROUND_11557(efx)) {
++              efx_oword_t reg;
++              int enabled;
++
++              falcon_read_table(efx, &reg, efx->type->rxd_ptr_tbl_base,
++                                rx_queue->queue);
++              enabled = EFX_OWORD_FIELD(reg, RX_DESCQ_EN);
++              if (!enabled) {
++                      EFX_LOG(efx, "rx queue %d disabled without a "
++                              "flush event seen\n", rx_queue->queue);
++                      return 0;
++              }
++      }
++
++      EFX_ERR(efx, "rx queue %d flush command timed out\n", rx_queue->queue);
++      return -ETIMEDOUT;
 +}
-+#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blktap/blktap.c linux-2.6.18-xen.hg/drivers/xen/blktap/blktap.c
---- linux-2.6.18/drivers/xen/blktap/blktap.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blktap/blktap.c    2007-12-23 11:15:33.547908998 +0100
-@@ -0,0 +1,1632 @@
-+/******************************************************************************
-+ * drivers/xen/blktap/blktap.c
-+ * 
-+ * Back-end driver for user level virtual block devices. This portion of the
-+ * driver exports a 'unified' block-device interface that can be accessed
-+ * by any operating system that implements a compatible front end. Requests
-+ * are remapped to a user-space memory region.
++
++void falcon_fini_rx(struct efx_rx_queue *rx_queue)
++{
++      efx_oword_t rx_desc_ptr;
++      struct efx_nic *efx = rx_queue->efx;
++      int i, rc;
++
++      /* Try and flush the rx queue. This may need to be repeated */
++      for (i = 0; i < 5; i++) {
++              rc = falcon_flush_rx_queue(rx_queue);
++              if (rc == -EAGAIN)
++                      continue;
++              break;
++      }
++      if (rc)
++              EFX_ERR(efx, "failed to flush rx queue %d\n", rx_queue->queue);
++
++      /* Remove RX descriptor ring from card */
++      EFX_ZERO_OWORD(rx_desc_ptr);
++      falcon_write_table(efx, &rx_desc_ptr, efx->type->rxd_ptr_tbl_base,
++                         rx_queue->queue);
++
++      /* Unpin RX descriptor ring */
++      falcon_fini_special_buffer(efx, &rx_queue->rxd);
++}
++
++/* Free buffers backing RX queue */
++void falcon_remove_rx(struct efx_rx_queue *rx_queue)
++{
++      falcon_free_special_buffer(rx_queue->efx, &rx_queue->rxd);
++}
++
++/**************************************************************************
 + *
-+ * Based on the blkback driver code.
-+ * 
-+ * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
++ * Falcon event queue processing
++ * Event queues are processed by per-channel tasklets.
 + *
-+ * Clean ups and fix ups:
-+ *    Copyright (c) 2006, Steven Rostedt - Red Hat, Inc.
++ **************************************************************************/
++
++/* Update a channel's event queue's read pointer (RPTR) register
 + *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++ * This writes the EVQ_RPTR_REG register for the specified channel's
++ * event queue.
++ *
++ * Note that EVQ_RPTR_REG contains the index of the "last read" event,
++ * whereas channel->eventq_read_ptr contains the index of the "next to
++ * read" event.
 + */
++#if defined(EFX_USE_FASTCALL)
++void fastcall falcon_eventq_read_ack(struct efx_channel *channel)
++#else
++void falcon_eventq_read_ack(struct efx_channel *channel)
++#endif
++{
++      efx_dword_t reg;
++      struct efx_nic *efx = channel->efx;
 +
-+#include <linux/spinlock.h>
-+#include <linux/kthread.h>
-+#include <linux/list.h>
-+#include <asm/hypervisor.h>
-+#include "common.h"
-+#include <xen/balloon.h>
-+#include <xen/driver_util.h>
-+#include <linux/kernel.h>
-+#include <linux/fs.h>
-+#include <linux/mm.h>
-+#include <linux/errno.h>
-+#include <linux/major.h>
-+#include <linux/gfp.h>
-+#include <linux/poll.h>
-+#include <asm/tlbflush.h>
++      EFX_POPULATE_DWORD_1(reg, EVQ_RPTR_DWORD, channel->eventq_read_ptr);
++      falcon_writel_table(efx, &reg, efx->type->evq_rptr_tbl_base,
++                          channel->evqnum);
++}
 +
-+#define MAX_TAP_DEV 256     /*the maximum number of tapdisk ring devices    */
-+#define MAX_DEV_NAME 100    /*the max tapdisk ring device name e.g. blktap0 */
++/* Use HW to insert a SW defined event */
++void falcon_generate_event(struct efx_channel *channel, efx_qword_t *event)
++{
++      efx_oword_t drv_ev_reg;
 +
-+/*
-+ * The maximum number of requests that can be outstanding at any time
-+ * is determined by 
-+ *
-+ *   [mmap_alloc * MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST] 
-+ *
-+ * where mmap_alloc < MAX_DYNAMIC_MEM.
++      EFX_POPULATE_OWORD_2(drv_ev_reg,
++                           DRV_EV_QID, channel->evqnum,
++                           DRV_EV_DATA,
++                           EFX_QWORD_FIELD64(*event, WHOLE_EVENT));
++      falcon_write(channel->efx, &drv_ev_reg, DRV_EV_REG_KER);
++}
++
++/* Handle a transmit completion event
 + *
-+ * TODO:
-+ * mmap_alloc is initialised to 2 and should be adjustable on the fly via
-+ * sysfs.
++ * Falcon batches TX completion events; the message we receive is of
++ * the form "complete all TX events up to this index".
 + */
-+#define BLK_RING_SIZE         __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE)
-+#define MAX_DYNAMIC_MEM               BLK_RING_SIZE
-+#define MAX_PENDING_REQS      BLK_RING_SIZE
-+#define MMAP_PAGES (MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
-+#define MMAP_VADDR(_start, _req,_seg)                                   \
-+        (_start +                                                       \
-+         ((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) +        \
-+         ((_seg) * PAGE_SIZE))
-+static int blkif_reqs = MAX_PENDING_REQS;
-+static int mmap_pages = MMAP_PAGES;
++static inline void falcon_handle_tx_event(struct efx_channel *channel,
++                                        efx_qword_t *event)
++{
++      unsigned int tx_ev_desc_ptr;
++      unsigned int tx_ev_q_label;
++      struct efx_tx_queue *tx_queue;
++      struct efx_nic *efx = channel->efx;
 +
-+#define RING_PAGES 1 /* BLKTAP - immediately before the mmap area, we
-+                    * have a bunch of pages reserved for shared
-+                    * memory rings.
-+                    */
++      if (likely(EFX_QWORD_FIELD(*event, TX_EV_COMP))) {
++              /* Transmit completion */
++              tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR);
++              tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
++              tx_queue = &efx->tx_queue[tx_ev_q_label];
++              efx_xmit_done(tx_queue, tx_ev_desc_ptr);
++      } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) {
++              /* Rewrite the FIFO write pointer */
++              tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
++              tx_queue = &efx->tx_queue[tx_ev_q_label];
 +
-+/*Data struct handed back to userspace for tapdisk device to VBD mapping*/
-+typedef struct domid_translate {
-+      unsigned short domid;
-+      unsigned short busid;
-+} domid_translate_t ;
++              if (efx->net_dev_registered)
++                      netif_tx_lock(efx->net_dev);
++              falcon_notify_tx_desc(tx_queue);
++              if (efx->net_dev_registered)
++                      netif_tx_unlock(efx->net_dev);
++      } else if (EFX_QWORD_FIELD(*event, TX_EV_PKT_ERR) &&
++                 EFX_WORKAROUND_10727(efx)) {
++              efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
++      } else {
++              EFX_ERR(efx, "channel %d unexpected TX event "
++                      EFX_QWORD_FMT"\n", channel->channel,
++                      EFX_QWORD_VAL(*event));
++      }
++}
 +
-+/*Data struct associated with each of the tapdisk devices*/
-+typedef struct tap_blkif {
-+      struct vm_area_struct *vma;   /*Shared memory area                   */
-+      unsigned long rings_vstart;   /*Kernel memory mapping                */
-+      unsigned long user_vstart;    /*User memory mapping                  */
-+      unsigned long dev_inuse;      /*One process opens device at a time.  */
-+      unsigned long dev_pending;    /*In process of being opened           */
-+      unsigned long ring_ok;        /*make this ring->state                */
-+      blkif_front_ring_t ufe_ring;  /*Rings up to user space.              */
-+      wait_queue_head_t wait;       /*for poll                             */
-+      unsigned long mode;           /*current switching mode               */
-+      int minor;                    /*Minor number for tapdisk device      */
-+      pid_t pid;                    /*tapdisk process id                   */
-+      enum { RUNNING, CLEANSHUTDOWN } status; /*Detect a clean userspace 
-+                                                shutdown                   */
-+      unsigned long *idx_map;       /*Record the user ring id to kern 
-+                                      [req id, idx] tuple                  */
-+      blkif_t *blkif;               /*Associate blkif with tapdev          */
-+      struct domid_translate trans; /*Translation from domid to bus.       */
-+} tap_blkif_t;
++/* Check received packet's destination MAC address. */
++static int check_dest_mac(struct efx_rx_queue *rx_queue,
++                        const efx_qword_t *event)
++{
++      struct efx_rx_buffer *rx_buf;
++      struct efx_nic *efx = rx_queue->efx;
++      int rx_ev_desc_ptr;
++      struct ethhdr *eh;
 +
-+static struct tap_blkif *tapfds[MAX_TAP_DEV];
-+static int blktap_next_minor;
++      if (efx->promiscuous)
++              return 1;
 +
-+module_param(blkif_reqs, int, 0);
-+/* Run-time switchable: /sys/module/blktap/parameters/ */
-+static unsigned int log_stats = 0;
-+static unsigned int debug_lvl = 0;
-+module_param(log_stats, int, 0644);
-+module_param(debug_lvl, int, 0644);
++      rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
++      rx_buf = efx_rx_buffer(rx_queue, rx_ev_desc_ptr);
++      eh = (struct ethhdr *)rx_buf->data;
++      if (memcmp(eh->h_dest, efx->net_dev->dev_addr, ETH_ALEN))
++              return 0;
++      return 1;
++}
 +
-+/*
-+ * Each outstanding request that we've passed to the lower device layers has a 
-+ * 'pending_req' allocated to it. Each buffer_head that completes decrements 
-+ * the pendcnt towards zero. When it hits zero, the specified domain has a 
-+ * response queued for it, with the saved 'id' passed back.
-+ */
-+typedef struct {
-+      blkif_t       *blkif;
-+      u64            id;
-+      unsigned short mem_idx;
-+      int            nr_pages;
-+      atomic_t       pendcnt;
-+      unsigned short operation;
-+      int            status;
-+      struct list_head free_list;
-+      int            inuse;
-+} pending_req_t;
++/* Detect errors included in the rx_evt_pkt_ok bit. */
++static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue,
++                                  const efx_qword_t *event,
++                                  unsigned *rx_ev_pkt_ok,
++                                  int *discard, int byte_count)
++{
++      struct efx_nic *efx = rx_queue->efx;
++      unsigned rx_ev_buf_owner_id_err, rx_ev_ip_hdr_chksum_err;
++      unsigned rx_ev_tcp_udp_chksum_err, rx_ev_eth_crc_err;
++      unsigned rx_ev_frm_trunc, rx_ev_drib_nib, rx_ev_tobe_disc;
++      unsigned rx_ev_pkt_type, rx_ev_other_err, rx_ev_pause_frm;
++      unsigned rx_ev_ip_frag_err, rx_ev_hdr_type, rx_ev_mcast_pkt;
++      int snap, non_ip;
++
++      rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
++      rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
++      rx_ev_tobe_disc = EFX_QWORD_FIELD(*event, RX_EV_TOBE_DISC);
++      rx_ev_pkt_type = EFX_QWORD_FIELD(*event, RX_EV_PKT_TYPE);
++      rx_ev_buf_owner_id_err = EFX_QWORD_FIELD(*event,
++                                               RX_EV_BUF_OWNER_ID_ERR);
++      rx_ev_ip_frag_err = EFX_QWORD_FIELD(*event, RX_EV_IF_FRAG_ERR);
++      rx_ev_ip_hdr_chksum_err = EFX_QWORD_FIELD(*event,
++                                                RX_EV_IP_HDR_CHKSUM_ERR);
++      rx_ev_tcp_udp_chksum_err = EFX_QWORD_FIELD(*event,
++                                                 RX_EV_TCP_UDP_CHKSUM_ERR);
++      rx_ev_eth_crc_err = EFX_QWORD_FIELD(*event, RX_EV_ETH_CRC_ERR);
++      rx_ev_frm_trunc = EFX_QWORD_FIELD(*event, RX_EV_FRM_TRUNC);
++      rx_ev_drib_nib = ((FALCON_REV(efx) >= FALCON_REV_B0) ?
++                        0 : EFX_QWORD_FIELD(*event, RX_EV_DRIB_NIB));
++      rx_ev_pause_frm = EFX_QWORD_FIELD(*event, RX_EV_PAUSE_FRM_ERR);
++
++      /* Every error apart from tobe_disc and pause_frm */
++      rx_ev_other_err = (rx_ev_drib_nib | rx_ev_tcp_udp_chksum_err |
++                         rx_ev_buf_owner_id_err | rx_ev_eth_crc_err |
++                         rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err);
++
++      snap = (rx_ev_pkt_type == RX_EV_PKT_TYPE_LLC_DECODE) ||
++              (rx_ev_pkt_type == RX_EV_PKT_TYPE_VLAN_LLC_DECODE);
++      non_ip = (rx_ev_hdr_type == RX_EV_HDR_TYPE_NON_IP_DECODE);
++
++      /* SFC bug 5475/8970: The Falcon XMAC incorrectly calculates the
++       * length field of an LLC frame, which sets TOBE_DISC. We could set
++       * PASS_LEN_ERR, but we want the MAC to filter out short frames (to
++       * protect the RX block).
++       *
++       * bug5475 - LLC/SNAP: Falcon identifies SNAP packets.
++       * bug8970 - LLC/noSNAP: Falcon does not provide an LLC flag.
++       *                       LLC can't encapsulate IP, so by definition
++       *                       these packets are NON_IP.
++       *
++       * Unicast mismatch will also cause TOBE_DISC, so the driver needs
++       * to check this.
++       */
++      if (EFX_WORKAROUND_5475(efx) && rx_ev_tobe_disc && (snap || non_ip)) {
++              /* If all the other flags are zero then we can state the
++               * entire packet is ok, which will flag to the kernel not
++               * to recalculate checksums.
++               */
++              if (!(non_ip | rx_ev_other_err | rx_ev_pause_frm))
++                      *rx_ev_pkt_ok = 1;
 +
-+static pending_req_t *pending_reqs[MAX_PENDING_REQS];
-+static struct list_head pending_free;
-+static DEFINE_SPINLOCK(pending_free_lock);
-+static DECLARE_WAIT_QUEUE_HEAD (pending_free_wq);
-+static int alloc_pending_reqs;
++              rx_ev_tobe_disc = 0;
 +
-+typedef unsigned int PEND_RING_IDX;
++              /* TOBE_DISC is set for unicast mismatch.  But given that
++               * we can't trust TOBE_DISC here, we must validate the dest
++               * MAC address ourselves.
++               */
++              if (!rx_ev_mcast_pkt && !check_dest_mac(rx_queue, event))
++                      rx_ev_tobe_disc = 1;
++      }
++
++      /* Count errors that are not in MAC stats. */
++      if (rx_ev_frm_trunc)
++              ++rx_queue->channel->n_rx_frm_trunc;
++      else if (rx_ev_tobe_disc)
++              ++rx_queue->channel->n_rx_tobe_disc;
++      else if (rx_ev_ip_hdr_chksum_err)
++              ++rx_queue->channel->n_rx_ip_hdr_chksum_err;
++      else if (rx_ev_tcp_udp_chksum_err)
++              ++rx_queue->channel->n_rx_tcp_udp_chksum_err;
++      if (rx_ev_ip_frag_err)
++              ++rx_queue->channel->n_rx_ip_frag_err;
++
++      /* The frame must be discarded if any of these are true. */
++      *discard = (rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_drib_nib |
++                  rx_ev_tobe_disc | rx_ev_pause_frm);
++
++      /* TOBE_DISC is expected on unicast mismatches; don't print out an
++       * error message.  FRM_TRUNC indicates RXDP dropped the packet due
++       * to a FIFO overflow.
++       */
++#ifdef EFX_ENABLE_DEBUG
++      if (rx_ev_other_err) {
++              EFX_INFO_RL(efx, " RX queue %d unexpected RX event "
++                          EFX_QWORD_FMT "%s%s%s%s%s%s%s%s%s\n",
++                          rx_queue->queue, EFX_QWORD_VAL(*event),
++                          rx_ev_buf_owner_id_err ? " [OWNER_ID_ERR]" : "",
++                          rx_ev_ip_hdr_chksum_err ?
++                          " [IP_HDR_CHKSUM_ERR]" : "",
++                          rx_ev_tcp_udp_chksum_err ?
++                          " [TCP_UDP_CHKSUM_ERR]" : "",
++                          rx_ev_eth_crc_err ? " [ETH_CRC_ERR]" : "",
++                          rx_ev_frm_trunc ? " [FRM_TRUNC]" : "",
++                          rx_ev_drib_nib ? " [DRIB_NIB]" : "",
++                          rx_ev_tobe_disc ? " [TOBE_DISC]" : "",
++                          rx_ev_pause_frm ? " [PAUSE]" : "",
++                          snap ? " [SNAP/LLC]" : "");
++      }
++#endif
++
++      if (unlikely(rx_ev_eth_crc_err && EFX_WORKAROUND_10750(efx) &&
++                   efx->phy_type == PHY_TYPE_10XPRESS))
++              tenxpress_crc_err(efx);
++}
++
++
++/* Handle receive events that are not in-order. */
++static void falcon_handle_rx_bad_index(struct efx_rx_queue *rx_queue,
++                                     unsigned index)
++{
++      struct efx_nic *efx = rx_queue->efx;
++      unsigned expected, dropped;
++
++      expected = rx_queue->removed_count & FALCON_RXD_RING_MASK;
++      dropped = ((index + FALCON_RXD_RING_SIZE - expected) &
++                 FALCON_RXD_RING_MASK);
++      EFX_INFO(efx, "dropped %d events (index=%d expected=%d)\n",
++              dropped, index, expected);
++
++      atomic_inc(&efx->errors.missing_event);
++      efx_schedule_reset(efx, EFX_WORKAROUND_5676(efx) ?
++                         RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
++}
++
++
++/* Handle a packet received event
++ *
++ * Falcon silicon gives a "discard" flag if it's a unicast packet with the
++ * wrong destination address
++ * Also "is multicast" and "matches multicast filter" flags can be used to
++ * discard non-matching multicast packets.
++ */
++static inline int falcon_handle_rx_event(struct efx_channel *channel,
++                                       const efx_qword_t *event)
++{
++      unsigned int rx_ev_q_label, rx_ev_desc_ptr, rx_ev_byte_cnt;
++      unsigned int rx_ev_pkt_ok, rx_ev_hdr_type, rx_ev_mcast_pkt;
++      unsigned expected_ptr;
++      int discard = 0, checksummed;
++      struct efx_rx_queue *rx_queue;
++      struct efx_nic *efx = channel->efx;
++
++      /* Basic packet information */
++      rx_ev_byte_cnt = EFX_QWORD_FIELD(*event, RX_EV_BYTE_CNT);
++      rx_ev_pkt_ok = EFX_QWORD_FIELD(*event, RX_EV_PKT_OK);
++      rx_ev_hdr_type = EFX_QWORD_FIELD(*event, RX_EV_HDR_TYPE);
++      WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_JUMBO_CONT));
++      WARN_ON(EFX_QWORD_FIELD(*event, RX_EV_SOP) != 1);
++
++      rx_ev_q_label = EFX_QWORD_FIELD(*event, RX_EV_Q_LABEL);
++      rx_queue = &efx->rx_queue[rx_ev_q_label];
++
++      rx_ev_desc_ptr = EFX_QWORD_FIELD(*event, RX_EV_DESC_PTR);
++      expected_ptr = rx_queue->removed_count & FALCON_RXD_RING_MASK;
++      if (unlikely(rx_ev_desc_ptr != expected_ptr)) {
++              falcon_handle_rx_bad_index(rx_queue, rx_ev_desc_ptr);
++              return rx_ev_q_label;
++      }
++
++      if (likely(rx_ev_pkt_ok)) {
++              /* If packet is marked as OK and packet type is TCP/IPv4 or
++               * UDP/IPv4, then we can rely on the hardware checksum.
++               */
++              checksummed = RX_EV_HDR_TYPE_HAS_CHECKSUMS(rx_ev_hdr_type);
++      } else {
++              falcon_handle_rx_not_ok(rx_queue, event, &rx_ev_pkt_ok,
++                                      &discard, rx_ev_byte_cnt);
++              checksummed = 0;
++      }
 +
-+static inline int MASK_PEND_IDX(int i) { 
-+      return (i & (MAX_PENDING_REQS-1));
-+}
++      /* Detect multicast packets that didn't match the filter */
++      rx_ev_mcast_pkt = EFX_QWORD_FIELD(*event, RX_EV_MCAST_PKT);
++      if (rx_ev_mcast_pkt) {
++              unsigned int rx_ev_mcast_hash_match =
++                      EFX_QWORD_FIELD(*event, RX_EV_MCAST_HASH_MATCH);
 +
-+static inline unsigned int RTN_PEND_IDX(pending_req_t *req, int idx) {
-+      return (req - pending_reqs[idx]);
-+}
++              if (unlikely(!rx_ev_mcast_hash_match))
++                      discard = 1;
++      }
 +
-+#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
++      /* Handle received packet */
++      efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt,
++                    checksummed, discard);
 +
-+#define BLKBACK_INVALID_HANDLE (~0)
++      return rx_ev_q_label;
++}
 +
-+static struct page **foreign_pages[MAX_DYNAMIC_MEM];
-+static inline unsigned long idx_to_kaddr(
-+      unsigned int mmap_idx, unsigned int req_idx, unsigned int sg_idx)
++/* Global events are basically PHY events */
++static void falcon_handle_global_event(struct efx_channel *channel,
++                                     efx_qword_t *event)
 +{
-+      unsigned int arr_idx = req_idx*BLKIF_MAX_SEGMENTS_PER_REQUEST + sg_idx;
-+      unsigned long pfn = page_to_pfn(foreign_pages[mmap_idx][arr_idx]);
-+      return (unsigned long)pfn_to_kaddr(pfn);
++      struct efx_nic *efx = channel->efx;
++      int is_phy_event = 0, handled = 0;
++
++      /* Check for interrupt on either port.  Some boards have a
++       * single PHY wired to the interrupt line for port 1. */
++      if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) ||
++          EFX_QWORD_FIELD(*event, G_PHY1_INTR) ||
++          EFX_QWORD_FIELD(*event, XG_PHY_INTR))
++              is_phy_event = 1;
++
++      if ((FALCON_REV(efx) >= FALCON_REV_B0) &&
++          EFX_OWORD_FIELD(*event, XG_MNT_INTR_B0))
++              is_phy_event = 1;
++
++      if (is_phy_event) {
++              efx->phy_op->clear_interrupt(efx);
++              queue_work(efx->workqueue, &efx->reconfigure_work);
++              handled = 1;
++      }
++
++      if (EFX_QWORD_FIELD_VER(efx, *event, RX_RECOVERY)) {
++              EFX_ERR(efx, "channel %d seen global RX_RESET "
++                      "event. Resetting.\n", channel->channel);
++
++              atomic_inc(&efx->errors.rx_reset);
++              efx_schedule_reset(efx, EFX_WORKAROUND_6555(efx) ?
++                                 RESET_TYPE_RX_RECOVERY : RESET_TYPE_DISABLE);
++              handled = 1;
++      }
++
++      if (!handled)
++              EFX_ERR(efx, "channel %d unknown global event "
++                      EFX_QWORD_FMT "\n", channel->channel,
++                      EFX_QWORD_VAL(*event));
 +}
 +
-+static unsigned short mmap_alloc = 0;
-+static unsigned short mmap_lock = 0;
-+static unsigned short mmap_inuse = 0;
++static void falcon_handle_driver_event(struct efx_channel *channel,
++                                     efx_qword_t *event)
++{
++      struct efx_nic *efx = channel->efx;
++      unsigned int ev_sub_code;
++      unsigned int ev_sub_data;
 +
-+/******************************************************************
-+ * GRANT HANDLES
-+ */
++      ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
++      ev_sub_data = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_DATA);
 +
-+/* When using grant tables to map a frame for device access then the
-+ * handle returned must be used to unmap the frame. This is needed to
-+ * drop the ref count on the frame.
-+ */
-+struct grant_handle_pair
++      switch (ev_sub_code) {
++      case TX_DESCQ_FLS_DONE_EV_DECODE:
++              EFX_TRACE(efx, "channel %d TXQ %d flushed\n",
++                        channel->channel, ev_sub_data);
++              EFX_DL_CALLBACK(efx, event, event);
++              break;
++      case RX_DESCQ_FLS_DONE_EV_DECODE:
++              EFX_TRACE(efx, "channel %d RXQ %d flushed\n",
++                        channel->channel, ev_sub_data);
++              EFX_DL_CALLBACK(efx, event, event);
++              break;
++      case EVQ_INIT_DONE_EV_DECODE:
++              EFX_LOG(efx, "channel %d EVQ %d initialised\n",
++                      channel->channel, ev_sub_data);
++              break;
++      case SRM_UPD_DONE_EV_DECODE:
++              EFX_TRACE(efx, "channel %d SRAM update done\n",
++                        channel->channel);
++              EFX_DL_CALLBACK(efx, event, event);
++              break;
++      case WAKE_UP_EV_DECODE:
++              EFX_TRACE(efx, "channel %d RXQ %d wakeup event\n",
++                        channel->channel, ev_sub_data);
++              EFX_DL_CALLBACK(efx, event, event);
++              break;
++      case TIMER_EV_DECODE:
++              EFX_TRACE(efx, "channel %d RX queue %d timer expired\n",
++                        channel->channel, ev_sub_data);
++              EFX_DL_CALLBACK(efx, event, event);
++              break;
++      case RX_RECOVERY_EV_DECODE:
++              EFX_ERR(efx, "channel %d seen DRIVER RX_RESET event. "
++                      "Resetting.\n", channel->channel);
++
++              atomic_inc(&efx->errors.rx_reset);
++              efx_schedule_reset(efx,
++                                 EFX_WORKAROUND_6555(efx) ?
++                                 RESET_TYPE_RX_RECOVERY :
++                                 RESET_TYPE_DISABLE);
++              break;
++      case RX_DSC_ERROR_EV_DECODE:
++              EFX_ERR(efx, "RX DMA Q %d reports descriptor fetch error."
++                      " RX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
++              atomic_inc(&efx->errors.rx_desc_fetch);
++              efx_schedule_reset(efx, RESET_TYPE_RX_DESC_FETCH);
++              break;
++      case TX_DSC_ERROR_EV_DECODE:
++              EFX_ERR(efx, "TX DMA Q %d reports descriptor fetch error."
++                      " TX Q %d is disabled.\n", ev_sub_data, ev_sub_data);
++              atomic_inc(&efx->errors.tx_desc_fetch);
++              efx_schedule_reset(efx, RESET_TYPE_TX_DESC_FETCH);
++              break;
++      default:
++              EFX_TRACE(efx, "channel %d unknown driver event code %d "
++                        "data %04x\n", channel->channel, ev_sub_code,
++                        ev_sub_data);
++              EFX_DL_CALLBACK(efx, event, event);
++              break;
++      }
++}
++
++#if defined(EFX_USE_FASTCALL)
++int fastcall falcon_process_eventq(struct efx_channel *channel, int *rx_quota)
++#else
++int falcon_process_eventq(struct efx_channel *channel, int *rx_quota)
++#endif
 +{
-+        grant_handle_t kernel;
-+        grant_handle_t user;
-+};
-+#define INVALID_GRANT_HANDLE  0xFFFF
++      unsigned int read_ptr;
++      efx_qword_t event, *p_event;
++      int ev_code;
++      int rxq;
++      int rxdmaqs = 0;
 +
-+static struct grant_handle_pair 
-+    pending_grant_handles[MAX_DYNAMIC_MEM][MMAP_PAGES];
-+#define pending_handle(_id, _idx, _i) \
-+    (pending_grant_handles[_id][((_idx) * BLKIF_MAX_SEGMENTS_PER_REQUEST) \
-+    + (_i)])
++      read_ptr = channel->eventq_read_ptr;
 +
++      do {
++              p_event = falcon_event(channel, read_ptr);
++              event = *p_event;
 +
-+static int blktap_read_ufe_ring(tap_blkif_t *info); /*local prototypes*/
++              if (!falcon_event_present(&event))
++                      /* End of events */
++                      break;
 +
-+#define BLKTAP_MINOR 0  /*/dev/xen/blktap has a dynamic major */
-+#define BLKTAP_DEV_DIR  "/dev/xen"
++              EFX_TRACE(channel->efx, "channel %d event is "EFX_QWORD_FMT"\n",
++                        channel->channel, EFX_QWORD_VAL(event));
 +
-+static int blktap_major;
++              /* Clear this event by marking it all ones */
++              EFX_SET_QWORD(*p_event);
 +
-+/* blktap IOCTLs: */
-+#define BLKTAP_IOCTL_KICK_FE         1
-+#define BLKTAP_IOCTL_KICK_BE         2 /* currently unused */
-+#define BLKTAP_IOCTL_SETMODE         3
-+#define BLKTAP_IOCTL_SENDPID       4
-+#define BLKTAP_IOCTL_NEWINTF       5
-+#define BLKTAP_IOCTL_MINOR         6
-+#define BLKTAP_IOCTL_MAJOR         7
-+#define BLKTAP_QUERY_ALLOC_REQS      8
-+#define BLKTAP_IOCTL_FREEINTF        9
-+#define BLKTAP_IOCTL_PRINT_IDXS      100  
++              ev_code = EFX_QWORD_FIELD(event, EV_CODE);
 +
-+/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE)             */
-+#define BLKTAP_MODE_PASSTHROUGH      0x00000000  /* default            */
-+#define BLKTAP_MODE_INTERCEPT_FE     0x00000001
-+#define BLKTAP_MODE_INTERCEPT_BE     0x00000002  /* unimp.             */
++              switch (ev_code) {
++              case RX_IP_EV_DECODE:
++                      rxq = falcon_handle_rx_event(channel, &event);
++                      rxdmaqs |= (1 << rxq);
++                      (*rx_quota)--;
++                      break;
++              case TX_IP_EV_DECODE:
++                      falcon_handle_tx_event(channel, &event);
++                      break;
++              case DRV_GEN_EV_DECODE:
++                      channel->eventq_magic
++                              = EFX_QWORD_FIELD(event, EVQ_MAGIC);
++                      EFX_LOG(channel->efx, "channel %d received generated "
++                              "event "EFX_QWORD_FMT"\n", channel->channel,
++                              EFX_QWORD_VAL(event));
++                      break;
++              case GLOBAL_EV_DECODE:
++                      falcon_handle_global_event(channel, &event);
++                      break;
++              case DRIVER_EV_DECODE:
++                      falcon_handle_driver_event(channel, &event);
++                      break;
++              default:
++                      EFX_ERR(channel->efx, "channel %d unknown event type %d"
++                              " (data " EFX_QWORD_FMT ")\n", channel->channel,
++                              ev_code, EFX_QWORD_VAL(event));
++              }
 +
-+#define BLKTAP_MODE_INTERPOSE \
-+           (BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
++              /* Increment read pointer */
++              read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
 +
++      } while (*rx_quota);
 +
-+static inline int BLKTAP_MODE_VALID(unsigned long arg)
++      channel->eventq_read_ptr = read_ptr;
++      return rxdmaqs;
++}
++
++void falcon_set_int_moderation(struct efx_channel *channel)
 +{
-+      return ((arg == BLKTAP_MODE_PASSTHROUGH ) ||
-+              (arg == BLKTAP_MODE_INTERCEPT_FE) ||
-+                (arg == BLKTAP_MODE_INTERPOSE   ));
++      efx_dword_t timer_cmd;
++      struct efx_nic *efx = channel->efx;
++
++      /* Set timer register */
++      if (channel->irq_moderation) {
++              /* Round to resolution supported by hardware.  The value we
++               * program is based at 0.  So actual interrupt moderation
++               * achieved is ((x + 1) * res).
++               */
++              unsigned int res = 5;
++              channel->irq_moderation -= (channel->irq_moderation % res);
++              if (channel->irq_moderation < res)
++                      channel->irq_moderation = res;
++              EFX_POPULATE_DWORD_2(timer_cmd,
++                                   TIMER_MODE, TIMER_MODE_INT_HLDOFF,
++                                   TIMER_VAL,
++                                   (channel->irq_moderation / res) - 1);
++      } else {
++              EFX_POPULATE_DWORD_2(timer_cmd,
++                                   TIMER_MODE, TIMER_MODE_DIS,
++                                   TIMER_VAL, 0);
++      }
++      falcon_writel_page_locked(efx, &timer_cmd, TIMER_CMD_REG_KER,
++                                channel->evqnum);
++
 +}
 +
-+/* Requests passing through the tap to userspace are re-assigned an ID.
-+ * We must record a mapping between the BE [IDX,ID] tuple and the userspace
-+ * ring ID. 
-+ */
++/* Allocate buffer table entries for event queue */
++int falcon_probe_eventq(struct efx_channel *channel)
++{
++      struct efx_nic *efx = channel->efx;
++      struct falcon_nic_data *nic_data = efx->nic_data;
++      unsigned int evq_size;
++      int rc;
 +
-+static inline unsigned long MAKE_ID(domid_t fe_dom, PEND_RING_IDX idx)
++      evq_size = FALCON_EVQ_SIZE * sizeof(efx_qword_t);
++      rc = falcon_alloc_special_buffer(efx, &channel->eventq, evq_size);
++      if (rc)
++              return rc;
++
++      nic_data->resources.evq_int_min = max(nic_data->resources.evq_int_min,
++                                            (unsigned)channel->evqnum + 1);
++
++      return 0;
++}
++
++int falcon_init_eventq(struct efx_channel *channel)
 +{
-+        return ((fe_dom << 16) | MASK_PEND_IDX(idx));
++      efx_oword_t evq_ptr;
++      struct efx_nic *efx = channel->efx;
++      int rc;
++
++      EFX_LOG(efx, "channel %d event queue in special buffers %d-%d\n",
++              channel->channel, channel->eventq.index,
++              channel->eventq.index + channel->eventq.entries - 1);
++
++      /* Pin event queue buffer */
++      rc = falcon_init_special_buffer(efx, &channel->eventq);
++      if (rc)
++              return rc;
++
++      /* Fill event queue with all ones (i.e. empty events) */
++      memset(channel->eventq.addr, 0xff, channel->eventq.len);
++
++      /* Push event queue to card */
++      EFX_POPULATE_OWORD_3(evq_ptr,
++                           EVQ_EN, 1,
++                           EVQ_SIZE, FALCON_EVQ_ORDER,
++                           EVQ_BUF_BASE_ID, channel->eventq.index);
++      falcon_write_table(efx, &evq_ptr, efx->type->evq_ptr_tbl_base,
++                         channel->evqnum);
++
++      falcon_set_int_moderation(channel);
++
++      return 0;
 +}
 +
-+extern inline PEND_RING_IDX ID_TO_IDX(unsigned long id)
++void falcon_fini_eventq(struct efx_channel *channel)
 +{
-+        return (PEND_RING_IDX)(id & 0x0000ffff);
++      efx_oword_t eventq_ptr;
++      struct efx_nic *efx = channel->efx;
++
++      /* Remove event queue from card */
++      EFX_ZERO_OWORD(eventq_ptr);
++      falcon_write_table(efx, &eventq_ptr, efx->type->evq_ptr_tbl_base,
++                         channel->evqnum);
++
++      /* Unpin event queue */
++      falcon_fini_special_buffer(efx, &channel->eventq);
 +}
 +
-+extern inline int ID_TO_MIDX(unsigned long id)
++/* Free buffers backing event queue */
++void falcon_remove_eventq(struct efx_channel *channel)
 +{
-+        return (int)(id >> 16);
++      falcon_free_special_buffer(channel->efx, &channel->eventq);
 +}
 +
-+#define INVALID_REQ 0xdead0000
 +
-+/*TODO: Convert to a free list*/
-+static inline int GET_NEXT_REQ(unsigned long *idx_map)
++/* Generates a test event on the event queue.  A subsequent call to
++ * process_eventq() should pick up the event and place the value of
++ * "magic" into channel->eventq_magic;
++ */
++void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic)
 +{
-+      int i;
-+      for (i = 0; i < MAX_PENDING_REQS; i++)
-+              if (idx_map[i] == INVALID_REQ)
-+                      return i;
++      efx_qword_t test_event;
 +
-+      return INVALID_REQ;
++      EFX_POPULATE_QWORD_2(test_event,
++                           EV_CODE, DRV_GEN_EV_DECODE,
++                           EVQ_MAGIC, magic);
++      falcon_generate_event(channel, &test_event);
 +}
 +
-+static inline int OFFSET_TO_USR_IDX(int offset)
++
++/**************************************************************************
++ *
++ * Falcon hardware interrupts
++ * The hardware interrupt handler does very little work; all the event
++ * queue processing is carried out by per-channel tasklets.
++ *
++ **************************************************************************/
++
++/* Enable/disable/generate Falcon interrupts */
++static inline void falcon_interrupts(struct efx_nic *efx, int enabled,
++                                   int force)
 +{
-+      return offset / BLKIF_MAX_SEGMENTS_PER_REQUEST;
++      efx_oword_t int_en_reg_ker;
++
++      EFX_POPULATE_OWORD_2(int_en_reg_ker,
++                           KER_INT_KER, force,
++                           DRV_INT_EN_KER, enabled);
++      falcon_write(efx, &int_en_reg_ker, INT_EN_REG_KER);
 +}
 +
-+static inline int OFFSET_TO_SEG(int offset)
++void falcon_enable_interrupts(struct efx_nic *efx)
 +{
-+      return offset % BLKIF_MAX_SEGMENTS_PER_REQUEST;
-+}
++      efx_oword_t int_adr_reg_ker;
++      struct efx_channel *channel;
 +
++      /* Zero INT_KER */
++      EFX_ZERO_OWORD(*((efx_oword_t *) efx->irq_status.addr));
++      wmb(); /* Ensure interrupt vector is clear before interrupts enabled */
 +
-+#define BLKTAP_INVALID_HANDLE(_g) \
-+    (((_g->kernel) == INVALID_GRANT_HANDLE) &&  \
-+     ((_g->user) == INVALID_GRANT_HANDLE))
++      /* Program INT_ADR_KER_REG */
++      EFX_POPULATE_OWORD_2(int_adr_reg_ker,
++                           NORM_INT_VEC_DIS_KER, EFX_INT_MODE_USE_MSI(efx),
++                           INT_ADR_KER, efx->irq_status.dma_addr);
++      falcon_write(efx, &int_adr_reg_ker, INT_ADR_REG_KER);
 +
-+#define BLKTAP_INVALIDATE_HANDLE(_g) do {       \
-+    (_g)->kernel = INVALID_GRANT_HANDLE; (_g)->user = INVALID_GRANT_HANDLE; \
-+    } while(0)
++      /* Enable interrupts */
++      falcon_interrupts(efx, 1, 0);
++
++      /* Force processing of all the channels to get the EVQ RPTRs up to
++         date */
++      efx_for_each_channel_with_interrupt(channel, efx)
++              efx_schedule_channel(channel);
++}
 +
++void falcon_disable_interrupts(struct efx_nic *efx)
++{
++      /* Disable interrupts */
++      falcon_interrupts(efx, 0, 0);
++}
 +
-+/******************************************************************
-+ * BLKTAP VM OPS
++/* Generate a Falcon test interrupt
++ * Interrupt must already have been enabled, otherwise nasty things
++ * may happen.
 + */
++void falcon_generate_interrupt(struct efx_nic *efx)
++{
++      falcon_interrupts(efx, 1, 1);
++}
 +
-+static struct page *blktap_nopage(struct vm_area_struct *vma,
-+                                unsigned long address,
-+                                int *type)
++/* Acknowledge a legacy interrupt from Falcon
++ *
++ * This acknowledges a legacy (not MSI) interrupt via INT_ACK_KER_REG.
++ *
++ * Due to SFC bug 3706 (silicon revision <=A1) reads can be duplicated in the
++ * BIU. Interrupt acknowledge is read sensitive so must write instead
++ * (then read to ensure the BIU collector is flushed)
++ *
++ * NB most hardware supports MSI interrupts
++ */
++static inline void falcon_irq_ack_a1(struct efx_nic *efx)
 +{
-+      /*
-+       * if the page has not been mapped in by the driver then return
-+       * NOPAGE_SIGBUS to the domain.
-+       */
++      efx_dword_t reg;
 +
-+      return NOPAGE_SIGBUS;
++      EFX_POPULATE_DWORD_1(reg, INT_ACK_DUMMY_DATA, 0xb7eb7e);
++      falcon_writel(efx, &reg, INT_ACK_REG_KER_A1);
++      falcon_readl(efx, &reg, WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1);
 +}
 +
-+static pte_t blktap_clear_pte(struct vm_area_struct *vma,
-+                            unsigned long uvaddr,
-+                            pte_t *ptep, int is_fullmm)
++/* Process a fatal interrupt
++ * Disable bus mastering ASAP and schedule a reset
++ */
++static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
 +{
-+      pte_t copy;
-+      tap_blkif_t *info;
-+      int offset, seg, usr_idx, pending_idx, mmap_idx;
-+      unsigned long uvstart = vma->vm_start + (RING_PAGES << PAGE_SHIFT);
-+      unsigned long kvaddr;
-+      struct page **map;
-+      struct page *pg;
-+      struct grant_handle_pair *khandle;
-+      struct gnttab_unmap_grant_ref unmap[2];
-+      int count = 0;
++      efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
++      efx_oword_t fatal_intr;
++      int error, mem_perr;
++      static int n_int_errors;
 +
-+      /*
-+       * If the address is before the start of the grant mapped region or
-+       * if vm_file is NULL (meaning mmap failed and we have nothing to do)
-+       */
-+      if (uvaddr < uvstart || vma->vm_file == NULL)
-+              return ptep_get_and_clear_full(vma->vm_mm, uvaddr, 
-+                                             ptep, is_fullmm);
++      falcon_read(efx, &fatal_intr, FATAL_INTR_REG_KER);
++      error = EFX_OWORD_FIELD(fatal_intr, INT_KER_ERROR);
 +
-+      info = vma->vm_file->private_data;
-+      map = vma->vm_private_data;
++      EFX_ERR(efx, "SYSTEM ERROR " EFX_OWORD_FMT " status "
++              EFX_OWORD_FMT ": %s\n", EFX_OWORD_VAL(*int_ker),
++              EFX_OWORD_VAL(fatal_intr),
++              error ? "disabling bus mastering" : "no recognised error");
++      if (error == 0)
++              goto out;
 +
-+      /* TODO Should these be changed to if statements? */
-+      BUG_ON(!info);
-+      BUG_ON(!info->idx_map);
-+      BUG_ON(!map);
++      /* If this is a memory parity error dump which blocks are offending */
++      mem_perr = EFX_OWORD_FIELD(fatal_intr, MEM_PERR_INT_KER);
++      if (mem_perr) {
++              efx_oword_t reg;
++              falcon_read(efx, &reg, MEM_STAT_REG_KER);
++              EFX_ERR(efx, "SYSTEM ERROR: memory parity error "
++                      EFX_OWORD_FMT "\n", EFX_OWORD_VAL(reg));
++      }
 +
-+      offset = (int) ((uvaddr - uvstart) >> PAGE_SHIFT);
-+      usr_idx = OFFSET_TO_USR_IDX(offset);
-+      seg = OFFSET_TO_SEG(offset);
++      /* Disable DMA bus mastering on both devices */
++      pci_disable_device(efx->pci_dev);
++      if (efx->type->is_dual_func)
++              pci_disable_device(efx->pci_dev2);
 +
-+      pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx]));
-+      mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]);
++      if (++n_int_errors < FALCON_MAX_INT_ERRORS) {
++              EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
++              efx_schedule_reset(efx, RESET_TYPE_INT_ERROR);
++      } else {
++              EFX_ERR(efx, "SYSTEM ERROR - max number of errors seen."
++                      "NIC will be disabled\n");
++              efx_schedule_reset(efx, RESET_TYPE_DISABLE);
++      }
++out:
++      return IRQ_HANDLED;
++}
 +
-+      kvaddr = idx_to_kaddr(mmap_idx, pending_idx, seg);
-+      pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
-+      ClearPageReserved(pg);
-+      map[offset + RING_PAGES] = NULL;
++/* Handle a legacy interrupt from Falcon
++ * Acknowledges the interrupt and schedule event queue processing.
++ *
++ * This routine must guarantee not to touch the hardware when
++ * interrupts are disabled, to allow for correct semantics of
++ * efx_suspend() and efx_resume().
++ */
++#if !defined(EFX_HAVE_IRQ_HANDLER_REGS)
++static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
++#else
++static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id,
++                                            struct pt_regs *regs
++                                            __attribute__ ((unused)))
++#endif
++{
++      struct efx_nic *efx = (struct efx_nic *)dev_id;
++      efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
++      struct efx_channel *channel;
++      efx_dword_t reg;
++      u32 queues;
++      int syserr;
 +
-+      khandle = &pending_handle(mmap_idx, pending_idx, seg);
++      /* Read the ISR which also ACKs the interrupts */
++      falcon_readl(efx, &reg, INT_ISR0_B0);
++      queues = EFX_EXTRACT_DWORD(reg, 0, 31);
 +
-+      if (khandle->kernel != INVALID_GRANT_HANDLE) {
-+              gnttab_set_unmap_op(&unmap[count], kvaddr, 
-+                                  GNTMAP_host_map, khandle->kernel);
-+              count++;
++      /* Check to see if we have a serious error condition */
++      syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
++      if (unlikely(syserr))
++              return falcon_fatal_interrupt(efx);
 +
-+              set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT, 
-+                                  INVALID_P2M_ENTRY);
++      if (queues == 0)
++              return IRQ_NONE;
++
++      efx->last_irq_cpu = raw_smp_processor_id();
++      EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
++                irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
++
++      /* Schedule processing of any interrupting queues */
++      channel = &efx->channel[0];
++      while (queues) {
++              if (queues & 0x01)
++                      efx_schedule_channel(channel);
++              channel++;
++              queues >>= 1;
 +      }
 +
-+      if (khandle->user != INVALID_GRANT_HANDLE) {
-+              BUG_ON(xen_feature(XENFEAT_auto_translated_physmap));
++      return IRQ_HANDLED;
++}
 +
-+              copy = *ptep;
-+              gnttab_set_unmap_op(&unmap[count], virt_to_machine(ptep), 
-+                                  GNTMAP_host_map 
-+                                  | GNTMAP_application_map 
-+                                  | GNTMAP_contains_pte,
-+                                  khandle->user);
-+              count++;
-+      } else {
-+              BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap));
 +
-+              /* USING SHADOW PAGE TABLES. */
-+              copy = ptep_get_and_clear_full(vma->vm_mm, uvaddr, ptep,
-+                                             is_fullmm);
++#if !defined(EFX_HAVE_IRQ_HANDLER_REGS)
++static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id)
++#else
++static irqreturn_t falcon_legacy_interrupt_a1(int irq, void *dev_id,
++                                            struct pt_regs *regs
++                                            __attribute__ ((unused)))
++#endif
++{
++      struct efx_nic *efx = (struct efx_nic *)dev_id;
++      efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
++      struct efx_channel *channel;
++      int syserr;
++      int queues;
++
++      /* Check to see if this is our interrupt.  If it isn't, we
++       * exit without having touched the hardware.
++       */
++      if (unlikely(EFX_OWORD_IS_ZERO(*int_ker))) {
++              EFX_TRACE(efx, "IRQ %d on CPU %d not for me\n", irq,
++                        raw_smp_processor_id());
++              return IRQ_NONE;
 +      }
++      efx->last_irq_cpu = raw_smp_processor_id();
++      EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
++                irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
 +
-+      if (count) {
-+              BLKTAP_INVALIDATE_HANDLE(khandle);
-+              if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
-+                                            unmap, count))
-+                      BUG();
++      /* Check to see if we have a serious error condition */
++      syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
++      if (unlikely(syserr))
++              return falcon_fatal_interrupt(efx);
++
++      /* Determine interrupting queues, clear interrupt status
++       * register and acknowledge the device interrupt.
++       */
++      BUILD_BUG_ON(INT_EVQS_WIDTH > EFX_MAX_CHANNELS);
++      queues = EFX_OWORD_FIELD(*int_ker, INT_EVQS);
++      EFX_ZERO_OWORD(*int_ker);
++      wmb(); /* Ensure the vector is cleared before interrupt ack */
++      falcon_irq_ack_a1(efx);
++
++      /* Schedule processing of any interrupting queues */
++      channel = &efx->channel[0];
++      while (queues) {
++              if (queues & 0x01)
++                      efx_schedule_channel(channel);
++              channel++;
++              queues >>= 1;
 +      }
 +
-+      return copy;
++      return IRQ_HANDLED;
 +}
 +
-+struct vm_operations_struct blktap_vm_ops = {
-+      nopage:   blktap_nopage,
-+      zap_pte:  blktap_clear_pte,
-+};
-+
-+/******************************************************************
-+ * BLKTAP FILE OPS
++/* Handle an MSI interrupt from Falcon
++ *
++ * Handle an MSI hardware interrupt.  This routine schedules event
++ * queue processing.  No interrupt acknowledgement cycle is necessary.
++ * Also, we never need to check that the interrupt is for us, since
++ * MSI interrupts cannot be shared.
++ *
++ * This routine must guarantee not to touch the hardware when
++ * interrupts are disabled, to allow for correct semantics of
++ * efx_suspend() and efx_resume().
 + */
-+ 
-+/*Function Declarations*/
-+static tap_blkif_t *get_next_free_dev(void);
-+static int blktap_open(struct inode *inode, struct file *filp);
-+static int blktap_release(struct inode *inode, struct file *filp);
-+static int blktap_mmap(struct file *filp, struct vm_area_struct *vma);
-+static int blktap_ioctl(struct inode *inode, struct file *filp,
-+                        unsigned int cmd, unsigned long arg);
-+static unsigned int blktap_poll(struct file *file, poll_table *wait);
++#if !defined(EFX_HAVE_IRQ_HANDLER_REGS)
++static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id)
++#else
++static irqreturn_t falcon_msi_interrupt(int irq, void *dev_id,
++                                      struct pt_regs *regs
++                                      __attribute__ ((unused)))
++#endif
++{
++      struct efx_channel *channel = (struct efx_channel *)dev_id;
++      struct efx_nic *efx = channel->efx;
++      efx_oword_t *int_ker = (efx_oword_t *) efx->irq_status.addr;
++      int syserr;
 +
-+static const struct file_operations blktap_fops = {
-+      .owner   = THIS_MODULE,
-+      .poll    = blktap_poll,
-+      .ioctl   = blktap_ioctl,
-+      .open    = blktap_open,
-+      .release = blktap_release,
-+      .mmap    = blktap_mmap,
-+};
++      efx->last_irq_cpu = raw_smp_processor_id();
++      EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_OWORD_FMT "\n",
++                irq, raw_smp_processor_id(), EFX_OWORD_VAL(*int_ker));
 +
++      /* Check to see if we have a serious error condition */
++      syserr = EFX_OWORD_FIELD(*int_ker, FATAL_INT);
++      if (unlikely(syserr))
++              return falcon_fatal_interrupt(efx);
 +
-+static tap_blkif_t *get_next_free_dev(void)
-+{
-+      struct class *class;
-+      tap_blkif_t *info;
-+      int minor;
++      /* Schedule processing of the channel */
++      efx_schedule_channel(channel);
 +
-+      /*
-+       * This is called only from the ioctl, which
-+       * means we should always have interrupts enabled.
-+       */
-+      BUG_ON(irqs_disabled());
++      return IRQ_HANDLED;
++}
 +
-+      spin_lock_irq(&pending_free_lock);
 +
-+      /* tapfds[0] is always NULL */
++/* Setup RSS indirection table.
++ * This maps from the hash value of the packet to RXQ
++ */
++static void falcon_setup_rss_indir_table(struct efx_nic *efx)
++{
++      int i = 0;
++      unsigned long offset;
++      unsigned long flags __attribute__ ((unused));
++      efx_dword_t dword;
 +
-+      for (minor = 1; minor < blktap_next_minor; minor++) {
-+              info = tapfds[minor];
-+              /* we could have failed a previous attempt. */
-+              if (!info ||
-+                  ((info->dev_inuse == 0) &&
-+                   (info->dev_pending == 0)) ) {
-+                      info->dev_pending = 1;
-+                      goto found;
-+              }
++      if (FALCON_REV(efx) < FALCON_REV_B0)
++              return;
++
++      for (offset = RX_RSS_INDIR_TBL_B0;
++           offset < RX_RSS_INDIR_TBL_B0 + 0x800;
++           offset += 0x10) {
++              EFX_POPULATE_DWORD_1(dword, RX_RSS_INDIR_ENT_B0,
++                                   i % efx->rss_queues);
++              falcon_writel(efx, &dword, offset);
++              i++;
 +      }
-+      info = NULL;
-+      minor = -1;
++}
 +
-+      /*
-+       * We didn't find free device. If we can still allocate
-+       * more, then we grab the next device minor that is
-+       * available.  This is done while we are still under
-+       * the protection of the pending_free_lock.
-+       */
-+      if (blktap_next_minor < MAX_TAP_DEV)
-+              minor = blktap_next_minor++;
-+found:
-+      spin_unlock_irq(&pending_free_lock);
++/* Hook interrupt handler(s)
++ * Try MSI and then legacy interrupts.
++ */
++int falcon_init_interrupt(struct efx_nic *efx)
++{
++      struct efx_channel *channel;
++      int rc;
 +
-+      if (!info && minor > 0) {
-+              info = kzalloc(sizeof(*info), GFP_KERNEL);
-+              if (unlikely(!info)) {
-+                      /*
-+                       * If we failed here, try to put back
-+                       * the next minor number. But if one
-+                       * was just taken, then we just lose this
-+                       * minor.  We can try to allocate this
-+                       * minor again later.
-+                       */
-+                      spin_lock_irq(&pending_free_lock);
-+                      if (blktap_next_minor == minor+1)
-+                              blktap_next_minor--;
-+                      spin_unlock_irq(&pending_free_lock);
-+                      goto out;
-+              }
++      if (!EFX_INT_MODE_USE_MSI(efx)) {
++              irq_handler_t handler;
++              if (FALCON_REV(efx) >= FALCON_REV_B0)
++                      handler = falcon_legacy_interrupt_b0;
++              else
++                      handler = falcon_legacy_interrupt_a1;
 +
-+              info->minor = minor;
-+              /*
-+               * Make sure that we have a minor before others can
-+               * see us.
-+               */
-+              wmb();
-+              tapfds[minor] = info;
++              rc = request_irq(efx->legacy_irq, handler, IRQF_SHARED,
++                               efx->name, efx);
++              if (rc) {
++                      EFX_ERR(efx, "failed to hook legacy IRQ %d\n",
++                              efx->pci_dev->irq);
++                      goto fail1;
++              }
++              return 0;
++      }
 +
-+              if ((class = get_xen_class()) != NULL)
-+                      class_device_create(class, NULL,
-+                                          MKDEV(blktap_major, minor), NULL,
-+                                          "blktap%d", minor);
++      /* Hook MSI or MSI-X interrupt */
++      efx_for_each_channel_with_interrupt(channel, efx) {
++              rc = request_irq(channel->irq, falcon_msi_interrupt,
++                               IRQF_PROBE_SHARED, /* Not shared */
++                               efx->name, channel);
++              if (rc) {
++                      EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq);
++                      goto fail2;
++              }
 +      }
 +
-+out:
-+      return info;
++      return 0;
++
++ fail2:
++      efx_for_each_channel_with_interrupt(channel, efx)
++              free_irq(channel->irq, channel);
++ fail1:
++      return rc;
 +}
 +
-+int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif) 
++void falcon_fini_interrupt(struct efx_nic *efx)
 +{
-+      tap_blkif_t *info;
-+      int i;
++      struct efx_channel *channel;
++      efx_oword_t reg;
 +
-+      for (i = 1; i < blktap_next_minor; i++) {
-+              info = tapfds[i];
-+              if ( info &&
-+                   (info->trans.domid == domid) &&
-+                   (info->trans.busid == xenbus_id) ) {
-+                      info->blkif = blkif;
-+                      info->status = RUNNING;
-+                      return i;
-+              }
-+      }
-+      return -1;
-+}
++      /* Disable MSI/MSI-X interrupts */
++      efx_for_each_channel_with_interrupt(channel, efx)
++              if (channel->irq)
++                      free_irq(channel->irq, channel);
 +
-+void signal_tapdisk(int idx) 
-+{
-+      tap_blkif_t *info;
-+      struct task_struct *ptask;
++      /* ACK legacy interrupt */
++      if (FALCON_REV(efx) >= FALCON_REV_B0)
++              falcon_read(efx, &reg, INT_ISR0_B0);
++      else
++              falcon_irq_ack_a1(efx);
 +
-+      info = tapfds[idx];
-+      if ((idx < 0) || (idx > MAX_TAP_DEV) || !info)
-+              return;
++      /* Disable legacy interrupt */
++      if (efx->legacy_irq)
++              free_irq(efx->legacy_irq, efx);
++}
 +
-+      if (info->pid > 0) {
-+              ptask = find_task_by_pid(info->pid);
-+              if (ptask)
-+                      info->status = CLEANSHUTDOWN;
-+      }
-+      info->blkif = NULL;
++/**************************************************************************
++ *
++ * EEPROM/flash
++ *
++ **************************************************************************
++ */
 +
-+      return;
++/* Wait for SPI command completion */
++static int falcon_spi_wait(struct efx_nic *efx)
++{
++      efx_oword_t reg;
++      int cmd_en, timer_active;
++      int count;
++
++      count = 0;
++      do {
++              falcon_read(efx, &reg, EE_SPI_HCMD_REG_KER);
++              cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN);
++              timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE);
++              if (!cmd_en && !timer_active)
++                      return 0;
++              udelay(10);
++      } while (++count < 10000); /* wait upto 100msec */
++      EFX_ERR(efx, "timed out waiting for SPI\n");
++      return -ETIMEDOUT;
 +}
 +
-+static int blktap_open(struct inode *inode, struct file *filp)
++static int
++falcon_spi_read(const struct efx_spi_device *spi, struct efx_nic *efx,
++              unsigned int command, int address, void *data, unsigned int len)
 +{
-+      blkif_sring_t *sring;
-+      int idx = iminor(inode) - BLKTAP_MINOR;
-+      tap_blkif_t *info;
-+      int i;
-+      
-+      /* ctrl device, treat differently */
-+      if (!idx)
-+              return 0;
++      int addressed = (address >= 0);
++      efx_oword_t reg;
++      int rc;
 +
-+      info = tapfds[idx];
++      /* Input validation */
++      if (len > FALCON_SPI_MAX_LEN)
++              return -EINVAL;
 +
-+      if ((idx < 0) || (idx > MAX_TAP_DEV) || !info) {
-+              WPRINTK("Unable to open device /dev/xen/blktap%d\n",
-+                      idx);
-+              return -ENODEV;
-+      }
++      /* Acquire SPI lock */
++      mutex_lock(&efx->spi_lock);
 +
-+      DPRINTK("Opening device /dev/xen/blktap%d\n",idx);
-+      
-+      /*Only one process can access device at a time*/
-+      if (test_and_set_bit(0, &info->dev_inuse))
-+              return -EBUSY;
++      /* Check SPI not currently being accessed */
++      rc = falcon_spi_wait(efx);
++      if (rc)
++              goto out;
 +
-+      info->dev_pending = 0;
-+          
-+      /* Allocate the fe ring. */
-+      sring = (blkif_sring_t *)get_zeroed_page(GFP_KERNEL);
-+      if (sring == NULL)
-+              goto fail_nomem;
++      /* Program address register, if we have an address */
++      if (addressed) {
++              EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
++              falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
++      }
++
++      /* Issue read command */
++      EFX_POPULATE_OWORD_7(reg,
++                           EE_SPI_HCMD_CMD_EN, 1,
++                           EE_SPI_HCMD_SF_SEL, spi->device_id,
++                           EE_SPI_HCMD_DABCNT, len,
++                           EE_SPI_HCMD_READ, EE_SPI_READ,
++                           EE_SPI_HCMD_DUBCNT, 0,
++                           EE_SPI_HCMD_ADBCNT,
++                           (addressed ? spi->addr_len : 0),
++                           EE_SPI_HCMD_ENC, command);
++      falcon_write(efx, &reg, EE_SPI_HCMD_REG_KER);
++
++      /* Wait for read to complete */
++      rc = falcon_spi_wait(efx);
++      if (rc)
++              goto out;
 +
-+      SetPageReserved(virt_to_page(sring));
-+    
-+      SHARED_RING_INIT(sring);
-+      FRONT_RING_INIT(&info->ufe_ring, sring, PAGE_SIZE);
-+      
-+      filp->private_data = info;
-+      info->vma = NULL;
++      /* Read data */
++      falcon_read(efx, &reg, EE_SPI_HDATA_REG_KER);
++      memcpy(data, &reg, len);
 +
-+      info->idx_map = kmalloc(sizeof(unsigned long) * MAX_PENDING_REQS, 
-+                              GFP_KERNEL);
-+      
-+      if (info->idx_map == NULL)
-+              goto fail_nomem;
++ out:
++      /* Release SPI lock */
++      mutex_unlock(&efx->spi_lock);
 +
-+      if (idx > 0) {
-+              init_waitqueue_head(&info->wait);
-+              for (i = 0; i < MAX_PENDING_REQS; i++) 
-+                      info->idx_map[i] = INVALID_REQ;
++      return rc;
++}
++
++static int
++falcon_spi_write(const struct efx_spi_device *spi, struct efx_nic *efx,
++               unsigned int command, int address, const void *data,
++               unsigned int len)
++{
++      int addressed = (address >= 0);
++      efx_oword_t reg;
++      int rc;
++
++      /* Input validation */
++      if (len > (addressed ? efx_spi_write_limit(spi, address)
++                 : FALCON_SPI_MAX_LEN))
++              return -EINVAL;
++
++      /* Acquire SPI lock */
++      mutex_lock(&efx->spi_lock);
++
++      /* Check SPI not currently being accessed */
++      rc = falcon_spi_wait(efx);
++      if (rc)
++              goto out;
++
++      /* Program address register, if we have an address */
++      if (addressed) {
++              EFX_POPULATE_OWORD_1(reg, EE_SPI_HADR_ADR, address);
++              falcon_write(efx, &reg, EE_SPI_HADR_REG_KER);
 +      }
 +
-+      DPRINTK("Tap open: device /dev/xen/blktap%d\n",idx);
-+      return 0;
++      /* Program data register, if we have data */
++      if (data) {
++              memcpy(&reg, data, len);
++              falcon_write(efx, &reg, EE_SPI_HDATA_REG_KER);
++      }
++
++      /* Issue write command */
++      EFX_POPULATE_OWORD_7(reg,
++                           EE_SPI_HCMD_CMD_EN, 1,
++                           EE_SPI_HCMD_SF_SEL, spi->device_id,
++                           EE_SPI_HCMD_DABCNT, len,
++                           EE_SPI_HCMD_READ, EE_SPI_WRITE,
++                           EE_SPI_HCMD_DUBCNT, 0,
++                           EE_SPI_HCMD_ADBCNT,
++                           (addressed ? spi->addr_len : 0),
++                           EE_SPI_HCMD_ENC, command);
++      falcon_write(efx, &reg, EE_SPI_HCMD_REG_KER);
++
++      /* Wait for write to complete */
++      rc = falcon_spi_wait(efx);
++      if (rc)
++              goto out;
 +
-+ fail_nomem:
-+      return -ENOMEM;
++ out:
++      /* Release SPI lock */
++      mutex_unlock(&efx->spi_lock);
++
++      return rc;
 +}
 +
-+static int blktap_release(struct inode *inode, struct file *filp)
++/**************************************************************************
++ *
++ * MAC wrapper
++ *
++ **************************************************************************
++ */
++void falcon_drain_tx_fifo(struct efx_nic *efx)
 +{
-+      tap_blkif_t *info = filp->private_data;
-+      
-+      /* check for control device */
-+      if (!info)
-+              return 0;
++      efx_oword_t temp;
++      efx_oword_t mcast_reg0;
++      efx_oword_t mcast_reg1;
++      int count;
 +
-+      info->dev_inuse = 0;
-+      DPRINTK("Freeing device [/dev/xen/blktap%d]\n",info->minor);
++      if (FALCON_REV(efx) < FALCON_REV_B0)
++              return;
 +
-+      /* Free the ring page. */
-+      ClearPageReserved(virt_to_page(info->ufe_ring.sring));
-+      free_page((unsigned long) info->ufe_ring.sring);
++      falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
++      /* There is no point in draining more than once */
++      if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
++              return;
 +
-+      /* Clear any active mappings and free foreign map table */
-+      if (info->vma) {
-+              zap_page_range(
-+                      info->vma, info->vma->vm_start, 
-+                      info->vma->vm_end - info->vma->vm_start, NULL);
++      /* MAC stats will fail whilst the TX fifo is draining. Serialise
++       * the drain sequence with the statistics fetch */
++      spin_lock(&efx->stats_lock);
 +
-+              kfree(info->vma->vm_private_data);
++      EFX_SET_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0, 1);
++      falcon_write(efx, &temp, MAC0_CTRL_REG_KER);
 +
-+              info->vma = NULL;
-+      }
++      falcon_read(efx, &mcast_reg0, MAC_MCAST_HASH_REG0_KER);
++      falcon_read(efx, &mcast_reg1, MAC_MCAST_HASH_REG1_KER);
 +
-+      if (info->idx_map) {
-+              kfree(info->idx_map);
-+              info->idx_map = NULL;
-+      }
++      /* Reset the MAC and EM block. */
++      falcon_read(efx, &temp, GLB_CTL_REG_KER);
++      EFX_SET_OWORD_FIELD(temp, RST_XGTX, 1);
++      EFX_SET_OWORD_FIELD(temp, RST_XGRX, 1);
++      EFX_SET_OWORD_FIELD(temp, RST_EM, 1);
++      falcon_write(efx, &temp, GLB_CTL_REG_KER);
 +
-+      if ( (info->status != CLEANSHUTDOWN) && (info->blkif != NULL) ) {
-+              if (info->blkif->xenblkd != NULL) {
-+                      kthread_stop(info->blkif->xenblkd);
-+                      info->blkif->xenblkd = NULL;
++      count = 0;
++      while (1) {
++              falcon_read(efx, &temp, GLB_CTL_REG_KER);
++              if (!EFX_OWORD_FIELD(temp, RST_XGTX) &&
++                  !EFX_OWORD_FIELD(temp, RST_XGRX) &&
++                  !EFX_OWORD_FIELD(temp, RST_EM)) {
++                      EFX_LOG(efx, "Completed MAC reset after %d loops\n",
++                              count);
++                      break;
 +              }
-+              info->status = CLEANSHUTDOWN;
++              if (count > 20) {
++                      EFX_ERR(efx, "MAC reset failed\n");
++                      break;
++              }
++              count++;
++              udelay(10);
 +      }
 +
-+      return 0;
++      spin_unlock(&efx->stats_lock);
++
++      /* Restore the multicast hash registers. */
++      falcon_write(efx, &mcast_reg0, MAC_MCAST_HASH_REG0_KER);
++      falcon_write(efx, &mcast_reg1, MAC_MCAST_HASH_REG1_KER);
++
++      /* If we've reset the EM block and the link is up, then
++       * we'll have to kick the XAUI link so the PHY can recover */
++      if (efx->link_up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx))
++              falcon_reset_xaui(efx);
 +}
 +
++void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
++{
++      struct falcon_nic_data *nic_data = efx->nic_data;
++      efx_oword_t temp;
++      int changing_loopback;
 +
-+/* Note on mmap:
-+ * We need to map pages to user space in a way that will allow the block
-+ * subsystem set up direct IO to them.  This couldn't be done before, because
-+ * there isn't really a sane way to translate a user virtual address down to a 
-+ * physical address when the page belongs to another domain.
-+ *
-+ * My first approach was to map the page in to kernel memory, add an entry
-+ * for it in the physical frame list (using alloc_lomem_region as in blkback)
-+ * and then attempt to map that page up to user space.  This is disallowed
-+ * by xen though, which realizes that we don't really own the machine frame
-+ * underlying the physical page.
-+ *
-+ * The new approach is to provide explicit support for this in xen linux.
-+ * The VMA now has a flag, VM_FOREIGN, to indicate that it contains pages
-+ * mapped from other vms.  vma->vm_private_data is set up as a mapping 
-+ * from pages to actual page structs.  There is a new clause in get_user_pages
-+ * that does the right thing for this sort of mapping.
-+ */
-+static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
++      if (FALCON_REV(efx) < FALCON_REV_B0)
++              return;
++
++      /* Isolate the MAC -> RX */
++      falcon_read(efx, &temp, RX_CFG_REG_KER);
++      EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 0);
++      falcon_write(efx, &temp, RX_CFG_REG_KER);
++
++      /* Synchronise the EM block against any loopback mode changes by
++       * draining the TX fifo and resetting. */
++      changing_loopback = (efx->loopback_mode != nic_data->old_loopback_mode);
++      nic_data->old_loopback_mode = efx->loopback_mode;
++      if (changing_loopback || !efx->link_up)
++              falcon_drain_tx_fifo(efx);
++}
++
++void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
 +{
-+      int size;
-+      struct page **map;
++      efx_oword_t reg;
++      int link_speed;
++      unsigned int tx_fc;
++
++      if (efx->link_options & GM_LPA_10000)
++              link_speed = 0x3;
++      else if (efx->link_options & GM_LPA_1000)
++              link_speed = 0x2;
++      else if (efx->link_options & GM_LPA_100)
++              link_speed = 0x1;
++      else
++              link_speed = 0x0;
++      /* MAC_LINK_STATUS controls MAC backpressure but doesn't work
++       * as advertised.  Disable to ensure packets are not
++       * indefinitely held and TX queue can be flushed at any point
++       * while the link is down.
++       */
++      EFX_POPULATE_OWORD_5(reg,
++                           MAC_XOFF_VAL, 0xffff /* max pause time */,
++                           MAC_BCAD_ACPT, 1,
++                           MAC_UC_PROM, efx->promiscuous,
++                           MAC_LINK_STATUS, 1, /* always set */
++                           MAC_SPEED, link_speed);
++      /* On B0, MAC backpressure can be disabled and packets get
++       * discarded. */
++      if (FALCON_REV(efx) >= FALCON_REV_B0) {
++              EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0,
++                                  !efx->link_up);
++      }
++
++      falcon_write(efx, &reg, MAC0_CTRL_REG_KER);
++
++      /*
++       * Transmission of pause frames when RX crosses the threshold is
++       * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
++       *
++       * Action on receipt of pause frames is controller by XM_DIS_FCNTL
++       */
++      tx_fc = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
++      falcon_read(efx, &reg, RX_CFG_REG_KER);
++      EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);
++
++      /* Unisolate the MAC -> RX */
++      if (FALCON_REV(efx) >= FALCON_REV_B0)
++              EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 1);
++      falcon_write(efx, &reg, RX_CFG_REG_KER);
++}
++
++int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset)
++{
++      efx_oword_t reg;
++      u32 *dma_done;
 +      int i;
-+      tap_blkif_t *info = filp->private_data;
-+      int ret;
 +
-+      if (info == NULL) {
-+              WPRINTK("blktap: mmap, retrieving idx failed\n");
-+              return -ENOMEM;
-+      }
-+      
-+      vma->vm_flags |= VM_RESERVED;
-+      vma->vm_ops = &blktap_vm_ops;
++      if (disable_dma_stats)
++              return 0;
 +
-+      size = vma->vm_end - vma->vm_start;
-+      if (size != ((mmap_pages + RING_PAGES) << PAGE_SHIFT)) {
-+              WPRINTK("you _must_ map exactly %d pages!\n",
-+                     mmap_pages + RING_PAGES);
-+              return -EAGAIN;
++      /* Statistics fetch will fail if the MAC is in TX drain */
++      if (FALCON_REV(efx) >= FALCON_REV_B0) {
++              efx_oword_t temp;
++              falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
++              if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
++                      return 0;
 +      }
 +
-+      size >>= PAGE_SHIFT;
-+      info->rings_vstart = vma->vm_start;
-+      info->user_vstart  = info->rings_vstart + (RING_PAGES << PAGE_SHIFT);
-+    
-+      /* Map the ring pages to the start of the region and reserve it. */
-+      if (xen_feature(XENFEAT_auto_translated_physmap))
-+              ret = vm_insert_page(vma, vma->vm_start,
-+                                   virt_to_page(info->ufe_ring.sring));
-+      else
-+              ret = remap_pfn_range(vma, vma->vm_start,
-+                                    __pa(info->ufe_ring.sring) >> PAGE_SHIFT,
-+                                    PAGE_SIZE, vma->vm_page_prot);
-+      if (ret) {
-+              WPRINTK("Mapping user ring failed!\n");
-+              goto fail;
++      /* Clear completion pointer */
++      dma_done = (efx->stats_buffer.addr + done_offset);
++      *dma_done = FALCON_STATS_NOT_DONE;
++      wmb(); /* ensure done flag is clear */
++
++      /* Initiate DMA transfer of stats */
++      EFX_POPULATE_OWORD_2(reg,
++                           MAC_STAT_DMA_CMD, 1,
++                           MAC_STAT_DMA_ADR,
++                           efx->stats_buffer.dma_addr);
++      falcon_write(efx, &reg, MAC0_STAT_DMA_REG_KER);
++
++      /* Wait for transfer to complete */
++      for (i = 0; i < 400; i++) {
++              if (*(volatile u32 *)dma_done == FALCON_STATS_DONE)
++                      return 0;
++              udelay(10);
 +      }
 +
-+      /* Mark this VM as containing foreign pages, and set up mappings. */
-+      map = kzalloc(((vma->vm_end - vma->vm_start) >> PAGE_SHIFT)
-+                    * sizeof(struct page_struct*),
-+                    GFP_KERNEL);
-+      if (map == NULL) {
-+              WPRINTK("Couldn't alloc VM_FOREIGN map.\n");
-+              goto fail;
++      if (EFX_WORKAROUND_8419(efx)) {
++              disable_dma_stats = 1;
++              EFX_INFO(efx, "MAC stats DMA disabled\n");
++      } else {
++              EFX_ERR(efx, "timed out waiting for statistics\n");
 +      }
 +
-+      for (i = 0; i < ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT); i++)
-+              map[i] = NULL;
-+    
-+      vma->vm_private_data = map;
-+      vma->vm_flags |= VM_FOREIGN;
-+      vma->vm_flags |= VM_DONTCOPY;
++      return -ETIMEDOUT;
++}
 +
-+#ifdef CONFIG_X86
-+      vma->vm_mm->context.has_foreign_mappings = 1;
-+#endif
++/**************************************************************************
++ *
++ * PHY access via GMII
++ *
++ **************************************************************************
++ */
 +
-+      info->vma = vma;
-+      info->ring_ok = 1;
-+      return 0;
-+ fail:
-+      /* Clear any active mappings. */
-+      zap_page_range(vma, vma->vm_start, 
-+                     vma->vm_end - vma->vm_start, NULL);
++/* Use the top bit of the MII PHY id to indicate the PHY type
++ * (1G/10G), with the remaining bits as the actual PHY id.
++ *
++ * This allows us to avoid leaking information from the mii_if_info
++ * structure into other data structures.
++ */
++#define FALCON_PHY_ID_ID_WIDTH  EFX_WIDTH(MD_PRT_DEV_ADR)
++#define FALCON_PHY_ID_ID_MASK   ((1 << FALCON_PHY_ID_ID_WIDTH) - 1)
++#define FALCON_PHY_ID_WIDTH     (FALCON_PHY_ID_ID_WIDTH + 1)
++#define FALCON_PHY_ID_MASK      ((1 << FALCON_PHY_ID_WIDTH) - 1)
++#define FALCON_PHY_ID_10G       (1 << (FALCON_PHY_ID_WIDTH - 1))
 +
-+      return -ENOMEM;
-+}
 +
++/* Packing the clause 45 port and device fields into a single value */
++#define MD_PRT_ADR_COMP_LBN   (MD_PRT_ADR_LBN - MD_DEV_ADR_LBN)
++#define MD_PRT_ADR_COMP_WIDTH  MD_PRT_ADR_WIDTH
++#define MD_DEV_ADR_COMP_LBN    0
++#define MD_DEV_ADR_COMP_WIDTH  MD_DEV_ADR_WIDTH
 +
-+static int blktap_ioctl(struct inode *inode, struct file *filp,
-+                        unsigned int cmd, unsigned long arg)
++
++/* Wait for GMII access to complete */
++static int falcon_gmii_wait(struct efx_nic *efx)
 +{
-+      tap_blkif_t *info = filp->private_data;
++      efx_dword_t md_stat;
++      int count;
 +
-+      switch(cmd) {
-+      case BLKTAP_IOCTL_KICK_FE: 
-+      {
-+              /* There are fe messages to process. */
-+              return blktap_read_ufe_ring(info);
-+      }
-+      case BLKTAP_IOCTL_SETMODE:
-+      {
-+              if (info) {
-+                      if (BLKTAP_MODE_VALID(arg)) {
-+                              info->mode = arg;
-+                              /* XXX: may need to flush rings here. */
-+                              DPRINTK("blktap: set mode to %lx\n", 
-+                                     arg);
-+                              return 0;
++      for (count = 0; count < 1000; count++) {        /* wait upto 10ms */
++              falcon_readl(efx, &md_stat, MD_STAT_REG_KER);
++              if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) {
++                      if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 ||
++                          EFX_DWORD_FIELD(md_stat, MD_BSERR) != 0) {
++                              EFX_ERR(efx, "error from GMII access "
++                                      EFX_DWORD_FMT"\n",
++                                      EFX_DWORD_VAL(md_stat));
++                              return -EIO;
 +                      }
++                      return 0;
 +              }
-+              return 0;
-+      }
-+      case BLKTAP_IOCTL_PRINT_IDXS:
-+        {
-+              if (info) {
-+                      printk("User Rings: \n-----------\n");
-+                      printk("UF: rsp_cons: %2d, req_prod_prv: %2d "
-+                              "| req_prod: %2d, rsp_prod: %2d\n",
-+                              info->ufe_ring.rsp_cons,
-+                              info->ufe_ring.req_prod_pvt,
-+                              info->ufe_ring.sring->req_prod,
-+                              info->ufe_ring.sring->rsp_prod);
-+              }
-+              return 0;
-+        }
-+      case BLKTAP_IOCTL_SENDPID:
-+      {
-+              if (info) {
-+                      info->pid = (pid_t)arg;
-+                      DPRINTK("blktap: pid received %d\n", 
-+                             info->pid);
-+              }
-+              return 0;
++              udelay(10);
 +      }
-+      case BLKTAP_IOCTL_NEWINTF:
-+      {               
-+              uint64_t val = (uint64_t)arg;
-+              domid_translate_t *tr = (domid_translate_t *)&val;
++      EFX_ERR(efx, "timed out waiting for GMII\n");
++      return -ETIMEDOUT;
++}
 +
-+              DPRINTK("NEWINTF Req for domid %d and bus id %d\n", 
-+                     tr->domid, tr->busid);
-+              info = get_next_free_dev();
-+              if (!info) {
-+                      WPRINTK("Error initialising /dev/xen/blktap - "
-+                              "No more devices\n");
-+                      return -1;
-+              }
-+              info->trans.domid = tr->domid;
-+              info->trans.busid = tr->busid;
-+              return info->minor;
++/* Writes a GMII register of a PHY connected to Falcon using MDIO. */
++static void falcon_mdio_write(struct net_device *net_dev, int phy_id,
++                            int addr, int value)
++{
++      struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
++      unsigned int phy_id2 = phy_id & FALCON_PHY_ID_ID_MASK;
++      unsigned int phy_10g = phy_id & FALCON_PHY_ID_10G;
++      efx_oword_t reg;
++
++      /* The 'generic' prt/dev packing in mdio_10g.h is conveniently
++       * chosen so that the only current user, Falcon, can take the
++       * packed value and use them directly.
++       * Fail to build if this assumption is broken.
++       */
++      BUILD_BUG_ON(FALCON_PHY_ID_10G != MDIO45_XPRT_ID_IS10G);
++      BUILD_BUG_ON(FALCON_PHY_ID_ID_WIDTH != MDIO45_PRT_DEV_WIDTH);
++      BUILD_BUG_ON(MD_PRT_ADR_COMP_LBN != MDIO45_PRT_ID_COMP_LBN);
++      BUILD_BUG_ON(MD_DEV_ADR_COMP_LBN != MDIO45_DEV_ID_COMP_LBN);
++
++      if (phy_id2 == PHY_ADDR_INVALID)
++              return;
++
++      /* See falcon_mdio_read for an explanation. */
++      if (EFX_ISCLAUSE45(efx) && !phy_10g) {
++              int mmd = ffs(efx->phy_op->mmds) - 1;
++              EFX_TRACE(efx, "Fixing erroneous clause22 write\n");
++              phy_id2 = mdio_clause45_pack(phy_id2, mmd)
++                      & FALCON_PHY_ID_ID_MASK;
++              phy_10g = 1;
 +      }
-+      case BLKTAP_IOCTL_FREEINTF:
-+      {
-+              unsigned long dev = arg;
-+              unsigned long flags;
 +
-+              info = tapfds[dev];
++      EFX_REGDUMP(efx, "writing GMII %d register %02x with %04x\n", phy_id,
++                  addr, value);
 +
-+              if ((dev > MAX_TAP_DEV) || !info)
-+                      return 0; /* should this be an error? */
++      /* Obtain PHY lock */
++      spin_lock_bh(&efx->phy_lock);
 +
-+              spin_lock_irqsave(&pending_free_lock, flags);
-+              if (info->dev_pending)
-+                      info->dev_pending = 0;
-+              spin_unlock_irqrestore(&pending_free_lock, flags);
++      /* Check MII not currently being accessed */
++      if (falcon_gmii_wait(efx) != 0)
++              goto out;
 +
-+              return 0;
++      /* Write the address/ID register */
++      EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
++      falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
++
++      if (phy_10g)
++              EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_id2);
++      else
++              /* MDIO clause 22 */
++              EFX_POPULATE_OWORD_2(reg,
++                                   MD_PRT_ADR, phy_id2,
++                                   MD_DEV_ADR, addr);
++      falcon_write(efx, &reg, MD_ID_REG_KER);
++
++      /* Write data */
++      EFX_POPULATE_OWORD_1(reg, MD_TXD, value);
++      falcon_write(efx, &reg, MD_TXD_REG_KER);
++
++      EFX_POPULATE_OWORD_2(reg,
++                           MD_WRC, 1,
++                           MD_GC, (phy_10g ? 0 : 1));
++      falcon_write(efx, &reg, MD_CS_REG_KER);
++
++      /* Wait for data to be written */
++      if (falcon_gmii_wait(efx) != 0) {
++              /* Abort the write operation */
++              EFX_POPULATE_OWORD_2(reg,
++                                   MD_WRC, 0,
++                                   MD_GC, 1);
++              falcon_write(efx, &reg, MD_CS_REG_KER);
++              udelay(10);
 +      }
-+      case BLKTAP_IOCTL_MINOR:
-+      {
-+              unsigned long dev = arg;
 +
-+              info = tapfds[dev];
++ out:
++      /* Release PHY lock */
++      spin_unlock_bh(&efx->phy_lock);
++}
 +
-+              if ((dev > MAX_TAP_DEV) || !info)
-+                      return -EINVAL;
++/* Reads a GMII register from a PHY connected to Falcon.  If no value
++ * could be read, -1 will be returned. */
++static int falcon_mdio_read(struct net_device *net_dev, int phy_id, int addr)
++{
++      struct efx_nic *efx = (struct efx_nic *)net_dev->priv;
++      unsigned int phy_addr = phy_id & FALCON_PHY_ID_ID_MASK;
++      unsigned int phy_10g = phy_id & FALCON_PHY_ID_10G;
++      efx_oword_t reg;
++      int value = -1;
++      unsigned long flags __attribute__ ((unused));
 +
-+              return info->minor;
-+      }
-+      case BLKTAP_IOCTL_MAJOR:
-+              return blktap_major;
++      if (phy_addr == PHY_ADDR_INVALID)
++              return -1;
 +
-+      case BLKTAP_QUERY_ALLOC_REQS:
-+      {
-+              WPRINTK("BLKTAP_QUERY_ALLOC_REQS ioctl: %d/%d\n",
-+                     alloc_pending_reqs, blkif_reqs);
-+              return (alloc_pending_reqs/blkif_reqs) * 100;
++      /* Our PHY code knows whether it needs to talk clause 22(1G) or 45(10G)
++       * but the generic Linux code does not make any distinction or have
++       * any state for this.
++       * We spot the case where someone tried to talk 22 to a 45 PHY and
++       * redirect the request to the lowest numbered MMD as a clause45
++       * request. This is enough to allow simple queries like id and link
++       * state to succeed. TODO: We may need to do more in future.
++       */
++      if (EFX_ISCLAUSE45(efx) && !phy_10g) {
++              int mmd = ffs(efx->phy_op->mmds) - 1;
++              EFX_TRACE(efx, "Fixing erroneous clause22 read\n");
++              phy_addr = mdio_clause45_pack(phy_addr, mmd)
++                      & FALCON_PHY_ID_ID_MASK;
++              phy_10g = 1;
 +      }
++
++      /* Obtain PHY lock */
++      spin_lock_bh(&efx->phy_lock);
++
++      /* Check MII not currently being accessed */
++      if (falcon_gmii_wait(efx) != 0)
++              goto out;
++
++      if (!phy_10g) {
++              /* Write the address registers */
++              EFX_POPULATE_OWORD_2(reg,
++                                   MD_PRT_ADR, phy_addr,
++                                   MD_DEV_ADR, addr);
++              falcon_write(efx, &reg, MD_ID_REG_KER);
++              /* Request data to be read */
++              EFX_POPULATE_OWORD_2(reg,
++                                   MD_RIC, 1,
++                                   MD_GC, 1);
++      } else {
++              EFX_POPULATE_OWORD_1(reg, MD_PHY_ADR, addr);
++              falcon_write(efx, &reg, MD_PHY_ADR_REG_KER);
++
++              EFX_POPULATE_OWORD_1(reg, MD_PRT_DEV_ADR, phy_addr);
++              falcon_write(efx, &reg, MD_ID_REG_KER);
++
++              /* Request data to be read */
++              EFX_POPULATE_OWORD_2(reg,
++                                   MD_RDC, 1,
++                                   MD_GC, 0);
++      }
++      falcon_write(efx, &reg, MD_CS_REG_KER);
++
++      /* Wait for data to become available */
++      value = falcon_gmii_wait(efx);
++      if (value == 0) {
++              falcon_read(efx, &reg, MD_RXD_REG_KER);
++              value = EFX_OWORD_FIELD(reg, MD_RXD);
++              EFX_REGDUMP(efx, "read from GMII %d register %02x, got %04x\n",
++                          phy_id, addr, value);
++      } else {
++              /* Abort the read operation */
++              EFX_POPULATE_OWORD_2(reg,
++                                   MD_RIC, 0,
++                                   MD_GC, 1);
++              falcon_write(efx, &reg, MD_CS_REG_KER);
++
++              EFX_LOG(efx, "read from GMII 0x%x register %02x, got "
++                      "error %d\n", phy_id, addr, value);
 +      }
-+      return -ENOIOCTLCMD;
++
++ out:
++      /* Release PHY lock */
++      spin_unlock_bh(&efx->phy_lock);
++
++      return value;
 +}
 +
-+static unsigned int blktap_poll(struct file *filp, poll_table *wait)
++static void falcon_init_mdio(struct mii_if_info *gmii)
 +{
-+      tap_blkif_t *info = filp->private_data;
-+      
-+      /* do not work on the control device */
-+      if (!info)
-+              return 0;
++      gmii->mdio_read = falcon_mdio_read;
++      gmii->mdio_write = falcon_mdio_write;
++      gmii->phy_id_mask = FALCON_PHY_ID_MASK;
++      gmii->reg_num_mask = ((1 << EFX_WIDTH(MD_DEV_ADR)) - 1);
++}
 +
-+      poll_wait(filp, &info->wait, wait);
-+      if (info->ufe_ring.req_prod_pvt != info->ufe_ring.sring->req_prod) {
-+              RING_PUSH_REQUESTS(&info->ufe_ring);
-+              return POLLIN | POLLRDNORM;
-+      }
++static int falcon_probe_gmac_port(struct efx_nic *efx)
++{
++      struct efx_phy_operations *phy_op = efx->phy_op;
++
++      efx->mac_op = &falcon_gmac_operations;
++      efx->loopback_modes = LOOPBACKS_1G_INTERNAL | phy_op->loopbacks;
++      efx->startup_loopbacks = ((1 << LOOPBACK_MAC) |
++                                (1 << phy_op->startup_loopback));
 +      return 0;
 +}
 +
-+void blktap_kick_user(int idx)
++static int falcon_probe_xmac_port(struct efx_nic *efx)
 +{
-+      tap_blkif_t *info;
-+
-+      info = tapfds[idx];
++      struct efx_phy_operations *phy_op = efx->phy_op;
 +
-+      if ((idx < 0) || (idx > MAX_TAP_DEV) || !info)
-+              return;
++      efx->mac_op = &falcon_xmac_operations;
 +
-+      wake_up_interruptible(&info->wait);
++      /* The Falcon B0 FPGA only supports XGMII loopback */
++      if (FALCON_REV(efx) >= FALCON_REV_B0 && !efx->is_asic)
++              efx->loopback_modes = (1 << LOOPBACK_XGMII);
++      else
++              efx->loopback_modes = LOOPBACKS_10G_INTERNAL;
++      efx->loopback_modes |= phy_op->loopbacks;
 +
-+      return;
++      efx->startup_loopbacks = ((1 << LOOPBACK_XGMII) |
++                                (1 << phy_op->startup_loopback));
++      return 0;
 +}
 +
-+static int do_block_io_op(blkif_t *blkif);
-+static void dispatch_rw_block_io(blkif_t *blkif,
-+                               blkif_request_t *req,
-+                               pending_req_t *pending_req);
-+static void make_response(blkif_t *blkif, u64 id,
-+                          unsigned short op, int st);
++static int falcon_probe_phy(struct efx_nic *efx)
++{
++      switch (efx->phy_type) {
++      case PHY_TYPE_1G_ALASKA:
++              efx->phy_op = &alaska_phy_operations;
++              break;
++      case PHY_TYPE_10XPRESS:
++              efx->phy_op = &falcon_tenxpress_phy_ops;
++              break;
++      case PHY_TYPE_NONE:
++              efx->phy_op = &falcon_null_phy_ops;
++              break;
++      case PHY_TYPE_XFP:
++              efx->phy_op = &falcon_xfp_phy_ops;
++              break;
++      case PHY_TYPE_CX4_RTMR:
++              efx->phy_op = &falcon_txc_phy_ops;
++              break;
++      case PHY_TYPE_PM8358:
++              efx->phy_op = &falcon_pm8358_phy_ops;
++              break;
++      default:
++              EFX_ERR(efx, "Unknown PHY type %d\n",
++                      efx->phy_type);
++              return -1;
++      }
++      return 0;
++}
 +
-+/******************************************************************
-+ * misc small helpers
-+ */
-+static int req_increase(void)
++/* This call is responsible for hooking in the MAC and PHY operations */
++int falcon_probe_port(struct efx_nic *efx)
 +{
-+      int i, j;
++      int rc;
 +
-+      if (mmap_alloc >= MAX_PENDING_REQS || mmap_lock) 
-+              return -EINVAL;
++      /* Hook in PHY operations table */
++      rc = falcon_probe_phy(efx);
++      if (rc)
++              return rc;
 +
-+      pending_reqs[mmap_alloc]  = kzalloc(sizeof(pending_req_t)
-+                                          * blkif_reqs, GFP_KERNEL);
-+      foreign_pages[mmap_alloc] = alloc_empty_pages_and_pagevec(mmap_pages);
++      /* Hook in MAC operations table */
++      if (EFX_IS10G(efx))
++              rc = falcon_probe_xmac_port(efx);
++      else
++              rc = falcon_probe_gmac_port(efx);
++      if (rc)
++              return rc;
 +
-+      if (!pending_reqs[mmap_alloc] || !foreign_pages[mmap_alloc])
-+              goto out_of_memory;
++      EFX_LOG(efx, "created port using %cMAC\n",
++              EFX_IS10G(efx) ? 'X' : 'G');
 +
-+      DPRINTK("%s: reqs=%d, pages=%d\n",
-+              __FUNCTION__, blkif_reqs, mmap_pages);
++      /* Set up GMII structure for PHY */
++      efx->mii.supports_gmii = 1;
++      falcon_init_mdio(&efx->mii);
 +
-+      for (i = 0; i < MAX_PENDING_REQS; i++) {
-+              list_add_tail(&pending_reqs[mmap_alloc][i].free_list, 
-+                            &pending_free);
-+              pending_reqs[mmap_alloc][i].mem_idx = mmap_alloc;
-+              for (j = 0; j < BLKIF_MAX_SEGMENTS_PER_REQUEST; j++)
-+                      BLKTAP_INVALIDATE_HANDLE(&pending_handle(mmap_alloc, 
-+                                                               i, j));
-+      }
++      /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
++      if (FALCON_REV(efx) >= FALCON_REV_B0)
++              efx->flow_control = EFX_FC_RX | EFX_FC_TX;
++      else
++              efx->flow_control = EFX_FC_RX;
 +
-+      mmap_alloc++;
-+      DPRINTK("# MMAPs increased to %d\n",mmap_alloc);
-+      return 0;
++      /* Allocate buffer for stats */
++      rc = falcon_alloc_buffer(efx, &efx->stats_buffer,
++                               FALCON_MAC_STATS_SIZE);
++      if (rc)
++              return rc;
++      EFX_LOG(efx, "stats buffer at %llx (virt %p phys %lx)\n",
++              (unsigned long long)efx->stats_buffer.dma_addr,
++              efx->stats_buffer.addr,
++              virt_to_phys(efx->stats_buffer.addr));
 +
-+ out_of_memory:
-+      free_empty_pages_and_pagevec(foreign_pages[mmap_alloc], mmap_pages);
-+      kfree(pending_reqs[mmap_alloc]);
-+      WPRINTK("%s: out of memory\n", __FUNCTION__);
-+      return -ENOMEM;
++      return 0;
 +}
 +
-+static void mmap_req_del(int mmap)
++void falcon_remove_port(struct efx_nic *efx)
 +{
-+      BUG_ON(!spin_is_locked(&pending_free_lock));
++      /* Free stats buffer */
++      falcon_free_buffer(efx, &efx->stats_buffer);
++}
 +
-+      kfree(pending_reqs[mmap]);
-+      pending_reqs[mmap] = NULL;
++/**************************************************************************
++ *
++ * Multicast filtering
++ *
++ **************************************************************************
++ */
 +
-+      free_empty_pages_and_pagevec(foreign_pages[mmap_alloc], mmap_pages);
-+      foreign_pages[mmap] = NULL;
++void falcon_set_multicast_hash(struct efx_nic *efx)
++{
++      union efx_multicast_hash falcon_mc_hash;
 +
-+      mmap_lock = 0;
-+      DPRINTK("# MMAPs decreased to %d\n",mmap_alloc);
-+      mmap_alloc--;
++      /* Broadcast packets go through the multicast hash filter.
++       * ether_crc_le() of the broadcast address is 0xbe2612ff
++       * so we always add bit 0xff to the mask we are given.
++       */
++      memcpy(&falcon_mc_hash, &efx->multicast_hash, sizeof(falcon_mc_hash));
++      set_bit_le(0xff, (void *)&falcon_mc_hash);
++
++      falcon_write(efx, &falcon_mc_hash.oword[0], MAC_MCAST_HASH_REG0_KER);
++      falcon_write(efx, &falcon_mc_hash.oword[1], MAC_MCAST_HASH_REG1_KER);
 +}
 +
-+static pending_req_t* alloc_req(void)
++/**************************************************************************
++ *
++ * Device reset
++ *
++ **************************************************************************
++ */
++
++static int falcon_clear_b0_memories(struct efx_nic *efx)
 +{
-+      pending_req_t *req = NULL;
-+      unsigned long flags;
++      /* Need to clear memories after a reset. On B0 we can do this
++       * via the net function.
++       */
++      int rc = 0, offset;
++      efx_oword_t blanko;
++      efx_dword_t blankd;
++      unsigned long membase_phys, membase_len;
++      void __iomem *membase_orig;
++      unsigned long flags __attribute__ ((unused));
 +
-+      spin_lock_irqsave(&pending_free_lock, flags);
++      EFX_ZERO_OWORD(blanko);
++      EFX_ZERO_DWORD(blankd);
++      membase_orig = efx->membase;
++      membase_phys = pci_resource_start(efx->pci_dev, efx->type->mem_bar);
 +
-+      if (!list_empty(&pending_free)) {
-+              req = list_entry(pending_free.next, pending_req_t, free_list);
-+              list_del(&req->free_list);
-+      }
++      for (offset = RX_FILTER_TBL0;
++           offset < RX_RSS_INDIR_TBL_B0;
++           offset += 0x10)
++              falcon_write(efx, &blanko, offset);
 +
-+      if (req) {
-+              req->inuse = 1;
-+              alloc_pending_reqs++;
++      /* Clear RSS indirection table */
++      for (offset = RX_RSS_INDIR_TBL_B0;
++           offset < RX_RSS_INDIR_TBL_B0 + 0x800;
++           offset += 0x10)
++              /* Clear 6 bits every 16 bytes */
++              falcon_writel(efx, &blankd, offset);
++
++      /* Need to split this into several mappings so MSI-X table and PBA
++       * never get mapped
++       */
++      membase_phys = membase_phys + 0x2800000;
++      membase_len = 0x3000000 - 0x2800000;
++
++      efx->membase = ioremap_nocache(membase_phys, membase_len);
++      if (efx->membase == NULL) {
++              EFX_ERR(efx, "could not map memory BAR %d at %lx+%lx\n",
++                      efx->type->mem_bar, membase_phys, membase_len);
++              rc = -ENOMEM;
++              goto out;
++      }
++      /* Clear the buffer table.  The first 7/8 of it is a duplicate
++       * of the mapping at 0x800000 and must be accessed 2 DWORDs at
++       * a time.  The final 1/8 must be accessed 4 DWORDs at a time.
++       * We make sure to obey both rules at the same time.
++       */
++      for (offset = 0; offset < membase_len; offset += 0x10) {
++              spin_lock_irqsave(&efx->biu_lock, flags);
++              _falcon_writel(efx, 0, offset + 0x0);
++              wmb();
++              _falcon_writel(efx, 0, offset + 0x4);
++              wmb();
++              _falcon_writel(efx, 0, offset + 0x8);
++              wmb();
++              _falcon_writel(efx, 0, offset + 0xc);
++              mmiowb();
++              spin_unlock_irqrestore(&efx->biu_lock, flags);
 +      }
-+      spin_unlock_irqrestore(&pending_free_lock, flags);
 +
-+      return req;
++      iounmap(efx->membase);
++
++out:
++      /* Restore */
++      efx->membase = membase_orig;
++
++      return rc;
 +}
 +
-+static void free_req(pending_req_t *req)
++
++/* Resets NIC to known state.  This routine must be called in process
++ * context and is allowed to sleep. */
++int falcon_reset_hw(struct efx_nic *efx, enum reset_type method)
 +{
-+      unsigned long flags;
-+      int was_empty;
++      efx_oword_t glb_ctl_reg_ker;
++      int rc;
 +
-+      spin_lock_irqsave(&pending_free_lock, flags);
++      EFX_LOG(efx, "performing %s hardware reset\n", RESET_TYPE(method));
 +
-+      alloc_pending_reqs--;
-+      req->inuse = 0;
-+      if (mmap_lock && (req->mem_idx == mmap_alloc-1)) {
-+              mmap_inuse--;
-+              if (mmap_inuse == 0) mmap_req_del(mmap_alloc-1);
-+              spin_unlock_irqrestore(&pending_free_lock, flags);
-+              return;
++      /* Initiate device reset */
++      if (method == RESET_TYPE_WORLD) {
++              /* Save PCI config space */
++              rc = pci_save_state(efx->pci_dev);
++              if (rc) {
++                      EFX_ERR(efx, "failed to backup PCI state of primary "
++                              "function prior to hardware reset\n");
++                      goto fail1;
++              }
++              if (efx->type->is_dual_func) {
++                      rc = pci_save_state(efx->pci_dev2);
++                      if (rc) {
++                              EFX_ERR(efx, "failed to backup PCI state of "
++                                      "secondary function prior to "
++                                      "hardware reset\n");
++                              goto fail2;
++                      }
++              }
++
++              EFX_POPULATE_OWORD_2(glb_ctl_reg_ker,
++                                   EXT_PHY_RST_DUR, 0x7,
++                                   SWRST, 1);
++      } else {
++              int reset_phy = (method == RESET_TYPE_INVISIBLE ?
++                               EXCLUDE_FROM_RESET : 0);
++
++              EFX_POPULATE_OWORD_7(glb_ctl_reg_ker,
++                                   EXT_PHY_RST_CTL, reset_phy,
++                                   PCIE_CORE_RST_CTL, EXCLUDE_FROM_RESET,
++                                   PCIE_NSTCK_RST_CTL, EXCLUDE_FROM_RESET,
++                                   PCIE_SD_RST_CTL, EXCLUDE_FROM_RESET,
++                                   EE_RST_CTL, EXCLUDE_FROM_RESET,
++                                   EXT_PHY_RST_DUR, 0x7 /* 10ms */,
++                                   SWRST, 1);
++      }
++      falcon_write(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
++
++      /* Wait for 50ms for the chip to come out of reset */
++      EFX_LOG(efx, "waiting for hardware reset\n");
++      schedule_timeout_uninterruptible(HZ / 20);
++
++      /* Restore PCI configuration if needed */
++      if (method == RESET_TYPE_WORLD) {
++              if (efx->type->is_dual_func) {
++                      rc = pci_restore_state(efx->pci_dev2);
++                      if (rc) {
++                              EFX_ERR(efx, "failed to restore PCI config for "
++                                      "the secondary function\n");
++                              goto fail3;
++                      }
++              }
++              rc = pci_restore_state(efx->pci_dev);
++              if (rc) {
++                      EFX_ERR(efx, "failed to restore PCI config for the "
++                              "primary function\n");
++                      goto fail4;
++              }
++              EFX_LOG(efx, "successfully restored PCI config\n");
 +      }
-+      was_empty = list_empty(&pending_free);
-+      list_add(&req->free_list, &pending_free);
 +
-+      spin_unlock_irqrestore(&pending_free_lock, flags);
++      /* Assert that reset complete */
++      falcon_read(efx, &glb_ctl_reg_ker, GLB_CTL_REG_KER);
++      if (EFX_OWORD_FIELD(glb_ctl_reg_ker, SWRST) != 0) {
++              rc = -ETIMEDOUT;
++              EFX_ERR(efx, "timed out waiting for hardware reset\n");
++              goto fail5;
++      }
++      EFX_LOG(efx, "hardware reset complete\n");
 +
-+      if (was_empty)
-+              wake_up(&pending_free_wq);
++      if (EFX_WORKAROUND_8202(efx)) {
++              rc = falcon_clear_b0_memories(efx);
++              if (rc)
++                      goto fail6;
++      }
++
++      return 0;
++
++      /* pci_save_state() and pci_restore_state() MUST be called in pairs */
++fail2:
++fail3:
++      pci_restore_state(efx->pci_dev);
++      /* fall-thru */
++fail1:
++fail4:
++fail5:
++fail6:
++      return rc;
 +}
 +
-+static void fast_flush_area(pending_req_t *req, int k_idx, int u_idx,
-+                          int tapidx)
++/* Zeroes out the SRAM contents.  This routine must be called in
++ * process context and is allowed to sleep.
++ */
++static int falcon_reset_sram(struct efx_nic *efx)
 +{
-+      struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
-+      unsigned int i, invcount = 0;
-+      struct grant_handle_pair *khandle;
-+      uint64_t ptep;
-+      int ret, mmap_idx;
-+      unsigned long kvaddr, uvaddr;
-+      tap_blkif_t *info;
-+      
++      efx_oword_t srm_cfg_reg_ker, gpio_cfg_reg_ker;
++      int count, onchip, sram_cfg_val;
 +
-+      info = tapfds[tapidx];
++      /* Set the SRAM wake/sleep GPIO appropriately. */
++      onchip = (efx->external_sram_cfg == SRM_NB_BSZ_ONCHIP_ONLY);
++      falcon_read(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
++      EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OEN, 1);
++      EFX_SET_OWORD_FIELD(gpio_cfg_reg_ker, GPIO1_OUT, onchip ? 1 : 0);
++      falcon_write(efx, &gpio_cfg_reg_ker, GPIO_CTL_REG_KER);
 +
-+      if ((tapidx < 0) || (tapidx > MAX_TAP_DEV) || !info) {
-+              WPRINTK("fast_flush: Couldn't get info!\n");
-+              return;
-+      }
++      /* Initiate SRAM reset */
++      sram_cfg_val = (efx->external_sram_cfg == SRM_NB_BSZ_ONCHIP_ONLY) ?
++              0 : efx->external_sram_cfg;
 +
-+      if (info->vma != NULL &&
-+          xen_feature(XENFEAT_auto_translated_physmap)) {
-+              down_write(&info->vma->vm_mm->mmap_sem);
-+              zap_page_range(info->vma, 
-+                             MMAP_VADDR(info->user_vstart, u_idx, 0), 
-+                             req->nr_pages << PAGE_SHIFT, NULL);
-+              up_write(&info->vma->vm_mm->mmap_sem);
-+              return;
++      EFX_POPULATE_OWORD_2(srm_cfg_reg_ker,
++                           SRAM_OOB_BT_INIT_EN, 1,
++                           SRM_NUM_BANKS_AND_BANK_SIZE, sram_cfg_val);
++      falcon_write(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
++
++      /* Wait for SRAM reset to complete */
++      count = 0;
++      do {
++              EFX_LOG(efx, "waiting for SRAM reset (attempt %d)...\n", count);
++
++              /* SRAM reset is slow; expect around 16ms */
++              schedule_timeout_uninterruptible(HZ / 50);
++
++              /* Check for reset complete */
++              falcon_read(efx, &srm_cfg_reg_ker, SRM_CFG_REG_KER);
++              if (!EFX_OWORD_FIELD(srm_cfg_reg_ker, SRAM_OOB_BT_INIT_EN)) {
++                      EFX_LOG(efx, "SRAM reset complete\n");
++
++                      return 0;
++              }
++      } while (++count < 20); /* wait upto 0.4 sec */
++
++      EFX_ERR(efx, "timed out waiting for SRAM reset\n");
++      return -ETIMEDOUT;
++}
++
++static void falcon_spi_device_init(struct efx_spi_device **spi_device_ret,
++                                 unsigned int device_id, u32 device_type)
++{
++      struct efx_spi_device *spi_device;
++
++      if (device_type != 0) {
++              spi_device = kmalloc(sizeof(*spi_device), GFP_KERNEL);
++              spi_device->device_id = device_id;
++              spi_device->size =
++                      1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_SIZE);
++              spi_device->addr_len =
++                      SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN);
++              spi_device->munge_address = (spi_device->size == 1 << 9 &&
++                                           spi_device->addr_len == 1);
++              spi_device->erase_command =
++                      SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ERASE_CMD);
++              spi_device->erase_size =
++                      1 << SPI_DEV_TYPE_FIELD(device_type,
++                                              SPI_DEV_TYPE_ERASE_SIZE);
++              spi_device->block_size =
++                      1 << SPI_DEV_TYPE_FIELD(device_type,
++                                              SPI_DEV_TYPE_BLOCK_SIZE);
++              spi_device->read = falcon_spi_read;
++              spi_device->write = falcon_spi_write;
++      } else {
++              spi_device = NULL;
 +      }
 +
-+      mmap_idx = req->mem_idx;
++      kfree(*spi_device_ret);
++      *spi_device_ret = spi_device;
++}
 +
-+      for (i = 0; i < req->nr_pages; i++) {
-+              kvaddr = idx_to_kaddr(mmap_idx, k_idx, i);
-+              uvaddr = MMAP_VADDR(info->user_vstart, u_idx, i);
++/* Extract non-volatile configuration */
++static int falcon_probe_nvconfig(struct efx_nic *efx)
++{
++      int rc;
++      struct falcon_nvconfig *nvconfig;
++      struct efx_spi_device *spi;
++      size_t offset, len;
++      int magic_num, struct_ver, board_rev, onchip_sram;
++
++      nvconfig = kmalloc(sizeof(*nvconfig), GFP_KERNEL);
++
++      /* Read the whole configuration structure into memory.  It's
++       * in Falcon's boot device, which may be either flash or
++       * EEPROM, but if both are present Falcon prefers flash.  The
++       * boot device is always too large for 9-bit addressing, so we
++       * don't have to munge commands.
++       */
++      spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom;
++      for (offset = 0; offset < sizeof(*nvconfig); offset += len) {
++              len = min(sizeof(*nvconfig) - offset,
++                        (size_t) FALCON_SPI_MAX_LEN);
++              rc = falcon_spi_read(spi, efx, SPI_READ,
++                                   NVCONFIG_BASE + offset,
++                                   (char *)nvconfig + offset, len);
++              if (rc)
++                      goto out;
++      }
 +
-+              khandle = &pending_handle(mmap_idx, k_idx, i);
++      /* Read the MAC addresses */
++      memcpy(efx->mac_address, nvconfig->mac_address[0], ETH_ALEN);
 +
-+              if (khandle->kernel != INVALID_GRANT_HANDLE) {
-+                      gnttab_set_unmap_op(&unmap[invcount],
-+                                          idx_to_kaddr(mmap_idx, k_idx, i),
-+                                          GNTMAP_host_map, khandle->kernel);
-+                      invcount++;
++      /* Read the board configuration. */
++      magic_num = le16_to_cpu(nvconfig->board_magic_num);
++      struct_ver = le16_to_cpu(nvconfig->board_struct_ver);
 +
-+                      set_phys_to_machine(
-+                              __pa(idx_to_kaddr(mmap_idx, k_idx, i))
-+                              >> PAGE_SHIFT, INVALID_P2M_ENTRY);
-+              }
++      if (magic_num != NVCONFIG_BOARD_MAGIC_NUM || struct_ver < 2) {
++              EFX_ERR(efx, "Non volatile memory bad magic=%x ver=%x "
++                      "therefore using defaults\n", magic_num, struct_ver);
++              efx->phy_type = PHY_TYPE_NONE;
++              efx->mii.phy_id = PHY_ADDR_INVALID;
++              board_rev = 0;
++              onchip_sram = 1;
 +
-+              if (khandle->user != INVALID_GRANT_HANDLE) {
-+                      BUG_ON(xen_feature(XENFEAT_auto_translated_physmap));
-+                      if (create_lookup_pte_addr(
-+                              info->vma->vm_mm,
-+                              MMAP_VADDR(info->user_vstart, u_idx, i),
-+                              &ptep) !=0) {
-+                              WPRINTK("Couldn't get a pte addr!\n");
-+                              return;
-+                      }
++      } else {
++              struct falcon_nvconfig_board_v2 *v2 = &nvconfig->board_v2;
++              struct falcon_nvconfig_board_v3 *v3 = &nvconfig->board_v3;
 +
-+                      gnttab_set_unmap_op(&unmap[invcount], ptep,
-+                                          GNTMAP_host_map
-+                                          | GNTMAP_application_map
-+                                          | GNTMAP_contains_pte,
-+                                          khandle->user);
-+                      invcount++;
-+              }
++              efx->phy_type = v2->port0_phy_type;
++              efx->mii.phy_id = v2->port0_phy_addr;
++              board_rev = le16_to_cpu(v2->board_revision);
++              onchip_sram = EFX_OWORD_FIELD(nvconfig->nic_stat_reg,
++                                            ONCHIP_SRAM);
 +
-+              BLKTAP_INVALIDATE_HANDLE(khandle);
++              if (struct_ver >= 3) {
++                      __le32 fl = v3->spi_device_type[EE_SPI_FLASH];
++                      __le32 ee = v3->spi_device_type[EE_SPI_EEPROM];
++                      falcon_spi_device_init(&efx->spi_flash, EE_SPI_FLASH,
++                                             le32_to_cpu(fl));
++                      falcon_spi_device_init(&efx->spi_eeprom, EE_SPI_EEPROM,
++                                             le32_to_cpu(ee));
++              }
 +      }
-+      ret = HYPERVISOR_grant_table_op(
-+              GNTTABOP_unmap_grant_ref, unmap, invcount);
-+      BUG_ON(ret);
-+      
-+      if (info->vma != NULL && !xen_feature(XENFEAT_auto_translated_physmap))
-+              zap_page_range(info->vma, 
-+                             MMAP_VADDR(info->user_vstart, u_idx, 0), 
-+                             req->nr_pages << PAGE_SHIFT, NULL);
-+}
 +
-+/******************************************************************
-+ * SCHEDULER FUNCTIONS
-+ */
++      EFX_LOG(efx, "PHY is %s(%d) phy_id %d\n",
++              PHY_TYPE(efx), efx->phy_type,
++              efx->mii.phy_id);
 +
-+static void print_stats(blkif_t *blkif)
-+{
-+      printk(KERN_DEBUG "%s: oo %3d  |  rd %4d  |  wr %4d\n",
-+             current->comm, blkif->st_oo_req,
-+             blkif->st_rd_req, blkif->st_wr_req);
-+      blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
-+      blkif->st_rd_req = 0;
-+      blkif->st_wr_req = 0;
-+      blkif->st_oo_req = 0;
-+}
++      efx_set_board_info(efx, board_rev);
 +
-+int tap_blkif_schedule(void *arg)
-+{
-+      blkif_t *blkif = arg;
++      /* Read the SRAM configuration.  The register is initialised
++       * automatically but might may been reset since boot.
++       */
++      if (onchip_sram) {
++              efx->external_sram_cfg = SRM_NB_BSZ_ONCHIP_ONLY;
++      } else {
++              efx->external_sram_cfg =
++                  EFX_OWORD_FIELD(nvconfig->srm_cfg_reg,
++                                  SRM_NUM_BANKS_AND_BANK_SIZE);
++              WARN_ON(efx->external_sram_cfg == SRM_NB_BSZ_RESERVED);
++              /* Replace invalid setting with the smallest defaults */
++              if (efx->external_sram_cfg == SRM_NB_BSZ_DEFAULT)
++                      efx->external_sram_cfg = SRM_NB_BSZ_1BANKS_2M;
++      }
++      EFX_LOG(efx, "external_sram_cfg=%d (>=0 is external)\n",
++              efx->external_sram_cfg);
 +
-+      blkif_get(blkif);
++ out:
++      kfree(nvconfig);
++      return rc;
++}
 +
-+      if (debug_lvl)
-+              printk(KERN_DEBUG "%s: started\n", current->comm);
++/* Looks at available SRAM resources and silicon revision, and works out
++ * how many queues we can support, and where things like descriptor caches
++ * should live. */
++static int falcon_dimension_resources(struct efx_nic *efx)
++{
++      unsigned buffer_entry_bytes, internal_dcs_entries, dcs;
++      struct falcon_nic_data *nic_data = efx->nic_data;
++      struct efx_dl_falcon_resources *res = &nic_data->resources;
++
++      /* Fill out the driverlink resource list */
++      res->hdr.type = EFX_DL_FALCON_RESOURCES;
++      res->biu_lock = &efx->biu_lock;
++      efx->dl_info = &res->hdr;
++
++      /* This is set to 16 for a good reason.  In summary, if larger than
++       * 16, the descriptor cache holds more than a default socket
++       * buffer's worth of packets (for UDP we can only have at most one
++       * socket buffer's worth outstanding).  This combined with the fact
++       * that we only get 1 TX event per descriptor cache means the NIC
++       * goes idle.
++       * 16 gives us up to 256 TXQs on Falcon B in internal-SRAM mode,
++       * and up to 512 on Falcon A.
++       */
++      nic_data->tx_dc_entries = 16;
++
++      /* Set the RX descriptor cache size.  Values 16, 32 and 64 are
++       * supported (8 won't work).  Bigger is better, especially on B
++       * silicon.
++       */
++      nic_data->rx_dc_entries = descriptor_cache_size;
++      dcs = ffs(nic_data->rx_dc_entries);
++      if ((dcs < 5) || (dcs > 7) ||
++          ((1 << (dcs - 1)) != nic_data->rx_dc_entries)) {
++              EFX_ERR(efx, "bad descriptor_cache_size=%d (dcs=%d)\n",
++                      nic_data->rx_dc_entries, dcs);
++              return -EINVAL;
++      }
 +
-+      while (!kthread_should_stop()) {
-+              if (try_to_freeze())
-+                      continue;
++      /* NB. The minimum values get increased as this driver initialises
++       * its resources, so this should prevent any overlap.
++       */
++      switch (FALCON_REV(efx)) {
++      case FALCON_REV_A1:
++              res->rxq_min = res->txq_min = 16;
++              res->evq_int_min = res->evq_int_max = 4;
++              res->evq_timer_min = 5;
++              res->evq_timer_max = 4096;
++              internal_dcs_entries = 8192;
++              break;
++      case FALCON_REV_B0:
++      default:
++              res->rxq_min = res->txq_min = res->evq_int_min = 0;
++              res->evq_int_max = 64;
++              res->evq_timer_min = 64;
++              res->evq_timer_max = 4096;
++              internal_dcs_entries = 4096;
++              break;
++      }
 +
-+              wait_event_interruptible(
-+                      blkif->wq,
-+                      blkif->waiting_reqs || kthread_should_stop());
-+              wait_event_interruptible(
-+                      pending_free_wq,
-+                      !list_empty(&pending_free) || kthread_should_stop());
++      buffer_entry_bytes = 8;
 +
-+              blkif->waiting_reqs = 0;
-+              smp_mb(); /* clear flag *before* checking for work */
++      if (efx->external_sram_cfg == SRM_NB_BSZ_ONCHIP_ONLY) {
++              res->rxq_max = internal_dcs_entries / nic_data->rx_dc_entries;
++              res->txq_max = internal_dcs_entries / nic_data->tx_dc_entries;
++              /* Prog model says 8K entries for buffer table in internal
++               * mode.  But does this not depend on full/half mode?
++               */
++              res->buffer_table_max = 8192;
++              nic_data->tx_dc_base = 0x130000;
++              nic_data->rx_dc_base = 0x100000;
++      } else {
++              unsigned sram_bytes, vnic_bytes, max_vnics, n_vnics;
 +
-+              if (do_block_io_op(blkif))
-+                      blkif->waiting_reqs = 1;
++              /* Determine how much SRAM we have to play with.  We have
++               * to fit buffer table and descriptor caches in.
++               */
++              switch (efx->external_sram_cfg) {
++              case SRM_NB_BSZ_1BANKS_2M:
++              default:
++                      sram_bytes = 2 * 1024 * 1024;
++                      break;
++              case SRM_NB_BSZ_1BANKS_4M:
++              case SRM_NB_BSZ_2BANKS_4M:
++                      sram_bytes = 4 * 1024 * 1024;
++                      break;
++              case SRM_NB_BSZ_1BANKS_8M:
++              case SRM_NB_BSZ_2BANKS_8M:
++                      sram_bytes = 8 * 1024 * 1024;
++                      break;
++              case SRM_NB_BSZ_2BANKS_16M:
++                      sram_bytes = 16 * 1024 * 1024;
++                      break;
++              }
++              /* For each VNIC allow at least 512 buffer table entries
++               * and descriptor cache for an rxq and txq.  Buffer table
++               * space for evqs and dmaqs is relatively trivial, so not
++               * considered in this calculation.
++               */
++              vnic_bytes = (512 * buffer_entry_bytes
++                            + nic_data->rx_dc_entries * 8
++                            + nic_data->tx_dc_entries * 8);
++              max_vnics = sram_bytes / vnic_bytes;
++              for (n_vnics = 1; n_vnics < res->evq_timer_min + max_vnics;)
++                      n_vnics *= 2;
++              res->rxq_max = n_vnics;
++              res->txq_max = n_vnics;
 +
-+              if (log_stats && time_after(jiffies, blkif->st_print))
-+                      print_stats(blkif);
++              dcs = n_vnics * nic_data->tx_dc_entries * 8;
++              nic_data->tx_dc_base = sram_bytes - dcs;
++              dcs = n_vnics * nic_data->rx_dc_entries * 8;
++              nic_data->rx_dc_base = nic_data->tx_dc_base - dcs;
++              res->buffer_table_max = nic_data->rx_dc_base / 8;
 +      }
 +
-+      if (log_stats)
-+              print_stats(blkif);
-+      if (debug_lvl)
-+              printk(KERN_DEBUG "%s: exiting\n", current->comm);
++      if (efx->type->is_dual_func)
++              res->flags |= EFX_DL_FALCON_DUAL_FUNC;
 +
-+      blkif->xenblkd = NULL;
-+      blkif_put(blkif);
++      if (EFX_INT_MODE_USE_MSI(efx))
++              res->flags |= EFX_DL_FALCON_USE_MSI;
 +
 +      return 0;
 +}
 +
-+/******************************************************************
-+ * COMPLETION CALLBACK -- Called by user level ioctl()
++/* Probe the NIC variant (revision, ASIC vs FPGA, function count, port
++ * count, port speed).  Set workaround and feature flags accordingly.
 + */
-+
-+static int blktap_read_ufe_ring(tap_blkif_t *info)
++static int falcon_probe_nic_variant(struct efx_nic *efx)
 +{
-+      /* This is called to read responses from the UFE ring. */
-+      RING_IDX i, j, rp;
-+      blkif_response_t *resp;
-+      blkif_t *blkif=NULL;
-+      int pending_idx, usr_idx, mmap_idx;
-+      pending_req_t *pending_req;
-+      
-+      if (!info)
-+              return 0;
++      efx_oword_t altera_build;
 +
-+      /* We currently only forward packets in INTERCEPT_FE mode. */
-+      if (!(info->mode & BLKTAP_MODE_INTERCEPT_FE))
-+              return 0;
-+
-+      /* for each outstanding message on the UFEring  */
-+      rp = info->ufe_ring.sring->rsp_prod;
-+      rmb();
-+        
-+      for (i = info->ufe_ring.rsp_cons; i != rp; i++) {
-+              blkif_response_t res;
-+              resp = RING_GET_RESPONSE(&info->ufe_ring, i);
-+              memcpy(&res, resp, sizeof(res));
-+              mb(); /* rsp_cons read by RING_FULL() in do_block_io_op(). */
-+              ++info->ufe_ring.rsp_cons;
-+
-+              /*retrieve [usr_idx] to [mmap_idx,pending_idx] mapping*/
-+              usr_idx = (int)res.id;
-+              pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx]));
-+              mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]);
-+
-+              if ( (mmap_idx >= mmap_alloc) || 
-+                 (ID_TO_IDX(info->idx_map[usr_idx]) >= MAX_PENDING_REQS) )
-+                      WPRINTK("Incorrect req map"
-+                             "[%d], internal map [%d,%d (%d)]\n", 
-+                             usr_idx, mmap_idx, 
-+                             ID_TO_IDX(info->idx_map[usr_idx]),
-+                             MASK_PEND_IDX(
-+                                     ID_TO_IDX(info->idx_map[usr_idx])));
++      falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER);
++      efx->is_asic = EFX_OWORD_FIELD(altera_build, VER_ALL) == 0;
 +
-+              pending_req = &pending_reqs[mmap_idx][pending_idx];
-+              blkif = pending_req->blkif;
-+
-+              for (j = 0; j < pending_req->nr_pages; j++) {
++#if !defined(EFX_USE_PCI_DEV_REVISION)
++      {
++              int rc;
++              rc = pci_read_config_byte(efx->pci_dev, PCI_CLASS_REVISION,
++                                        &efx->revision);
++              if (rc)
++                      return rc;
++      }
++#endif
++      switch (FALCON_REV(efx)) {
++      case FALCON_REV_A0:
++      case 0xff:
++              EFX_ERR(efx, "Falcon rev A0 not supported\n");
++              return -ENODEV;
 +
-+                      unsigned long kvaddr, uvaddr;
-+                      struct page **map = info->vma->vm_private_data;
-+                      struct page *pg;
-+                      int offset;
++      case FALCON_REV_A1:{
++              efx_oword_t nic_stat;
 +
-+                      uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, j);
-+                      kvaddr = idx_to_kaddr(mmap_idx, pending_idx, j);
++              falcon_read(efx, &nic_stat, NIC_STAT_REG);
 +
-+                      pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
-+                      ClearPageReserved(pg);
-+                      offset = (uvaddr - info->vma->vm_start) 
-+                              >> PAGE_SHIFT;
-+                      map[offset] = NULL;
++              if (!efx->is_asic) {
++                      EFX_ERR(efx, "Falcon rev A1 FPGA not supported\n");
++                      return -ENODEV;
 +              }
-+              fast_flush_area(pending_req, pending_idx, usr_idx, info->minor);
-+              info->idx_map[usr_idx] = INVALID_REQ;
-+              make_response(blkif, pending_req->id, res.operation,
-+                            res.status);
-+              blkif_put(pending_req->blkif);
-+              free_req(pending_req);
++              if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) {
++                      EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
++                      return -ENODEV;
++              }
++              efx->is_10g = EFX_OWORD_FIELD(nic_stat, STRAP_10G);
++              efx->silicon_rev = "falcon/a1";
++              break;
 +      }
-+              
-+      return 0;
-+}
 +
++      case FALCON_REV_B0:{
++              efx->is_10g = 1;
++              efx->silicon_rev = "falcon/b0";
++              break;
++      }
 +
-+/******************************************************************************
-+ * NOTIFICATION FROM GUEST OS.
-+ */
++      default:
++              EFX_ERR(efx, "Unknown Falcon rev %d\n", FALCON_REV(efx));
++              return -ENODEV;
++      }
 +
-+static void blkif_notify_work(blkif_t *blkif)
-+{
-+      blkif->waiting_reqs = 1;
-+      wake_up(&blkif->wq);
++      return 0;
 +}
 +
-+irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
++/* Probe all SPI devices on the NIC */
++static void falcon_probe_spi_devices(struct efx_nic *efx)
 +{
-+      blkif_notify_work(dev_id);
-+      return IRQ_HANDLED;
-+}
++      efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg;
++      unsigned int has_flash, has_eeprom, boot_is_external;
 +
++      falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER);
++      falcon_read(efx, &nic_stat, NIC_STAT_REG);
++      falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
 +
++      has_flash = EFX_OWORD_FIELD(nic_stat, SF_PRST);
++      has_eeprom = EFX_OWORD_FIELD(nic_stat, EE_PRST);
++      boot_is_external = EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE);
 +
-+/******************************************************************
-+ * DOWNWARD CALLS -- These interface with the block-device layer proper.
-+ */
-+static int print_dbug = 1;
-+static int do_block_io_op(blkif_t *blkif)
-+{
-+      blkif_back_rings_t *blk_rings = &blkif->blk_rings;
-+      blkif_request_t req;
-+      pending_req_t *pending_req;
-+      RING_IDX rc, rp;
-+      int more_to_do = 0;
-+      tap_blkif_t *info;
++      if (has_flash) {
++              u32 flash_device_type;
 +
-+      rc = blk_rings->common.req_cons;
-+      rp = blk_rings->common.sring->req_prod;
-+      rmb(); /* Ensure we see queued requests up to 'rp'. */
++              if (flash_type == -1) {
++                      /* Default flash SPI device: Atmel AT25F1024
++                       * 128 KB, 24-bit address, 32 KB erase block,
++                       * 256 B write block
++                       */
++                      flash_device_type =
++                              (17 << SPI_DEV_TYPE_SIZE_LBN)
++                              | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN)
++                              | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN)
++                              | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN)
++                              | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
++              } else {
++                      flash_device_type = flash_type;
++              }
 +
-+      /*Check blkif has corresponding UE ring*/
-+      if (blkif->dev_num < 0) {
-+              /*oops*/
-+              if (print_dbug) {
-+                      WPRINTK("Corresponding UE " 
-+                             "ring does not exist!\n");
-+                      print_dbug = 0; /*We only print this message once*/
++              falcon_spi_device_init(&efx->spi_flash, EE_SPI_FLASH,
++                                     flash_device_type);
++
++              if (!boot_is_external) {
++                      /* Disable VPD and set clock dividers to safe
++                       * values for initial programming.
++                       */
++                      EFX_LOG(efx, "Booted from internal ASIC settings;"
++                              " setting SPI config\n");
++                      EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0,
++                                           /* 125 MHz / 7 ~= 20 MHz */
++                                           EE_SF_CLOCK_DIV, 7,
++                                           /* 125 MHz / 63 ~= 2 MHz */
++                                           EE_EE_CLOCK_DIV, 63);
++                      falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER);
 +              }
-+              return 0;
 +      }
 +
-+      info = tapfds[blkif->dev_num];
++      if (has_eeprom) {
++              u32 eeprom_device_type;
 +
-+      if (blkif->dev_num > MAX_TAP_DEV || !info || !info->dev_inuse) {
-+              if (print_dbug) {
-+                      WPRINTK("Can't get UE info!\n");
-+                      print_dbug = 0;
++              /* eeprom_type may be -1 (default) for automatic detection,
++               * 0 or 1 to select the default or large EEPROM, or
++               * some larger number to specify the precise configuration
++               */
++              if (eeprom_type == -1 || eeprom_type <= 1) {
++                      /* If it has no flash, it must have a large EEPROM
++                       * for chip config; otherwise check whether 9-bit
++                       * addressing is used for VPD configuration
++                       */
++                      if (eeprom_type == 0 ||
++                          (eeprom_type == -1 && has_flash &&
++                           (!boot_is_external ||
++                            EFX_OWORD_FIELD(ee_vpd_cfg,
++                                            EE_VPD_EN_AD9_MODE)))) {
++                              /* Default SPI device: Atmel AT25040 or similar
++                               * 512 B, 9-bit address, 8 B write block
++                               */
++                              eeprom_device_type =
++                                      (9 << SPI_DEV_TYPE_SIZE_LBN)
++                                      | (1 << SPI_DEV_TYPE_ADDR_LEN_LBN)
++                                      | (3 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
++                      } else {
++                              /* "Large" SPI device: Atmel AT25640 or similar
++                               * 8 KB, 16-bit address, 32 B write block
++                               */
++                              eeprom_device_type =
++                                      (13 << SPI_DEV_TYPE_SIZE_LBN)
++                                      | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN)
++                                      | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN);
++                      }
++              } else {
++                      eeprom_device_type = eeprom_type;
 +              }
-+              return 0;
++
++              falcon_spi_device_init(&efx->spi_eeprom, EE_SPI_EEPROM,
++                                     eeprom_device_type);
 +      }
 +
-+      while (rc != rp) {
-+              
-+              if (RING_FULL(&info->ufe_ring)) {
-+                      WPRINTK("RING_FULL! More to do\n");
-+                      more_to_do = 1;
-+                      break;
-+              }
++      EFX_LOG(efx, "flash is %s, EEPROM is %s\n",
++              (has_flash ? "present" : "absent"),
++              (has_eeprom ? "present" : "absent"));
++}
 +
-+              if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc)) {
-+                      WPRINTK("RING_REQUEST_CONS_OVERFLOW!"
-+                             " More to do\n");
-+                      more_to_do = 1;
-+                      break;          
-+              }
++static void falcon_remove_spi_devices(struct efx_nic *efx)
++{
++      kfree(efx->spi_eeprom);
++      efx->spi_eeprom = NULL;
++      kfree(efx->spi_flash);
++      efx->spi_flash = NULL;
++}
 +
-+              pending_req = alloc_req();
-+              if (NULL == pending_req) {
-+                      blkif->st_oo_req++;
-+                      more_to_do = 1;
-+                      break;
-+              }
++#ifdef CONFIG_SFC_DEBUGFS
 +
-+              switch (blkif->blk_protocol) {
-+              case BLKIF_PROTOCOL_NATIVE:
-+                      memcpy(&req, RING_GET_REQUEST(&blk_rings->native, rc),
-+                             sizeof(req));
-+                      break;
-+              case BLKIF_PROTOCOL_X86_32:
-+                      blkif_get_x86_32_req(&req, RING_GET_REQUEST(&blk_rings->x86_32, rc));
-+                      break;
-+              case BLKIF_PROTOCOL_X86_64:
-+                      blkif_get_x86_64_req(&req, RING_GET_REQUEST(&blk_rings->x86_64, rc));
-+                      break;
-+              default:
-+                      BUG();
-+              }
-+              blk_rings->common.req_cons = ++rc; /* before make_response() */
++/* Generate a hardware revision string */
++int falcon_debugfs_read_hardware_desc(struct seq_file *file, void *data)
++{
++      struct efx_nic *efx = data;
++      efx_oword_t altera_build;
++      int major, minor, build;
++      int rc, len;
 +
-+              switch (req.operation) {
-+              case BLKIF_OP_READ:
-+                      blkif->st_rd_req++;
-+                      dispatch_rw_block_io(blkif, &req, pending_req);
-+                      break;
++      if (efx->is_asic) {
++              rc = seq_puts(file, "Falcon ASIC");
++      } else {
++              falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER);
 +
-+              case BLKIF_OP_WRITE:
-+                      blkif->st_wr_req++;
-+                      dispatch_rw_block_io(blkif, &req, pending_req);
-+                      break;
++              major = EFX_OWORD_FIELD(altera_build, VER_MAJOR);
++              minor = EFX_OWORD_FIELD(altera_build, VER_MINOR);
++              build = EFX_OWORD_FIELD(altera_build, VER_BUILD);
++              rc = seq_printf(file, "Falcon FPGA v%x.%x.%x",
++                              major, minor, build);
++      }
++      len = rc;
 +
-+              default:
-+                      WPRINTK("unknown operation [%d]\n",
-+                              req.operation);
-+                      make_response(blkif, req.id, req.operation,
-+                                    BLKIF_RSP_ERROR);
-+                      free_req(pending_req);
-+                      break;
-+              }
++      switch (FALCON_REV(efx)) {
++      case FALCON_REV_A1:
++              rc = seq_puts(file, " rev A1 ");
++              break;
++      case FALCON_REV_B0:
++              rc = seq_puts(file, " rev B0 ");
++              break;
++      default:
++              rc = seq_puts(file, " rev ?? ");
++              break;
 +      }
-+              
-+      blktap_kick_user(blkif->dev_num);
++      len += rc;
 +
-+      return more_to_do;
++      rc = seq_printf(file, "%s %s\n",
++                      efx->is_10g ? "10G" : "1G", PHY_TYPE(efx));
++      len += rc;
++
++      return rc < 0 ? rc : len;
 +}
 +
-+static void dispatch_rw_block_io(blkif_t *blkif,
-+                               blkif_request_t *req,
-+                               pending_req_t *pending_req)
++#endif /* CONFIG_SFC_DEBUGFS */
++
++int falcon_probe_nic(struct efx_nic *efx)
 +{
-+      extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
-+      int op, operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
-+      struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
-+      unsigned int nseg;
-+      int ret, i, nr_sects = 0;
-+      tap_blkif_t *info;
-+      blkif_request_t *target;
-+      int pending_idx = RTN_PEND_IDX(pending_req,pending_req->mem_idx);
-+      int usr_idx;
-+      uint16_t mmap_idx = pending_req->mem_idx;
++      struct falcon_nic_data *nic_data;
++      int rc;
 +
-+      if (blkif->dev_num < 0 || blkif->dev_num > MAX_TAP_DEV)
-+              goto fail_response;
++      /* Initialise I2C interface state */
++      efx->i2c.efx = efx;
++      efx->i2c.op = &falcon_i2c_bit_operations;
++      efx->i2c.sda = 1;
++      efx->i2c.scl = 1;
 +
-+      info = tapfds[blkif->dev_num];
-+      if (info == NULL)
-+              goto fail_response;
++      /* Determine number of ports etc. */
++      rc = falcon_probe_nic_variant(efx);
++      if (rc)
++              goto fail1;
 +
-+      /* Check we have space on user ring - should never fail. */
-+      usr_idx = GET_NEXT_REQ(info->idx_map);
-+      if (usr_idx == INVALID_REQ) {
-+              BUG();
-+              goto fail_response;
-+      }
++      /* Probe secondary function if expected */
++      if (efx->type->is_dual_func) {
++              struct pci_dev *dev = pci_dev_get(efx->pci_dev);
 +
-+      /* Check that number of segments is sane. */
-+      nseg = req->nr_segments;
-+      if ( unlikely(nseg == 0) || 
-+          unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) ) {
-+              WPRINTK("Bad number of segments in request (%d)\n", nseg);
-+              goto fail_response;
-+      }
-+      
-+      /* Make sure userspace is ready. */
-+      if (!info->ring_ok) {
-+              WPRINTK("blktap: ring not ready for requests!\n");
-+              goto fail_response;
++              while ((dev = pci_get_device(EFX_VENDID_SFC, FALCON_A_S_DEVID,
++                                           dev))) {
++                      if (dev->bus == efx->pci_dev->bus &&
++                          dev->devfn == efx->pci_dev->devfn + 1) {
++                              efx->pci_dev2 = dev;
++                              break;
++                      }
++              }
++              if (!efx->pci_dev2) {
++                      EFX_ERR(efx, "failed to find secondary function\n");
++                      rc = -ENODEV;
++                      goto fail2;
++              }
 +      }
 +
-+      if (RING_FULL(&info->ufe_ring)) {
-+              WPRINTK("blktap: fe_ring is full, can't add "
-+                      "IO Request will be dropped. %d %d\n",
-+                      RING_SIZE(&info->ufe_ring),
-+                      RING_SIZE(&blkif->blk_rings.common));
-+              goto fail_response;
++      /* Now we can reset the NIC */
++      rc = falcon_reset_hw(efx, RESET_TYPE_ALL);
++      if (rc) {
++              EFX_ERR(efx, "failed to reset NIC\n");
++              goto fail3;
 +      }
 +
-+      pending_req->blkif     = blkif;
-+      pending_req->id        = req->id;
-+      pending_req->operation = operation;
-+      pending_req->status    = BLKIF_RSP_OKAY;
-+      pending_req->nr_pages  = nseg;
-+      op = 0;
-+      for (i = 0; i < nseg; i++) {
-+              unsigned long uvaddr;
-+              unsigned long kvaddr;
-+              uint64_t ptep;
-+              uint32_t flags;
++      /* Allocate memory for INT_KER */
++      rc = falcon_alloc_buffer(efx, &efx->irq_status, sizeof(efx_oword_t));
++      if (rc)
++              goto fail4;
++      BUG_ON(efx->irq_status.dma_addr & 0x0f);
 +
-+              uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i);
-+              kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i);
++      EFX_LOG(efx, "INT_KER at %llx (virt %p phys %lx)\n",
++              (unsigned long long)efx->irq_status.dma_addr,
++              efx->irq_status.addr, virt_to_phys(efx->irq_status.addr));
 +
-+              flags = GNTMAP_host_map;
-+              if (operation == WRITE)
-+                      flags |= GNTMAP_readonly;
-+              gnttab_set_map_op(&map[op], kvaddr, flags,
-+                                req->seg[i].gref, blkif->domid);
-+              op++;
-+
-+              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+                      /* Now map it to user. */
-+                      ret = create_lookup_pte_addr(info->vma->vm_mm, 
-+                                                   uvaddr, &ptep);
-+                      if (ret) {
-+                              WPRINTK("Couldn't get a pte addr!\n");
-+                              goto fail_flush;
-+                      }
++      /* Determine attached SPI devices */
++      falcon_probe_spi_devices(efx);
 +
-+                      flags = GNTMAP_host_map | GNTMAP_application_map
-+                              | GNTMAP_contains_pte;
-+                      if (operation == WRITE)
-+                              flags |= GNTMAP_readonly;
-+                      gnttab_set_map_op(&map[op], ptep, flags,
-+                                        req->seg[i].gref, blkif->domid);
-+                      op++;
-+              }
++      /* Read in the non-volatile configuration */
++      rc = falcon_probe_nvconfig(efx);
++      if (rc)
++              goto fail5;
 +
-+              nr_sects += (req->seg[i].last_sect - 
-+                           req->seg[i].first_sect + 1);
++      if (!efx->is_10g && efx->phy_type != PHY_TYPE_1G_ALASKA) {
++              /* Actually using 1G port, not 10G port */
++              efx->phy_type = PHY_TYPE_1G_ALASKA;
++              efx->mii.phy_id = 2;
 +      }
 +
-+      ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, op);
-+      BUG_ON(ret);
++      /* Decide how many resources we can allocate, to ourselves
++       * and to driverlink clients */
++      nic_data = kzalloc(sizeof(*nic_data), GFP_KERNEL);
++      efx->nic_data = (void *) nic_data;
 +
-+      if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+              for (i = 0; i < (nseg*2); i+=2) {
-+                      unsigned long uvaddr;
-+                      unsigned long kvaddr;
-+                      unsigned long offset;
-+                      struct page *pg;
++      rc = falcon_dimension_resources(efx);
++      if (rc)
++              goto fail6;
 +
-+                      uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i/2);
-+                      kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i/2);
++      return 0;
 +
-+                      if (unlikely(map[i].status != 0)) {
-+                              WPRINTK("invalid kernel buffer -- "
-+                                      "could not remap it\n");
-+                              ret |= 1;
-+                              map[i].handle = INVALID_GRANT_HANDLE;
-+                      }
++ fail6:
++      kfree(nic_data);
++      efx->nic_data = efx->dl_info = NULL;
++ fail5:
++      falcon_remove_spi_devices(efx);
++      falcon_free_buffer(efx, &efx->irq_status);
++ fail4:
++      /* fall-thru */
++ fail3:
++      if (efx->pci_dev2) {
++              pci_dev_put(efx->pci_dev2);
++              efx->pci_dev2 = NULL;
++      }
++ fail2:
++      /* fall-thru */
++ fail1:
++      return rc;
++}
 +
-+                      if (unlikely(map[i+1].status != 0)) {
-+                              WPRINTK("invalid user buffer -- "
-+                                      "could not remap it\n");
-+                              ret |= 1;
-+                              map[i+1].handle = INVALID_GRANT_HANDLE;
-+                      }
++static int falcon_check_power_limit(struct efx_nic *efx)
++{
++      int pciecap_offset = pci_find_capability(efx->pci_dev, PCI_CAP_ID_EXP);
++      u32 pcie_devcap;
++      unsigned val, scale;
++      int rc;
 +
-+                      pending_handle(mmap_idx, pending_idx, i/2).kernel 
-+                              = map[i].handle;
-+                      pending_handle(mmap_idx, pending_idx, i/2).user   
-+                              = map[i+1].handle;
++      if (!pciecap_offset)
++              return -EIO;
++      rc = pci_read_config_dword(efx->pci_dev,
++                                 (pciecap_offset + PCI_EXP_DEVCAP),
++                                 &pcie_devcap);
++      if (rc)
++              return rc;
 +
-+                      if (ret)
-+                              continue;
++      val = ((pcie_devcap & PCI_EXP_DEVCAP_PWR_VAL) >>
++             PCI_EXP_DEVCAP_PWR_VAL_LBN);
++      scale = ((pcie_devcap & PCI_EXP_DEVCAP_PWR_SCL) >>
++               PCI_EXP_DEVCAP_PWR_SCL_LBN);
 +
-+                      set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT,
-+                                          FOREIGN_FRAME(map[i].dev_bus_addr
-+                                                        >> PAGE_SHIFT));
-+                      offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT;
-+                      pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
-+                      ((struct page **)info->vma->vm_private_data)[offset] =
-+                              pg;
-+              }
-+      } else {
-+              for (i = 0; i < nseg; i++) {
-+                      unsigned long uvaddr;
-+                      unsigned long kvaddr;
-+                      unsigned long offset;
-+                      struct page *pg;
++      /* Re-scale to milliwatts if necessary */
++      while (scale != 3) {
++              val *= 10;
++              scale++;
++      }
 +
-+                      uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i);
-+                      kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i);
++      if (val != 0 && efx->board_info.mwatts > val) {
++              EFX_ERR(efx, "board needs %d mW but only %d mW available\n",
++                      efx->board_info.mwatts, val);
++              return -EIO;
++      }
 +
-+                      if (unlikely(map[i].status != 0)) {
-+                              WPRINTK("invalid kernel buffer -- "
-+                                      "could not remap it\n");
-+                              ret |= 1;
-+                              map[i].handle = INVALID_GRANT_HANDLE;
-+                      }
++      return 0;
++}
 +
-+                      pending_handle(mmap_idx, pending_idx, i).kernel 
-+                              = map[i].handle;
++static void falcon_init_ack_repl_timer(struct efx_nic *efx, int num_lanes)
++{
++      unsigned tlp_size;
++      efx_dword_t pcie_ack_rpl_reg;
++      efx_dword_t pcie_ack_freq_reg;
++      efx_dword_t pcie_ctrl_stat_reg;
++      u16 pcie_devicectrl;
++      int lut_index, tlp_size_decoded;
++      int current_replay, expected_replay;
++      int current_ack_timer, current_ack_freq;
++
++      static struct efx_tlp_ack_factor {
++              int tlp;
++              int replay[4]; /* 0=1x, 1=2x, 3=4x, 4=8x (see pcie docs) */
++      } tlp_ack_factor_lut[4] = {
++              { 128,  { 421, 257, 174, 166 } },
++              { 256,  { 689, 391, 241, 225 } },
++              { 512,  { 903, 498, 295, 193 } },
++              { 1024, { 1670, 881, 487, 290 } }
++      };
++      struct efx_tlp_ack_factor *tlp_ack_factor;
++
++      /* Get TLP size */
++      falcon_pcie_core_read_reg(efx, PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT,
++                                &pcie_ctrl_stat_reg);
++      pcie_devicectrl = (u16) EFX_EXTRACT_DWORD(pcie_ctrl_stat_reg, 0, 15);
++      tlp_size = ((PCI_EXP_DEVCTL_PAYLOAD & pcie_devicectrl) >>
++                  ffs(PCI_EXP_DEVCTL_PAYLOAD));
++      EFX_WARN_ON_PARANOID(tlp_size > 3); /* => 1024 bytes */
++      tlp_ack_factor = &tlp_ack_factor_lut[tlp_size & 0x3];
++      tlp_size_decoded = tlp_ack_factor->tlp;
++
++      /* Get actual ack & actual and expected replay settings */
++      falcon_pcie_core_read_reg(efx, PCIE_CORE_ADDR_ACK_RPL_TIMER,
++                                &pcie_ack_rpl_reg);
++      current_replay = EFX_DWORD_FIELD(pcie_ack_rpl_reg, PCIE_CORE_RPL_TL);
++      current_ack_timer = EFX_DWORD_FIELD(pcie_ack_rpl_reg,
++                                          PCIE_CORE_ACK_TL);
++
++      lut_index = ffs(num_lanes) - 1;
++      expected_replay = tlp_ack_factor->replay[lut_index & 0x3];
++
++      falcon_pcie_core_read_reg(efx, PCIE_CORE_ADDR_ACK_FREQ,
++                                &pcie_ack_freq_reg);
++      current_ack_freq = EFX_DWORD_FIELD(pcie_ack_freq_reg,
++                                         PCIE_CORE_ACK_FREQ);
++
++      EFX_LOG(efx, "pcie x%d tlp=%d replay_reg=" EFX_DWORD_FMT " { ack=%d "
++              "current_replay=%d expected_replay=%d } ack_reg="
++              EFX_DWORD_FMT " { current_freq=%d expected_freq=%d }\n",
++              num_lanes, tlp_size_decoded,
++              EFX_DWORD_VAL(pcie_ack_rpl_reg), current_ack_timer,
++              current_replay, expected_replay,
++              EFX_DWORD_VAL(pcie_ack_rpl_reg), current_ack_freq, 0);
++
++      /* If expected replay setting needs to be bigger then set it */
++      if (expected_replay > current_replay) {
++              EFX_SET_DWORD_FIELD(pcie_ack_rpl_reg, PCIE_CORE_RPL_TL,
++                                  expected_replay);
++
++              falcon_pcie_core_write_reg(efx, PCIE_CORE_ADDR_ACK_RPL_TIMER,
++                                         pcie_ack_rpl_reg);
++      }
++}
++
++static int falcon_init_pcie_core(struct efx_nic *efx)
++{
++      int pciecap_offset;
++      unsigned num_lanes = 0;
++
++      /* Get num lanes */
++      pciecap_offset = pci_find_capability(efx->pci_dev, PCI_CAP_ID_EXP);
++      if (pciecap_offset) {
++              u16 pcie_linkstat;
++              int rc, link_sta;
++
++              link_sta = pciecap_offset + PCI_EXP_LNKSTA;
++              rc = pci_read_config_word(efx->pci_dev, link_sta,
++                                        &pcie_linkstat);
++              if (rc)
++                      return rc;
 +
-+                      if (ret)
-+                              continue;
++              num_lanes = ((pcie_linkstat & PCI_EXP_LNKSTA_LNK_WID)
++                           >> PCI_EXP_LNKSTA_LNK_WID_LBN);
++              EFX_BUG_ON_PARANOID(num_lanes <= 0 || num_lanes > 8);
 +
-+                      offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT;
-+                      pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
-+                      ((struct page **)info->vma->vm_private_data)[offset] =
-+                              pg;
-+              }
++              if (num_lanes < 8)
++                      EFX_ERR(efx, "WARNING: the Solarflare Network Adapter "
++                              "has been plugged into a PCI-Express slot with "
++                              "less than 8 lanes (%d detected). This will "
++                              "limit the maximum achievable bandwidth! "
++                              "Consult your motherboard documentation to "
++                              "find a slot that is 8 lanes electrically and "
++                              "physically\n", num_lanes);
 +      }
 +
-+      if (ret)
-+              goto fail_flush;
++      if (FALCON_REV(efx) <= FALCON_REV_A1)
++              return 0;
 +
-+      if (xen_feature(XENFEAT_auto_translated_physmap))
-+              down_write(&info->vma->vm_mm->mmap_sem);
-+      /* Mark mapped pages as reserved: */
-+      for (i = 0; i < req->nr_segments; i++) {
-+              unsigned long kvaddr;
-+              struct page *pg;
++      if (EFX_WORKAROUND_6943(efx) && num_lanes > 0)
++              falcon_init_ack_repl_timer(efx, num_lanes);
 +
-+              kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i);
-+              pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
-+              SetPageReserved(pg);
-+              if (xen_feature(XENFEAT_auto_translated_physmap)) {
-+                      ret = vm_insert_page(info->vma,
-+                                           MMAP_VADDR(info->user_vstart,
-+                                                      usr_idx, i), pg);
-+                      if (ret) {
-+                              up_write(&info->vma->vm_mm->mmap_sem);
-+                              goto fail_flush;
-+                      }
-+              }
++      if (EFX_WORKAROUND_9096(efx)) {
++              efx_dword_t pcie_ack_freq_reg;
++
++              /* ensure ack freq timer is 0 = always ack after timeout */
++              falcon_pcie_core_read_reg(efx, PCIE_CORE_ADDR_ACK_FREQ,
++                                        &pcie_ack_freq_reg);
++              EFX_SET_DWORD_FIELD(pcie_ack_freq_reg, PCIE_CORE_ACK_FREQ, 0);
++              falcon_pcie_core_write_reg(efx, PCIE_CORE_ADDR_ACK_FREQ,
++                                         pcie_ack_freq_reg);
 +      }
-+      if (xen_feature(XENFEAT_auto_translated_physmap))
-+              up_write(&info->vma->vm_mm->mmap_sem);
-+      
-+      /*record [mmap_idx,pending_idx] to [usr_idx] mapping*/
-+      info->idx_map[usr_idx] = MAKE_ID(mmap_idx, pending_idx);
 +
-+      blkif_get(blkif);
-+      /* Finally, write the request message to the user ring. */
-+      target = RING_GET_REQUEST(&info->ufe_ring,
-+                                info->ufe_ring.req_prod_pvt);
-+      memcpy(target, req, sizeof(*req));
-+      target->id = usr_idx;
-+      wmb(); /* blktap_poll() reads req_prod_pvt asynchronously */
-+      info->ufe_ring.req_prod_pvt++;
++      return 0;
++}
 +
-+      if (operation == READ)
-+              blkif->st_rd_sect += nr_sects;
-+      else if (operation == WRITE)
-+              blkif->st_wr_sect += nr_sects;
++static void falcon_fini_pcie_core(struct efx_nic *efx)
++{
++      efx_dword_t pcie_ack_freq_reg;
 +
-+      return;
++      if (FALCON_REV(efx) <= FALCON_REV_A1)
++              return;
 +
-+ fail_flush:
-+      WPRINTK("Reached Fail_flush\n");
-+      fast_flush_area(pending_req, pending_idx, usr_idx, blkif->dev_num);
-+ fail_response:
-+      make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
-+      free_req(pending_req);
-+} 
++      if (EFX_WORKAROUND_9096(efx)) {
++              /* Set the ACK frequency timer to 1, so TLP's are acked in
++               * a timely fashion.
++               */
++              falcon_pcie_core_read_reg(efx, PCIE_CORE_ADDR_ACK_FREQ,
++                                        &pcie_ack_freq_reg);
++              EFX_SET_DWORD_FIELD(pcie_ack_freq_reg, PCIE_CORE_ACK_FREQ, 1);
++              falcon_pcie_core_write_reg(efx, PCIE_CORE_ADDR_ACK_FREQ,
++                                         pcie_ack_freq_reg);
++      }
++}
 +
++/* This call performs hardware-specific global initialisation, such as
++ * defining the descriptor cache sizes and number of RSS channels.
++ * It does not set up any buffers, descriptor rings or event queues.
++ */
++int falcon_init_nic(struct efx_nic *efx)
++{
++      struct falcon_nic_data *data;
++      efx_oword_t temp;
++      unsigned thresh;
++      int rc;
 +
++      data = (struct falcon_nic_data *)efx->nic_data;
 +
-+/******************************************************************
-+ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
-+ */
++      /* Set up the address region register. This is only needed
++       * for the B0 FPGA, but since we are just pushing in the
++       * reset defaults this may as well be unconditional. */
++      EFX_POPULATE_OWORD_4(temp, ADR_REGION0, 0,
++                                 ADR_REGION1, (1 << 16),
++                                 ADR_REGION2, (2 << 16),
++                                 ADR_REGION3, (3 << 16));
++      falcon_write(efx, &temp, ADR_REGION_REG_KER);
 +
++      /* Use on-chip SRAM if needed.
++       */
++      falcon_read(efx, &temp, NIC_STAT_REG);
++      if (efx->external_sram_cfg == SRM_NB_BSZ_ONCHIP_ONLY)
++              EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1);
++      else
++              EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 0);
++      falcon_write(efx, &temp, NIC_STAT_REG);
 +
-+static void make_response(blkif_t *blkif, u64 id,
-+                          unsigned short op, int st)
-+{
-+      blkif_response_t  resp;
-+      unsigned long     flags;
-+      blkif_back_rings_t *blk_rings = &blkif->blk_rings;
-+      int more_to_do = 0;
-+      int notify;
++      /* Check power requirements against PCIe power budgeting */
++      rc = falcon_check_power_limit(efx);
++      if (rc)
++              return rc;
 +
-+      resp.id        = id;
-+      resp.operation = op;
-+      resp.status    = st;
++      /* Warn if <8 lanes of PCIe detected & set pcie timers */
++      rc = falcon_init_pcie_core(efx);
++      if (rc)
++              return rc;
 +
-+      spin_lock_irqsave(&blkif->blk_ring_lock, flags);
-+      /* Place on the response ring for the relevant domain. */
-+      switch (blkif->blk_protocol) {
-+      case BLKIF_PROTOCOL_NATIVE:
-+              memcpy(RING_GET_RESPONSE(&blk_rings->native,
-+                                       blk_rings->native.rsp_prod_pvt),
-+                     &resp, sizeof(resp));
-+              break;
-+      case BLKIF_PROTOCOL_X86_32:
-+              memcpy(RING_GET_RESPONSE(&blk_rings->x86_32,
-+                                       blk_rings->x86_32.rsp_prod_pvt),
-+                     &resp, sizeof(resp));
-+              break;
-+      case BLKIF_PROTOCOL_X86_64:
-+              memcpy(RING_GET_RESPONSE(&blk_rings->x86_64,
-+                                       blk_rings->x86_64.rsp_prod_pvt),
-+                     &resp, sizeof(resp));
-+              break;
-+      default:
-+              BUG();
-+      }
-+      blk_rings->common.rsp_prod_pvt++;
-+      RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify);
++      /* Set buffer table mode */
++      EFX_POPULATE_OWORD_1(temp, BUF_TBL_MODE, BUF_TBL_MODE_FULL);
++      falcon_write(efx, &temp, BUF_TBL_CFG_REG_KER);
 +
-+      if (blk_rings->common.rsp_prod_pvt == blk_rings->common.req_cons) {
-+              /*
-+               * Tail check for pending requests. Allows frontend to avoid
-+               * notifications if requests are already in flight (lower
-+               * overheads and promotes batching).
-+               */
-+              RING_FINAL_CHECK_FOR_REQUESTS(&blk_rings->common, more_to_do);
-+      } else if (RING_HAS_UNCONSUMED_REQUESTS(&blk_rings->common)) {
-+              more_to_do = 1;
-+      }
++      rc = falcon_reset_sram(efx);
++      if (rc)
++              return rc;
 +
-+      spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
-+      if (more_to_do)
-+              blkif_notify_work(blkif);
-+      if (notify)
-+              notify_remote_via_irq(blkif->irq);
-+}
++      /* Set positions of descriptor caches in SRAM. */
++      EFX_POPULATE_OWORD_1(temp, SRM_TX_DC_BASE_ADR, data->tx_dc_base / 8);
++      falcon_write(efx, &temp, SRM_TX_DC_CFG_REG_KER);
++      EFX_POPULATE_OWORD_1(temp, SRM_RX_DC_BASE_ADR, data->rx_dc_base / 8);
++      falcon_write(efx, &temp, SRM_RX_DC_CFG_REG_KER);
 +
-+static int __init blkif_init(void)
-+{
-+      int i, ret;
-+      struct class *class;
++      /* Set TX descriptor cache size. */
++      EFX_POPULATE_OWORD_1(temp, TX_DC_SIZE, ffs(data->tx_dc_entries) - 4);
++      falcon_write(efx, &temp, TX_DC_CFG_REG_KER);
 +
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++      /* Set RX descriptor cache size.  Set low watermark to size-8, as
++       * this allows most efficient prefetching.
++       */
++      EFX_POPULATE_OWORD_1(temp, RX_DC_SIZE, ffs(data->rx_dc_entries) - 4);
++      falcon_write(efx, &temp, RX_DC_CFG_REG_KER);
++      EFX_POPULATE_OWORD_1(temp, RX_DC_PF_LWM, data->rx_dc_entries - 8);
++      falcon_write(efx, &temp, RX_DC_PF_WM_REG_KER);
 +
-+      INIT_LIST_HEAD(&pending_free);
-+        for(i = 0; i < 2; i++) {
-+              ret = req_increase();
-+              if (ret)
-+                      break;
++      /* Clear the parity enables on the TX data fifos as
++       * they produce false parity errors because of timing issues
++       */
++      if (EFX_WORKAROUND_5129(efx)) {
++              falcon_read(efx, &temp, SPARE_REG_KER);
++              EFX_SET_OWORD_FIELD(temp, MEM_PERR_EN_TX_DATA, 0);
++              falcon_write(efx, &temp, SPARE_REG_KER);
 +      }
-+      if (i == 0)
-+              return ret;
 +
-+      tap_blkif_interface_init();
-+
-+      alloc_pending_reqs = 0;
++      /* Enable all the genuinely fatal interrupts.  (They are still
++       * masked by the overall interrupt mask, controlled by
++       * falcon_interrupts()).
++       *
++       * Note: All other fatal interrupts are enabled
++       */
++      EFX_POPULATE_OWORD_3(temp,
++                           ILL_ADR_INT_KER_EN, 1,
++                           RBUF_OWN_INT_KER_EN, 1,
++                           TBUF_OWN_INT_KER_EN, 1);
++      EFX_INVERT_OWORD(temp);
++      falcon_write(efx, &temp, FATAL_INTR_REG_KER);
++
++      /* Set number of RSS queues for receive path. */
++      falcon_read(efx, &temp, RX_FILTER_CTL_REG);
++      if (FALCON_REV(efx) >= FALCON_REV_B0)
++              EFX_SET_OWORD_FIELD(temp, NUM_KER, 0);
++      else
++              EFX_SET_OWORD_FIELD(temp, NUM_KER, efx->rss_queues - 1);
++      if (EFX_WORKAROUND_7244(efx)) {
++              EFX_SET_OWORD_FIELD(temp, UDP_FULL_SRCH_LIMIT, 8);
++              EFX_SET_OWORD_FIELD(temp, UDP_WILD_SRCH_LIMIT, 8);
++              EFX_SET_OWORD_FIELD(temp, TCP_FULL_SRCH_LIMIT, 8);
++              EFX_SET_OWORD_FIELD(temp, TCP_WILD_SRCH_LIMIT, 8);
++      }
++      falcon_write(efx, &temp, RX_FILTER_CTL_REG);
++
++      falcon_setup_rss_indir_table(efx);
++
++      /* Setup RX.  Wait for descriptor is broken and must
++       * be disabled.  RXDP recovery shouldn't be needed, but is.
++       */
++      falcon_read(efx, &temp, RX_SELF_RST_REG_KER);
++      EFX_SET_OWORD_FIELD(temp, RX_NODESC_WAIT_DIS, 1);
++      EFX_SET_OWORD_FIELD(temp, RX_RECOVERY_EN, 1);
++      if (EFX_WORKAROUND_5583(efx))
++              EFX_SET_OWORD_FIELD(temp, RX_ISCSI_DIS, 1);
++      falcon_write(efx, &temp, RX_SELF_RST_REG_KER);
++
++      /* Disable the ugly timer-based TX DMA backoff and allow TX DMA to be
++       * controlled by the RX FIFO fill level. Set arbitration to one pkt/Q.
++       */
++      falcon_read(efx, &temp, TX_CFG2_REG_KER);
++      EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER, 0xfe);
++      EFX_SET_OWORD_FIELD(temp, TX_RX_SPACER_EN, 1);
++      EFX_SET_OWORD_FIELD(temp, TX_ONE_PKT_PER_Q, 1);
++      EFX_SET_OWORD_FIELD(temp, TX_CSR_PUSH_EN, 0);
++      EFX_SET_OWORD_FIELD(temp, TX_DIS_NON_IP_EV, 1);
++      /* Enable SW_EV to inherit in char driver - assume harmless here */
++      EFX_SET_OWORD_FIELD(temp, TX_SW_EV_EN, 1);
++      /* Prefetch threshold 2 => fetch when descriptor cache half empty */
++      EFX_SET_OWORD_FIELD(temp, TX_PREF_THRESHOLD, 2);
++      if (EFX_WORKAROUND_9008(efx))
++              EFX_SET_OWORD_FIELD(temp, TX_PREF_WD_TMR, (unsigned)0x3fffff);
++      /* Squash TX of packets of 16 bytes or less */
++      if (FALCON_REV(efx) >= FALCON_REV_B0 && EFX_WORKAROUND_9141(efx))
++              EFX_SET_OWORD_FIELD(temp, TX_FLUSH_MIN_LEN_EN_B0, 1);
++      falcon_write(efx, &temp, TX_CFG2_REG_KER);
++
++      /* Do not enable TX_NO_EOP_DISC_EN, since it limits packets to 16
++       * descriptors (which is bad).
++       */
++      falcon_read(efx, &temp, TX_CFG_REG_KER);
++      EFX_SET_OWORD_FIELD(temp, TX_NO_EOP_DISC_EN, 0);
++      falcon_write(efx, &temp, TX_CFG_REG_KER);
++
++      /* RX config */
++      falcon_read(efx, &temp, RX_CFG_REG_KER);
++      EFX_SET_OWORD_FIELD_VER(efx, temp, RX_DESC_PUSH_EN, 0);
++      if (EFX_WORKAROUND_7575(efx))
++              EFX_SET_OWORD_FIELD_VER(efx, temp, RX_USR_BUF_SIZE,
++                                      (3 * 4096) / 32);
++      if (FALCON_REV(efx) >= FALCON_REV_B0)
++              EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 1);
++
++      /* RX FIFO flow control thresholds */
++      thresh = ((rx_xon_thresh_bytes >= 0) ?
++                rx_xon_thresh_bytes : efx->type->rx_xon_thresh);
++      EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_MAC_TH, thresh / 256);
++      thresh = ((rx_xoff_thresh_bytes >= 0) ?
++                rx_xoff_thresh_bytes : efx->type->rx_xoff_thresh);
++      EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_MAC_TH, thresh / 256);
++      /* RX control FIFO thresholds [32 entries] */
++      EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XON_TX_TH, 25);
++      EFX_SET_OWORD_FIELD_VER(efx, temp, RX_XOFF_TX_TH, 20);
++      falcon_write(efx, &temp, RX_CFG_REG_KER);
++
++      /* Set destination of both TX and RX Flush events */
++      if (FALCON_REV(efx) >= FALCON_REV_B0) {
++              EFX_POPULATE_OWORD_1(temp, FLS_EVQ_ID, 0);
++              falcon_write(efx, &temp, DP_CTRL_REG);
++      }
 +
-+      tap_blkif_xenbus_init();
++      return 0;
++}
 +
-+      /* Dynamically allocate a major for this device */
-+      ret = register_chrdev(0, "blktap", &blktap_fops);
++void falcon_fini_nic(struct efx_nic *efx)
++{
++      falcon_fini_pcie_core(efx);
++}
 +
-+      if (ret < 0) {
-+              WPRINTK("Couldn't register /dev/xen/blktap\n");
-+              return -ENOMEM;
-+      }       
-+      
-+      blktap_major = ret;
++void falcon_remove_nic(struct efx_nic *efx)
++{
++      /* Tear down the private nic state, and the driverlink nic params */
++      kfree(efx->nic_data);
++      efx->nic_data = efx->dl_info = NULL;
 +
-+      /* tapfds[0] is always NULL */
-+      blktap_next_minor++;
++      falcon_remove_spi_devices(efx);
++      falcon_free_buffer(efx, &efx->irq_status);
 +
-+      DPRINTK("Created misc_dev [/dev/xen/blktap%d]\n",i);
++      /* Reset the NIC finally */
++      (void) falcon_reset_hw(efx, RESET_TYPE_ALL);
 +
-+      /* Make sure the xen class exists */
-+      if ((class = get_xen_class()) != NULL) {
-+              /*
-+               * This will allow udev to create the blktap ctrl device.
-+               * We only want to create blktap0 first.  We don't want
-+               * to flood the sysfs system with needless blktap devices.
-+               * We only create the device when a request of a new device is
-+               * made.
-+               */
-+              class_device_create(class, NULL,
-+                                  MKDEV(blktap_major, 0), NULL,
-+                                  "blktap0");
-+      } else {
-+              /* this is bad, but not fatal */
-+              WPRINTK("blktap: sysfs xen_class not created\n");
++      /* Release the second function after the reset */
++      if (efx->pci_dev2) {
++              pci_dev_put(efx->pci_dev2);
++              efx->pci_dev2 = NULL;
 +      }
++}
 +
-+      DPRINTK("Blktap device successfully created\n");
++void falcon_update_nic_stats(struct efx_nic *efx)
++{
++      efx_oword_t cnt;
 +
-+      return 0;
++      /* Read the RX drop counter */
++      falcon_read(efx, &cnt, RX_NODESC_DROP_REG_KER);
++      efx->n_rx_nodesc_drop_cnt += EFX_OWORD_FIELD(cnt, RX_NODESC_DROP_CNT);
 +}
 +
-+module_init(blkif_init);
-+
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blktap/common.h linux-2.6.18-xen.hg/drivers/xen/blktap/common.h
---- linux-2.6.18/drivers/xen/blktap/common.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blktap/common.h    2007-12-23 11:15:33.547908998 +0100
-@@ -0,0 +1,121 @@
-+/* 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++/**************************************************************************
++ *
++ * Revision-dependent attributes used by efx.c
++ *
++ **************************************************************************
 + */
 +
-+#ifndef __BLKIF__BACKEND__COMMON_H__
-+#define __BLKIF__BACKEND__COMMON_H__
++struct efx_nic_type falcon_a_nic_type = {
++      .is_dual_func = 1,
++      .mem_bar = 2,
++      .mem_map_size = 0x20000,
++      .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_A1,
++      .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_A1,
++      .buf_tbl_base = BUF_TBL_KER_A1,
++      .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_A1,
++      .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_A1,
++      .txd_ring_mask = FALCON_TXD_RING_MASK,
++      .rxd_ring_mask = FALCON_RXD_RING_MASK,
++      .evq_size = FALCON_EVQ_SIZE,
++      .max_dma_mask = FALCON_DMA_MASK,
++      .tx_dma_mask = FALCON_TX_DMA_MASK,
++      .bug5391_mask = 0xf,
++      .rx_xoff_thresh = 2048,
++      .rx_xon_thresh = 512,
++      .rx_buffer_padding = 0x24,
++      .max_interrupt_mode = EFX_INT_MODE_MSI,
++      .phys_addr_channels = 4,
++};
 +
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/slab.h>
-+#include <linux/blkdev.h>
-+#include <linux/vmalloc.h>
-+#include <asm/io.h>
-+#include <asm/setup.h>
-+#include <asm/pgalloc.h>
-+#include <xen/evtchn.h>
-+#include <asm/hypervisor.h>
-+#include <xen/blkif.h>
-+#include <xen/gnttab.h>
-+#include <xen/driver_util.h>
++struct efx_nic_type falcon_b_nic_type = {
++      .is_dual_func = 0,
++      .mem_bar = 2,
++      /* Map everything up to and including the RSS indirection
++       * table.  Don't map MSI-X table, MSI-X PBA since Linux
++       * requires that they not be mapped.  */
++      .mem_map_size = RX_RSS_INDIR_TBL_B0 + 0x800,
++      .txd_ptr_tbl_base = TX_DESC_PTR_TBL_KER_B0,
++      .rxd_ptr_tbl_base = RX_DESC_PTR_TBL_KER_B0,
++      .buf_tbl_base = BUF_TBL_KER_B0,
++      .evq_ptr_tbl_base = EVQ_PTR_TBL_KER_B0,
++      .evq_rptr_tbl_base = EVQ_RPTR_REG_KER_B0,
++      .txd_ring_mask = FALCON_TXD_RING_MASK,
++      .rxd_ring_mask = FALCON_RXD_RING_MASK,
++      .evq_size = FALCON_EVQ_SIZE,
++      .max_dma_mask = FALCON_DMA_MASK,
++      .tx_dma_mask = FALCON_TX_DMA_MASK,
++      .bug5391_mask = 0,
++      .rx_xoff_thresh = 54272, /* ~80Kb - 3*max MTU */
++      .rx_xon_thresh = 27648,  /* ~3*max MTU */
++      .rx_buffer_padding = 0,
++      .max_interrupt_mode = EFX_INT_MODE_MSIX,
++      .phys_addr_channels = 32, /* Hardware limit is 64, but the legacy
++                                 * interrupt handler only supports 32
++                                 * channels */
 +
-+#define DPRINTK(_f, _a...) pr_debug("(file=%s, line=%d) " _f, \
-+                                    __FILE__ , __LINE__ , ## _a )
++};
 +
-+#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args)
+--- linux-2.6.18.8/drivers/net/sfc/falcon.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/falcon.h       2008-05-19 00:33:28.845808833 +0300
+@@ -0,0 +1,177 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+struct backend_info;
++#ifndef EFX_FALCON_H
++#define EFX_FALCON_H
 +
-+typedef struct blkif_st {
-+      /* Unique identifier for this interface. */
-+      domid_t           domid;
-+      unsigned int      handle;
-+      /* Physical parameters of the comms window. */
-+      unsigned int      irq;
-+      /* Comms information. */
-+      enum blkif_protocol blk_protocol;
-+      blkif_back_rings_t blk_rings;
-+      struct vm_struct *blk_ring_area;
-+      /* Back pointer to the backend_info. */
-+      struct backend_info *be;
-+      /* Private fields. */
-+      spinlock_t       blk_ring_lock;
-+      atomic_t         refcnt;
++#include <asm/io.h>
++#include <linux/spinlock.h>
++#include "net_driver.h"
 +
-+      wait_queue_head_t   wq;
-+      struct task_struct  *xenblkd;
-+      unsigned int        waiting_reqs;
-+      request_queue_t     *plug;
++/*
++ * Falcon hardware control
++ */
 +
-+      /* statistics */
-+      unsigned long       st_print;
-+      int                 st_rd_req;
-+      int                 st_wr_req;
-+      int                 st_oo_req;
-+      int                 st_rd_sect;
-+      int                 st_wr_sect;
++enum falcon_revision {
++      FALCON_REV_A0 = 0,
++      FALCON_REV_A1 = 1,
++      FALCON_REV_B0 = 2,
++};
 +
-+      wait_queue_head_t waiting_to_free;
++#if defined(EFX_USE_PCI_DEV_REVISION)
++#define FALCON_REV(efx) ((efx)->pci_dev->revision)
++#else
++#define FALCON_REV(efx) ((efx)->revision)
++#endif
 +
-+      grant_handle_t shmem_handle;
-+      grant_ref_t    shmem_ref;
-+      
-+      int             dev_num;
-+      uint64_t        sectors;
-+} blkif_t;
++extern struct efx_nic_type falcon_a_nic_type;
++extern struct efx_nic_type falcon_b_nic_type;
 +
-+blkif_t *tap_alloc_blkif(domid_t domid);
-+void tap_blkif_free(blkif_t *blkif);
-+int tap_blkif_map(blkif_t *blkif, unsigned long shared_page, 
-+                unsigned int evtchn);
-+void tap_blkif_unmap(blkif_t *blkif);
++/**************************************************************************
++ *
++ * Externs
++ *
++ **************************************************************************
++ */
 +
-+#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
-+#define blkif_put(_b)                                 \
-+      do {                                            \
-+              if (atomic_dec_and_test(&(_b)->refcnt)) \
-+                      wake_up(&(_b)->waiting_to_free);\
-+      } while (0)
++/* TX data path */
++extern int falcon_probe_tx(struct efx_tx_queue *tx_queue);
++extern int falcon_init_tx(struct efx_tx_queue *tx_queue);
++extern void falcon_fini_tx(struct efx_tx_queue *tx_queue);
++extern void falcon_remove_tx(struct efx_tx_queue *tx_queue);
++#if defined(EFX_USE_FASTCALL)
++extern void fastcall falcon_push_buffers(struct efx_tx_queue *tx_queue);
++#else
++extern void falcon_push_buffers(struct efx_tx_queue *tx_queue);
++#endif
 +
++/* RX data path */
++extern int falcon_probe_rx(struct efx_rx_queue *rx_queue);
++extern int falcon_init_rx(struct efx_rx_queue *rx_queue);
++extern void falcon_fini_rx(struct efx_rx_queue *rx_queue);
++extern void falcon_remove_rx(struct efx_rx_queue *rx_queue);
++#if defined(EFX_USE_FASTCALL)
++extern void fastcall falcon_notify_rx_desc(struct efx_rx_queue *rx_queue);
++#else
++extern void falcon_notify_rx_desc(struct efx_rx_queue *rx_queue);
++#endif
 +
-+struct phys_req {
-+      unsigned short       dev;
-+      unsigned short       nr_sects;
-+      struct block_device *bdev;
-+      blkif_sector_t       sector_number;
-+};
++/* Event data path */
++extern int falcon_probe_eventq(struct efx_channel *channel);
++extern int falcon_init_eventq(struct efx_channel *channel);
++extern void falcon_fini_eventq(struct efx_channel *channel);
++extern void falcon_remove_eventq(struct efx_channel *channel);
++#if defined(EFX_USE_FASTCALL)
++extern int fastcall falcon_process_eventq(struct efx_channel *channel,
++                                        int *rx_quota);
++#else
++extern int falcon_process_eventq(struct efx_channel *channel, int *rx_quota);
++#endif
++#if defined(EFX_USE_FASTCALL)
++extern void fastcall falcon_eventq_read_ack(struct efx_channel *channel);
++#else
++extern void falcon_eventq_read_ack(struct efx_channel *channel);
++#endif
++
++/* Ports */
++extern int falcon_probe_port(struct efx_nic *efx);
++extern void falcon_remove_port(struct efx_nic *efx);
++
++/* MAC/PHY */
++extern void falcon_check_xaui_link_up(struct efx_nic *efx);
++extern int falcon_xaui_link_ok(struct efx_nic *efx);
++extern int falcon_dma_stats(struct efx_nic *efx,
++                          unsigned int done_offset);
++extern void falcon_drain_tx_fifo(struct efx_nic *efx);
++extern void falcon_deconfigure_mac_wrapper(struct efx_nic *efx);
++extern void falcon_reconfigure_mac_wrapper(struct efx_nic *efx);
++
++/* Interrupts and test events */
++extern int falcon_init_interrupt(struct efx_nic *efx);
++extern void falcon_enable_interrupts(struct efx_nic *efx);
++extern void falcon_generate_test_event(struct efx_channel *channel,
++                                     unsigned int magic);
++extern void falcon_generate_interrupt(struct efx_nic *efx);
++extern void falcon_set_int_moderation(struct efx_channel *channel);
++extern void falcon_disable_interrupts(struct efx_nic *efx);
++extern void falcon_fini_interrupt(struct efx_nic *efx);
++
++/* Global Resources */
++extern int falcon_probe_nic(struct efx_nic *efx);
++extern int falcon_probe_resources(struct efx_nic *efx);
++extern int falcon_init_nic(struct efx_nic *efx);
++extern int falcon_reset_hw(struct efx_nic *efx, enum reset_type method);
++extern void falcon_fini_nic(struct efx_nic *efx);
++extern void falcon_remove_resources(struct efx_nic *efx);
++extern void falcon_remove_nic(struct efx_nic *efx);
++extern void falcon_update_nic_stats(struct efx_nic *efx);
++extern void falcon_set_multicast_hash(struct efx_nic *efx);
++extern int falcon_reset_xaui(struct efx_nic *efx);
++
++/**************************************************************************
++ *
++ * Falcon MAC stats
++ *
++ **************************************************************************
++ */
++
++#define FALCON_STAT_OFFSET(falcon_stat) EFX_VAL(falcon_stat, offset)
++#define FALCON_STAT_WIDTH(falcon_stat) EFX_VAL(falcon_stat, WIDTH)
++
++/* Retrieve statistic from statistics block */
++#define FALCON_STAT(efx, falcon_stat, efx_stat) do {          \
++      if (FALCON_STAT_WIDTH(falcon_stat) == 16)               \
++              (efx)->mac_stats.efx_stat += le16_to_cpu(       \
++                      *((__force __le16 *)                            \
++                        (efx->stats_buffer.addr +             \
++                         FALCON_STAT_OFFSET(falcon_stat))));  \
++      else if (FALCON_STAT_WIDTH(falcon_stat) == 32)          \
++              (efx)->mac_stats.efx_stat += le32_to_cpu(       \
++                      *((__force __le32 *)                            \
++                        (efx->stats_buffer.addr +             \
++                         FALCON_STAT_OFFSET(falcon_stat))));  \
++      else                                                    \
++              (efx)->mac_stats.efx_stat += le64_to_cpu(       \
++                      *((__force __le64 *)                            \
++                        (efx->stats_buffer.addr +             \
++                         FALCON_STAT_OFFSET(falcon_stat))));  \
++      } while (0)
 +
-+void tap_blkif_interface_init(void);
++#define FALCON_MAC_STATS_SIZE 0x100
 +
-+void tap_blkif_xenbus_init(void);
++#define MAC_DATA_LBN 0
++#define MAC_DATA_WIDTH 32
 +
-+irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
-+int tap_blkif_schedule(void *arg);
++extern void falcon_generate_event(struct efx_channel *channel,
++                                efx_qword_t *event);
 +
-+int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif);
-+void signal_tapdisk(int idx);
++#ifdef CONFIG_SFC_DEBUGFS
++struct seq_file;
++extern int falcon_debugfs_read_hardware_desc(struct seq_file *file, void *data);
++#endif
 +
-+#endif /* __BLKIF__BACKEND__COMMON_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blktap/interface.c linux-2.6.18-xen.hg/drivers/xen/blktap/interface.c
---- linux-2.6.18/drivers/xen/blktap/interface.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blktap/interface.c 2007-12-23 11:15:33.547908998 +0100
-@@ -0,0 +1,174 @@
-+/******************************************************************************
-+ * drivers/xen/blktap/interface.c
-+ * 
-+ * Block-device interface management.
-+ * 
-+ * Copyright (c) 2004, Keir Fraser
++#endif /* EFX_FALCON_H */
+--- linux-2.6.18.8/drivers/net/sfc/falcon_gmac.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/falcon_gmac.c  2008-05-19 00:33:28.845808833 +0300
+@@ -0,0 +1,320 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
 + *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
 + *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
 + *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
 + *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include "common.h"
-+#include <xen/evtchn.h>
++#include <linux/delay.h>
++#include "net_driver.h"
++#include "efx.h"
++#include "falcon.h"
++#include "mac.h"
++#include "falcon_hwdefs.h"
++#include "falcon_io.h"
++#include "gmii.h"
 +
-+static kmem_cache_t *blkif_cachep;
++/**************************************************************************
++ *
++ * MAC register access
++ *
++ **************************************************************************/
 +
-+blkif_t *tap_alloc_blkif(domid_t domid)
++/* Offset of a GMAC register within Falcon */
++#define FALCON_GMAC_REG(mac_reg)                                      \
++      (FALCON_GMAC_REGBANK + ((mac_reg) * FALCON_GMAC_REG_SIZE))
++
++static void falcon_gmac_writel(struct efx_nic *efx,
++                             efx_dword_t *value, unsigned int mac_reg)
 +{
-+      blkif_t *blkif;
++      efx_oword_t temp;
 +
-+      blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
-+      if (!blkif)
-+              return ERR_PTR(-ENOMEM);
++      EFX_POPULATE_OWORD_1(temp, MAC_DATA, EFX_DWORD_FIELD(*value, MAC_DATA));
++      falcon_write(efx, &temp, FALCON_GMAC_REG(mac_reg));
++}
 +
-+      memset(blkif, 0, sizeof(*blkif));
-+      blkif->domid = domid;
-+      spin_lock_init(&blkif->blk_ring_lock);
-+      atomic_set(&blkif->refcnt, 1);
-+      init_waitqueue_head(&blkif->wq);
-+      blkif->st_print = jiffies;
-+      init_waitqueue_head(&blkif->waiting_to_free);
++static void falcon_gmac_readl(struct efx_nic *efx,
++                            efx_dword_t *value, unsigned int mac_reg)
++{
++      efx_oword_t temp;
 +
-+      return blkif;
++      falcon_read(efx, &temp, FALCON_GMAC_REG(mac_reg));
++      EFX_POPULATE_DWORD_1(*value, MAC_DATA, EFX_OWORD_FIELD(temp, MAC_DATA));
 +}
 +
-+static int map_frontend_page(blkif_t *blkif, unsigned long shared_page)
++/**************************************************************************
++ *
++ * MAC operations
++ *
++ *************************************************************************/
++
++static int falcon_init_gmac(struct efx_nic *efx)
 +{
-+      struct gnttab_map_grant_ref op;
++      int rc;
 +
-+      gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
-+                        GNTMAP_host_map, shared_page, blkif->domid);
++      /* Reset the MAC */
++      mentormac_reset(efx);
 +
-+      if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
-+              BUG();
++      /* Initialise PHY */
++      rc = efx->phy_op->init(efx);
++      if (rc)
++              return rc;
 +
-+      if (op.status) {
-+              DPRINTK(" Grant table operation failure !\n");
-+              return op.status;
-+      }
++      return 0;
++}
 +
-+      blkif->shmem_ref = shared_page;
-+      blkif->shmem_handle = op.handle;
++static void falcon_reconfigure_gmac(struct efx_nic *efx)
++{
++      /* Reconfigure PHY and pick up PHY parameters.  This updates
++       * the link status. */
++      efx->phy_op->reconfigure(efx);
 +
-+      return 0;
++      /* Isolate the MAC. */
++      falcon_deconfigure_mac_wrapper(efx);
++
++      /* Reconfigure MAC */
++      mentormac_reconfigure(efx);
++
++      /* Reconfigure MAC wrapper */
++      falcon_reconfigure_mac_wrapper(efx);
 +}
 +
-+static void unmap_frontend_page(blkif_t *blkif)
++static void falcon_fini_gmac(struct efx_nic *efx)
 +{
-+      struct gnttab_unmap_grant_ref op;
++      /* Isolate the MAC - PHY */
++      falcon_deconfigure_mac_wrapper(efx);
 +
-+      gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
-+                          GNTMAP_host_map, blkif->shmem_handle);
++      /* Shut down PHY */
++      efx->phy_op->fini(efx);
 +
-+      if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
-+              BUG();
++      /* Reset MAC */
++      mentormac_reset(efx);
 +}
 +
-+int tap_blkif_map(blkif_t *blkif, unsigned long shared_page, 
-+                unsigned int evtchn)
++static void falcon_update_stats_gmac(struct efx_nic *efx)
 +{
-+      int err;
++      struct efx_mac_stats *mac_stats = &efx->mac_stats;
++      unsigned long old_rx_pause, old_tx_pause;
++      unsigned long new_rx_pause, new_tx_pause;
++      int rc;
 +
-+      /* Already connected through? */
-+      if (blkif->irq)
-+              return 0;
++      rc = falcon_dma_stats(efx, GDmaDone_offset);
++      if (rc)
++              return;
 +
-+      if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
-+              return -ENOMEM;
++      /* Pause frames are erroneously counted as errors (SFC bug 3269) */
++      old_rx_pause = mac_stats->rx_pause;
++      old_tx_pause = mac_stats->tx_pause;
++
++      /* Update MAC stats from DMAed values */
++      FALCON_STAT(efx, GRxGoodOct, rx_good_bytes);
++      FALCON_STAT(efx, GRxBadOct, rx_bad_bytes);
++      FALCON_STAT(efx, GRxMissPkt, rx_missed);
++      FALCON_STAT(efx, GRxFalseCRS, rx_false_carrier);
++      FALCON_STAT(efx, GRxPausePkt, rx_pause);
++      FALCON_STAT(efx, GRxBadPkt, rx_bad);
++      FALCON_STAT(efx, GRxUcastPkt, rx_unicast);
++      FALCON_STAT(efx, GRxMcastPkt, rx_multicast);
++      FALCON_STAT(efx, GRxBcastPkt, rx_broadcast);
++      FALCON_STAT(efx, GRxGoodLt64Pkt, rx_good_lt64);
++      FALCON_STAT(efx, GRxBadLt64Pkt, rx_bad_lt64);
++      FALCON_STAT(efx, GRx64Pkt, rx_64);
++      FALCON_STAT(efx, GRx65to127Pkt, rx_65_to_127);
++      FALCON_STAT(efx, GRx128to255Pkt, rx_128_to_255);
++      FALCON_STAT(efx, GRx256to511Pkt, rx_256_to_511);
++      FALCON_STAT(efx, GRx512to1023Pkt, rx_512_to_1023);
++      FALCON_STAT(efx, GRx1024to15xxPkt, rx_1024_to_15xx);
++      FALCON_STAT(efx, GRx15xxtoJumboPkt, rx_15xx_to_jumbo);
++      FALCON_STAT(efx, GRxGtJumboPkt, rx_gtjumbo);
++      FALCON_STAT(efx, GRxFcsErr64to15xxPkt, rx_bad_64_to_15xx);
++      FALCON_STAT(efx, GRxFcsErr15xxtoJumboPkt, rx_bad_15xx_to_jumbo);
++      FALCON_STAT(efx, GRxFcsErrGtJumboPkt, rx_bad_gtjumbo);
++      FALCON_STAT(efx, GTxGoodBadOct, tx_bytes);
++      FALCON_STAT(efx, GTxGoodOct, tx_good_bytes);
++      FALCON_STAT(efx, GTxSglColPkt, tx_single_collision);
++      FALCON_STAT(efx, GTxMultColPkt, tx_multiple_collision);
++      FALCON_STAT(efx, GTxExColPkt, tx_excessive_collision);
++      FALCON_STAT(efx, GTxDefPkt, tx_deferred);
++      FALCON_STAT(efx, GTxLateCol, tx_late_collision);
++      FALCON_STAT(efx, GTxExDefPkt, tx_excessive_deferred);
++      FALCON_STAT(efx, GTxPausePkt, tx_pause);
++      FALCON_STAT(efx, GTxBadPkt, tx_bad);
++      FALCON_STAT(efx, GTxUcastPkt, tx_unicast);
++      FALCON_STAT(efx, GTxMcastPkt, tx_multicast);
++      FALCON_STAT(efx, GTxBcastPkt, tx_broadcast);
++      FALCON_STAT(efx, GTxLt64Pkt, tx_lt64);
++      FALCON_STAT(efx, GTx64Pkt, tx_64);
++      FALCON_STAT(efx, GTx65to127Pkt, tx_65_to_127);
++      FALCON_STAT(efx, GTx128to255Pkt, tx_128_to_255);
++      FALCON_STAT(efx, GTx256to511Pkt, tx_256_to_511);
++      FALCON_STAT(efx, GTx512to1023Pkt, tx_512_to_1023);
++      FALCON_STAT(efx, GTx1024to15xxPkt, tx_1024_to_15xx);
++      FALCON_STAT(efx, GTx15xxtoJumboPkt, tx_15xx_to_jumbo);
++      FALCON_STAT(efx, GTxGtJumboPkt, tx_gtjumbo);
++      FALCON_STAT(efx, GTxNonTcpUdpPkt, tx_non_tcpudp);
++      FALCON_STAT(efx, GTxMacSrcErrPkt, tx_mac_src_error);
++      FALCON_STAT(efx, GTxIpSrcErrPkt, tx_ip_src_error);
++
++      /* Pause frames are erroneously counted as errors (SFC bug 3269) */
++      new_rx_pause = mac_stats->rx_pause;
++      new_tx_pause = mac_stats->tx_pause;
++      mac_stats->rx_bad -= (new_rx_pause - old_rx_pause);
++      mac_stats->tx_bad -= (new_tx_pause - old_tx_pause);
++
++      /* Derive stats that the MAC doesn't provide directly */
++      mac_stats->tx_bad_bytes =
++              mac_stats->tx_bytes - mac_stats->tx_good_bytes;
++      mac_stats->tx_packets =
++              mac_stats->tx_lt64 + mac_stats->tx_64 +
++              mac_stats->tx_65_to_127 + mac_stats->tx_128_to_255 +
++              mac_stats->tx_256_to_511 + mac_stats->tx_512_to_1023 +
++              mac_stats->tx_1024_to_15xx + mac_stats->tx_15xx_to_jumbo +
++              mac_stats->tx_gtjumbo;
++      mac_stats->tx_collision =
++              mac_stats->tx_single_collision +
++              mac_stats->tx_multiple_collision +
++              mac_stats->tx_excessive_collision +
++              mac_stats->tx_late_collision;
++      mac_stats->rx_bytes =
++              mac_stats->rx_good_bytes + mac_stats->rx_bad_bytes;
++      mac_stats->rx_packets =
++              mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64 +
++              mac_stats->rx_64 + mac_stats->rx_65_to_127 +
++              mac_stats->rx_128_to_255 + mac_stats->rx_256_to_511 +
++              mac_stats->rx_512_to_1023 + mac_stats->rx_1024_to_15xx +
++              mac_stats->rx_15xx_to_jumbo + mac_stats->rx_gtjumbo;
++      mac_stats->rx_good = mac_stats->rx_packets - mac_stats->rx_bad;
++      mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64;
++}
++
++static int falcon_check_gmac(struct efx_nic *efx)
++{
++      /* Nothing to do */
++      return 0;
++}
 +
-+      err = map_frontend_page(blkif, shared_page);
-+      if (err) {
-+              free_vm_area(blkif->blk_ring_area);
-+              return err;
-+      }
++static void falcon_gmac_sim_phy_event(struct efx_nic *efx)
++{
++      efx_qword_t phy_event;
 +
-+      switch (blkif->blk_protocol) {
-+      case BLKIF_PROTOCOL_NATIVE:
-+      {
-+              blkif_sring_t *sring;
-+              sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
-+              BACK_RING_INIT(&blkif->blk_rings.native, sring, PAGE_SIZE);
-+              break;
-+      }
-+      case BLKIF_PROTOCOL_X86_32:
-+      {
-+              blkif_x86_32_sring_t *sring_x86_32;
-+              sring_x86_32 = (blkif_x86_32_sring_t *)blkif->blk_ring_area->addr;
-+              BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32, PAGE_SIZE);
-+              break;
-+      }
-+      case BLKIF_PROTOCOL_X86_64:
-+      {
-+              blkif_x86_64_sring_t *sring_x86_64;
-+              sring_x86_64 = (blkif_x86_64_sring_t *)blkif->blk_ring_area->addr;
-+              BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64, PAGE_SIZE);
-+              break;
-+      }
-+      default:
-+              BUG();
-+      }
++      EFX_POPULATE_QWORD_2(phy_event,
++                           EV_CODE, GLOBAL_EV_DECODE,
++                           G_PHY0_INTR, 1);
++      falcon_generate_event(&efx->channel[0], &phy_event);
++}
 +
-+      err = bind_interdomain_evtchn_to_irqhandler(
-+              blkif->domid, evtchn, tap_blkif_be_int,
-+              0, "blkif-backend", blkif);
-+      if (err < 0) {
-+              unmap_frontend_page(blkif);
-+              free_vm_area(blkif->blk_ring_area);
-+              blkif->blk_rings.common.sring = NULL;
-+              return err;
++static void falcon_gmac_reset_phy(struct efx_nic *efx)
++{
++      struct mii_if_info *gmii = &efx->mii;
++      int bmcr, i;
++
++      /* Perform software reset to make new settings take effect */
++      bmcr = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_BMCR);
++      bmcr |= BMCR_RESET;
++      gmii->mdio_write(gmii->dev, gmii->phy_id, MII_BMCR, bmcr);
++
++      /* Wait for the reset to deassert */
++      for (i = 20; i; --i) {
++              udelay(10);
++              if ((gmii->mdio_read(gmii->dev, gmii->phy_id, MII_BMCR) &
++                  BMCR_RESET) == 0)
++                      return;
 +      }
-+      blkif->irq = err;
 +
-+      return 0;
++      EFX_ERR(efx, "wait for PHY reset timed out\n");
 +}
 +
-+void tap_blkif_unmap(blkif_t *blkif)
++
++static int falcon_gmac_get_settings(struct efx_nic *efx,
++                                  struct ethtool_cmd *ecmd)
 +{
-+      if (blkif->irq) {
-+              unbind_from_irqhandler(blkif->irq, blkif);
-+              blkif->irq = 0;
-+      }
-+      if (blkif->blk_rings.common.sring) {
-+              unmap_frontend_page(blkif);
-+              free_vm_area(blkif->blk_ring_area);
-+              blkif->blk_rings.common.sring = NULL;
-+      }
++      struct mii_if_info *gmii = &efx->mii;
++      int rc;
++
++      rc = mii_ethtool_gset(gmii, ecmd);
++      ecmd->supported &= ~(SUPPORTED_1000baseT_Half);
++      return rc;
 +}
 +
-+void tap_blkif_free(blkif_t *blkif)
++static int falcon_gmac_set_settings(struct efx_nic *efx,
++                                  struct ethtool_cmd *ecmd)
 +{
-+      atomic_dec(&blkif->refcnt);
-+      wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
++      struct mii_if_info *gmii = &efx->mii;
++      int rc;
 +
-+      tap_blkif_unmap(blkif);
-+      kmem_cache_free(blkif_cachep, blkif);
++      /* 1000Mbps half-duplex is technically legal, but none of our
++       * current hardware supports it, so just disallow it. */
++      if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) {
++              EFX_LOG(efx, "rejecting unsupported 1000Mbps HD"
++                      " setting\n");
++              return -EINVAL;
++      }
++
++      /* Use MII to set all other settings */
++      rc = mii_ethtool_sset(gmii, ecmd);
++      if (rc)
++              return rc;
++
++      /* Reset the PHY */
++      falcon_gmac_reset_phy(efx);
++
++      return 0;
 +}
 +
-+void __init tap_blkif_interface_init(void)
++static int falcon_gmac_set_pause(struct efx_nic *efx,
++                               enum efx_fc_type flow_control)
 +{
-+      blkif_cachep = kmem_cache_create("blktapif_cache", sizeof(blkif_t), 
-+                                       0, 0, NULL, NULL);
++      struct mii_if_info *gmii = &efx->mii;
++      int adv;
++
++      /* GMAC has tiny MAC FIFO, so TX flow control won't work */
++      if (flow_control & EFX_FC_TX)
++              return -EINVAL;
++
++      efx->flow_control = flow_control;
++
++      /* Push autonegotiation to PHY */
++      adv = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_ADVERTISE);
++      adv &= ~GM_ADVERTISE_PAUSE_CAP;
++      adv |= (flow_control & EFX_FC_AUTO) ? GM_ADVERTISE_PAUSE_CAP : 0;
++      gmii->mdio_write(gmii->dev, gmii->phy_id, MII_ADVERTISE, adv);
++
++      falcon_gmac_reset_phy(efx);
++
++      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blktap/Makefile linux-2.6.18-xen.hg/drivers/xen/blktap/Makefile
---- linux-2.6.18/drivers/xen/blktap/Makefile   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blktap/Makefile    2007-12-23 11:15:33.544575492 +0100
-@@ -0,0 +1,5 @@
-+LINUXINCLUDE += -I../xen/include/public/io
 +
-+obj-$(CONFIG_XEN_BLKDEV_TAP) := xenblktap.o
 +
-+xenblktap-y := xenbus.o interface.o blktap.o 
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/blktap/xenbus.c linux-2.6.18-xen.hg/drivers/xen/blktap/xenbus.c
---- linux-2.6.18/drivers/xen/blktap/xenbus.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/blktap/xenbus.c    2007-12-23 11:15:33.547908998 +0100
-@@ -0,0 +1,477 @@
-+/* drivers/xen/blktap/xenbus.c
++struct efx_mac_operations falcon_gmac_operations = {
++      .mac_writel     = falcon_gmac_writel,
++      .mac_readl      = falcon_gmac_readl,
++      .init           = falcon_init_gmac,
++      .reconfigure    = falcon_reconfigure_gmac,
++      .update_stats   = falcon_update_stats_gmac,
++      .fini           = falcon_fini_gmac,
++      .check_hw       = falcon_check_gmac,
++      .fake_phy_event = falcon_gmac_sim_phy_event,
++      .get_settings   = falcon_gmac_get_settings,
++      .set_settings   = falcon_gmac_set_settings,
++      .set_pause      = falcon_gmac_set_pause,
++};
+--- linux-2.6.18.8/drivers/net/sfc/falcon_hwdefs.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/falcon_hwdefs.h        2008-05-19 00:33:28.849809063 +0300
+@@ -0,0 +1,1620 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
 + *
-+ * Xenbus code for blktap
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
 + *
-+ * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
 + *
-+ * Based on the blkback xenbus code:
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
 + *
-+ * Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
-+ * Copyright (C) 2005 XenSource Ltd
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
 + *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef EFX_FALCON_HWDEFS_H
++#define EFX_FALCON_HWDEFS_H
++
++/*
++ * Falcon hardware value definitions.
++ * Falcon is the internal codename for the SFC4000 controller that is
++ * present in SFE400X evaluation boards
++ */
++
++/**************************************************************************
++ *
++ * Falcon registers
++ *
++ **************************************************************************
++ */
++
++/* Address region register */
++#define ADR_REGION_REG_KER    0x00
++#define ADR_REGION0_LBN       0
++#define ADR_REGION0_WIDTH     18
++#define ADR_REGION1_LBN       32
++#define ADR_REGION1_WIDTH     18
++#define ADR_REGION2_LBN       64
++#define ADR_REGION2_WIDTH     18
++#define ADR_REGION3_LBN       96
++#define ADR_REGION3_WIDTH     18
++
++/* Interrupt enable register */
++#define INT_EN_REG_KER 0x0010
++#define INT_LEVEL_SEL_LBN 8
++#define INT_LEVEL_SEL_WIDTH 6
++#define MEM_PERR_INT_EN_KER_LBN 5
++#define MEM_PERR_INT_EN_KER_WIDTH 1
++#define KER_INT_CHAR_LBN 4
++#define KER_INT_CHAR_WIDTH 1
++#define KER_INT_KER_LBN 3
++#define KER_INT_KER_WIDTH 1
++#define ILL_ADR_ERR_INT_EN_KER_LBN 2
++#define ILL_ADR_ERR_INT_EN_KER_WIDTH 1
++#define SRM_PERR_INT_EN_KER_LBN 1
++#define SRM_PERR_INT_EN_KER_WIDTH 1
++#define DRV_INT_EN_KER_LBN 0
++#define DRV_INT_EN_KER_WIDTH 1
++
++/* Interrupt status address register */
++#define INT_ADR_REG_KER       0x0030
++#define NORM_INT_VEC_DIS_KER_LBN 64
++#define NORM_INT_VEC_DIS_KER_WIDTH 1
++#define INT_ADR_KER_LBN 0
++#define INT_ADR_KER_WIDTH EFX_DMA_TYPE_WIDTH(64) /* not 46 for this one */
++
++/* Interrupt status register (B0 only) */
++#define INT_ISR0_B0 0x90
++#define INT_ISR1_B0 0xA0
++
++/* Interrupt acknowledge register (A0/A1 only) */
++#define INT_ACK_REG_KER_A1 0x0050
++#define INT_ACK_DUMMY_DATA_LBN 0
++#define INT_ACK_DUMMY_DATA_WIDTH 32
++
++/* Interrupt acknowledge work-around register (A0/A1 only )*/
++#define WORK_AROUND_BROKEN_PCI_READS_REG_KER_A1 0x0070
++
++/* Hardware initialisation register */
++#define HW_INIT_REG_KER 0x00c0
++#define BCSR_TARGET_MASK_LBN 101
++#define BCSR_TARGET_MASK_WIDTH 4
++#define PCIE_TIMEOUT_DIS_LBN 123
++#define PCIE_TIMEOUT_DIS_WIDTH 1
++#define B2B_REQ_EN_B0_LBN 45
++#define B2B_REQ_EN_B0_WIDTH 1
++#define FC_BLOCKING_EN_B0_LBN 44
++#define FC_BLOCKING_EN_B0_WIDTH 1
++
++/* SPI host command register */
++#define EE_SPI_HCMD_REG_KER 0x0100
++#define EE_SPI_HCMD_CMD_EN_LBN 31
++#define EE_SPI_HCMD_CMD_EN_WIDTH 1
++#define EE_WR_TIMER_ACTIVE_LBN 28
++#define EE_WR_TIMER_ACTIVE_WIDTH 1
++#define EE_SPI_HCMD_SF_SEL_LBN 24
++#define EE_SPI_HCMD_SF_SEL_WIDTH 1
++#define EE_SPI_EEPROM 0
++#define EE_SPI_FLASH 1
++#define EE_SPI_HCMD_DABCNT_LBN 16
++#define EE_SPI_HCMD_DABCNT_WIDTH 5
++#define EE_SPI_HCMD_READ_LBN 15
++#define EE_SPI_HCMD_READ_WIDTH 1
++#define EE_SPI_READ 1
++#define EE_SPI_WRITE 0
++#define EE_SPI_HCMD_DUBCNT_LBN 12
++#define EE_SPI_HCMD_DUBCNT_WIDTH 2
++#define EE_SPI_HCMD_ADBCNT_LBN 8
++#define EE_SPI_HCMD_ADBCNT_WIDTH 2
++#define EE_SPI_HCMD_ENC_LBN 0
++#define EE_SPI_HCMD_ENC_WIDTH 8
++
++/* SPI host address register */
++#define EE_SPI_HADR_REG_KER 0x0110
++#define EE_SPI_HADR_DUBYTE_LBN 24
++#define EE_SPI_HADR_DUBYTE_WIDTH 8
++#define EE_SPI_HADR_ADR_LBN 0
++#define EE_SPI_HADR_ADR_WIDTH 24
++
++/* SPI host data register */
++#define EE_SPI_HDATA_REG_KER 0x0120
++#define EE_SPI_HDATA3_LBN 96
++#define EE_SPI_HDATA3_WIDTH 32
++#define EE_SPI_HDATA2_LBN 64
++#define EE_SPI_HDATA2_WIDTH 32
++#define EE_SPI_HDATA1_LBN 32
++#define EE_SPI_HDATA1_WIDTH 32
++#define EE_SPI_HDATA0_LBN 0
++#define EE_SPI_HDATA0_WIDTH 32
++
++/* SPI/VPD config register */
++#define EE_VPD_CFG_REG_KER 0x0140
++#define EE_VPD_EN_LBN 0
++#define EE_VPD_EN_WIDTH 1
++#define EE_VPD_EN_AD9_MODE_LBN 1
++#define EE_VPD_EN_AD9_MODE_WIDTH 1
++#define EE_EE_CLOCK_DIV_LBN 112
++#define EE_EE_CLOCK_DIV_WIDTH 7
++#define EE_SF_CLOCK_DIV_LBN 120
++#define EE_SF_CLOCK_DIV_WIDTH 7
++
++/* PCIE CORE ACCESS REG */
++#define PCIE_CORE_INDIRECT_REG 0x01f0
++#define PCIE_CORE_ADDR_LBN 0
++#define PCIE_CORE_ADDR_WIDTH 12
++#define PCIE_CORE_RW_LBN 15
++#define PCIE_CORE_RW_WIDTH 1
++#define PCIE_CORE_VALUE_LBN 32
++#define PCIE_CORE_VALUE_WIDTH 32
++
++#define PCIE_CORE_ADDR_PCIE_DEVICE_CTRL_STAT 0x68
++#define PCIE_CORE_ADDR_PCIE_LINK_CTRL_STAT 0x70
++#define PCIE_CORE_ADDR_ACK_RPL_TIMER 0x700
++#define PCIE_CORE_ACK_TL_LBN 0
++#define PCIE_CORE_ACK_TL_WIDTH 16
++#define PCIE_CORE_RPL_TL_LBN 16
++#define PCIE_CORE_RPL_TL_WIDTH 16
++
++#define PCIE_CORE_ADDR_ACK_FREQ 0x70C
++#define PCIE_CORE_ACK_FREQ_LBN 0
++#define PCIE_CORE_ACK_FREQ_WIDTH 7
++
++
++/* NIC status register */
++#define NIC_STAT_REG 0x0200
++#define EE_STRAP_EN_LBN 31
++#define EE_STRAP_EN_WIDTH 1
++#define EE_STRAP_OVR_LBN 24
++#define EE_STRAP_OVR_WIDTH 4
++#define ONCHIP_SRAM_LBN 16
++#define ONCHIP_SRAM_WIDTH 1
++#define SF_PRST_LBN 9
++#define SF_PRST_WIDTH 1
++#define EE_PRST_LBN 8
++#define EE_PRST_WIDTH 1
++#define EE_STRAP_LBN 7
++#define EE_STRAP_WIDTH 1
++/* See pic_mode_t for decoding of this field */
++#define STRAP_ISCSI_EN_LBN 3
++#define STRAP_ISCSI_EN_WIDTH 1
++#define STRAP_PINS_LBN 0
++#define STRAP_PINS_WIDTH 3
++/* These bit definitions are extrapolated from the list of numerical
++ * values for STRAP_PINS.
++ */
++#define STRAP_10G_LBN 2
++#define STRAP_10G_WIDTH 1
++#define STRAP_DUAL_PORT_LBN 1
++#define STRAP_DUAL_PORT_WIDTH 1
++#define STRAP_PCIE_LBN 0
++#define STRAP_PCIE_WIDTH 1
++
++#define FLASH_PRESENT_LBN 7
++#define FLASH_PRESENT_WIDTH 1
++#define EEPROM_PRESENT_LBN 6
++#define EEPROM_PRESENT_WIDTH 1
++#define BOOTED_USING_NVDEVICE_LBN 3
++#define BOOTED_USING_NVDEVICE_WIDTH 1
++
++/* GPIO control register */
++
++#define GPIO_CTL_REG_KER 0x0210
++
++#define GPIO_USE_NIC_CLK_LBN (30)
++#define GPIO_USE_NIC_CLK_WIDTH (1)
++
++#define GPIO_OUTPUTS_LBN   (16)
++#define GPIO_OUTPUTS_WIDTH (4)
++
++#define GPIO_INPUTS_LBN (8)
++#define GPIO_INPUT_WIDTH (4)
++
++#define GPIO_DIRECTION_LBN (24)
++#define GPIO_DIRECTION_WIDTH (4)
++#define GPIO_DIRECTION_OUT (1)
++#define GPIO_SRAM_SLEEP (1 << 1)
++
++#define GPIO3_OEN_LBN (GPIO_DIRECTION_LBN + 3)
++#define       GPIO3_OEN_WIDTH 1
++#define       GPIO2_OEN_LBN (GPIO_DIRECTION_LBN + 2)
++#define       GPIO2_OEN_WIDTH 1
++#define       GPIO1_OEN_LBN (GPIO_DIRECTION_LBN + 1)
++#define       GPIO1_OEN_WIDTH 1
++#define GPIO0_OEN_LBN (GPIO_DIRECTION_LBN + 0)
++#define       GPIO0_OEN_WIDTH 1
++
++#define       GPIO3_OUT_LBN (GPIO_OUTPUTS_LBN + 3)
++#define       GPIO3_OUT_WIDTH 1
++#define       GPIO2_OUT_LBN (GPIO_OUTPUTS_LBN + 2)
++#define       GPIO2_OUT_WIDTH 1
++#define       GPIO1_OUT_LBN (GPIO_OUTPUTS_LBN + 1)
++#define       GPIO1_OUT_WIDTH 1
++#define       GPIO0_OUT_LBN (GPIO_OUTPUTS_LBN + 0)
++#define       GPIO0_OUT_WIDTH 1
++
++#define GPIO3_IN_LBN (GPIO_INPUTS_LBN + 3)
++#define       GPIO3_IN_WIDTH 1
++#define GPIO2_IN_LBN (GPIO_INPUTS_LBN + 2)
++#define       GPIO2_IN_WIDTH 1
++#define GPIO1_IN_LBN (GPIO_INPUTS_LBN + 1)
++#define       GPIO1_IN_WIDTH 1
++#define GPIO0_IN_LBN (GPIO_INPUTS_LBN + 0)
++#define       GPIO0_IN_WIDTH 1
++
++/* Global control register */
++#define GLB_CTL_REG_KER       0x0220
++#define EXT_PHY_RST_CTL_LBN 63
++#define EXT_PHY_RST_CTL_WIDTH 1
++#define PCIE_SD_RST_CTL_LBN 61
++#define PCIE_SD_RST_CTL_WIDTH 1
++#define PCIX_RST_CTL_LBN 60
++#define PCIX_RST_CTL_WIDTH 1
++#define PCIE_STCK_RST_CTL_LBN 59
++
++#define PCIE_STCK_RST_CTL_WIDTH 1
++#define PCIE_NSTCK_RST_CTL_LBN 58
++#define PCIE_NSTCK_RST_CTL_WIDTH 1
++#define PCIE_CORE_RST_CTL_LBN 57
++#define PCIE_CORE_RST_CTL_WIDTH 1
++#define EE_RST_CTL_LBN 49
++#define EE_RST_CTL_WIDTH 1
++#define CS_RST_CTL_LBN 48
++#define CS_RST_CTL_WIDTH 1
++#define RST_EXT_PHY_LBN 31
++#define RST_EXT_PHY_WIDTH 1
++#define RST_XGRX_LBN 24
++#define RST_XGRX_WIDTH 1
++#define RST_XGTX_LBN 23
++#define RST_XGTX_WIDTH 1
++#define RST_EM_LBN 22
++#define RST_EM_WIDTH 1
++#define INT_RST_DUR_LBN 4
++#define INT_RST_DUR_WIDTH 3
++#define EXT_PHY_RST_DUR_LBN 1
++#define EXT_PHY_RST_DUR_WIDTH 3
++#define SWRST_LBN 0
++#define SWRST_WIDTH 1
++#define INCLUDE_IN_RESET 0
++#define EXCLUDE_FROM_RESET 1
++
++/* Fatal interrupt register */
++#define FATAL_INTR_REG_KER 0x0230
++#define PCI_BUSERR_INT_KER_EN_LBN 43
++#define PCI_BUSERR_INT_KER_EN_WIDTH 1
++#define SRAM_OOB_INT_KER_EN_LBN 42
++#define SRAM_OOB_INT_KER_EN_WIDTH 1
++#define BUFID_OOB_INT_KER_EN_LBN 41
++#define BUFID_OOB_INT_KER_EN_WIDTH 1
++#define MEM_PERR_INT_KER_EN_LBN 40
++#define MEM_PERR_INT_KER_EN_WIDTH 1
++#define RBUF_OWN_INT_KER_EN_LBN 39
++#define RBUF_OWN_INT_KER_EN_WIDTH 1
++#define TBUF_OWN_INT_KER_EN_LBN 38
++#define TBUF_OWN_INT_KER_EN_WIDTH 1
++#define RDESCQ_OWN_INT_KER_EN_LBN 37
++#define RDESCQ_OWN_INT_KER_EN_WIDTH 1
++#define TDESCQ_OWN_INT_KER_EN_LBN 36
++#define TDESCQ_OWN_INT_KER_EN_WIDTH 1
++#define EVQ_OWN_INT_KER_EN_LBN 35
++#define EVQ_OWN_INT_KER_EN_WIDTH 1
++#define EVFF_OFLO_INT_KER_EN_LBN 34
++#define EVFF_OFLO_INT_KER_EN_WIDTH 1
++#define ILL_ADR_INT_KER_EN_LBN 33
++#define ILL_ADR_INT_KER_EN_WIDTH 1
++#define SRM_PERR_INT_KER_EN_LBN 32
++#define SRM_PERR_INT_KER_EN_WIDTH 1
++#define MEM_PERR_INT_KER_LBN 8
++#define MEM_PERR_INT_KER_WIDTH 1
++#define INT_KER_ERROR_LBN 0
++#define INT_KER_ERROR_WIDTH 12
++
++#define DP_CTRL_REG 0x250
++#define FLS_EVQ_ID_LBN 0
++#define FLS_EVQ_ID_WIDTH 11
++
++#define MEM_STAT_REG_KER 0x260
++
++/* Debug probe register */
++#define DEBUG_REG_KER 0x0270
++#define DEBUG_BLK_SEL2_LBN 47
++#define DEBUG_BLK_SEL2_WIDTH 3
++#define DEBUG_BLK_SEL1_LBN 44
++#define DEBUG_BLK_SEL1_WIDTH 3
++#define DEBUG_BLK_SEL0_LBN 41
++#define DEBUG_BLK_SEL0_WIDTH 3
++#define DEBUG_BLK_SEL_MISC 7
++#define DEBUG_BLK_SEL_SERDES 6
++#define DEBUG_BLK_SEL_EM 5
++#define DEBUG_BLK_SEL_SR 4
++#define DEBUG_BLK_SEL_EV 3
++#define DEBUG_BLK_SEL_RX 2
++#define DEBUG_BLK_SEL_TX 1
++#define DEBUG_BLK_SEL_BIU 0
++#define MISC_DEBUG_ADDR_LBN 36
++#define MISC_DEBUG_ADDR_WIDTH 5
++#define SERDES_DEBUG_ADDR_LBN 31
++#define SERDES_DEBUG_ADDR_WIDTH 5
++#define EM_DEBUG_ADDR_LBN 26
++#define EM_DEBUG_ADDR_WIDTH 5
++#define SR_DEBUG_ADDR_LBN 21
++#define SR_DEBUG_ADDR_WIDTH 5
++#define EV_DEBUG_ADDR_LBN 16
++#define EV_DEBUG_ADDR_WIDTH 5
++#define RX_DEBUG_ADDR_LBN 11
++#define RX_DEBUG_ADDR_WIDTH 5
++#define TX_DEBUG_ADDR_LBN 5
++#define TX_DEBUG_ADDR_WIDTH 5
++#define BIU_DEBUG_ADDR_LBN 1
++#define BIU_DEBUG_ADDR_WIDTH 5
++#define DEBUG_DIS_LBN 0
++#define DEBUG_DIS_WIDTH 1
++
++/* Scratch register 0 */
++#define DRIVER_REG0_KER 0x0280
++#define DRIVER_DW0_LBN 0
++#define DRIVER_DW0_WIDTH 32
++
++/* Scratch register 1 */
++#define DRIVER_REG1_KER 0x0290
++#define DRIVER_DW1_LBN 0
++#define DRIVER_DW1_WIDTH 32
++
++/* Scratch register 2 */
++#define DRIVER_REG2_KER 0x02A0
++#define DRIVER_DW2_LBN 0
++#define DRIVER_DW2_WIDTH 32
++
++/* Scratch register 3 */
++#define DRIVER_REG3_KER 0x02B0
++#define DRIVER_DW3_LBN 0
++#define DRIVER_DW3_WIDTH 32
++
++/* Scratch register 4 */
++#define DRIVER_REG4_KER 0x02C0
++#define DRIVER_DW3_LBN 0
++#define DRIVER_DW3_WIDTH 32
++
++/* Scratch register 5 */
++#define DRIVER_REG5_KER 0x02D0
++#define DRIVER_DW3_LBN 0
++#define DRIVER_DW3_WIDTH 32
++
++/* Scratch register 6 */
++#define DRIVER_REG6_KER 0x02E0
++#define DRIVER_DW3_LBN 0
++#define DRIVER_DW3_WIDTH 32
++
++/* Scratch register 7 */
++#define DRIVER_REG7_KER 0x02F0
++#define DRIVER_DW3_LBN 0
++#define DRIVER_DW3_WIDTH 32
++
++/* FPGA build version */
++#define ALTERA_BUILD_REG_KER 0x0300
++#define VER_MAJOR_LBN 24
++#define VER_MAJOR_WIDTH 8
++#define VER_MINOR_LBN 16
++#define VER_MINOR_WIDTH 8
++#define VER_BUILD_LBN 0
++#define VER_BUILD_WIDTH 16
++#define VER_ALL_LBN 0
++#define VER_ALL_WIDTH 32
++
++/* Spare EEPROM bits register (flash 0x390) */
++#define SPARE_REG_KER 0x310
++#define MEM_PERR_EN_LBN 64
++#define MEM_PERR_EN_WIDTH 38
++#define MEM_PERR_EN_TX_DATA_LBN 72
++#define MEM_PERR_EN_TX_DATA_WIDTH 2
++#define SPARE_EE_BITS_LBN 1
++#define SPARE_EE_BITS_WIDTH 31
++#define PCIE_LEGACY_ENDPOINT_LBN 0
++#define PCIE_LEGACY_ENDPOINT_WIDTH 1
++
++/* Page mapped view of bottom 1024 EVQ RPTRS */
++#define EVQ_RPTR_REG_P0       0x400
++/* Bit definitions are as for the densely mapped
++ * RPTR registers. */
++
++/* Timer table for kernel access */
++#define TIMER_CMD_REG_KER 0x420
++#define TIMER_MODE_LBN 12
++#define TIMER_MODE_WIDTH 2
++#define TIMER_MODE_DIS 0
++#define TIMER_MODE_INT_HLDOFF 2
++#define TIMER_VAL_LBN 0
++#define TIMER_VAL_WIDTH 12
++
++/* Driver generated event register */
++#define DRV_EV_REG_KER 0x440
++#define DRV_EV_QID_LBN 64
++#define DRV_EV_QID_WIDTH 12
++#define DRV_EV_DATA_LBN 0
++#define DRV_EV_DATA_WIDTH 64
++
++/* Event Queue control register */
++#define EVQ_CTL_REG_KER 0x450
++#define EVQ_FIFO_NOTAF_TH_LBN 0
++#define EVQ_FIFO_NOTAF_TH_WIDTH 6
++#define EVQ_FIFO_AF_TH_LBN 8
++#define EVQ_FIFO_AF_TH_WIDTH 6
++
++/* Buffer table configuration register */
++#define BUF_TBL_CFG_REG_KER 0x600
++#define BUF_TBL_MODE_LBN 3
++#define BUF_TBL_MODE_WIDTH 1
++#define BUF_TBL_MODE_HALF 0
++#define BUF_TBL_MODE_FULL 1
++
++/* SRAM receive descriptor cache configuration register */
++#define SRM_RX_DC_CFG_REG_KER 0x610
++#define SRM_RX_DC_BASE_ADR_LBN 0
++#define SRM_RX_DC_BASE_ADR_WIDTH 21
++
++/* SRAM transmit descriptor cache configuration register */
++#define SRM_TX_DC_CFG_REG_KER 0x620
++#define SRM_TX_DC_BASE_ADR_LBN 0
++#define SRM_TX_DC_BASE_ADR_WIDTH 21
++
++/* SRAM configuration register */
++#define SRM_CFG_REG_KER 0x630
++#define SRAM_OOB_ADR_INTEN_LBN 5
++#define SRAM_OOB_ADR_INTEN_WIDTH 1
++#define SRAM_OOB_BUF_INTEN_LBN 4
++#define SRAM_OOB_BUF_INTEN_WIDTH 1
++#define SRAM_OOB_BT_INIT_EN_LBN 3
++#define SRAM_OOB_BT_INIT_EN_WIDTH 1
++#define SRM_NUM_BANK_LBN 2
++#define SRM_NUM_BANK_WIDTH 1
++#define SRM_BANK_SIZE_LBN 0
++#define SRM_BANK_SIZE_WIDTH 2
++#define SRM_NUM_BANKS_AND_BANK_SIZE_LBN 0
++#define SRM_NUM_BANKS_AND_BANK_SIZE_WIDTH 3
++#define SRM_NB_BSZ_1BANKS_2M 0
++#define SRM_NB_BSZ_1BANKS_4M 1
++#define SRM_NB_BSZ_1BANKS_8M 2
++#define SRM_NB_BSZ_DEFAULT 3 /* char driver will set the default */
++#define SRM_NB_BSZ_2BANKS_4M 4
++#define SRM_NB_BSZ_2BANKS_8M 5
++#define SRM_NB_BSZ_2BANKS_16M 6
++#define SRM_NB_BSZ_RESERVED 7
++
++/* Special buffer table update register */
++#define BUF_TBL_UPD_REG_KER 0x0650
++#define BUF_UPD_CMD_LBN 63
++#define BUF_UPD_CMD_WIDTH 1
++#define BUF_CLR_CMD_LBN 62
++#define BUF_CLR_CMD_WIDTH 1
++#define BUF_CLR_END_ID_LBN 32
++#define BUF_CLR_END_ID_WIDTH 20
++#define BUF_CLR_START_ID_LBN 0
++#define BUF_CLR_START_ID_WIDTH 20
++
++/* Receive configuration register */
++#define RX_CFG_REG_KER 0x800
++
++/* B0 */
++#define RX_TOEP_TCP_SUPPRESS_B0_LBN 48
++#define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1
++#define RX_INGR_EN_B0_LBN 47
++#define RX_INGR_EN_B0_WIDTH 1
++#define RX_TOEP_IPV4_B0_LBN 46
++#define RX_TOEP_IPV4_B0_WIDTH 1
++#define RX_HASH_ALG_B0_LBN 45
++#define RX_HASH_ALG_B0_WIDTH 1
++#define RX_HASH_INSERT_HDR_B0_LBN 44
++#define RX_HASH_INSERT_HDR_B0_WIDTH 1
++#define RX_DESC_PUSH_EN_B0_LBN 43
++#define RX_DESC_PUSH_EN_B0_WIDTH 1
++#define RX_RDW_PATCH_EN_LBN 42 /* Non head of line blocking */
++#define RX_RDW_PATCH_EN_WIDTH 1
++#define RX_PCI_BURST_SIZE_B0_LBN 39
++#define RX_PCI_BURST_SIZE_B0_WIDTH 3
++#define RX_OWNERR_CTL_B0_LBN 38
++#define RX_OWNERR_CTL_B0_WIDTH 1
++#define RX_XON_TX_TH_B0_LBN 33
++#define RX_XON_TX_TH_B0_WIDTH 5
++#define RX_XOFF_TX_TH_B0_LBN 28
++#define RX_XOFF_TX_TH_B0_WIDTH 5
++#define RX_USR_BUF_SIZE_B0_LBN 19
++#define RX_USR_BUF_SIZE_B0_WIDTH 9
++#define RX_XON_MAC_TH_B0_LBN 10
++#define RX_XON_MAC_TH_B0_WIDTH 9
++#define RX_XOFF_MAC_TH_B0_LBN 1
++#define RX_XOFF_MAC_TH_B0_WIDTH 9
++#define RX_XOFF_MAC_EN_B0_LBN 0
++#define RX_XOFF_MAC_EN_B0_WIDTH 1
++
++/* A1 */
++#define RX_DESC_PUSH_EN_A1_LBN 35
++#define RX_DESC_PUSH_EN_A1_WIDTH 1
++#define RX_PCI_BURST_SIZE_A1_LBN 31
++#define RX_PCI_BURST_SIZE_A1_WIDTH 3
++#define RX_OWNERR_CTL_A1_LBN 30
++#define RX_OWNERR_CTL_A1_WIDTH 1
++#define RX_XON_TX_TH_A1_LBN 25
++#define RX_XON_TX_TH_A1_WIDTH 5
++#define RX_XOFF_TX_TH_A1_LBN 20
++#define RX_XOFF_TX_TH_A1_WIDTH 5
++#define RX_USR_BUF_SIZE_A1_LBN 11
++#define RX_USR_BUF_SIZE_A1_WIDTH 9
++#define RX_XON_MAC_TH_A1_LBN 6
++#define RX_XON_MAC_TH_A1_WIDTH 5
++#define RX_XOFF_MAC_TH_A1_LBN 1
++#define RX_XOFF_MAC_TH_A1_WIDTH 5
++#define RX_XOFF_MAC_EN_A1_LBN 0
++#define RX_XOFF_MAC_EN_A1_WIDTH 1
++
++/* Receive filter control register */
++#define RX_FILTER_CTL_REG 0x810
++#define SCATTER_ENBL_NO_MATCH_Q_B0_LBN 40
++#define SCATTER_ENBL_NO_MATCH_Q_B0_WIDTH 1
++#define UDP_FULL_SRCH_LIMIT_LBN 32
++#define UDP_FULL_SRCH_LIMIT_WIDTH 8
++#define NUM_KER_LBN 24
++#define NUM_KER_WIDTH 2
++#define UDP_WILD_SRCH_LIMIT_LBN 16
++#define UDP_WILD_SRCH_LIMIT_WIDTH 8
++#define TCP_WILD_SRCH_LIMIT_LBN 8
++#define TCP_WILD_SRCH_LIMIT_WIDTH 8
++#define TCP_FULL_SRCH_LIMIT_LBN 0
++#define TCP_FULL_SRCH_LIMIT_WIDTH 8
++
++/* RX queue flush register */
++#define RX_FLUSH_DESCQ_REG_KER 0x0820
++#define RX_FLUSH_DESCQ_CMD_LBN 24
++#define RX_FLUSH_DESCQ_CMD_WIDTH 1
++#define RX_FLUSH_DESCQ_LBN 0
++#define RX_FLUSH_DESCQ_WIDTH 12
++
++/* Receive descriptor update register */
++#define RX_DESC_UPD_REG_KER 0x0830
++#define RX_DESC_WPTR_LBN 96
++#define RX_DESC_WPTR_WIDTH 12
++#define RX_DESC_UPD_REG_KER_DWORD (RX_DESC_UPD_REG_KER + 12)
++#define RX_DESC_WPTR_DWORD_LBN 0
++#define RX_DESC_WPTR_DWORD_WIDTH 12
++
++/* Receive descriptor cache configuration register */
++#define RX_DC_CFG_REG_KER 0x840
++#define RX_DC_SIZE_LBN 0
++#define RX_DC_SIZE_WIDTH 2
++
++#define RX_DC_PF_WM_REG_KER 0x850
++#define RX_DC_PF_LWM_LBN 0
++#define RX_DC_PF_LWM_WIDTH 6
++
++/* RX no descriptor drop counter */
++#define RX_NODESC_DROP_REG_KER 0x880
++#define RX_NODESC_DROP_CNT_LBN 0
++#define RX_NODESC_DROP_CNT_WIDTH 16
++
++/* RX black magic register */
++#define RX_SELF_RST_REG_KER 0x890
++#define RX_ISCSI_DIS_LBN 17
++#define RX_ISCSI_DIS_WIDTH 1
++#define RX_PREFETCH_TIMEOUT_EN_LBN 10
++#define RX_PREFETCH_TIMEOUT_EN_WIDTH 1
++#define RX_NODESC_WAIT_DIS_LBN 9
++#define RX_NODESC_WAIT_DIS_WIDTH 1
++#define RX_RECOVERY_EN_LBN 8
++#define RX_RECOVERY_EN_WIDTH 1
++#define RX_SHUTDOWN_REASON_LBN        0
++#define RX_SHUTDOWN_REASON_WIDTH (3)
++
++/* TX queue flush register */
++#define TX_FLUSH_DESCQ_REG_KER 0x0a00
++#define TX_FLUSH_DESCQ_CMD_LBN 12
++#define TX_FLUSH_DESCQ_CMD_WIDTH 1
++#define TX_FLUSH_DESCQ_LBN 0
++#define TX_FLUSH_DESCQ_WIDTH 12
++
++/* Transmit descriptor update register */
++#define TX_DESC_UPD_REG_KER 0x0a10
++#define TX_DESC_WPTR_LBN 96
++#define TX_DESC_WPTR_WIDTH 12
++#define TX_DESC_UPD_REG_KER_DWORD (TX_DESC_UPD_REG_KER + 12)
++#define TX_DESC_WPTR_DWORD_LBN 0
++#define TX_DESC_WPTR_DWORD_WIDTH 12
++
++/* Transmit descriptor cache configuration register */
++#define TX_DC_CFG_REG_KER 0xa20
++#define TX_DC_SIZE_LBN 0
++#define TX_DC_SIZE_WIDTH 2
++
++/* Transmit checksum configuration register (A0/A1 only) */
++#define TX_CHKSM_CFG_REG_KER_A1 0xa30
++
++/* Transmit configuration register */
++#define TX_CFG_REG_KER 0xa50
++#define TX_NO_EOP_DISC_EN_LBN 5
++#define TX_NO_EOP_DISC_EN_WIDTH 1
++
++/* Transmit configuration register 2 */
++#define TX_CFG2_REG_KER 0xa80
++#define TX_CSR_PUSH_EN_LBN 89
++#define TX_CSR_PUSH_EN_WIDTH 1
++#define TX_RX_SPACER_LBN 64
++#define TX_RX_SPACER_WIDTH 8
++#define TX_SW_EV_EN_LBN 59
++#define TX_SW_EV_EN_WIDTH 1
++#define TX_RX_SPACER_EN_LBN 57
++#define TX_RX_SPACER_EN_WIDTH 1
++#define TX_PREF_WD_TMR_LBN 22
++#define TX_PREF_WD_TMR_WIDTH 22
++#define TX_PREF_THRESHOLD_LBN 19
++#define TX_PREF_THRESHOLD_WIDTH 2
++#define TX_ONE_PKT_PER_Q_LBN 18
++#define TX_ONE_PKT_PER_Q_WIDTH 1
++#define TX_DIS_NON_IP_EV_LBN 17
++#define TX_DIS_NON_IP_EV_WIDTH 1
++#define TX_DMA_SPACER_LBN 8
++#define TX_DMA_SPACER_WIDTH 8
++#define TX_FLUSH_MIN_LEN_EN_B0_LBN 7
++#define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1
++#define TX_TCP_DIS_A1_LBN 7
++#define TX_TCP_DIS_A1_WIDTH 1
++#define TX_IP_DIS_A1_LBN 6
++#define TX_IP_DIS_A1_WIDTH 1
++#define TX_MAX_CPL_LBN 2
++#define TX_MAX_CPL_WIDTH 2
++#define TX_MAX_PREF_LBN 0
++#define TX_MAX_PREF_WIDTH 2
++
++/* Transmit VLAN filter control register */
++#define TX_VLAN_REG 0xae0
++
++/* PHY management transmit data register */
++#define MD_TXD_REG_KER 0xc00
++#define MD_TXD_LBN 0
++#define MD_TXD_WIDTH 16
++
++/* PHY management receive data register */
++#define MD_RXD_REG_KER 0xc10
++#define MD_RXD_LBN 0
++#define MD_RXD_WIDTH 16
++
++/* PHY management configuration & status register */
++#define MD_CS_REG_KER 0xc20
++#define MD_PT_LBN 7
++#define MD_PT_WIDTH 3
++#define MD_PL_LBN 6
++#define MD_PL_WIDTH 1
++#define MD_INT_CLR_LBN 5
++#define MD_INT_CLR_WIDTH 1
++#define MD_GC_LBN 4
++#define MD_GC_WIDTH 1
++#define MD_PRSP_LBN 3
++#define MD_PRSP_WIDTH 1
++#define MD_RIC_LBN 2
++#define MD_RIC_WIDTH 1
++#define MD_RDC_LBN 1
++#define MD_RDC_WIDTH 1
++#define MD_WRC_LBN 0
++#define MD_WRC_WIDTH 1
++
++/* PHY management PHY address register */
++#define MD_PHY_ADR_REG_KER 0xc30
++#define MD_PHY_ADR_LBN 0
++#define MD_PHY_ADR_WIDTH 16
++
++/* PHY management ID register */
++#define MD_ID_REG_KER 0xc40
++#define MD_PRT_ADR_LBN 11
++#define MD_PRT_ADR_WIDTH 5
++#define MD_DEV_ADR_LBN 6
++#define MD_DEV_ADR_WIDTH 5
++/* Used for writing both at once */
++#define MD_PRT_DEV_ADR_LBN 6
++#define MD_PRT_DEV_ADR_WIDTH 10
++
++/* PHY management status & mask register (DWORD read only) */
++#define MD_STAT_REG_KER 0xc50
++#define MD_PINT_LBN 4
++#define MD_PINT_WIDTH 1
++#define MD_DONE_LBN 3
++#define MD_DONE_WIDTH 1
++#define MD_BSERR_LBN 2
++#define MD_BSERR_WIDTH 1
++#define MD_LNFL_LBN 1
++#define MD_LNFL_WIDTH 1
++#define MD_BSY_LBN 0
++#define MD_BSY_WIDTH 1
++
++/* Port 0 and 1 MAC stats registers */
++#define MAC0_STAT_DMA_REG_KER 0xc60
++#define MAC1_STAT_DMA_REG_KER 0xc70
++#define MAC_STAT_DMA_CMD_LBN 48
++#define MAC_STAT_DMA_CMD_WIDTH 1
++#define MAC_STAT_DMA_REGION_LBN 46
++#define MAC_STAT_DMA_REGION_WIDTH 2
++#define MAC_STAT_DMA_ADR_LBN 0
++#define MAC_STAT_DMA_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
++
++/* Port 0 and 1 MAC control registers */
++#define MAC0_CTRL_REG_KER 0xc80
++#define MAC1_CTRL_REG_KER 0xc90
++#define MAC_XOFF_VAL_LBN 16
++#define MAC_XOFF_VAL_WIDTH 16
++#define TXFIFO_DRAIN_EN_B0_LBN 7
++#define TXFIFO_DRAIN_EN_B0_WIDTH 1
++#define MAC_XG_DISTXCRC_LBN 5
++#define MAC_XG_DISTXCRC_WIDTH 1
++#define MAC_BCAD_ACPT_LBN 4
++#define MAC_BCAD_ACPT_WIDTH 1
++#define MAC_UC_PROM_LBN 3
++#define MAC_UC_PROM_WIDTH 1
++#define MAC_LINK_STATUS_LBN 2
++#define MAC_LINK_STATUS_WIDTH 1
++#define MAC_SPEED_LBN 0
++#define MAC_SPEED_WIDTH 2
++
++/* External interrupt control (replaces MAC1_CTRL in B0) */
++#define GEN_MODE_REG_KER 0xc90
++#define XFP_PHY_INT_POL_SEL_LBN 3
++#define XFP_PHY_INT_POL_SEL_WIDTH 1
++#define XG_PHY_INT_POL_SEL_LBN 2
++#define XG_PHY_INT_POL_SEL_WIDTH 1
++#define XFP_PHY_INT_MASK_LBN 1
++#define XFP_PHY_INT_MASK_WIDTH 1
++#define XG_PHY_INT_MASK_LBN 0
++#define XG_PHY_INT_MASK_WIDTH 1
++
++
++/* 10G XAUI XGXS default values */
++#define XX_TXDRV_DEQ_DEFAULT 0xe /* deq=.6 */
++#define XX_TXDRV_DTX_DEFAULT 0x5 /* 1.25 */
++#define XX_SD_CTL_DRV_DEFAULT 0  /* 20mA */
++
++/* Multicast address hash table */
++#define MAC_MCAST_HASH_REG0_KER 0xca0
++#define MAC_MCAST_HASH_REG1_KER 0xcb0
++
++/* MAC test register. */
++#define MAC_TEST_REG_KER 0xcc0
++#define MAC_PTLOOP_EN_LBN 0
++#define MAC_PTLOOP_EN_WIDTH 1
++
++/* GMAC registers */
++#define FALCON_GMAC_REGBANK 0xe00
++#define FALCON_GMAC_REGBANK_SIZE 0x200
++#define FALCON_GMAC_REG_SIZE 0x10
++
++/* Source MAC filter control register */
++#define TX_SRC_MAC_CTRL_REG 0x1100
++
++/* XMAC registers */
++#define FALCON_XMAC_REGBANK 0x1200
++#define FALCON_XMAC_REGBANK_SIZE 0x200
++#define FALCON_XMAC_REG_SIZE 0x10
++
++/* XGMAC address register low */
++#define XM_ADR_LO_REG_MAC 0x00
++#define XM_ADR_3_LBN 24
++#define XM_ADR_3_WIDTH 8
++#define XM_ADR_2_LBN 16
++#define XM_ADR_2_WIDTH 8
++#define XM_ADR_1_LBN 8
++#define XM_ADR_1_WIDTH 8
++#define XM_ADR_0_LBN 0
++#define XM_ADR_0_WIDTH 8
++
++/* XGMAC address register high */
++#define XM_ADR_HI_REG_MAC 0x01
++#define XM_ADR_5_LBN 8
++#define XM_ADR_5_WIDTH 8
++#define XM_ADR_4_LBN 0
++#define XM_ADR_4_WIDTH 8
++
++/* XGMAC global configuration */
++#define XM_GLB_CFG_REG_MAC 0x02
++#define XM_LINE_LB_DEEP_RSVD_LBN 28
++#define XM_LINE_LB_DEEP_RSVD_WIDTH 1
++#define XM_RMTFLT_GEN_LBN 17
++#define XM_RMTFLT_GEN_WIDTH 1
++#define XM_DEBUG_MODE_LBN 16
++#define XM_DEBUG_MODE_WIDTH 1
++#define XM_RX_STAT_EN_LBN 11
++#define XM_RX_STAT_EN_WIDTH 1
++#define XM_TX_STAT_EN_LBN 10
++#define XM_TX_STAT_EN_WIDTH 1
++#define XM_RX_JUMBO_MODE_LBN 6
++#define XM_RX_JUMBO_MODE_WIDTH 1
++#define XM_WAN_MODE_LBN 5
++#define XM_WAN_MODE_WIDTH 1
++#define XM_AUTOCLR_MODE_LBN 4
++#define XM_AUTOCLR_MODE_WIDTH 1
++#define XM_INTCLR_MODE_LBN 3
++#define XM_INTCLR_MODE_WIDTH 1
++#define XM_CORE_RST_LBN 0
++#define XM_CORE_RST_WIDTH 1
++
++/* XGMAC transmit configuration */
++#define XM_TX_CFG_REG_MAC 0x03
++#define XM_TX_PROG_LBN 24
++#define XM_TX_PROG_WIDTH 1
++#define XM_IPG_LBN 16
++#define XM_IPG_WIDTH 4
++#define XM_FCNTL_LBN 10
++#define XM_FCNTL_WIDTH 1
++#define XM_TXCRC_LBN 8
++#define XM_TXCRC_WIDTH 1
++#define XM_EDRC_LBN 6
++#define XM_EDRC_WIDTH 1
++#define XM_AUTO_PAD_LBN 5
++#define XM_AUTO_PAD_WIDTH 1
++#define XM_TX_PRMBL_LBN 2
++#define XM_TX_PRMBL_WIDTH 1
++#define XM_TXEN_LBN 1
++#define XM_TXEN_WIDTH 1
++#define XM_TX_RST_LBN 0
++#define XM_TX_RST_WIDTH 1
++
++/* XGMAC receive configuration */
++#define XM_RX_CFG_REG_MAC 0x04
++#define XM_PASS_LENERR_LBN 26
++#define XM_PASS_LENERR_WIDTH 1
++#define XM_PASS_CRC_ERR_LBN 25
++#define XM_PASS_CRC_ERR_WIDTH 1
++#define XM_PASS_PRMBLE_ERR_LBN 24
++#define XM_PASS_PRMBLE_ERR_WIDTH 1
++#define XM_ACPT_ALL_MCAST_LBN 11
++#define XM_ACPT_ALL_MCAST_WIDTH 1
++#define XM_ACPT_ALL_UCAST_LBN 9
++#define XM_ACPT_ALL_UCAST_WIDTH 1
++#define XM_AUTO_DEPAD_LBN 8
++#define XM_AUTO_DEPAD_WIDTH 1
++#define XM_RXCRC_LBN 3
++#define XM_RXCRC_WIDTH 1
++#define XM_RX_PRMBL_LBN 2
++#define XM_RX_PRMBL_WIDTH 1
++#define XM_RXEN_LBN 1
++#define XM_RXEN_WIDTH 1
++#define XM_RX_RST_LBN 0
++#define XM_RX_RST_WIDTH 1
++
++/* XGMAC flow control register */
++#define XM_FC_REG_MAC 0x7
++#define XM_PAUSE_TIME_LBN 16
++#define XM_PAUSE_TIME_WIDTH 16
++#define XM_DIS_FCNTL_LBN 0
++#define XM_DIS_FCNTL_WIDTH 1
++
++/* XGMAC pause time count register */
++#define XM_PAUSE_TIME_REG_MAC 0x9
++#define XM_TX_PAUSE_CNT_LBN 16
++#define XM_TX_PAUSE_CNT_WIDTH 16
++#define XM_RX_PAUSE_CNT_LBN 0
++#define XM_RX_PAUSE_CNT_WIDTH 16
++
++/* XGMAC transmit parameter register */
++#define XM_TX_PARAM_REG_MAC 0x0d
++#define XM_TX_JUMBO_MODE_LBN 31
++#define XM_TX_JUMBO_MODE_WIDTH 1
++#define XM_MAX_TX_FRM_SIZE_LBN 16
++#define XM_MAX_TX_FRM_SIZE_WIDTH 14
++#define XM_PAD_CHAR_LBN 0
++#define XM_PAD_CHAR_WIDTH 8
++
++/* XGMAC receive parameter register */
++#define XM_RX_PARAM_REG_MAC 0x0e
++#define XM_MAX_RX_FRM_SIZE_LBN 0
++#define XM_MAX_RX_FRM_SIZE_WIDTH 14
++
++/* XGXS/XAUI powerdown/reset register */
++#define XX_PWR_RST_REG_MAC 0x10
++
++#define XX_PWRDND_EN_LBN 15
++#define XX_PWRDND_EN_WIDTH 1
++#define XX_PWRDNC_EN_LBN 14
++#define XX_PWRDNC_EN_WIDTH 1
++#define XX_PWRDNB_EN_LBN 13
++#define XX_PWRDNB_EN_WIDTH 1
++#define XX_PWRDNA_EN_LBN 12
++#define XX_PWRDNA_EN_WIDTH 1
++#define XX_RSTPLLCD_EN_LBN 9
++#define XX_RSTPLLCD_EN_WIDTH 1
++#define XX_RSTPLLAB_EN_LBN 8
++#define XX_RSTPLLAB_EN_WIDTH 1
++#define XX_RESETD_EN_LBN 7
++#define XX_RESETD_EN_WIDTH 1
++#define XX_RESETC_EN_LBN 6
++#define XX_RESETC_EN_WIDTH 1
++#define XX_RESETB_EN_LBN 5
++#define XX_RESETB_EN_WIDTH 1
++#define XX_RESETA_EN_LBN 4
++#define XX_RESETA_EN_WIDTH 1
++#define XX_RSTXGXSRX_EN_LBN 2
++#define XX_RSTXGXSRX_EN_WIDTH 1
++#define XX_RSTXGXSTX_EN_LBN 1
++#define XX_RSTXGXSTX_EN_WIDTH 1
++#define XX_RST_XX_EN_LBN 0
++#define XX_RST_XX_EN_WIDTH 1
++
++/* XGXS/XAUI powerdown/reset control register */
++#define XX_SD_CTL_REG_MAC 0x11
++#define XX_TERMADJ1_LBN 17
++#define XX_TERMADJ1_WIDTH 1
++#define XX_TERMADJ0_LBN 16
++#define XX_TERMADJ0_WIDTH 1
++#define XX_HIDRVD_LBN 15
++#define XX_HIDRVD_WIDTH 1
++#define XX_LODRVD_LBN 14
++#define XX_LODRVD_WIDTH 1
++#define XX_HIDRVC_LBN 13
++#define XX_HIDRVC_WIDTH 1
++#define XX_LODRVC_LBN 12
++#define XX_LODRVC_WIDTH 1
++#define XX_HIDRVB_LBN 11
++#define XX_HIDRVB_WIDTH 1
++#define XX_LODRVB_LBN 10
++#define XX_LODRVB_WIDTH 1
++#define XX_HIDRVA_LBN 9
++#define XX_HIDRVA_WIDTH 1
++#define XX_LODRVA_LBN 8
++#define XX_LODRVA_WIDTH 1
++#define XX_LPBKD_LBN 3
++#define XX_LPBKD_WIDTH 1
++#define XX_LPBKC_LBN 2
++#define XX_LPBKC_WIDTH 1
++#define XX_LPBKB_LBN 1
++#define XX_LPBKB_WIDTH 1
++#define XX_LPBKA_LBN 0
++#define XX_LPBKA_WIDTH 1
++
++#define XX_TXDRV_CTL_REG_MAC 0x12
++#define XX_DEQD_LBN 28
++#define XX_DEQD_WIDTH 4
++#define XX_DEQC_LBN 24
++#define XX_DEQC_WIDTH 4
++#define XX_DEQB_LBN 20
++#define XX_DEQB_WIDTH 4
++#define XX_DEQA_LBN 16
++#define XX_DEQA_WIDTH 4
++#define XX_DTXD_LBN 12
++#define XX_DTXD_WIDTH 4
++#define XX_DTXC_LBN 8
++#define XX_DTXC_WIDTH 4
++#define XX_DTXB_LBN 4
++#define XX_DTXB_WIDTH 4
++#define XX_DTXA_LBN 0
++#define XX_DTXA_WIDTH 4
++
++/* XAUI XGXS core status register */
++#define XX_FORCE_SIG_LBN 24
++#define XX_FORCE_SIG_WIDTH 8
++#define XX_FORCE_SIG_DECODE_FORCED 0xff
++#define XX_XGXS_LB_EN_LBN 23
++#define XX_XGXS_LB_EN_WIDTH 1
++#define XX_XGMII_LB_EN_LBN 22
++#define XX_XGMII_LB_EN_WIDTH 1
++#define XX_CORE_STAT_REG_MAC 0x16
++#define XX_ALIGN_DONE_LBN 20
++#define XX_ALIGN_DONE_WIDTH 1
++#define XX_SYNC_STAT_LBN 16
++#define XX_SYNC_STAT_WIDTH 4
++#define XX_SYNC_STAT_DECODE_SYNCED 0xf
++#define XX_COMMA_DET_LBN 12
++#define XX_COMMA_DET_WIDTH 4
++#define XX_COMMA_DET_DECODE_DETECTED 0xf
++#define XX_COMMA_DET_RESET 0xf
++#define XX_CHARERR_LBN 4
++#define XX_CHARERR_WIDTH 4
++#define XX_CHARERR_RESET 0xf
++#define XX_DISPERR_LBN 0
++#define XX_DISPERR_WIDTH 4
++#define XX_DISPERR_RESET 0xf
++
++/* Receive filter table */
++#define RX_FILTER_TBL0 0xF00000
++
++/* Receive descriptor pointer table */
++#define RX_DESC_PTR_TBL_KER_A1 0x11800
++#define RX_DESC_PTR_TBL_KER_B0 0xF40000
++#define RX_DESC_PTR_TBL_KER_P0 0x900
++#define RX_ISCSI_DDIG_EN_LBN 88
++#define RX_ISCSI_DDIG_EN_WIDTH 1
++#define RX_ISCSI_HDIG_EN_LBN 87
++#define RX_ISCSI_HDIG_EN_WIDTH 1
++#define RX_DESC_PREF_ACT_LBN 86
++#define RX_DESC_PREF_ACT_WIDTH 1
++#define RX_DC_HW_RPTR_LBN 80
++#define RX_DC_HW_RPTR_WIDTH 6
++#define RX_DESCQ_HW_RPTR_LBN 68
++#define RX_DESCQ_HW_RPTR_WIDTH 12
++#define RX_DESCQ_SW_WPTR_LBN 56
++#define RX_DESCQ_SW_WPTR_WIDTH 12
++#define RX_DESCQ_BUF_BASE_ID_LBN 36
++#define RX_DESCQ_BUF_BASE_ID_WIDTH 20
++#define RX_DESCQ_EVQ_ID_LBN 24
++#define RX_DESCQ_EVQ_ID_WIDTH 12
++#define RX_DESCQ_OWNER_ID_LBN 10
++#define RX_DESCQ_OWNER_ID_WIDTH 14
++#define RX_DESCQ_LABEL_LBN 5
++#define RX_DESCQ_LABEL_WIDTH 5
++#define RX_DESCQ_SIZE_LBN 3
++#define RX_DESCQ_SIZE_WIDTH 2
++#define RX_DESCQ_SIZE_4K 3
++#define RX_DESCQ_SIZE_2K 2
++#define RX_DESCQ_SIZE_1K 1
++#define RX_DESCQ_SIZE_512 0
++#define RX_DESCQ_TYPE_LBN 2
++#define RX_DESCQ_TYPE_WIDTH 1
++#define RX_DESCQ_JUMBO_LBN 1
++#define RX_DESCQ_JUMBO_WIDTH 1
++#define RX_DESCQ_EN_LBN 0
++#define RX_DESCQ_EN_WIDTH 1
++
++/* Transmit descriptor pointer table */
++#define TX_DESC_PTR_TBL_KER_A1 0x11900
++#define TX_DESC_PTR_TBL_KER_B0 0xF50000
++#define TX_DESC_PTR_TBL_KER_P0 0xa40
++#define TX_NON_IP_DROP_DIS_B0_LBN 91
++#define TX_NON_IP_DROP_DIS_B0_WIDTH 1
++#define TX_IP_CHKSM_DIS_B0_LBN 90
++#define TX_IP_CHKSM_DIS_B0_WIDTH 1
++#define TX_TCP_CHKSM_DIS_B0_LBN 89
++#define TX_TCP_CHKSM_DIS_B0_WIDTH 1
++#define TX_DESCQ_EN_LBN 88
++#define TX_DESCQ_EN_WIDTH 1
++#define TX_ISCSI_DDIG_EN_LBN 87
++#define TX_ISCSI_DDIG_EN_WIDTH 1
++#define TX_ISCSI_HDIG_EN_LBN 86
++#define TX_ISCSI_HDIG_EN_WIDTH 1
++#define TX_DC_HW_RPTR_LBN 80
++#define TX_DC_HW_RPTR_WIDTH 6
++#define TX_DESCQ_HW_RPTR_LBN 68
++#define TX_DESCQ_HW_RPTR_WIDTH 12
++#define TX_DESCQ_SW_WPTR_LBN 56
++#define TX_DESCQ_SW_WPTR_WIDTH 12
++#define TX_DESCQ_BUF_BASE_ID_LBN 36
++#define TX_DESCQ_BUF_BASE_ID_WIDTH 20
++#define TX_DESCQ_EVQ_ID_LBN 24
++#define TX_DESCQ_EVQ_ID_WIDTH 12
++#define TX_DESCQ_OWNER_ID_LBN 10
++#define TX_DESCQ_OWNER_ID_WIDTH 14
++#define TX_DESCQ_LABEL_LBN 5
++#define TX_DESCQ_LABEL_WIDTH 5
++#define TX_DESCQ_SIZE_LBN 3
++#define TX_DESCQ_SIZE_WIDTH 2
++#define TX_DESCQ_SIZE_4K 3
++#define TX_DESCQ_SIZE_2K 2
++#define TX_DESCQ_SIZE_1K 1
++#define TX_DESCQ_SIZE_512 0
++#define TX_DESCQ_TYPE_LBN 1
++#define TX_DESCQ_TYPE_WIDTH 2
++#define TX_DESCQ_FLUSH_LBN 0
++#define TX_DESCQ_FLUSH_WIDTH 1
++
++/* Event queue pointer */
++#define EVQ_PTR_TBL_KER_A1 0x11a00
++#define EVQ_PTR_TBL_KER_B0 0xf60000
++#define EVQ_PTR_TBL_KER_P0 0x500
++#define EVQ_WKUP_OR_INT_EN_LBN 39
++#define EVQ_WKUP_OR_INT_EN_WIDTH 1
++#define EVQ_NXT_WPTR_LBN 24
++#define EVQ_NXT_WPTR_WIDTH 15
++#define EVQ_EN_LBN 23
++#define EVQ_EN_WIDTH 1
++#define EVQ_SIZE_LBN 20
++#define EVQ_SIZE_WIDTH 3
++#define EVQ_SIZE_32K 6
++#define EVQ_SIZE_16K 5
++#define EVQ_SIZE_8K 4
++#define EVQ_SIZE_4K 3
++#define EVQ_SIZE_2K 2
++#define EVQ_SIZE_1K 1
++#define EVQ_SIZE_512 0
++#define EVQ_BUF_BASE_ID_LBN 0
++#define EVQ_BUF_BASE_ID_WIDTH 20
++
++/* Event queue read pointer */
++#define EVQ_RPTR_REG_KER_A1 0x11b00
++#define EVQ_RPTR_REG_KER_B0 0xfa0000
++#define EVQ_RPTR_LBN 0
++#define EVQ_RPTR_WIDTH 14
++#define EVQ_RPTR_REG_KER_DWORD (EVQ_RPTR_REG_KER + 0)
++#define EVQ_RPTR_DWORD_LBN 0
++#define EVQ_RPTR_DWORD_WIDTH 14
++
++/* RSS indirection table */
++#define RX_RSS_INDIR_TBL_B0 0xFB0000
++#define RX_RSS_INDIR_ENT_B0_LBN 0
++#define RX_RSS_INDIR_ENT_B0_WIDTH 6
++
++/* Special buffer descriptors (full-mode) */
++#define BUF_FULL_TBL_KER_A1 0x8000
++#define BUF_FULL_TBL_KER_B0 0x800000
++#define IP_DAT_BUF_SIZE_LBN 50
++#define IP_DAT_BUF_SIZE_WIDTH 1
++#define IP_DAT_BUF_SIZE_8K 1
++#define IP_DAT_BUF_SIZE_4K 0
++#define BUF_ADR_REGION_LBN 48
++#define BUF_ADR_REGION_WIDTH 2
++#define BUF_ADR_FBUF_LBN 14
++#define BUF_ADR_FBUF_WIDTH 34
++#define BUF_OWNER_ID_FBUF_LBN 0
++#define BUF_OWNER_ID_FBUF_WIDTH 14
++
++/* Special buffer descriptors (half-mode) */
++#define BUF_HALF_TBL_KER_A1 0x8000
++#define BUF_HALF_TBL_KER_B0 0x800000
++#define BUF_ADR_HBUF_ODD_LBN 44
++#define BUF_ADR_HBUF_ODD_WIDTH 20
++#define BUF_OWNER_ID_HBUF_ODD_LBN 32
++#define BUF_OWNER_ID_HBUF_ODD_WIDTH 12
++#define BUF_ADR_HBUF_EVEN_LBN 12
++#define BUF_ADR_HBUF_EVEN_WIDTH 20
++#define BUF_OWNER_ID_HBUF_EVEN_LBN 0
++#define BUF_OWNER_ID_HBUF_EVEN_WIDTH 12
++
++#define SRM_DBG_REG_B0 0x3000000
++
++/* Transmit descriptor */
++#define TX_KER_PORT_LBN 63
++#define TX_KER_PORT_WIDTH 1
++#define TX_KER_CONT_LBN 62
++#define TX_KER_CONT_WIDTH 1
++#define TX_KER_BYTE_CNT_LBN 48
++#define TX_KER_BYTE_CNT_WIDTH 14
++#define TX_KER_BUF_REGION_LBN 46
++#define TX_KER_BUF_REGION_WIDTH 2
++#define TX_KER_BUF_REGION0_DECODE 0
++#define TX_KER_BUF_REGION1_DECODE 1
++#define TX_KER_BUF_REGION2_DECODE 2
++#define TX_KER_BUF_REGION3_DECODE 3
++#define TX_KER_BUF_ADR_LBN 0
++#define TX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
++
++/* Receive descriptor */
++#define RX_KER_BUF_SIZE_LBN 48
++#define RX_KER_BUF_SIZE_WIDTH 14
++#define RX_KER_BUF_REGION_LBN 46
++#define RX_KER_BUF_REGION_WIDTH 2
++#define RX_KER_BUF_REGION0_DECODE 0
++#define RX_KER_BUF_REGION1_DECODE 1
++#define RX_KER_BUF_REGION2_DECODE 2
++#define RX_KER_BUF_REGION3_DECODE 3
++#define RX_KER_BUF_ADR_LBN 0
++#define RX_KER_BUF_ADR_WIDTH EFX_DMA_TYPE_WIDTH(46)
++
++/**************************************************************************
++ *
++ * Falcon events
++ *
++ **************************************************************************
++ */
++
++/* Event queue entries */
++#define EV_CODE_LBN 60
++#define EV_CODE_WIDTH 4
++#define RX_IP_EV_DECODE 0
++#define TX_IP_EV_DECODE 2
++#define DRIVER_EV_DECODE 5
++#define GLOBAL_EV_DECODE 6
++#define DRV_GEN_EV_DECODE 7
++#define WHOLE_EVENT_LBN 0
++#define WHOLE_EVENT_WIDTH 64
++
++/* Receive events */
++#define RX_EV_PKT_OK_LBN 56
++#define RX_EV_PKT_OK_WIDTH 1
++#define RX_EV_PAUSE_FRM_ERR_LBN 55
++#define RX_EV_PAUSE_FRM_ERR_WIDTH 1
++#define RX_EV_BUF_OWNER_ID_ERR_LBN 54
++#define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
++#define RX_EV_IF_FRAG_ERR_LBN 53
++#define RX_EV_IF_FRAG_ERR_WIDTH 1
++#define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
++#define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
++#define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
++#define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
++#define RX_EV_ETH_CRC_ERR_LBN 50
++#define RX_EV_ETH_CRC_ERR_WIDTH 1
++#define RX_EV_FRM_TRUNC_LBN 49
++#define RX_EV_FRM_TRUNC_WIDTH 1
++#define RX_EV_DRIB_NIB_LBN 48
++#define RX_EV_DRIB_NIB_WIDTH 1
++#define RX_EV_TOBE_DISC_LBN 47
++#define RX_EV_TOBE_DISC_WIDTH 1
++#define RX_EV_PKT_TYPE_LBN 44
++#define RX_EV_PKT_TYPE_WIDTH 3
++#define RX_EV_PKT_TYPE_ETH_DECODE 0
++#define RX_EV_PKT_TYPE_LLC_DECODE 1
++#define RX_EV_PKT_TYPE_JUMBO_DECODE 2
++#define RX_EV_PKT_TYPE_VLAN_DECODE 3
++#define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4
++#define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5
++#define RX_EV_HDR_TYPE_LBN 42
++#define RX_EV_HDR_TYPE_WIDTH 2
++#define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0
++#define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1
++#define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2
++#define RX_EV_HDR_TYPE_NON_IP_DECODE 3
++#define RX_EV_HDR_TYPE_HAS_CHECKSUMS(hdr_type) \
++      ((hdr_type) <= RX_EV_HDR_TYPE_UDP_IPV4_DECODE)
++#define RX_EV_DESC_Q_EMPTY_LBN 41
++#define RX_EV_DESC_Q_EMPTY_WIDTH 1
++#define RX_EV_MCAST_HASH_MATCH_LBN 40
++#define RX_EV_MCAST_HASH_MATCH_WIDTH 1
++#define RX_EV_MCAST_PKT_LBN 39
++#define RX_EV_MCAST_PKT_WIDTH 1
++#define RX_EV_RECOVERY_FLAG_LBN 37
++#define RX_EV_RECOVERY_FLAG_WIDTH 1
++#define RX_EV_Q_LABEL_LBN 32
++#define RX_EV_Q_LABEL_WIDTH 5
++#define RX_EV_JUMBO_CONT_LBN 31
++#define RX_EV_JUMBO_CONT_WIDTH 1
++#define RX_EV_PORT_LBN 30
++#define RX_EV_PORT_WIDTH 1
++#define RX_EV_BYTE_CNT_LBN 16
++#define RX_EV_BYTE_CNT_WIDTH 14
++#define RX_EV_SOP_LBN 15
++#define RX_EV_SOP_WIDTH 1
++#define RX_ISCSI_DDIG_ERR_LBN 13
++#define RX_ISCSI_DDIG_ERR_WIDTH 1
++#define RX_ISCSI_HDIG_ERR_LBN 12
++#define RX_ISCSI_HDIG_ERR_WIDTH 1
++#define RX_EV_DESC_PTR_LBN 0
++#define RX_EV_DESC_PTR_WIDTH 12
++
++/* Transmit events */
++#define TX_EV_PKT_ERR_LBN 38
++#define TX_EV_PKT_ERR_WIDTH 1
++#define TX_EV_PKT_TOO_BIG_LBN 37
++#define TX_EV_PKT_TOO_BIG_WIDTH 1
++#define TX_EV_Q_LABEL_LBN 32
++#define TX_EV_Q_LABEL_WIDTH 5
++#define TX_EV_PORT_LBN 16
++#define TX_EV_PORT_WIDTH 1
++#define TX_EV_WQ_FF_FULL_LBN 15
++#define TX_EV_WQ_FF_FULL_WIDTH 1
++#define TX_EV_BUF_OWNER_ID_ERR_LBN 14
++#define TX_EV_BUF_OWNER_ID_ERR_WIDTH 1
++#define TX_EV_COMP_LBN 12
++#define TX_EV_COMP_WIDTH 1
++#define TX_EV_DESC_PTR_LBN 0
++#define TX_EV_DESC_PTR_WIDTH 12
++
++/* Driver events */
++#define DRIVER_EV_SUB_CODE_LBN 56
++#define DRIVER_EV_SUB_CODE_WIDTH 4
++#define DRIVER_EV_SUB_DATA_LBN 0
++#define DRIVER_EV_SUB_DATA_WIDTH 14
++#define TX_DESCQ_FLS_DONE_EV_DECODE 0
++#define RX_DESCQ_FLS_DONE_EV_DECODE 1
++#define EVQ_INIT_DONE_EV_DECODE 2
++#define EVQ_NOT_EN_EV_DECODE 3
++#define RX_DESCQ_FLSFF_OVFL_EV_DECODE 4
++#define SRM_UPD_DONE_EV_DECODE 5
++#define WAKE_UP_EV_DECODE 6
++#define TX_PKT_NON_TCP_UDP_DECODE 9
++#define TIMER_EV_DECODE 10
++#define RX_RECOVERY_EV_DECODE 11
++#define RX_DSC_ERROR_EV_DECODE 14
++#define TX_DSC_ERROR_EV_DECODE 15
++#define DRIVER_EV_TX_DESCQ_ID_LBN 0
++#define DRIVER_EV_TX_DESCQ_ID_WIDTH 12
++#define DRIVER_EV_RX_FLUSH_FAIL_LBN 12
++#define DRIVER_EV_RX_FLUSH_FAIL_WIDTH 1
++#define DRIVER_EV_RX_DESCQ_ID_LBN 0
++#define DRIVER_EV_RX_DESCQ_ID_WIDTH 12
++#define DRIVER_EV_EVQ_ID_LBN 0
++#define DRIVER_EV_EVQ_ID_WIDTH 12
++#define DRIVER_EV_SRM_UPD_LBN 0
++#define DRIVER_EV_SRM_UPD_WIDTH 2
++#define SRM_CLR_EV_DECODE 0
++#define SRM_UPD_EV_DECODE 1
++#define SRM_ILLCLR_EV_DECODE 2
++
++/* Global events */
++#define RX_RECOVERY_B0_LBN 12
++#define RX_RECOVERY_B0_WIDTH 1
++#define XG_MNT_INTR_B0_LBN 11
++#define XG_MNT_INTR_B0_WIDTH 1
++
++#define RX_RECOVERY_A1_LBN 11
++#define RX_RECOVERY_A1_WIDTH 1
++
++#define XFP_PHY_INTR_LBN 10
++#define XFP_PHY_INTR_WIDTH 1
++#define XG_PHY_INTR_LBN 9
++#define XG_PHY_INTR_WIDTH 1
++#define G_PHY1_INTR_LBN 8
++#define G_PHY1_INTR_WIDTH 1
++#define G_PHY0_INTR_LBN 7
++#define G_PHY0_INTR_WIDTH 1
++
++/* Driver-generated test events */
++#define DRV_GEN_EV_CODE_LBN 60
++#define DRV_GEN_EV_CODE_WIDTH 4
++#define DRV_GEN_EV_DATA_LBN 0
++#define DRV_GEN_EV_DATA_WIDTH 60
++#define EVQ_MAGIC_LBN 0
++#define EVQ_MAGIC_WIDTH 32
++
++/**************************************************************************
++ *
++ * Falcon MAC stats
++ *
++ **************************************************************************
++ *
++ */
++
++#define GRxGoodOct_offset 0x0
++#define GRxGoodOct_WIDTH 48
++#define GRxBadOct_offset 0x8
++#define GRxBadOct_WIDTH 48
++#define GRxMissPkt_offset 0x10
++#define GRxMissPkt_WIDTH 32
++#define GRxFalseCRS_offset 0x14
++#define GRxFalseCRS_WIDTH 32
++#define GRxPausePkt_offset 0x18
++#define GRxPausePkt_WIDTH 32
++#define GRxBadPkt_offset 0x1C
++#define GRxBadPkt_WIDTH 32
++#define GRxUcastPkt_offset 0x20
++#define GRxUcastPkt_WIDTH 32
++#define GRxMcastPkt_offset 0x24
++#define GRxMcastPkt_WIDTH 32
++#define GRxBcastPkt_offset 0x28
++#define GRxBcastPkt_WIDTH 32
++#define GRxGoodLt64Pkt_offset 0x2C
++#define GRxGoodLt64Pkt_WIDTH 32
++#define GRxBadLt64Pkt_offset 0x30
++#define GRxBadLt64Pkt_WIDTH 32
++#define GRx64Pkt_offset 0x34
++#define GRx64Pkt_WIDTH 32
++#define GRx65to127Pkt_offset 0x38
++#define GRx65to127Pkt_WIDTH 32
++#define GRx128to255Pkt_offset 0x3C
++#define GRx128to255Pkt_WIDTH 32
++#define GRx256to511Pkt_offset 0x40
++#define GRx256to511Pkt_WIDTH 32
++#define GRx512to1023Pkt_offset 0x44
++#define GRx512to1023Pkt_WIDTH 32
++#define GRx1024to15xxPkt_offset 0x48
++#define GRx1024to15xxPkt_WIDTH 32
++#define GRx15xxtoJumboPkt_offset 0x4C
++#define GRx15xxtoJumboPkt_WIDTH 32
++#define GRxGtJumboPkt_offset 0x50
++#define GRxGtJumboPkt_WIDTH 32
++#define GRxFcsErr64to15xxPkt_offset 0x54
++#define GRxFcsErr64to15xxPkt_WIDTH 32
++#define GRxFcsErr15xxtoJumboPkt_offset 0x58
++#define GRxFcsErr15xxtoJumboPkt_WIDTH 32
++#define GRxFcsErrGtJumboPkt_offset 0x5C
++#define GRxFcsErrGtJumboPkt_WIDTH 32
++#define GTxGoodBadOct_offset 0x80
++#define GTxGoodBadOct_WIDTH 48
++#define GTxGoodOct_offset 0x88
++#define GTxGoodOct_WIDTH 48
++#define GTxSglColPkt_offset 0x90
++#define GTxSglColPkt_WIDTH 32
++#define GTxMultColPkt_offset 0x94
++#define GTxMultColPkt_WIDTH 32
++#define GTxExColPkt_offset 0x98
++#define GTxExColPkt_WIDTH 32
++#define GTxDefPkt_offset 0x9C
++#define GTxDefPkt_WIDTH 32
++#define GTxLateCol_offset 0xA0
++#define GTxLateCol_WIDTH 32
++#define GTxExDefPkt_offset 0xA4
++#define GTxExDefPkt_WIDTH 32
++#define GTxPausePkt_offset 0xA8
++#define GTxPausePkt_WIDTH 32
++#define GTxBadPkt_offset 0xAC
++#define GTxBadPkt_WIDTH 32
++#define GTxUcastPkt_offset 0xB0
++#define GTxUcastPkt_WIDTH 32
++#define GTxMcastPkt_offset 0xB4
++#define GTxMcastPkt_WIDTH 32
++#define GTxBcastPkt_offset 0xB8
++#define GTxBcastPkt_WIDTH 32
++#define GTxLt64Pkt_offset 0xBC
++#define GTxLt64Pkt_WIDTH 32
++#define GTx64Pkt_offset 0xC0
++#define GTx64Pkt_WIDTH 32
++#define GTx65to127Pkt_offset 0xC4
++#define GTx65to127Pkt_WIDTH 32
++#define GTx128to255Pkt_offset 0xC8
++#define GTx128to255Pkt_WIDTH 32
++#define GTx256to511Pkt_offset 0xCC
++#define GTx256to511Pkt_WIDTH 32
++#define GTx512to1023Pkt_offset 0xD0
++#define GTx512to1023Pkt_WIDTH 32
++#define GTx1024to15xxPkt_offset 0xD4
++#define GTx1024to15xxPkt_WIDTH 32
++#define GTx15xxtoJumboPkt_offset 0xD8
++#define GTx15xxtoJumboPkt_WIDTH 32
++#define GTxGtJumboPkt_offset 0xDC
++#define GTxGtJumboPkt_WIDTH 32
++#define GTxNonTcpUdpPkt_offset 0xE0
++#define GTxNonTcpUdpPkt_WIDTH 16
++#define GTxMacSrcErrPkt_offset 0xE4
++#define GTxMacSrcErrPkt_WIDTH 16
++#define GTxIpSrcErrPkt_offset 0xE8
++#define GTxIpSrcErrPkt_WIDTH 16
++#define GDmaDone_offset 0xEC
++#define GDmaDone_WIDTH 32
++
++#define XgRxOctets_offset 0x0
++#define XgRxOctets_WIDTH 48
++#define XgRxOctetsOK_offset 0x8
++#define XgRxOctetsOK_WIDTH 48
++#define XgRxPkts_offset 0x10
++#define XgRxPkts_WIDTH 32
++#define XgRxPktsOK_offset 0x14
++#define XgRxPktsOK_WIDTH 32
++#define XgRxBroadcastPkts_offset 0x18
++#define XgRxBroadcastPkts_WIDTH 32
++#define XgRxMulticastPkts_offset 0x1C
++#define XgRxMulticastPkts_WIDTH 32
++#define XgRxUnicastPkts_offset 0x20
++#define XgRxUnicastPkts_WIDTH 32
++#define XgRxUndersizePkts_offset 0x24
++#define XgRxUndersizePkts_WIDTH 32
++#define XgRxOversizePkts_offset 0x28
++#define XgRxOversizePkts_WIDTH 32
++#define XgRxJabberPkts_offset 0x2C
++#define XgRxJabberPkts_WIDTH 32
++#define XgRxUndersizeFCSerrorPkts_offset 0x30
++#define XgRxUndersizeFCSerrorPkts_WIDTH 32
++#define XgRxDropEvents_offset 0x34
++#define XgRxDropEvents_WIDTH 32
++#define XgRxFCSerrorPkts_offset 0x38
++#define XgRxFCSerrorPkts_WIDTH 32
++#define XgRxAlignError_offset 0x3C
++#define XgRxAlignError_WIDTH 32
++#define XgRxSymbolError_offset 0x40
++#define XgRxSymbolError_WIDTH 32
++#define XgRxInternalMACError_offset 0x44
++#define XgRxInternalMACError_WIDTH 32
++#define XgRxControlPkts_offset 0x48
++#define XgRxControlPkts_WIDTH 32
++#define XgRxPausePkts_offset 0x4C
++#define XgRxPausePkts_WIDTH 32
++#define XgRxPkts64Octets_offset 0x50
++#define XgRxPkts64Octets_WIDTH 32
++#define XgRxPkts65to127Octets_offset 0x54
++#define XgRxPkts65to127Octets_WIDTH 32
++#define XgRxPkts128to255Octets_offset 0x58
++#define XgRxPkts128to255Octets_WIDTH 32
++#define XgRxPkts256to511Octets_offset 0x5C
++#define XgRxPkts256to511Octets_WIDTH 32
++#define XgRxPkts512to1023Octets_offset 0x60
++#define XgRxPkts512to1023Octets_WIDTH 32
++#define XgRxPkts1024to15xxOctets_offset 0x64
++#define XgRxPkts1024to15xxOctets_WIDTH 32
++#define XgRxPkts15xxtoMaxOctets_offset 0x68
++#define XgRxPkts15xxtoMaxOctets_WIDTH 32
++#define XgRxLengthError_offset 0x6C
++#define XgRxLengthError_WIDTH 32
++#define XgTxPkts_offset 0x80
++#define XgTxPkts_WIDTH 32
++#define XgTxOctets_offset 0x88
++#define XgTxOctets_WIDTH 48
++#define XgTxMulticastPkts_offset 0x90
++#define XgTxMulticastPkts_WIDTH 32
++#define XgTxBroadcastPkts_offset 0x94
++#define XgTxBroadcastPkts_WIDTH 32
++#define XgTxUnicastPkts_offset 0x98
++#define XgTxUnicastPkts_WIDTH 32
++#define XgTxControlPkts_offset 0x9C
++#define XgTxControlPkts_WIDTH 32
++#define XgTxPausePkts_offset 0xA0
++#define XgTxPausePkts_WIDTH 32
++#define XgTxPkts64Octets_offset 0xA4
++#define XgTxPkts64Octets_WIDTH 32
++#define XgTxPkts65to127Octets_offset 0xA8
++#define XgTxPkts65to127Octets_WIDTH 32
++#define XgTxPkts128to255Octets_offset 0xAC
++#define XgTxPkts128to255Octets_WIDTH 32
++#define XgTxPkts256to511Octets_offset 0xB0
++#define XgTxPkts256to511Octets_WIDTH 32
++#define XgTxPkts512to1023Octets_offset 0xB4
++#define XgTxPkts512to1023Octets_WIDTH 32
++#define XgTxPkts1024to15xxOctets_offset 0xB8
++#define XgTxPkts1024to15xxOctets_WIDTH 32
++#define XgTxPkts1519toMaxOctets_offset 0xBC
++#define XgTxPkts1519toMaxOctets_WIDTH 32
++#define XgTxUndersizePkts_offset 0xC0
++#define XgTxUndersizePkts_WIDTH 32
++#define XgTxOversizePkts_offset 0xC4
++#define XgTxOversizePkts_WIDTH 32
++#define XgTxNonTcpUdpPkt_offset 0xC8
++#define XgTxNonTcpUdpPkt_WIDTH 16
++#define XgTxMacSrcErrPkt_offset 0xCC
++#define XgTxMacSrcErrPkt_WIDTH 16
++#define XgTxIpSrcErrPkt_offset 0xD0
++#define XgTxIpSrcErrPkt_WIDTH 16
++#define XgDmaDone_offset 0xD4
++#define XgDmaDone_WIDTH 32
++
++#define FALCON_STATS_NOT_DONE 0x00000000
++#define FALCON_STATS_DONE 0xffffffff
++
++/* Interrupt status register bits */
++#define FATAL_INT_LBN 64
++#define FATAL_INT_WIDTH 1
++#define INT_EVQS_LBN 40
++#define INT_EVQS_WIDTH 4
++#define INT_FLAG_LBN 32
++#define INT_FLAG_WIDTH 1
++#define EVQ_FIFO_HF_LBN 1
++#define EVQ_FIFO_HF_WIDTH 1
++#define EVQ_FIFO_AF_LBN 0
++#define EVQ_FIFO_AF_WIDTH 1
++
++/**************************************************************************
++ *
++ * Falcon non-volatile configuration
++ *
++ **************************************************************************
++ */
++
++/* Board configuration v2 (v1 is obsolete; later versions are compatible) */
++struct falcon_nvconfig_board_v2 {
++      __le16 nports;
++      u8 port0_phy_addr;
++      u8 port0_phy_type;
++      u8 port1_phy_addr;
++      u8 port1_phy_type;
++      __le16 asic_sub_revision;
++      __le16 board_revision;
++} __attribute__ ((packed));
++
++/* Board configuration v3 extra information */
++struct falcon_nvconfig_board_v3 {
++      __le32 spi_device_type[2];
++} __attribute__ ((packed));
++
++/* Bit numbers for spi_device_type */
++#define SPI_DEV_TYPE_SIZE_LBN 0
++#define SPI_DEV_TYPE_SIZE_WIDTH 5
++#define SPI_DEV_TYPE_ADDR_LEN_LBN 6
++#define SPI_DEV_TYPE_ADDR_LEN_WIDTH 2
++#define SPI_DEV_TYPE_ERASE_CMD_LBN 8
++#define SPI_DEV_TYPE_ERASE_CMD_WIDTH 8
++#define SPI_DEV_TYPE_ERASE_SIZE_LBN 16
++#define SPI_DEV_TYPE_ERASE_SIZE_WIDTH 5
++#define SPI_DEV_TYPE_BLOCK_SIZE_LBN 24
++#define SPI_DEV_TYPE_BLOCK_SIZE_WIDTH 5
++#define SPI_DEV_TYPE_FIELD(type, field) \
++      (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(field))
++
++#define NVCONFIG_BASE 0x300
++#define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C
++struct falcon_nvconfig {
++      efx_oword_t ee_vpd_cfg_reg;                     /* 0x300 */
++      u8 mac_address[2][8];                   /* 0x310 */
++      efx_oword_t pcie_sd_ctl0123_reg;                /* 0x320 */
++      efx_oword_t pcie_sd_ctl45_reg;                  /* 0x330 */
++      efx_oword_t pcie_pcs_ctl_stat_reg;              /* 0x340 */
++      efx_oword_t hw_init_reg;                        /* 0x350 */
++      efx_oword_t nic_stat_reg;                       /* 0x360 */
++      efx_oword_t glb_ctl_reg;                        /* 0x370 */
++      efx_oword_t srm_cfg_reg;                        /* 0x380 */
++      efx_oword_t spare_reg;                          /* 0x390 */
++      __le16 board_magic_num;                 /* 0x3A0 */
++      __le16 board_struct_ver;
++      __le16 board_checksum;
++      struct falcon_nvconfig_board_v2 board_v2;
++      efx_oword_t ee_base_page_reg;                   /* 0x3B0 */
++      struct falcon_nvconfig_board_v3 board_v3;       /* 0x3C0 */
++} __attribute__ ((packed));
++
++#endif /* EFX_FALCON_HWDEFS_H */
+--- linux-2.6.18.8/drivers/net/sfc/falcon_io.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/falcon_io.h    2008-05-19 00:33:28.849809063 +0300
+@@ -0,0 +1,259 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
 + *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
 + *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
 + *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <stdarg.h>
-+#include <linux/module.h>
-+#include <linux/kthread.h>
-+#include <xen/xenbus.h>
-+#include "common.h"
++#ifndef EFX_FALCON_IO_H
++#define EFX_FALCON_IO_H
 +
++#include "net_driver.h"
++#include "falcon.h"
 +
-+struct backend_info
-+{
-+      struct xenbus_device *dev;
-+      blkif_t *blkif;
-+      struct xenbus_watch backend_watch;
-+      int xenbus_id;
-+      int group_added;
-+};
++/**************************************************************************
++ *
++ * Falcon hardware access
++ *
++ **************************************************************************
++ *
++ * Notes on locking strategy:
++ *
++ * Most Falcon registers require 16-byte (or 8-byte, for SRAM
++ * registers) atomic writes which necessitates locking.
++ * Under normal operation few writes to the Falcon BAR are made and these
++ * registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and TX_DESC_UPD_REG) are special
++ * cased to allow 4-byte (hence lockless) accesses.
++ *
++ * It *is* safe to write to these 4-byte registers in the middle of an
++ * access to an 8-byte or 16-byte register.  We therefore use a
++ * spinlock to protect accesses to the larger registers, but no locks
++ * for the 4-byte registers.
++ *
++ * A write barrier is needed to ensure that DW3 is written after DW0/1/2
++ * due to the way the 16byte registers are "collected" in the Falcon BIU
++ *
++ * We also lock when carrying out reads, to ensure consistency of the
++ * data (made possible since the BIU reads all 128 bits into a cache).
++ * Reads are very rare, so this isn't a significant performance
++ * impact.  (Most data transferred from NIC to host is DMAed directly
++ * into host memory).
++ *
++ * I/O BAR access uses locks for both reads and writes (but is only provided
++ * for testing purposes).
++ */
 +
++/* Special buffer descriptors (Falcon SRAM) */
++#define BUF_TBL_KER_A1 0x18000
++#define BUF_TBL_KER_B0 0x800000
 +
-+static void connect(struct backend_info *);
-+static int connect_ring(struct backend_info *);
-+static int blktap_remove(struct xenbus_device *dev);
-+static int blktap_probe(struct xenbus_device *dev,
-+                       const struct xenbus_device_id *id);
-+static void tap_backend_changed(struct xenbus_watch *, const char **,
-+                          unsigned int);
-+static void tap_frontend_changed(struct xenbus_device *dev,
-+                           enum xenbus_state frontend_state);
 +
-+static int strsep_len(const char *str, char c, unsigned int len)
-+{
-+        unsigned int i;
++#if BITS_PER_LONG == 64
++#define FALCON_USE_QWORD_IO 1
++#endif
 +
-+        for (i = 0; str[i]; i++)
-+                if (str[i] == c) {
-+                        if (len == 0)
-+                                return i;
-+                        len--;
-+                }
-+        return (len == 0) ? i : -ERANGE;
-+}
++#define _falcon_writeq(efx, value, reg) \
++      __raw_writeq((__force u64) (value), (efx)->membase + (reg))
++#define _falcon_writel(efx, value, reg) \
++      __raw_writel((__force u32) (value), (efx)->membase + (reg))
++#define _falcon_readq(efx, reg) \
++      ((__force __le64) __raw_readq((efx)->membase + (reg)))
++#define _falcon_readl(efx, reg) \
++      ((__force __le32) __raw_readl((efx)->membase + (reg)))
 +
-+static long get_id(const char *str)
++/* Writes to a normal 16-byte Falcon register, locking as appropriate. */
++static inline void falcon_write(struct efx_nic *efx, efx_oword_t *value,
++                              unsigned int reg)
 +{
-+        int len,end;
-+        const char *ptr;
-+        char *tptr, num[10];
-+      
-+        len = strsep_len(str, '/', 2);
-+        end = strlen(str);
-+        if ( (len < 0) || (end < 0) ) return -1;
-+      
-+        ptr = str + len + 1;
-+        strncpy(num,ptr,end - len);
-+        tptr = num + (end - (len + 1));
-+        *tptr = '\0';
-+      DPRINTK("Get_id called for %s (%s)\n",str,num);
-+      
-+        return simple_strtol(num, NULL, 10);
-+}                             
++      unsigned long flags __attribute__ ((unused));
 +
-+static int blktap_name(blkif_t *blkif, char *buf)
++      EFX_REGDUMP(efx, "writing register %x with " EFX_OWORD_FMT "\n", reg,
++                  EFX_OWORD_VAL(*value));
++
++      spin_lock_irqsave(&efx->biu_lock, flags);
++#ifdef FALCON_USE_QWORD_IO
++      _falcon_writeq(efx, value->u64[0], reg + 0);
++      wmb();
++      _falcon_writeq(efx, value->u64[1], reg + 8);
++#else
++      _falcon_writel(efx, value->u32[0], reg + 0);
++      _falcon_writel(efx, value->u32[1], reg + 4);
++      _falcon_writel(efx, value->u32[2], reg + 8);
++      wmb();
++      _falcon_writel(efx, value->u32[3], reg + 12);
++#endif
++      mmiowb();
++      spin_unlock_irqrestore(&efx->biu_lock, flags);
++}
++
++/* Writes to an 8-byte Falcon SRAM register, locking as appropriate. */
++static inline void falcon_write_sram(struct efx_nic *efx, efx_qword_t *value,
++                                   unsigned int index)
 +{
-+      char *devpath, *devname;
-+      struct xenbus_device *dev = blkif->be->dev;
++      unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
++      unsigned long flags __attribute__ ((unused));
 +
-+      devpath = xenbus_read(XBT_NIL, dev->nodename, "dev", NULL);
-+      if (IS_ERR(devpath)) 
-+              return PTR_ERR(devpath);
-+      
-+      if ((devname = strstr(devpath, "/dev/")) != NULL)
-+              devname += strlen("/dev/");
-+      else
-+              devname  = devpath;
++      EFX_REGDUMP(efx, "writing SRAM register %x with " EFX_QWORD_FMT "\n",
++                  reg, EFX_QWORD_VAL(*value));
 +
-+      snprintf(buf, TASK_COMM_LEN, "blktap.%d.%s", blkif->domid, devname);
-+      kfree(devpath);
-+      
-+      return 0;
++      spin_lock_irqsave(&efx->biu_lock, flags);
++#ifdef FALCON_USE_QWORD_IO
++      _falcon_writeq(efx, value->u64[0], reg + 0);
++#else
++      _falcon_writel(efx, value->u32[0], reg + 0);
++      wmb();
++      _falcon_writel(efx, value->u32[1], reg + 4);
++#endif
++      mmiowb();
++      spin_unlock_irqrestore(&efx->biu_lock, flags);
 +}
 +
-+/****************************************************************
-+ *  sysfs interface for I/O requests of blktap device
++/* Write dword to Falcon register that allows partial writes
++ *
++ * Some Falcon registers (EVQ_RPTR_REG, RX_DESC_UPD_REG and
++ * TX_DESC_UPD_REG) can be written to as a single dword.  This allows
++ * for lockless writes.
 + */
++static inline void falcon_writel(struct efx_nic *efx, efx_dword_t *value,
++                               unsigned int reg)
++{
++      EFX_REGDUMP(efx, "writing partial register %x with "EFX_DWORD_FMT"\n",
++                  reg, EFX_DWORD_VAL(*value));
 +
-+#define VBD_SHOW(name, format, args...)                                       \
-+      static ssize_t show_##name(struct device *_dev,                 \
-+                                 struct device_attribute *attr,       \
-+                                 char *buf)                           \
-+      {                                                               \
-+              struct xenbus_device *dev = to_xenbus_device(_dev);     \
-+              struct backend_info *be = dev->dev.driver_data;         \
-+                                                                      \
-+              return sprintf(buf, format, ##args);                    \
-+      }                                                               \
-+      static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
++      /* No lock required */
++      _falcon_writel(efx, value->u32[0], reg);
++}
 +
-+VBD_SHOW(oo_req,  "%d\n", be->blkif->st_oo_req);
-+VBD_SHOW(rd_req,  "%d\n", be->blkif->st_rd_req);
-+VBD_SHOW(wr_req,  "%d\n", be->blkif->st_wr_req);
-+VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect);
-+VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect);
++/* Read from a Falcon register
++ *
++ * This reads an entire 16-byte Falcon register in one go, locking as
++ * appropriate.  It is essential to read the first dword first, as this
++ * prompts Falcon to load the current value into the shadow register.
++ */
++static inline void falcon_read(struct efx_nic *efx, efx_oword_t *value,
++                             unsigned int reg)
++{
++      unsigned long flags __attribute__ ((unused));
 +
-+static struct attribute *tapstat_attrs[] = {
-+      &dev_attr_oo_req.attr,
-+      &dev_attr_rd_req.attr,
-+      &dev_attr_wr_req.attr,
-+      &dev_attr_rd_sect.attr,
-+      &dev_attr_wr_sect.attr,
-+      NULL
-+};
++      spin_lock_irqsave(&efx->biu_lock, flags);
++      value->u32[0] = _falcon_readl(efx, reg + 0);
++      rmb();
++      value->u32[1] = _falcon_readl(efx, reg + 4);
++      value->u32[2] = _falcon_readl(efx, reg + 8);
++      value->u32[3] = _falcon_readl(efx, reg + 12);
++      spin_unlock_irqrestore(&efx->biu_lock, flags);
 +
-+static struct attribute_group tapstat_group = {
-+      .name = "statistics",
-+      .attrs = tapstat_attrs,
-+};
++      EFX_REGDUMP(efx, "read from register %x, got " EFX_OWORD_FMT "\n", reg,
++                  EFX_OWORD_VAL(*value));
++}
 +
-+int xentap_sysfs_addif(struct xenbus_device *dev)
++/* This reads an 8-byte Falcon SRAM entry in one go. */
++static inline void falcon_read_sram(struct efx_nic *efx, efx_qword_t *value,
++                                  unsigned int index)
 +{
-+      int err;
-+      struct backend_info *be = dev->dev.driver_data;
-+      err = sysfs_create_group(&dev->dev.kobj, &tapstat_group);
-+      if (!err)
-+              be->group_added = 1;
-+      return err;
++      unsigned int reg = efx->type->buf_tbl_base + (index * sizeof(*value));
++      unsigned long flags __attribute__ ((unused));
++
++      spin_lock_irqsave(&efx->biu_lock, flags);
++#ifdef FALCON_USE_QWORD_IO
++      value->u64[0] = _falcon_readq(efx, reg + 0);
++#else
++      value->u32[0] = _falcon_readl(efx, reg + 0);
++      rmb();
++      value->u32[1] = _falcon_readl(efx, reg + 4);
++#endif
++      spin_unlock_irqrestore(&efx->biu_lock, flags);
++
++      EFX_REGDUMP(efx, "read from SRAM register %x, got "EFX_QWORD_FMT"\n",
++                  reg, EFX_QWORD_VAL(*value));
 +}
 +
-+void xentap_sysfs_delif(struct xenbus_device *dev)
++/* Read dword from Falcon register that allows partial writes (sic) */
++static inline void falcon_readl(struct efx_nic *efx, efx_dword_t *value,
++                              unsigned int reg)
 +{
-+      struct backend_info *be = dev->dev.driver_data;
-+      sysfs_remove_group(&dev->dev.kobj, &tapstat_group);
-+      be->group_added = 0;
++      value->u32[0] = _falcon_readl(efx, reg);
++      EFX_REGDUMP(efx, "read from register %x, got "EFX_DWORD_FMT"\n",
++                  reg, EFX_DWORD_VAL(*value));
 +}
 +
-+static int blktap_remove(struct xenbus_device *dev)
++/* Write to a register forming part of a table */
++static inline void falcon_write_table(struct efx_nic *efx, efx_oword_t *value,
++                                    unsigned int reg, unsigned int index)
 +{
-+      struct backend_info *be = dev->dev.driver_data;
++      falcon_write(efx, value, reg + index * sizeof(efx_oword_t));
++}
 +
-+      if (be->group_added)
-+              xentap_sysfs_delif(be->dev);
-+      if (be->backend_watch.node) {
-+              unregister_xenbus_watch(&be->backend_watch);
-+              kfree(be->backend_watch.node);
-+              be->backend_watch.node = NULL;
-+      }
-+      if (be->blkif) {
-+              if (be->blkif->xenblkd)
-+                      kthread_stop(be->blkif->xenblkd);
-+              signal_tapdisk(be->blkif->dev_num);
-+              tap_blkif_free(be->blkif);
-+              be->blkif = NULL;
-+      }
-+      kfree(be);
-+      dev->dev.driver_data = NULL;
-+      return 0;
++/* Read to a register forming part of a table */
++static inline void falcon_read_table(struct efx_nic *efx, efx_oword_t *value,
++                                   unsigned int reg, unsigned int index)
++{
++      falcon_read(efx, value, reg + index * sizeof(efx_oword_t));
 +}
 +
-+static void tap_update_blkif_status(blkif_t *blkif)
-+{ 
-+      int err;
-+      char name[TASK_COMM_LEN];
++/* Write to a dword register forming part of a table */
++static inline void falcon_writel_table(struct efx_nic *efx, efx_dword_t *value,
++                                     unsigned int reg, unsigned int index)
++{
++      falcon_writel(efx, value, reg + index * sizeof(efx_oword_t));
++}
 +
-+      /* Not ready to connect? */
-+      if(!blkif->irq || !blkif->sectors) {
-+              return;
-+      } 
++/* Page-mapped register block size */
++#define FALCON_PAGE_BLOCK_SIZE 0x2000
 +
-+      /* Already connected? */
-+      if (blkif->be->dev->state == XenbusStateConnected)
-+              return;
++/* Calculate offset to page-mapped register block */
++#define FALCON_PAGED_REG(page, reg) \
++      ((page) * FALCON_PAGE_BLOCK_SIZE + (reg))
 +
-+      /* Attempt to connect: exit if we fail to. */
-+      connect(blkif->be);
-+      if (blkif->be->dev->state != XenbusStateConnected)
-+              return;
++/* As for falcon_write(), but for a page-mapped register. */
++static inline void falcon_write_page(struct efx_nic *efx, efx_oword_t *value,
++                                   unsigned int reg, unsigned int page)
++{
++      falcon_write(efx, value, FALCON_PAGED_REG(page, reg));
++}
 +
-+      err = blktap_name(blkif, name);
-+      if (err) {
-+              xenbus_dev_error(blkif->be->dev, err, "get blktap dev name");
-+              return;
-+      }
++/* As for falcon_writel(), but for a page-mapped register. */
++static inline void falcon_writel_page(struct efx_nic *efx, efx_dword_t *value,
++                                    unsigned int reg, unsigned int page)
++{
++      falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
++}
 +
-+      if (!blkif->be->group_added) {
-+              err = xentap_sysfs_addif(blkif->be->dev);
-+              if (err) {
-+                      xenbus_dev_fatal(blkif->be->dev, err, 
-+                                       "creating sysfs entries");
-+                      return;
-+              }
-+      }
++/* Write dword to Falcon page-mapped register with an extra lock.
++ *
++ * As for falcon_writel_page(), but for a register that suffers from
++ * SFC bug 3181. Take out a lock so the BIU collector cannot be
++ * confused. */
++static inline void falcon_writel_page_locked(struct efx_nic *efx,
++                                           efx_dword_t *value,
++                                           unsigned int reg,
++                                           unsigned int page)
++{
++      unsigned long flags __attribute__ ((unused));
 +
-+      blkif->xenblkd = kthread_run(tap_blkif_schedule, blkif, name);
-+      if (IS_ERR(blkif->xenblkd)) {
-+              err = PTR_ERR(blkif->xenblkd);
-+              blkif->xenblkd = NULL;
-+              xenbus_dev_fatal(blkif->be->dev, err, "start xenblkd");
-+              WPRINTK("Error starting thread\n");
-+      }
++      spin_lock_irqsave(&efx->biu_lock, flags);
++      falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
++      spin_unlock_irqrestore(&efx->biu_lock, flags);
 +}
 +
-+/**
-+ * Entry point to this code when a new device is created.  Allocate
-+ * the basic structures, and watch the store waiting for the
-+ * user-space program to tell us the physical device info.  Switch to
-+ * InitWait.
++#endif /* EFX_FALCON_IO_H */
+--- linux-2.6.18.8/drivers/net/sfc/falcon_xmac.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/falcon_xmac.c  2008-05-19 00:33:28.849809063 +0300
+@@ -0,0 +1,691 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
-+static int blktap_probe(struct xenbus_device *dev,
-+                       const struct xenbus_device_id *id)
-+{
-+      int err;
-+      struct backend_info *be = kzalloc(sizeof(struct backend_info),
-+                                        GFP_KERNEL);
-+      if (!be) {
-+              xenbus_dev_fatal(dev, -ENOMEM,
-+                               "allocating backend structure");
-+              return -ENOMEM;
-+      }
 +
-+      be->dev = dev;
-+      dev->dev.driver_data = be;
-+      be->xenbus_id = get_id(dev->nodename);
++#include <linux/delay.h>
++#include "net_driver.h"
++#include "efx.h"
++#include "falcon.h"
++#include "falcon_hwdefs.h"
++#include "falcon_io.h"
++#include "mac.h"
++#include "gmii.h"
++#include "mdio_10g.h"
++#include "phy.h"
++#include "boards.h"
++#include "workarounds.h"
 +
-+      be->blkif = tap_alloc_blkif(dev->otherend_id);
-+      if (IS_ERR(be->blkif)) {
-+              err = PTR_ERR(be->blkif);
-+              be->blkif = NULL;
-+              xenbus_dev_fatal(dev, err, "creating block interface");
-+              goto fail;
-+      }
++/**************************************************************************
++ *
++ * MAC register access
++ *
++ **************************************************************************/
 +
-+      /* setup back pointer */
-+      be->blkif->be = be;
-+      be->blkif->sectors = 0;
++/* Offset of an XMAC register within Falcon */
++#define FALCON_XMAC_REG(mac_reg)                                      \
++      (FALCON_XMAC_REGBANK + ((mac_reg) * FALCON_XMAC_REG_SIZE))
 +
-+      /* set a watch on disk info, waiting for userspace to update details*/
-+      err = xenbus_watch_path2(dev, dev->nodename, "info",
-+                               &be->backend_watch, tap_backend_changed);
-+      if (err)
-+              goto fail;
-+      
-+      err = xenbus_switch_state(dev, XenbusStateInitWait);
-+      if (err)
-+              goto fail;
-+      return 0;
++static void falcon_xmac_writel(struct efx_nic *efx,
++                             efx_dword_t *value, unsigned int mac_reg)
++{
++      efx_oword_t temp;
 +
-+fail:
-+      DPRINTK("blktap probe failed\n");
-+      blktap_remove(dev);
-+      return err;
++      EFX_POPULATE_OWORD_1(temp, MAC_DATA, EFX_DWORD_FIELD(*value, MAC_DATA));
++      falcon_write(efx, &temp, FALCON_XMAC_REG(mac_reg));
 +}
 +
-+
-+/**
-+ * Callback received when the user space code has placed the device
-+ * information in xenstore. 
-+ */
-+static void tap_backend_changed(struct xenbus_watch *watch,
-+                          const char **vec, unsigned int len)
++static void falcon_xmac_readl(struct efx_nic *efx,
++                            efx_dword_t *value, unsigned int mac_reg)
 +{
-+      int err;
-+      unsigned long info;
-+      struct backend_info *be
-+              = container_of(watch, struct backend_info, backend_watch);
-+      struct xenbus_device *dev = be->dev;
-+      
-+      /** 
-+       * Check to see whether userspace code has opened the image 
-+       * and written sector
-+       * and disk info to xenstore
-+       */
-+      err = xenbus_gather(XBT_NIL, dev->nodename, "info", "%lu", &info, 
-+                          NULL);
-+      if (XENBUS_EXIST_ERR(err))
-+              return;
-+      if (err) {
-+              xenbus_dev_error(dev, err, "getting info");
-+              return;
-+      }
++      efx_oword_t temp;
 +
-+      DPRINTK("Userspace update on disk info, %lu\n",info);
++      falcon_read(efx, &temp, FALCON_XMAC_REG(mac_reg));
++      EFX_POPULATE_DWORD_1(*value, MAC_DATA, EFX_OWORD_FIELD(temp, MAC_DATA));
++}
 +
-+      err = xenbus_gather(XBT_NIL, dev->nodename, "sectors", "%llu", 
-+                          &be->blkif->sectors, NULL);
++/**************************************************************************
++ *
++ * MAC operations
++ *
++ *************************************************************************/
++static int falcon_reset_xmac(struct efx_nic *efx)
++{
++      efx_dword_t reg;
++      int count;
 +
-+      /* Associate tap dev with domid*/
-+      be->blkif->dev_num = dom_to_devid(be->blkif->domid, be->xenbus_id, 
-+                                        be->blkif);
-+      DPRINTK("Thread started for domid [%d], connecting disk\n", 
-+              be->blkif->dev_num);
++      EFX_POPULATE_DWORD_1(reg, XM_CORE_RST, 1);
++      efx->mac_op->mac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
 +
-+      tap_update_blkif_status(be->blkif);
++      for (count = 0; count < 10000; count++) {       /* wait upto 100ms */
++              efx->mac_op->mac_readl(efx, &reg, XM_GLB_CFG_REG_MAC);
++              if (EFX_DWORD_FIELD(reg, XM_CORE_RST) == 0)
++                      return 0;
++              udelay(10);
++      }
++
++      EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
++      return -ETIMEDOUT;
 +}
 +
-+/**
-+ * Callback received when the frontend's state changes.
-+ */
-+static void tap_frontend_changed(struct xenbus_device *dev,
-+                           enum xenbus_state frontend_state)
++/* Configure the XAUI driver that is an output from Falcon */
++static void falcon_setup_xaui(struct efx_nic *efx)
 +{
-+      struct backend_info *be = dev->dev.driver_data;
-+      int err;
++      efx_dword_t sdctl, txdrv;
 +
-+      DPRINTK("\n");
++      /* Move the XAUI into low power, unless there is no PHY, in
++       * which case the XAUI will have to drive a cable. */
++      if (efx->phy_type == PHY_TYPE_NONE)
++              return;
 +
-+      switch (frontend_state) {
-+      case XenbusStateInitialising:
-+              if (dev->state == XenbusStateClosed) {
-+                      printk(KERN_INFO "%s: %s: prepare for reconnect\n",
-+                             __FUNCTION__, dev->nodename);
-+                      xenbus_switch_state(dev, XenbusStateInitWait);
-+              }
-+              break;
++      efx->mac_op->mac_readl(efx, &sdctl, XX_SD_CTL_REG_MAC);
++      EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVD, XX_SD_CTL_DRV_DEFAULT);
++      EFX_SET_DWORD_FIELD(sdctl, XX_LODRVD, XX_SD_CTL_DRV_DEFAULT);
++      EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVC, XX_SD_CTL_DRV_DEFAULT);
++      EFX_SET_DWORD_FIELD(sdctl, XX_LODRVC, XX_SD_CTL_DRV_DEFAULT);
++      EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVB, XX_SD_CTL_DRV_DEFAULT);
++      EFX_SET_DWORD_FIELD(sdctl, XX_LODRVB, XX_SD_CTL_DRV_DEFAULT);
++      EFX_SET_DWORD_FIELD(sdctl, XX_HIDRVA, XX_SD_CTL_DRV_DEFAULT);
++      EFX_SET_DWORD_FIELD(sdctl, XX_LODRVA, XX_SD_CTL_DRV_DEFAULT);
++      efx->mac_op->mac_writel(efx, &sdctl, XX_SD_CTL_REG_MAC);
++
++      EFX_POPULATE_DWORD_8(txdrv,
++                           XX_DEQD, XX_TXDRV_DEQ_DEFAULT,
++                           XX_DEQC, XX_TXDRV_DEQ_DEFAULT,
++                           XX_DEQB, XX_TXDRV_DEQ_DEFAULT,
++                           XX_DEQA, XX_TXDRV_DEQ_DEFAULT,
++                           XX_DTXD, XX_TXDRV_DTX_DEFAULT,
++                           XX_DTXC, XX_TXDRV_DTX_DEFAULT,
++                           XX_DTXB, XX_TXDRV_DTX_DEFAULT,
++                           XX_DTXA, XX_TXDRV_DTX_DEFAULT);
++      efx->mac_op->mac_writel(efx, &txdrv, XX_TXDRV_CTL_REG_MAC);
++}
++
++static void falcon_hold_xaui_in_rst(struct efx_nic *efx)
++{
++      efx_dword_t reg;
++
++      EFX_ZERO_DWORD(reg);
++      EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 1);
++      EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 1);
++      EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 1);
++      EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 1);
++      EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 1);
++      EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 1);
++      EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 1);
++      EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 1);
++      EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 1);
++      EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 1);
++      EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
++      EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
++      efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
++      udelay(10);
++}
++
++static int _falcon_reset_xaui_a(struct efx_nic *efx)
++{
++      efx_dword_t reg;
++
++      if (!efx->is_asic)
++              return 0;
 +
-+      case XenbusStateInitialised:
-+      case XenbusStateConnected:
-+              /* Ensure we connect even when two watches fire in 
-+                 close successsion and we miss the intermediate value 
-+                 of frontend_state. */
-+              if (dev->state == XenbusStateConnected)
-+                      break;
++      falcon_hold_xaui_in_rst(efx);
++      efx->mac_op->mac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
 +
-+              err = connect_ring(be);
-+              if (err)
-+                      break;
-+              tap_update_blkif_status(be->blkif);
-+              break;
++      /* Follow the RAMBUS XAUI data reset sequencing
++       * Channels A and B first: power down, reset PLL, reset, clear
++       */
++      EFX_SET_DWORD_FIELD(reg, XX_PWRDNA_EN, 0);
++      EFX_SET_DWORD_FIELD(reg, XX_PWRDNB_EN, 0);
++      efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
++      udelay(10);
 +
-+      case XenbusStateClosing:
-+              if (be->blkif->xenblkd) {
-+                      kthread_stop(be->blkif->xenblkd);
-+                      be->blkif->xenblkd = NULL;
-+              }
-+              xenbus_switch_state(dev, XenbusStateClosing);
-+              break;
++      EFX_SET_DWORD_FIELD(reg, XX_RSTPLLAB_EN, 0);
++      efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
++      udelay(10);
 +
-+      case XenbusStateClosed:
-+              xenbus_switch_state(dev, XenbusStateClosed);
-+              if (xenbus_dev_is_online(dev))
-+                      break;
-+              /* fall through if not online */
-+      case XenbusStateUnknown:
-+              device_unregister(&dev->dev);
-+              break;
++      EFX_SET_DWORD_FIELD(reg, XX_RESETA_EN, 0);
++      EFX_SET_DWORD_FIELD(reg, XX_RESETB_EN, 0);
++      efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
++      udelay(10);
 +
-+      default:
-+              xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
-+                               frontend_state);
-+              break;
-+      }
-+}
++      /* Channels C and D: power down, reset PLL, reset, clear */
++      EFX_SET_DWORD_FIELD(reg, XX_PWRDNC_EN, 0);
++      EFX_SET_DWORD_FIELD(reg, XX_PWRDND_EN, 0);
++      efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
++      udelay(10);
 +
++      EFX_SET_DWORD_FIELD(reg, XX_RSTPLLCD_EN, 0);
++      efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
++      udelay(10);
 +
-+/**
-+ * Switch to Connected state.
-+ */
-+static void connect(struct backend_info *be)
-+{
-+      int err;
++      EFX_SET_DWORD_FIELD(reg, XX_RESETC_EN, 0);
++      EFX_SET_DWORD_FIELD(reg, XX_RESETD_EN, 0);
++      efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
++      udelay(10);
 +
-+      struct xenbus_device *dev = be->dev;
++      /* Setup XAUI */
++      falcon_setup_xaui(efx);
++      udelay(10);
 +
-+      err = xenbus_switch_state(dev, XenbusStateConnected);
-+      if (err)
-+              xenbus_dev_fatal(dev, err, "switching to Connected state",
-+                               dev->nodename);
++      /* Take XGXS out of reset */
++      EFX_ZERO_DWORD(reg);
++      efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
++      udelay(10);
 +
-+      return;
++      return 0;
 +}
 +
-+
-+static int connect_ring(struct backend_info *be)
++static int _falcon_reset_xaui_b(struct efx_nic *efx)
 +{
-+      struct xenbus_device *dev = be->dev;
-+      unsigned long ring_ref;
-+      unsigned int evtchn;
-+      char protocol[64];
-+      int err;
++      efx_dword_t reg;
++      int count;
 +
-+      DPRINTK("%s\n", dev->otherend);
++      if (!efx->is_asic)
++              return 0;
 +
-+      err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", 
-+                          &ring_ref, "event-channel", "%u", &evtchn, NULL);
-+      if (err) {
-+              xenbus_dev_fatal(dev, err,
-+                               "reading %s/ring-ref and event-channel",
-+                               dev->otherend);
-+              return err;
-+      }
++      EFX_POPULATE_DWORD_1(reg, XX_RST_XX_EN, 1);
++      efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
 +
-+      be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
-+      err = xenbus_gather(XBT_NIL, dev->otherend, "protocol",
-+                          "%63s", protocol, NULL);
-+      if (err)
-+              strcpy(protocol, "unspecified, assuming native");
-+      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE))
-+              be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
-+      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
-+              be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32;
-+      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64))
-+              be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64;
-+      else {
-+              xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol);
-+              return -1;
++      /* Give some time for the link to establish */
++      for (count = 0; count < 1000; count++) { /* wait upto 10ms */
++              efx->mac_op->mac_readl(efx, &reg, XX_PWR_RST_REG_MAC);
++              if (EFX_DWORD_FIELD(reg, XX_RST_XX_EN) == 0) {
++                      falcon_setup_xaui(efx);
++                      return 0;
++              }
++              udelay(10);
 +      }
-+      printk(KERN_INFO
-+             "blktap: ring-ref %ld, event-channel %d, protocol %d (%s)\n",
-+             ring_ref, evtchn, be->blkif->blk_protocol, protocol);
++      EFX_ERR(efx, "timed out waiting for XAUI/XGXS reset\n");
++      return -ETIMEDOUT;
++}
 +
-+      /* Map the shared frame, irq etc. */
-+      err = tap_blkif_map(be->blkif, ring_ref, evtchn);
-+      if (err) {
-+              xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
-+                               ring_ref, evtchn);
-+              return err;
-+      } 
++int falcon_reset_xaui(struct efx_nic *efx)
++{
++      int rc;
 +
-+      return 0;
++      if (EFX_WORKAROUND_9388(efx)) {
++              falcon_hold_xaui_in_rst(efx);
++              efx->phy_op->reset_xaui(efx);
++              rc = _falcon_reset_xaui_a(efx);
++      } else {
++              rc = _falcon_reset_xaui_b(efx);
++      }
++      return rc;
 +}
 +
++static int falcon_init_xmac(struct efx_nic *efx)
++{
++      int rc;
 +
-+/* ** Driver Registration ** */
-+
++      /* Initialize the PHY first so the clock is around */
++      rc = efx->phy_op->init(efx);
++      if (rc)
++              goto fail1;
 +
-+static struct xenbus_device_id blktap_ids[] = {
-+      { "tap" },
-+      { "" }
-+};
++      rc = falcon_reset_xaui(efx);
++      if (rc)
++              goto fail2;
 +
++      /* Wait again. Give the PHY and MAC time to faff */
++      schedule_timeout_uninterruptible(HZ / 10);
 +
-+static struct xenbus_driver blktap = {
-+      .name = "tap",
-+      .owner = THIS_MODULE,
-+      .ids = blktap_ids,
-+      .probe = blktap_probe,
-+      .remove = blktap_remove,
-+      .otherend_changed = tap_frontend_changed
-+};
++      /* Reset the MAC */
++      rc = falcon_reset_xmac(efx);
++      if (rc)
++              goto fail2;
 +
++      return 0;
 +
-+void tap_blkif_xenbus_init(void)
-+{
-+      xenbus_register_backend(&blktap);
++ fail2:
++      efx->phy_op->fini(efx);
++ fail1:
++      return rc;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/char/Makefile linux-2.6.18-xen.hg/drivers/xen/char/Makefile
---- linux-2.6.18/drivers/xen/char/Makefile     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/char/Makefile      2007-12-23 11:15:33.547908998 +0100
-@@ -0,0 +1 @@
-+obj-$(CONFIG_XEN_DEVMEM)      := mem.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/char/mem.c linux-2.6.18-xen.hg/drivers/xen/char/mem.c
---- linux-2.6.18/drivers/xen/char/mem.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/char/mem.c 2007-12-23 11:15:33.551242507 +0100
-@@ -0,0 +1,190 @@
-+/*
-+ *  Originally from linux/drivers/char/mem.c
-+ *
-+ *  Copyright (C) 1991, 1992  Linus Torvalds
-+ *
-+ *  Added devfs support. 
-+ *    Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
-+ *  Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
-+ */
-+
-+#include <linux/mm.h>
-+#include <linux/miscdevice.h>
-+#include <linux/slab.h>
-+#include <linux/vmalloc.h>
-+#include <linux/mman.h>
-+#include <linux/random.h>
-+#include <linux/init.h>
-+#include <linux/raw.h>
-+#include <linux/tty.h>
-+#include <linux/capability.h>
-+#include <linux/smp_lock.h>
-+#include <linux/ptrace.h>
-+#include <linux/device.h>
-+#include <asm/pgalloc.h>
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <asm/hypervisor.h>
 +
-+static inline int uncached_access(struct file *file)
++/* Get status of XAUI link */
++int falcon_xaui_link_ok(struct efx_nic *efx)
 +{
-+      if (file->f_flags & O_SYNC)
++      efx_dword_t reg;
++      int align_done;
++      int sync_status;
++      int link_ok = 0;
++
++      /* If we're in internal loopback, then the link is up.
++       * The A1 FPGA/4G has RX and TX XAUI wired together, so the link is up.
++       * The B0 FPGA has XAUI offchip, so it is always up.
++       */
++      if (!efx->is_asic || LOOPBACK_INTERNAL(efx))
 +              return 1;
-+      /* Xen sets correct MTRR type on non-RAM for us. */
-+      return 0;
-+}
 +
-+/*
-+ * This funcion reads the *physical* memory. The f_pos points directly to the 
-+ * memory location. 
-+ */
-+static ssize_t read_mem(struct file * file, char __user * buf,
-+                      size_t count, loff_t *ppos)
-+{
-+      unsigned long p = *ppos, ignored;
-+      ssize_t read = 0, sz;
-+      void __iomem *v;
++      /* Read link status */
++      efx->mac_op->mac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
++
++      align_done = EFX_DWORD_FIELD(reg, XX_ALIGN_DONE);
++      sync_status = EFX_DWORD_FIELD(reg, XX_SYNC_STAT);
++      if (align_done && (sync_status == XX_SYNC_STAT_DECODE_SYNCED))
++              link_ok = 1;
++
++      /* Clear link status ready for next read */
++      EFX_SET_DWORD_FIELD(reg, XX_COMMA_DET, XX_COMMA_DET_RESET);
++      EFX_SET_DWORD_FIELD(reg, XX_CHARERR, XX_CHARERR_RESET);
++      EFX_SET_DWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET);
++
++      efx->mac_op->mac_writel(efx, &reg, XX_CORE_STAT_REG_MAC);
++
++      return link_ok;
++}
++
++/* Do most of the heavy lifting of falcon_reconfigure_xmac */
++static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
++{
++      unsigned int max_frame_len;
++      efx_dword_t reg;
++      efx_oword_t mac_test_reg;
++      int rx_fc = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
++
++      if (FALCON_REV(efx) <= FALCON_REV_A1 && !efx->is_asic) {
++              /* 10G FPGA's have the XAUI TX and RX wired together. Fake
++               * the link status and configure the link options before
++               * the MAC wrapper is configured */
++              efx->link_options = GM_LPA_10000FULL;
++              efx->link_up = 1;
++      }
++
++      /* Configure MAC  - cut-thru mode is hard wired on */
++      EFX_POPULATE_DWORD_3(reg,
++                           XM_RX_JUMBO_MODE, 1,
++                           XM_TX_STAT_EN, 1,
++                           XM_RX_STAT_EN, 1);
++      efx->mac_op->mac_writel(efx, &reg, XM_GLB_CFG_REG_MAC);
++
++      /* Configure TX */
++      EFX_POPULATE_DWORD_6(reg,
++                           XM_TXEN, 1,
++                           XM_TX_PRMBL, 1,
++                           XM_AUTO_PAD, 1,
++                           XM_TXCRC, 1,
++                           XM_FCNTL, 1,
++                           XM_IPG, 0x3);
++      efx->mac_op->mac_writel(efx, &reg, XM_TX_CFG_REG_MAC);
++
++      /* Configure RX */
++      EFX_POPULATE_DWORD_5(reg,
++                           XM_RXEN, 1,
++                           XM_AUTO_DEPAD, 0,
++                           XM_ACPT_ALL_MCAST, 1,
++                           XM_ACPT_ALL_UCAST, efx->promiscuous,
++                           XM_PASS_CRC_ERR, 1);
++      efx->mac_op->mac_writel(efx, &reg, XM_RX_CFG_REG_MAC);
++
++      /* Set frame length */
++      max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
++      EFX_POPULATE_DWORD_1(reg, XM_MAX_RX_FRM_SIZE, max_frame_len);
++      efx->mac_op->mac_writel(efx, &reg, XM_RX_PARAM_REG_MAC);
++      EFX_POPULATE_DWORD_2(reg,
++                           XM_MAX_TX_FRM_SIZE, max_frame_len,
++                           XM_TX_JUMBO_MODE, 1);
++      efx->mac_op->mac_writel(efx, &reg, XM_TX_PARAM_REG_MAC);
++
++      EFX_POPULATE_DWORD_2(reg,
++                           XM_PAUSE_TIME, 0xfffe, /* MAX PAUSE TIME */
++                           XM_DIS_FCNTL, rx_fc ? 0 : 1);
++      efx->mac_op->mac_writel(efx, &reg, XM_FC_REG_MAC);
++
++      /* Set MAC address */
++      EFX_POPULATE_DWORD_4(reg,
++                           XM_ADR_0, efx->net_dev->dev_addr[0],
++                           XM_ADR_1, efx->net_dev->dev_addr[1],
++                           XM_ADR_2, efx->net_dev->dev_addr[2],
++                           XM_ADR_3, efx->net_dev->dev_addr[3]);
++      efx->mac_op->mac_writel(efx, &reg, XM_ADR_LO_REG_MAC);
++      EFX_POPULATE_DWORD_2(reg,
++                           XM_ADR_4, efx->net_dev->dev_addr[4],
++                           XM_ADR_5, efx->net_dev->dev_addr[5]);
++      efx->mac_op->mac_writel(efx, &reg, XM_ADR_HI_REG_MAC);
++
++      /* Handle B0 FPGA loopback where RAMBUS XGXS block not present */
++      if (FALCON_REV(efx) == FALCON_REV_B0 && !efx->is_asic) {
++              int xgmii_loopback =
++                      (efx->loopback_mode == LOOPBACK_XGMII) ? 1 : 0;
++
++              /* Set the MAC loopback bit. */
++              EFX_POPULATE_OWORD_1(mac_test_reg,
++                                   MAC_PTLOOP_EN, xgmii_loopback);
++              falcon_write(efx, &mac_test_reg, MAC_TEST_REG_KER);
++      }
++}
++
++/* Do most of the heavy lifting of falcon_reconfigure_xmac */
++static void falcon_reconfigure_xgxs_core(struct efx_nic *efx)
++{
++      efx_dword_t reg;
++      int xgxs_loopback = (efx->loopback_mode == LOOPBACK_XGXS) ? 1 : 0;
++      int xaui_loopback = (efx->loopback_mode == LOOPBACK_XAUI) ? 1 : 0;
++      int xgmii_loopback =
++              (efx->loopback_mode == LOOPBACK_XGMII) ? 1 : 0;
++
++      if (FALCON_REV(efx) == FALCON_REV_B0 && !efx->is_asic)
++              /* RAMBUS XGXS block is not present */
++              return;
 +
-+      while (count > 0) {
-+              /*
-+               * Handle first page in case it's not aligned
-+               */
-+              if (-p & (PAGE_SIZE - 1))
-+                      sz = -p & (PAGE_SIZE - 1);
-+              else
-+                      sz = PAGE_SIZE;
++      /* XGXS block is flaky and will need to be reset if moving
++       * into our out of XGMII, XGXS or XAUI loopbacks. */
++      if (EFX_WORKAROUND_5147(efx)) {
++              int old_xgmii_loopback, old_xgxs_loopback, old_xaui_loopback;
++              int reset_xgxs;
++
++              efx->mac_op->mac_readl(efx, &reg,
++                                          XX_CORE_STAT_REG_MAC);
++              old_xgxs_loopback = EFX_DWORD_FIELD(reg, XX_XGXS_LB_EN);
++              old_xgmii_loopback = EFX_DWORD_FIELD(reg, XX_XGMII_LB_EN);
++
++              efx->mac_op->mac_readl(efx, &reg, XX_SD_CTL_REG_MAC);
++              old_xaui_loopback = EFX_DWORD_FIELD(reg, XX_LPBKA);
++
++              /* The PHY driver may have turned XAUI off */
++              reset_xgxs = ((xgxs_loopback != old_xgxs_loopback) ||
++                            (xaui_loopback != old_xaui_loopback) ||
++                            (xgmii_loopback != old_xgmii_loopback));
++              if (reset_xgxs) {
++                      efx->mac_op->mac_readl(efx, &reg,
++                                                  XX_PWR_RST_REG_MAC);
++                      EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 1);
++                      EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 1);
++                      efx->mac_op->mac_writel(efx, &reg,
++                                                   XX_PWR_RST_REG_MAC);
++                      udelay(1);
++                      EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSTX_EN, 0);
++                      EFX_SET_DWORD_FIELD(reg, XX_RSTXGXSRX_EN, 0);
++                      efx->mac_op->mac_writel(efx, &reg,
++                                                   XX_PWR_RST_REG_MAC);
++                      udelay(1);
++              }
++      }
++
++      efx->mac_op->mac_readl(efx, &reg, XX_CORE_STAT_REG_MAC);
++      EFX_SET_DWORD_FIELD(reg, XX_FORCE_SIG,
++                          (xgxs_loopback || xaui_loopback) ?
++                          XX_FORCE_SIG_DECODE_FORCED : 0);
++      EFX_SET_DWORD_FIELD(reg, XX_XGXS_LB_EN, xgxs_loopback);
++      EFX_SET_DWORD_FIELD(reg, XX_XGMII_LB_EN, xgmii_loopback);
++      efx->mac_op->mac_writel(efx, &reg, XX_CORE_STAT_REG_MAC);
++
++      efx->mac_op->mac_readl(efx, &reg, XX_SD_CTL_REG_MAC);
++      EFX_SET_DWORD_FIELD(reg, XX_LPBKD, xaui_loopback);
++      EFX_SET_DWORD_FIELD(reg, XX_LPBKC, xaui_loopback);
++      EFX_SET_DWORD_FIELD(reg, XX_LPBKB, xaui_loopback);
++      EFX_SET_DWORD_FIELD(reg, XX_LPBKA, xaui_loopback);
++      efx->mac_op->mac_writel(efx, &reg, XX_SD_CTL_REG_MAC);
++}
++
++
++/* Sometimes the XAUI link between Falcon and XFP fails to come up. The state
++ * of the link is checked during phy_reconfigure(). After XAIU is reset then
++ * the MAC must be reconfigured.
++ */
++#define MAX_XAUI_TRIES (5)    /* It's never been seen to take more than 2 */
++
++void falcon_check_xaui_link_up(struct efx_nic *efx)
++{
++      int max_tries, tries;
++      tries = EFX_WORKAROUND_5147(efx) ? MAX_XAUI_TRIES : 1;
++      max_tries = tries;
++
++      if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
++          (efx->phy_type == PHY_TYPE_NONE) ||
++          !efx->phy_powered)
++              return;
 +
-+              sz = min_t(unsigned long, sz, count);
++      while (tries) {
++              if (falcon_xaui_link_ok(efx))
++                      return;
 +
-+              v = ioremap(p, sz);
-+              if (IS_ERR(v) || v == NULL) {
-+                      /*
-+                       * Some programs (e.g., dmidecode) groove off into
-+                       * weird RAM areas where no tables can possibly exist
-+                       * (because Xen will have stomped on them!). These
-+                       * programs get rather upset if we let them know that
-+                       * Xen failed their access, so we fake out a read of
-+                       * all zeroes.
-+                       */
-+                      if (clear_user(buf, count))
-+                              return -EFAULT;
-+                      read += count;
-+                      break;
-+              }
++              EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n",
++                      __func__, tries);
++              (void) falcon_reset_xaui(efx);
++              /* Cannot use full reconfigure. Need to avoid recursion */
 +
-+              ignored = copy_to_user(buf, v, sz);
-+              iounmap(v);
-+              if (ignored)
-+                      return -EFAULT;
-+              buf += sz;
-+              p += sz;
-+              count -= sz;
-+              read += sz;
++              /* Give the poor thing time to sort itself out: if we retry
++               * too fast it will never train. */
++              udelay(200);
++
++              falcon_reconfigure_xgxs_core(efx);
++
++              tries--;
 +      }
 +
-+      *ppos += read;
-+      return read;
++      EFX_ERR(efx, "Failed to bring XAUI link back up in %d tries!\n",
++              max_tries);
 +}
 +
-+static ssize_t write_mem(struct file * file, const char __user * buf, 
-+                       size_t count, loff_t *ppos)
++static void falcon_reconfigure_xmac(struct efx_nic *efx)
 +{
-+      unsigned long p = *ppos, ignored;
-+      ssize_t written = 0, sz;
-+      void __iomem *v;
++      falcon_deconfigure_mac_wrapper(efx);
 +
-+      while (count > 0) {
-+              /*
-+               * Handle first page in case it's not aligned
-+               */
-+              if (-p & (PAGE_SIZE - 1))
-+                      sz = -p & (PAGE_SIZE - 1);
-+              else
-+                      sz = PAGE_SIZE;
++      /* In internal loopback modes disable transmit */
++      efx->tx_disabled = LOOPBACK_INTERNAL(efx);
 +
-+              sz = min_t(unsigned long, sz, count);
++      efx->phy_op->reconfigure(efx);
 +
-+              v = ioremap(p, sz);
-+              if (v == NULL)
-+                      break;
-+              if (IS_ERR(v)) {
-+                      if (written == 0)
-+                              return PTR_ERR(v);
-+                      break;
-+              }
++      falcon_reconfigure_xgxs_core(efx);
++      falcon_reconfigure_xmac_core(efx);
 +
-+              ignored = copy_from_user(v, buf, sz);
-+              iounmap(v);
-+              if (ignored) {
-+                      written += sz - ignored;
-+                      if (written)
-+                              break;
-+                      return -EFAULT;
-+              }
-+              buf += sz;
-+              p += sz;
-+              count -= sz;
-+              written += sz;
-+      }
++      /* Reconfigure MAC wrapper */
++      falcon_reconfigure_mac_wrapper(efx);
 +
-+      *ppos += written;
-+      return written;
++      /* Ensure XAUI link is up - might repeat reconfigure_xmac_core */
++      falcon_check_xaui_link_up(efx);
 +}
 +
-+#ifndef ARCH_HAS_DEV_MEM_MMAP_MEM
-+static int xen_mmap_mem(struct file * file, struct vm_area_struct * vma)
++static void falcon_fini_xmac(struct efx_nic *efx)
 +{
-+      size_t size = vma->vm_end - vma->vm_start;
-+
-+      if (uncached_access(file))
-+              vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++      /* Isolate the MAC - PHY */
++      falcon_deconfigure_mac_wrapper(efx);
 +
-+      /* We want to return the real error code, not EAGAIN. */
-+      return direct_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
-+                                    size, vma->vm_page_prot, DOMID_IO);
++      /* Potentially power down the PHY */
++      efx->phy_op->fini(efx);
 +}
-+#endif
 +
-+/*
-+ * The memory devices use the full 32/64 bits of the offset, and so we cannot
-+ * check against negative addresses: they are ok. The return value is weird,
-+ * though, in that case (0).
-+ *
-+ * also note that seeking relative to the "end of file" isn't supported:
-+ * it has no meaning, so it returns -EINVAL.
-+ */
-+static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
++static void falcon_update_stats_xmac(struct efx_nic *efx)
 +{
-+      loff_t ret;
++      struct efx_mac_stats *mac_stats = &efx->mac_stats;
++      int rc;
 +
-+      mutex_lock(&file->f_dentry->d_inode->i_mutex);
-+      switch (orig) {
-+              case 0:
-+                      file->f_pos = offset;
-+                      ret = file->f_pos;
-+                      force_successful_syscall_return();
-+                      break;
-+              case 1:
-+                      file->f_pos += offset;
-+                      ret = file->f_pos;
-+                      force_successful_syscall_return();
-+                      break;
-+              default:
-+                      ret = -EINVAL;
++      rc = falcon_dma_stats(efx, XgDmaDone_offset);
++      if (rc)
++              return;
++
++      /* Update MAC stats from DMAed values */
++      FALCON_STAT(efx, XgRxOctets, rx_bytes);
++      FALCON_STAT(efx, XgRxOctetsOK, rx_good_bytes);
++      FALCON_STAT(efx, XgRxPkts, rx_packets);
++      FALCON_STAT(efx, XgRxPktsOK, rx_good);
++      FALCON_STAT(efx, XgRxBroadcastPkts, rx_broadcast);
++      FALCON_STAT(efx, XgRxMulticastPkts, rx_multicast);
++      FALCON_STAT(efx, XgRxUnicastPkts, rx_unicast);
++      FALCON_STAT(efx, XgRxUndersizePkts, rx_lt64);
++      FALCON_STAT(efx, XgRxOversizePkts, rx_gtjumbo);
++      FALCON_STAT(efx, XgRxJabberPkts, rx_bad_gtjumbo);
++      FALCON_STAT(efx, XgRxUndersizeFCSerrorPkts, rx_bad_lt64);
++      FALCON_STAT(efx, XgRxDropEvents, rx_overflow);
++      FALCON_STAT(efx, XgRxFCSerrorPkts, rx_bad);
++      FALCON_STAT(efx, XgRxAlignError, rx_align_error);
++      FALCON_STAT(efx, XgRxSymbolError, rx_symbol_error);
++      FALCON_STAT(efx, XgRxInternalMACError, rx_internal_error);
++      FALCON_STAT(efx, XgRxControlPkts, rx_control);
++      FALCON_STAT(efx, XgRxPausePkts, rx_pause);
++      FALCON_STAT(efx, XgRxPkts64Octets, rx_64);
++      FALCON_STAT(efx, XgRxPkts65to127Octets, rx_65_to_127);
++      FALCON_STAT(efx, XgRxPkts128to255Octets, rx_128_to_255);
++      FALCON_STAT(efx, XgRxPkts256to511Octets, rx_256_to_511);
++      FALCON_STAT(efx, XgRxPkts512to1023Octets, rx_512_to_1023);
++      FALCON_STAT(efx, XgRxPkts1024to15xxOctets, rx_1024_to_15xx);
++      FALCON_STAT(efx, XgRxPkts15xxtoMaxOctets, rx_15xx_to_jumbo);
++      FALCON_STAT(efx, XgRxLengthError, rx_length_error);
++      FALCON_STAT(efx, XgTxPkts, tx_packets);
++      FALCON_STAT(efx, XgTxOctets, tx_bytes);
++      FALCON_STAT(efx, XgTxMulticastPkts, tx_multicast);
++      FALCON_STAT(efx, XgTxBroadcastPkts, tx_broadcast);
++      FALCON_STAT(efx, XgTxUnicastPkts, tx_unicast);
++      FALCON_STAT(efx, XgTxControlPkts, tx_control);
++      FALCON_STAT(efx, XgTxPausePkts, tx_pause);
++      FALCON_STAT(efx, XgTxPkts64Octets, tx_64);
++      FALCON_STAT(efx, XgTxPkts65to127Octets, tx_65_to_127);
++      FALCON_STAT(efx, XgTxPkts128to255Octets, tx_128_to_255);
++      FALCON_STAT(efx, XgTxPkts256to511Octets, tx_256_to_511);
++      FALCON_STAT(efx, XgTxPkts512to1023Octets, tx_512_to_1023);
++      FALCON_STAT(efx, XgTxPkts1024to15xxOctets, tx_1024_to_15xx);
++      FALCON_STAT(efx, XgTxPkts1519toMaxOctets, tx_15xx_to_jumbo);
++      FALCON_STAT(efx, XgTxUndersizePkts, tx_lt64);
++      FALCON_STAT(efx, XgTxOversizePkts, tx_gtjumbo);
++      FALCON_STAT(efx, XgTxNonTcpUdpPkt, tx_non_tcpudp);
++      FALCON_STAT(efx, XgTxMacSrcErrPkt, tx_mac_src_error);
++      FALCON_STAT(efx, XgTxIpSrcErrPkt, tx_ip_src_error);
++
++      /* Update derived statistics */
++      mac_stats->tx_good_bytes =
++              (mac_stats->tx_bytes - mac_stats->tx_bad_bytes);
++      mac_stats->rx_bad_bytes =
++              (mac_stats->rx_bytes - mac_stats->rx_good_bytes);
++}
++
++#define EFX_XAUI_RETRAIN_MAX 8
++
++static int falcon_check_xmac(struct efx_nic *efx)
++{
++      unsigned link_ok, phyxs_ok = 1;
++      unsigned has_phyxs = efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS);
++
++      /* Check the remote XAUI link status */
++      link_ok = falcon_xaui_link_ok(efx);
++
++      if ((efx->loopback_mode == LOOPBACK_NETWORK) ||
++          !efx->phy_powered)
++              return 0;
++
++      if (link_ok && has_phyxs && !LOOPBACK_INTERNAL(efx)) {
++              /* Does the PHYXS think we have lane sync? */
++              phyxs_ok = mdio_clause45_phyxgxs_lane_sync(efx);
 +      }
-+      mutex_unlock(&file->f_dentry->d_inode->i_mutex);
-+      return ret;
++
++      if (EFX_WORKAROUND_5147(efx) && (!link_ok || !phyxs_ok)) {
++              (void) falcon_reset_xaui(efx);
++              falcon_reconfigure_xgxs_core(efx);
++      }
++
++      /* Call the PHY check_hw routine */
++      efx->phy_op->check_hw(efx);
++      return 0;
 +}
 +
-+static int open_mem(struct inode * inode, struct file * filp)
++/* Simulate a PHY event */
++static void falcon_xmac_sim_phy_event(struct efx_nic *efx)
 +{
-+      return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
-+}
++      efx_qword_t phy_event;
 +
-+const struct file_operations mem_fops = {
-+      .llseek         = memory_lseek,
-+      .read           = read_mem,
-+      .write          = write_mem,
-+      .mmap           = xen_mmap_mem,
-+      .open           = open_mem,
-+};
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/console/console.c linux-2.6.18-xen.hg/drivers/xen/console/console.c
---- linux-2.6.18/drivers/xen/console/console.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/console/console.c  2007-12-23 11:15:33.551242507 +0100
-@@ -0,0 +1,731 @@
-+/******************************************************************************
-+ * console.c
-+ * 
-+ * Virtual console driver.
-+ * 
-+ * Copyright (c) 2002-2004, K A Fraser.
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
++      EFX_POPULATE_QWORD_2(phy_event,
++                           EV_CODE, GLOBAL_EV_DECODE,
++                           XG_PHY_INTR, 1);
++      falcon_generate_event(&efx->channel[0], &phy_event);
++}
 +
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/signal.h>
-+#include <linux/sched.h>
-+#include <linux/interrupt.h>
-+#include <linux/tty.h>
-+#include <linux/tty_flip.h>
-+#include <linux/serial.h>
-+#include <linux/major.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+#include <linux/init.h>
-+#include <linux/console.h>
-+#include <linux/bootmem.h>
-+#include <linux/sysrq.h>
-+#include <linux/screen_info.h>
-+#include <linux/vt.h>
-+#include <asm/io.h>
-+#include <asm/irq.h>
-+#include <asm/uaccess.h>
-+#include <xen/interface/xen.h>
-+#include <xen/interface/event_channel.h>
-+#include <asm/hypervisor.h>
-+#include <xen/evtchn.h>
-+#include <xen/xenbus.h>
-+#include <xen/xencons.h>
++static int falcon_xmac_get_settings(struct efx_nic *efx,
++                                  struct ethtool_cmd *ecmd)
++{
++      mdio_clause45_get_settings(efx, ecmd);
++      ecmd->transceiver = XCVR_INTERNAL;
++      ecmd->phy_address = efx->mii.phy_id;
++      ecmd->autoneg = AUTONEG_DISABLE;
++      ecmd->duplex = DUPLEX_FULL;
++      return 0;
++}
 +
-+/*
-+ * Modes:
-+ *  'xencons=off'  [XC_OFF]:     Console is disabled.
-+ *  'xencons=tty'  [XC_TTY]:     Console attached to '/dev/tty[0-9]+'.
-+ *  'xencons=ttyS' [XC_SERIAL]:  Console attached to '/dev/ttyS[0-9]+'.
-+ *  'xencons=xvc'  [XC_XVC]:     Console attached to '/dev/xvc0'.
-+ *  default:                     XC_XVC
-+ * 
-+ * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
-+ * warnings from standard distro startup scripts.
-+ */
-+static enum {
-+      XC_OFF, XC_TTY, XC_SERIAL, XC_XVC
-+} xc_mode = XC_XVC;
-+static int xc_num = -1;
++static int falcon_xmac_set_settings(struct efx_nic *efx,
++                                  struct ethtool_cmd *ecmd)
++{
++      if (ecmd->transceiver != XCVR_INTERNAL)
++              return -EINVAL;
++      if (ecmd->autoneg != AUTONEG_DISABLE)
++              return -EINVAL;
++      if (ecmd->duplex != DUPLEX_FULL)
++              return -EINVAL;
 +
-+/* /dev/xvc0 device number allocated by lanana.org. */
-+#define XEN_XVC_MAJOR 204
-+#define XEN_XVC_MINOR 191
++      return mdio_clause45_set_settings(efx, ecmd);
++}
 +
-+#ifdef CONFIG_MAGIC_SYSRQ
-+static unsigned long sysrq_requested;
-+extern int sysrq_enabled;
-+#endif
 +
-+static int __init xencons_setup(char *str)
++static int falcon_xmac_set_pause(struct efx_nic *efx,
++                               enum efx_fc_type flow_control)
 +{
-+      char *q;
-+      int n;
-+      extern int console_use_vt;
++      int reset;
 +
-+      console_use_vt = 1;
-+      if (!strncmp(str, "ttyS", 4)) {
-+              xc_mode = XC_SERIAL;
-+              str += 4;
-+      } else if (!strncmp(str, "tty", 3)) {
-+              xc_mode = XC_TTY;
-+              str += 3;
-+              console_use_vt = 0;
-+      } else if (!strncmp(str, "xvc", 3)) {
-+              xc_mode = XC_XVC;
-+              str += 3;
-+      } else if (!strncmp(str, "off", 3)) {
-+              xc_mode = XC_OFF;
-+              str += 3;
++      if (flow_control & EFX_FC_AUTO) {
++              EFX_LOG(efx, "10G does not support flow control "
++                      "autonegotiation\n");
++              return -EINVAL;
 +      }
 +
-+      n = simple_strtol(str, &q, 10);
-+      if (q != str)
-+              xc_num = n;
++      if ((flow_control & EFX_FC_TX) && !(flow_control & EFX_FC_RX))
++              return -EINVAL;
 +
-+      return 1;
++      /* TX flow control may automatically turn itself off if the
++       * link partner (intermittently) stops responding to pause
++       * frames. There isn't any indication that this has happened,
++       * so the best we do is leave it up to the user to spot this
++       * and fix it be cycling transmit flow control on this end. */
++      reset = ((flow_control & EFX_FC_TX) &&
++               !(efx->flow_control & EFX_FC_TX));
++      if (EFX_WORKAROUND_11482(efx) && reset) {
++              if (FALCON_REV(efx) == FALCON_REV_B0) {
++                      /* Recover by resetting the EM block */
++                      mutex_lock(&efx->mac_lock);
++                      if (efx->link_up)
++                              falcon_drain_tx_fifo(efx);
++                      mutex_unlock(&efx->mac_lock);
++              } else {
++                      /* Schedule a reset to recover */
++                      efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
++              }
++      }
++
++      efx->flow_control = flow_control;
++
++      return 0;
 +}
-+__setup("xencons=", xencons_setup);
 +
-+/* The kernel and user-land drivers share a common transmit buffer. */
-+static unsigned int wbuf_size = 4096;
-+#define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
-+static char *wbuf;
-+static unsigned int wc, wp; /* write_cons, write_prod */
++struct efx_mac_operations falcon_xmac_operations = {
++      .mac_writel     = falcon_xmac_writel,
++      .mac_readl      = falcon_xmac_readl,
++      .init           = falcon_init_xmac,
++      .reconfigure    = falcon_reconfigure_xmac,
++      .update_stats   = falcon_update_stats_xmac,
++      .fini           = falcon_fini_xmac,
++      .check_hw       = falcon_check_xmac,
++      .fake_phy_event = falcon_xmac_sim_phy_event,
++      .get_settings   = falcon_xmac_get_settings,
++      .set_settings   = falcon_xmac_set_settings,
++      .set_pause      = falcon_xmac_set_pause,
++};
+--- linux-2.6.18.8/drivers/net/sfc/gmii.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/gmii.h 2008-05-19 00:33:28.849809063 +0300
+@@ -0,0 +1,212 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef EFX_GMII_H
++#define EFX_GMII_H
++
++/*
++ * GMII interface
++ */
++
++#include <linux/mii.h>
++
++/* GMII registers, excluding registers already defined as MII
++ * registers in mii.h
++ */
++#define GMII_IER              0x12    /* Interrupt enable register */
++#define GMII_ISR              0x13    /* Interrupt status register */
++
++/* Interrupt enable register */
++#define IER_ANEG_ERR          0x8000  /* Bit 15 - autonegotiation error */
++#define IER_SPEED_CHG         0x4000  /* Bit 14 - speed changed */
++#define IER_DUPLEX_CHG                0x2000  /* Bit 13 - duplex changed */
++#define IER_PAGE_RCVD         0x1000  /* Bit 12 - page received */
++#define IER_ANEG_DONE         0x0800  /* Bit 11 - autonegotiation complete */
++#define IER_LINK_CHG          0x0400  /* Bit 10 - link status changed */
++#define IER_SYM_ERR           0x0200  /* Bit 9 - symbol error */
++#define IER_FALSE_CARRIER     0x0100  /* Bit 8 - false carrier */
++#define IER_FIFO_ERR          0x0080  /* Bit 7 - FIFO over/underflow */
++#define IER_MDIX_CHG          0x0040  /* Bit 6 - MDI crossover changed */
++#define IER_DOWNSHIFT         0x0020  /* Bit 5 - downshift */
++#define IER_ENERGY            0x0010  /* Bit 4 - energy detect */
++#define IER_DTE_POWER         0x0004  /* Bit 2 - DTE power detect */
++#define IER_POLARITY_CHG      0x0002  /* Bit 1 - polarity changed */
++#define IER_JABBER            0x0001  /* Bit 0 - jabber */
++
++/* Interrupt status register */
++#define ISR_ANEG_ERR          0x8000  /* Bit 15 - autonegotiation error */
++#define ISR_SPEED_CHG         0x4000  /* Bit 14 - speed changed */
++#define ISR_DUPLEX_CHG                0x2000  /* Bit 13 - duplex changed */
++#define ISR_PAGE_RCVD         0x1000  /* Bit 12 - page received */
++#define ISR_ANEG_DONE         0x0800  /* Bit 11 - autonegotiation complete */
++#define ISR_LINK_CHG          0x0400  /* Bit 10 - link status changed */
++#define ISR_SYM_ERR           0x0200  /* Bit 9 - symbol error */
++#define ISR_FALSE_CARRIER     0x0100  /* Bit 8 - false carrier */
++#define ISR_FIFO_ERR          0x0080  /* Bit 7 - FIFO over/underflow */
++#define ISR_MDIX_CHG          0x0040  /* Bit 6 - MDI crossover changed */
++#define ISR_DOWNSHIFT         0x0020  /* Bit 5 - downshift */
++#define ISR_ENERGY            0x0010  /* Bit 4 - energy detect */
++#define ISR_DTE_POWER         0x0004  /* Bit 2 - DTE power detect */
++#define ISR_POLARITY_CHG      0x0002  /* Bit 1 - polarity changed */
++#define ISR_JABBER            0x0001  /* Bit 0 - jabber */
++
++/* Logically extended advertisement register */
++#define GM_ADVERTISE_SLCT             ADVERTISE_SLCT
++#define GM_ADVERTISE_CSMA             ADVERTISE_CSMA
++#define GM_ADVERTISE_10HALF           ADVERTISE_10HALF
++#define GM_ADVERTISE_1000XFULL                ADVERTISE_1000XFULL
++#define GM_ADVERTISE_10FULL           ADVERTISE_10FULL
++#define GM_ADVERTISE_1000XHALF                ADVERTISE_1000XHALF
++#define GM_ADVERTISE_100HALF          ADVERTISE_100HALF
++#define GM_ADVERTISE_1000XPAUSE               ADVERTISE_1000XPAUSE
++#define GM_ADVERTISE_100FULL          ADVERTISE_100FULL
++#define GM_ADVERTISE_1000XPSE_ASYM    ADVERTISE_1000XPSE_ASYM
++#define GM_ADVERTISE_100BASE4         ADVERTISE_100BASE4
++#define GM_ADVERTISE_PAUSE_CAP                ADVERTISE_PAUSE_CAP
++#define GM_ADVERTISE_PAUSE_ASYM               ADVERTISE_PAUSE_ASYM
++#define GM_ADVERTISE_RESV             ADVERTISE_RESV
++#define GM_ADVERTISE_RFAULT           ADVERTISE_RFAULT
++#define GM_ADVERTISE_LPACK            ADVERTISE_LPACK
++#define GM_ADVERTISE_NPAGE            ADVERTISE_NPAGE
++#define GM_ADVERTISE_1000FULL         (ADVERTISE_1000FULL << 8)
++#define GM_ADVERTISE_1000HALF         (ADVERTISE_1000HALF << 8)
++#define GM_ADVERTISE_1000             (GM_ADVERTISE_1000FULL | \
++                                       GM_ADVERTISE_1000HALF)
++#define GM_ADVERTISE_FULL             (GM_ADVERTISE_1000FULL | \
++                                       ADVERTISE_FULL)
++#define GM_ADVERTISE_ALL              (GM_ADVERTISE_1000FULL | \
++                                       GM_ADVERTISE_1000HALF | \
++                                       ADVERTISE_ALL)
++
++/* Logically extended link partner ability register */
++#define GM_LPA_SLCT                   LPA_SLCT
++#define GM_LPA_10HALF                 LPA_10HALF
++#define GM_LPA_1000XFULL              LPA_1000XFULL
++#define GM_LPA_10FULL                 LPA_10FULL
++#define GM_LPA_1000XHALF              LPA_1000XHALF
++#define GM_LPA_100HALF                        LPA_100HALF
++#define GM_LPA_1000XPAUSE             LPA_1000XPAUSE
++#define GM_LPA_100FULL                        LPA_100FULL
++#define GM_LPA_1000XPAUSE_ASYM                LPA_1000XPAUSE_ASYM
++#define GM_LPA_100BASE4                       LPA_100BASE4
++#define GM_LPA_PAUSE_CAP              LPA_PAUSE_CAP
++#define GM_LPA_PAUSE_ASYM             LPA_PAUSE_ASYM
++#define GM_LPA_RESV                   LPA_RESV
++#define GM_LPA_RFAULT                 LPA_RFAULT
++#define GM_LPA_LPACK                  LPA_LPACK
++#define GM_LPA_NPAGE                  LPA_NPAGE
++#define GM_LPA_1000FULL                       (LPA_1000FULL << 6)
++#define GM_LPA_1000HALF                       (LPA_1000HALF << 6)
++#define GM_LPA_10000FULL              0x00040000
++#define GM_LPA_10000HALF              0x00080000
++#define GM_LPA_DUPLEX                 (GM_LPA_1000FULL | GM_LPA_10000FULL \
++                                       | LPA_DUPLEX)
++#define GM_LPA_10                     (LPA_10FULL | LPA_10HALF)
++#define GM_LPA_100                    LPA_100
++#define GM_LPA_1000                   (GM_LPA_1000FULL | GM_LPA_1000HALF)
++#define GM_LPA_10000                  (GM_LPA_10000FULL | GM_LPA_10000HALF)
++
++/* Retrieve GMII autonegotiation advertised abilities
++ *
++ * The MII advertisment register (MII_ADVERTISE) is logically extended
++ * to include advertisement bits ADVERTISE_1000FULL and
++ * ADVERTISE_1000HALF from MII_CTRL1000.  The result can be tested
++ * against the GM_ADVERTISE_xxx constants.
++ */
++static inline unsigned int gmii_advertised(struct mii_if_info *gmii)
++{
++      unsigned int advertise;
++      unsigned int ctrl1000;
++
++      advertise = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_ADVERTISE);
++      ctrl1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000);
++      return (((ctrl1000 << 8) & GM_ADVERTISE_1000) | advertise);
++}
++
++/* Retrieve GMII autonegotiation link partner abilities
++ *
++ * The MII link partner ability register (MII_LPA) is logically
++ * extended by adding bits LPA_1000HALF and LPA_1000FULL from
++ * MII_STAT1000.  The result can be tested against the GM_LPA_xxx
++ * constants.
++ */
++static inline unsigned int gmii_lpa(struct mii_if_info *gmii)
++{
++      unsigned int lpa;
++      unsigned int stat1000;
++
++      lpa = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_LPA);
++      stat1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_STAT1000);
++      return (((stat1000 << 6) & GM_LPA_1000) | lpa);
++}
++
++/* Calculate GMII autonegotiated link technology
++ *
++ * "negotiated" should be the result of gmii_advertised() logically
++ * ANDed with the result of gmii_lpa().
++ *
++ * "tech" will be negotiated with the unused bits masked out.  For
++ * example, if both ends of the link are capable of both
++ * GM_LPA_1000FULL and GM_LPA_100FULL, GM_LPA_100FULL will be masked
++ * out.
++ */
++static inline unsigned int gmii_nway_result(unsigned int negotiated)
++{
++      unsigned int other_bits;
++
++      /* Mask out the speed and duplexity bits */
++      other_bits = negotiated & ~(GM_LPA_10 | GM_LPA_100 | GM_LPA_1000);
++
++      if (negotiated & GM_LPA_1000FULL)
++              return (other_bits | GM_LPA_1000FULL);
++      else if (negotiated & GM_LPA_1000HALF)
++              return (other_bits | GM_LPA_1000HALF);
++      else
++              return (other_bits | mii_nway_result(negotiated));
++}
 +
-+static int __init xencons_bufsz_setup(char *str)
++/* Calculate GMII non-autonegotiated link technology
++ *
++ * This provides an equivalent to gmii_nway_result for the case when
++ * autonegotiation is disabled.
++ */
++static inline unsigned int gmii_forced_result(unsigned int bmcr)
 +{
-+      unsigned int goal;
-+      goal = simple_strtoul(str, NULL, 0);
-+      if (goal) {
-+              goal = roundup_pow_of_two(goal);
-+              if (wbuf_size < goal)
-+                      wbuf_size = goal;
-+      }
-+      return 1;
++      unsigned int result;
++      int full_duplex;
++
++      full_duplex = bmcr & BMCR_FULLDPLX;
++      if (bmcr & BMCR_SPEED1000)
++              result = full_duplex ? GM_LPA_1000FULL : GM_LPA_1000HALF;
++      else if (bmcr & BMCR_SPEED100)
++              result = full_duplex ? GM_LPA_100FULL : GM_LPA_100HALF;
++      else
++              result = full_duplex ? GM_LPA_10FULL : GM_LPA_10HALF;
++      return result;
 +}
-+__setup("xencons_bufsz=", xencons_bufsz_setup);
 +
-+/* This lock protects accesses to the common transmit buffer. */
-+static DEFINE_SPINLOCK(xencons_lock);
++#endif /* EFX_GMII_H */
+--- linux-2.6.18.8/drivers/net/sfc/i2c-direct.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/i2c-direct.c   2008-05-19 00:33:28.853809294 +0300
+@@ -0,0 +1,398 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005:      Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+/* Common transmit-kick routine. */
-+static void __xencons_tx_flush(void);
++#include <asm/io.h>
++#include <linux/delay.h>
++#include "net_driver.h"
++#include "i2c-direct.h"
 +
-+static struct tty_driver *xencons_driver;
++/* EEPROM access via I2C
++ * data (SDA) and clock (SCL) line read/writes
++ */
 +
-+/******************** Kernel console driver ********************************/
++static inline void setsda(struct efx_i2c_interface *i2c, int state)
++{
++      udelay(i2c->op->udelay);
++      i2c->sda = state;
++      i2c->op->setsda(i2c);
++      udelay(i2c->op->udelay);
++}
 +
-+static void kcons_write(struct console *c, const char *s, unsigned int count)
++static inline void setscl(struct efx_i2c_interface *i2c, int state)
 +{
-+      int           i = 0;
-+      unsigned long flags;
++      udelay(i2c->op->udelay);
++      i2c->scl = state;
++      i2c->op->setscl(i2c);
++      udelay(i2c->op->udelay);
++}
 +
-+      spin_lock_irqsave(&xencons_lock, flags);
++static inline int getsda(struct efx_i2c_interface *i2c)
++{
++      int sda;
 +
-+      while (i < count) {
-+              for (; i < count; i++) {
-+                      if ((wp - wc) >= (wbuf_size - 1))
-+                              break;
-+                      if ((wbuf[WBUF_MASK(wp++)] = s[i]) == '\n')
-+                              wbuf[WBUF_MASK(wp++)] = '\r';
-+              }
++      udelay(i2c->op->udelay);
++      sda = i2c->op->getsda(i2c);
++      udelay(i2c->op->udelay);
++      return sda;
++}
 +
-+              __xencons_tx_flush();
-+      }
++static inline int getscl(struct efx_i2c_interface *i2c)
++{
++      int scl;
 +
-+      spin_unlock_irqrestore(&xencons_lock, flags);
++      udelay(i2c->op->udelay);
++      scl = i2c->op->getscl(i2c);
++      udelay(i2c->op->udelay);
++      return scl;
 +}
 +
-+static void kcons_write_dom0(struct console *c, const char *s, unsigned int count)
-+{
++/*
++ * I2C low-level protocol operations
++ *
++ */
 +
-+      while (count > 0) {
-+              int rc;
-+              rc = HYPERVISOR_console_io( CONSOLEIO_write, count, (char *)s);
-+              if (rc <= 0)
-+                      break;
-+              count -= rc;
-+              s += rc;
-+      }
++static inline void i2c_release(struct efx_i2c_interface *i2c)
++{
++      EFX_WARN_ON_PARANOID(!i2c->scl);
++      EFX_WARN_ON_PARANOID(!i2c->sda);
++      /* Just in case */
++      setscl(i2c, 1);
++      setsda(i2c, 1);
++      EFX_BUG_ON_PARANOID(getsda(i2c) != 1);
++      EFX_BUG_ON_PARANOID(getscl(i2c) != 1);
 +}
 +
-+static struct tty_driver *kcons_device(struct console *c, int *index)
++static inline void i2c_start(struct efx_i2c_interface *i2c)
 +{
-+      *index = 0;
-+      return xencons_driver;
++      /* We may be restarting immediately after a {send,recv}_bit,
++       * so SCL will not necessarily already be high.
++       */
++      EFX_WARN_ON_PARANOID(!i2c->sda);
++      setscl(i2c, 1);
++      setsda(i2c, 0);
++      setscl(i2c, 0);
++      setsda(i2c, 1);
 +}
 +
-+static struct console kcons_info = {
-+      .device = kcons_device,
-+      .flags  = CON_PRINTBUFFER | CON_ENABLED,
-+      .index  = -1,
-+};
++static inline void i2c_send_bit(struct efx_i2c_interface *i2c, int bit)
++{
++      EFX_WARN_ON_PARANOID(i2c->scl != 0);
++      setsda(i2c, bit);
++      setscl(i2c, 1);
++      setscl(i2c, 0);
++      setsda(i2c, 1);
++}
 +
-+static int __init xen_console_init(void)
++static inline int i2c_recv_bit(struct efx_i2c_interface *i2c)
 +{
-+      if (!is_running_on_xen())
-+              goto out;
++      int bit;
 +
-+      if (is_initial_xendomain()) {
-+              kcons_info.write = kcons_write_dom0;
-+      } else {
-+              if (!xen_start_info->console.domU.evtchn)
-+                      goto out;
-+              kcons_info.write = kcons_write;
-+      }
++      EFX_WARN_ON_PARANOID(i2c->scl != 0);
++      EFX_WARN_ON_PARANOID(!i2c->sda);
++      setscl(i2c, 1);
++      bit = getsda(i2c);
++      setscl(i2c, 0);
++      return bit;
++}
 +
-+      switch (xc_mode) {
-+      case XC_XVC:
-+              strcpy(kcons_info.name, "xvc");
-+              if (xc_num == -1)
-+                      xc_num = 0;
-+              break;
++static inline void i2c_stop(struct efx_i2c_interface *i2c)
++{
++      EFX_WARN_ON_PARANOID(i2c->scl != 0);
++      setsda(i2c, 0);
++      setscl(i2c, 1);
++      setsda(i2c, 1);
++}
 +
-+      case XC_SERIAL:
-+              strcpy(kcons_info.name, "ttyS");
-+              if (xc_num == -1)
-+                      xc_num = 0;
-+              break;
++/*
++ * I2C mid-level protocol operations
++ *
++ */
 +
-+      case XC_TTY:
-+              strcpy(kcons_info.name, "tty");
-+              if (xc_num == -1)
-+                      xc_num = 1;
-+              break;
++/* Sends a byte via the I2C bus and checks for an acknowledgement from
++ * the slave device.
++ */
++static int i2c_send_byte(struct efx_i2c_interface *i2c, u8 byte)
++{
++      int i;
 +
-+      default:
-+              goto out;
++      /* Send byte */
++      for (i = 0; i < 8; i++) {
++              i2c_send_bit(i2c, !!(byte & 0x80));
++              byte <<= 1;
 +      }
 +
-+      wbuf = alloc_bootmem(wbuf_size);
-+
-+      register_console(&kcons_info);
-+
-+ out:
-+      return 0;
++      /* Check for acknowledgement from slave */
++      return (i2c_recv_bit(i2c) == 0 ? 0 : -EIO);
 +}
-+console_initcall(xen_console_init);
 +
-+/*** Useful function for console debugging -- goes straight to Xen. ***/
-+asmlinkage int xprintk(const char *fmt, ...)
++/* Receives a byte via the I2C bus and sends ACK/NACK to the slave device. */
++static u8 i2c_recv_byte(struct efx_i2c_interface *i2c, int ack)
 +{
-+      va_list args;
-+      int printk_len;
-+      static char printk_buf[1024];
++      u8 value = 0;
++      int i;
 +
-+      /* Emit the output into the temporary buffer */
-+      va_start(args, fmt);
-+      printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
-+      va_end(args);
++      /* Receive byte */
++      for (i = 0; i < 8; i++)
++              value = (value << 1) | i2c_recv_bit(i2c);
 +
-+      /* Send the processed output directly to Xen. */
-+      kcons_write_dom0(NULL, printk_buf, printk_len);
++      /* Send ACK/NACK */
++      i2c_send_bit(i2c, (ack ? 0 : 1));
 +
-+      return 0;
++      return value;
 +}
 +
-+/*** Forcibly flush console data before dying. ***/
-+void xencons_force_flush(void)
++/* Calculate command byte for a read operation */
++static inline u8 i2c_read_cmd(u8 device_id)
 +{
-+      int sz;
-+
-+      /* Emergency console is synchronous, so there's nothing to flush. */
-+      if (!is_running_on_xen() ||
-+          is_initial_xendomain() ||
-+          !xen_start_info->console.domU.evtchn)
-+              return;
-+
-+      /* Spin until console data is flushed through to the daemon. */
-+      while (wc != wp) {
-+              int sent = 0;
-+              if ((sz = wp - wc) == 0)
-+                      continue;
-+              sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
-+              if (sent > 0)
-+                      wc += sent;
-+      }
++      return ((device_id << 1) | 1);
 +}
 +
-+
-+void __init dom0_init_screen_info(const struct dom0_vga_console_info *info, size_t size)
++/* Calculate command byte for a write operation */
++static inline u8 i2c_write_cmd(u8 device_id)
 +{
-+      /* This is drawn from a dump from vgacon:startup in
-+       * standard Linux. */
-+      screen_info.orig_video_mode = 3;
-+      screen_info.orig_video_isVGA = 1;
-+      screen_info.orig_video_lines = 25;
-+      screen_info.orig_video_cols = 80;
-+      screen_info.orig_video_ega_bx = 3;
-+      screen_info.orig_video_points = 16;
-+      screen_info.orig_y = screen_info.orig_video_lines - 1;
++      return ((device_id << 1) | 0);
++}
 +
-+      switch (info->video_type) {
-+      case XEN_VGATYPE_TEXT_MODE_3:
-+              if (size < offsetof(struct dom0_vga_console_info, u.text_mode_3)
-+                         + sizeof(info->u.text_mode_3))
-+                      break;
-+              screen_info.orig_video_lines = info->u.text_mode_3.rows;
-+              screen_info.orig_video_cols = info->u.text_mode_3.columns;
-+              screen_info.orig_x = info->u.text_mode_3.cursor_x;
-+              screen_info.orig_y = info->u.text_mode_3.cursor_y;
-+              screen_info.orig_video_points =
-+                      info->u.text_mode_3.font_height;
-+              break;
++int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id)
++{
++      int rc;
 +
-+      case XEN_VGATYPE_VESA_LFB:
-+              if (size < offsetof(struct dom0_vga_console_info,
-+                                  u.vesa_lfb.gbl_caps))
-+                      break;
-+              screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
-+              screen_info.lfb_width = info->u.vesa_lfb.width;
-+              screen_info.lfb_height = info->u.vesa_lfb.height;
-+              screen_info.lfb_depth = info->u.vesa_lfb.bits_per_pixel;
-+              screen_info.lfb_base = info->u.vesa_lfb.lfb_base;
-+              screen_info.lfb_size = info->u.vesa_lfb.lfb_size;
-+              screen_info.lfb_linelength = info->u.vesa_lfb.bytes_per_line;
-+              screen_info.red_size = info->u.vesa_lfb.red_size;
-+              screen_info.red_pos = info->u.vesa_lfb.red_pos;
-+              screen_info.green_size = info->u.vesa_lfb.green_size;
-+              screen_info.green_pos = info->u.vesa_lfb.green_pos;
-+              screen_info.blue_size = info->u.vesa_lfb.blue_size;
-+              screen_info.blue_pos = info->u.vesa_lfb.blue_pos;
-+              screen_info.rsvd_size = info->u.vesa_lfb.rsvd_size;
-+              screen_info.rsvd_pos = info->u.vesa_lfb.rsvd_pos;
-+              if (size >= offsetof(struct dom0_vga_console_info,
-+                                   u.vesa_lfb.gbl_caps)
-+                          + sizeof(info->u.vesa_lfb.gbl_caps))
-+                      screen_info.capabilities = info->u.vesa_lfb.gbl_caps;
-+              if (size >= offsetof(struct dom0_vga_console_info,
-+                                   u.vesa_lfb.mode_attrs)
-+                          + sizeof(info->u.vesa_lfb.mode_attrs))
-+                      screen_info.vesa_attributes = info->u.vesa_lfb.mode_attrs;
-+              break;
++      /* If someone is driving the bus low we just give up. */
++      if (getsda(i2c) == 0 || getscl(i2c) == 0) {
++              EFX_ERR(i2c->efx, "%s someone is holding the I2C bus low."
++                      " Giving up.\n", __func__);
++              return -EFAULT;
 +      }
++
++      /* Pretend to initiate a device write */
++      i2c_start(i2c);
++      rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
++      if (rc)
++              goto out;
++
++ out:
++      i2c_stop(i2c);
++      i2c_release(i2c);
++
++      return rc;
 +}
 +
++/* This performs a fast read of one or more consecutive bytes from an
++ * I2C device.  Not all devices support consecutive reads of more than
++ * one byte; for these devices use efx_i2c_read() instead.
++ */
++int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
++                    u8 device_id, u8 offset, u8 *data, unsigned int len)
++{
++      int i;
++      int rc;
 +
-+/******************** User-space console driver (/dev/console) ************/
++      EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
++      EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
++      EFX_WARN_ON_PARANOID(data == NULL);
++      EFX_WARN_ON_PARANOID(len < 1);
 +
-+#define DRV(_d)         (_d)
-+#define DUMMY_TTY(_tty) ((xc_mode == XC_TTY) &&               \
-+                       ((_tty)->index != (xc_num - 1)))
++      /* Select device and starting offset */
++      i2c_start(i2c);
++      rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
++      if (rc)
++              goto out;
++      rc = i2c_send_byte(i2c, offset);
++      if (rc)
++              goto out;
 +
-+static struct termios *xencons_termios[MAX_NR_CONSOLES];
-+static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
-+static struct tty_struct *xencons_tty;
-+static int xencons_priv_irq;
-+static char x_char;
++      /* Read data from device */
++      i2c_start(i2c);
++      rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
++      if (rc)
++              goto out;
++      for (i = 0; i < (len - 1); i++)
++              /* Read and acknowledge all but the last byte */
++              data[i] = i2c_recv_byte(i2c, 1);
++      /* Read last byte with no acknowledgement */
++      data[i] = i2c_recv_byte(i2c, 0);
 +
-+void xencons_rx(char *buf, unsigned len, struct pt_regs *regs)
++ out:
++      i2c_stop(i2c);
++      i2c_release(i2c);
++
++      return rc;
++}
++
++/* This performs a fast write of one or more consecutive bytes to an
++ * I2C device.  Not all devices support consecutive writes of more
++ * than one byte; for these devices use efx_i2c_write() instead.
++ */
++int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
++                     u8 device_id, u8 offset,
++                     const u8 *data, unsigned int len)
 +{
-+      int           i;
-+      unsigned long flags;
++      int i;
++      int rc;
 +
-+      spin_lock_irqsave(&xencons_lock, flags);
-+      if (xencons_tty == NULL)
++      EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
++      EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
++      EFX_WARN_ON_PARANOID(len < 1);
++
++      /* Select device and starting offset */
++      i2c_start(i2c);
++      rc = i2c_send_byte(i2c, i2c_write_cmd(device_id));
++      if (rc)
++              goto out;
++      rc = i2c_send_byte(i2c, offset);
++      if (rc)
 +              goto out;
 +
++      /* Write data to device */
 +      for (i = 0; i < len; i++) {
-+#ifdef CONFIG_MAGIC_SYSRQ
-+              if (sysrq_enabled) {
-+                      if (buf[i] == '\x0f') { /* ^O */
-+                              if (!sysrq_requested) {
-+                                      sysrq_requested = jiffies;
-+                                      continue; /* don't print sysrq key */
-+                              }
-+                              sysrq_requested = 0;
-+                      } else if (sysrq_requested) {
-+                              unsigned long sysrq_timeout =
-+                                      sysrq_requested + HZ*2;
-+                              sysrq_requested = 0;
-+                              if (time_before(jiffies, sysrq_timeout)) {
-+                                      spin_unlock_irqrestore(
-+                                              &xencons_lock, flags);
-+                                      handle_sysrq(
-+                                              buf[i], regs, xencons_tty);
-+                                      spin_lock_irqsave(
-+                                              &xencons_lock, flags);
-+                                      continue;
-+                              }
-+                      }
-+              }
-+#endif
-+              tty_insert_flip_char(xencons_tty, buf[i], 0);
++              rc = i2c_send_byte(i2c, data[i]);
++              if (rc)
++                      goto out;
 +      }
-+      tty_flip_buffer_push(xencons_tty);
 +
 + out:
-+      spin_unlock_irqrestore(&xencons_lock, flags);
++      i2c_stop(i2c);
++      i2c_release(i2c);
++
++      return rc;
 +}
 +
-+static void __xencons_tx_flush(void)
++/* I2C byte-by-byte read */
++int efx_i2c_read(struct efx_i2c_interface *i2c,
++               u8 device_id, u8 offset, u8 *data, unsigned int len)
 +{
-+      int sent, sz, work_done = 0;
++      int rc;
 +
-+      if (x_char) {
-+              if (is_initial_xendomain())
-+                      kcons_write_dom0(NULL, &x_char, 1);
-+              else
-+                      while (x_char)
-+                              if (xencons_ring_send(&x_char, 1) == 1)
-+                                      break;
-+              x_char = 0;
-+              work_done = 1;
++      /* i2c_fast_read with length 1 is a single byte read */
++      for (; len > 0; offset++, data++, len--) {
++              rc = efx_i2c_fast_read(i2c, device_id, offset, data, 1);
++              if (rc)
++                      return rc;
 +      }
 +
-+      while (wc != wp) {
-+              sz = wp - wc;
-+              if (sz > (wbuf_size - WBUF_MASK(wc)))
-+                      sz = wbuf_size - WBUF_MASK(wc);
-+              if (is_initial_xendomain()) {
-+                      kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
-+                      wc += sz;
-+              } else {
-+                      sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
-+                      if (sent == 0)
-+                              break;
-+                      wc += sent;
-+              }
-+              work_done = 1;
-+      }
++      return 0;
++}
 +
-+      if (work_done && (xencons_tty != NULL)) {
-+              wake_up_interruptible(&xencons_tty->write_wait);
-+              if ((xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
-+                  (xencons_tty->ldisc.write_wakeup != NULL))
-+                      (xencons_tty->ldisc.write_wakeup)(xencons_tty);
++/* I2C byte-by-byte write */
++int efx_i2c_write(struct efx_i2c_interface *i2c,
++                u8 device_id, u8 offset, const u8 *data, unsigned int len)
++{
++      int rc;
++
++      /* i2c_fast_write with length 1 is a single byte write */
++      for (; len > 0; offset++, data++, len--) {
++              rc = efx_i2c_fast_write(i2c, device_id, offset, data, 1);
++              if (rc)
++                      return rc;
++              mdelay(i2c->op->mdelay);
 +      }
++
++      return 0;
 +}
 +
-+void xencons_tx(void)
-+{
-+      unsigned long flags;
 +
-+      spin_lock_irqsave(&xencons_lock, flags);
-+      __xencons_tx_flush();
-+      spin_unlock_irqrestore(&xencons_lock, flags);
++/* This is just a slightly neater wrapper round efx_i2c_fast_write
++ * in the case where the target doesn't take an offset
++ */
++int efx_i2c_send_bytes(struct efx_i2c_interface *i2c,
++                     u8 device_id, const u8 *data, unsigned int len)
++{
++      return efx_i2c_fast_write(i2c, device_id, data[0], data + 1, len - 1);
 +}
 +
-+/* Privileged receive callback and transmit kicker. */
-+static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
-+                                        struct pt_regs *regs)
++/* I2C receiving of bytes - does not send an offset byte */
++int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
++                     u8 *bytes, unsigned int len)
 +{
-+      static char rbuf[16];
-+      int         l;
++      int i;
++      int rc;
 +
-+      while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0)
-+              xencons_rx(rbuf, l, regs);
++      EFX_WARN_ON_PARANOID(getsda(i2c) != 1);
++      EFX_WARN_ON_PARANOID(getscl(i2c) != 1);
++      EFX_WARN_ON_PARANOID(len < 1);
 +
-+      xencons_tx();
++      /* Select device */
++      i2c_start(i2c);
 +
-+      return IRQ_HANDLED;
++      /* Read data from device */
++      rc = i2c_send_byte(i2c, i2c_read_cmd(device_id));
++      if (rc)
++              goto out;
++
++      for (i = 0; i < (len - 1); i++)
++              /* Read and acknowledge all but the last byte */
++              bytes[i] = i2c_recv_byte(i2c, 1);
++      /* Read last byte with no acknowledgement */
++      bytes[i] = i2c_recv_byte(i2c, 0);
++
++ out:
++      i2c_stop(i2c);
++      i2c_release(i2c);
++
++      return rc;
 +}
 +
-+static int xencons_write_room(struct tty_struct *tty)
++/* SMBus and some I2C devices will time out if the I2C clock is
++ * held low for too long. This is most likely to happen in virtualised
++ * systems (when the entire domain is descheduled) but could in
++ * principle happen due to preemption on any busy system (and given the
++ * potential length of an I2C operation turning preemption off is not
++ * a sensible option). The following functions deal with the failure by
++ * retrying up to a fixed number of times.
++  */
++
++#define I2C_MAX_RETRIES       (10)
++
++/* The timeout problem will result in -EIO. If the wrapped function
++ * returns any other error, pass this up and do not retry. */
++#define RETRY_WRAPPER(_f) \
++      int retries = I2C_MAX_RETRIES; \
++      int rc; \
++      while (retries) { \
++              rc = _f; \
++              if (rc != -EIO) \
++                      return rc; \
++              retries--; \
++      } \
++      return rc; \
++
++int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c, u8 device_id)
 +{
-+      return wbuf_size - (wp - wc);
++      RETRY_WRAPPER(efx_i2c_check_presence(i2c, device_id))
 +}
 +
-+static int xencons_chars_in_buffer(struct tty_struct *tty)
++int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
++               u8 device_id, u8 offset, u8 *data, unsigned int len)
 +{
-+      return wp - wc;
++      RETRY_WRAPPER(efx_i2c_read(i2c, device_id, offset, data, len))
 +}
 +
-+static void xencons_send_xchar(struct tty_struct *tty, char ch)
++int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
++                u8 device_id, u8 offset, const u8 *data, unsigned int len)
 +{
-+      unsigned long flags;
++      RETRY_WRAPPER(efx_i2c_write(i2c, device_id, offset, data, len))
++}
+--- linux-2.6.18.8/drivers/net/sfc/i2c-direct.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/i2c-direct.h   2008-05-19 00:33:28.853809294 +0300
+@@ -0,0 +1,108 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005:      Fen Systems Ltd.
++ * Copyright 2006:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      if (DUMMY_TTY(tty))
-+              return;
++#ifndef EFX_I2C_DIRECT_H
++#define EFX_I2C_DIRECT_H
 +
-+      spin_lock_irqsave(&xencons_lock, flags);
-+      x_char = ch;
-+      __xencons_tx_flush();
-+      spin_unlock_irqrestore(&xencons_lock, flags);
-+}
++#include "net_driver.h"
 +
-+static void xencons_throttle(struct tty_struct *tty)
-+{
-+      if (DUMMY_TTY(tty))
-+              return;
++/*
++ * Direct control of an I2C bus
++ */
 +
-+      if (I_IXOFF(tty))
-+              xencons_send_xchar(tty, STOP_CHAR(tty));
-+}
++struct efx_i2c_interface;
 +
-+static void xencons_unthrottle(struct tty_struct *tty)
-+{
-+      if (DUMMY_TTY(tty))
-+              return;
++/**
++ * struct efx_i2c_bit_operations - I2C bus direct control methods
++ *
++ * I2C bus direct control methods.
++ *
++ * @setsda: Set state of SDA line
++ * @setscl: Set state of SCL line
++ * @getsda: Get state of SDA line
++ * @getscl: Get state of SCL line
++ * @udelay: Delay between each bit operation
++ * @mdelay: Delay between each byte write
++ */
++struct efx_i2c_bit_operations {
++      void (*setsda) (struct efx_i2c_interface *i2c);
++      void (*setscl) (struct efx_i2c_interface *i2c);
++      int (*getsda) (struct efx_i2c_interface *i2c);
++      int (*getscl) (struct efx_i2c_interface *i2c);
++      unsigned int udelay;
++      unsigned int mdelay;
++};
 +
-+      if (I_IXOFF(tty)) {
-+              if (x_char != 0)
-+                      x_char = 0;
-+              else
-+                      xencons_send_xchar(tty, START_CHAR(tty));
-+      }
-+}
++/**
++ * struct efx_i2c_interface - an I2C interface
++ *
++ * An I2C interface.
++ *
++ * @efx: Attached Efx NIC
++ * @op: I2C bus control methods
++ * @sda: Current output state of SDA line
++ * @scl: Current output state of SCL line
++ */
++struct efx_i2c_interface {
++      struct efx_nic *efx;
++      struct efx_i2c_bit_operations *op;
++      unsigned int sda:1;
++      unsigned int scl:1;
++};
 +
-+static void xencons_flush_buffer(struct tty_struct *tty)
-+{
-+      unsigned long flags;
++extern int efx_i2c_check_presence(struct efx_i2c_interface *i2c, u8 device_id);
++extern int efx_i2c_fast_read(struct efx_i2c_interface *i2c,
++                           u8 device_id, u8 offset,
++                           u8 *data, unsigned int len);
++extern int efx_i2c_fast_write(struct efx_i2c_interface *i2c,
++                            u8 device_id, u8 offset,
++                            const u8 *data, unsigned int len);
++extern int efx_i2c_read(struct efx_i2c_interface *i2c,
++                      u8 device_id, u8 offset, u8 *data, unsigned int len);
++extern int efx_i2c_write(struct efx_i2c_interface *i2c,
++                       u8 device_id, u8 offset,
++                       const u8 *data, unsigned int len);
 +
-+      if (DUMMY_TTY(tty))
-+              return;
++extern int efx_i2c_send_bytes(struct efx_i2c_interface *i2c, u8 device_id,
++                            const u8 *bytes, unsigned int len);
 +
-+      spin_lock_irqsave(&xencons_lock, flags);
-+      wc = wp = 0;
-+      spin_unlock_irqrestore(&xencons_lock, flags);
-+}
++extern int efx_i2c_recv_bytes(struct efx_i2c_interface *i2c, u8 device_id,
++                            u8 *bytes, unsigned int len);
 +
-+static inline int __xencons_put_char(int ch)
-+{
-+      char _ch = (char)ch;
-+      if ((wp - wc) == wbuf_size)
-+              return 0;
-+      wbuf[WBUF_MASK(wp++)] = _ch;
-+      return 1;
-+}
 +
-+static int xencons_write(
-+      struct tty_struct *tty,
-+      const unsigned char *buf,
-+      int count)
-+{
-+      int i;
-+      unsigned long flags;
++/* Versions of the API that retry on failure. */
++extern int efx_i2c_check_presence_retry(struct efx_i2c_interface *i2c,
++                                      u8 device_id);
 +
-+      if (DUMMY_TTY(tty))
-+              return count;
++extern int efx_i2c_read_retry(struct efx_i2c_interface *i2c,
++                      u8 device_id, u8 offset, u8 *data, unsigned int len);
 +
-+      spin_lock_irqsave(&xencons_lock, flags);
++extern int efx_i2c_write_retry(struct efx_i2c_interface *i2c,
++                       u8 device_id, u8 offset,
++                       const u8 *data, unsigned int len);
 +
-+      for (i = 0; i < count; i++)
-+              if (!__xencons_put_char(buf[i]))
-+                      break;
++#endif /* EFX_I2C_DIRECT_H */
+--- linux-2.6.18.8/drivers/net/sfc/kernel_compat.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/kernel_compat.c        2008-05-19 00:33:28.865809986 +0300
+@@ -0,0 +1,654 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      if (i != 0)
-+              __xencons_tx_flush();
++#define EFX_IN_KCOMPAT_C 1
 +
-+      spin_unlock_irqrestore(&xencons_lock, flags);
++#include "net_driver.h"
++#include <linux/mii.h>
++#include <linux/ethtool.h>
++#include <linux/random.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include <linux/rtnetlink.h>
++#include <linux/bootmem.h>
++#include <asm/uaccess.h>
++#include "gmii.h"
++#include "ethtool.h"
 +
-+      return i;
-+}
++/*
++ * Kernel backwards compatibility
++ *
++ * This file provides functionality missing from earlier kernels.
++ */
 +
-+static void xencons_put_char(struct tty_struct *tty, u_char ch)
++/**************************************************************************
++ *
++ * GMII-friendly versions of mii_ethtool_[gs]set
++ *
++ **************************************************************************
++ *
++ * Kernels prior to 2.6.12 don't support GMII PHYs via
++ * mii_ethtool_gset and mii_ethtool_sset.  These are those functions
++ * taken from a 2.6.12 kernel tree, with the tests for
++ * mii->supports_gmii removed (since that field doesn't exist in older
++ * kernels).
++ *
++ */
++
++#ifdef EFX_NEED_MII_ETHTOOL_FIX
++int efx_mii_ethtool_gset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
 +{
-+      unsigned long flags;
++      struct net_device *dev = mii->dev;
++      u32 advert, bmcr, lpa, nego;
++      u32 advert2 = 0, bmcr2 = 0, lpa2 = 0;
 +
-+      if (DUMMY_TTY(tty))
-+              return;
++      ecmd->supported =
++          (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
++           SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full |
++           SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII);
++      ecmd->supported |= SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full;
 +
-+      spin_lock_irqsave(&xencons_lock, flags);
-+      (void)__xencons_put_char(ch);
-+      spin_unlock_irqrestore(&xencons_lock, flags);
-+}
++      /* only supports twisted-pair */
++      ecmd->port = PORT_MII;
 +
-+static void xencons_flush_chars(struct tty_struct *tty)
-+{
-+      unsigned long flags;
++      /* only supports internal transceiver */
++      ecmd->transceiver = XCVR_INTERNAL;
 +
-+      if (DUMMY_TTY(tty))
-+              return;
++      /* this isn't fully supported at higher layers */
++      ecmd->phy_address = mii->phy_id;
 +
-+      spin_lock_irqsave(&xencons_lock, flags);
-+      __xencons_tx_flush();
-+      spin_unlock_irqrestore(&xencons_lock, flags);
-+}
++      ecmd->advertising = ADVERTISED_TP | ADVERTISED_MII;
++      advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
++      advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
 +
-+static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
-+{
-+      unsigned long orig_jiffies = jiffies;
++      if (advert & ADVERTISE_10HALF)
++              ecmd->advertising |= ADVERTISED_10baseT_Half;
++      if (advert & ADVERTISE_10FULL)
++              ecmd->advertising |= ADVERTISED_10baseT_Full;
++      if (advert & ADVERTISE_100HALF)
++              ecmd->advertising |= ADVERTISED_100baseT_Half;
++      if (advert & ADVERTISE_100FULL)
++              ecmd->advertising |= ADVERTISED_100baseT_Full;
++      if (advert2 & ADVERTISE_1000HALF)
++              ecmd->advertising |= ADVERTISED_1000baseT_Half;
++      if (advert2 & ADVERTISE_1000FULL)
++              ecmd->advertising |= ADVERTISED_1000baseT_Full;
 +
-+      if (DUMMY_TTY(tty))
-+              return;
++      bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
++      lpa = mii->mdio_read(dev, mii->phy_id, MII_LPA);
++      bmcr2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
++      lpa2 = mii->mdio_read(dev, mii->phy_id, MII_STAT1000);
++      if (bmcr & BMCR_ANENABLE) {
++              ecmd->advertising |= ADVERTISED_Autoneg;
++              ecmd->autoneg = AUTONEG_ENABLE;
 +
-+      while (DRV(tty->driver)->chars_in_buffer(tty)) {
-+              set_current_state(TASK_INTERRUPTIBLE);
-+              schedule_timeout(1);
-+              if (signal_pending(current))
-+                      break;
-+              if (timeout && time_after(jiffies, orig_jiffies + timeout))
-+                      break;
++              nego = mii_nway_result(advert & lpa);
++              if ((bmcr2 & (ADVERTISE_1000HALF | ADVERTISE_1000FULL)) &
++                  (lpa2 >> 2))
++                      ecmd->speed = SPEED_1000;
++              else if (nego == LPA_100FULL || nego == LPA_100HALF)
++                      ecmd->speed = SPEED_100;
++              else
++                      ecmd->speed = SPEED_10;
++              if ((lpa2 & LPA_1000FULL) || nego == LPA_100FULL ||
++                  nego == LPA_10FULL) {
++                      ecmd->duplex = DUPLEX_FULL;
++                      mii->full_duplex = 1;
++              } else {
++                      ecmd->duplex = DUPLEX_HALF;
++                      mii->full_duplex = 0;
++              }
++      } else {
++              ecmd->autoneg = AUTONEG_DISABLE;
++
++              ecmd->speed = ((bmcr & BMCR_SPEED1000 &&
++                              (bmcr & BMCR_SPEED100) == 0) ? SPEED_1000 :
++                             (bmcr & BMCR_SPEED100) ? SPEED_100 : SPEED_10);
++              ecmd->duplex =
++                      (bmcr & BMCR_FULLDPLX) ? DUPLEX_FULL : DUPLEX_HALF;
 +      }
 +
-+      set_current_state(TASK_RUNNING);
++      /* ignore maxtxpkt, maxrxpkt for now */
++
++      return 0;
 +}
 +
-+static int xencons_open(struct tty_struct *tty, struct file *filp)
++int efx_mii_ethtool_sset(struct mii_if_info *mii, struct ethtool_cmd *ecmd)
 +{
-+      unsigned long flags;
++      struct net_device *dev = mii->dev;
 +
-+      if (DUMMY_TTY(tty))
-+              return 0;
++      if (ecmd->speed != SPEED_10 &&
++          ecmd->speed != SPEED_100 &&
++          ecmd->speed != SPEED_1000)
++              return -EINVAL;
++      if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL)
++              return -EINVAL;
++      if (ecmd->port != PORT_MII)
++              return -EINVAL;
++      if (ecmd->transceiver != XCVR_INTERNAL)
++              return -EINVAL;
++      if (ecmd->phy_address != mii->phy_id)
++              return -EINVAL;
++      if (ecmd->autoneg != AUTONEG_DISABLE && ecmd->autoneg != AUTONEG_ENABLE)
++              return -EINVAL;
 +
-+      spin_lock_irqsave(&xencons_lock, flags);
-+      tty->driver_data = NULL;
-+      if (xencons_tty == NULL)
-+              xencons_tty = tty;
-+      __xencons_tx_flush();
-+      spin_unlock_irqrestore(&xencons_lock, flags);
++      /* ignore supported, maxtxpkt, maxrxpkt */
++
++      if (ecmd->autoneg == AUTONEG_ENABLE) {
++              u32 bmcr, advert, tmp;
++              u32 advert2 = 0, tmp2 = 0;
++
++              if ((ecmd->advertising & (ADVERTISED_10baseT_Half |
++                                        ADVERTISED_10baseT_Full |
++                                        ADVERTISED_100baseT_Half |
++                                        ADVERTISED_100baseT_Full |
++                                        ADVERTISED_1000baseT_Half |
++                                        ADVERTISED_1000baseT_Full)) == 0)
++                      return -EINVAL;
++
++              /* advertise only what has been requested */
++              advert = mii->mdio_read(dev, mii->phy_id, MII_ADVERTISE);
++              tmp = advert & ~(ADVERTISE_ALL | ADVERTISE_100BASE4);
++              advert2 = mii->mdio_read(dev, mii->phy_id, MII_CTRL1000);
++              tmp2 = advert2 & ~(ADVERTISE_1000HALF | ADVERTISE_1000FULL);
++              if (ecmd->advertising & ADVERTISED_10baseT_Half)
++                      tmp |= ADVERTISE_10HALF;
++              if (ecmd->advertising & ADVERTISED_10baseT_Full)
++                      tmp |= ADVERTISE_10FULL;
++              if (ecmd->advertising & ADVERTISED_100baseT_Half)
++                      tmp |= ADVERTISE_100HALF;
++              if (ecmd->advertising & ADVERTISED_100baseT_Full)
++                      tmp |= ADVERTISE_100FULL;
++              if (ecmd->advertising & ADVERTISED_1000baseT_Half)
++                      tmp2 |= ADVERTISE_1000HALF;
++              if (ecmd->advertising & ADVERTISED_1000baseT_Full)
++                      tmp2 |= ADVERTISE_1000FULL;
++              if (advert != tmp) {
++                      mii->mdio_write(dev, mii->phy_id, MII_ADVERTISE, tmp);
++                      mii->advertising = tmp;
++              }
++              if (advert2 != tmp2)
++                      mii->mdio_write(dev, mii->phy_id, MII_CTRL1000, tmp2);
++
++              /* turn on autonegotiation, and force a renegotiate */
++              bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
++              bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
++              mii->mdio_write(dev, mii->phy_id, MII_BMCR, bmcr);
++
++              mii->force_media = 0;
++      } else {
++              u32 bmcr, tmp;
++
++              /* turn off auto negotiation, set speed and duplexity */
++              bmcr = mii->mdio_read(dev, mii->phy_id, MII_BMCR);
++              tmp = bmcr & ~(BMCR_ANENABLE | BMCR_SPEED100 |
++                             BMCR_SPEED1000 | BMCR_FULLDPLX);
++              if (ecmd->speed == SPEED_1000)
++                      tmp |= BMCR_SPEED1000;
++              else if (ecmd->speed == SPEED_100)
++                      tmp |= BMCR_SPEED100;
++              if (ecmd->duplex == DUPLEX_FULL) {
++                      tmp |= BMCR_FULLDPLX;
++                      mii->full_duplex = 1;
++              } else {
++                      mii->full_duplex = 0;
++              }
++              if (bmcr != tmp)
++                      mii->mdio_write(dev, mii->phy_id, MII_BMCR, tmp);
 +
++              mii->force_media = 1;
++      }
 +      return 0;
 +}
++#endif /* NEED_EFX_MII_ETHTOOL_GSET */
 +
-+static void xencons_close(struct tty_struct *tty, struct file *filp)
++/**************************************************************************
++ *
++ * unregister_netdevice_notifier : Has a race before 2.6.17
++ *
++ **************************************************************************
++ *
++ */
++
++#ifdef EFX_NEED_UNREGISTER_NETDEVICE_NOTIFIER_FIX
++/**
++ * efx_unregister_netdevice_notifier - fixed unregister_netdevice_notifier
++ * @nb:               notifier to unregister
++ *
++ * unregister_netdevice_notifier() does not wait for the notifier
++ * to be unused before 2.6.17.  This wrapper fixes that.
++ */
++int efx_unregister_netdevice_notifier(struct notifier_block *nb)
 +{
-+      unsigned long flags;
++      int res;
 +
-+      if (DUMMY_TTY(tty))
-+              return;
++      res = unregister_netdevice_notifier(nb);
++      /* Ensure any outstanding calls complete. */
++      rtnl_lock();
++      rtnl_unlock();
++      return res;
++}
++#endif /* NEED_EFX_UNREGISTER_NETDEVICE_NOTIFIER */
 +
-+      mutex_lock(&tty_mutex);
++/**************************************************************************
++ *
++ * IOMMU-locking versions of pci_[un]map_single and
++ * pci_{alloc,free}_consistent.  See SFC bug 4560.
++ *
++ **************************************************************************
++ *
++ */
++#ifdef EFX_NEED_IOMMU_LOCK
 +
-+      if (tty->count != 1) {
-+              mutex_unlock(&tty_mutex);
-+              return;
-+      }
++/*
++ * efx_use_iommu_lock - IOMMU lock use control
++ *
++ * If set to 1, the driver will attempt to mitigate the race condition
++ * bug around IOMMU accesses in some 2.6 kernels.  If set to 2, the
++ * driver will use the lock even if it thinks it doesn't need to.
++ * Note that this is only a best-effort attempt; in particular, we
++ * cannot do anything about other drivers touching the IOMMU.
++ */
++static unsigned int efx_use_iommu_lock = 1;
++EXPORT_SYMBOL(efx_use_iommu_lock);
 +
-+      /* Prevent other threads from re-opening this tty. */
-+      set_bit(TTY_CLOSING, &tty->flags);
-+      mutex_unlock(&tty_mutex);
++/*
++ * efx_iommu_lock - lock around IOMMU accesses
++ *
++ * This spinlock should be held while calling functions that access
++ * the IOMMU if efx_use_iommu_lock is >= 2.  The efx_pci_*()
++ * functions do this where possible.
++ */
++static spinlock_t efx_iommu_lock = SPIN_LOCK_UNLOCKED;
++EXPORT_SYMBOL(efx_iommu_lock);
 +
-+      tty->closing = 1;
-+      tty_wait_until_sent(tty, 0);
-+      if (DRV(tty->driver)->flush_buffer != NULL)
-+              DRV(tty->driver)->flush_buffer(tty);
-+      if (tty->ldisc.flush_buffer != NULL)
-+              tty->ldisc.flush_buffer(tty);
-+      tty->closing = 0;
-+      spin_lock_irqsave(&xencons_lock, flags);
-+      xencons_tty = NULL;
-+      spin_unlock_irqrestore(&xencons_lock, flags);
++/* Don't use the IOMMU lock if the device can access the whole of memory */
++#define EFX_DMA_CONSISTENT(_efx)                      \
++      (((_efx)->dma_mask >> PAGE_SHIFT) >= max_pfn)
++/**
++ * efx_pci_map_single - map buffer for DMA, under IOMMU lock
++ * @pci:              PCI device
++ * @ptr:              Buffer
++ * @size:             Buffer length
++ * @direction:                DMA direction
++ *
++ * Wrapper for pci_map_single that uses efx_iommu_lock if necessary.
++ */
++dma_addr_t efx_pci_map_single(struct pci_dev *pci, void *ptr, size_t size,
++                            int direction)
++{
++      struct efx_nic *efx = pci_get_drvdata(pci);
++      unsigned long flags __attribute__ ((unused));
++      dma_addr_t dma_addr;
++
++      if (unlikely((efx_use_iommu_lock &&
++                    (!EFX_NO_IOMMU) &&
++                    (!EFX_DMA_CONSISTENT(efx))) ||
++                   efx_use_iommu_lock >= 2)) {
++              spin_lock_irqsave(&efx_iommu_lock, flags);
++              dma_addr = pci_map_single(pci, ptr, size, direction);
++              spin_unlock_irqrestore(&efx_iommu_lock, flags);
++      } else {
++              dma_addr = pci_map_single(pci, ptr, size, direction);
++      }
++      return dma_addr;
 +}
 +
-+static struct tty_operations xencons_ops = {
-+      .open = xencons_open,
-+      .close = xencons_close,
-+      .write = xencons_write,
-+      .write_room = xencons_write_room,
-+      .put_char = xencons_put_char,
-+      .flush_chars = xencons_flush_chars,
-+      .chars_in_buffer = xencons_chars_in_buffer,
-+      .send_xchar = xencons_send_xchar,
-+      .flush_buffer = xencons_flush_buffer,
-+      .throttle = xencons_throttle,
-+      .unthrottle = xencons_unthrottle,
-+      .wait_until_sent = xencons_wait_until_sent,
-+};
++/**
++ * efx_pci_unmap_single - unmap buffer for DMA, under IOMMU lock
++ * @pci:              PCI device
++ * @dma_addr:         DMA address
++ * @size:             Buffer length
++ * @direction:                DMA direction
++ *
++ * Wrapper for pci_unmap_single that uses efx_iommu_lock if necessary.
++ */
++void efx_pci_unmap_single(struct pci_dev *pci, dma_addr_t dma_addr,
++                        size_t size, int direction)
++{
++      struct efx_nic *efx = pci_get_drvdata(pci);
++      unsigned long flags __attribute__ ((unused));
++
++      if (unlikely((efx_use_iommu_lock &&
++                    (!EFX_NO_IOMMU) &&
++                    (!EFX_DMA_CONSISTENT(efx))) ||
++                   efx_use_iommu_lock >= 2)) {
++              spin_lock_irqsave(&efx_iommu_lock, flags);
++              pci_unmap_single(pci, dma_addr, size, direction);
++              spin_unlock_irqrestore(&efx_iommu_lock, flags);
++      } else {
++              pci_unmap_single(pci, dma_addr, size, direction);
++      }
++}
 +
-+static int __init xencons_init(void)
++/**
++ * efx_pci_alloc_consistent - allocate DMA-consistent buffer, under IOMMU lock
++ * @pci:              PCI device
++ * @size:             Buffer length
++ * @dma_addr:         DMA address
++ *
++ * Wrapper for pci_alloc_consistent that uses efx_iommu_lock if necessary.
++ *
++ * Bugs: Currently this can't use the spinlock because
++ *    pci_alloc_consistent may block.
++ */
++void *efx_pci_alloc_consistent(struct pci_dev *pci, size_t size,
++                             dma_addr_t *dma_addr)
 +{
-+      int rc;
++      return pci_alloc_consistent(pci, size, dma_addr);
++}
 +
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++/**
++ * efx_pci_free_consistent - free DMA-consistent buffer, under IOMMU lock
++ * @pci:              PCI device
++ * @size:             Buffer length
++ * @ptr:              Buffer
++ * @dma_addr:         DMA address
++ *
++ * Wrapper for pci_free_consistent that uses efx_iommu_lock if necessary.
++ */
++void efx_pci_free_consistent(struct pci_dev *pci, size_t size, void *ptr,
++                           dma_addr_t dma_addr)
++{
++      struct efx_nic *efx = pci_get_drvdata(pci);
++      unsigned long flags __attribute__ ((unused));
++
++      if (unlikely((efx_use_iommu_lock &&
++                    (!EFX_NO_IOMMU) &&
++                    (!EFX_DMA_CONSISTENT(efx))) ||
++                   efx_use_iommu_lock >= 2)) {
++              spin_lock_irqsave(&efx_iommu_lock, flags);
++              pci_free_consistent(pci, size, ptr, dma_addr);
++              spin_unlock_irqrestore(&efx_iommu_lock, flags);
++      } else {
++              pci_free_consistent(pci, size, ptr, dma_addr);
++      }
++}
 +
-+      if (xc_mode == XC_OFF)
-+              return 0;
++module_param(efx_use_iommu_lock, uint, 0644);
++MODULE_PARM_DESC(efx_use_iommu_lock, "Enable lock for bug in free_iommu");
 +
-+      if (!is_initial_xendomain()) {
-+              rc = xencons_ring_init();
-+              if (rc)
-+                      return rc;
-+      }
++#endif
 +
-+      xencons_driver = alloc_tty_driver((xc_mode == XC_TTY) ?
-+                                        MAX_NR_CONSOLES : 1);
-+      if (xencons_driver == NULL)
-+              return -ENOMEM;
-+
-+      DRV(xencons_driver)->name            = "xencons";
-+      DRV(xencons_driver)->major           = TTY_MAJOR;
-+      DRV(xencons_driver)->type            = TTY_DRIVER_TYPE_SERIAL;
-+      DRV(xencons_driver)->subtype         = SERIAL_TYPE_NORMAL;
-+      DRV(xencons_driver)->init_termios    = tty_std_termios;
-+      DRV(xencons_driver)->flags           =
-+              TTY_DRIVER_REAL_RAW |
-+              TTY_DRIVER_RESET_TERMIOS;
-+      DRV(xencons_driver)->termios         = xencons_termios;
-+      DRV(xencons_driver)->termios_locked  = xencons_termios_locked;
-+
-+      switch (xc_mode) {
-+      case XC_XVC:
-+              DRV(xencons_driver)->name        = "xvc";
-+              DRV(xencons_driver)->major       = XEN_XVC_MAJOR;
-+              DRV(xencons_driver)->minor_start = XEN_XVC_MINOR;
-+              DRV(xencons_driver)->name_base   = xc_num;
-+              break;
-+      case XC_SERIAL:
-+              DRV(xencons_driver)->name        = "ttyS";
-+              DRV(xencons_driver)->minor_start = 64 + xc_num;
-+              DRV(xencons_driver)->name_base   = xc_num;
-+              break;
-+      default:
-+              DRV(xencons_driver)->name        = "tty";
-+              DRV(xencons_driver)->minor_start = 1;
-+              DRV(xencons_driver)->name_base   = 1;
-+              break;
-+      }
-+
-+      tty_set_operations(xencons_driver, &xencons_ops);
-+
-+      if ((rc = tty_register_driver(DRV(xencons_driver))) != 0) {
-+              printk("WARNING: Failed to register Xen virtual "
-+                     "console driver as '%s%d'\n",
-+                     DRV(xencons_driver)->name,
-+                     DRV(xencons_driver)->name_base);
-+              put_tty_driver(xencons_driver);
-+              xencons_driver = NULL;
-+              return rc;
-+      }
-+
-+      if (is_initial_xendomain()) {
-+              xencons_priv_irq = bind_virq_to_irqhandler(
-+                      VIRQ_CONSOLE,
-+                      0,
-+                      xencons_priv_interrupt,
-+                      0,
-+                      "console",
-+                      NULL);
-+              BUG_ON(xencons_priv_irq < 0);
-+      }
++#ifdef EFX_NEED_COMPOUND_PAGE_FIX
 +
-+      printk("Xen virtual console successfully installed as %s%d\n",
-+             DRV(xencons_driver)->name, xc_num);
++void efx_compound_page_destructor(struct page *page)
++{
++      /* Fake up page state to keep __free_pages happy */
++      set_page_count(page, 1);
++      page[1].mapping = NULL;
 +
-+      return 0;
++      __free_pages(page, (unsigned long)page[1].index);
 +}
 +
-+module_init(xencons_init);
-+
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/console/Makefile linux-2.6.18-xen.hg/drivers/xen/console/Makefile
---- linux-2.6.18/drivers/xen/console/Makefile  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/console/Makefile   2007-12-23 11:15:33.551242507 +0100
-@@ -0,0 +1,2 @@
++#endif /* NEED_COMPOUND_PAGE_FIX */
 +
-+obj-y := console.o xencons_ring.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/console/xencons_ring.c linux-2.6.18-xen.hg/drivers/xen/console/xencons_ring.c
---- linux-2.6.18/drivers/xen/console/xencons_ring.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/console/xencons_ring.c     2007-12-23 11:15:33.551242507 +0100
-@@ -0,0 +1,143 @@
-+/* 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++/**************************************************************************
++ *
++ * print_hex_dump, taken from lib/hexdump.c.
++ *
++ **************************************************************************
++ *
 + */
++#ifdef EFX_NEED_HEX_DUMP
 +
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/errno.h>
-+#include <linux/signal.h>
-+#include <linux/sched.h>
-+#include <linux/interrupt.h>
-+#include <linux/tty.h>
-+#include <linux/tty_flip.h>
-+#include <linux/serial.h>
-+#include <linux/major.h>
-+#include <linux/ptrace.h>
-+#include <linux/ioport.h>
-+#include <linux/mm.h>
-+#include <linux/slab.h>
-+
-+#include <asm/hypervisor.h>
-+#include <xen/evtchn.h>
-+#include <xen/xencons.h>
-+#include <linux/wait.h>
-+#include <linux/interrupt.h>
-+#include <linux/sched.h>
-+#include <linux/err.h>
-+#include <xen/interface/io/console.h>
-+
-+static int xencons_irq;
-+
-+static inline struct xencons_interface *xencons_interface(void)
-+{
-+      return mfn_to_virt(xen_start_info->console.domU.mfn);
-+}
-+
-+static inline void notify_daemon(void)
-+{
-+      /* Use evtchn: this is called early, before irq is set up. */
-+      notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
-+}
++#define hex_asc(x)    "0123456789abcdef"[x]
++#define isascii(c) (((unsigned char)(c))<=0x7f)
 +
-+int xencons_ring_send(const char *data, unsigned len)
++static void hex_dump_to_buffer(const void *buf, size_t len, int rowsize,
++                             int groupsize, char *linebuf, size_t linebuflen,
++                             int ascii)
 +{
-+      int sent = 0;
-+      struct xencons_interface *intf = xencons_interface();
-+      XENCONS_RING_IDX cons, prod;
-+
-+      cons = intf->out_cons;
-+      prod = intf->out_prod;
-+      mb();
-+      BUG_ON((prod - cons) > sizeof(intf->out));
++        const u8 *ptr = buf;
++        u8 ch;
++        int j, lx = 0;
++        int ascii_column;
 +
-+      while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
-+              intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
++        if (rowsize != 16 && rowsize != 32)
++                rowsize = 16;
 +
-+      wmb();
-+      intf->out_prod = prod;
++        if (!len)
++                goto nil;
++        if (len > rowsize)              /* limit to one line at a time */
++                len = rowsize;
++        if ((len % groupsize) != 0)     /* no mixed size output */
++                groupsize = 1;
 +
-+      notify_daemon();
++        switch (groupsize) {
++        case 8: {
++                const u64 *ptr8 = buf;
++                int ngroups = len / groupsize;
 +
-+      return sent;
-+}
++                for (j = 0; j < ngroups; j++)
++                        lx += scnprintf(linebuf + lx, linebuflen - lx,
++                              "%16.16llx ", (unsigned long long)*(ptr8 + j));
++                ascii_column = 17 * ngroups + 2;
++                break;
++        }
 +
-+static irqreturn_t handle_input(int irq, void *unused, struct pt_regs *regs)
-+{
-+      struct xencons_interface *intf = xencons_interface();
-+      XENCONS_RING_IDX cons, prod;
++        case 4: {
++                const u32 *ptr4 = buf;
++                int ngroups = len / groupsize;
 +
-+      cons = intf->in_cons;
-+      prod = intf->in_prod;
-+      mb();
-+      BUG_ON((prod - cons) > sizeof(intf->in));
++                for (j = 0; j < ngroups; j++)
++                        lx += scnprintf(linebuf + lx, linebuflen - lx,
++                              "%8.8x ", *(ptr4 + j));
++                ascii_column = 9 * ngroups + 2;
++                break;
++        }
 +
-+      while (cons != prod) {
-+              xencons_rx(intf->in+MASK_XENCONS_IDX(cons,intf->in), 1, regs);
-+              cons++;
-+      }
++        case 2: {
++                const u16 *ptr2 = buf;
++                int ngroups = len / groupsize;
 +
-+      mb();
-+      intf->in_cons = cons;
++                for (j = 0; j < ngroups; j++)
++                        lx += scnprintf(linebuf + lx, linebuflen - lx,
++                              "%4.4x ", *(ptr2 + j));
++                ascii_column = 5 * ngroups + 2;
++                break;
++        }
 +
-+      notify_daemon();
++        default:
++                for (j = 0; (j < rowsize) && (j < len) && (lx + 4) < linebuflen;
++                     j++) {
++                        ch = ptr[j];
++                        linebuf[lx++] = hex_asc(ch >> 4);
++                        linebuf[lx++] = hex_asc(ch & 0x0f);
++                        linebuf[lx++] = ' ';
++                }
++                ascii_column = 3 * rowsize + 2;
++                break;
++        }
++        if (!ascii)
++                goto nil;
++
++        while (lx < (linebuflen - 1) && lx < (ascii_column - 1))
++                linebuf[lx++] = ' ';
++      /* Removed is_print() check */
++        for (j = 0; (j < rowsize) && (j < len) && (lx + 2) < linebuflen; j++)
++                linebuf[lx++] = isascii(ptr[j]) ? ptr[j] : '.';
++nil:
++        linebuf[lx++] = '\0';
++}
++
++void print_hex_dump(const char *level, const char *prefix_str, int prefix_type,
++                  int rowsize, int groupsize,
++                  const void *buf, size_t len, int ascii)
++{
++        const u8 *ptr = buf;
++        int i, linelen, remaining = len;
++        char linebuf[200];
++
++        if (rowsize != 16 && rowsize != 32)
++                rowsize = 16;
++
++        for (i = 0; i < len; i += rowsize) {
++                linelen = min(remaining, rowsize);
++                remaining -= rowsize;
++                hex_dump_to_buffer(ptr + i, linelen, rowsize, groupsize,
++                                 linebuf, sizeof(linebuf), ascii);
++
++                switch (prefix_type) {
++                case DUMP_PREFIX_ADDRESS:
++                        printk("%s%s%*p: %s\n", level, prefix_str,
++                             (int)(2 * sizeof(void *)), ptr + i, linebuf);
++                        break;
++                case DUMP_PREFIX_OFFSET:
++                        printk("%s%s%.8x: %s\n", level, prefix_str, i, linebuf);
++                        break;
++                default:
++                        printk("%s%s%s\n", level, prefix_str, linebuf);
++                        break;
++                }
++        }
++}
 +
-+      xencons_tx();
++#endif /* EFX_NEED_HEX_DUMP */
 +
-+      return IRQ_HANDLED;
++/**************************************************************************
++ *
++ * print_mac, from net/ethernet/eth.c in v2.6.24
++ *
++ **************************************************************************
++ *
++ */
++#ifdef EFX_NEED_PRINT_MAC
++char *print_mac(char *buf, const u8 *addr)
++{
++        sprintf(buf, "%02x:%02x:%02x:%02x:%02x:%02x",
++                addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
++        return buf;
 +}
++#endif /* EFX_NEED_PRINT_MAC */
 +
-+int xencons_ring_init(void)
++#ifdef EFX_NEED_CSUM_TCPUDP_NOFOLD
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++__wsum
++csum_tcpudp_nofold (__be32 saddr, __be32 daddr, unsigned short len,
++                  unsigned short proto, __wsum sum)
++#else
++__wsum
++csum_tcpudp_nofold (unsigned long saddr, unsigned long daddr,
++                  unsigned short len, unsigned short proto, __wsum sum)
++#endif
 +{
-+      int irq;
-+
-+      if (xencons_irq)
-+              unbind_from_irqhandler(xencons_irq, NULL);
-+      xencons_irq = 0;
-+
-+      if (!is_running_on_xen() ||
-+          is_initial_xendomain() ||
-+          !xen_start_info->console.domU.evtchn)
-+              return -ENODEV;
-+
-+      irq = bind_caller_port_to_irqhandler(
-+              xen_start_info->console.domU.evtchn,
-+              handle_input, 0, "xencons", NULL);
-+      if (irq < 0) {
-+              printk(KERN_ERR "XEN console request irq failed %i\n", irq);
-+              return irq;
-+      }
++      unsigned long result;
 +
-+      xencons_irq = irq;
++      result = (__force u64)saddr + (__force u64)daddr +
++              (__force u64)sum + ((len + proto) << 8);
 +
-+      /* In case we have in-flight data after save/restore... */
-+      notify_daemon();
++      /* Fold down to 32-bits so we don't lose in the typedef-less network stack.  */
++      /* 64 to 33 */
++      result = (result & 0xffffffff) + (result >> 32);
++      /* 33 to 32 */
++      result = (result & 0xffffffff) + (result >> 32);
++      return (__force __wsum)result;
 +
-+      return 0;
 +}
++#endif /* EFX_NEED_CSUM_TCPUDP_NOFOLD */
 +
-+void xencons_resume(void)
-+{
-+      (void)xencons_ring_init();
++#ifdef EFX_NEED_RANDOM_ETHER_ADDR
++/* Generate random MAC address */
++void efx_random_ether_addr(uint8_t *addr) {
++        get_random_bytes (addr, ETH_ALEN);
++      addr [0] &= 0xfe;       /* clear multicast bit */
++      addr [0] |= 0x02;       /* set local assignment bit (IEEE802) */
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/cpu_hotplug.c linux-2.6.18-xen.hg/drivers/xen/core/cpu_hotplug.c
---- linux-2.6.18/drivers/xen/core/cpu_hotplug.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/cpu_hotplug.c 2007-12-23 11:15:33.551242507 +0100
-@@ -0,0 +1,172 @@
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/notifier.h>
-+#include <linux/cpu.h>
-+#include <xen/cpu_hotplug.h>
-+#include <xen/xenbus.h>
++#endif /* EFX_NEED_RANDOM_ETHER_ADDR */
 +
++#ifdef EFX_NEED_MSECS_TO_JIFFIES
 +/*
-+ * Set of CPUs that remote admin software will allow us to bring online.
-+ * Notified to us via xenbus.
++ * When we convert to jiffies then we interpret incoming values
++ * the following way:
++ *
++ * - negative values mean 'infinite timeout' (MAX_JIFFY_OFFSET)
++ *
++ * - 'too large' values [that would result in larger than
++ *   MAX_JIFFY_OFFSET values] mean 'infinite timeout' too.
++ *
++ * - all other values are converted to jiffies by either multiplying
++ *   the input value by a factor or dividing it with a factor
++ *
++ * We must also be careful about 32-bit overflows.
 + */
-+static cpumask_t xenbus_allowed_cpumask;
-+
-+/* Set of CPUs that local admin will allow us to bring online. */
-+static cpumask_t local_allowed_cpumask = CPU_MASK_ALL;
-+
-+static int local_cpu_hotplug_request(void)
++#ifndef MSEC_PER_SEC
++#define MSEC_PER_SEC  1000L
++#endif
++unsigned long msecs_to_jiffies(const unsigned int m)
 +{
 +      /*
-+       * We assume a CPU hotplug request comes from local admin if it is made
-+       * via a userspace process (i.e., one with a real mm_struct).
++       * Negative value, means infinite timeout:
 +       */
-+      return (current->mm != NULL);
-+}
-+
-+static void vcpu_hotplug(unsigned int cpu)
-+{
-+      int err;
-+      char dir[32], state[32];
-+
-+      if ((cpu >= NR_CPUS) || !cpu_possible(cpu))
-+              return;
-+
-+      sprintf(dir, "cpu/%d", cpu);
-+      err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
-+      if (err != 1) {
-+              printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
-+              return;
-+      }
++      if ((int)m < 0)
++              return MAX_JIFFY_OFFSET;
 +
-+      if (strcmp(state, "online") == 0) {
-+              cpu_set(cpu, xenbus_allowed_cpumask);
-+              (void)cpu_up(cpu);
-+      } else if (strcmp(state, "offline") == 0) {
-+              cpu_clear(cpu, xenbus_allowed_cpumask);
-+              (void)cpu_down(cpu);
-+      } else {
-+              printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
-+                     state, cpu);
-+      }
-+}
++#if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ)
++      /*
++       * HZ is equal to or smaller than 1000, and 1000 is a nice
++       * round multiple of HZ, divide with the factor between them,
++       * but round upwards:
++       */
++      return (m + (MSEC_PER_SEC / HZ) - 1) / (MSEC_PER_SEC / HZ);
++#elif HZ > MSEC_PER_SEC && !(HZ % MSEC_PER_SEC)
++      /*
++       * HZ is larger than 1000, and HZ is a nice round multiple of
++       * 1000 - simply multiply with the factor between them.
++       *
++       * But first make sure the multiplication result cannot
++       * overflow:
++       */
++      if (m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
++              return MAX_JIFFY_OFFSET;
 +
-+static void handle_vcpu_hotplug_event(
-+      struct xenbus_watch *watch, const char **vec, unsigned int len)
-+{
-+      int cpu;
-+      char *cpustr;
-+      const char *node = vec[XS_WATCH_PATH];
++      return m * (HZ / MSEC_PER_SEC);
++#else
++      /*
++       * Generic case - multiply, round and divide. But first
++       * check that if we are doing a net multiplication, that
++       * we wouldnt overflow:
++       */
++      if (HZ > MSEC_PER_SEC && m > jiffies_to_msecs(MAX_JIFFY_OFFSET))
++              return MAX_JIFFY_OFFSET;
 +
-+      if ((cpustr = strstr(node, "cpu/")) != NULL) {
-+              sscanf(cpustr, "cpu/%d", &cpu);
-+              vcpu_hotplug(cpu);
-+      }
++      return (m * HZ + MSEC_PER_SEC - 1) / MSEC_PER_SEC;
++#endif
 +}
++#endif /* EFX_NEED_MSECS_TO_JIFFIES */
 +
-+static int smpboot_cpu_notify(struct notifier_block *notifier,
-+                            unsigned long action, void *hcpu)
++#ifdef EFX_NEED_MSLEEP
++/**
++ * msleep - sleep safely even with waitqueue interruptions
++ * @msecs: Time in milliseconds to sleep for
++ */
++void msleep(unsigned int msecs)
 +{
-+      int cpu = (long)hcpu;
-+
-+      /*
-+       * We do this in a callback notifier rather than __cpu_disable()
-+       * because local_cpu_hotplug_request() does not work in the latter
-+       * as it's always executed from within a stopmachine kthread.
-+       */
-+      if ((action == CPU_DOWN_PREPARE) && local_cpu_hotplug_request())
-+              cpu_clear(cpu, local_allowed_cpumask);
++      unsigned long timeout = msecs_to_jiffies(msecs) + 1;
 +
-+      return NOTIFY_OK;
++      while (timeout)
++              timeout = schedule_timeout_uninterruptible(timeout);
 +}
++#endif
+--- linux-2.6.18.8/drivers/net/sfc/kernel_compat.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/kernel_compat.h        2008-05-19 00:33:28.865809986 +0300
+@@ -0,0 +1,925 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static int setup_cpu_watcher(struct notifier_block *notifier,
-+                            unsigned long event, void *data)
-+{
-+      int i;
++#ifndef EFX_KERNEL_COMPAT_H
++#define EFX_KERNEL_COMPAT_H
 +
-+      static struct xenbus_watch cpu_watch = {
-+              .node = "cpu",
-+              .callback = handle_vcpu_hotplug_event,
-+              .flags = XBWF_new_thread };
-+      (void)register_xenbus_watch(&cpu_watch);
++#include <linux/version.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/pci.h>
++#include <linux/workqueue.h>
++#include <linux/moduleparam.h>
++#include <linux/interrupt.h>
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
 +
-+      if (!is_initial_xendomain()) {
-+              for_each_possible_cpu(i)
-+                      vcpu_hotplug(i);
-+              printk(KERN_INFO "Brought up %ld CPUs\n",
-+                     (long)num_online_cpus());
-+      }
++#include "extraversion.h"
 +
-+      return NOTIFY_DONE;
-+}
++/*
++ * Kernel backwards compatibility
++ *
++ * This file provides macros that enable the driver to be compiled on
++ * any kernel from 2.6.9 onward (plus SLES 9 2.6.5), without requiring
++ * explicit version tests scattered throughout the code.
++ */
 +
-+static int __init setup_vcpu_hotplug_event(void)
-+{
-+      static struct notifier_block hotplug_cpu = {
-+              .notifier_call = smpboot_cpu_notify };
-+      static struct notifier_block xsn_cpu = {
-+              .notifier_call = setup_cpu_watcher };
++/**************************************************************************
++ *
++ * Version/config/architecture tests to set feature flags
++ *
++ **************************************************************************
++ *
++ * NOTE: For simplicity, these initial version tests cover kernel.org
++ * releases only.  Backported features in "enterprise" kernels are
++ * handled further down.
++ */
 +
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) &&      \
++      !(defined(EFX_DIST_SUSE) &&                      \
++        LINUX_VERSION_CODE == KERNEL_VERSION(2,6,5) && \
++        EFX_DIST_KVER_LEVEL_1 == 7)
++      #error "This kernel version is now unsupported"
++#endif
 +
-+      register_cpu_notifier(&hotplug_cpu);
-+      register_xenstore_notifier(&xsn_cpu);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,6)
++      #define EFX_NEED_RANDOM_ETHER_ADDR yes
++#endif
 +
-+      return 0;
-+}
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,7)
++      #define EFX_NEED_I2C_CLASS_HWMON yes
++      #define EFX_NEED_IF_MII yes
++      #define EFX_NEED_MSLEEP yes
++      #define EFX_NEED_MSECS_TO_JIFFIES yes
++#endif
 +
-+arch_initcall(setup_vcpu_hotplug_event);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,8)
++      #define EFX_USE_MTD_ERASE_FAIL_ADDR yes
++#else
++      #define EFX_NEED_MTD_ERASE_CALLBACK yes
++      #define EFX_NEED_DUMMY_PCI_DISABLE_MSI yes
++      #define EFX_NEED_DUMMY_MSIX yes
++#endif
 +
-+int smp_suspend(void)
-+{
-+      int cpu, err;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
++      #define EFX_NEED_BYTEORDER_TYPES yes
++#endif
 +
-+      for_each_online_cpu(cpu) {
-+              if (cpu == 0)
-+                      continue;
-+              err = cpu_down(cpu);
-+              if (err) {
-+                      printk(KERN_CRIT "Failed to take all CPUs "
-+                             "down: %d.\n", err);
-+                      for_each_possible_cpu(cpu)
-+                              vcpu_hotplug(cpu);
-+                      return err;
-+              }
-+      }
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
++      #define EFX_NEED_MMIOWB yes
++      #define EFX_NEED_PCI_SAVE_RESTORE_WRAPPERS yes
++#endif
 +
-+      return 0;
-+}
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
++      #define EFX_NEED_DUMMY_SUPPORTS_GMII yes
++      #define EFX_NEED_MII_CONSTANTS yes
++      #define EFX_NEED_MII_ETHTOOL_FIX yes
++      #define EFX_HAVE_MSIX_TABLE_RESERVED yes
++#endif
 +
-+void smp_resume(void)
-+{
-+      int cpu;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14)
++      #define EFX_NEED_SCHEDULE_TIMEOUT_INTERRUPTIBLE yes
++      #define EFX_NEED_SCHEDULE_TIMEOUT_UNINTERRUPTIBLE yes
++      #define EFX_NEED_GFP_T yes
++      #define EFX_NEED_KZALLOC yes
++#endif
 +
-+      for_each_possible_cpu(cpu)
-+              vcpu_hotplug(cpu);
-+}
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
++      #define EFX_NEED_SETUP_TIMER yes
++      #ifdef CONFIG_HUGETLB_PAGE
++              #define EFX_USE_COMPOUND_PAGES yes
++      #endif
++#else
++      #define EFX_USE_COMPOUND_PAGES yes
++#endif
 +
-+int cpu_up_check(unsigned int cpu)
-+{
-+      int rc = 0;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
++      #define EFX_NEED_MUTEX yes
++      #define EFX_NEED_SAFE_LISTS yes
++      #ifdef EFX_USE_COMPOUND_PAGES
++              #define EFX_NEED_COMPOUND_PAGE_FIX yes
++      #endif
++#endif
 +
-+      if (local_cpu_hotplug_request()) {
-+              cpu_set(cpu, local_allowed_cpumask);
-+              if (!cpu_isset(cpu, xenbus_allowed_cpumask)) {
-+                      printk("%s: attempt to bring up CPU %u disallowed by "
-+                             "remote admin.\n", __FUNCTION__, cpu);
-+                      rc = -EBUSY;
-+              }
-+      } else if (!cpu_isset(cpu, local_allowed_cpumask) ||
-+                 !cpu_isset(cpu, xenbus_allowed_cpumask)) {
-+              rc = -EBUSY;
-+      }
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
++      #define EFX_NEED_UNREGISTER_NETDEVICE_NOTIFIER_FIX yes
++      #define EFX_NEED_DEV_NOTICE yes
++#endif
 +
-+      return rc;
-+}
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++      #define EFX_NEED_IRQF_FLAGS yes
++      #define EFX_NEED_NETDEV_ALLOC_SKB yes
++      /* Fedora backported 2.6.18 netdevice.h changes */
++      #ifndef NETIF_F_GSO
++              #define EFX_NEED_NETIF_TX_LOCK yes
++      #endif
++#else
++      #define EFX_USE_MTD_WRITESIZE yes
++#endif
 +
-+void init_xenbus_allowed_cpumask(void)
-+{
-+      xenbus_allowed_cpumask = cpu_present_map;
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/evtchn.c linux-2.6.18-xen.hg/drivers/xen/core/evtchn.c
---- linux-2.6.18/drivers/xen/core/evtchn.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/evtchn.c      2007-12-23 11:15:33.554576016 +0100
-@@ -0,0 +1,1060 @@
-+/******************************************************************************
-+ * evtchn.c
-+ * 
-+ * Communication via Xen event channels.
-+ * 
-+ * Copyright (c) 2002-2005, K A Fraser
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++      #define EFX_NEED_IRQ_HANDLER_T yes
++      #define EFX_HAVE_IRQ_HANDLER_REGS yes
++#endif
 +
-+#include <linux/module.h>
-+#include <linux/irq.h>
-+#include <linux/interrupt.h>
-+#include <linux/sched.h>
-+#include <linux/kernel_stat.h>
-+#include <linux/version.h>
-+#include <asm/atomic.h>
-+#include <asm/system.h>
-+#include <asm/ptrace.h>
-+#include <asm/synch_bitops.h>
-+#include <xen/evtchn.h>
-+#include <xen/interface/event_channel.h>
-+#include <xen/interface/physdev.h>
-+#include <asm/hypervisor.h>
-+#include <linux/mc146818rtc.h> /* RTC_IRQ */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++      #define EFX_NEED_WORK_API_WRAPPERS yes
++      #define EFX_USE_FASTCALL yes
++      #define EFX_NEED_CSUM_UNFOLDED yes
++#endif
 +
-+/*
-+ * This lock protects updates to the following mapping and reference-count
-+ * arrays. The lock does not need to be acquired to read the mapping tables.
-+ */
-+static DEFINE_SPINLOCK(irq_mapping_update_lock);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
++      /*
++       * debugfs was introduced earlier, but only supports sym-links
++       * from 2.6.21
++       */
++      #ifdef CONFIG_DEBUG_FS
++              #define EFX_USE_DEBUGFS yes
++      #endif
++#endif
 +
-+/* IRQ <-> event-channel mappings. */
-+static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
-+      [0 ...  NR_EVENT_CHANNELS-1] = -1 };
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
++      #define EFX_NEED_SKB_HEADER_MACROS yes
++      #define EFX_NEED_HEX_DUMP yes
++#else
++      #define EFX_USE_CANCEL_WORK_SYNC yes
++#endif
 +
-+/* Packed IRQ information: binding type, sub-type index, and event channel. */
-+static u32 irq_info[NR_IRQS];
++#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,22)
++      #define EFX_NEED_HEX_DUMP_CONST_FIX yes
++#endif
 +
-+/* Binding types. */
-+enum {
-+      IRQT_UNBOUND,
-+      IRQT_PIRQ,
-+      IRQT_VIRQ,
-+      IRQT_IPI,
-+      IRQT_LOCAL_PORT,
-+      IRQT_CALLER_PORT
-+};
++#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)) && \
++    (LINUX_VERSION_CODE <  KERNEL_VERSION(2,6,23))
++      #define EFX_USE_ETHTOOL_GET_PERM_ADDR yes
++#endif
 +
-+/* Constructor for packed IRQ information. */
-+static inline u32 mk_irq_info(u32 type, u32 index, u32 evtchn)
-+{
-+      return ((type << 24) | (index << 16) | evtchn);
-+}
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23)
++      #ifdef __ia64__
++              /* csum_tcpudp_nofold() is extern but not exported */
++              #define EFX_NEED_CSUM_TCPUDP_NOFOLD yes
++      #endif
++#else
++      #define EFX_USE_PCI_DEV_REVISION yes
++      #define EFX_USE_CANCEL_DELAYED_WORK_SYNC yes
++#endif
 +
-+/* Convenient shorthand for packed representation of an unbound IRQ. */
-+#define IRQ_UNBOUND   mk_irq_info(IRQT_UNBOUND, 0, 0)
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
++      #define EFX_HAVE_OLD_NAPI yes
++      #define EFX_NEED_GENERIC_LRO yes
++      #define EFX_NEED_PRINT_MAC yes
++#else
++      #define EFX_USE_ETHTOOL_FLAGS yes
++#endif
 +
 +/*
-+ * Accessors for packed IRQ information.
++ * SFC Bug 4560: Some kernels leak IOMMU entries under heavy load.  Use a
++ * spinlock to serialise access where possible to alleviate the
++ * problem.
++ *
++ * NB. The following definition is duplicated in
++ * the char driver.  Please keep in sync.
 + */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17) && \
++     defined(__x86_64__) && defined(CONFIG_SMP))
++      #define EFX_NEED_IOMMU_LOCK yes
++      #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
++              #if defined(CONFIG_GART_IOMMU)
++                      #define EFX_NO_IOMMU no_iommu
++              #else
++                      #define EFX_NO_IOMMU 1
++              #endif
++      #else
++              #define EFX_NO_IOMMU 0
++      #endif
++#endif
 +
-+static inline unsigned int evtchn_from_irq(int irq)
-+{
-+      return (u16)(irq_info[irq]);
-+}
++#ifdef CONFIG_PPC64
++      /* __raw_writel and friends are broken on ppc64 */
++      #define EFX_NEED_RAW_READ_AND_WRITE_FIX yes
++#endif
 +
-+static inline unsigned int index_from_irq(int irq)
-+{
-+      return (u8)(irq_info[irq] >> 16);
-+}
++/**************************************************************************
++ *
++ * Exceptions for backported features
++ *
++ **************************************************************************
++ */
 +
-+static inline unsigned int type_from_irq(int irq)
-+{
-+      return (u8)(irq_info[irq] >> 24);
-+}
++/* RHEL4 */
++#if defined(EFX_DIST_RHEL) && LINUX_VERSION_CODE == KERNEL_VERSION(2,6,9)
++      #if EFX_DIST_KVER_LEVEL_1 >= 22
++              /* linux-2.6.9-mmiowb.patch */
++              #undef EFX_NEED_MMIOWB
++      #endif
++      #if EFX_DIST_KVER_LEVEL_1 >= 34
++              /* linux-2.6.9-net-mii-update.patch */
++              #undef EFX_NEED_DUMMY_SUPPORTS_GMII
++              #undef EFX_NEED_MII_CONSTANTS
++              #undef EFX_NEED_MII_ETHTOOL_FIX
++              /* linux-2.6.9-gfp_t-typedef.patch */
++              #undef EFX_NEED_GFP_T
++              /* linux-2.6.9-slab-update.patch */
++              #undef EFX_NEED_KZALLOC
++      #endif
++      #if EFX_DIST_KVER_LEVEL_1 >= 55
++              /* linux-2.6.18-sata-update.patch (ported from 2.6.18->2.6.9) */
++              #undef EFX_NEED_SCHEDULE_TIMEOUT_UNINTERRUPTIBLE
++              #undef EFX_NEED_IRQ_HANDLER_T
++      #endif
++#endif
 +
-+/* IRQ <-> VIRQ mapping. */
-+DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1};
++/* RHEL5 */
++#if defined(EFX_DIST_RHEL) && LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18)
++      #if EFX_DIST_KVER_LEVEL_1 >= 53
++              /* linux-2.6.18-sata-update.patch */
++              #undef EFX_NEED_SCHEDULE_TIMEOUT_UNINTERRUPTIBLE
++              #undef EFX_NEED_IRQ_HANDLER_T
++      #endif
++#endif
 +
-+/* IRQ <-> IPI mapping. */
-+#ifndef NR_IPIS
-+#define NR_IPIS 1
++#if defined(EFX_DIST_RHEL)
++      #if (LINUX_VERSION_CODE != KERNEL_VERSION(2,6,9)) && \
++           (LINUX_VERSION_CODE != KERNEL_VERSION(2,6,18))
++              #error "Unknown Red Hat Enterprise kernel version"
++      #endif
 +#endif
-+DEFINE_PER_CPU(int, ipi_to_irq[NR_IPIS]) = {[0 ... NR_IPIS-1] = -1};
 +
-+/* Reference counts for bindings to IRQs. */
-+static int irq_bindcount[NR_IRQS];
++/* SLES9 */
++#if defined(EFX_DIST_SUSE) && LINUX_VERSION_CODE == KERNEL_VERSION(2,6,5) && \
++      EFX_DIST_KVER_LEVEL_1 == 7
++      #if EFX_DIST_KVER_LEVEL_2 >= 139
++              #undef EFX_NEED_MMIOWB
++      #endif
++      #if EFX_DIST_KVER_LEVEL_2 >= 191
++              #undef EFX_NEED_MSLEEP
++              #undef EFX_NEED_MSECS_TO_JIFFIES
++      #endif
++      #if EFX_DIST_KVER_LEVEL_2 >= 244
++              #undef EFX_NEED_BYTEORDER_TYPES
++      #endif
++      #if EFX_DIST_KVER_LEVEL_2 >= 252
++              #undef EFX_NEED_KZALLOC
++      #endif
++#endif
 +
-+/* Bitmap indicating which PIRQs require Xen to be notified on unmask. */
-+static DECLARE_BITMAP(pirq_needs_eoi, NR_PIRQS);
++/**************************************************************************
++ *
++ * Definitions of missing constants, types, functions and macros
++ *
++ **************************************************************************
++ *
++ */
 +
-+#ifdef CONFIG_SMP
++#ifndef DMA_40BIT_MASK
++      #define DMA_40BIT_MASK  0x000000ffffffffffULL
++#endif
 +
-+static u8 cpu_evtchn[NR_EVENT_CHANNELS];
-+static unsigned long cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG];
++#ifndef spin_trylock_irqsave
++      #define spin_trylock_irqsave(lock, flags)       \
++      ({                                              \
++              local_irq_save(flags);                  \
++              spin_trylock(lock) ?                    \
++              1 : ({local_irq_restore(flags); 0;});   \
++      })
++#endif
 +
-+static inline unsigned long active_evtchns(unsigned int cpu, shared_info_t *sh,
-+                                         unsigned int idx)
-+{
-+      return (sh->evtchn_pending[idx] &
-+              cpu_evtchn_mask[cpu][idx] &
-+              ~sh->evtchn_mask[idx]);
-+}
++#ifndef raw_smp_processor_id
++      #define raw_smp_processor_id() (current_thread_info()->cpu)
++#endif
 +
-+static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
-+{
-+      shared_info_t *s = HYPERVISOR_shared_info;
-+      int irq = evtchn_to_irq[chn];
++#ifndef NETIF_F_LRO
++      #define NETIF_F_LRO 0
++#endif
 +
-+      BUG_ON(!test_bit(chn, s->evtchn_mask));
++/* Cope with small changes in PCI constants between minor kernel revisions */
++#if PCI_X_STATUS != 4
++      #undef PCI_X_STATUS
++      #define PCI_X_STATUS 4
++      #undef PCI_X_STATUS_MAX_SPLIT
++      #define PCI_X_STATUS_MAX_SPLIT 0x03800000
++#endif
 +
-+      if (irq != -1)
-+              set_native_irq_info(irq, cpumask_of_cpu(cpu));
++#ifndef PCI_EXP_LNKSTA
++      #define PCI_EXP_LNKSTA          18          /* Link Status */
++#endif
 +
-+      clear_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu_evtchn[chn]]);
-+      set_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu]);
-+      cpu_evtchn[chn] = cpu;
-+}
++/* Used for struct pt_regs */
++#ifndef regs_return_value
++      #if defined(__x86_64__)
++              #define regs_return_value(regs) ((regs)->rax)
++      #elif defined(__i386__)
++              #define regs_return_value(regs) ((regs)->eax)
++      #elif defined(__ia64__)
++              #define regs_return_value(regs) ((regs)->r8)
++      #else
++              #error "Need definition for regs_return_value()"
++      #endif
++#endif
 +
-+static void init_evtchn_cpu_bindings(void)
-+{
-+      int i;
++#ifndef __GFP_COMP
++      #define __GFP_COMP 0
++#endif
 +
-+      /* By default all event channels notify CPU#0. */
-+      for (i = 0; i < NR_IRQS; i++)
-+              set_native_irq_info(i, cpumask_of_cpu(0));
++#ifndef __iomem
++      #define __iomem
++#endif
 +
-+      memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
-+      memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
-+}
++#ifndef NET_IP_ALIGN
++      #define NET_IP_ALIGN 2
++#endif
 +
-+static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
-+{
-+      return cpu_evtchn[evtchn];
-+}
++#ifndef PCI_CAP_ID_EXP
++#define PCI_CAP_ID_EXP                0x10    /* PCI Express */
++#endif
 +
-+#else
++#ifndef PCI_EXP_FLAGS
++#define PCI_EXP_FLAGS           2           /* Capabilities register */
++#define PCI_EXP_FLAGS_TYPE      0x00f0      /* Capability version */
++#define PCI_EXP_TYPE_ENDPOINT   0x0         /* Express Endpoint */
++#define PCI_EXP_TYPE_LEG_END    0x1         /* Legacy Endpoint */
++#define PCI_EXP_TYPE_ROOT_PORT  0x4         /* Root Port */
++#endif
 +
-+static inline unsigned long active_evtchns(unsigned int cpu, shared_info_t *sh,
-+                                         unsigned int idx)
-+{
-+      return (sh->evtchn_pending[idx] & ~sh->evtchn_mask[idx]);
-+}
++#ifndef PCI_EXP_DEVCAP
++#define PCI_EXP_DEVCAP          4           /* Device capabilities */
++#define PCI_EXP_DEVCAP_PAYLOAD  0x07        /* Max_Payload_Size */
++#define PCI_EXP_DEVCAP_PWR_VAL  0x3fc0000   /* Slot Power Limit Value */
++#define PCI_EXP_DEVCAP_PWR_SCL  0xc000000   /* Slot Power Limit Scale */
++#endif
 +
-+static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
-+{
-+}
++#ifndef PCI_EXP_DEVCTL
++#define PCI_EXP_DEVCTL          8           /* Device Control */
++#define PCI_EXP_DEVCTL_PAYLOAD  0x00e0      /* Max_Payload_Size */
++#define PCI_EXP_DEVCTL_READRQ   0x7000      /* Max_Read_Request_Size */
++#endif
 +
-+static void init_evtchn_cpu_bindings(void)
-+{
-+}
++#ifndef PCI_EXP_LNKSTA
++#define PCI_EXP_LNKSTA                18          /* Link Status */
++#endif
 +
-+static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
-+{
-+      return 0;
-+}
++#ifndef NETDEV_TX_OK
++      #define NETDEV_TX_OK 0
++#endif
 +
++#ifndef NETDEV_TX_BUSY
++      #define NETDEV_TX_BUSY 1
 +#endif
 +
-+/* Upcall to generic IRQ layer. */
-+#ifdef CONFIG_X86
-+extern fastcall unsigned int do_IRQ(struct pt_regs *regs);
-+void __init xen_init_IRQ(void);
-+void __init init_IRQ(void)
-+{
-+      irq_ctx_init(0);
-+      xen_init_IRQ();
-+}
-+#if defined (__i386__)
-+static inline void exit_idle(void) {}
-+#define IRQ_REG orig_eax
-+#elif defined (__x86_64__)
-+#include <asm/idle.h>
-+#define IRQ_REG orig_rax
++#ifndef __force
++      #define __force
 +#endif
-+#define do_IRQ(irq, regs) do {                \
-+      (regs)->IRQ_REG = ~(irq);       \
-+      do_IRQ((regs));                 \
-+} while (0)
-+#elif defined (__powerpc__)
-+#define do_IRQ(irq, regs)     __do_IRQ(irq, regs)
-+static inline void exit_idle(void) {}
++
++#if ! defined(for_each_cpu_mask) && ! defined(CONFIG_SMP)
++      #define for_each_cpu_mask(cpu, mask)            \
++              for ((cpu) = 0; (cpu) < 1; (cpu)++, (void)mask)
 +#endif
 +
-+/* Xen will never allocate port zero for any purpose. */
-+#define VALID_EVTCHN(chn)     ((chn) != 0)
++/**************************************************************************/
 +
-+/*
-+ * Force a proper event-channel callback from Xen after clearing the
-+ * callback mask. We do this in a very simple manner, by making a call
-+ * down into Xen. The pending flag will be checked by Xen on return.
-+ */
-+void force_evtchn_callback(void)
-+{
-+      (void)HYPERVISOR_xen_version(0, NULL);
-+}
-+/* Not a GPL symbol: used in ubiquitous macros, so too restrictive. */
-+EXPORT_SYMBOL(force_evtchn_callback);
++#ifdef EFX_NEED_IRQ_HANDLER_T
++      typedef irqreturn_t (*irq_handler_t)(int, void *, struct pt_regs *);
++#endif
 +
-+static DEFINE_PER_CPU(unsigned int, upcall_count) = { 0 };
-+static DEFINE_PER_CPU(unsigned int, last_processed_l1i) = { BITS_PER_LONG - 1 };
-+static DEFINE_PER_CPU(unsigned int, last_processed_l2i) = { BITS_PER_LONG - 1 };
++#ifdef EFX_NEED_I2C_CLASS_HWMON
++      #define I2C_CLASS_HWMON (1<<0)
++#endif
 +
-+/* NB. Interrupts are disabled on entry. */
-+asmlinkage void evtchn_do_upcall(struct pt_regs *regs)
-+{
-+      unsigned long       l1, l2;
-+      unsigned long       masked_l1, masked_l2;
-+      unsigned int        l1i, l2i, port, count;
-+      int                 irq, cpu = smp_processor_id();
-+      shared_info_t      *s = HYPERVISOR_shared_info;
-+      vcpu_info_t        *vcpu_info = &s->vcpu_info[cpu];
++#ifdef EFX_NEED_MII_CONSTANTS
++      #define MII_CTRL1000            0x09
++      #define MII_STAT1000            0x0a
++      #define BMCR_SPEED1000          0x0040
++      #define ADVERTISE_PAUSE_ASYM    0x0800
++      #define ADVERTISE_PAUSE_CAP     0x0400
++      #define LPA_PAUSE_ASYM          0x0800
++      #define LPA_PAUSE_CAP           0x0400
++      #define ADVERTISE_1000FULL      0x0200
++      #define ADVERTISE_1000HALF      0x0100
++      #define LPA_1000FULL            0x0800
++      #define LPA_1000HALF            0x0400
++#endif
 +
++#ifdef EFX_NEED_DUMMY_SUPPORTS_GMII
++      #include <linux/mii.h>
++      /* Ugly; redirect nonexistent new field to an old unused field */
++      #undef supports_gmii
++      #define supports_gmii full_duplex
++#endif
 +
-+      do {
-+              /* Avoid a callback storm when we reenable delivery. */
-+              vcpu_info->evtchn_upcall_pending = 0;
++#ifdef EFX_NEED_SKB_HEADER_MACROS
++      #define skb_mac_header(skb)     (skb)->mac.raw
++      #define skb_network_header(skb) (skb)->nh.raw
++      #define tcp_hdr(skb)            (skb)->h.th
++      #define ip_hdr(skb)             (skb)->nh.iph
++      #define skb_tail_pointer(skb)   (skb)->tail
++#endif
 +
-+              /* Nested invocations bail immediately. */
-+              if (unlikely(per_cpu(upcall_count, cpu)++))
-+                      return;
++#ifdef EFX_NEED_RAW_READ_AND_WRITE_FIX
++      #include <asm/io.h>
++      static inline void
++      efx_raw_writeb(u8 value, volatile void __iomem *addr)
++      {
++              writeb(value, addr);
++      }
++      static inline void
++      efx_raw_writew(u16 value, volatile void __iomem *addr)
++      {
++              writew(le16_to_cpu(value), addr);
++      }
++      static inline void
++      efx_raw_writel(u32 value, volatile void __iomem *addr)
++      {
++              writel(le32_to_cpu(value), addr);
++      }
++      static inline void
++      efx_raw_writeq(u64 value, volatile void __iomem *addr)
++      {
++              writeq(le64_to_cpu(value), addr);
++      }
++      static inline u8
++      efx_raw_readb(const volatile void __iomem *addr)
++      {
++              return readb(addr);
++      }
++      static inline u16
++      efx_raw_readw(const volatile void __iomem *addr)
++      {
++              return cpu_to_le16(readw(addr));
++      }
++      static inline u32
++      efx_raw_readl(const volatile void __iomem *addr)
++      {
++              return cpu_to_le32(readl(addr));
++      }
++      static inline u64
++      efx_raw_readq(const volatile void __iomem *addr)
++      {
++              return cpu_to_le64(readq(addr));
++      }
++
++      #undef __raw_writeb
++      #undef __raw_writew
++      #undef __raw_writel
++      #undef __raw_writeq
++      #undef __raw_readb
++      #undef __raw_readw
++      #undef __raw_readl
++      #undef __raw_readq
++      #define __raw_writeb efx_raw_writeb
++      #define __raw_writew efx_raw_writew
++      #define __raw_writel efx_raw_writel
++      #define __raw_writeq efx_raw_writeq
++      #define __raw_readb efx_raw_readb
++      #define __raw_readw efx_raw_readw
++      #define __raw_readl efx_raw_readl
++      #define __raw_readq efx_raw_readq
++#endif
++
++#ifdef EFX_NEED_SCHEDULE_TIMEOUT_INTERRUPTIBLE
++      static inline signed long
++      schedule_timeout_interruptible(signed long timeout)
++      {
++              set_current_state(TASK_INTERRUPTIBLE);
++              return schedule_timeout(timeout);
++      }
++#endif
 +
-+#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
-+              /* Clear master flag /before/ clearing selector flag. */
-+              rmb();
++#ifdef EFX_NEED_SCHEDULE_TIMEOUT_UNINTERRUPTIBLE
++      static inline signed long
++      schedule_timeout_uninterruptible(signed long timeout)
++      {
++              set_current_state(TASK_UNINTERRUPTIBLE);
++              return schedule_timeout(timeout);
++      }
 +#endif
-+              l1 = xchg(&vcpu_info->evtchn_pending_sel, 0);
 +
-+              l1i = per_cpu(last_processed_l1i, cpu);
-+              l2i = per_cpu(last_processed_l2i, cpu);
++#ifdef EFX_NEED_MMIOWB
++      #if defined(__i386__) || defined(__x86_64__)
++              #define mmiowb()
++      #elif defined(__ia64__)
++              #ifndef ia64_mfa
++                      #define ia64_mfa() asm volatile ("mf.a" ::: "memory")
++              #endif
++              #define mmiowb ia64_mfa
++      #else
++              #error "Need definition for mmiowb()"
++      #endif
++#endif
 +
-+              while (l1 != 0) {
++#ifdef EFX_NEED_KZALLOC
++      static inline void *kzalloc(size_t size, int flags)
++      {
++              void *buf = kmalloc(size, flags);
++              if (buf)
++                      memset(buf, 0,size);
++              return buf;
++      }
++#endif
 +
-+                      l1i = (l1i + 1) % BITS_PER_LONG;
-+                      masked_l1 = l1 & ((~0UL) << l1i);
++#ifdef EFX_NEED_SETUP_TIMER
++      static inline void setup_timer(struct timer_list * timer,
++                                     void (*function)(unsigned long),
++                                     unsigned long data)
++      {
++              timer->function = function;
++              timer->data = data;
++              init_timer(timer);
++      }
++#endif
 +
-+                      if (masked_l1 == 0) { /* if we masked out all events, wrap around to the beginning */
-+                              l1i = BITS_PER_LONG - 1;
-+                              l2i = BITS_PER_LONG - 1;
-+                              continue;
-+                      }
-+                      l1i = __ffs(masked_l1);
++#ifdef EFX_NEED_MUTEX
++      #define EFX_DEFINE_MUTEX(x) DECLARE_MUTEX(x)
++      #undef DEFINE_MUTEX
++      #define DEFINE_MUTEX EFX_DEFINE_MUTEX
 +
-+                      do {
-+                              l2 = active_evtchns(cpu, s, l1i);
++      #define efx_mutex semaphore
++      #undef mutex
++      #define mutex efx_mutex
 +
-+                              l2i = (l2i + 1) % BITS_PER_LONG;
-+                              masked_l2 = l2 & ((~0UL) << l2i);
++      #define efx_mutex_init(x) init_MUTEX(x)
++      #undef mutex_init
++      #define mutex_init efx_mutex_init
 +
-+                              if (masked_l2 == 0) { /* if we masked out all events, move on */
-+                                      l2i = BITS_PER_LONG - 1;
-+                                      break;
-+                              }
++      #define efx_mutex_destroy(x) do { } while(0)
++      #undef mutex_destroy
++      #define mutex_destroy efx_mutex_destroy
 +
-+                              l2i = __ffs(masked_l2);
++      #define efx_mutex_lock(x) down(x)
++      #undef mutex_lock
++      #define mutex_lock efx_mutex_lock
 +
-+                              /* process port */
-+                              port = (l1i * BITS_PER_LONG) + l2i;
-+                              if ((irq = evtchn_to_irq[port]) != -1)
-+                                      do_IRQ(irq, regs);
-+                              else {
-+                                      exit_idle();
-+                                      evtchn_device_upcall(port);
-+                              }
++      #define efx_mutex_lock_interruptible(x) down_interruptible(x)
++      #undef mutex_lock_interruptible
++      #define mutex_lock_interruptible efx_mutex_lock_interruptible
 +
-+                              /* if this is the final port processed, we'll pick up here+1 next time */
-+                              per_cpu(last_processed_l1i, cpu) = l1i;
-+                              per_cpu(last_processed_l2i, cpu) = l2i;
++      #define efx_mutex_unlock(x) up(x)
++      #undef mutex_unlock
++      #define mutex_unlock efx_mutex_unlock
 +
-+                      } while (l2i != BITS_PER_LONG - 1);
++      #define efx_mutex_trylock(x) (!down_trylock(x))
++      #undef mutex_trylock
++      #define mutex_trylock efx_mutex_trylock
 +
-+                      l2 = active_evtchns(cpu, s, l1i);
-+                      if (l2 == 0) /* we handled all ports, so we can clear the selector bit */
-+                              l1 &= ~(1UL << l1i);
++      static inline int efx_mutex_is_locked(struct efx_mutex *m)
++      {
++              /* NB. This is quite inefficient, but it's the best we
++               * can do with the semaphore API. */
++              if ( down_trylock(m) )
++                      return 1;
++              /* Undo the effect of down_trylock. */
++              up(m);
++              return 0;
++      }
++      #undef mutex_is_locked
++      #define mutex_is_locked efx_mutex_is_locked
++#endif
 +
-+              }
++#ifndef NETIF_F_GSO
++      #define efx_gso_size tso_size
++      #undef gso_size
++      #define gso_size efx_gso_size
++      #define efx_gso_segs tso_segs
++      #undef gso_segs
++      #define gso_segs efx_gso_segs
++#endif
 +
-+              /* If there were nested callbacks then we have more to do. */
-+              count = per_cpu(upcall_count, cpu);
-+              per_cpu(upcall_count, cpu) = 0;
-+      } while (unlikely(count != 1));
-+}
++#ifdef EFX_NEED_IRQF_FLAGS
++      #ifdef SA_PROBEIRQ
++              #define IRQF_PROBE_SHARED  SA_PROBEIRQ
++      #else
++              #define IRQF_PROBE_SHARED  0
++      #endif
++      #define IRQF_SHARED        SA_SHIRQ
++#endif
 +
-+static int find_unbound_irq(void)
-+{
-+      static int warned;
-+      int dynirq, irq;
++#ifdef EFX_NEED_NETDEV_ALLOC_SKB
++      #ifndef NET_SKB_PAD
++              #define NET_SKB_PAD 16
++      #endif
 +
-+      for (dynirq = 0; dynirq < NR_DYNIRQS; dynirq++) {
-+              irq = dynirq_to_irq(dynirq);
-+              if (irq_bindcount[irq] == 0)
-+                      return irq;
++      static inline
++      struct sk_buff *netdev_alloc_skb(struct net_device *dev,
++                                       unsigned int length)
++      {
++              struct sk_buff *skb = alloc_skb(length + NET_SKB_PAD,
++                                              GFP_ATOMIC | __GFP_COLD);
++              if (likely(skb)) {
++                      skb_reserve(skb, NET_SKB_PAD);
++                      skb->dev = dev;
++              }
++              return skb;
 +      }
++#endif
 +
-+      if (!warned) {
-+              warned = 1;
-+              printk(KERN_WARNING "No available IRQ to bind to: "
-+                     "increase NR_DYNIRQS.\n");
++#ifdef EFX_NEED_NETIF_TX_LOCK
++      static inline void netif_tx_lock(struct net_device *dev)
++      {
++              spin_lock(&dev->xmit_lock);
++              dev->xmit_lock_owner = smp_processor_id();
++      }
++      static inline void netif_tx_lock_bh(struct net_device *dev)
++      {
++              spin_lock_bh(&dev->xmit_lock);
++              dev->xmit_lock_owner = smp_processor_id();
++      }
++      static inline void netif_tx_unlock_bh(struct net_device *dev)
++      {
++              dev->xmit_lock_owner = -1;
++              spin_unlock_bh(&dev->xmit_lock);
++      }
++      static inline void netif_tx_unlock(struct net_device *dev)
++      {
++              dev->xmit_lock_owner = -1;
++              spin_unlock(&dev->xmit_lock);
 +      }
++#endif
 +
-+      return -ENOSPC;
-+}
++#ifdef EFX_NEED_CSUM_UNFOLDED
++      typedef u32 __wsum;
++      #define csum_unfold(x) ((__force __wsum) x)
++#endif
 +
-+static int bind_caller_port_to_irq(unsigned int caller_port)
-+{
-+      int irq;
++#ifdef EFX_NEED_HEX_DUMP
++      enum {
++              DUMP_PREFIX_NONE,
++              DUMP_PREFIX_ADDRESS,
++              DUMP_PREFIX_OFFSET
++      };
++#endif
 +
-+      spin_lock(&irq_mapping_update_lock);
++#ifdef EFX_NEED_PRINT_MAC
++      #define DECLARE_MAC_BUF(var) char var[18] __attribute__((unused))
++#endif
 +
-+      if ((irq = evtchn_to_irq[caller_port]) == -1) {
-+              if ((irq = find_unbound_irq()) < 0)
-+                      goto out;
++#ifdef EFX_NEED_GFP_T
++      typedef unsigned int gfp_t;
++#endif
 +
-+              evtchn_to_irq[caller_port] = irq;
-+              irq_info[irq] = mk_irq_info(IRQT_CALLER_PORT, 0, caller_port);
++#ifdef EFX_NEED_SAFE_LISTS
++      #define list_for_each_entry_safe_reverse(pos, n, head, member)       \
++              for (pos = list_entry((head)->prev, typeof(*pos), member),   \
++                   n = list_entry(pos->member.prev, typeof(*pos), member); \
++                   &pos->member != (head);                                 \
++                   pos = n,                                                \
++                   n = list_entry(n->member.prev, typeof(*n), member))
++#endif
++
++#ifdef EFX_NEED_DEV_NOTICE
++      #define dev_notice dev_warn
++#endif
++
++#ifdef EFX_NEED_IF_MII
++      #include <linux/mii.h>
++      static inline struct mii_ioctl_data *efx_if_mii ( struct ifreq *rq ) {
++              return ( struct mii_ioctl_data * ) &rq->ifr_ifru;
 +      }
++      #undef if_mii
++      #define if_mii efx_if_mii
++#endif
 +
-+      irq_bindcount[irq]++;
++#ifdef EFX_NEED_MTD_ERASE_CALLBACK
++      #include <linux/mtd/mtd.h>
++      static inline void efx_mtd_erase_callback(struct erase_info *instr) {
++              if ( instr->callback )
++                      instr->callback ( instr );
++      }
++      #undef mtd_erase_callback
++      #define mtd_erase_callback efx_mtd_erase_callback
++#endif
 +
-+ out:
-+      spin_unlock(&irq_mapping_update_lock);
-+      return irq;
-+}
++#ifdef EFX_NEED_DUMMY_PCI_DISABLE_MSI
++      #include <linux/pci.h>
++      static inline void dummy_pci_disable_msi ( struct pci_dev *dev ) {
++              /* Do nothing */
++      }
++      #undef pci_disable_msi
++      #define pci_disable_msi dummy_pci_disable_msi
++#endif
 +
-+static int bind_local_port_to_irq(unsigned int local_port)
-+{
-+      int irq;
++#ifdef EFX_NEED_DUMMY_MSIX
++      struct msix_entry {
++              u16     vector; /* kernel uses to write allocated vector */
++              u16     entry;  /* driver uses to specify entry, OS writes */
++      };
++      static inline int pci_enable_msix(struct pci_dev* dev,
++                                        struct msix_entry *entries, int nvec)
++              {return -1;}
++      static inline void pci_disable_msix(struct pci_dev *dev) { /* Do nothing */}
++#endif
 +
-+      spin_lock(&irq_mapping_update_lock);
++#ifdef EFX_NEED_BYTEORDER_TYPES
++      typedef __u16 __be16;
++      typedef __u32 __be32;
++      typedef __u64 __be64;
++      typedef __u16 __le16;
++      typedef __u32 __le32;
++      typedef __u64 __le64;
++#endif
 +
-+      BUG_ON(evtchn_to_irq[local_port] != -1);
++/**************************************************************************
++ *
++ * Missing functions provided by kernel_compat.c
++ *
++ **************************************************************************
++ *
++ */
++#ifdef EFX_NEED_RANDOM_ETHER_ADDR
++      extern void efx_random_ether_addr(uint8_t *addr);
++      #ifndef EFX_IN_KCOMPAT_C
++              #undef random_ether_addr
++              #define random_ether_addr efx_random_ether_addr
++      #endif
++#endif
 +
-+      if ((irq = find_unbound_irq()) < 0) {
-+              struct evtchn_close close = { .port = local_port };
-+              if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
-+                      BUG();
-+              goto out;
-+      }
++#ifdef EFX_NEED_MII_ETHTOOL_FIX
++      extern int efx_mii_ethtool_gset(struct mii_if_info *mii,
++                                      struct ethtool_cmd *ecmd);
++      extern int efx_mii_ethtool_sset(struct mii_if_info *mii,
++                                      struct ethtool_cmd *ecmd);
++      #ifndef EFX_IN_KCOMPAT_C
++              #undef mii_ethtool_gset
++              #define mii_ethtool_gset efx_mii_ethtool_gset
++              #undef mii_ethtool_sset
++              #define mii_ethtool_sset efx_mii_ethtool_sset
++      #endif
++#endif
 +
-+      evtchn_to_irq[local_port] = irq;
-+      irq_info[irq] = mk_irq_info(IRQT_LOCAL_PORT, 0, local_port);
-+      irq_bindcount[irq]++;
++#ifdef EFX_NEED_UNREGISTER_NETDEVICE_NOTIFIER_FIX
++      extern int efx_unregister_netdevice_notifier(struct notifier_block *nb);
++      #ifndef EFX_IN_KCOMPAT_C
++              #undef unregister_netdevice_notifier
++              #define unregister_netdevice_notifier \
++                              efx_unregister_netdevice_notifier
++      #endif
++#endif
 +
-+ out:
-+      spin_unlock(&irq_mapping_update_lock);
-+      return irq;
-+}
++#ifdef EFX_NEED_IOMMU_LOCK
++      extern dma_addr_t efx_pci_map_single(struct pci_dev *pci, void *ptr,
++                                           size_t size, int direction);
++      extern void efx_pci_unmap_single(struct pci_dev *pci,
++                                       dma_addr_t dma_addr, size_t size,
++                                       int direction);
++      extern void * efx_pci_alloc_consistent(struct pci_dev *pci,
++                                             size_t size,
++                                             dma_addr_t *dma_addr);
++      extern void efx_pci_free_consistent(struct pci_dev *pci,
++                                          size_t size, void *ptr,
++                                          dma_addr_t dma_addr);
++      #ifndef EFX_IN_KCOMPAT_C
++              #undef pci_map_single
++              #undef pci_unmap_single
++              #undef pci_alloc_consistent
++              #undef pci_free_consistent
++              #define pci_map_single efx_pci_map_single
++              #define pci_unmap_single efx_pci_unmap_single
++              #define pci_alloc_consistent efx_pci_alloc_consistent
++              #define pci_free_consistent efx_pci_free_consistent
++      #endif
++#endif
 +
-+static int bind_listening_port_to_irq(unsigned int remote_domain)
-+{
-+      struct evtchn_alloc_unbound alloc_unbound;
-+      int err;
++#ifdef EFX_NEED_PRINT_MAC
++      extern char *print_mac(char *buf, const u8 *addr);
++#endif
 +
-+      alloc_unbound.dom        = DOMID_SELF;
-+      alloc_unbound.remote_dom = remote_domain;
++#ifdef EFX_NEED_COMPOUND_PAGE_FIX
++      extern void efx_compound_page_destructor(struct page *page);
++#endif
 +
-+      err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
-+                                        &alloc_unbound);
++#ifdef EFX_NEED_HEX_DUMP
++      extern void
++      print_hex_dump(const char *level, const char *prefix_str,
++                     int prefix_type, int rowsize, int groupsize,
++                     const void *buf, size_t len, int ascii);
++#endif
 +
-+      return err ? : bind_local_port_to_irq(alloc_unbound.port);
-+}
++#ifdef EFX_NEED_MSECS_TO_JIFFIES
++      extern unsigned long msecs_to_jiffies(const unsigned int m);
++#endif
 +
-+static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
-+                                        unsigned int remote_port)
-+{
-+      struct evtchn_bind_interdomain bind_interdomain;
-+      int err;
++#ifdef EFX_NEED_MSLEEP
++      extern void msleep(unsigned int msecs);
++#endif
 +
-+      bind_interdomain.remote_dom  = remote_domain;
-+      bind_interdomain.remote_port = remote_port;
++/**************************************************************************
++ *
++ * Wrappers to fix bugs and parameter changes
++ *
++ **************************************************************************
++ *
++ */
 +
-+      err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
-+                                        &bind_interdomain);
++#ifdef EFX_NEED_PCI_SAVE_RESTORE_WRAPPERS
++      #define pci_save_state(_dev)                                    \
++              pci_save_state(_dev, (_dev)->saved_config_space)
 +
-+      return err ? : bind_local_port_to_irq(bind_interdomain.local_port);
-+}
++      #define pci_restore_state(_dev)                                 \
++              pci_restore_state(_dev, (_dev)->saved_config_space)
++#endif
 +
-+static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
-+{
-+      struct evtchn_bind_virq bind_virq;
-+      int evtchn, irq;
++#ifdef EFX_NEED_WORK_API_WRAPPERS
++      /**
++       * queue_delayed_work in pre 2.6.20 can't rearm from inside
++       * the work member. So instead do a rather hacky sleep
++       */
++      #define delayed_work work_struct
++      #define INIT_DELAYED_WORK INIT_WORK
 +
-+      spin_lock(&irq_mapping_update_lock);
++      static int inline efx_queue_delayed_work(struct workqueue_struct *wq,
++                                               struct work_struct *work,
++                                               unsigned long delay)
++      {
++              if (unlikely(delay > 0))
++                      schedule_timeout_uninterruptible(delay);
++              return queue_work(wq, work);
++      }
++      #define queue_delayed_work efx_queue_delayed_work
 +
-+      if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) {
-+              if ((irq = find_unbound_irq()) < 0)
-+                      goto out;
++      /**
++       * The old and new work-function prototypes just differ
++       * in the type of the pointer returned, so it's safe
++       * to cast between the prototypes.
++       */
++      typedef void (*efx_old_work_func_t)(void *p);
++
++      #undef INIT_WORK
++      #define INIT_WORK(_work, _func)                                 \
++              do {                                                    \
++                      INIT_LIST_HEAD(&(_work)->entry);                \
++                      (_work)->pending = 0;                           \
++                      PREPARE_WORK((_work),                           \
++                                   (efx_old_work_func_t) (_func),     \
++                                   (_work));                          \
++              } while (0)
++#endif
++
++#ifdef EFX_HAVE_OLD_NAPI
++      #define napi_str napi_dev[0]
++
++      static inline void netif_napi_add(struct net_device *dev,
++                                        struct net_device *dummy,
++                                        int (*poll) (struct net_device *,
++                                                     int *),
++                                        int weight)
++      {
++              dev->weight = weight;
++              dev->poll = poll;
++      }
 +
-+              bind_virq.virq = virq;
-+              bind_virq.vcpu = cpu;
-+              if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
-+                                              &bind_virq) != 0)
-+                      BUG();
-+              evtchn = bind_virq.port;
++      #define napi_enable netif_poll_enable
++      #define napi_disable netif_poll_disable
 +
-+              evtchn_to_irq[evtchn] = irq;
-+              irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
++      #define netif_rx_complete(dev, dummy) netif_rx_complete(dev)
++#endif
 +
-+              per_cpu(virq_to_irq, cpu)[virq] = irq;
++#ifdef EFX_NEED_COMPOUND_PAGE_FIX
++      static inline
++      struct page *efx_alloc_pages(gfp_t flags, unsigned int order)
++      {
++              struct page *p = alloc_pages(flags, order);
++              if ((flags & __GFP_COMP) && (p != NULL) && (order > 0))
++                      p[1].mapping = (void *)efx_compound_page_destructor;
++              return p;
++      }
++      #undef alloc_pages
++      #define alloc_pages efx_alloc_pages
 +
-+              bind_evtchn_to_cpu(evtchn, cpu);
++      static inline
++      void efx_free_pages(struct page *p, unsigned int order)
++      {
++              if ((order > 0) && (page_count(p) == 1))
++                      p[1].mapping = NULL;
++              __free_pages(p, order);
 +      }
++      #define __free_pages efx_free_pages
++#endif
 +
-+      irq_bindcount[irq]++;
++#ifdef EFX_NEED_HEX_DUMP_CONST_FIX
++      #define print_hex_dump(v,s,t,r,g,b,l,a) \
++              print_hex_dump((v),(s),(t),(r),(g),(void*)(b),(l),(a))
++#endif
 +
-+ out:
-+      spin_unlock(&irq_mapping_update_lock);
-+      return irq;
-+}
++#endif /* EFX_KERNEL_COMPAT_H */
+--- linux-2.6.18.8/drivers/net/sfc/lm87_support.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/lm87_support.c 2008-05-19 00:33:29.309835579 +0300
+@@ -0,0 +1,295 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2007:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************/
 +
-+static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
-+{
-+      struct evtchn_bind_ipi bind_ipi;
-+      int evtchn, irq;
++#include "net_driver.h"
++#include "lm87_support.h"
++#include "workarounds.h"
 +
-+      spin_lock(&irq_mapping_update_lock);
++/* Setting this to 1 will cause efx_check_lm87 to dump the status when it
++ * detects an alarm. This will result in the canonical name (i.e. that in
++ * the LM87 data book) being printed for each set status bit, along with
++ * the reading for that sensor value, if applicable. If set to 0 only the
++ * raw status1 and status2 register values are printed. */
++#define LM87_VERBOSE_ALARMS   1
 +
-+      if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) {
-+              if ((irq = find_unbound_irq()) < 0)
-+                      goto out;
++/**************************************************************************
++ *
++ * Onboard LM87 temperature and voltage monitor
++ *
++ **************************************************************************
++ */
 +
-+              bind_ipi.vcpu = cpu;
-+              if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
-+                                              &bind_ipi) != 0)
-+                      BUG();
-+              evtchn = bind_ipi.port;
++/* LM87 channel mode: all current boards either do not use AIN1/FAN1 and 2
++ * or use them as AIN. */
++#define LM87_CHANNEL_MODE 0x16
++#define LM87_CHANNEL_AIN1 1
++#define LM87_CHANNEL_AIN2 2
++#define LM87_CHANNEL_INIT (LM87_CHANNEL_AIN2 | LM87_CHANNEL_AIN1)
 +
-+              evtchn_to_irq[evtchn] = irq;
-+              irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
++/* LM87 configuration register 1 */
++#define LM87_CONFIG_1 0x40
++#define LM87_START 0x01
++#define LM87_INTEN 0x02
++#define LM87_INITIALIZATION 0x80
 +
-+              per_cpu(ipi_to_irq, cpu)[ipi] = irq;
++/* LM87 interrupt status register 1 */
++#define LM87_INT_STATUS_1 0x41
 +
-+              bind_evtchn_to_cpu(evtchn, cpu);
-+      }
++/* LM87 interrupt status register 2 */
++#define LM87_INT_STATUS_2 0x42
 +
-+      irq_bindcount[irq]++;
++/* LM87 interrupt mask register 1 */
++#define LM87_INT_MASK_1 0x43
 +
-+ out:
-+      spin_unlock(&irq_mapping_update_lock);
-+      return irq;
-+}
++/* LM87 interrupt mask register 2 */
++#define LM87_INT_MASK_2 0x44
 +
-+static void unbind_from_irq(unsigned int irq)
-+{
-+      struct evtchn_close close;
-+      int cpu, evtchn = evtchn_from_irq(irq);
++/* LM87 monitoring limits */
++#define LM87_LIMITS 0x2b
 +
-+      spin_lock(&irq_mapping_update_lock);
 +
-+      if ((--irq_bindcount[irq] == 0) && VALID_EVTCHN(evtchn)) {
-+              close.port = evtchn;
-+              if ((type_from_irq(irq) != IRQT_CALLER_PORT) &&
-+                  HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
-+                      BUG();
++int efx_probe_lm87(struct efx_nic *efx, int addr,
++                 const u8 *limits, int nlimits, const u16 irqmask)
++{
++      struct efx_i2c_interface *i2c = &efx->i2c;
++      u8 byte;
++      int rc;
 +
-+              switch (type_from_irq(irq)) {
-+              case IRQT_VIRQ:
-+                      per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
-+                              [index_from_irq(irq)] = -1;
-+                      break;
-+              case IRQT_IPI:
-+                      per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn))
-+                              [index_from_irq(irq)] = -1;
-+                      break;
-+              default:
-+                      break;
++      /* Check for onboard LM87 */
++      rc = efx_i2c_check_presence_retry(i2c, addr);
++      if (rc) {
++              /* Not an error to lack an LM87, but failure to probe the
++               * bus is worrying. */
++              if (rc == -EFAULT) {
++                      EFX_ERR(efx, "Failed to probe I2C bus for LM87!\n");
++                      return rc;
++              } else {
++                      EFX_LOG(efx, "has no onboard LM87 chip\n");
++                      return 0;
 +              }
++      }
++      efx->board_info.lm87_addr = addr;
++      EFX_LOG(efx, "detected onboard LM87 chip at 0x%2x\n", addr);
 +
-+              /* Closed ports are implicitly re-bound to VCPU0. */
-+              bind_evtchn_to_cpu(evtchn, 0);
++      /* Reset chip */
++      byte = LM87_INITIALIZATION;
++      rc = efx_i2c_write_retry(i2c, addr, LM87_CONFIG_1, &byte, 1);
++      if (rc) {
++              EFX_ERR(efx, "could not reset LM87\n");
++              return rc;
++      }
 +
-+              evtchn_to_irq[evtchn] = -1;
-+              irq_info[irq] = IRQ_UNBOUND;
++      /* Configure channel mode: currently hardwire to make pins 5 and 6
++       * AIN1 and AIN2 rather than FAN1, FAN2. */
++      byte = LM87_CHANNEL_INIT;
++      rc = efx_i2c_write_retry(i2c, addr, LM87_CHANNEL_MODE, &byte, 1);
++      if (rc) {
++              EFX_ERR(efx, "could not program LM87 chan. mode\n");
++              return rc;
++      }
 +
-+              /* Zap stats across IRQ changes of use. */
-+              for_each_possible_cpu(cpu)
-+                      kstat_cpu(cpu).irqs[irq] = 0;
++      /* Configure limits */
++      rc = efx_i2c_write_retry(i2c, addr, LM87_LIMITS, limits, nlimits);
++      if (rc) {
++              EFX_ERR(efx, "could not program LM87 limits\n");
++              return rc;
 +      }
 +
-+      spin_unlock(&irq_mapping_update_lock);
-+}
++      /* Mask off unwanted interrupts */
++      byte = (irqmask & 0xff);
++      rc = efx_i2c_write_retry(i2c, addr, LM87_INT_MASK_1, &byte, 1);
++      if (rc) {
++              EFX_ERR(efx, "could not mask LM87 interrupts\n");
++              return rc;
++      }
 +
-+int bind_caller_port_to_irqhandler(
-+      unsigned int caller_port,
-+      irqreturn_t (*handler)(int, void *, struct pt_regs *),
-+      unsigned long irqflags,
-+      const char *devname,
-+      void *dev_id)
-+{
-+      int irq, retval;
++      byte = (irqmask >> 8);
++      rc = efx_i2c_write_retry(i2c, addr, LM87_INT_MASK_2, &byte, 1);
++      if (rc) {
++              EFX_ERR(efx, "could not mask LM87 interrupts\n");
++              return rc;
++      }
 +
-+      irq = bind_caller_port_to_irq(caller_port);
-+      if (irq < 0)
-+              return irq;
++      /* Start monitoring */
++      byte = LM87_START;
++      if (irqmask != EFX_LM87_NO_INTS)
++              byte |= LM87_INTEN;
 +
-+      retval = request_irq(irq, handler, irqflags, devname, dev_id);
-+      if (retval != 0) {
-+              unbind_from_irq(irq);
-+              return retval;
++      rc = efx_i2c_write_retry(i2c, addr, LM87_CONFIG_1, &byte, 1);
++      if (rc) {
++              EFX_ERR(efx, "could not start LM87\n");
++              return rc;
 +      }
 +
-+      return irq;
++      return rc;
 +}
-+EXPORT_SYMBOL_GPL(bind_caller_port_to_irqhandler);
 +
-+int bind_listening_port_to_irqhandler(
-+      unsigned int remote_domain,
-+      irqreturn_t (*handler)(int, void *, struct pt_regs *),
-+      unsigned long irqflags,
-+      const char *devname,
-+      void *dev_id)
++void efx_remove_lm87(struct efx_nic *efx)
 +{
-+      int irq, retval;
++      struct efx_i2c_interface *i2c = &efx->i2c;
++      u8 byte;
 +
-+      irq = bind_listening_port_to_irq(remote_domain);
-+      if (irq < 0)
-+              return irq;
++      if (!efx->board_info.lm87_addr)
++              return;
 +
-+      retval = request_irq(irq, handler, irqflags, devname, dev_id);
-+      if (retval != 0) {
-+              unbind_from_irq(irq);
-+              return retval;
++      /* Reset chip */
++      byte = LM87_INITIALIZATION;
++      if (efx_i2c_write_retry(i2c, efx->board_info.lm87_addr,
++                              LM87_CONFIG_1, &byte, 1) != 0)
++              EFX_ERR(efx, "could not reset LM87 on exit\n");
++}
++
++#if LM87_VERBOSE_ALARMS
++/* Bit number to name mapping for status1 */
++static const char *lm_stat_names[] = {
++/* Status 1 contents */
++      "+2.5Vin",
++      "Vccp1",
++      "Vcc",
++      "+5Vin",
++      "Int. Temp.",
++      "Ext. Temp.",
++      "FAN1/AIN1",
++      "FAN2/AIN2",
++/* Status 2 contents */
++      "+12Vin",
++      "Vccp2",
++      "Reserved",
++      "Reserved",
++      "CI",
++      "THERM#",
++      "D1 Fault",
++      "D2 Fault"
++};
++
++/* Where to read the value corresponding to an alarm bit. */
++static const int lm_stat_regs[] = {
++      0x20, 0x21, 0x22, 0x23, 0x27, 0x26, 0x28, 0x29,
++      0x24, 0x25, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
++};
++
++/* The positions of the alarm bits do not correspond exactly to the
++ * order of the limit values. Convert so the user only needs to maintain
++ * one array */
++static int lm_bit_to_lim[] = {
++      0, /* 2.5V */
++      1, /* Vccp1 */
++      2, /* Vcc */
++      3, /* 5V */
++      7, /* Int temp. */
++      6, /* Ext temp. */
++      8, /* AIN1 */
++      9, /* AIN2 */
++      4, /* 12V */
++      5  /* Vccp2 */
++};
++
++/* These are bit numbers. I feel justified in hardwiring the max. */
++static const int lm_stat_max = 16;
++
++static void lm87_show_alarm(struct efx_nic *efx, int bit)
++{
++      char valbuf[8];
++      u8 val;
++
++      if (lm_stat_regs[bit] != 0xff) {
++              efx_i2c_read_retry(&efx->i2c, efx->board_info.lm87_addr,
++                                 lm_stat_regs[bit], &val, 1);
++              sprintf(valbuf, "0x%02x  ", val);
++      } else {
++              strcpy(valbuf, "----  ");
 +      }
-+
-+      return irq;
++      /* If the board code knows what this sensor is wired to, let it tell
++       * us, else just print the LM87 datasheet name of the input, and the
++       * value. */
++      if (efx->board_info.interpret_sensor == NULL ||
++          (bit < ARRAY_SIZE(lm_bit_to_lim) &&
++           efx->board_info.interpret_sensor(efx, lm_bit_to_lim[bit], val)
++           == 0))
++              EFX_ERR(efx, ": %10s  %4s\n",
++                      STRING_TABLE_LOOKUP(bit, lm_stat), valbuf);
 +}
-+EXPORT_SYMBOL_GPL(bind_listening_port_to_irqhandler);
 +
-+int bind_interdomain_evtchn_to_irqhandler(
-+      unsigned int remote_domain,
-+      unsigned int remote_port,
-+      irqreturn_t (*handler)(int, void *, struct pt_regs *),
-+      unsigned long irqflags,
-+      const char *devname,
-+      void *dev_id)
++static void lm87_dump_alarms(struct efx_nic *efx, int stat1, int stat2)
 +{
-+      int irq, retval;
-+
-+      irq = bind_interdomain_evtchn_to_irq(remote_domain, remote_port);
-+      if (irq < 0)
-+              return irq;
-+
-+      retval = request_irq(irq, handler, irqflags, devname, dev_id);
-+      if (retval != 0) {
-+              unbind_from_irq(irq);
-+              return retval;
++      int i;
++      EFX_ERR(efx, "   NAME    value\n");
++      for (i = 0; i < 8; i++) {
++              if (stat1 & (1 << i))
++                      lm87_show_alarm(efx, i);
++              if (stat2 & (1 << i))
++                      lm87_show_alarm(efx, i + 8);
 +      }
-+
-+      return irq;
 +}
-+EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler);
-+
-+int bind_virq_to_irqhandler(
-+      unsigned int virq,
-+      unsigned int cpu,
-+      irqreturn_t (*handler)(int, void *, struct pt_regs *),
-+      unsigned long irqflags,
-+      const char *devname,
-+      void *dev_id)
-+{
-+      int irq, retval;
-+
-+      irq = bind_virq_to_irq(virq, cpu);
-+      if (irq < 0)
-+              return irq;
-+
-+      retval = request_irq(irq, handler, irqflags, devname, dev_id);
-+      if (retval != 0) {
-+              unbind_from_irq(irq);
-+              return retval;
-+      }
 +
-+      return irq;
-+}
-+EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
++#else
++#define lm87_dump_alarms(_name, _stat1, _stat2) do {} while (0)
++#endif
 +
-+int bind_ipi_to_irqhandler(
-+      unsigned int ipi,
-+      unsigned int cpu,
-+      irqreturn_t (*handler)(int, void *, struct pt_regs *),
-+      unsigned long irqflags,
-+      const char *devname,
-+      void *dev_id)
++/* Read onboard LM87 (if present)
++ * Return error code if lm87 could not be read (-EIO)
++ * _or_ is raising an alarm (-ERANGE). 0 if AOK.
++ */
++int efx_check_lm87(struct efx_nic *efx, unsigned mask)
 +{
-+      int irq, retval;
++      struct efx_i2c_interface *i2c = &efx->i2c;
++      u8 int_status_1, int_status_2;
++      unsigned ints;
++      int rc = 0;
 +
-+      irq = bind_ipi_to_irq(ipi, cpu);
-+      if (irq < 0)
-+              return irq;
++      /* If link is up then do not monitor temperature */
++      if (EFX_WORKAROUND_7884(efx) && efx->link_up)
++              return 0;
 +
-+      retval = request_irq(irq, handler, irqflags, devname, dev_id);
-+      if (retval != 0) {
-+              unbind_from_irq(irq);
-+              return retval;
++      if (!efx->board_info.lm87_addr)
++              return 0;
++
++      /* Read interrupt status registers */
++      rc = efx_i2c_read_retry(i2c, efx->board_info.lm87_addr,
++                              LM87_INT_STATUS_1, &int_status_1, 1);
++      if (rc) {
++              EFX_ERR(efx, "could not read LM87 INT status 1\n");
++              return rc;
++      }
++      rc = efx_i2c_read_retry(i2c, efx->board_info.lm87_addr,
++                              LM87_INT_STATUS_2, &int_status_2, 1);
++      if (rc) {
++              EFX_ERR(efx, "could not read LM87 INT status 2\n");
++              return rc;
 +      }
 +
-+      return irq;
-+}
-+EXPORT_SYMBOL_GPL(bind_ipi_to_irqhandler);
++      int_status_1 &= mask;
++      int_status_2 &= (mask >> 8);
++      ints = ((int_status_2 << 8) | int_status_1);
 +
-+void unbind_from_irqhandler(unsigned int irq, void *dev_id)
-+{
-+      free_irq(irq, dev_id);
-+      unbind_from_irq(irq);
-+}
-+EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
++      /* Check interrupt status */
++      if (ints == 0)
++              return 0;
 +
-+#ifdef CONFIG_SMP
-+void rebind_evtchn_to_cpu(int port, unsigned int cpu)
-+{
-+      struct evtchn_bind_vcpu ebv = { .port = port, .vcpu = cpu };
-+      int masked;
++      EFX_ERR(efx, "LM87 detected a hardware failure (status %02x:%02x)\n",
++              int_status_1, int_status_2);
++      lm87_dump_alarms(efx, int_status_1, int_status_2);
 +
-+      masked = test_and_set_evtchn_mask(port);
-+      if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &ebv) == 0)
-+              bind_evtchn_to_cpu(port, cpu);
-+      if (!masked)
-+              unmask_evtchn(port);
++      return -ERANGE;
 +}
+--- linux-2.6.18.8/drivers/net/sfc/lm87_support.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/lm87_support.h 2008-05-19 00:33:29.309835579 +0300
+@@ -0,0 +1,58 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2007:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************/
++
++#ifndef EFX_LM87_SUPPORT_H
++#define EFX_LM87_SUPPORT_H
++
++/* The interrupt bit masks. These are the same in the interrupt status and
++ * interrupt mask registers. */
++/* Register 1 bits */
++#define EFX_LM87_2_5V_INT     (1)
++#define EFX_LM87_VCCP1_INT    (2)
++#define EFX_LM87_VCC_INT      (4)
++#define EFX_LM87_5_V_INT      (8)
++#define EFX_LM87_ITMP_INT     (0x10)
++#define EFX_LM87_ETMP_INT     (0x20)
++#define EFX_LM87_FAN1_INT     (0x40)
++#define EFX_LM87_FAN2_INT     (0x80)
++/* Register 2 bits */
++#define EFX_LM87_12V_INT      (0x100)
++#define EFX_LM87_VCCP2_INT    (0x200)
++/* Bits 2 and 3 are reserved. */
++#define EFX_LM87_CI_INT               (0x1000)
++#define EFX_LM87_THERM_INT    (0x2000)
++#define EFX_LM87_D1_INT               (0x4000)
++#define EFX_LM87_D2_INT               (0x8000)
++
++#define EFX_LM87_NO_INTS      ((u16)-1)
 +
-+static void rebind_irq_to_cpu(unsigned int irq, unsigned int tcpu)
-+{
-+      int evtchn = evtchn_from_irq(irq);
++extern
++int efx_probe_lm87(struct efx_nic *efx, int addr, const u8 *limits,
++                 int nlimits, const u16 irqmask);
 +
-+      if (VALID_EVTCHN(evtchn))
-+              rebind_evtchn_to_cpu(evtchn, tcpu);
-+}
++extern void efx_remove_lm87(struct efx_nic *efx);
 +
-+static void set_affinity_irq(unsigned int irq, cpumask_t dest)
-+{
-+      unsigned tcpu = first_cpu(dest);
-+      rebind_irq_to_cpu(irq, tcpu);
-+}
-+#endif
++extern int efx_check_lm87(struct efx_nic *efx, unsigned mask);
 +
-+int resend_irq_on_evtchn(unsigned int irq)
-+{
-+      int masked, evtchn = evtchn_from_irq(irq);
-+      shared_info_t *s = HYPERVISOR_shared_info;
++#endif /* EFX_LM87_SUPPORT_H */
+--- linux-2.6.18.8/drivers/net/sfc/mac.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/mac.h  2008-05-19 00:33:29.309835579 +0300
+@@ -0,0 +1,38 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      if (!VALID_EVTCHN(evtchn))
-+              return 1;
++#ifndef EFX_MAC_H
++#define EFX_MAC_H
 +
-+      masked = test_and_set_evtchn_mask(evtchn);
-+      synch_set_bit(evtchn, s->evtchn_pending);
-+      if (!masked)
-+              unmask_evtchn(evtchn);
++#include "net_driver.h"
 +
-+      return 1;
-+}
++extern void mentormac_reset(struct efx_nic *efx);
++extern void mentormac_reconfigure(struct efx_nic *efx);
++extern struct efx_mac_operations falcon_gmac_operations;
++extern struct efx_mac_operations falcon_xmac_operations;
 +
++#endif
+--- linux-2.6.18.8/drivers/net/sfc/mdio_10g.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/mdio_10g.c     2008-05-19 00:33:29.313835810 +0300
+@@ -0,0 +1,441 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +/*
-+ * Interface to generic handling in irq.c
++ * Useful functions for working with MDIO clause 45 PHYs
 + */
++#include <linux/types.h>
++#include <linux/ethtool.h>
++#include <linux/delay.h>
++#include "net_driver.h"
++#include "mdio_10g.h"
++#include "boards.h"
 +
-+static unsigned int startup_dynirq(unsigned int irq)
-+{
-+      int evtchn = evtchn_from_irq(irq);
-+
-+      if (VALID_EVTCHN(evtchn))
-+              unmask_evtchn(evtchn);
-+      return 0;
-+}
++static const char *mmd_block_names[] = {
++      [0]               = "(illegal)",
++      [MDIO_MMD_PMAPMD] = "PMA/PMD",
++      [MDIO_MMD_WIS]    = "WIS",
++      [MDIO_MMD_PCS]    = "PCS",
++      [MDIO_MMD_PHYXS]  = "PHY XS",
++      [MDIO_MMD_DTEXS]  = "DTE XS",
++      [MDIO_MMD_TC]     = "TC",
++      [MDIO_MMD_AN]     = "AN",
++};
++static const int mmd_block_max = ARRAY_SIZE(mmd_block_names);
 +
-+static void shutdown_dynirq(unsigned int irq)
++const char *mdio_clause45_mmd_name(int mmd)
 +{
-+      int evtchn = evtchn_from_irq(irq);
-+
-+      if (VALID_EVTCHN(evtchn))
-+              mask_evtchn(evtchn);
++      return STRING_TABLE_LOOKUP(mmd, mmd_block);
 +}
 +
-+static void enable_dynirq(unsigned int irq)
++int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd,
++                          int spins, int spintime)
 +{
-+      int evtchn = evtchn_from_irq(irq);
++      u32 ctrl;
++      int phy_id = port->mii.phy_id;
 +
-+      if (VALID_EVTCHN(evtchn))
-+              unmask_evtchn(evtchn);
-+}
++      /* Catch callers passing values in the wrong units (or just silly) */
++      EFX_BUG_ON_PARANOID(spins * spintime >= 5000);
 +
-+static void disable_dynirq(unsigned int irq)
-+{
-+      int evtchn = evtchn_from_irq(irq);
++      mdio_clause45_write(port, phy_id, mmd, MDIO_MMDREG_CTRL1,
++                          (1 << MDIO_MMDREG_CTRL1_RESET_LBN));
++      /* Wait for the reset bit to clear. */
++      do {
++              msleep(spintime);
++              ctrl = mdio_clause45_read(port, phy_id, mmd, MDIO_MMDREG_CTRL1);
++              spins--;
 +
-+      if (VALID_EVTCHN(evtchn))
-+              mask_evtchn(evtchn);
++      } while (spins && (ctrl & (1 << MDIO_MMDREG_CTRL1_RESET_LBN)));
++
++      return spins ? spins : -ETIMEDOUT;
 +}
 +
-+static void ack_dynirq(unsigned int irq)
++static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd,
++                                 int fault_fatal)
 +{
-+      int evtchn = evtchn_from_irq(irq);
++      int status;
++      int phy_id = efx->mii.phy_id;
++      const char *mmdname = STRING_TABLE_LOOKUP(mmd, mmd_block);
 +
-+      move_native_irq(irq);
++      if (LOOPBACK_INTERNAL(efx))
++              return 0;
 +
-+      if (VALID_EVTCHN(evtchn)) {
-+              mask_evtchn(evtchn);
-+              clear_evtchn(evtchn);
++      /* Read MMD STATUS2 to check it is responding. */
++      status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2);
++      if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) &
++           ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) !=
++          MDIO_MMDREG_STAT2_PRESENT_VAL) {
++              EFX_ERR(efx, "PHY MMD %s not responding.\n", mmdname);
++              return -EIO;
 +      }
-+}
-+
-+static void end_dynirq(unsigned int irq)
-+{
-+      int evtchn = evtchn_from_irq(irq);
 +
-+      if (VALID_EVTCHN(evtchn) && !(irq_desc[irq].status & IRQ_DISABLED))
-+              unmask_evtchn(evtchn);
++      /* Read MMD STATUS 1 to check for fault. */
++      status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT1);
++      if ((status & (1 << MDIO_MMDREG_STAT1_FAULT_LBN)) != 0) {
++              if (fault_fatal) {
++                      EFX_ERR(efx, "PHY MMD %s reporting fatal"
++                              " fault: status %x\n", mmdname, status);
++                      return -EIO;
++              } else {
++                      EFX_LOG(efx, "PHY MMD %s reporting status"
++                              " %x (expected)\n", mmdname, status);
++              }
++      }
++      return 0;
 +}
 +
-+static struct hw_interrupt_type dynirq_type = {
-+      .typename = "Dynamic-irq",
-+      .startup  = startup_dynirq,
-+      .shutdown = shutdown_dynirq,
-+      .enable   = enable_dynirq,
-+      .disable  = disable_dynirq,
-+      .ack      = ack_dynirq,
-+      .end      = end_dynirq,
-+#ifdef CONFIG_SMP
-+      .set_affinity = set_affinity_irq,
-+#endif
-+      .retrigger = resend_irq_on_evtchn,
-+};
-+
-+static inline void pirq_unmask_notify(int pirq)
-+{
-+      struct physdev_eoi eoi = { .irq = pirq };
-+      if (unlikely(test_bit(pirq, pirq_needs_eoi)))
-+              (void)HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi);
-+}
++/* This ought to be ridiculous overkill. We expect it to fail rarely */
++#define MDIO45_RESET_TIME     HZ
++#define MDIO45_RESET_ITERS    (100)
 +
-+static inline void pirq_query_unmask(int pirq)
++int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
++                                unsigned int mmd_mask)
 +{
-+      struct physdev_irq_status_query irq_status;
-+      irq_status.irq = pirq;
-+      (void)HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status);
-+      clear_bit(pirq, pirq_needs_eoi);
-+      if (irq_status.flags & XENIRQSTAT_needs_eoi)
-+              set_bit(pirq, pirq_needs_eoi);
++      const int spintime = MDIO45_RESET_TIME / MDIO45_RESET_ITERS;
++      int tries = MDIO45_RESET_ITERS;
++      int rc = 0;
++      int in_reset;
++
++      while (tries) {
++              int mask = mmd_mask;
++              int mmd = 0;
++              int stat;
++              in_reset = 0;
++              while (mask) {
++                      if (mask & 1) {
++                              stat = mdio_clause45_read(efx,
++                                                        efx->mii.phy_id,
++                                                        mmd,
++                                                        MDIO_MMDREG_CTRL1);
++                              if (stat < 0) {
++                                      EFX_ERR(efx, "failed to read"
++                                              " status of MMD %s\n",
++                                              STRING_TABLE_LOOKUP(mmd,
++                                                                  mmd_block));
++                                      return -EIO;
++                              }
++                              if (stat & (1 << MDIO_MMDREG_CTRL1_RESET_LBN))
++                                      in_reset |= (1 << mmd);
++                      }
++                      mask = mask >> 1;
++                      mmd++;
++              }
++              if (!in_reset)
++                      break;
++              tries--;
++              msleep(spintime);
++      }
++      if (in_reset != 0) {
++              EFX_ERR(efx, "not all MMDs came out of reset in time."
++                      " MMDs still in reset: %x\n", in_reset);
++              rc = -ETIMEDOUT;
++      }
++      return rc;
 +}
 +
-+/*
-+ * On startup, if there is no action associated with the IRQ then we are
-+ * probing. In this case we should not share with others as it will confuse us.
-+ */
-+#define probing_irq(_irq) (irq_desc[(_irq)].action == NULL)
-+
-+static unsigned int startup_pirq(unsigned int irq)
++int mdio_clause45_check_mmds(struct efx_nic *efx,
++                           unsigned int mmd_mask, unsigned int fatal_mask)
 +{
-+      struct evtchn_bind_pirq bind_pirq;
-+      int evtchn = evtchn_from_irq(irq);
++      int devices, mmd = 0;
++      int probe_mmd;
 +
-+      if (VALID_EVTCHN(evtchn))
-+              goto out;
++      /* Historically we have probed the PHYXS to find out what devices are
++       * present,but that doesn't work so well if the PHYXS isn't expected
++       * to exist, if so just find the first item in the list supplied. */
++      probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS0_PHYXS) ? MDIO_MMD_PHYXS :
++          __ffs(mmd_mask);
++      devices = mdio_clause45_read(efx, efx->mii.phy_id,
++                                   probe_mmd, MDIO_MMDREG_DEVS0);
 +
-+      bind_pirq.pirq  = irq;
-+      /* NB. We are happy to share unless we are probing. */
-+      bind_pirq.flags = probing_irq(irq) ? 0 : BIND_PIRQ__WILL_SHARE;
-+      if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq) != 0) {
-+              if (!probing_irq(irq))
-+                      printk(KERN_INFO "Failed to obtain physical IRQ %d\n",
-+                             irq);
-+              return 0;
++      /* Check all the expected MMDs are present */
++      if (devices < 0) {
++              EFX_ERR(efx, "failed to read devices present\n");
++              return -EIO;
 +      }
-+      evtchn = bind_pirq.port;
++      if ((devices & mmd_mask) != mmd_mask) {
++              EFX_ERR(efx, "required MMDs not present: got %x, "
++                      "wanted %x\n", devices, mmd_mask);
++              return -ENODEV;
++      }
++      EFX_TRACE(efx, "Devices present: %x\n", devices);
 +
-+      pirq_query_unmask(irq_to_pirq(irq));
++      /* Check all required MMDs are responding and happy. */
++      while (mmd_mask) {
++              if (mmd_mask & 1) {
++                      int fault_fatal = fatal_mask & 1;
++                      if (mdio_clause45_check_mmd(efx, mmd, fault_fatal))
++                              return -EIO;
++              }
++              mmd_mask = mmd_mask >> 1;
++              fatal_mask = fatal_mask >> 1;
++              mmd++;
++      }
 +
-+      evtchn_to_irq[evtchn] = irq;
-+      bind_evtchn_to_cpu(evtchn, 0);
-+      irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, evtchn);
++      return 0;
++}
 +
-+ out:
-+      unmask_evtchn(evtchn);
-+      pirq_unmask_notify(irq_to_pirq(irq));
++int mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask)
++{
++      int phy_id = efx->mii.phy_id;
++      int status;
++      int ok = 1;
++      int mmd = 0;
++      int good;
 +
-+      return 0;
++      /* If the port is in loopback, then we should only consider a subset
++       * of mmd's */
++      if (LOOPBACK_INTERNAL(efx))
++              return 1;
++      else if (efx->loopback_mode == LOOPBACK_NETWORK)
++              return 0;
++      else if (!efx->phy_powered)
++              return 0;
++      else if (efx->loopback_mode == LOOPBACK_PHYXS)
++              mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS |
++                            MDIO_MMDREG_DEVS0_PCS |
++                            MDIO_MMDREG_DEVS0_PMAPMD);
++      else if (efx->loopback_mode == LOOPBACK_PCS)
++              mmd_mask &= ~(MDIO_MMDREG_DEVS0_PCS |
++                            MDIO_MMDREG_DEVS0_PMAPMD);
++      else if (efx->loopback_mode == LOOPBACK_PMAPMD)
++              mmd_mask &= ~MDIO_MMDREG_DEVS0_PMAPMD;
++
++      while (mmd_mask) {
++              if (mmd_mask & 1) {
++                      /* Double reads because link state is latched, and a
++                       * read moves the current state into the register */
++                      status = mdio_clause45_read(efx, phy_id,
++                                                  mmd, MDIO_MMDREG_STAT1);
++                      status = mdio_clause45_read(efx, phy_id,
++                                                  mmd, MDIO_MMDREG_STAT1);
++
++                      good = status & (1 << MDIO_MMDREG_STAT1_LINK_LBN);
++                      ok = ok && good;
++              }
++              mmd_mask = (mmd_mask >> 1);
++              mmd++;
++      }
++      return ok;
++}
++
++void mdio_clause45_transmit_disable(struct efx_nic *efx, int disable)
++{
++      int phy_id = efx->mii.phy_id;
++      int ctrl1, ctrl2;
++
++      ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
++                                         MDIO_MMDREG_TXDIS);
++      if (disable)
++              ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
++      else
++              ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN);
++      if (ctrl1 != ctrl2)
++              mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
++                                  MDIO_MMDREG_TXDIS, ctrl2);
 +}
 +
-+static void shutdown_pirq(unsigned int irq)
++void mdio_clause45_phy_reconfigure(struct efx_nic *efx)
 +{
-+      struct evtchn_close close;
-+      int evtchn = evtchn_from_irq(irq);
++      int phy_id = efx->mii.phy_id;
++      int ctrl1, ctrl2;
 +
-+      if (!VALID_EVTCHN(evtchn))
-+              return;
++      /* Handle (with debouncing) PMA/PMD loopback */
++      ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
++                                         MDIO_MMDREG_CTRL1);
 +
-+      mask_evtchn(evtchn);
++      if (efx->loopback_mode == LOOPBACK_PMAPMD)
++              ctrl2 |= (1 << MDIO_PMAPMD_CTRL1_LBACK_LBN);
++      else
++              ctrl2 &= ~(1 << MDIO_PMAPMD_CTRL1_LBACK_LBN);
 +
-+      close.port = evtchn;
-+      if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
-+              BUG();
++      if (ctrl1 != ctrl2)
++              mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
++                                  MDIO_MMDREG_CTRL1, ctrl2);
 +
-+      bind_evtchn_to_cpu(evtchn, 0);
-+      evtchn_to_irq[evtchn] = -1;
-+      irq_info[irq] = IRQ_UNBOUND;
++      /* Handle (with debouncing) PCS loopback */
++      ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
++                                         MDIO_MMDREG_CTRL1);
++      if (efx->loopback_mode == LOOPBACK_PCS)
++              ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
++      else
++              ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
++
++      if (ctrl1 != ctrl2)
++              mdio_clause45_write(efx, phy_id, MDIO_MMD_PCS,
++                                  MDIO_MMDREG_CTRL1, ctrl2);
++
++      /* Handle (with debouncing) PHYXS network loopback */
++      ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
++                                         MDIO_MMDREG_CTRL1);
++      if (efx->loopback_mode == LOOPBACK_NETWORK)
++              ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
++      else
++              ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
++
++      if (ctrl1 != ctrl2)
++              mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS,
++                                  MDIO_MMDREG_CTRL1, ctrl2);
 +}
 +
-+static void enable_pirq(unsigned int irq)
++static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx,
++                                       int lpower, int mmd)
 +{
-+      startup_pirq(irq);
++      const char *mmdname = STRING_TABLE_LOOKUP(mmd, mmd_block);
++      int phy = efx->mii.phy_id;
++      int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1);
++      int ctrl1, ctrl2;
++
++      EFX_TRACE(efx, "Setting low power mode for MMD %s to %d\n",
++                mmdname, lpower);
++
++      if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) {
++              ctrl1 = ctrl2 = mdio_clause45_read(efx, phy,
++                                                 mmd, MDIO_MMDREG_CTRL1);
++              if (lpower)
++                      ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LPOWER_LBN);
++              else
++                      ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LPOWER_LBN);
++              if (ctrl1 != ctrl2)
++                      mdio_clause45_write(efx, phy, mmd,
++                                          MDIO_MMDREG_CTRL1, ctrl2);
++      } else {
++              /* If we ever want a completely generic PHY driver
++               * that which just does clause 45, we may consider not
++               * complaining, but for now expect the driver to know
++               * which MMDs to apply this to. */
++              EFX_ERR(efx, "Attempt change power setting of MMD %s"
++                      " which doesn't support it.\n", mmdname);
++      }
 +}
 +
-+static void disable_pirq(unsigned int irq)
++void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
++                                 int low_power, unsigned int mmd_mask)
 +{
++      int mmd = 0;
++      while (mmd_mask) {
++              if (mmd_mask & 1)
++                      mdio_clause45_set_mmd_lpower(efx, low_power, mmd);
++              mmd_mask = (mmd_mask >> 1);
++              mmd++;
++      }
 +}
 +
-+static void ack_pirq(unsigned int irq)
++/**
++ * mdio_clause45_get_settings - Read (some of) the PHY settings over MDIO.
++ * @efx:              Efx NIC
++ * @ecmd:             Buffer for settings
++ *
++ * On return the 'port', 'speed', 'supported' and 'advertising' fields of
++ * ecmd have been filled out based on the PMA type.
++ */
++void mdio_clause45_get_settings(struct efx_nic *efx,
++                              struct ethtool_cmd *ecmd)
 +{
-+      int evtchn = evtchn_from_irq(irq);
-+
-+      move_native_irq(irq);
++      int pma_type;
 +
-+      if (VALID_EVTCHN(evtchn)) {
-+              mask_evtchn(evtchn);
-+              clear_evtchn(evtchn);
++      /* If no PMA is present we are presumably talking something XAUI-ish
++       * like CX4. Which we report as FIBRE (see below) */
++      if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) {
++              ecmd->speed = SPEED_10000;
++              ecmd->port = PORT_FIBRE;
++              ecmd->supported = SUPPORTED_FIBRE;
++              ecmd->advertising = ADVERTISED_FIBRE;
++              return;
 +      }
-+}
 +
-+static void end_pirq(unsigned int irq)
-+{
-+      int evtchn = evtchn_from_irq(irq);
++      pma_type = mdio_clause45_read(efx, efx->mii.phy_id,
++                                    MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2);
++      pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK;
 +
-+      if ((irq_desc[irq].status & (IRQ_DISABLED|IRQ_PENDING)) ==
-+          (IRQ_DISABLED|IRQ_PENDING)) {
-+              shutdown_pirq(irq);
-+      } else if (VALID_EVTCHN(evtchn)) {
-+              unmask_evtchn(evtchn);
-+              pirq_unmask_notify(irq_to_pirq(irq));
++      switch (pma_type) {
++              /* We represent CX4 as fibre in the absence of anything
++                 better. */
++      case MDIO_PMAPMD_CTRL2_10G_CX4:
++              ecmd->speed = SPEED_10000;
++              ecmd->port = PORT_FIBRE;
++              ecmd->supported = SUPPORTED_FIBRE;
++              ecmd->advertising = ADVERTISED_FIBRE;
++              break;
++              /* 10G Base-T */
++      case MDIO_PMAPMD_CTRL2_10G_BT:
++              ecmd->speed = SPEED_10000;
++              ecmd->port = PORT_TP;
++              ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full;
++              ecmd->advertising = (ADVERTISED_FIBRE
++                                   | ADVERTISED_10000baseT_Full);
++              break;
++      case MDIO_PMAPMD_CTRL2_1G_BT:
++              ecmd->speed = SPEED_1000;
++              ecmd->port = PORT_TP;
++              ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full;
++              ecmd->advertising = (ADVERTISED_FIBRE
++                                   | ADVERTISED_1000baseT_Full);
++              break;
++      case MDIO_PMAPMD_CTRL2_100_BT:
++              ecmd->speed = SPEED_100;
++              ecmd->port = PORT_TP;
++              ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full;
++              ecmd->advertising = (ADVERTISED_FIBRE
++                                   | ADVERTISED_100baseT_Full);
++              break;
++      case MDIO_PMAPMD_CTRL2_10_BT:
++              ecmd->speed = SPEED_10;
++              ecmd->port = PORT_TP;
++              ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full;
++              ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full;
++              break;
++      /* All the other defined modes are flavours of
++       * 10G optical */
++      default:
++              ecmd->speed = SPEED_10000;
++              ecmd->port = PORT_FIBRE;
++              ecmd->supported = SUPPORTED_FIBRE;
++              ecmd->advertising = ADVERTISED_FIBRE;
++              break;
 +      }
 +}
 +
-+static struct hw_interrupt_type pirq_type = {
-+      .typename = "Phys-irq",
-+      .startup  = startup_pirq,
-+      .shutdown = shutdown_pirq,
-+      .enable   = enable_pirq,
-+      .disable  = disable_pirq,
-+      .ack      = ack_pirq,
-+      .end      = end_pirq,
-+#ifdef CONFIG_SMP
-+      .set_affinity = set_affinity_irq,
-+#endif
-+      .retrigger = resend_irq_on_evtchn,
-+};
++/**
++ * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO.
++ * @efx:              Efx NIC
++ * @ecmd:             New settings
++ *
++ * Currently this just enforces that we are _not_ changing the
++ * 'port', 'speed', 'supported' or 'advertising' settings as these
++ * cannot be changed on any currently supported PHY.
++ */
++int mdio_clause45_set_settings(struct efx_nic *efx,
++                             struct ethtool_cmd *ecmd)
++{
++      struct ethtool_cmd tmpcmd;
++      mdio_clause45_get_settings(efx, &tmpcmd);
++      /* None of the current PHYs support more than one mode
++       * of operation (and only 10GBT ever will), so keep things
++       * simple for now */
++      if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) &&
++          (ecmd->supported == tmpcmd.supported) &&
++          (ecmd->advertising == tmpcmd.advertising))
++              return 0;
++      return -EOPNOTSUPP;
++}
+--- linux-2.6.18.8/drivers/net/sfc/mdio_10g.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/mdio_10g.h     2008-05-19 00:33:29.313835810 +0300
+@@ -0,0 +1,295 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef EFX_MDIO_10G_H
++#define EFX_MDIO_10G_H
++
++/*
++ * Definitions needed for doing 10G MDIO as specified in clause 45
++ * MDIO, which do not appear in Linux yet. Also some helper functions.
++ */
++
++#include "efx.h"
++#include "boards.h"
++
++/* Numbering of the MDIO Manageable Devices (MMDs) */
++/* Physical Medium Attachment/ Physical Medium Dependent sublayer */
++#define MDIO_MMD_PMAPMD       (1)
++/* WAN Interface Sublayer */
++#define MDIO_MMD_WIS  (2)
++/* Physical Coding Sublayer */
++#define MDIO_MMD_PCS  (3)
++/* PHY Extender Sublayer */
++#define MDIO_MMD_PHYXS        (4)
++/* Extender Sublayer */
++#define MDIO_MMD_DTEXS        (5)
++/* Transmission convergence */
++#define MDIO_MMD_TC   (6)
++/* Auto negotiation */
++#define MDIO_MMD_AN   (7)
++
++/* Generic register locations */
++#define MDIO_MMDREG_CTRL1     (0)
++#define MDIO_MMDREG_STAT1     (1)
++#define MDIO_MMDREG_IDHI      (2)
++#define MDIO_MMDREG_IDLOW     (3)
++#define MDIO_MMDREG_SPEED     (4)
++#define MDIO_MMDREG_DEVS0     (5)
++#define MDIO_MMDREG_DEVS1     (6)
++#define MDIO_MMDREG_CTRL2     (7)
++#define MDIO_MMDREG_STAT2     (8)
++#define MDIO_MMDREG_TXDIS     (9)
++
++/* Bits in MMDREG_CTRL1 */
++/* Reset */
++#define MDIO_MMDREG_CTRL1_RESET_LBN   (15)
++#define MDIO_MMDREG_CTRL1_RESET_WIDTH (1)
++/* Loopback */
++/* Note that while WIS, PCS, PHYXS and DTEXS have the loopback bit here,
++ * the PMA/PMD does not. */
++#define MDIO_MMDREG_CTRL1_LBACK_LBN   (14)
++#define MDIO_MMDREG_CTRL1_LBACK_WIDTH (1)
++/* Low power */
++#define MDIO_MMDREG_CTRL1_LPOWER_LBN  (11)
++#define MDIO_MMDREG_CTRL1_LPOWER_WIDTH        (1)
++
++/* Bits in MMDREG_STAT1 */
++#define MDIO_MMDREG_STAT1_FAULT_LBN   (7)
++#define MDIO_MMDREG_STAT1_FAULT_WIDTH (1)
++/* Link state */
++#define MDIO_MMDREG_STAT1_LINK_LBN    (2)
++#define MDIO_MMDREG_STAT1_LINK_WIDTH  (1)
++/* Low power ability */
++#define MDIO_MMDREG_STAT1_LPABLE_LBN  (1)
++#define MDIO_MMDREG_STAT1_LPABLE_WIDTH        (1)
++
++/* Bits in ID reg */
++#define MDIO_ID_REV(_id32)    (_id32 & 0xf)
++#define MDIO_ID_MODEL(_id32)  ((_id32 >> 4) & 0x3f)
++#define MDIO_ID_OUI(_id32)    (_id32 >> 10)
++
++/* Bits in MMDREG_DEVS0. Someone thoughtfully layed things out
++ * so the 'bit present' bit number of an MMD is the number of
++ * that MMD */
++#define DEV_PRESENT_BIT(_b) (1 << _b)
++
++#define MDIO_MMDREG_DEVS0_DTEXS        DEV_PRESENT_BIT(MDIO_MMD_DTEXS)
++#define MDIO_MMDREG_DEVS0_PHYXS        DEV_PRESENT_BIT(MDIO_MMD_PHYXS)
++#define MDIO_MMDREG_DEVS0_PCS  DEV_PRESENT_BIT(MDIO_MMD_PCS)
++#define MDIO_MMDREG_DEVS0_WIS  DEV_PRESENT_BIT(MDIO_MMD_WIS)
++#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)
++#define MDIO_MMDREG_DEVS0_AN     DEV_PRESENT_BIT(MDIO_MMD_AN)
++
++
++/* Bits in MMDREG_STAT2 */
++#define MDIO_MMDREG_STAT2_PRESENT_VAL (2)
++#define MDIO_MMDREG_STAT2_PRESENT_LBN (14)
++#define MDIO_MMDREG_STAT2_PRESENT_WIDTH (2)
++
++/* Bits in MMDREG_TXDIS */
++#define MDIO_MMDREG_TXDIS_GLOBAL_LBN    (0)
++#define MDIO_MMDREG_TXDIS_GLOBAL_WIDTH  (1)
++
++/* MMD-specific bits, ordered by MMD, then register */
++#define MDIO_PMAPMD_CTRL1_LBACK_LBN   (0)
++#define MDIO_PMAPMD_CTRL1_LBACK_WIDTH (1)
++
++/* PMA type (4 bits) */
++#define MDIO_PMAPMD_CTRL2_10G_CX4     (0x0)
++#define MDIO_PMAPMD_CTRL2_10G_EW      (0x1)
++#define MDIO_PMAPMD_CTRL2_10G_LW      (0x2)
++#define MDIO_PMAPMD_CTRL2_10G_SW      (0x3)
++#define MDIO_PMAPMD_CTRL2_10G_LX4     (0x4)
++#define MDIO_PMAPMD_CTRL2_10G_ER      (0x5)
++#define MDIO_PMAPMD_CTRL2_10G_LR      (0x6)
++#define MDIO_PMAPMD_CTRL2_10G_SR      (0x7)
++/* Reserved */
++#define MDIO_PMAPMD_CTRL2_10G_BT      (0x9)
++/* Reserved */
++/* Reserved */
++#define MDIO_PMAPMD_CTRL2_1G_BT               (0xc)
++/* Reserved */
++#define MDIO_PMAPMD_CTRL2_100_BT      (0xe)
++#define MDIO_PMAPMD_CTRL2_10_BT               (0xf)
++#define MDIO_PMAPMD_CTRL2_TYPE_MASK   (0xf)
++
++/* PCS 10GBT registers */
++#define MDIO_PCS_10GBT_STATUS         (32)
++#define MDIO_PCS_10GBT_STATUS2                (33)
++#define MDIO_PCS_10GBT_STATUS2_BER_LBN        (8)
++#define MDIO_PCS_10GBT_STATUS2_BER_WIDTH      (6)
++#define MDIO_PCS_10GBT_STATUS2_ERR_LBN        (0)
++#define MDIO_PCS_10GBT_STATUS2_ERR_WIDTH      (8)
++
++/* PHY XGXS lane state */
++#define MDIO_PHYXS_LANE_STATE         (0x18)
++#define MDIO_PHYXS_LANE_ALIGNED_LBN   (12)
++#define MDIO_PHYXS_LANE_SYNC0_LBN     (0)
++#define MDIO_PHYXS_LANE_SYNC1_LBN     (1)
++#define MDIO_PHYXS_LANE_SYNC2_LBN     (2)
++#define MDIO_PHYXS_LANE_SYNC3_LBN     (3)
++
++/* AN registers */
++#define MDIO_AN_STATUS                        (1)
++#define MDIO_AN_STATUS_XNP_LBN                (7)
++#define MDIO_AN_STATUS_PAGE_LBN               (6)
++#define MDIO_AN_STATUS_AN_DONE_LBN    (5)
++#define MDIO_AN_STATUS_LP_AN_CAP_LBN  (0)
++
++#define MDIO_AN_10GBT_STATUS          (33)
++#define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */
++#define MDIO_AN_10GBT_STATUS_MS_LBN     (14) /* MASTER/SLAVE config */
++#define MDIO_AN_10GBT_STATUS_LOC_OK_LBN (13) /* Local OK */
++#define MDIO_AN_10GBT_STATUS_REM_OK_LBN (12) /* Remote OK */
++#define MDIO_AN_10GBT_STATUS_LP_10G_LBN (11) /* Link partner is 10GBT capable */
++#define MDIO_AN_10GBT_STATUS_LP_LTA_LBN (10) /* LP loop timing ability */
++#define MDIO_AN_10GBT_STATUS_LP_TRR_LBN (9)  /* LP Training Reset Request */
++
++
++/* Packing of the prt and dev arguments of clause 45 style MDIO into a
++ * single int so they can be passed into the mdio_read/write functions
++ * that currently exist. Note that as Falcon is the only current user,
++ * the packed form is chosen to match what Falcon needs to write into
++ * a register. This is checked at compile-time so do not change it. If
++ * your target chip needs things layed out differently you will need
++ * to unpack the arguments in your chip-specific mdio functions.
++ */
++ /* These are defined by the standard. */
++#define MDIO45_PRT_ID_WIDTH  (5)
++#define MDIO45_DEV_ID_WIDTH  (5)
 +
-+int irq_ignore_unhandled(unsigned int irq)
-+{
-+      struct physdev_irq_status_query irq_status = { .irq = irq };
++/* The prt ID is just packed in immediately to the left of the dev ID */
++#define MDIO45_PRT_DEV_WIDTH (MDIO45_PRT_ID_WIDTH + MDIO45_DEV_ID_WIDTH)
 +
-+      if (!is_running_on_xen())
-+              return 0;
++#define MDIO45_PRT_ID_MASK   ((1 << MDIO45_PRT_DEV_WIDTH) - 1)
++/* This is the prt + dev extended by 1 bit to hold the 'is clause 45' flag. */
++#define MDIO45_XPRT_ID_WIDTH   (MDIO45_PRT_DEV_WIDTH + 1)
++#define MDIO45_XPRT_ID_MASK   ((1 << MDIO45_XPRT_ID_WIDTH) - 1)
++#define MDIO45_XPRT_ID_IS10G   (1 << (MDIO45_XPRT_ID_WIDTH - 1))
 +
-+      (void)HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status);
-+      return !!(irq_status.flags & XENIRQSTAT_shared);
-+}
 +
-+void notify_remote_via_irq(int irq)
-+{
-+      int evtchn = evtchn_from_irq(irq);
++#define MDIO45_PRT_ID_COMP_LBN   MDIO45_DEV_ID_WIDTH
++#define MDIO45_PRT_ID_COMP_WIDTH  MDIO45_PRT_ID_WIDTH
++#define MDIO45_DEV_ID_COMP_LBN    0
++#define MDIO45_DEV_ID_COMP_WIDTH  MDIO45_DEV_ID_WIDTH
 +
-+      if (VALID_EVTCHN(evtchn))
-+              notify_remote_via_evtchn(evtchn);
++/* Compose port and device into a phy_id */
++static inline int mdio_clause45_pack(u8 prt, u8 dev)
++{
++      efx_dword_t phy_id;
++      EFX_POPULATE_DWORD_2(phy_id, MDIO45_PRT_ID_COMP, prt,
++                           MDIO45_DEV_ID_COMP, dev);
++      return MDIO45_XPRT_ID_IS10G | EFX_DWORD_VAL(phy_id);
 +}
-+EXPORT_SYMBOL_GPL(notify_remote_via_irq);
 +
-+int irq_to_evtchn_port(int irq)
++static inline void mdio_clause45_unpack(u32 val, u8 *prt, u8 *dev)
 +{
-+      return evtchn_from_irq(irq);
++      efx_dword_t phy_id;
++      EFX_POPULATE_DWORD_1(phy_id, EFX_DWORD_0, val);
++      *prt = EFX_DWORD_FIELD(phy_id, MDIO45_PRT_ID_COMP);
++      *dev = EFX_DWORD_FIELD(phy_id, MDIO45_DEV_ID_COMP);
 +}
-+EXPORT_SYMBOL_GPL(irq_to_evtchn_port);
 +
-+void mask_evtchn(int port)
++static inline int mdio_clause45_read(struct efx_nic *efx,
++                                   u8 prt, u8 dev, u16 addr)
 +{
-+      shared_info_t *s = HYPERVISOR_shared_info;
-+      synch_set_bit(port, s->evtchn_mask);
++      return efx->mii.mdio_read(efx->net_dev,
++                                mdio_clause45_pack(prt, dev), addr);
 +}
-+EXPORT_SYMBOL_GPL(mask_evtchn);
 +
-+void unmask_evtchn(int port)
++static inline void mdio_clause45_write(struct efx_nic *efx,
++                                     u8 prt, u8 dev, u16 addr, int value)
 +{
-+      shared_info_t *s = HYPERVISOR_shared_info;
-+      unsigned int cpu = smp_processor_id();
-+      vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
-+
-+      BUG_ON(!irqs_disabled());
-+
-+      /* Slow path (hypercall) if this is a non-local port. */
-+      if (unlikely(cpu != cpu_from_evtchn(port))) {
-+              struct evtchn_unmask unmask = { .port = port };
-+              (void)HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask);
-+              return;
-+      }
++      efx->mii.mdio_write(efx->net_dev,
++                          mdio_clause45_pack(prt, dev), addr, value);
++}
 +
-+      synch_clear_bit(port, s->evtchn_mask);
 +
-+      /* Did we miss an interrupt 'edge'? Re-fire if so. */
-+      if (synch_test_bit(port, s->evtchn_pending) &&
-+          !synch_test_and_set_bit(port / BITS_PER_LONG,
-+                                  &vcpu_info->evtchn_pending_sel))
-+              vcpu_info->evtchn_upcall_pending = 1;
++static inline u32 mdio_clause45_read_id(struct efx_nic *efx, int mmd)
++{
++      int phy_id = efx->mii.phy_id;
++      u16 id_low = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDLOW);
++      u16 id_hi = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_IDHI);
++      return (id_hi << 16) | (id_low);
 +}
-+EXPORT_SYMBOL_GPL(unmask_evtchn);
 +
-+void disable_all_local_evtchn(void)
++static inline int mdio_clause45_phyxgxs_lane_sync(struct efx_nic *efx)
 +{
-+      unsigned i, cpu = smp_processor_id();
-+      shared_info_t *s = HYPERVISOR_shared_info;
++      int i, sync, lane_status;
 +
-+      for (i = 0; i < NR_EVENT_CHANNELS; ++i)
-+              if (cpu_from_evtchn(i) == cpu)
-+                      synch_set_bit(i, &s->evtchn_mask[0]);
++      for (i = 0; i < 2; ++i)
++              lane_status = mdio_clause45_read(efx, efx->mii.phy_id,
++                                               MDIO_MMD_PHYXS,
++                                               MDIO_PHYXS_LANE_STATE);
++
++      sync = (lane_status & (1 << MDIO_PHYXS_LANE_ALIGNED_LBN)) != 0;
++      if (!sync)
++              EFX_INFO(efx, "XGXS lane status: %x\n", lane_status);
++      return sync;
 +}
 +
-+static void restore_cpu_virqs(int cpu)
-+{
-+      struct evtchn_bind_virq bind_virq;
-+      int virq, irq, evtchn;
++extern const char *mdio_clause45_mmd_name(int mmd);
 +
-+      for (virq = 0; virq < NR_VIRQS; virq++) {
-+              if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1)
-+                      continue;
++/*
++ * Reset a specific MMD and wait for reset to clear.
++ * Return number of spins left (>0) on success, -%ETIMEDOUT on failure.
++ *
++ * This function will sleep
++ */
++extern int mdio_clause45_reset_mmd(struct efx_nic *efx, int mmd,
++                                 int spins, int spintime);
 +
-+              BUG_ON(irq_info[irq] != mk_irq_info(IRQT_VIRQ, virq, 0));
++/* As mdio_clause45_check_mmd but for multiple MMDs */
++int mdio_clause45_check_mmds(struct efx_nic *efx,
++                           unsigned int mmd_mask, unsigned int fatal_mask);
 +
-+              /* Get a new binding from Xen. */
-+              bind_virq.virq = virq;
-+              bind_virq.vcpu = cpu;
-+              if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
-+                                              &bind_virq) != 0)
-+                      BUG();
-+              evtchn = bind_virq.port;
++/* Check the link status of specified mmds in bit mask */
++extern int mdio_clause45_links_ok(struct efx_nic *efx,
++                                unsigned int mmd_mask);
 +
-+              /* Record the new mapping. */
-+              evtchn_to_irq[evtchn] = irq;
-+              irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
-+              bind_evtchn_to_cpu(evtchn, cpu);
++/* Generic transmit disable support though PMAPMD */
++extern void mdio_clause45_transmit_disable(struct efx_nic *efx,
++                                         int disable);
 +
-+              /* Ready for use. */
-+              unmask_evtchn(evtchn);
-+      }
-+}
++/* Generic part of reconfigure: set/clear loopback bits */
++extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx);
 +
-+static void restore_cpu_ipis(int cpu)
-+{
-+      struct evtchn_bind_ipi bind_ipi;
-+      int ipi, irq, evtchn;
++/* Set the power state of the specified MMDs */
++extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx,
++                                        int low_power, unsigned int mmd_mask);
 +
-+      for (ipi = 0; ipi < NR_IPIS; ipi++) {
-+              if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1)
-+                      continue;
++/* Read (some of) the PHY settings over MDIO */
++extern void mdio_clause45_get_settings(struct efx_nic *efx,
++                                     struct ethtool_cmd *ecmd);
 +
-+              BUG_ON(irq_info[irq] != mk_irq_info(IRQT_IPI, ipi, 0));
++/* Set (some of) the PHY settings over MDIO */
++extern int mdio_clause45_set_settings(struct efx_nic *efx,
++                                    struct ethtool_cmd *ecmd);
 +
-+              /* Get a new binding from Xen. */
-+              bind_ipi.vcpu = cpu;
-+              if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
-+                                              &bind_ipi) != 0)
-+                      BUG();
-+              evtchn = bind_ipi.port;
++/* Wait for specified MMDs to exit reset within a timeout */
++extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
++                                       unsigned int mmd_mask);
 +
-+              /* Record the new mapping. */
-+              evtchn_to_irq[evtchn] = irq;
-+              irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
-+              bind_evtchn_to_cpu(evtchn, cpu);
++#endif /* EFX_MDIO_10G_H */
+--- linux-2.6.18.8/drivers/net/sfc/mentormac.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/mentormac.c    2008-05-19 00:33:29.313835810 +0300
+@@ -0,0 +1,506 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+              /* Ready for use. */
-+              unmask_evtchn(evtchn);
++#include <linux/delay.h>
++#include "net_driver.h"
++#include "gmii.h"
++#include "mac.h"
++
++/*
++ * Mentor MAC control
++ */
++
++/**************************************************************************
++ *
++ * Mentor MAC registers
++ *
++ **************************************************************************
++ *
++ * Register addresses are Mentor MAC register numbers.  Falcon maps these
++ * registers in at 16-byte intervals.  The mac_writel() and mac_readl()
++ * methods take care of abstracting away this difference.
++ */
++
++/* GMAC configuration register 1 */
++#define GM_CFG1_REG_MAC 0x00
++#define GM_SW_RST_LBN 31
++#define GM_SW_RST_WIDTH 1
++#define GM_SIM_RST_LBN 30
++#define GM_SIM_RST_WIDTH 1
++#define GM_RST_RX_MAC_CTL_LBN 19
++#define GM_RST_RX_MAC_CTL_WIDTH 1
++#define GM_RST_TX_MAC_CTL_LBN 18
++#define GM_RST_TX_MAC_CTL_WIDTH 1
++#define GM_RST_RX_FUNC_LBN 17
++#define GM_RST_RX_FUNC_WIDTH 1
++#define GM_RST_TX_FUNC_LBN 16
++#define GM_RST_TX_FUNC_WIDTH 1
++#define GM_LOOP_LBN 8
++#define GM_LOOP_WIDTH 1
++#define GM_RX_FC_EN_LBN 5
++#define GM_RX_FC_EN_WIDTH 1
++#define GM_TX_FC_EN_LBN 4
++#define GM_TX_FC_EN_WIDTH 1
++#define GM_SYNC_RXEN_LBN 3
++#define GM_SYNC_RXEN_WIDTH 1
++#define GM_RX_EN_LBN 2
++#define GM_RX_EN_WIDTH 1
++#define GM_SYNC_TXEN_LBN 1
++#define GM_SYNC_TXEN_WIDTH 1
++#define GM_TX_EN_LBN 0
++#define GM_TX_EN_WIDTH 1
++
++/* GMAC configuration register 2 */
++#define GM_CFG2_REG_MAC 0x01
++#define GM_PAMBL_LEN_LBN 12
++#define GM_PAMBL_LEN_WIDTH 4
++#define GM_IF_MODE_LBN 8
++#define GM_IF_MODE_WIDTH 2
++#define GM_HUGE_FRM_EN_LBN 5
++#define GM_HUGE_FRM_EN_WIDTH 1
++#define GM_LEN_CHK_LBN 4
++#define GM_LEN_CHK_WIDTH 1
++#define GM_PAD_CRC_EN_LBN 2
++#define GM_PAD_CRC_EN_WIDTH 1
++#define GM_CRC_EN_LBN 1
++#define GM_CRC_EN_WIDTH 1
++#define GM_FD_LBN 0
++#define GM_FD_WIDTH 1
++
++/* GMAC maximum frame length register */
++#define GM_MAX_FLEN_REG_MAC 0x04
++#define GM_MAX_FLEN_LBN 0
++#define GM_MAX_FLEN_WIDTH 16
++
++/* GMAC MII management configuration register */
++#define GM_MII_MGMT_CFG_REG_MAC 0x08
++#define GM_RST_MII_MGMT_LBN 31
++#define GM_RST_MII_MGMT_WIDTH 1
++#define GM_MGMT_SCAN_AUTO_INC_LBN 5
++#define GM_MGMT_SCAN_AUTO_INC_WIDTH 1
++#define GM_MGMT_PREM_SUPR_LBN 4
++#define GM_MGMT_PREM_SUPR_WIDTH 1
++#define GM_MGMT_CLK_SEL_LBN 0
++#define GM_MGMT_CLK_SEL_WIDTH 3
++
++/* GMAC MII management command register */
++#define GM_MII_MGMT_CMD_REG_MAC 0x09
++#define GM_MGMT_SCAN_CYC_LBN 1
++#define GM_MGMT_SCAN_CYC_WIDTH 1
++#define GM_MGMT_RD_CYC_LBN 0
++#define GM_MGMT_RD_CYC_WIDTH 1
++
++/* GMAC MII management address register */
++#define GM_MII_MGMT_ADR_REG_MAC 0x0a
++#define GM_MGMT_PHY_ADDR_LBN 8
++#define GM_MGMT_PHY_ADDR_WIDTH 5
++#define GM_MGMT_REG_ADDR_LBN 0
++#define GM_MGMT_REG_ADDR_WIDTH 5
++
++/* GMAC MII management control register */
++#define GM_MII_MGMT_CTL_REG_MAC 0x0b
++#define GM_MGMT_CTL_LBN 0
++#define GM_MGMT_CTL_WIDTH 16
++
++/* GMAC MII management status register */
++#define GM_MII_MGMT_STAT_REG_MAC 0x0c
++#define GM_MGMT_STAT_LBN 0
++#define GM_MGMT_STAT_WIDTH 16
++
++/* GMAC MII management indicators register */
++#define GM_MII_MGMT_IND_REG_MAC 0x0d
++#define GM_MGMT_NOT_VLD_LBN 2
++#define GM_MGMT_NOT_VLD_WIDTH 1
++#define GM_MGMT_SCANNING_LBN 1
++#define GM_MGMT_SCANNING_WIDTH 1
++#define GM_MGMT_BUSY_LBN 0
++#define GM_MGMT_BUSY_WIDTH 1
++
++/* GMAC station address register 1 */
++#define GM_ADR1_REG_MAC 0x10
++#define GM_HWADDR_5_LBN 24
++#define GM_HWADDR_5_WIDTH 8
++#define GM_HWADDR_4_LBN 16
++#define GM_HWADDR_4_WIDTH 8
++#define GM_HWADDR_3_LBN 8
++#define GM_HWADDR_3_WIDTH 8
++#define GM_HWADDR_2_LBN 0
++#define GM_HWADDR_2_WIDTH 8
++
++/* GMAC station address register 2 */
++#define GM_ADR2_REG_MAC 0x11
++#define GM_HWADDR_1_LBN 24
++#define GM_HWADDR_1_WIDTH 8
++#define GM_HWADDR_0_LBN 16
++#define GM_HWADDR_0_WIDTH 8
++
++/* GMAC FIFO configuration register 0 */
++#define GMF_CFG0_REG_MAC 0x12
++#define GMF_FTFENRPLY_LBN 20
++#define GMF_FTFENRPLY_WIDTH 1
++#define GMF_STFENRPLY_LBN 19
++#define GMF_STFENRPLY_WIDTH 1
++#define GMF_FRFENRPLY_LBN 18
++#define GMF_FRFENRPLY_WIDTH 1
++#define GMF_SRFENRPLY_LBN 17
++#define GMF_SRFENRPLY_WIDTH 1
++#define GMF_WTMENRPLY_LBN 16
++#define GMF_WTMENRPLY_WIDTH 1
++#define GMF_FTFENREQ_LBN 12
++#define GMF_FTFENREQ_WIDTH 1
++#define GMF_STFENREQ_LBN 11
++#define GMF_STFENREQ_WIDTH 1
++#define GMF_FRFENREQ_LBN 10
++#define GMF_FRFENREQ_WIDTH 1
++#define GMF_SRFENREQ_LBN 9
++#define GMF_SRFENREQ_WIDTH 1
++#define GMF_WTMENREQ_LBN 8
++#define GMF_WTMENREQ_WIDTH 1
++#define GMF_HSTRSTFT_LBN 4
++#define GMF_HSTRSTFT_WIDTH 1
++#define GMF_HSTRSTST_LBN 3
++#define GMF_HSTRSTST_WIDTH 1
++#define GMF_HSTRSTFR_LBN 2
++#define GMF_HSTRSTFR_WIDTH 1
++#define GMF_HSTRSTSR_LBN 1
++#define GMF_HSTRSTSR_WIDTH 1
++#define GMF_HSTRSTWT_LBN 0
++#define GMF_HSTRSTWT_WIDTH 1
++
++/* GMAC FIFO configuration register 1 */
++#define GMF_CFG1_REG_MAC 0x13
++#define GMF_CFGFRTH_LBN 16
++#define GMF_CFGFRTH_WIDTH 5
++#define GMF_CFGXOFFRTX_LBN 0
++#define GMF_CFGXOFFRTX_WIDTH 16
++
++/* GMAC FIFO configuration register 2 */
++#define GMF_CFG2_REG_MAC 0x14
++#define GMF_CFGHWM_LBN 16
++#define GMF_CFGHWM_WIDTH 6
++#define GMF_CFGLWM_LBN 0
++#define GMF_CFGLWM_WIDTH 6
++
++/* GMAC FIFO configuration register 3 */
++#define GMF_CFG3_REG_MAC 0x15
++#define GMF_CFGHWMFT_LBN 16
++#define GMF_CFGHWMFT_WIDTH 6
++#define GMF_CFGFTTH_LBN 0
++#define GMF_CFGFTTH_WIDTH 6
++
++/* GMAC FIFO configuration register 4 */
++#define GMF_CFG4_REG_MAC 0x16
++#define GMF_HSTFLTRFRM_LBN 0
++#define GMF_HSTFLTRFRM_WIDTH 18
++#define GMF_HSTFLTRFRM_PAUSE_LBN 12
++#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12
++
++/* GMAC FIFO configuration register 5 */
++#define GMF_CFG5_REG_MAC 0x17
++#define GMF_CFGHDPLX_LBN 22
++#define GMF_CFGHDPLX_WIDTH 1
++#define GMF_SRFULL_LBN 21
++#define GMF_SRFULL_WIDTH 1
++#define GMF_HSTSRFULLCLR_LBN 20
++#define GMF_HSTSRFULLCLR_WIDTH 1
++#define GMF_CFGBYTMODE_LBN 19
++#define GMF_CFGBYTMODE_WIDTH 1
++#define GMF_HSTDRPLT64_LBN 18
++#define GMF_HSTDRPLT64_WIDTH 1
++#define GMF_HSTFLTRFRMDC_LBN 0
++#define GMF_HSTFLTRFRMDC_WIDTH 18
++#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12
++#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1
++
++/* TX total octet count */
++#define GM_TX_OCT_CNT_REG_MAC 0x40
++#define GM_STAT_LBN 0
++#define GM_STAT_WIDTH 32
++
++/* TX good octet count */
++#define GM_TX_GOOD_OCT_CNT_REG_MAC 0x41
++
++/* TX single collision packet count */
++#define GM_TX_SGLCOL_PKT_CNT_REG_MAC 0x42
++
++/* TX multiple collision packet count */
++#define GM_TX_MULTCOL_PKT_CNT_REG_MAC 0x43
++
++/* TX excessive collision packet count */
++#define GM_TX_EXCOL_PKT_CNT_REG_MAC 0x44
++
++/* TX deferred packet count */
++#define GM_TX_DEF_PKT_CNT_REG_MAC 0x45
++
++/* TX late packet count */
++#define GM_TX_LATECOL_PKT_CNT_REG_MAC 0x46
++
++/* TX excessive deferral packet count */
++#define GM_TX_EXDEF_PKT_CNT_REG_MAC 0x47
++
++/* TX pause packet count */
++#define GM_TX_PAUSE_PKT_CNT_REG_MAC 0x48
++
++/* TX bad packet count */
++#define GM_TX_BAD_PKT_CNT_REG_MAC 0x49
++
++/* TX unicast packet count */
++#define GM_TX_UCAST_PKT_CNT_REG_MAC 0x4a
 +
-+      }
-+}
++/* TX multicast packet count */
++#define GM_TX_MCAST_PKT_CNT_REG_MAC 0x4b
 +
-+void irq_resume(void)
-+{
-+      int cpu, pirq, irq, evtchn;
++/* TX broadcast packet count */
++#define GM_TX_BCAST_PKT_CNT_REG_MAC 0x4c
 +
-+      init_evtchn_cpu_bindings();
++/* TX <64-byte packet count */
++#define GM_TX_LT64_PKT_CNT_REG_MAC 0x4d
 +
-+      /* New event-channel space is not 'live' yet. */
-+      for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
-+              mask_evtchn(evtchn);
++/* TX 64-byte packet count */
++#define GM_TX_64_PKT_CNT_REG_MAC 0x4e
 +
-+      /* Check that no PIRQs are still bound. */
-+      for (pirq = 0; pirq < NR_PIRQS; pirq++)
-+              BUG_ON(irq_info[pirq_to_irq(pirq)] != IRQ_UNBOUND);
++/* TX 65-byte to 127-byte packet count */
++#define GM_TX_65_TO_127_PKT_CNT_REG_MAC 0x4f
 +
-+      /* No IRQ <-> event-channel mappings. */
-+      for (irq = 0; irq < NR_IRQS; irq++)
-+              irq_info[irq] &= ~0xFFFF; /* zap event-channel binding */
-+      for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
-+              evtchn_to_irq[evtchn] = -1;
++/* TX 128-byte to 255-byte packet count */
++#define GM_TX_128_TO_255_PKT_CNT_REG_MAC 0x50
 +
-+      for_each_possible_cpu(cpu) {
-+              restore_cpu_virqs(cpu);
-+              restore_cpu_ipis(cpu);
-+      }
++/* TX 256-byte to 511-byte packet count */
++#define GM_TX_256_TO_511_PKT_CNT_REG_MAC 0x51
 +
-+}
++/* TX 512-byte to 1023-byte packet count */
++#define GM_TX_512_TO_1023_PKT_CNT_REG_MAC 0x52
 +
-+void __init xen_init_IRQ(void)
-+{
-+      int i;
++/* TX 1024-byte to 15xx-byte packet count */
++#define GM_TX_1024_TO_15XX_PKT_CNT_REG_MAC 0x53
 +
-+      init_evtchn_cpu_bindings();
++/* TX 15xx-byte to jumbo packet count */
++#define GM_TX_15XX_TO_JUMBO_PKT_CNT_REG_MAC 0x54
 +
-+      /* No event channels are 'live' right now. */
-+      for (i = 0; i < NR_EVENT_CHANNELS; i++)
-+              mask_evtchn(i);
++/* TX >jumbo packet count */
++#define GM_TX_GTJUMBO_PKT_CNT_REG_MAC 0x55
 +
-+      /* No IRQ -> event-channel mappings. */
-+      for (i = 0; i < NR_IRQS; i++)
-+              irq_info[i] = IRQ_UNBOUND;
++/* RX good octet count */
++#define GM_RX_GOOD_OCT_CNT_REG_MAC 0x60
 +
-+      /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
-+      for (i = 0; i < NR_DYNIRQS; i++) {
-+              irq_bindcount[dynirq_to_irq(i)] = 0;
++/* RX bad octet count */
++#define GM_RX_BAD_OCT_CNT_REG_MAC 0x61
 +
-+              irq_desc[dynirq_to_irq(i)].status = IRQ_DISABLED;
-+              irq_desc[dynirq_to_irq(i)].action = NULL;
-+              irq_desc[dynirq_to_irq(i)].depth = 1;
-+              irq_desc[dynirq_to_irq(i)].chip = &dynirq_type;
-+      }
++/* RX missed packet count */
++#define GM_RX_MISS_PKT_CNT_REG_MAC 0x62
 +
-+      /* Phys IRQ space is statically bound (1:1 mapping). Nail refcnts. */
-+      for (i = 0; i < NR_PIRQS; i++) {
-+              irq_bindcount[pirq_to_irq(i)] = 1;
++/* RX false carrier count */
++#define GM_RX_FALSE_CRS_CNT_REG_MAC 0x63
 +
-+#ifdef RTC_IRQ
-+              /* If not domain 0, force our RTC driver to fail its probe. */
-+              if ((i == RTC_IRQ) && !is_initial_xendomain())
-+                      continue;
-+#endif
++/* RX pause packet count */
++#define GM_RX_PAUSE_PKT_CNT_REG_MAC 0x64
 +
-+              irq_desc[pirq_to_irq(i)].status = IRQ_DISABLED;
-+              irq_desc[pirq_to_irq(i)].action = NULL;
-+              irq_desc[pirq_to_irq(i)].depth = 1;
-+              irq_desc[pirq_to_irq(i)].chip = &pirq_type;
-+      }
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/features.c linux-2.6.18-xen.hg/drivers/xen/core/features.c
---- linux-2.6.18/drivers/xen/core/features.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/features.c    2007-12-23 11:15:33.554576016 +0100
-@@ -0,0 +1,34 @@
-+/******************************************************************************
-+ * features.c
-+ *
-+ * Xen feature flags.
-+ *
-+ * Copyright (c) 2006, Ian Campbell, XenSource Inc.
-+ */
-+#include <linux/types.h>
-+#include <linux/cache.h>
-+#include <linux/module.h>
-+#include <asm/hypervisor.h>
-+#include <xen/features.h>
++/* RX bad packet count */
++#define GM_RX_BAD_PKT_CNT_REG_MAC 0x65
 +
-+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
-+#include <xen/platform-compat.h>
-+#endif
++/* RX unicast packet count */
++#define GM_RX_UCAST_PKT_CNT_REG_MAC 0x66
 +
-+u8 xen_features[XENFEAT_NR_SUBMAPS * 32] __read_mostly;
-+/* Not a GPL symbol: used in ubiquitous macros, so too restrictive. */
-+EXPORT_SYMBOL(xen_features);
++/* RX multicast packet count */
++#define GM_RX_MCAST_PKT_CNT_REG_MAC 0x67
 +
-+void setup_xen_features(void)
-+{
-+      xen_feature_info_t fi;
-+      int i, j;
++/* RX broadcast packet count */
++#define GM_RX_BCAST_PKT_CNT_REG_MAC 0x68
 +
-+      for (i = 0; i < XENFEAT_NR_SUBMAPS; i++) {
-+              fi.submap_idx = i;
-+              if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
-+                      break;
-+              for (j=0; j<32; j++)
-+                      xen_features[i*32+j] = !!(fi.submap & 1<<j);
-+      }
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/firmware.c linux-2.6.18-xen.hg/drivers/xen/core/firmware.c
---- linux-2.6.18/drivers/xen/core/firmware.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/firmware.c    2007-12-23 11:15:33.554576016 +0100
-@@ -0,0 +1,74 @@
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/init.h>
-+#include <linux/edd.h>
-+#include <video/edid.h>
-+#include <xen/interface/platform.h>
-+#include <asm/hypervisor.h>
++/* RX <64-byte good packet count */
++#define GM_RX_GOOD_LT64_PKT_CNT_REG_MAC 0x69
 +
-+#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
-+void __init copy_edd(void)
-+{
-+      int ret;
-+      struct xen_platform_op op;
++/* RX <64-byte bad packet count */
++#define GM_RX_BAD_LT64_PKT_CNT_REG_MAC 0x6a
 +
-+      if (!is_initial_xendomain())
-+              return;
++/* RX 64-byte packet count */
++#define GM_RX_64_PKT_CNT_REG_MAC 0x6b
 +
-+      op.cmd = XENPF_firmware_info;
++/* RX 65-byte to 127-byte packet count */
++#define GM_RX_65_TO_127_PKT_CNT_REG_MAC 0x6c
 +
-+      op.u.firmware_info.type = XEN_FW_DISK_INFO;
-+      for (op.u.firmware_info.index = 0;
-+           edd.edd_info_nr < EDDMAXNR;
-+           op.u.firmware_info.index++) {
-+              struct edd_info *info = edd.edd_info + edd.edd_info_nr;
++/* RX 128-byte to 255-byte packet count*/
++#define GM_RX_128_TO_255_PKT_CNT_REG_MAC 0x6d
 +
-+              info->params.length = sizeof(info->params);
-+              set_xen_guest_handle(op.u.firmware_info.u.disk_info.edd_params,
-+                                   &info->params);
-+              ret = HYPERVISOR_platform_op(&op);
-+              if (ret)
-+                      break;
++/* RX 256-byte to 511-byte packet count */
++#define GM_RX_256_TO_511_PKT_CNT_REG_MAC 0x6e
 +
-+#define C(x) info->x = op.u.firmware_info.u.disk_info.x
-+              C(device);
-+              C(version);
-+              C(interface_support);
-+              C(legacy_max_cylinder);
-+              C(legacy_max_head);
-+              C(legacy_sectors_per_track);
-+#undef C
++/* RX 512-byte to 1023-byte packet count */
++#define GM_RX_512_TO_1023_PKT_CNT_REG_MAC 0x6f
 +
-+              edd.edd_info_nr++;
-+      }
++/* RX 1024-byte to 15xx-byte packet count */
++#define GM_RX_1024_TO_15XX_PKT_CNT_REG_MAC 0x70
 +
-+      op.u.firmware_info.type = XEN_FW_DISK_MBR_SIGNATURE;
-+      for (op.u.firmware_info.index = 0;
-+           edd.mbr_signature_nr < EDD_MBR_SIG_MAX;
-+           op.u.firmware_info.index++) {
-+              ret = HYPERVISOR_platform_op(&op);
-+              if (ret)
-+                      break;
-+              edd.mbr_signature[edd.mbr_signature_nr++] =
-+                      op.u.firmware_info.u.disk_mbr_signature.mbr_signature;
-+      }
-+}
-+#endif
++/* RX 15xx-byte to jumbo packet count */
++#define GM_RX_15XX_TO_JUMBO_PKT_CNT_REG_MAC 0x71
 +
-+void __init copy_edid(void)
-+{
-+#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86)
-+      struct xen_platform_op op;
++/* RX >jumbo packet count */
++#define GM_RX_GTJUMBO_PKT_CNT_REG_MAC 0x72
 +
-+      if (!is_initial_xendomain())
-+              return;
++/* RX 64-byte to 15xx-byte bad crc packet count */
++#define GM_RX_BAD_64_TO_15XX_PKT_CNT_REG_MAC 0x73
 +
-+      op.cmd = XENPF_firmware_info;
-+      op.u.firmware_info.index = 0;
-+      op.u.firmware_info.type = XEN_FW_VBEDDC_INFO;
-+      set_xen_guest_handle(op.u.firmware_info.u.vbeddc_info.edid,
-+                           edid_info.dummy);
-+      if (HYPERVISOR_platform_op(&op) != 0)
-+              memset(edid_info.dummy, 0x13, sizeof(edid_info.dummy));
-+#endif
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/gnttab.c linux-2.6.18-xen.hg/drivers/xen/core/gnttab.c
---- linux-2.6.18/drivers/xen/core/gnttab.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/gnttab.c      2007-12-23 11:15:33.661248285 +0100
-@@ -0,0 +1,766 @@
-+/******************************************************************************
-+ * gnttab.c
-+ *
-+ * Granting foreign access to our memory reservation.
-+ *
-+ * Copyright (c) 2005-2006, Christopher Clark
-+ * Copyright (c) 2004-2005, K A Fraser
++/* RX 15xx-byte to jumbo bad crc packet count */
++#define GM_RX_BAD_15XX_TO_JUMBO_PKT_CNT_REG_MAC 0x74
++
++/* RX >jumbo bad crc packet count */
++#define GM_RX_BAD_GTJUMBO_PKT_CNT_REG_MAC 0x75
++
++/**************************************************************************
 + *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
++ * GMII access to PHY
 + *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
++ **************************************************************************
++ */
++
++/* This does not reset the PHY, only the MAC.  However, TX and RX will
++ * both be disabled on the MAC after this, so the state of the PHY is
++ * somewhat irrelevant until the MAC is reinitialised.
++ */
++void mentormac_reset(struct efx_nic *efx)
++{
++      efx_dword_t reg;
++
++      EFX_POPULATE_DWORD_1(reg, GM_SW_RST, 1);
++      efx->mac_op->mac_writel(efx, &reg, GM_CFG1_REG_MAC);
++      udelay(1000);
++
++      EFX_POPULATE_DWORD_1(reg, GM_SW_RST, 0);
++      efx->mac_op->mac_writel(efx, &reg, GM_CFG1_REG_MAC);
++      udelay(1000);
++
++      /* Configure GMII interface so PHY is accessible */
++      EFX_POPULATE_DWORD_1(reg, GM_MGMT_CLK_SEL, 0x4);
++      efx->mac_op->mac_writel(efx, &reg,
++                                   GM_MII_MGMT_CFG_REG_MAC);
++      udelay(10);
++}
++
++void mentormac_reconfigure(struct efx_nic *efx)
++{
++      int loopback, tx_fc, rx_fc, if_mode, full_duplex, bytemode, half_duplex;
++      unsigned int max_frame_len;
++      efx_dword_t reg;
++
++      /* Configuration register 1 */
++      tx_fc = (efx->flow_control & EFX_FC_TX) ? 1 : 0;
++      rx_fc = (efx->flow_control & EFX_FC_RX) ? 1 : 0;
++      loopback = (efx->loopback_mode == LOOPBACK_MAC) ? 1 : 0;
++      bytemode = (efx->link_options & GM_LPA_1000) ? 1 : 0;
++
++      if (efx->loopback_mode != LOOPBACK_NONE)
++              bytemode = 1;
++      if (!(efx->link_options & GM_LPA_DUPLEX))
++              /* Half-duplex operation requires TX flow control */
++              tx_fc = 1;
++      EFX_POPULATE_DWORD_5(reg,
++                           GM_LOOP, loopback,
++                           GM_TX_EN, 1,
++                           GM_TX_FC_EN, tx_fc,
++                           GM_RX_EN, 1,
++                           GM_RX_FC_EN, rx_fc);
++      efx->mac_op->mac_writel(efx, &reg, GM_CFG1_REG_MAC);
++      udelay(10);
++
++      /* Configuration register 2 */
++      if_mode = (bytemode) ? 2 : 1;
++      full_duplex = (efx->link_options & GM_LPA_DUPLEX) ? 1 : 0;
++      EFX_POPULATE_DWORD_4(reg,
++                           GM_IF_MODE, if_mode,
++                           GM_PAD_CRC_EN, 1,
++                           GM_FD, full_duplex,
++                           GM_PAMBL_LEN, 0x7/*datasheet recommended */);
++
++      efx->mac_op->mac_writel(efx, &reg, GM_CFG2_REG_MAC);
++      udelay(10);
++
++      /* Max frame len register */
++      max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu);
++      EFX_POPULATE_DWORD_1(reg, GM_MAX_FLEN, max_frame_len);
++      efx->mac_op->mac_writel(efx, &reg, GM_MAX_FLEN_REG_MAC);
++      udelay(10);
++
++      /* FIFO configuration register 0 */
++      EFX_POPULATE_DWORD_5(reg,
++                           GMF_FTFENREQ, 1,
++                           GMF_STFENREQ, 1,
++                           GMF_FRFENREQ, 1,
++                           GMF_SRFENREQ, 1,
++                           GMF_WTMENREQ, 1);
++      efx->mac_op->mac_writel(efx, &reg, GMF_CFG0_REG_MAC);
++      udelay(10);
++
++      /* FIFO configuration register 1 */
++      EFX_POPULATE_DWORD_2(reg,
++                           GMF_CFGFRTH, 0x12,
++                           GMF_CFGXOFFRTX, 0xffff);
++      efx->mac_op->mac_writel(efx, &reg, GMF_CFG1_REG_MAC);
++      udelay(10);
++
++      /* FIFO configuration register 2 */
++      EFX_POPULATE_DWORD_2(reg,
++                           GMF_CFGHWM, 0x3f,
++                           GMF_CFGLWM, 0xa);
++      efx->mac_op->mac_writel(efx, &reg, GMF_CFG2_REG_MAC);
++      udelay(10);
++
++      /* FIFO configuration register 3 */
++      EFX_POPULATE_DWORD_2(reg,
++                           GMF_CFGHWMFT, 0x1c,
++                           GMF_CFGFTTH, 0x08);
++      efx->mac_op->mac_writel(efx, &reg, GMF_CFG3_REG_MAC);
++      udelay(10);
++
++      /* FIFO configuration register 4 */
++      EFX_POPULATE_DWORD_1(reg, GMF_HSTFLTRFRM_PAUSE, 1);
++      efx->mac_op->mac_writel(efx, &reg, GMF_CFG4_REG_MAC);
++      udelay(10);
++
++      /* FIFO configuration register 5 */
++      half_duplex = (efx->link_options & GM_LPA_DUPLEX) ? 0 : 1;
++      efx->mac_op->mac_readl(efx, &reg, GMF_CFG5_REG_MAC);
++      EFX_SET_DWORD_FIELD(reg, GMF_CFGBYTMODE, bytemode);
++      EFX_SET_DWORD_FIELD(reg, GMF_CFGHDPLX, half_duplex);
++      EFX_SET_DWORD_FIELD(reg, GMF_HSTDRPLT64, half_duplex);
++      EFX_SET_DWORD_FIELD(reg, GMF_HSTFLTRFRMDC_PAUSE, 0);
++      efx->mac_op->mac_writel(efx, &reg, GMF_CFG5_REG_MAC);
++      udelay(10);
++
++      /* MAC address */
++      EFX_POPULATE_DWORD_4(reg,
++                           GM_HWADDR_5, efx->net_dev->dev_addr[5],
++                           GM_HWADDR_4, efx->net_dev->dev_addr[4],
++                           GM_HWADDR_3, efx->net_dev->dev_addr[3],
++                           GM_HWADDR_2, efx->net_dev->dev_addr[2]);
++      efx->mac_op->mac_writel(efx, &reg, GM_ADR1_REG_MAC);
++      udelay(10);
++      EFX_POPULATE_DWORD_2(reg,
++                           GM_HWADDR_1, efx->net_dev->dev_addr[1],
++                           GM_HWADDR_0, efx->net_dev->dev_addr[0]);
++      efx->mac_op->mac_writel(efx, &reg, GM_ADR2_REG_MAC);
++      udelay(10);
++}
+--- linux-2.6.18.8/drivers/net/sfc/mtd.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/mtd.c  2008-05-19 00:33:29.313835810 +0300
+@@ -0,0 +1,602 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
 + *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
 + *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
 +#include <linux/module.h>
-+#include <linux/sched.h>
-+#include <linux/mm.h>
-+#include <linux/seqlock.h>
-+#include <xen/interface/xen.h>
-+#include <xen/gnttab.h>
-+#include <asm/pgtable.h>
-+#include <asm/uaccess.h>
-+#include <asm/synch_bitops.h>
-+#include <asm/io.h>
-+#include <xen/interface/memory.h>
-+#include <xen/driver_util.h>
-+#include <asm/gnttab_dma.h>
-+
-+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
-+#include <xen/platform-compat.h>
-+#endif
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
++#include <linux/delay.h>
 +
-+/* External tools reserve first few grant table entries. */
-+#define NR_RESERVED_ENTRIES 8
-+#define GNTTAB_LIST_END 0xffffffff
-+#define GREFS_PER_GRANT_FRAME (PAGE_SIZE / sizeof(grant_entry_t))
++#define EFX_DRIVER_NAME "sfc_mtd"
++#include "driverlink_api.h"
++#include "net_driver.h"
++#include "spi.h"
 +
-+static grant_ref_t **gnttab_list;
-+static unsigned int nr_grant_frames;
-+static unsigned int boot_max_nr_grant_frames;
-+static int gnttab_free_count;
-+static grant_ref_t gnttab_free_head;
-+static DEFINE_SPINLOCK(gnttab_list_lock);
++/*
++ * Flash and EEPROM (MTD) device driver
++ *
++ * This file provides a separate kernel module (sfc_mtd) which
++ * exposes the flash and EEPROM devices present on Solarflare NICs as
++ * MTD devices, enabling you to reflash the boot ROM code (or use the
++ * remaining space on the flash as a jffs2 filesystem, should you want
++ * to do so).
++ */
 +
-+static struct grant_entry *shared;
++#define EFX_MTD_VERIFY_BUF_LEN 16
++#define EFX_MAX_PARTITIONS 2
++#define EFX_FLASH_BOOTROM_OFFSET 0x8000U
 +
-+static struct gnttab_free_callback *gnttab_free_callback_list;
++/* Write enable for EEPROM/flash configuration area
++ *
++ * Normally, writes to parts of non-volatile storage which contain
++ * critical configuration are disabled to prevent accidents.  This
++ * parameter allows enabling of such writes.
++ */
++static unsigned int efx_allow_nvconfig_writes;
 +
-+static int gnttab_expand(unsigned int req_entries);
++struct efx_mtd {
++      struct mtd_info mtd;
++      struct mtd_partition part[EFX_MAX_PARTITIONS];
++      char part_name[EFX_MAX_PARTITIONS][32];
++      char name[32];
++      struct efx_dl_device *efx_dev;
++      struct efx_nic *efx;
++      /* This must be held when using *spi; it guards against races
++       * with device reset and between sequences of dependent
++       * commands. */
++      struct semaphore access_lock;
++      struct efx_spi_device *spi;
++};
 +
-+#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
-+#define gnttab_entry(entry) (gnttab_list[(entry) / RPP][(entry) % RPP])
++/* SPI utilities */
 +
-+static int get_free_entries(int count)
++static int efx_spi_fast_wait(struct efx_mtd *efx_mtd)
 +{
-+      unsigned long flags;
-+      int ref, rc;
-+      grant_ref_t head;
++      struct efx_spi_device *spi = efx_mtd->spi;
++      u8 status;
++      int i, rc;
 +
-+      spin_lock_irqsave(&gnttab_list_lock, flags);
++      /* Wait up to 1000us for flash/EEPROM to finish a fast operation. */
++      for (i = 0; i < 50; i++) {
++              udelay(20);
 +
-+      if ((gnttab_free_count < count) &&
-+          ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
-+              spin_unlock_irqrestore(&gnttab_list_lock, flags);
-+              return rc;
++              rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1,
++                             &status, sizeof(status));
++              if (rc)
++                      return rc;
++              if (!(status & SPI_STATUS_NRDY))
++                      return 0;
 +      }
-+
-+      ref = head = gnttab_free_head;
-+      gnttab_free_count -= count;
-+      while (count-- > 1)
-+              head = gnttab_entry(head);
-+      gnttab_free_head = gnttab_entry(head);
-+      gnttab_entry(head) = GNTTAB_LIST_END;
-+
-+      spin_unlock_irqrestore(&gnttab_list_lock, flags);
-+
-+      return ref;
++      EFX_ERR(efx_mtd->efx, "timed out waiting for %s last status=0x%02x\n",
++              efx_mtd->name, status);
++      return -ETIMEDOUT;
 +}
 +
-+#define get_free_entry() get_free_entries(1)
-+
-+static void do_free_callbacks(void)
++static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, int uninterruptible)
 +{
-+      struct gnttab_free_callback *callback, *next;
-+
-+      callback = gnttab_free_callback_list;
-+      gnttab_free_callback_list = NULL;
++      struct efx_spi_device *spi = efx_mtd->spi;
++      u8 status;
++      int rc, i;
 +
-+      while (callback != NULL) {
-+              next = callback->next;
-+              if (gnttab_free_count >= callback->count) {
-+                      callback->next = NULL;
-+                      callback->fn(callback->arg);
-+              } else {
-+                      callback->next = gnttab_free_callback_list;
-+                      gnttab_free_callback_list = callback;
-+              }
-+              callback = next;
++      /* Wait up to 4s for flash/EEPROM to finish a slow operation. */
++      for (i = 0; i < 40; i++) {
++              __set_current_state(uninterruptible ?
++                                  TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE);
++              schedule_timeout(HZ / 10);
++              rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1,
++                             &status, sizeof(status));
++              if (rc)
++                      return rc;
++              if (!(status & SPI_STATUS_NRDY))
++                      return 0;
++              if (signal_pending(current))
++                      return -EINTR;
 +      }
++      EFX_ERR(efx_mtd->efx, "timed out waiting for %s\n", efx_mtd->name);
++      return -ETIMEDOUT;
 +}
 +
-+static inline void check_free_callbacks(void)
++static int
++efx_spi_write_enable(struct efx_mtd *efx_mtd)
 +{
-+      if (unlikely(gnttab_free_callback_list))
-+              do_free_callbacks();
++      struct efx_spi_device *spi = efx_mtd->spi;
++
++      return spi->write(spi, efx_mtd->efx, SPI_WREN, -1, NULL, 0);
 +}
 +
-+static void put_free_entry(grant_ref_t ref)
++static int efx_spi_unlock(struct efx_mtd *efx_mtd)
 +{
-+      unsigned long flags;
-+      spin_lock_irqsave(&gnttab_list_lock, flags);
-+      gnttab_entry(ref) = gnttab_free_head;
-+      gnttab_free_head = ref;
-+      gnttab_free_count++;
-+      check_free_callbacks();
-+      spin_unlock_irqrestore(&gnttab_list_lock, flags);
-+}
++      struct efx_spi_device *spi = efx_mtd->spi;
++      const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 |
++                                   SPI_STATUS_BP0);
++      u8 status;
++      int rc;
 +
-+/*
-+ * Public grant-issuing interface functions
-+ */
++      rc = spi->read(spi, efx_mtd->efx, SPI_RDSR, -1, &status,
++                     sizeof(status));
++      if (rc)
++              return rc;
 +
-+int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
-+                              int flags)
-+{
-+      int ref;
++      if (!(status & unlock_mask))
++              return 0; /* already unlocked */
 +
-+      if (unlikely((ref = get_free_entry()) < 0))
-+              return -ENOSPC;
++      rc = efx_spi_write_enable(efx_mtd);
++      if (rc)
++              return rc;
++      rc = spi->write(spi, efx_mtd->efx, SPI_SST_EWSR, -1, NULL, 0);
++      if (rc)
++              return rc;
 +
-+      shared[ref].frame = frame;
-+      shared[ref].domid = domid;
-+      wmb();
-+      BUG_ON(flags & (GTF_accept_transfer | GTF_reading | GTF_writing));
-+      shared[ref].flags = GTF_permit_access | flags;
++      status &= ~unlock_mask;
++      rc = spi->write(spi, efx_mtd->efx, SPI_WRSR, -1, &status,
++                      sizeof(status));
++      if (rc)
++              return rc;
++      rc = efx_spi_fast_wait(efx_mtd);
++      if (rc)
++              return rc;
 +
-+      return ref;
++      return 0;
 +}
-+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
 +
-+void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
-+                                   unsigned long frame, int flags)
++/* Dummy device used in case of a failed reset */
++
++static int efx_spi_dummy_read(const struct efx_spi_device *spi,
++                            struct efx_nic *efx, unsigned int command,
++                            int address, void *data, unsigned int len)
 +{
-+      shared[ref].frame = frame;
-+      shared[ref].domid = domid;
-+      wmb();
-+      BUG_ON(flags & (GTF_accept_transfer | GTF_reading | GTF_writing));
-+      shared[ref].flags = GTF_permit_access | flags;
++      return -EIO;
 +}
-+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
-+
 +
-+int gnttab_query_foreign_access(grant_ref_t ref)
++static int efx_spi_dummy_write(const struct efx_spi_device *spi,
++                             struct efx_nic *efx, unsigned int command,
++                             int address, const void *data, unsigned int len)
 +{
-+      u16 nflags;
++      return -EIO;
++}
 +
-+      nflags = shared[ref].flags;
++static struct efx_spi_device efx_spi_dummy_device = {
++      .block_size     = 1,
++      .erase_command  = 0xff,
++      .read           = efx_spi_dummy_read,
++      .write          = efx_spi_dummy_write,
++};
 +
-+      return (nflags & (GTF_reading|GTF_writing));
-+}
-+EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
++/* MTD interface */
 +
-+int gnttab_end_foreign_access_ref(grant_ref_t ref)
++static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len,
++                      size_t *retlen, u8 *buffer)
 +{
-+      u16 flags, nflags;
++      struct efx_mtd *efx_mtd = mtd->priv;
++      struct efx_spi_device *spi;
++      unsigned int command;
++      unsigned int block_len;
++      unsigned int pos = 0;
++      int rc;
 +
-+      nflags = shared[ref].flags;
-+      do {
-+              if ((flags = nflags) & (GTF_reading|GTF_writing)) {
-+                      printk(KERN_DEBUG "WARNING: g.e. still in use!\n");
-+                      return 0;
++      rc = down_interruptible(&efx_mtd->access_lock);
++      if (rc)
++              goto out;
++      spi = efx_mtd->spi;
++
++      while (pos < len) {
++              block_len = min((unsigned int)len - pos,
++                              efx_spi_read_limit(spi, start + pos));
++              command = efx_spi_munge_command(spi, SPI_READ, start + pos);
++              rc = spi->read(spi, efx_mtd->efx, command, start + pos,
++                             buffer + pos, block_len);
++              if (rc)
++                      break;
++              pos += block_len;
++
++              /* Avoid locking up the system */
++              cond_resched();
++              if (signal_pending(current)) {
++                      rc = -EINTR;
++                      break;
 +              }
-+      } while ((nflags = synch_cmpxchg_subword(&shared[ref].flags, flags, 0)) !=
-+               flags);
++      }
 +
-+      return 1;
++      up(&efx_mtd->access_lock);
++out:
++      *retlen = pos;
++      return rc;
 +}
-+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
 +
-+void gnttab_end_foreign_access(grant_ref_t ref, unsigned long page)
++/* Check that device contents match buffer.  If repeat is true, buffer
++ * contains a pattern of length EFX_MTD_VERIFY_BUF_LEN which the
++ * device contents should match repeatedly.
++ */
++static int efx_mtd_verify(struct mtd_info *mtd, loff_t start,
++                        size_t len, const u8 *buffer, int repeat)
 +{
-+      if (gnttab_end_foreign_access_ref(ref)) {
-+              put_free_entry(ref);
-+              if (page != 0)
-+                      free_page(page);
-+      } else {
-+              /* XXX This needs to be fixed so that the ref and page are
-+                 placed on a list to be freed up later. */
-+              printk(KERN_DEBUG
-+                     "WARNING: leaking g.e. and page still in use!\n");
++      u8 verify_buffer[EFX_MTD_VERIFY_BUF_LEN];
++      unsigned int block_len;
++      size_t read_len;
++      unsigned int pos = 0;
++      int rc = 0;
++
++      while (pos < len) {
++              block_len = min(len - pos, sizeof(verify_buffer));
++              rc = efx_mtd_read(mtd, start + pos, block_len, &read_len,
++                                verify_buffer);
++              if (rc)
++                      return rc;
++              if (memcmp(repeat ? buffer : buffer + pos, verify_buffer,
++                         block_len))
++                      return -EIO;
++              pos += block_len;
 +      }
++
++      return 0;
 +}
-+EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
 +
-+int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
++static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase)
 +{
-+      int ref;
++      struct efx_mtd *efx_mtd = mtd->priv;
++      struct efx_spi_device *spi;
++      u8 empty[EFX_MTD_VERIFY_BUF_LEN];
++      int rc;
 +
-+      if (unlikely((ref = get_free_entry()) < 0))
-+              return -ENOSPC;
-+      gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
++      if (erase->len != mtd->erasesize) {
++              rc = -EINVAL;
++              goto out;
++      }
 +
-+      return ref;
-+}
-+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
++      rc = down_interruptible(&efx_mtd->access_lock);
++      if (rc)
++              goto out;
++      spi = efx_mtd->spi;
++      if (spi->erase_command == 0) {
++              rc = -EOPNOTSUPP;
++              goto out_up;
++      }
 +
-+void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
-+                                     unsigned long pfn)
-+{
-+      shared[ref].frame = pfn;
-+      shared[ref].domid = domid;
-+      wmb();
-+      shared[ref].flags = GTF_accept_transfer;
++      rc = efx_spi_unlock(efx_mtd);
++      if (rc)
++              goto out_up;
++      rc = efx_spi_write_enable(efx_mtd);
++      if (rc)
++              goto out_up;
++      rc = spi->write(spi, efx_mtd->efx, spi->erase_command, erase->addr,
++                      NULL, 0);
++      if (rc)
++              goto out_up;
++      rc = efx_spi_slow_wait(efx_mtd, 0);
++
++out_up:
++      up(&efx_mtd->access_lock);
++      if (rc)
++              goto out;
++
++      memset(empty, 0xff, sizeof(empty));
++      rc = efx_mtd_verify(mtd, erase->addr, erase->len, empty, 1);
++
++out:
++      if (rc == 0) {
++              erase->state = MTD_ERASE_DONE;
++      } else {
++              erase->state = MTD_ERASE_FAILED;
++#if defined(EFX_USE_MTD_ERASE_FAIL_ADDR)
++              erase->fail_addr = 0xffffffff;
++#endif
++      }
++      mtd_erase_callback(erase);
++      return rc;
 +}
-+EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
 +
-+unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
++static int efx_mtd_write(struct mtd_info *mtd, loff_t start,
++                       size_t len, size_t *retlen, const u8 *buffer)
 +{
-+      unsigned long frame;
-+      u16           flags;
++      struct efx_mtd *efx_mtd = mtd->priv;
++      struct efx_spi_device *spi;
++      unsigned int command;
++      unsigned int block_len;
++      unsigned int pos = 0;
++      int rc;
 +
-+      /*
-+       * If a transfer is not even yet started, try to reclaim the grant
-+       * reference and return failure (== 0).
-+       */
-+      while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
-+              if (synch_cmpxchg_subword(&shared[ref].flags, flags, 0) == flags)
-+                      return 0;
-+              cpu_relax();
-+      }
++      rc = down_interruptible(&efx_mtd->access_lock);
++      if (rc)
++              goto out;
++      spi = efx_mtd->spi;
 +
-+      /* If a transfer is in progress then wait until it is completed. */
-+      while (!(flags & GTF_transfer_completed)) {
-+              flags = shared[ref].flags;
-+              cpu_relax();
-+      }
++      rc = efx_spi_unlock(efx_mtd);
++      if (rc)
++              goto out_up;
 +
-+      /* Read the frame number /after/ reading completion status. */
-+      rmb();
-+      frame = shared[ref].frame;
-+      BUG_ON(frame == 0);
++      while (pos < len) {
++              rc = efx_spi_write_enable(efx_mtd);
++              if (rc)
++                      break;
 +
-+      return frame;
-+}
-+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
++              block_len = min((unsigned int)len - pos,
++                              efx_spi_write_limit(spi, start + pos));
++              command = efx_spi_munge_command(spi, SPI_WRITE, start + pos);
++              rc = spi->write(spi, efx_mtd->efx, command, start + pos,
++                              buffer + pos, block_len);
++              if (rc)
++                      break;
++              pos += block_len;
 +
-+unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
-+{
-+      unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
-+      put_free_entry(ref);
-+      return frame;
++              rc = efx_spi_fast_wait(efx_mtd);
++              if (rc)
++                      break;
++
++              /* Avoid locking up the system */
++              cond_resched();
++              if (signal_pending(current)) {
++                      rc = -EINTR;
++                      break;
++              }
++      }
++
++out_up:
++      up(&efx_mtd->access_lock);
++      if (rc == 0)
++              rc = efx_mtd_verify(mtd, start, len, buffer, 0);
++out:
++      *retlen = pos;
++      return rc;
 +}
-+EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
 +
-+void gnttab_free_grant_reference(grant_ref_t ref)
++static void efx_mtd_sync(struct mtd_info *mtd)
 +{
-+      put_free_entry(ref);
++      struct efx_mtd *efx_mtd = mtd->priv;
++      int rc;
++
++      down(&efx_mtd->access_lock);
++      rc = efx_spi_slow_wait(efx_mtd, 1);
++      if (rc)
++              EFX_ERR(efx_mtd->efx, "%s sync failed (%d)\n",
++                      efx_mtd->name, rc);
++      up(&efx_mtd->access_lock);
 +}
-+EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
 +
-+void gnttab_free_grant_references(grant_ref_t head)
++/* Driverlink interface */
++
++static void efx_mtd_reset_suspend(struct efx_dl_device *efx_dev)
 +{
-+      grant_ref_t ref;
-+      unsigned long flags;
-+      int count = 1;
-+      if (head == GNTTAB_LIST_END)
++      struct efx_mtd *efx_mtd = efx_dev->priv;
++
++      if (!efx_mtd)
 +              return;
-+      spin_lock_irqsave(&gnttab_list_lock, flags);
-+      ref = head;
-+      while (gnttab_entry(ref) != GNTTAB_LIST_END) {
-+              ref = gnttab_entry(ref);
-+              count++;
-+      }
-+      gnttab_entry(ref) = gnttab_free_head;
-+      gnttab_free_head = head;
-+      gnttab_free_count += count;
-+      check_free_callbacks();
-+      spin_unlock_irqrestore(&gnttab_list_lock, flags);
++
++      /* Acquire lock to ensure that any in-progress operations have
++       * completed, and no new ones can start.
++       */
++      down(&efx_mtd->access_lock);
 +}
-+EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
 +
-+int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
++static void efx_mtd_reset_resume(struct efx_dl_device *efx_dev, int ok)
 +{
-+      int h = get_free_entries(count);
++      struct efx_mtd *efx_mtd = efx_dev->priv;
 +
-+      if (h < 0)
-+              return -ENOSPC;
++      if (!efx_mtd)
++              return;
 +
-+      *head = h;
++      /* If device reset failed already, or SPI device doesn't
++       * become ready, disable device.
++       */
++      if (!ok || efx_spi_slow_wait(efx_mtd, 1) != 0) {
++              efx_mtd->spi = &efx_spi_dummy_device;
++              EFX_ERR(efx_mtd->efx, "%s disabled after failed reset\n",
++                      efx_mtd->name);
++      }
 +
-+      return 0;
++      up(&efx_mtd->access_lock);
 +}
-+EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
 +
-+int gnttab_empty_grant_references(const grant_ref_t *private_head)
++static void efx_mtd_remove(struct efx_dl_device *efx_dev)
 +{
-+      return (*private_head == GNTTAB_LIST_END);
-+}
-+EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
++      struct efx_mtd *efx_mtd = efx_dev->priv;
 +
-+int gnttab_claim_grant_reference(grant_ref_t *private_head)
-+{
-+      grant_ref_t g = *private_head;
-+      if (unlikely(g == GNTTAB_LIST_END))
-+              return -ENOSPC;
-+      *private_head = gnttab_entry(g);
-+      return g;
++      del_mtd_partitions(&efx_mtd->mtd);
++      kfree(efx_mtd);
++      efx_dev->priv = NULL;
 +}
-+EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
 +
-+void gnttab_release_grant_reference(grant_ref_t *private_head,
-+                                  grant_ref_t release)
++static __devinit int efx_mtd_register(struct efx_mtd *efx_mtd,
++                                    struct efx_dl_device *efx_dev,
++                                    struct efx_nic *efx,
++                                    struct efx_spi_device *spi,
++                                    const char *type_name,
++                                    const char **part_type_name,
++                                    unsigned int num_parts)
 +{
-+      gnttab_entry(release) = *private_head;
-+      *private_head = release;
-+}
-+EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
++      int i;
 +
-+void gnttab_request_free_callback(struct gnttab_free_callback *callback,
-+                                void (*fn)(void *), void *arg, u16 count)
-+{
-+      unsigned long flags;
-+      spin_lock_irqsave(&gnttab_list_lock, flags);
-+      if (callback->next)
-+              goto out;
-+      callback->fn = fn;
-+      callback->arg = arg;
-+      callback->count = count;
-+      callback->next = gnttab_free_callback_list;
-+      gnttab_free_callback_list = callback;
-+      check_free_callbacks();
-+out:
-+      spin_unlock_irqrestore(&gnttab_list_lock, flags);
-+}
-+EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
++      efx_dev->priv = efx_mtd;
 +
-+void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
-+{
-+      struct gnttab_free_callback **pcb;
-+      unsigned long flags;
++      efx_mtd->efx_dev = efx_dev;
++      efx_mtd->efx = efx;
++      efx_mtd->spi = spi;
++      sema_init(&efx_mtd->access_lock, 1);
 +
-+      spin_lock_irqsave(&gnttab_list_lock, flags);
-+      for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
-+              if (*pcb == callback) {
-+                      *pcb = callback->next;
-+                      break;
-+              }
-+      }
-+      spin_unlock_irqrestore(&gnttab_list_lock, flags);
-+}
-+EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
++      efx_mtd->mtd.size = spi->size;
++      efx_mtd->mtd.erasesize = spi->erase_size;
++#if defined(EFX_USE_MTD_WRITESIZE)
++      efx_mtd->mtd.writesize = 1;
++#endif
++      if (snprintf(efx_mtd->name, sizeof(efx_mtd->name),
++                   "%s %s", efx->name, type_name) >=
++          sizeof(efx_mtd->name))
++              return -ENAMETOOLONG;
 +
-+static int grow_gnttab_list(unsigned int more_frames)
-+{
-+      unsigned int new_nr_grant_frames, extra_entries, i;
++      efx_mtd->mtd.priv = efx_mtd;
++      efx_mtd->mtd.name = efx_mtd->name;
++      efx_mtd->mtd.erase = efx_mtd_erase;
++      efx_mtd->mtd.read = efx_mtd_read;
++      efx_mtd->mtd.write = efx_mtd_write;
++      efx_mtd->mtd.sync = efx_mtd_sync;
 +
-+      new_nr_grant_frames = nr_grant_frames + more_frames;
-+      extra_entries       = more_frames * GREFS_PER_GRANT_FRAME;
++      for (i = 0; i < num_parts; i++) {
++              efx_mtd->part[i].name = efx_mtd->part_name[i];
++              if (snprintf(efx_mtd->part_name[i],
++                           sizeof(efx_mtd->part_name[i]),
++                           "%s %s", efx->name, part_type_name[i]) >=
++                  sizeof(efx_mtd->part_name[i]))
++                      return -ENAMETOOLONG;
 +
-+      for (i = nr_grant_frames; i < new_nr_grant_frames; i++)
-+      {
-+              gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
-+              if (!gnttab_list[i])
-+                      goto grow_nomem;
++              if (efx_allow_nvconfig_writes)
++                      efx_mtd->part[i].mask_flags &= ~MTD_WRITEABLE;
 +      }
 +
++      return add_mtd_partitions(&efx_mtd->mtd, efx_mtd->part, num_parts);
++}
 +
-+      for (i = GREFS_PER_GRANT_FRAME * nr_grant_frames;
-+           i < GREFS_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
-+              gnttab_entry(i) = i + 1;
++static int __devinit
++efx_flash_probe(struct efx_dl_device *efx_dev,
++              const struct net_device *net_dev,
++              const struct efx_dl_device_info *dev_info,
++              const char *silicon_rev)
++{
++      struct efx_nic *efx = efx_dl_get_nic(efx_dev);
++      struct efx_mtd *efx_mtd;
++      const char *part_type_name[2];
++      unsigned int num_parts;
++      int rc;
 +
-+      gnttab_entry(i) = gnttab_free_head;
-+      gnttab_free_head = GREFS_PER_GRANT_FRAME * nr_grant_frames;
-+      gnttab_free_count += extra_entries;
++      if (!efx->spi_flash)
++              return -ENODEV;
 +
-+      nr_grant_frames = new_nr_grant_frames;
++      efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
++      if (!efx_mtd)
++              return -ENOMEM;
 +
-+      check_free_callbacks();
++      efx_mtd->mtd.type = MTD_NORFLASH;
++      efx_mtd->mtd.flags = MTD_CAP_NORFLASH;
 +
-+      return 0;
-+      
-+grow_nomem:
-+      for ( ; i >= nr_grant_frames; i--)
-+              free_page((unsigned long) gnttab_list[i]);
-+      return -ENOMEM;
++      part_type_name[0] = "sfc_flash_config";
++      efx_mtd->part[0].offset = 0;
++      efx_mtd->part[0].size = min(efx->spi_flash->size,
++                                  EFX_FLASH_BOOTROM_OFFSET);
++      efx_mtd->part[0].mask_flags = MTD_WRITEABLE;
++
++      if (efx->spi_flash->size <= EFX_FLASH_BOOTROM_OFFSET) {
++              num_parts = 1;
++      } else {
++              part_type_name[1] = "sfc_flash_bootrom";
++              efx_mtd->part[1].offset = EFX_FLASH_BOOTROM_OFFSET;
++              efx_mtd->part[1].size = (efx->spi_flash->size
++                                       - EFX_FLASH_BOOTROM_OFFSET);
++              num_parts = 2;
++      }
++
++      rc = efx_mtd_register(efx_mtd, efx_dev, efx, efx->spi_flash,
++                            "sfc_flash", part_type_name, num_parts);
++      if (rc)
++              kfree(efx_mtd);
++      return rc;
 +}
 +
-+static unsigned int __max_nr_grant_frames(void)
-+{
-+      struct gnttab_query_size query;
++static struct efx_dl_driver efx_flash_driver = {
++      .name           = "sfc_flash",
++      .probe          = efx_flash_probe,
++      .remove         = efx_mtd_remove,
++      .reset_suspend  = efx_mtd_reset_suspend,
++      .reset_resume   = efx_mtd_reset_resume,
++};
++
++static int __devinit
++efx_eeprom_probe(struct efx_dl_device *efx_dev,
++               const struct net_device *net_dev,
++               const struct efx_dl_device_info *dev_info,
++               const char *silicon_rev)
++{
++      struct efx_nic *efx = efx_dl_get_nic(efx_dev);
++      struct efx_mtd *efx_mtd;
++      const char *type_name;
++      const char *part_type_name[1];
 +      int rc;
 +
-+      query.dom = DOMID_SELF;
++      if (!efx->spi_eeprom)
++              return -ENODEV;
 +
-+      rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
-+      if ((rc < 0) || (query.status != GNTST_okay))
-+              return 4; /* Legacy max supported number of frames */
++      efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL);
++      if (!efx_mtd)
++              return -ENOMEM;
 +
-+      return query.max_nr_frames;
-+}
++      efx_mtd->mtd.type = MTD_RAM;
++      efx_mtd->mtd.flags = MTD_CAP_RAM;
 +
-+static inline unsigned int max_nr_grant_frames(void)
-+{
-+      unsigned int xen_max = __max_nr_grant_frames();
++      efx_mtd->part[0].offset = 0;
++      efx_mtd->part[0].size = efx->spi_eeprom->size;
++      efx_mtd->part[0].mask_flags = MTD_WRITEABLE;
 +
-+      if (xen_max > boot_max_nr_grant_frames)
-+              return boot_max_nr_grant_frames;
-+      return xen_max;
++      if (efx->spi_eeprom->size <= 0x200) {
++              type_name = "sfc_small_eeprom";
++              part_type_name[0] = "sfc_small_config";
++      } else {
++              type_name = "sfc_large_eeprom";
++              part_type_name[0] = "sfc_large_config";
++      }
++
++      rc = efx_mtd_register(efx_mtd, efx_dev, efx, efx->spi_eeprom,
++                            type_name, part_type_name, 1);
++      if (rc)
++              kfree(efx_mtd);
++      return rc;
 +}
 +
-+#ifdef CONFIG_XEN
++static struct efx_dl_driver efx_eeprom_driver = {
++      .name           = "sfc_eeprom",
++      .probe          = efx_eeprom_probe,
++      .remove         = efx_mtd_remove,
++      .reset_suspend  = efx_mtd_reset_suspend,
++      .reset_resume   = efx_mtd_reset_resume,
++};
 +
-+static DEFINE_SEQLOCK(gnttab_dma_lock);
++/* Kernel module interface */
 +
-+#ifdef CONFIG_X86
-+static int map_pte_fn(pte_t *pte, struct page *pmd_page,
-+                    unsigned long addr, void *data)
++static int __init efx_mtd_init_module(void)
 +{
-+      unsigned long **frames = (unsigned long **)data;
-+
-+      set_pte_at(&init_mm, addr, pte, pfn_pte_ma((*frames)[0], PAGE_KERNEL));
-+      (*frames)++;
-+      return 0;
-+}
++      int rc;
 +
-+static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
-+                      unsigned long addr, void *data)
-+{
++      rc = efx_dl_register_driver(&efx_flash_driver);
++      if (rc)
++              return rc;
++      rc = efx_dl_register_driver(&efx_eeprom_driver);
++      if (rc) {
++              efx_dl_unregister_driver(&efx_flash_driver);
++              return rc;
++      }
 +
-+      set_pte_at(&init_mm, addr, pte, __pte(0));
 +      return 0;
 +}
 +
-+void *arch_gnttab_alloc_shared(unsigned long *frames)
++static void __exit efx_mtd_exit_module(void)
 +{
-+      struct vm_struct *area;
-+      area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames());
-+      BUG_ON(area == NULL);
-+      return area->addr;
++      efx_dl_unregister_driver(&efx_eeprom_driver);
++      efx_dl_unregister_driver(&efx_flash_driver);
 +}
-+#endif /* CONFIG_X86 */
-+
-+static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
-+{
-+      struct gnttab_setup_table setup;
-+      unsigned long *frames;
-+      unsigned int nr_gframes = end_idx + 1;
-+      int rc;
 +
-+      frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
-+      if (!frames)
-+              return -ENOMEM;
++module_init(efx_mtd_init_module);
++module_exit(efx_mtd_exit_module);
 +
-+      setup.dom        = DOMID_SELF;
-+      setup.nr_frames  = nr_gframes;
-+      set_xen_guest_handle(setup.frame_list, frames);
++MODULE_AUTHOR("Michael Brown <mbrown@fensystems.co.uk> and "
++            "Solarflare Communications");
++MODULE_DESCRIPTION("SFC MTD driver");
++MODULE_LICENSE("GPL");
+--- linux-2.6.18.8/drivers/net/sfc/net_driver.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/net_driver.h   2008-05-19 00:33:29.317836041 +0300
+@@ -0,0 +1,1096 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
-+      if (rc == -ENOSYS) {
-+              kfree(frames);
-+              return -ENOSYS;
-+      }
++/* Common definitions for all Efx net driver code */
 +
-+      BUG_ON(rc || setup.status);
++#ifndef EFX_NET_DRIVER_H
++#define EFX_NET_DRIVER_H
 +
-+      if (shared == NULL)
-+              shared = arch_gnttab_alloc_shared(frames);
++#include <linux/version.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/ethtool.h>
++#include <linux/if_vlan.h>
++#include <linux/timer.h>
++#include <linux/mii.h>
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/device.h>
 +
-+#ifdef CONFIG_X86
-+      rc = apply_to_page_range(&init_mm, (unsigned long)shared,
-+                               PAGE_SIZE * nr_gframes,
-+                               map_pte_fn, &frames);
-+      BUG_ON(rc);
-+      frames -= nr_gframes; /* adjust after map_pte_fn() */
-+#endif /* CONFIG_X86 */
++/* Must come before other headers */
++#include "kernel_compat.h"
 +
-+      kfree(frames);
++#include "enum.h"
++#include "bitfield.h"
++#include "driverlink_api.h"
++#include "driverlink.h"
++#include "i2c-direct.h"
 +
-+      return 0;
-+}
++      #ifndef EFX_USE_DEBUGFS
++              /* Sick, but we have no other use for dentry */
++              #define dentry proc_dir_entry
++      #endif
 +
-+static void gnttab_page_free(struct page *page)
-+{
-+      ClearPageForeign(page);
-+      gnttab_reset_grant_page(page);
-+      put_page(page);
-+}
++#define EFX_MAX_LRO_DESCRIPTORS 8
++#define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS
 +
-+/*
-+ * Must not be called with IRQs off.  This should only be used on the
-+ * slow path.
++/**************************************************************************
 + *
-+ * Copy a foreign granted page to local memory.
-+ */
-+int gnttab_copy_grant_page(grant_ref_t ref, struct page **pagep)
-+{
-+      struct gnttab_unmap_and_replace unmap;
-+      mmu_update_t mmu;
-+      struct page *page;
-+      struct page *new_page;
-+      void *new_addr;
-+      void *addr;
-+      paddr_t pfn;
-+      maddr_t mfn;
-+      maddr_t new_mfn;
-+      int err;
++ * Build definitions
++ *
++ **************************************************************************/
++#ifndef EFX_DRIVER_NAME
++#define EFX_DRIVER_NAME       "sfc"
++#endif
++#define EFX_DRIVER_VERSION    "2.2.0101"
 +
-+      page = *pagep;
-+      if (!get_page_unless_zero(page))
-+              return -ENOENT;
++#ifdef EFX_ENABLE_DEBUG
++#define EFX_BUG_ON_PARANOID(x) BUG_ON(x)
++#define EFX_WARN_ON_PARANOID(x) WARN_ON(x)
++#else
++#define EFX_BUG_ON_PARANOID(x) do {} while (0)
++#define EFX_WARN_ON_PARANOID(x) do {} while (0)
++#endif
 +
-+      err = -ENOMEM;
-+      new_page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
-+      if (!new_page)
-+              goto out;
++/* Include net device name in log messages if it has been registered.
++ * Use efx->name not efx->net_dev->name so that races with (un)registration
++ * are harmless.
++ */
++#define NET_DEV_NAME(efx) ((efx)->net_dev_registered ? (efx)->name : "")
 +
-+      new_addr = page_address(new_page);
-+      addr = page_address(page);
-+      memcpy(new_addr, addr, PAGE_SIZE);
++/* Un-rate-limited logging */
++#define EFX_ERR(efx, fmt, args...) \
++dev_err(&((efx)->pci_dev->dev), "ERR: %s " fmt, NET_DEV_NAME(efx), ##args)
 +
-+      pfn = page_to_pfn(page);
-+      mfn = pfn_to_mfn(pfn);
-+      new_mfn = virt_to_mfn(new_addr);
++#define EFX_INFO(efx, fmt, args...) \
++dev_info(&((efx)->pci_dev->dev), "INFO: %s " fmt, NET_DEV_NAME(efx), ##args)
 +
-+      write_seqlock(&gnttab_dma_lock);
++#ifdef EFX_ENABLE_DEBUG
++#define EFX_LOG(efx, fmt, args...) \
++dev_info(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
++#else
++#define EFX_LOG(efx, fmt, args...) \
++dev_dbg(&((efx)->pci_dev->dev), "DBG: %s " fmt, NET_DEV_NAME(efx), ##args)
++#endif
 +
-+      /* Make seq visible before checking page_mapped. */
-+      smp_mb();
++#define EFX_TRACE(efx, fmt, args...) do {} while (0)
 +
-+      /* Has the page been DMA-mapped? */
-+      if (unlikely(page_mapped(page))) {
-+              write_sequnlock(&gnttab_dma_lock);
-+              put_page(new_page);
-+              err = -EBUSY;
-+              goto out;
-+      }
++#define EFX_REGDUMP(efx, fmt, args...) do {} while (0)
 +
-+      if (!xen_feature(XENFEAT_auto_translated_physmap))
-+              set_phys_to_machine(pfn, new_mfn);
++/* Rate-limited logging */
++#define EFX_ERR_RL(efx, fmt, args...) \
++do {if (net_ratelimit()) EFX_ERR(efx, fmt, ##args); } while (0)
 +
-+      gnttab_set_replace_op(&unmap, (unsigned long)addr,
-+                            (unsigned long)new_addr, ref);
++#define EFX_INFO_RL(efx, fmt, args...) \
++do {if (net_ratelimit()) EFX_INFO(efx, fmt, ##args); } while (0)
 +
-+      err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
-+                                      &unmap, 1);
-+      BUG_ON(err);
-+      BUG_ON(unmap.status);
++#define EFX_LOG_RL(efx, fmt, args...) \
++do {if (net_ratelimit()) EFX_LOG(efx, fmt, ##args); } while (0)
 +
-+      write_sequnlock(&gnttab_dma_lock);
++/* Kernel headers may redefine inline anyway */
++#ifndef inline
++#define inline inline __attribute__ ((always_inline))
++#endif
 +
-+      if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+              set_phys_to_machine(page_to_pfn(new_page), INVALID_P2M_ENTRY);
++/**************************************************************************
++ *
++ * Efx data structures
++ *
++ **************************************************************************/
 +
-+              mmu.ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
-+              mmu.val = pfn;
-+              err = HYPERVISOR_mmu_update(&mmu, 1, NULL, DOMID_SELF);
-+              BUG_ON(err);
-+      }
++#define EFX_MAX_CHANNELS 32
++#define EFX_MAX_TX_QUEUES 1
++#define EFX_MAX_RX_QUEUES EFX_MAX_CHANNELS
 +
-+      new_page->mapping = page->mapping;
-+      new_page->index = page->index;
-+      set_bit(PG_foreign, &new_page->flags);
-+      *pagep = new_page;
++/**
++ * struct efx_special_buffer - An Efx special buffer
++ * @addr: CPU base address of the buffer
++ * @dma_addr: DMA base address of the buffer
++ * @len: Buffer length, in bytes
++ * @index: Buffer index within controller;s buffer table
++ * @entries: Number of buffer table entries
++ *
++ * Special buffers are used for the event queues and the TX and RX
++ * descriptor queues for each channel.  They are *not* used for the
++ * actual transmit and receive buffers.
++ *
++ * Note that for Falcon, TX and RX descriptor queues live in host memory.
++ * Allocation and freeing procedures must take this into account.
++ */
++struct efx_special_buffer {
++      void *addr;
++      dma_addr_t dma_addr;
++      unsigned int len;
++      int index;
++      int entries;
++};
 +
-+      SetPageForeign(page, gnttab_page_free);
-+      page->mapping = NULL;
++/**
++ * struct efx_tx_buffer - An Efx TX buffer
++ * @skb: The associated socket buffer.
++ *    Set only on the final fragment of a packet; %NULL for all other
++ *    fragments.  When this fragment completes, then we can free this
++ *    skb.
++ * @dma_addr: DMA address of the fragment.
++ * @len: Length of this fragment.
++ *    This field is zero when the queue slot is empty.
++ * @continuation: True if this fragment is not the end of a packet.
++ * @unmap_single: True if pci_unmap_single should be used.
++ * @unmap_addr: DMA address to unmap
++ * @unmap_len: Length of this fragment to unmap
++ */
++struct efx_tx_buffer {
++      const struct sk_buff *skb;
++      dma_addr_t dma_addr;
++      unsigned short len;
++      unsigned char continuation;
++      unsigned char unmap_single;
++      dma_addr_t unmap_addr;
++      unsigned short unmap_len;
++};
 +
-+out:
-+      put_page(page);
-+      return err;
-+}
-+EXPORT_SYMBOL_GPL(gnttab_copy_grant_page);
++/**
++ * struct efx_tx_queue - An Efx TX queue
++ *
++ * This is a ring buffer of TX fragments.
++ * Since the TX completion path always executes on the same
++ * CPU and the xmit path can operate on different CPUs,
++ * performance is increased by ensuring that the completion
++ * path and the xmit path operate on different cache lines.
++ * This is particularly important if the xmit path is always
++ * executing on one CPU which is different from the completion
++ * path.  There is also a cache line for members which are
++ * read but not written on the fast path.
++ *
++ * @efx: The associated Efx NIC
++ * @queue: DMA queue number
++ * @used: Queue is used by net driver
++ * @channel: The associated channel
++ * @buffer: The software buffer ring
++ * @txd: The hardware descriptor ring
++ * @debug_dir: debugfs directory
++ * @read_count: Current read pointer.
++ *    This is the number of buffers that have been removed from both rings.
++ * @stopped: Stopped flag.
++ *    Set if this TX queue is currently stopping its port.
++ * @insert_count: Current insert pointer
++ *    This is the number of buffers that have been added to the
++ *    software ring.
++ * @write_count: Current write pointer
++ *    This is the number of buffers that have been added to the
++ *    hardware ring.
++ * @old_read_count: The value of read_count when last checked.
++ *    This is here for performance reasons.  The xmit path will
++ *    only get the up-to-date value of read_count if this
++ *    variable indicates that the queue is full.  This is to
++ *    avoid cache-line ping-pong between the xmit path and the
++ *    completion path.
++ */
++struct efx_tx_queue {
++      /* Members which don't change on the fast path */
++      struct efx_nic *efx ____cacheline_aligned_in_smp;
++      int queue;
++      int used;
++      struct efx_channel *channel;
++      struct efx_nic *nic;
++      struct efx_tx_buffer *buffer;
++      struct efx_special_buffer txd;
++#ifdef CONFIG_SFC_DEBUGFS
++      struct dentry *debug_dir;
++#endif
++
++      /* Members used mainly on the completion path */
++      unsigned int read_count ____cacheline_aligned_in_smp;
++      int stopped;
++
++      /* Members used only on the xmit path */
++      unsigned int insert_count ____cacheline_aligned_in_smp;
++      unsigned int write_count;
++      unsigned int old_read_count;
++};
 +
-+void gnttab_reset_grant_page(struct page *page)
-+{
-+      init_page_count(page);
-+      reset_page_mapcount(page);
-+}
-+EXPORT_SYMBOL_GPL(gnttab_reset_grant_page);
++/**
++ * struct efx_rx_buffer - An Efx RX data buffer
++ * @dma_addr: DMA base address of the buffer
++ * @skb: The associated socket buffer, if any.
++ *    If both this and page are %NULL, the buffer slot is currently free.
++ * @page: The associated page buffer, if any.
++ *    If both this and skb are %NULL, the buffer slot is currently free.
++ * @data: Pointer to ethernet header
++ * @len: Buffer length, in bytes.
++ * @unmap_addr: DMA address to unmap
++ */
++struct efx_rx_buffer {
++      dma_addr_t dma_addr;
++      struct sk_buff *skb;
++      struct page *page;
++      char *data;
++      unsigned int len;
++      dma_addr_t unmap_addr;
++};
 +
-+/*
-+ * Keep track of foreign pages marked as PageForeign so that we don't
-+ * return them to the remote domain prematurely.
-+ *
-+ * PageForeign pages are pinned down by increasing their mapcount.
++/**
++ * struct efx_rx_queue - An Efx RX queue
++ * @efx: The associated Efx NIC
++ * @queue: DMA queue number
++ * @used: Queue is used by net driver
++ * @channel: The associated channel
++ * @buffer: The software buffer ring
++ * @rxd: The hardware descriptor ring
++ * @added_count: Number of buffers added to the receive queue.
++ * @notified_count: Number of buffers given to NIC (<= @added_count).
++ * @removed_count: Number of buffers removed from the receive queue.
++ * @add_lock: Receive queue descriptor add spin lock.
++ *    This lock must be held in order to add buffers to the RX
++ *    descriptor ring (rxd and buffer) and to update added_count (but
++ *    not removed_count).
++ * @max_fill: RX descriptor maximum fill level (<= ring size)
++ * @fast_fill_trigger: RX descriptor fill level that will trigger a fast fill
++ *    (<= @max_fill)
++ * @fast_fill_limit: The level to which a fast fill will fill
++ *    (@fast_fill_trigger <= @fast_fill_limit <= @max_fill)
++ * @min_fill: RX descriptor minimum non-zero fill level.
++ *    This records the minimum fill level observed when a ring
++ *    refill was triggered.
++ * @min_overfill: RX descriptor minimum overflow fill level.
++ *    This records the minimum fill level at which RX queue
++ *    overflow was observed.  It should never be set.
++ * @alloc_page_count: RX allocation strategy counter.
++ * @alloc_skb_count: RX allocation strategy counter.
++ * @work: Descriptor push work thread
++ * @buf_page: Page for next RX buffer.
++ *    We can use a single page for multiple RX buffers. This tracks
++ *    the remaining space in the allocation.
++ * @buf_dma_addr: Page's DMA address.
++ * @buf_data: Page's host address.
++ * @debug_dir: debugfs directory
++ */
++struct efx_rx_queue {
++      struct efx_nic *efx;
++      int queue;
++      int used;
++      struct efx_channel *channel;
++      struct efx_rx_buffer *buffer;
++      struct efx_special_buffer rxd;
++
++      int added_count;
++      int notified_count;
++      int removed_count;
++      spinlock_t add_lock;
++      unsigned int max_fill;
++      unsigned int fast_fill_trigger;
++      unsigned int fast_fill_limit;
++      unsigned int min_fill;
++      unsigned int min_overfill;
++      unsigned int alloc_page_count;
++      unsigned int alloc_skb_count;
++      struct delayed_work work;
++      unsigned int slow_fill_count;
++
++      struct page *buf_page;
++      dma_addr_t buf_dma_addr;
++      char *buf_data;
++
++#ifdef CONFIG_SFC_DEBUGFS
++      struct dentry *debug_dir;
++#endif
++};
++
++/**
++ * struct efx_buffer - An Efx general-purpose buffer
++ * @addr: host base address of the buffer
++ * @dma_addr: DMA base address of the buffer
++ * @len: Buffer length, in bytes
 + *
-+ * All other pages are simply returned as is.
++ * Falcon uses these buffers for its interrupt status registers and
++ * MAC stats dumps.
 + */
-+void __gnttab_dma_map_page(struct page *page)
-+{
-+      unsigned int seq;
++struct efx_buffer {
++      void *addr;
++      dma_addr_t dma_addr;
++      unsigned int len;
++};
 +
-+      if (!is_running_on_xen() || !PageForeign(page))
-+              return;
 +
-+      do {
-+              seq = read_seqbegin(&gnttab_dma_lock);
++/* Flags for channel->used_flags */
++#define EFX_USED_BY_RX 1
++#define EFX_USED_BY_TX 2
++#define EFX_USED_BY_RX_TX (EFX_USED_BY_RX | EFX_USED_BY_TX)
 +
-+              if (gnttab_dma_local_pfn(page))
-+                      break;
++enum efx_rx_alloc_method {
++      RX_ALLOC_METHOD_AUTO = 0,
++      RX_ALLOC_METHOD_SKB = 1,
++      RX_ALLOC_METHOD_PAGE = 2,
++};
 +
-+              atomic_set(&page->_mapcount, 0);
++/**
++ * struct efx_channel - An Efx channel
++ *
++ * A channel comprises an event queue, at least one TX queue, at least
++ * one RX queue, and an associated tasklet for processing the event
++ * queue.
++ *
++ * @efx: Associated Efx NIC
++ * @evqnum: Event queue number
++ * @channel: Channel instance number
++ * @used_flags: Channel is used by net driver
++ * @enabled: Channel enabled indicator
++ * @irq: IRQ number (MSI and MSI-X only)
++ * @has_interrupt: Channel has an interrupt
++ * @irq_moderation: IRQ moderation value (in us)
++ * @napi_dev: Net device used with NAPI
++ * @napi_str: NAPI control structure
++ * @reset_work: Scheduled reset work thread
++ * @work_pending: Is work pending via NAPI?
++ * @eventq: Event queue buffer
++ * @eventq_read_ptr: Event queue read pointer
++ * @last_eventq_read_ptr: Last event queue read pointer value.
++ * @eventq_magic: Event queue magic value for driver-generated test events
++ * @debug_dir: debugfs directory
++ * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
++ *    and diagnostic counters
++ * @rx_alloc_push_pages: RX allocation method currently in use for pushing
++ *    descriptors
++ * @rx_alloc_pop_pages: RX allocation method currently in use for popping
++ *    descriptors
++ * @n_rx_tobe_disc: Count of RX_TOBE_DISC errors
++ * @n_rx_ip_frag_err: Count of RX IP fragment errors
++ * @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors
++ * @n_rx_tcp_udp_chksum_err: Count of RX TCP and UDP checksum errors
++ * @n_rx_frm_trunc: Count of RX_FRM_TRUNC errors
++ * @n_rx_overlength: Count of RX_OVERLENGTH errors
++ * @n_skbuff_leaks: Count of skbuffs leaked due to RX overrun
++ */
++struct efx_channel {
++      struct efx_nic *efx;
++      int evqnum;
++      int channel;
++      int used_flags;
++      int enabled;
++      int irq;
++      unsigned int has_interrupt;
++      unsigned int irq_moderation;
++      struct net_device *napi_dev;
++#if !defined(EFX_HAVE_OLD_NAPI)
++      struct napi_struct napi_str;
++#endif
++      struct work_struct reset_work;
++      int work_pending;
++      struct efx_special_buffer eventq;
++      unsigned int eventq_read_ptr;
++      unsigned int last_eventq_read_ptr;
++      unsigned int eventq_magic;
 +
-+              /* Make _mapcount visible before read_seqretry. */
-+              smp_mb();
-+      } while (unlikely(read_seqretry(&gnttab_dma_lock, seq)));
-+}
++#ifdef CONFIG_SFC_DEBUGFS
++      struct dentry *debug_dir;
++#endif
 +
-+int gnttab_resume(void)
-+{
-+      if (max_nr_grant_frames() < nr_grant_frames)
-+              return -ENOSYS;
-+      return gnttab_map(0, nr_grant_frames - 1);
-+}
++      int rx_alloc_level;
++      int rx_alloc_push_pages;
++      int rx_alloc_pop_pages;
 +
-+int gnttab_suspend(void)
-+{
-+#ifdef CONFIG_X86
-+      apply_to_page_range(&init_mm, (unsigned long)shared,
-+                          PAGE_SIZE * nr_grant_frames,
-+                          unmap_pte_fn, NULL);
-+#endif
-+      return 0;
-+}
++      unsigned n_rx_tobe_disc;
++      unsigned n_rx_ip_frag_err;
++      unsigned n_rx_ip_hdr_chksum_err;
++      unsigned n_rx_tcp_udp_chksum_err;
++      unsigned n_rx_frm_trunc;
++      unsigned n_rx_overlength;
++      unsigned n_skbuff_leaks;
 +
-+#else /* !CONFIG_XEN */
++      /* Used to pipeline received packets in order to optimise memory
++       * access with prefetches.
++       */
++      struct efx_rx_buffer *rx_pkt;
++      int rx_pkt_csummed;
 +
-+#include <platform-pci.h>
++};
 +
-+static unsigned long resume_frames;
++/**
++ * struct efx_blinker - S/W LED blinking context
++ * @led_num: LED ID (board-specific meaning)
++ * @state: Current state - on or off
++ * @resubmit: Timer resubmission flag
++ * @timer: Control timer for blinking
++ */
++struct efx_blinker {
++      int led_num;
++      int state;
++      int resubmit;
++      struct timer_list timer;
++};
 +
-+static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
-+{
-+      struct xen_add_to_physmap xatp;
-+      unsigned int i = end_idx;
 +
-+      /* Loop backwards, so that the first hypercall has the largest index,
-+       * ensuring that the table will grow only once.
-+       */
-+      do {
-+              xatp.domid = DOMID_SELF;
-+              xatp.idx = i;
-+              xatp.space = XENMAPSPACE_grant_table;
-+              xatp.gpfn = (resume_frames >> PAGE_SHIFT) + i;
-+              if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
-+                      BUG();
-+      } while (i-- > start_idx);
++/**
++ * struct efx_board - board information
++ * @type: Board model type
++ * @major: Major rev. ('A', 'B' ...)
++ * @minor: Minor rev. (0, 1, ...)
++ * @init: Initialisation function
++ * @init_leds: Sets up board LEDs
++ * @set_fault_led: Turns the fault LED on or off
++ * @blink: Starts/stops blinking
++ * @monitor: Board-specific health check function
++ * @fini: Cleanup function
++ * @interpret_sensor: Function to interpret LM87 sensor meanings.
++ *    Returns %FALSE if no board-specific meaning.
++ * @mwatts: Power requirements (mW)
++ * @blinker: used to blink LEDs in software
++ * @lm87_addr: I2C address of LM87 monitoring chip (0 if absent)
++ */
++struct efx_board {
++      int type;
++      int major;
++      int minor;
++      int (*init) (struct efx_nic *nic);
++      /* As the LEDs are typically attached to the PHY, LEDs
++       * have a separate init callback that happens later than
++       * board init. */
++      int (*init_leds)(struct efx_nic *efx);
++      int (*monitor) (struct efx_nic *nic);
++      void (*set_fault_led) (struct efx_nic *efx, int state);
++      void (*blink) (struct efx_nic *efx, int start);
++      void (*fini) (struct efx_nic *nic);
++      int (*interpret_sensor) (struct efx_nic *nic, int num, unsigned val);
++      unsigned mwatts;
++      struct efx_blinker blinker;
++      unsigned int lm87_addr;
++};
++
++#define STRING_TABLE_LOOKUP(val, member) \
++      ((val) < member ## _max) ? member ## _names[val] : "(invalid)"
++
++extern const char *efx_loopback_mode_names[];
++extern const unsigned int efx_loopback_mode_max;
++#define LOOPBACK_MODE(efx) \
++      STRING_TABLE_LOOKUP((efx)->loopback_mode, efx_loopback_mode)
++
++extern const char *efx_interrupt_mode_names[];
++extern const unsigned int efx_interrupt_mode_max;
++#define INT_MODE(efx) \
++      STRING_TABLE_LOOKUP(efx->interrupt_mode, efx_interrupt_mode)
++
++extern const char *efx_reset_type_names[];
++extern const unsigned int efx_reset_type_max;
++#define RESET_TYPE(type) \
++      STRING_TABLE_LOOKUP(type, efx_reset_type)
++
++extern const char *efx_phy_type_names[];
++extern const unsigned int efx_phy_type_max;
++#define PHY_TYPE(efx) \
++      STRING_TABLE_LOOKUP((efx)->phy_type, efx_phy_type)
++
++extern const char *efx_nic_state_names[];
++extern const unsigned int efx_nic_state_max;
++#define STATE_NAME(efx)       \
++      STRING_TABLE_LOOKUP((efx)->state, efx_nic_state)
++
++enum efx_int_mode {
++      /* Be careful if altering to correct macro below */
++      EFX_INT_MODE_MSIX = 0,
++      EFX_INT_MODE_MSI = 1,
++      EFX_INT_MODE_LEGACY = 2,
++      EFX_INT_MODE_MAX        /* Insert any new items before this */
++};
++#define EFX_INT_MODE_USE_MSI(x) (((x)->interrupt_mode) <= EFX_INT_MODE_MSI)
++
++enum phy_type {
++      PHY_TYPE_NONE = 0,
++      PHY_TYPE_CX4_RTMR = 1,
++      PHY_TYPE_1G_ALASKA = 2,
++      PHY_TYPE_10XPRESS = 3,
++      PHY_TYPE_XFP = 4,
++      PHY_TYPE_PM8358 = 6,
++      PHY_TYPE_MAX    /* Insert any new items before this */
++};
++
++#define PHY_ADDR_INVALID 0xff
++
++#define EFX_IS10G(efx) ((efx)->is_10g)
++#define EFX_ISCLAUSE45(efx) ((efx)->phy_type != PHY_TYPE_1G_ALASKA)
++
++enum nic_state {
++      STATE_INIT = 0,      /* suspend_lock always held */
++      STATE_RUNNING = 1,
++      STATE_FINI = 2,
++      STATE_RESETTING = 3, /* suspend_lock always held */
++      STATE_DISABLED = 4,
++      STATE_MAX,
++};
++
++/*
++ * Alignment of page-allocated RX buffers
++ *
++ * Controls the number of bytes inserted at the start of an RX buffer.
++ * This is the equivalent of NET_IP_ALIGN [which controls the alignment
++ * of the skb->head for hardware DMA].
++ */
++#ifdef __ia64__
++#define EFX_PAGE_IP_ALIGN 2
++#else
++#define EFX_PAGE_IP_ALIGN 0
++#endif
 +
-+      return 0;
-+}
++/*
++ * Alignment of the skb->head which wraps a page-allocated RX buffer
++ *
++ * The skb allocated to wrap an rx_buffer can have this alignment. Since
++ * the data is memcpy'd from the rx_buf, it does not need to be equal to
++ * EFX_PAGE_IP_ALIGN.
++ */
++#define EFX_PAGE_SKB_ALIGN 2
 +
-+int gnttab_resume(void)
-+{
-+      unsigned int max_nr_gframes, nr_gframes;
++/* Forward declaration */
++struct efx_nic;
 +
-+      nr_gframes = nr_grant_frames;
-+      max_nr_gframes = max_nr_grant_frames();
-+      if (max_nr_gframes < nr_gframes)
-+              return -ENOSYS;
++/* Pseudo bit-mask flow control field */
++enum efx_fc_type {
++      EFX_FC_RX = 1,
++      EFX_FC_TX = 2,
++      EFX_FC_AUTO = 4,
++};
 +
-+      if (!resume_frames) {
-+              resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
-+              shared = ioremap(resume_frames, PAGE_SIZE * max_nr_gframes);
-+              if (shared == NULL) {
-+                      printk("error to ioremap gnttab share frames\n");
-+                      return -1;
-+              }
-+      }
++/**
++ * struct efx_mac_operations - Efx MAC operations table
++ * @mac_writel: Write dword to MAC register
++ * @mac_readl: Read dword from a MAC register
++ * @init: Initialise MAC and PHY
++ * @reconfigure: Reconfigure MAC and PHY (e.g. for new link parameters)
++ * @update_stats: Update statistics
++ * @fini: Shut down MAC and PHY
++ * @check_hw: Check hardware
++ * @fake_phy_event: Simulate a PHY event on a port
++ * @get_settings: Get ethtool settings
++ * @set_settings: Set ethtool settings
++ * @set_pause: Set pause parameters
++ */
++struct efx_mac_operations {
++      void (*mac_writel) (struct efx_nic *efx,
++                          efx_dword_t *value, unsigned int mac_reg);
++      void (*mac_readl) (struct efx_nic *efx,
++                         efx_dword_t *value, unsigned int mac_reg);
++      int (*init) (struct efx_nic *efx);
++      void (*reconfigure) (struct efx_nic *efx);
++      void (*update_stats) (struct efx_nic *efx);
++      void (*fini) (struct efx_nic *efx);
++      int (*check_hw) (struct efx_nic *efx);
++      void (*fake_phy_event) (struct efx_nic *efx);
++
++      int (*get_settings) (struct efx_nic *efx,
++                           struct ethtool_cmd *ecmd);
++      int (*set_settings) (struct efx_nic *efx,
++                           struct ethtool_cmd *ecmd);
++      int (*set_pause) (struct efx_nic *efx,
++                        enum efx_fc_type pause_params);
++};
 +
-+      gnttab_map(0, nr_gframes - 1);
++/**
++ * struct efx_phy_operations - Efx PHY operations table
++ * @init: Initialise PHY
++ * @fini: Shut down PHY
++ * @reconfigure: Reconfigure PHY (e.g. for new link parameters)
++ * @clear_interrupt: Clear down interrupt
++ * @blink: Blink LEDs
++ * @check_hw: Check hardware
++ * @reset_xaui: Reset XAUI side of PHY for (software sequenced reset)
++ * @mmds: MMD presence mask
++ * @loopbacks: Supported loopback modes mask
++ * @startup_loopback: Loopback mode for start-of-day self-test
++ */
++struct efx_phy_operations {
++      int (*init) (struct efx_nic *efx);
++      void (*fini) (struct efx_nic *efx);
++      void (*reconfigure) (struct efx_nic *efx);
++      void (*clear_interrupt) (struct efx_nic *efx);
++      int (*check_hw) (struct efx_nic *efx);
++      void (*reset_xaui) (struct efx_nic *efx);
++      int mmds;
++      unsigned loopbacks;
++      unsigned startup_loopback;
++};
++
++/*
++ * Efx extended statistics
++ *
++ * Not all statistics are provided by all supported MACs.  The purpose
++ * is this structure is to contain the raw statistics provided by each
++ * MAC.
++ */
++struct efx_mac_stats {
++      u64 tx_bytes;
++      u64 tx_good_bytes;
++      u64 tx_bad_bytes;
++      unsigned long tx_packets;
++      unsigned long tx_bad;
++      unsigned long tx_pause;
++      unsigned long tx_control;
++      unsigned long tx_unicast;
++      unsigned long tx_multicast;
++      unsigned long tx_broadcast;
++      unsigned long tx_lt64;
++      unsigned long tx_64;
++      unsigned long tx_65_to_127;
++      unsigned long tx_128_to_255;
++      unsigned long tx_256_to_511;
++      unsigned long tx_512_to_1023;
++      unsigned long tx_1024_to_15xx;
++      unsigned long tx_15xx_to_jumbo;
++      unsigned long tx_gtjumbo;
++      unsigned long tx_collision;
++      unsigned long tx_single_collision;
++      unsigned long tx_multiple_collision;
++      unsigned long tx_excessive_collision;
++      unsigned long tx_deferred;
++      unsigned long tx_late_collision;
++      unsigned long tx_excessive_deferred;
++      unsigned long tx_non_tcpudp;
++      unsigned long tx_mac_src_error;
++      unsigned long tx_ip_src_error;
++      u64 rx_bytes;
++      u64 rx_good_bytes;
++      u64 rx_bad_bytes;
++      unsigned long rx_packets;
++      unsigned long rx_good;
++      unsigned long rx_bad;
++      unsigned long rx_pause;
++      unsigned long rx_control;
++      unsigned long rx_unicast;
++      unsigned long rx_multicast;
++      unsigned long rx_broadcast;
++      unsigned long rx_lt64;
++      unsigned long rx_64;
++      unsigned long rx_65_to_127;
++      unsigned long rx_128_to_255;
++      unsigned long rx_256_to_511;
++      unsigned long rx_512_to_1023;
++      unsigned long rx_1024_to_15xx;
++      unsigned long rx_15xx_to_jumbo;
++      unsigned long rx_gtjumbo;
++      unsigned long rx_bad_lt64;
++      unsigned long rx_bad_64_to_15xx;
++      unsigned long rx_bad_15xx_to_jumbo;
++      unsigned long rx_bad_gtjumbo;
++      unsigned long rx_overflow;
++      unsigned long rx_missed;
++      unsigned long rx_false_carrier;
++      unsigned long rx_symbol_error;
++      unsigned long rx_align_error;
++      unsigned long rx_length_error;
++      unsigned long rx_internal_error;
++      unsigned long rx_good_lt64;
++};
++
++/* Number of bits used in a multicast filter hash address */
++#define EFX_MCAST_HASH_BITS 8
++
++/* Number of (single-bit) entries in a multicast filter hash */
++#define EFX_MCAST_HASH_ENTRIES (1 << EFX_MCAST_HASH_BITS)
++
++/* An Efx multicast filter hash */
++union efx_multicast_hash {
++      u8 byte[EFX_MCAST_HASH_ENTRIES / sizeof(u8)];
++      efx_oword_t oword[EFX_MCAST_HASH_ENTRIES / sizeof(efx_oword_t)];
++};
++
++/* Efx Error condition statistics */
++struct efx_nic_errors {
++      atomic_t missing_event;
++      atomic_t rx_reset;
++      atomic_t rx_desc_fetch;
++      atomic_t tx_desc_fetch;
++      atomic_t spurious_tx;
++
++#ifdef CONFIG_SFC_DEBUGFS
++      struct dentry *debug_dir;
++#endif
++};
 +
-+      return 0;
-+}
++/**
++ * struct efx_nic - an Efx NIC
++ * @name: Device name (net device name or bus id before net device registered)
++ * @pci_dev: The PCI device
++ * @pci_dev2: The secondary PCI device if present
++ * @type: Controller type attributes
++ * @dma_mask: DMA mask
++ * @legacy_irq: IRQ number
++ * @workqueue: Workqueue for resets, port reconfigures and the HW monitor
++ * @refill_workqueue: RX refill workqueue
++ * @reset_work: Scheduled reset workitem
++ * @monitor_work: Hardware monitor workitem
++ * @membase_phys: Memory BAR value as physical address
++ * @membase: Memory BAR value
++ * @biu_lock: BIU (bus interface unit) lock
++ * @interrupt_mode: Interrupt mode
++ * @is_asic: Is ASIC (else FPGA)
++ * @is_10g: Is set to 10G (else 1G)
++ * @external_sram_cfg: Size and number of banks of external SRAM
++ * @i2c: I2C interface
++ * @board_info: Board-level information
++ * @state: Device state flag. Can only be manipulated when both
++ *    suspend_lock and rtnl_lock are held.  Can be read when
++ *    either is held.
++ * @reset_pending: Pending reset method (normally RESET_TYPE_NONE)
++ * @suspend_lock: Device suspend lock.  This must not be acquired with
++ *    rtnl_lock held.
++ * @tx_queue: TX DMA queues
++ * @rx_queue: RX DMA queues
++ * @channel: Channels
++ * @rss_queues: Number of RSS queues
++ * @rx_buffer_len: RX buffer length
++ * @rx_buffer_order: Order (log2) of number of pages for each RX buffer
++ * @errors: Error condition stats
++ * @irq_status: Interrupt status buffer
++ * @last_irq_cpu: Last CPU to handle interrupt.
++ *    This register is written with the SMP processor ID whenever an
++ *    interrupt is handled.  It is used by falcon_test_interrupt()
++ *    to verify that an interrupt has occurred.
++ * @spi_flash: SPI flash device
++ *    This field will be %NULL if no flash device is present.
++ * @spi_eeprom: SPI EEPROM device
++ *    This field will be %NULL if no EEPROM device is present.
++ * @spi_lock: SPI bus lock
++ * @n_rx_nodesc_drop_cnt: RX no descriptor drop count
++ * @nic_data: Hardware dependant state
++ * @mac_lock: MAC access lock. Protects efx->port_enabled/net_dev_registered
++ *            and efx_reconfigure_port()
++ * @port_enabled: Port enabled indicator.
++ *    Serialises efx_stop_all and efx_start_all with kernel interfaces.
++ *    Safe to read under the rtnl_lock, mac_lock, or netif_tx_lock, but
++ *    all three must be held to modify it.
++ * @net_dev_registered: Port is registered with operating system.
++ * @port_initialized: Port initialized?
++ * @net_dev: Operating system network device. Consider holding the rtnl lock
++ * @rx_checksum_enabled: RX checksumming enabled
++ * @netif_stop_count: Port stop count
++ * @netif_stop_lock: Port stop lock
++ * @mac_stats: MAC statistics
++ * @stats: Net device statistics.
++ *    Hardware-specific code fills in @mac_stats, which provides a
++ *    detailed breakdown.  Generic code aggregates these statistics
++ *    into a standard &struct net_device_stats.
++ * @stats_buffer: DMA buffer for statistics
++ * @stats_lock: Statistics update lock
++ * @mac_op: MAC interface
++ * @mac_address: Permanent MAC address
++ * @phy_type: PHY type
++ * @phy_lock: PHY access lock
++ * @phy_op: PHY interface
++ * @phy_data: PHY private data (including PHY-specific stats)
++ * @mii: PHY interface
++ * @phy_powered: PHY power state
++ * @tx_disabled: PHY transmitter turned off
++ * @link_up: Link status
++ * @link_options: Link options (MII/GMII format)
++ * @n_link_state_changes: Number of times the link has changed state
++ * @promiscuous: Promiscuous flag. Protected by netif_tx_lock.
++ * @multicast_hash: Multicast hash table
++ * @flow_control: Flow control flags - separate RX/TX so can't use link_options
++ * @reconfigure_work: work item for dealing with PHY events
++ * @loopback_mode: Loopback status
++ * @loopback_modes: Supported loopback mode bitmask
++ * @loopback_selftest: Offline self-test private state
++ * @silicon_rev: Silicon revision description for driverlink
++ * @dl_info: Linked list of hardware parameters exposed through driverlink
++ * @dl_node: Driverlink port list
++ * @dl_device_list: Driverlink device list
++ * @dl_cb: Driverlink callbacks table
++ * @dl_cb_dev: Driverlink callback owner devices
++ * @debug_dir: NIC debugfs directory
++ * @debug_symlink: NIC debugfs sym-link (nic_eth\%d)
++ * @debug_port_dir: Port debugfs directory
++ * @debug_port_symlink: Port debugfs sym-link (if_eth\%d)
++ *
++ * The @priv field of the corresponding &struct net_device points to
++ * this.
++ */
++struct efx_nic {
++      char name[IFNAMSIZ];
++      struct pci_dev *pci_dev;
++      struct pci_dev *pci_dev2;
++#if !defined(EFX_USE_PCI_DEV_REVISION)
++      u8 revision;
++#endif
++      const struct efx_nic_type *type;
++      dma_addr_t dma_mask;
++      int legacy_irq;
++      struct workqueue_struct *workqueue;
++#if !defined(EFX_USE_CANCEL_DELAYED_WORK_SYNC)
++      /* Since we can't use cancel_delayed_work_sync efx_reset() has to
++       * flush efx->workqueue to serialise against efx_reconfigure_port
++       * and efx_monitor. So it can't also run on workqueue */
++      struct workqueue_struct *reset_workqueue;
++#endif
++      struct workqueue_struct *refill_workqueue;
++      struct work_struct reset_work;
++      struct delayed_work monitor_work;
++      unsigned long membase_phys;
++      void __iomem *membase;
++      spinlock_t biu_lock;
++      enum efx_int_mode interrupt_mode;
++      unsigned int is_asic:1;
++      unsigned int is_10g:1;
++      int external_sram_cfg;
++
++      struct efx_i2c_interface i2c;
++      struct efx_board board_info;
++
++      enum nic_state state;
++      enum reset_type reset_pending;
++
++      struct semaphore suspend_lock;
++
++      struct efx_tx_queue tx_queue[EFX_MAX_TX_QUEUES];
++      struct efx_rx_queue rx_queue[EFX_MAX_RX_QUEUES];
++      struct efx_channel channel[EFX_MAX_CHANNELS];
++
++      int rss_queues;
++      unsigned int rx_buffer_len;
++      unsigned int rx_buffer_order;
++
++      struct efx_nic_errors errors;
++
++      struct efx_buffer irq_status;
++      volatile signed int last_irq_cpu;
++
++      struct efx_spi_device *spi_flash;
++      struct efx_spi_device *spi_eeprom;
++      struct mutex spi_lock;
++
++      unsigned n_rx_nodesc_drop_cnt;
++
++      void *nic_data;
++
++      struct mutex mac_lock;
++      int port_enabled;
++      int net_dev_registered;
++
++      int port_initialized;
++      struct net_device *net_dev;
++      int rx_checksum_enabled;
++
++      atomic_t netif_stop_count;
++      spinlock_t netif_stop_lock;
++
++      struct efx_mac_stats mac_stats;
++      struct net_device_stats stats;
++      struct efx_buffer stats_buffer;
++      spinlock_t stats_lock;
 +
-+#endif /* !CONFIG_XEN */
++      struct efx_mac_operations *mac_op;
++      unsigned char mac_address[ETH_ALEN];
 +
-+static int gnttab_expand(unsigned int req_entries)
-+{
-+      int rc;
-+      unsigned int cur, extra;
++      enum phy_type phy_type;
++      spinlock_t phy_lock;
++      struct efx_phy_operations *phy_op;
++      void *phy_data;
++      struct mii_if_info mii;
++      unsigned phy_powered;
++      unsigned tx_disabled;
 +
-+      cur = nr_grant_frames;
-+      extra = ((req_entries + (GREFS_PER_GRANT_FRAME-1)) /
-+               GREFS_PER_GRANT_FRAME);
-+      if (cur + extra > max_nr_grant_frames())
-+              return -ENOSPC;
++      int link_up;
++      unsigned int link_options;
++      unsigned int n_link_state_changes;
 +
-+      if ((rc = gnttab_map(cur, cur + extra - 1)) == 0)
-+              rc = grow_gnttab_list(extra);
++      int promiscuous;
++      union efx_multicast_hash multicast_hash;
++      enum efx_fc_type flow_control;
++      struct work_struct reconfigure_work;
 +
-+      return rc;
-+}
++      enum efx_loopback_mode loopback_mode;
++      unsigned int loopback_modes;
++      unsigned int startup_loopbacks;
 +
-+int __devinit gnttab_init(void)
-+{
-+      int i;
-+      unsigned int max_nr_glist_frames;
-+      unsigned int nr_init_grefs;
++      void *loopback_selftest;
 +
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++      const char *silicon_rev;
++      struct efx_dl_device_info *dl_info;
++      struct list_head dl_node;
++      struct list_head dl_device_list;
++      struct efx_dl_callbacks dl_cb;
++      struct efx_dl_cb_devices dl_cb_dev;
 +
-+      nr_grant_frames = 1;
-+      boot_max_nr_grant_frames = __max_nr_grant_frames();
++#ifdef CONFIG_SFC_DEBUGFS
++      struct dentry *debug_dir;
++      struct dentry *debug_symlink;
++      struct dentry *debug_port_dir;
++      struct dentry *debug_port_symlink;
++#endif
++};
 +
-+      /* Determine the maximum number of frames required for the
-+       * grant reference free list on the current hypervisor.
-+       */
-+      max_nr_glist_frames = (boot_max_nr_grant_frames *
-+                             GREFS_PER_GRANT_FRAME /
-+                             (PAGE_SIZE / sizeof(grant_ref_t)));
++/**
++ * struct efx_nic_type - Efx device type definition
++ * @is_dual_func: Is dual-function (else single-function)
++ * @mem_bar: Memory BAR number
++ * @mem_map_size: Memory BAR mapped size
++ * @txd_ptr_tbl_base: TX descriptor ring base address
++ * @rxd_ptr_tbl_base: RX descriptor ring base address
++ * @buf_tbl_base: Buffer table base address
++ * @evq_ptr_tbl_base: Event queue pointer table base address
++ * @evq_rptr_tbl_base: Event queue read-pointer table base address
++ * @txd_ring_mask: TX descriptor ring size - 1 (must be a power of two - 1)
++ * @rxd_ring_mask: RX descriptor ring size - 1 (must be a power of two - 1)
++ * @evq_size: Event queue size (must be a power of two)
++ * @max_dma_mask: Maximum possible DMA mask
++ * @tx_dma_mask: TX DMA mask
++ * @bug5391_mask: Address mask for bug 5391 workaround
++ * @rx_xoff_thresh: RX FIFO XOFF watermark (bytes)
++ * @rx_xon_thresh: RX FIFO XON watermark (bytes)
++ * @rx_buffer_padding: Padding added to each RX buffer
++ * @max_interrupt_mode: Highest capability interrupt mode supported
++ *    from &enum efx_init_mode.
++ * @phys_addr_channels: Number of channels with physically addressed
++ *    descriptors
++ */
++struct efx_nic_type {
++      unsigned int is_dual_func;
++      unsigned int mem_bar;
++      unsigned int mem_map_size;
++      unsigned int txd_ptr_tbl_base;
++      unsigned int rxd_ptr_tbl_base;
++      unsigned int buf_tbl_base;
++      unsigned int evq_ptr_tbl_base;
++      unsigned int evq_rptr_tbl_base;
++
++      unsigned int txd_ring_mask;
++      unsigned int rxd_ring_mask;
++      unsigned int evq_size;
++      dma_addr_t max_dma_mask;
++      unsigned int tx_dma_mask;
++      unsigned bug5391_mask;
++
++      int rx_xoff_thresh;
++      int rx_xon_thresh;
++      unsigned int rx_buffer_padding;
++      unsigned int max_interrupt_mode;
++      unsigned int phys_addr_channels;
++};
++
++/**************************************************************************
++ *
++ * Prototypes and inline functions
++ *
++ *************************************************************************/
++
++/* Iterate over all used channels */
++#define efx_for_each_channel(_channel, _efx)                          \
++      for (_channel = &_efx->channel[0];                              \
++           _channel < &_efx->channel[EFX_MAX_CHANNELS];               \
++           _channel++)                                                \
++              if (!_channel->used_flags)                              \
++                      continue;                                       \
++              else
 +
-+      gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
-+                            GFP_KERNEL);
-+      if (gnttab_list == NULL)
-+              return -ENOMEM;
++/* Iterate over all used channels with interrupts */
++#define efx_for_each_channel_with_interrupt(_channel, _efx)           \
++      for (_channel = &_efx->channel[0];                              \
++           _channel < &_efx->channel[EFX_MAX_CHANNELS];               \
++           _channel++)                                                \
++              if (!(_channel->used_flags && _channel->has_interrupt)) \
++                      continue;                                       \
++              else
 +
-+      for (i = 0; i < nr_grant_frames; i++) {
-+              gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
-+              if (gnttab_list[i] == NULL)
-+                      goto ini_nomem;
-+      }
++/* Iterate over all used TX queues */
++#define efx_for_each_tx_queue(_tx_queue, _efx)                                \
++      for (_tx_queue = &_efx->tx_queue[0];                            \
++           _tx_queue < &_efx->tx_queue[EFX_MAX_TX_QUEUES];            \
++           _tx_queue++)                                               \
++              if (!_tx_queue->used)                                   \
++                      continue;                                       \
++              else
 +
-+      if (gnttab_resume() < 0)
-+              return -ENODEV;
++/* Iterate over all TX queues belonging to a channel */
++#define efx_for_each_channel_tx_queue(_tx_queue, _channel)            \
++      for (_tx_queue = &_channel->efx->tx_queue[0];                   \
++           _tx_queue < &_channel->efx->tx_queue[EFX_MAX_TX_QUEUES];   \
++           _tx_queue++)                                               \
++              if ((!_tx_queue->used) ||                               \
++                  (_tx_queue->channel != _channel))                   \
++                      continue;                                       \
++              else
 +
-+      nr_init_grefs = nr_grant_frames * GREFS_PER_GRANT_FRAME;
++/* Iterate over all used RX queues */
++#define efx_for_each_rx_queue(_rx_queue, _efx)                                \
++      for (_rx_queue = &_efx->rx_queue[0];                            \
++           _rx_queue < &_efx->rx_queue[EFX_MAX_RX_QUEUES];            \
++           _rx_queue++)                                               \
++              if (!_rx_queue->used)                                   \
++                      continue;                                       \
++              else
 +
-+      for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
-+              gnttab_entry(i) = i + 1;
++/* Iterate over all RX queues belonging to a channel */
++#define efx_for_each_channel_rx_queue(_rx_queue, _channel)            \
++      for (_rx_queue = &_channel->efx->rx_queue[0];                   \
++           _rx_queue < &_channel->efx->rx_queue[EFX_MAX_RX_QUEUES];   \
++           _rx_queue++)                                               \
++              if ((!_rx_queue->used) ||                               \
++                  (_rx_queue->channel != _channel))                   \
++                      continue;                                       \
++              else
 +
-+      gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
-+      gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
-+      gnttab_free_head  = NR_RESERVED_ENTRIES;
++/* Name formats */
++#define EFX_CHANNEL_NAME(_channel) "channel%d", _channel->channel
++#define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue
++#define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue
 +
-+      return 0;
++/* Returns a pointer to the specified receive buffer in the RX
++ * descriptor queue.
++ */
++static inline struct efx_rx_buffer *efx_rx_buffer(struct efx_rx_queue *rx_queue,
++                                                unsigned int index)
++{
++      return (&rx_queue->buffer[index]);
++}
 +
-+ ini_nomem:
-+      for (i--; i >= 0; i--)
-+              free_page((unsigned long)gnttab_list[i]);
-+      kfree(gnttab_list);
-+      return -ENOMEM;
++/* Set bit in a little-endian bitfield */
++static inline void set_bit_le(int nr, unsigned char *addr)
++{
++      addr[nr / 8] |= (1 << (nr % 8));
 +}
 +
-+#ifdef CONFIG_XEN
-+core_initcall(gnttab_init);
-+#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/hypervisor_sysfs.c linux-2.6.18-xen.hg/drivers/xen/core/hypervisor_sysfs.c
---- linux-2.6.18/drivers/xen/core/hypervisor_sysfs.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/hypervisor_sysfs.c    2007-12-23 11:15:33.661248285 +0100
-@@ -0,0 +1,57 @@
-+/*
-+ *  copyright (c) 2006 IBM Corporation
-+ *  Authored by: Mike D. Day <ncmike@us.ibm.com>
++/* Clear bit in a little-endian bitfield */
++static inline void clear_bit_le(int nr, unsigned char *addr)
++{
++      addr[nr / 8] &= ~(1 << (nr % 8));
++}
++
++
++/**
++ * EFX_MAX_FRAME_LEN - calculate maximum frame length
 + *
-+ *  This program is free software; you can redistribute it and/or modify
-+ *  it under the terms of the GNU General Public License version 2 as
-+ *  published by the Free Software Foundation.
++ * This calculates the maximum frame length that will be used for a
++ * given MTU.  The frame length will be equal to the MTU plus a
++ * constant amount of header space and padding.  This is the quantity
++ * that the net driver will program into the MAC as the maximum frame
++ * length.
++ *
++ * The 10G MAC used in Falcon requires 8-byte alignment on the frame
++ * length, so we round up to the nearest 8.
 + */
++#define EFX_MAX_FRAME_LEN(mtu) \
++      ((((mtu) + ETH_HLEN + VLAN_HLEN + 4/* FCS */) + 7) & ~7)
 +
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/kobject.h>
-+#include <xen/hypervisor_sysfs.h>
-+#include <asm/hypervisor.h>
 +
-+static ssize_t hyp_sysfs_show(struct kobject *kobj,
-+                            struct attribute *attr,
-+                            char *buffer)
++#endif /* EFX_NET_DRIVER_H */
+--- linux-2.6.18.8/drivers/net/sfc/null_phy.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/null_phy.c     2008-05-19 00:33:29.317836041 +0300
+@@ -0,0 +1,62 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include "efx.h"
++#include "falcon.h"
++#include "gmii.h"
++#include "phy.h"
++
++static int falcon_null_phy_check_hw(struct efx_nic *efx)
 +{
-+      struct hyp_sysfs_attr *hyp_attr;
-+      hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
-+      if (hyp_attr->show)
-+              return hyp_attr->show(hyp_attr, buffer);
++      int link_ok = falcon_xaui_link_ok(efx);
++
++      /* Generate PHY event that a PHY would have generated */
++      if (link_ok != efx->link_up) {
++              efx->link_up = link_ok;
++              efx->mac_op->fake_phy_event(efx);
++      }
++
 +      return 0;
 +}
 +
-+static ssize_t hyp_sysfs_store(struct kobject *kobj,
-+                             struct attribute *attr,
-+                             const char *buffer,
-+                             size_t len)
++static void falcon_null_phy_reconfigure(struct efx_nic *efx)
 +{
-+      struct hyp_sysfs_attr *hyp_attr;
-+      hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
-+      if (hyp_attr->store)
-+              return hyp_attr->store(hyp_attr, buffer, len);
-+      return 0;
++      /* CX4 is always 10000FD only */
++      efx->link_options = GM_LPA_10000FULL;
++
++      falcon_null_phy_check_hw(efx);
 +}
 +
-+static struct sysfs_ops hyp_sysfs_ops = {
-+      .show = hyp_sysfs_show,
-+      .store = hyp_sysfs_store,
++struct efx_phy_operations falcon_null_phy_ops = {
++      .reconfigure     = falcon_null_phy_reconfigure,
++      .check_hw        = falcon_null_phy_check_hw,
++      .fini            = efx_port_dummy_op_void,
++      .clear_interrupt = efx_port_dummy_op_void,
++      .init            = efx_port_dummy_op_int,
++      .reset_xaui      = efx_port_dummy_op_void,
++      .mmds            = 0,
++      .loopbacks       = 0,
++      .startup_loopback = 0,
 +};
+--- linux-2.6.18.8/drivers/net/sfc/phy.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/phy.c  2008-05-19 00:33:29.317836041 +0300
+@@ -0,0 +1,28 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2007:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static struct kobj_type hyp_sysfs_kobj_type = {
-+      .sysfs_ops = &hyp_sysfs_ops,
-+};
++#include "net_driver.h"
++#include "phy.h"
 +
-+static int __init hypervisor_subsys_init(void)
-+{
-+      if (!is_running_on_xen())
-+              return -ENODEV;
+--- linux-2.6.18.8/drivers/net/sfc/phy.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/phy.h  2008-05-19 00:33:29.317836041 +0300
+@@ -0,0 +1,90 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2007:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      hypervisor_subsys.kset.kobj.ktype = &hyp_sysfs_kobj_type;
-+      return 0;
-+}
++#ifndef EFX_PHY_H
++#define EFX_PHY_H
 +
-+device_initcall(hypervisor_subsys_init);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/machine_kexec.c linux-2.6.18-xen.hg/drivers/xen/core/machine_kexec.c
---- linux-2.6.18/drivers/xen/core/machine_kexec.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/machine_kexec.c       2007-12-23 11:15:33.664581791 +0100
-@@ -0,0 +1,189 @@
-+/*
-+ * drivers/xen/core/machine_kexec.c 
-+ * handle transition of Linux booting another kernel
++/****************************************************************************
++ * 10Xpress (SFX7101) PHY
 + */
++extern struct efx_phy_operations falcon_tenxpress_phy_ops;
 +
-+#include <linux/kexec.h>
-+#include <xen/interface/kexec.h>
-+#include <linux/mm.h>
-+#include <linux/bootmem.h>
++enum tenxpress_state {
++      TENXPRESS_STATUS_OFF = 0,
++      TENXPRESS_STATUS_OTEMP = 1,
++      TENXPRESS_STATUS_NORMAL = 2,
++};
 +
-+extern void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, 
-+                                       struct kimage *image);
++extern void tenxpress_set_state(struct efx_nic *efx,
++                              enum tenxpress_state state);
++extern void tenxpress_phy_blink(struct efx_nic *efx, int blink);
++extern void tenxpress_crc_err(struct efx_nic *efx);
 +
-+static int __initdata xen_max_nr_phys_cpus;
-+static struct resource xen_hypervisor_res;
-+static struct resource *xen_phys_cpus;
++/****************************************************************************
++ * Marvell 88E1111 "Alaska" PHY control
++ */
++extern struct efx_phy_operations alaska_phy_operations;
 +
-+void __init xen_machine_kexec_setup_resources(void)
-+{
-+      xen_kexec_range_t range;
-+      struct resource *res;
-+      int k = 0;
++/****************************************************************************
++* Exported functions from the driver for Transwitch CX4 retimer
++*/
++extern struct efx_phy_operations falcon_txc_phy_ops;
 +
-+      if (!is_initial_xendomain())
-+              return;
++#define TXC_GPIO_DIR_INPUT  (0)
++#define TXC_GPIO_DIR_OUTPUT (1)
 +
-+      /* determine maximum number of physical cpus */
++extern void txc_set_gpio_dir(struct efx_nic *p, int pin, int dir);
++extern void txc_set_gpio_val(struct efx_nic *p, int pin, int val);
 +
-+      while (1) {
-+              memset(&range, 0, sizeof(range));
-+              range.range = KEXEC_RANGE_MA_CPU;
-+              range.nr = k;
++/****************************************************************************
++ * Exported functions from the driver for PMC PM8358 PHY
++ */
++extern struct efx_phy_operations falcon_pm8358_phy_ops;
 +
-+              if(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
-+                      break;
++/****************************************************************************
++ * Exported functions from the driver for XFP optical PHYs
++ */
++extern struct efx_phy_operations falcon_xfp_phy_ops;
 +
-+              k++;
-+      }
++/* The QUAKE XFP PHY provides various H/W control states for LEDs */
++#define QUAKE_LED_LINK_INVAL  (0)
++#define QUAKE_LED_LINK_STAT   (1)
++#define QUAKE_LED_LINK_ACT    (2)
++#define QUAKE_LED_LINK_ACTSTAT        (3)
++#define QUAKE_LED_OFF         (4)
++#define QUAKE_LED_ON          (5)
++#define QUAKE_LED_LINK_INPUT  (6)     /* Pin is an input. */
++/* What link the LED tracks */
++#define QUAKE_LED_TXLINK      (0)
++#define QUAKE_LED_RXLINK      (8)
 +
-+      if (k == 0)
-+              return;
++extern void xfp_set_led(struct efx_nic *p, int led, int state);
 +
-+      xen_max_nr_phys_cpus = k;
++/****************************************************************************
++ * NULL PHY ops
++ */
++extern struct efx_phy_operations falcon_null_phy_ops;
 +
-+      /* allocate xen_phys_cpus */
++#endif
+--- linux-2.6.18.8/drivers/net/sfc/pm8358_phy.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/pm8358_phy.c   2008-05-19 00:33:29.317836041 +0300
+@@ -0,0 +1,206 @@
++/* Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++/*
++ *  Driver for PMC-Sierra PM8358 XAUI PHY
++ */
 +
-+      xen_phys_cpus = alloc_bootmem_low(k * sizeof(struct resource));
-+      BUG_ON(xen_phys_cpus == NULL);
++#include <linux/delay.h>
++#include "efx.h"
++#include "gmii.h"
++#include "mdio_10g.h"
++#include "phy.h"
++
++#define PM8358_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_DTEXS)
++#define PM8358_LOOPBACKS (1 << LOOPBACK_PHY)
++
++/* PHY-specific definitions */
++/* Master ID and Global Performance Monitor Update */
++#define PMC_MASTER_REG (0xd000)
++/* Analog TX/RX settings under software control */
++#define PMC_MASTER_ANLG_CTRL (1 << 11)
++
++#define PMC_MCONF2_REG        (0xd002)
++/* Drive TX off centre of data eye (1) vs. clock edge (0) */
++#define       PMC_MCONF2_TEDGE (1 << 2)
++/* Drive RX off centre of data eye (1) vs. clock edge (0) */
++#define PMC_MCONF2_REDGE (1 << 3)
++
++/* Analog RX settings */
++#define PMC_ANALOG_RX_CFG0   (0xd025)
++#define PMC_ANALOG_RX_CFG1   (0xd02d)
++#define PMC_ANALOG_RX_CFG2   (0xd035)
++#define PMC_ANALOG_RX_CFG3   (0xd03d)
++#define PMC_ANALOG_RX_TERM     (1 << 15) /* Bit 15 of RX CFG: 0 for 100 ohms
++                                          float, 1 for 50 to 1.2V */
++#define PMC_ANALOG_RX_EQ_MASK (3 << 8)
++#define PMC_ANALOG_RX_EQ_NONE (0 << 8)
++#define PMC_ANALOG_RX_EQ_HALF (1 << 8)
++#define PMC_ANALOG_RX_EQ_FULL (2 << 8)
++#define PMC_ANALOG_RX_EQ_RSVD (3 << 8)
++
++/* Reset the DTE XS MMD. */
++#define PMC_MAX_RESET_TIME 500
++#define PMC_RESET_WAIT 10
++
++static int pmc_reset_phy(struct efx_nic *efx)
++{
++      int rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_DTEXS,
++                                       PMC_MAX_RESET_TIME / PMC_RESET_WAIT,
++                                       PMC_RESET_WAIT);
++      if (rc >= 0) {
++              EFX_TRACE(efx, "PMC8358: came out of reset with "
++                        "%d0 ms left\n", rc);
++              rc = 0;
++      } else {
++              EFX_ERR(efx, "PMC8358: reset timed out!\n");
++      }
++      return rc;
++}
 +
-+      /* fill in xen_phys_cpus with per-cpu crash note information */
 +
-+      for (k = 0; k < xen_max_nr_phys_cpus; k++) {
-+              memset(&range, 0, sizeof(range));
-+              range.range = KEXEC_RANGE_MA_CPU;
-+              range.nr = k;
++static void pmc_full_rx_eq(struct efx_nic *efx)
++{
++      int i, reg;
 +
-+              if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
-+                      goto err;
++      /* Enable software control of analog settings */
++      reg = mdio_clause45_read(efx, efx->mii.phy_id,
++                               MDIO_MMD_DTEXS, PMC_MASTER_REG);
++      reg |= PMC_MASTER_ANLG_CTRL;
 +
-+              res = xen_phys_cpus + k;
++      mdio_clause45_write(efx, efx->mii.phy_id,
++                          MDIO_MMD_DTEXS, PMC_MASTER_REG, reg);
 +
-+              memset(res, 0, sizeof(*res));
-+              res->name = "Crash note";
-+              res->start = range.start;
-+              res->end = range.start + range.size - 1;
-+              res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
++      /* Turn RX eq on full for all channels. */
++      for (i = 0; i < 3; i++) {
++              /* The analog CFG registers are evenly spaced 8 apart */
++              u16 addr = PMC_ANALOG_RX_CFG0 + 8 * i;
++
++              reg = mdio_clause45_read(efx, efx->mii.phy_id,
++                                       MDIO_MMD_DTEXS, addr);
++              reg = (reg & ~PMC_ANALOG_RX_EQ_MASK) | PMC_ANALOG_RX_EQ_FULL;
++              mdio_clause45_write(efx, efx->mii.phy_id,
++                                  MDIO_MMD_DTEXS, addr, reg);
 +      }
++}
 +
-+      /* fill in xen_hypervisor_res with hypervisor machine address range */
++static void pmc_set_data_edges(struct efx_nic *efx)
++{
++      int reg;
++      /* Set TEDGE, clear REDGE */
++      reg = mdio_clause45_read(efx, efx->mii.phy_id,
++                               MDIO_MMD_DTEXS, PMC_MCONF2_REG);
++      reg &= ~PMC_MCONF2_REDGE;
++      reg |= PMC_MCONF2_TEDGE;
 +
-+      memset(&range, 0, sizeof(range));
-+      range.range = KEXEC_RANGE_MA_XEN;
++      mdio_clause45_write(efx, efx->mii.phy_id,
++                          MDIO_MMD_DTEXS, PMC_MCONF2_REG, reg);
++}
 +
-+      if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
-+              goto err;
++static int pm8358_phy_init(struct efx_nic *efx)
++{
++      u32 devid;
++      int rc;
 +
-+      xen_hypervisor_res.name = "Hypervisor code and data";
-+      xen_hypervisor_res.start = range.start;
-+      xen_hypervisor_res.end = range.start + range.size - 1;
-+      xen_hypervisor_res.flags = IORESOURCE_BUSY | IORESOURCE_MEM;
++      /* The GLB_CTL reset line has been pulled before this is called,
++       * and it may take up to 5ms for the PLL's to synchronise after
++       * this is done. Best to wait 10ms here */
++      schedule_timeout_uninterruptible(HZ / 100);
 +
-+      /* fill in crashk_res if range is reserved by hypervisor */
++      rc = pmc_reset_phy(efx);
++      if (rc < 0)
++              return rc;
 +
-+      memset(&range, 0, sizeof(range));
-+      range.range = KEXEC_RANGE_MA_CRASH;
++      /* Check that all the MMDs we expect are present and responding. We
++       * expect faults on some if the link is down, but not on the PHY XS */
++      rc = mdio_clause45_check_mmds(efx, PM8358_REQUIRED_DEVS, 0);
++      if (rc < 0)
++              return rc;
 +
-+      if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
-+              return;
++      devid = mdio_clause45_read_id(efx, MDIO_MMD_DTEXS);
++      EFX_LOG(efx, "PM8358: PHY ID reg %x (OUI %x model %x revision"
++              " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
++              MDIO_ID_REV(devid));
 +
-+      if (range.size) {
-+              crashk_res.start = range.start;
-+              crashk_res.end = range.start + range.size - 1;
-+      }
++      /* Turn on full RX equalisation */
++      pmc_full_rx_eq(efx);
 +
-+      return;
++      /* Adjust RX and TX data edge position */
++      pmc_set_data_edges(efx);
 +
-+ err:
-+      /*
-+       * It isn't possible to free xen_phys_cpus this early in the
-+       * boot. Failure at this stage is unexpected and the amount of
-+       * memory is small therefore we tolerate the potential leak.
-+         */
-+      xen_max_nr_phys_cpus = 0;
-+      return;
++      EFX_LOG(efx, "PM8358: PHY init successful.\n");
++      return rc;
 +}
 +
-+void __init xen_machine_kexec_register_resources(struct resource *res)
++static int pm8358_link_ok(struct efx_nic *efx)
 +{
-+      int k;
-+
-+      request_resource(res, &xen_hypervisor_res);
++      return mdio_clause45_links_ok(efx, PM8358_REQUIRED_DEVS);
++}
 +
-+      for (k = 0; k < xen_max_nr_phys_cpus; k++)
-+              request_resource(&xen_hypervisor_res, xen_phys_cpus + k);
++static int pm8358_phy_check_hw(struct efx_nic *efx)
++{
++      int rc = 0;
++      int link_up = pm8358_link_ok(efx);
++      /* Simulate a PHY event if link state has changed */
++      if (link_up != efx->link_up) {
++              efx->link_up = link_up;
++              efx->mac_op->fake_phy_event(efx);
++      }
 +
++      return rc;
 +}
 +
-+static void setup_load_arg(xen_kexec_image_t *xki, struct kimage *image)
++static void pm8358_phy_reconfigure(struct efx_nic *efx)
 +{
-+      machine_kexec_setup_load_arg(xki, image);
++      int phy_id = efx->mii.phy_id;
++      int ctrl;
++      /* Handle DTE loopback */
++      ctrl = mdio_clause45_read(efx, phy_id, MDIO_MMD_DTEXS,
++                                MDIO_MMDREG_CTRL1);
++      if (efx->loopback_mode == LOOPBACK_PHY) {
++              EFX_TRACE(efx, "PM8358: setting DTE loopback\n");
++              ctrl |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
++      } else {
++              if (ctrl & (1 << MDIO_MMDREG_CTRL1_LBACK_LBN))
++                      EFX_TRACE(efx,
++                                "PM8358: clearing DTE loopback\n");
++              ctrl &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN);
++      }
++      mdio_clause45_write(efx, phy_id, MDIO_MMD_DTEXS,
++                          MDIO_MMDREG_CTRL1, ctrl);
++
++      efx->link_up = pm8358_link_ok(efx);
++      efx->link_options = GM_LPA_10000FULL;
++}
++
++struct efx_phy_operations falcon_pm8358_phy_ops = {
++      .init            = pm8358_phy_init,
++      .reconfigure     = pm8358_phy_reconfigure,
++      .check_hw        = pm8358_phy_check_hw,
++      .fini            = efx_port_dummy_op_void,
++      .clear_interrupt = efx_port_dummy_op_void,
++      .reset_xaui      = efx_port_dummy_op_void,
++      .mmds            = PM8358_REQUIRED_DEVS,
++      .loopbacks       = PM8358_LOOPBACKS,
++      .startup_loopback = LOOPBACK_PHY,
++};
+--- linux-2.6.18.8/drivers/net/sfc/rx.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/rx.c   2008-05-19 00:33:29.321836271 +0300
+@@ -0,0 +1,798 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      xki->indirection_page = image->head;
-+      xki->start_address = image->start;
-+}
++#include <linux/socket.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <net/ip.h>
++#include <net/checksum.h>
++#include "net_driver.h"
++#include "rx.h"
++#include "efx.h"
++#include "falcon.h"
++#include "selftest.h"
++#include "workarounds.h"
++
++
++/* Number of RX descriptors pushed at once. */
++#define EFX_RX_BATCH  8
++
++/* Size of buffer allocated for skb header area. */
++#define EFX_SKB_HEADERS  64u
 +
 +/*
-+ * Load the image into xen so xen can kdump itself
-+ * This might have been done in prepare, but prepare
-+ * is currently called too early. It might make sense
-+ * to move prepare, but for now, just add an extra hook.
++ * rx_alloc_method - RX buffer allocation method
++ *
++ * This driver supports two methods for allocating and using RX buffers:
++ * each RX buffer may be backed by an skb or by an order-n page.
++ *
++ * When LRO is in use then the second method has a lower overhead,
++ * since we don't have to allocate then free skbs on reassembled frames.
++ *
++ * Values:
++ *   - RX_ALLOC_METHOD_AUTO = 0
++ *   - RX_ALLOC_METHOD_SKB  = 1
++ *   - RX_ALLOC_METHOD_PAGE = 2
++ *
++ * The heuristic for %RX_ALLOC_METHOD_AUTO is a simple hysteresis count
++ * controlled by the parameters below.
++ *
++ *   - Since pushing and popping descriptors are separated by the rx_queue
++ *     size, so the watermarks should be ~rxd_size.
++ *   - The performance win by using page-based allocation for LRO is less
++ *     than the performance hit of using page-based allocation of non-LRO,
++ *     so the watermarks should reflect this.
++ *
++ * Per channel we maintain a single variable, updated by each channel:
++ *
++ *   rx_alloc_level += (lro_performed ? RX_ALLOC_FACTOR_LRO :
++ *                      RX_ALLOC_FACTOR_SKB)
++ * Per NAPI poll interval, we constrain rx_alloc_level to 0..MAX (which
++ * limits the hysteresis), and update the allocation strategy:
++ *
++ *   rx_alloc_method = (rx_alloc_level > RX_ALLOC_LEVEL_LRO ?
++ *                      RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB)
 + */
-+int xen_machine_kexec_load(struct kimage *image)
-+{
-+      xen_kexec_load_t xkl;
++static int rx_alloc_method = RX_ALLOC_METHOD_PAGE;
 +
-+      memset(&xkl, 0, sizeof(xkl));
-+      xkl.type = image->type;
-+      setup_load_arg(&xkl.image, image);
-+      return HYPERVISOR_kexec_op(KEXEC_CMD_kexec_load, &xkl);
-+}
++#define RX_ALLOC_LEVEL_LRO 0x2000
++#define RX_ALLOC_LEVEL_MAX 0x3000
++#define RX_ALLOC_FACTOR_LRO 1
++#define RX_ALLOC_FACTOR_SKB -2
 +
-+/*
-+ * Unload the image that was stored by machine_kexec_load()
-+ * This might have been done in machine_kexec_cleanup() but it
-+ * is called too late, and its possible xen could try and kdump
-+ * using resources that have been freed.
++/* This is the percentage fill level below which new RX descriptors
++ * will be added to the RX descriptor ring.
 + */
-+void xen_machine_kexec_unload(struct kimage *image)
-+{
-+      xen_kexec_load_t xkl;
++static unsigned int rx_refill_threshold = 90;
 +
-+      memset(&xkl, 0, sizeof(xkl));
-+      xkl.type = image->type;
-+      HYPERVISOR_kexec_op(KEXEC_CMD_kexec_unload, &xkl);
-+}
++/* This is the percentage fill level to which an RX queue will be refilled
++ * when the "RX refill threshold" is reached.
++ */
++static unsigned int rx_refill_limit = 95;
 +
 +/*
-+ * Do not allocate memory (or fail in any way) in machine_kexec().
-+ * We are past the point of no return, committed to rebooting now.
++ * RX maximum head room required.
 + *
-+ * This has the hypervisor move to the prefered reboot CPU, 
-+ * stop all CPUs and kexec. That is it combines machine_shutdown()
-+ * and machine_kexec() in Linux kexec terms.
++ * This must be at least 1 to prevent overflow and at least 2 to allow
++ * pipelined receives.
 + */
-+NORET_TYPE void machine_kexec(struct kimage *image)
++#define EFX_RXD_HEAD_ROOM 2
++
++/* Macros for zero-order pages (potentially) containing multiple RX buffers */
++#define RX_DATA_OFFSET(_data)                         \
++      (((unsigned long) (_data)) & (PAGE_SIZE-1))
++#define RX_BUF_OFFSET(_rx_buf)                                \
++      RX_DATA_OFFSET((_rx_buf)->data)
++
++#define RX_PAGE_SIZE(_efx)                            \
++      (PAGE_SIZE * (1u << (_efx)->rx_buffer_order))
++
++
++/**
++ * efx_init_rx_buffer_skb - create new RX buffer using skb-based allocation
++ *
++ * @rx_queue:         Efx RX queue
++ * @rx_buf:           RX buffer structure to populate
++ *
++ * This allocates memory for a new receive buffer, maps it for DMA,
++ * and populates a struct efx_rx_buffer with the relevant
++ * information.  Return a negative error code or 0 on success.
++ */
++static inline int efx_init_rx_buffer_skb(struct efx_rx_queue *rx_queue,
++                                       struct efx_rx_buffer *rx_buf)
 +{
-+      xen_kexec_exec_t xke;
++      struct efx_nic *efx = rx_queue->efx;
++      struct net_device *net_dev = efx->net_dev;
++      int skb_len = efx->rx_buffer_len;
 +
-+      memset(&xke, 0, sizeof(xke));
-+      xke.type = image->type;
-+      HYPERVISOR_kexec_op(KEXEC_CMD_kexec, &xke);
-+      panic("KEXEC_CMD_kexec hypercall should not return\n");
++      rx_buf->skb = netdev_alloc_skb(net_dev, skb_len);
++      if (unlikely(!rx_buf->skb))
++              return -ENOMEM;
++
++      /* Adjust the SKB for padding and checksum */
++      skb_reserve(rx_buf->skb, NET_IP_ALIGN);
++      rx_buf->len = skb_len - NET_IP_ALIGN;
++      rx_buf->data = (char *)rx_buf->skb->data;
++
++      rx_buf->skb->ip_summed = CHECKSUM_UNNECESSARY;
++
++      /* Map for DMA */
++      rx_buf->dma_addr = pci_map_single(efx->pci_dev,
++                                        rx_buf->data, rx_buf->len,
++                                        PCI_DMA_FROMDEVICE);
++
++      if (unlikely(pci_dma_mapping_error(rx_buf->dma_addr))) {
++              /* Free the SKB */
++              dev_kfree_skb_any(rx_buf->skb);
++              rx_buf->skb = NULL;
++              return -EIO;
++      }
++
++      return 0;
 +}
 +
-+void machine_shutdown(void)
++/**
++ * efx_init_rx_buffer_page - create new RX buffer using page-based allocation
++ *
++ * @rx_queue:         Efx RX queue
++ * @rx_buf:           RX buffer structure to populate
++ *
++ * This allocates memory for a new receive buffer, maps it for DMA,
++ * and populates a struct efx_rx_buffer with the relevant
++ * information.  Return a negative error code or 0 on success.
++ */
++static inline int efx_init_rx_buffer_page(struct efx_rx_queue *rx_queue,
++                                        struct efx_rx_buffer *rx_buf)
 +{
-+      /* do nothing */
-+}
++      struct efx_nic *efx = rx_queue->efx;
++      int bytes, space, offset;
 +
++      bytes = efx->rx_buffer_len - EFX_PAGE_IP_ALIGN;
 +
-+/*
-+ * Local variables:
-+ *  c-file-style: "linux"
-+ *  indent-tabs-mode: t
-+ *  c-indent-level: 8
-+ *  c-basic-offset: 8
-+ *  tab-width: 8
-+ * End:
-+ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/machine_reboot.c linux-2.6.18-xen.hg/drivers/xen/core/machine_reboot.c
---- linux-2.6.18/drivers/xen/core/machine_reboot.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/machine_reboot.c      2007-12-23 11:15:33.664581791 +0100
-@@ -0,0 +1,240 @@
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/mm.h>
-+#include <linux/unistd.h>
-+#include <linux/module.h>
-+#include <linux/reboot.h>
-+#include <linux/sysrq.h>
-+#include <linux/stringify.h>
-+#include <linux/stop_machine.h>
-+#include <asm/irq.h>
-+#include <asm/mmu_context.h>
-+#include <xen/evtchn.h>
-+#include <asm/hypervisor.h>
-+#include <xen/xenbus.h>
-+#include <linux/cpu.h>
-+#include <xen/gnttab.h>
-+#include <xen/xencons.h>
-+#include <xen/cpu_hotplug.h>
-+#include <xen/interface/vcpu.h>
++      /* If there is space left in the previously allocated page,
++       * then use it. Otherwise allocate a new one */
++      rx_buf->page = rx_queue->buf_page;
++      if (rx_buf->page == NULL) {
++              dma_addr_t dma_addr;
 +
-+#if defined(__i386__) || defined(__x86_64__)
++              rx_buf->page = alloc_pages(__GFP_COLD | __GFP_COMP | GFP_ATOMIC,
++                                         efx->rx_buffer_order);
++              if (unlikely(rx_buf->page == NULL))
++                      return -ENOMEM;
 +
-+/*
-+ * Power off function, if any
-+ */
-+void (*pm_power_off)(void);
-+EXPORT_SYMBOL(pm_power_off);
++              /* Map the entire page for DMA */
++              dma_addr = pci_map_page(efx->pci_dev, rx_buf->page,
++                                      0, RX_PAGE_SIZE(efx),
++                                      PCI_DMA_FROMDEVICE);
 +
-+void machine_emergency_restart(void)
-+{
-+      /* We really want to get pending console data out before we die. */
-+      xencons_force_flush();
-+      HYPERVISOR_shutdown(SHUTDOWN_reboot);
++              if (unlikely(pci_dma_mapping_error(dma_addr))) {
++                      __free_pages(rx_buf->page, efx->rx_buffer_order);
++                      rx_buf->page = NULL;
++                      return -EIO;
++              }
++
++              rx_queue->buf_page = rx_buf->page;
++              rx_queue->buf_dma_addr = dma_addr;
++              rx_queue->buf_data = ((char *) page_address(rx_buf->page) +
++                                    EFX_PAGE_IP_ALIGN);
++      }
++
++      offset = RX_DATA_OFFSET(rx_queue->buf_data);
++      rx_buf->len = bytes;
++      rx_buf->dma_addr = rx_queue->buf_dma_addr + offset;
++      rx_buf->data = rx_queue->buf_data;
++
++      /* Try to pack multiple buffers per page */
++      if (efx->rx_buffer_order == 0) {
++              /* The next buffer starts on the next 512 byte boundary */
++              rx_queue->buf_data += ((bytes + 0x1ff) & ~0x1ff);
++              offset += ((bytes + 0x1ff) & ~0x1ff);
++
++              space = RX_PAGE_SIZE(efx) - offset;
++              if (space >= bytes) {
++                      /* Refs dropped on kernel releasing each skb */
++                      get_page(rx_queue->buf_page);
++                      goto out;
++              }
++      }
++
++      /* This is the final RX buffer for this page, so mark it for
++       * unmapping */
++      rx_queue->buf_page = NULL;
++      rx_buf->unmap_addr = rx_queue->buf_dma_addr;
++
++ out:
++      return 0;
 +}
 +
-+void machine_restart(char * __unused)
++/* This allocates memory for a new receive buffer, maps it for DMA,
++ * and populates a struct efx_rx_buffer with the relevant
++ * information.
++ */
++static inline int efx_init_rx_buffer(struct efx_rx_queue *rx_queue,
++                                   struct efx_rx_buffer *new_rx_buf)
 +{
-+      machine_emergency_restart();
++      int rc = 0;
++
++      if (rx_queue->channel->rx_alloc_push_pages) {
++              new_rx_buf->skb = NULL;
++              rc = efx_init_rx_buffer_page(rx_queue, new_rx_buf);
++              rx_queue->alloc_page_count++;
++      } else {
++              new_rx_buf->page = NULL;
++              rc = efx_init_rx_buffer_skb(rx_queue, new_rx_buf);
++              rx_queue->alloc_skb_count++;
++      }
++
++      if (unlikely(rc < 0))
++              EFX_LOG_RL(rx_queue->efx, "%s RXQ[%d] =%d\n", __func__,
++                         rx_queue->queue, rc);
++      return rc;
 +}
 +
-+void machine_halt(void)
++static inline void efx_unmap_rx_buffer(struct efx_nic *efx,
++                                     struct efx_rx_buffer *rx_buf)
 +{
-+      machine_power_off();
++      if (rx_buf->page) {
++              EFX_BUG_ON_PARANOID(rx_buf->skb);
++              if (rx_buf->unmap_addr) {
++                      pci_unmap_page(efx->pci_dev, rx_buf->unmap_addr,
++                                     RX_PAGE_SIZE(efx), PCI_DMA_FROMDEVICE);
++                      rx_buf->unmap_addr = 0;
++              }
++      } else if (likely(rx_buf->skb)) {
++              pci_unmap_single(efx->pci_dev, rx_buf->dma_addr,
++                               rx_buf->len, PCI_DMA_FROMDEVICE);
++      }
 +}
 +
-+void machine_power_off(void)
++static inline void efx_free_rx_buffer(struct efx_nic *efx,
++                                    struct efx_rx_buffer *rx_buf)
 +{
-+      /* We really want to get pending console data out before we die. */
-+      xencons_force_flush();
-+      if (pm_power_off)
-+              pm_power_off();
-+      HYPERVISOR_shutdown(SHUTDOWN_poweroff);
++      if (rx_buf->page) {
++              __free_pages(rx_buf->page, efx->rx_buffer_order);
++              rx_buf->page = NULL;
++      } else if (likely(rx_buf->skb)) {
++              dev_kfree_skb_any(rx_buf->skb);
++              rx_buf->skb = NULL;
++      }
 +}
 +
-+int reboot_thru_bios = 0;     /* for dmi_scan.c */
-+EXPORT_SYMBOL(machine_restart);
-+EXPORT_SYMBOL(machine_halt);
-+EXPORT_SYMBOL(machine_power_off);
-+
-+static void pre_suspend(void)
++inline void efx_fini_rx_buffer(struct efx_rx_queue *rx_queue,
++                             struct efx_rx_buffer *rx_buf)
 +{
-+      HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
-+      HYPERVISOR_update_va_mapping(fix_to_virt(FIX_SHARED_INFO),
-+                                   __pte_ma(0), 0);
++      /* Unmap for DMA */
++      efx_unmap_rx_buffer(rx_queue->efx, rx_buf);
 +
-+      xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
-+      xen_start_info->console.domU.mfn =
-+              mfn_to_pfn(xen_start_info->console.domU.mfn);
++      /* Free the skb/page */
++      efx_free_rx_buffer(rx_queue->efx, rx_buf);
 +}
 +
-+static void post_suspend(int suspend_cancelled)
-+{
-+      int i, j, k, fpp;
-+      unsigned long shinfo_mfn;
-+      extern unsigned long max_pfn;
-+      extern unsigned long *pfn_to_mfn_frame_list_list;
-+      extern unsigned long *pfn_to_mfn_frame_list[];
++/**
++ * efx_fast_push_rx_descriptors - push new RX descriptors quickly
++ * @rx_queue:         RX descriptor queue
++ * @retry:              Recheck the fill level
++ * This will aim to fill the RX descriptor queue up to
++ * @rx_queue->@fast_fill_limit. If there is insufficient atomic
++ * memory to do so, the caller should retry.
++ */
++static int __efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue,
++                                        int retry)
++{
++      struct efx_rx_buffer *rx_buf;
++      unsigned fill_level, index;
++      int i, space, rc = 0;
++
++      /* Calculate current fill level.  Do this outside the lock,
++       * because most of the time we'll end up not wanting to do the
++       * fill anyway.
++       */
++      fill_level = (rx_queue->added_count - rx_queue->removed_count);
++      EFX_BUG_ON_PARANOID(fill_level >
++                          rx_queue->efx->type->rxd_ring_mask + 1);
++
++      /* Don't fill if we don't need to */
++      if (fill_level >= rx_queue->fast_fill_trigger)
++              return 0;
 +
-+      if (suspend_cancelled) {
-+              xen_start_info->store_mfn =
-+                      pfn_to_mfn(xen_start_info->store_mfn);
-+              xen_start_info->console.domU.mfn =
-+                      pfn_to_mfn(xen_start_info->console.domU.mfn);
-+      } else {
-+#ifdef CONFIG_SMP
-+              cpu_initialized_map = cpu_online_map;
-+#endif
-+      }
++      /* Record minimum fill level */
++      if (unlikely(fill_level < rx_queue->min_fill))
++              if (fill_level)
++                      rx_queue->min_fill = fill_level;
 +
-+      shinfo_mfn = xen_start_info->shared_info >> PAGE_SHIFT;
-+      HYPERVISOR_update_va_mapping(fix_to_virt(FIX_SHARED_INFO),
-+                                   pfn_pte_ma(shinfo_mfn, PAGE_KERNEL), 0);
-+      HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
++      /* Acquire RX add lock.  If this lock is contended, then a fast
++       * fill must already be in progress (e.g. in the refill
++       * tasklet), so we don't need to do anything
++       */
++      if (!spin_trylock_bh(&rx_queue->add_lock))
++              return -1;
 +
-+      memset(empty_zero_page, 0, PAGE_SIZE);
++ retry:
++      /* Recalculate current fill level now that we have the lock */
++      fill_level = (rx_queue->added_count - rx_queue->removed_count);
++      EFX_BUG_ON_PARANOID(fill_level >
++                          rx_queue->efx->type->rxd_ring_mask + 1);
++      space = rx_queue->fast_fill_limit - fill_level;
++      if (space < EFX_RX_BATCH)
++              goto out_unlock;
 +
-+      fpp = PAGE_SIZE/sizeof(unsigned long);
-+      for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
-+              if ((j % fpp) == 0) {
-+                      k++;
-+                      pfn_to_mfn_frame_list_list[k] =
-+                              virt_to_mfn(pfn_to_mfn_frame_list[k]);
-+                      j = 0;
++      EFX_TRACE(rx_queue->efx, "RX queue %d fast-filling descriptor ring from"
++                " level %d to level %d using %s allocation\n",
++                rx_queue->queue, fill_level, rx_queue->fast_fill_limit,
++                rx_queue->channel->rx_alloc_push_pages ? "page" : "skb");
++
++      do {
++              for (i = 0; i < EFX_RX_BATCH; ++i) {
++                      index = (rx_queue->added_count &
++                               rx_queue->efx->type->rxd_ring_mask);
++                      rx_buf = efx_rx_buffer(rx_queue, index);
++                      rc = efx_init_rx_buffer(rx_queue, rx_buf);
++                      if (unlikely(rc))
++                              goto out;
++                      ++rx_queue->added_count;
 +              }
-+              pfn_to_mfn_frame_list[k][j] =
-+                      virt_to_mfn(&phys_to_machine_mapping[i]);
-+      }
-+      HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
-+      HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
-+              virt_to_mfn(pfn_to_mfn_frame_list_list);
-+}
++      } while ((space -= EFX_RX_BATCH) >= EFX_RX_BATCH);
 +
-+#else /* !(defined(__i386__) || defined(__x86_64__)) */
++      EFX_TRACE(rx_queue->efx, "RX queue %d fast-filled descriptor ring "
++                "to level %d\n", rx_queue->queue,
++                rx_queue->added_count - rx_queue->removed_count);
 +
-+#ifndef HAVE_XEN_PRE_SUSPEND
-+#define xen_pre_suspend()     ((void)0)
-+#endif
++ out:
++      /* Send write pointer to card.  */
++      falcon_notify_rx_desc(rx_queue);
 +
-+#ifndef HAVE_XEN_POST_SUSPEND
-+#define xen_post_suspend(x)   ((void)0)
-+#endif
++      /* If the fast fill is running inside from the refill tasklet, then
++       * for SMP systems it may be running on a different CPU to
++       * RX event processing, which means that the fill level may now be
++       * out of date. */
++      if (unlikely(retry && (rc == 0)))
++              goto retry;
 +
-+#define switch_idle_mm()      ((void)0)
-+#define mm_pin_all()          ((void)0)
-+#define pre_suspend()         xen_pre_suspend()
-+#define post_suspend(x)               xen_post_suspend(x)
++ out_unlock:
++      /* Release RX add lock */
++      spin_unlock_bh(&rx_queue->add_lock);
 +
-+#endif
++      return rc;
++}
 +
-+static int take_machine_down(void *p_fast_suspend)
++/**
++ * efx_fast_push_rx_descriptors - push new RX descriptors quickly
++ * @rx_queue:         RX descriptor queue
++ *
++ * This will aim to fill the RX descriptor queue up to
++ * @rx_queue->@fast_fill_limit.  If there is insufficient memory to do so,
++ * it will schedule a work item to immediately continue the fast fill
++ */
++void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue)
 +{
-+      int fast_suspend = *(int *)p_fast_suspend;
-+      int suspend_cancelled, err;
-+      extern void time_resume(void);
++      int rc;
 +
-+      if (fast_suspend) {
-+              BUG_ON(!irqs_disabled());
-+      } else {
-+              BUG_ON(irqs_disabled());
++      rc = __efx_fast_push_rx_descriptors(rx_queue, 0);
++      if (unlikely(rc)) {
++              /* Schedule the work item to run immediately. The hope is
++               * that work is immediately pending to free some memory
++               * (e.g. an RX event or TX completion)
++               */
++              queue_delayed_work(rx_queue->efx->refill_workqueue,
++                                 &rx_queue->work, 0);
++      }
++}
 +
-+              for (;;) {
-+                      err = smp_suspend();
-+                      if (err)
-+                              return err;
++void efx_rx_work(struct work_struct *data)
++{
++      struct efx_rx_queue *rx_queue;
++      int rc;
 +
-+                      xenbus_suspend();
-+                      preempt_disable();
++#if !defined(EFX_NEED_WORK_API_WRAPPERS)
++      rx_queue = container_of(data, struct efx_rx_queue, work.work);
++#else
++      rx_queue = container_of(data, struct efx_rx_queue, work);
++#endif
 +
-+                      if (num_online_cpus() == 1)
-+                              break;
++      if (unlikely(!rx_queue->channel->enabled))
++              return;
 +
-+                      preempt_enable();
-+                      xenbus_suspend_cancel();
-+              }
++      EFX_TRACE(rx_queue->efx, "RX queue %d worker thread executing on CPU "
++                "%d\n", rx_queue->queue, raw_smp_processor_id());
 +
-+              local_irq_disable();
++      ++rx_queue->slow_fill_count;
++      /* Push new RX descriptors, allowing at least 1 jiffy for
++       * the kernel to free some more memory. */
++      rc = __efx_fast_push_rx_descriptors(rx_queue, 1);
++      if (rc) {
++              queue_delayed_work(rx_queue->efx->refill_workqueue,
++                                 &rx_queue->work, 1);
 +      }
++}
 +
-+      mm_pin_all();
-+      gnttab_suspend();
-+      pre_suspend();
++static inline void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
++                                          struct efx_rx_buffer *rx_buf,
++                                          int len, int *discard,
++                                          int *leak_packet)
++{
++      struct efx_nic *efx = rx_queue->efx;
++      unsigned max_len = rx_buf->len - efx->type->rx_buffer_padding;
 +
-+      /*
-+       * This hypercall returns 1 if suspend was cancelled or the domain was
-+       * merely checkpointed, and 0 if it is resuming in a new domain.
++      if (likely(len <= max_len))
++              return;
++
++      /* The packet must be discarded, but this is only a fatal error
++       * if the caller indicated it was
 +       */
-+      suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
++      *discard = 1;
 +
-+      post_suspend(suspend_cancelled);
-+      gnttab_resume();
-+      if (!suspend_cancelled) {
-+              irq_resume();
-+#ifdef __x86_64__
-+              /*
-+               * Older versions of Xen do not save/restore the user %cr3.
-+               * We do it here just in case, but there's no need if we are
-+               * in fast-suspend mode as that implies a new enough Xen.
++      if ((len > rx_buf->len) && EFX_WORKAROUND_8071(efx)) {
++              EFX_ERR_RL(efx, " RX queue %d seriously overlength "
++                         "RX event (0x%x > 0x%x+0x%x). Leaking\n",
++                         rx_queue->queue, len, max_len,
++                         efx->type->rx_buffer_padding);
++              /* If this buffer was skb-allocated, then the meta
++               * data at the end of the skb will be trashed. So
++               * we have no choice but to leak the fragment.
 +               */
-+              if (!fast_suspend) {
-+                      struct mmuext_op op;
-+                      op.cmd = MMUEXT_NEW_USER_BASEPTR;
-+                      op.arg1.mfn = pfn_to_mfn(__pa(__user_pgd(
-+                              current->active_mm->pgd)) >> PAGE_SHIFT);
-+                      if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
-+                              BUG();
-+              }
-+#endif
++              *leak_packet = (rx_buf->skb != NULL);
++              efx_schedule_reset(efx, RESET_TYPE_RX_RECOVERY);
++      } else {
++              EFX_ERR_RL(efx, " RX queue %d overlength RX event "
++                         "(0x%x > 0x%x)\n", rx_queue->queue, len, max_len);
 +      }
-+      time_resume();
-+
-+      if (!fast_suspend)
-+              local_irq_enable();
 +
-+      return suspend_cancelled;
++      rx_queue->channel->n_rx_overlength++;
 +}
 +
-+int __xen_suspend(int fast_suspend)
++/* Allocate and construct an SKB around a struct page.*/
++static inline struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
++                                          struct efx_nic *efx,
++                                          int hdr_len)
 +{
-+      int err, suspend_cancelled;
-+
-+      BUG_ON(smp_processor_id() != 0);
-+      BUG_ON(in_interrupt());
++      struct sk_buff *skb;
 +
-+#if defined(__i386__) || defined(__x86_64__)
-+      if (xen_feature(XENFEAT_auto_translated_physmap)) {
-+              printk(KERN_WARNING "Cannot suspend in "
-+                     "auto_translated_physmap mode.\n");
-+              return -EOPNOTSUPP;
++      /* Allocate an SKB to store the headers */
++      skb = netdev_alloc_skb(efx->net_dev, hdr_len + EFX_PAGE_SKB_ALIGN);
++      if (unlikely(skb == NULL)) {
++              EFX_ERR_RL(efx, "RX out of memory for skb\n");
++              return NULL;
 +      }
-+#endif
 +
-+      /* If we are definitely UP then 'slow mode' is actually faster. */
-+      if (num_possible_cpus() == 1)
-+              fast_suspend = 0;
++      EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags);
++      EFX_BUG_ON_PARANOID(rx_buf->len < hdr_len);
 +
-+      if (fast_suspend) {
-+              xenbus_suspend();
-+              err = stop_machine_run(take_machine_down, &fast_suspend, 0);
-+              if (err < 0)
-+                      xenbus_suspend_cancel();
-+      } else {
-+              err = take_machine_down(&fast_suspend);
-+      }
++      skb->ip_summed = CHECKSUM_UNNECESSARY;
++      skb_reserve(skb, EFX_PAGE_SKB_ALIGN);
 +
-+      if (err < 0)
-+              return err;
++      skb->len = rx_buf->len;
++      skb->truesize = rx_buf->len + sizeof(struct sk_buff);
++      memcpy(skb->data, rx_buf->data, hdr_len);
++      skb->tail += hdr_len;
 +
-+      suspend_cancelled = err;
-+      if (!suspend_cancelled) {
-+              xencons_resume();
-+              xenbus_resume();
++      /* Append the remaining page onto the frag list */
++      if (unlikely(rx_buf->len > hdr_len)) {
++              struct skb_frag_struct *frag = skb_shinfo(skb)->frags;
++              frag->page = rx_buf->page;
++              frag->page_offset = RX_BUF_OFFSET(rx_buf) + hdr_len;
++              frag->size = skb->len - hdr_len;
++              skb_shinfo(skb)->nr_frags = 1;
++              skb->data_len = frag->size;
 +      } else {
-+              xenbus_suspend_cancel();
++              __free_pages(rx_buf->page, efx->rx_buffer_order);
++              skb->data_len = 0;
 +      }
 +
-+      if (!fast_suspend)
-+              smp_resume();
++      /* Ownership has transferred from the rx_buf to skb */
++      rx_buf->page = NULL;
 +
-+      return 0;
++      /* Move past the ethernet header */
++      skb->protocol = eth_type_trans(skb, efx->net_dev);
++
++      return skb;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/Makefile linux-2.6.18-xen.hg/drivers/xen/core/Makefile
---- linux-2.6.18/drivers/xen/core/Makefile     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/Makefile      2007-12-23 11:15:33.551242507 +0100
-@@ -0,0 +1,13 @@
-+#
-+# Makefile for the linux kernel.
-+#
 +
-+obj-y := evtchn.o gnttab.o features.o reboot.o machine_reboot.o firmware.o
++#if defined(EFX_USE_FASTCALL)
++void fastcall efx_rx_packet(struct efx_rx_queue *rx_queue,
++                          unsigned int index, unsigned int len,
++                          int checksummed, int discard)
++#else
++void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
++                 unsigned int len, int checksummed, int discard)
++#endif
++{
++      struct efx_nic *efx = rx_queue->efx;
++      struct efx_rx_buffer *rx_buf;
++      int leak_packet = 0;
 +
-+obj-$(CONFIG_PROC_FS)         += xen_proc.o
-+obj-$(CONFIG_SYS_HYPERVISOR)  += hypervisor_sysfs.o
-+obj-$(CONFIG_HOTPLUG_CPU)     += cpu_hotplug.o
-+obj-$(CONFIG_XEN_SYSFS)               += xen_sysfs.o
-+obj-$(CONFIG_XEN_SMPBOOT)     += smpboot.o
-+obj-$(CONFIG_KEXEC)           += machine_kexec.o
-+obj-$(CONFIG_XEN_XENCOMM)     += xencomm.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/reboot.c linux-2.6.18-xen.hg/drivers/xen/core/reboot.c
---- linux-2.6.18/drivers/xen/core/reboot.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/reboot.c      2007-12-23 11:15:33.664581791 +0100
-@@ -0,0 +1,246 @@
-+#define __KERNEL_SYSCALLS__
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/unistd.h>
-+#include <linux/module.h>
-+#include <linux/reboot.h>
-+#include <linux/sysrq.h>
-+#include <asm/hypervisor.h>
-+#include <xen/xenbus.h>
-+#include <linux/kmod.h>
-+#include <linux/slab.h>
-+#include <linux/workqueue.h>
++      rx_buf = efx_rx_buffer(rx_queue, index);
++      EFX_BUG_ON_PARANOID(!rx_buf->data);
++      EFX_BUG_ON_PARANOID(rx_buf->skb && rx_buf->page);
++      EFX_BUG_ON_PARANOID(!(rx_buf->skb || rx_buf->page));
 +
-+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
-+#include <xen/platform-compat.h>
-+#endif
++      /* This allows the refill path to post another buffer.
++       * EFX_RXD_HEAD_ROOM ensures that the slot we are using
++       * isn't overwritten yet.
++       */
++      rx_queue->removed_count++;
 +
-+MODULE_LICENSE("Dual BSD/GPL");
++      /* Validate the length encoded in the event vs the descriptor pushed */
++      efx_rx_packet__check_len(rx_queue, rx_buf, len,
++                               &discard, &leak_packet);
 +
-+#define SHUTDOWN_INVALID  -1
-+#define SHUTDOWN_POWEROFF  0
-+#define SHUTDOWN_SUSPEND   2
-+/* Code 3 is SHUTDOWN_CRASH, which we don't use because the domain can only
-+ * report a crash, not be instructed to crash!
-+ * HALT is the same as POWEROFF, as far as we're concerned.  The tools use
-+ * the distinction when we return the reason code to them.
-+ */
-+#define SHUTDOWN_HALT      4
++      EFX_TRACE(efx, "RX queue %d received id %x at %llx+%x %s%s\n",
++                rx_queue->queue, index,
++                (unsigned long long)rx_buf->dma_addr, len,
++                (checksummed ? " [SUMMED]" : ""),
++                (discard ? " [DISCARD]" : ""));
 +
-+/* Ignore multiple shutdown requests. */
-+static int shutting_down = SHUTDOWN_INVALID;
++      /* Discard packet, if instructed to do so */
++      if (unlikely(discard)) {
++              if (unlikely(leak_packet))
++                      rx_queue->channel->n_skbuff_leaks++;
++              else
++                      /* We haven't called efx_unmap_rx_buffer yet,
++                       * so fini the entire rx_buffer here */
++                      efx_fini_rx_buffer(rx_queue, rx_buf);
++              return;
++      }
 +
-+/* Can we leave APs online when we suspend? */
-+static int fast_suspend;
++      /* Release card resources - assumes all RX buffers consumed in-order
++       * per RX queue
++       */
++      efx_unmap_rx_buffer(efx, rx_buf);
 +
-+static void __shutdown_handler(void *unused);
-+static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
++      /* Prefetch nice and early so data will (hopefully) be in cache by
++       * the time we look at it.
++       */
++      prefetch(rx_buf->data);
 +
-+int __xen_suspend(int fast_suspend);
++      /* Pipeline receives so that we give time for packet headers to be
++       * prefetched into cache.
++       */
++      rx_buf->len = len;
++      if (rx_queue->channel->rx_pkt)
++              __efx_rx_packet(rx_queue->channel,
++                              rx_queue->channel->rx_pkt,
++                              rx_queue->channel->rx_pkt_csummed);
++      rx_queue->channel->rx_pkt = rx_buf;
++      rx_queue->channel->rx_pkt_csummed = checksummed;
++}
 +
-+static int shutdown_process(void *__unused)
++/* Handle a received packet.  Second half: Touches packet payload. */
++void __efx_rx_packet(struct efx_channel *channel,
++                   struct efx_rx_buffer *rx_buf, int checksummed)
 +{
-+      static char *envp[] = { "HOME=/", "TERM=linux",
-+                              "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
-+      static char *poweroff_argv[] = { "/sbin/poweroff", NULL };
++      struct efx_nic *efx = channel->efx;
++      enum efx_veto veto;
++      struct sk_buff *skb;
 +
-+      extern asmlinkage long sys_reboot(int magic1, int magic2,
-+                                        unsigned int cmd, void *arg);
++      /* If we're in loopback test, then pass the packet directly to the
++       * loopback layer, and free the rx_buf here
++       */
++      if (unlikely(efx->loopback_selftest)) {
++              efx_loopback_rx_packet(efx, rx_buf->data, rx_buf->len);
++              efx_free_rx_buffer(efx, rx_buf);
++              goto done;
++      }
 +
-+      if ((shutting_down == SHUTDOWN_POWEROFF) ||
-+          (shutting_down == SHUTDOWN_HALT)) {
-+              if (call_usermodehelper("/sbin/poweroff", poweroff_argv,
-+                                      envp, 0) < 0) {
-+#ifdef CONFIG_XEN
-+                      sys_reboot(LINUX_REBOOT_MAGIC1,
-+                                 LINUX_REBOOT_MAGIC2,
-+                                 LINUX_REBOOT_CMD_POWER_OFF,
-+                                 NULL);
-+#endif /* CONFIG_XEN */
-+              }
-+      }
++      if (rx_buf->skb) {
++              /* Prefetch more information */
++              prefetch(skb_shinfo(rx_buf->skb));
 +
-+      shutting_down = SHUTDOWN_INVALID; /* could try again */
++              /* Reserve space for the data */
++              skb_put(rx_buf->skb, rx_buf->len);
 +
-+      return 0;
-+}
++              /* Move past the ethernet header. rx_buf->data still points
++               * at the ethernet header */
++              rx_buf->skb->protocol = eth_type_trans(rx_buf->skb,
++                                                     efx->net_dev);
++      }
 +
-+static int xen_suspend(void *__unused)
-+{
-+      int err;
++      /* Both our generic-LRO and SFC-SSR support skb and page based
++       * allocation, but neither support switching from one to the
++       * other on the fly. If we spot that the allocation mode has
++       * changed, then flush the LRO state.
++       */
++      if (unlikely(channel->rx_alloc_pop_pages != (rx_buf->page != NULL))) {
++              channel->rx_alloc_pop_pages = (rx_buf->page != NULL);
++      }
 +
-+      daemonize("suspend");
-+      err = set_cpus_allowed(current, cpumask_of_cpu(0));
-+      if (err) {
-+              printk(KERN_ERR "Xen suspend can't run on CPU0 (%d)\n", err);
-+              goto out;
++      /* Allow callback to veto the packet */
++      veto = EFX_DL_CALLBACK(efx, rx_packet, rx_buf->data, rx_buf->len);
++      if (unlikely(veto)) {
++              EFX_LOG(efx, "RX vetoed by driverlink %s driver\n",
++                      efx->dl_cb_dev.rx_packet->driver->name);
++              /* Free the buffer now */
++              efx_free_rx_buffer(efx, rx_buf);
++              goto done;
 +      }
 +
-+      err = __xen_suspend(fast_suspend);
-+      if (err)
-+              printk(KERN_ERR "Xen suspend failed (%d)\n", err);
++      /* Form an skb if required */
++      if (rx_buf->page) {
++              int hdr_len = min(rx_buf->len, EFX_SKB_HEADERS);
++              skb = efx_rx_mk_skb(rx_buf, efx, hdr_len);
++              if (unlikely(skb == NULL)) {
++                      efx_free_rx_buffer(efx, rx_buf);
++                      goto done;
++              }
++      } else {
++              /* We now own the SKB */
++              skb = rx_buf->skb;
++              rx_buf->skb = NULL;
++      }
 +
-+ out:
-+      shutting_down = SHUTDOWN_INVALID;
-+      return 0;
++      EFX_BUG_ON_PARANOID(rx_buf->page);
++      EFX_BUG_ON_PARANOID(rx_buf->skb);
++      EFX_BUG_ON_PARANOID(!skb);
++
++      /* Set the SKB flags */
++      if (unlikely(!checksummed || !efx->rx_checksum_enabled))
++              skb->ip_summed = CHECKSUM_NONE;
++
++      /* Pass the packet up */
++      netif_receive_skb(skb);
++
++      /* Update allocation strategy method */
++      channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
++
++      /* fall-thru */
++done:
++      /* Update statistics */
++      efx->net_dev->last_rx = jiffies;
 +}
 +
-+static void __shutdown_handler(void *unused)
++void efx_rx_strategy(struct efx_channel *channel)
 +{
-+      int err;
++      enum efx_rx_alloc_method method = rx_alloc_method;
 +
-+      err = kernel_thread((shutting_down == SHUTDOWN_SUSPEND) ?
-+                          xen_suspend : shutdown_process,
-+                          NULL, CLONE_FS | CLONE_FILES);
++      /* Only makes sense to use page based allocation if LRO is enabled */
++      if (!(channel->efx->net_dev->features & NETIF_F_LRO)) {
++              method = RX_ALLOC_METHOD_SKB;
++      } else if (method == RX_ALLOC_METHOD_AUTO) {
++              /* Constrain the rx_alloc_level */
++              if (channel->rx_alloc_level < 0)
++                      channel->rx_alloc_level = 0;
++              else if (channel->rx_alloc_level > RX_ALLOC_LEVEL_MAX)
++                      channel->rx_alloc_level = RX_ALLOC_LEVEL_MAX;
 +
-+      if (err < 0) {
-+              printk(KERN_WARNING "Error creating shutdown process (%d): "
-+                     "retrying...\n", -err);
-+              schedule_delayed_work(&shutdown_work, HZ/2);
++              /* Decide on the allocation method */
++              method = ((channel->rx_alloc_level > RX_ALLOC_LEVEL_LRO) ?
++                        RX_ALLOC_METHOD_PAGE : RX_ALLOC_METHOD_SKB);
 +      }
++
++      /* Push the option */
++      channel->rx_alloc_push_pages = (method == RX_ALLOC_METHOD_PAGE);
 +}
 +
-+static void shutdown_handler(struct xenbus_watch *watch,
-+                           const char **vec, unsigned int len)
++int efx_probe_rx_queue(struct efx_rx_queue *rx_queue)
 +{
-+      extern void ctrl_alt_del(void);
-+      char *str;
-+      struct xenbus_transaction xbt;
-+      int err;
-+
-+      if (shutting_down != SHUTDOWN_INVALID)
-+              return;
++      struct efx_nic *efx = rx_queue->efx;
++      unsigned int rxq_size;
++      int rc;
 +
-+ again:
-+      err = xenbus_transaction_start(&xbt);
-+      if (err)
-+              return;
++      EFX_LOG(efx, "creating RX queue %d\n", rx_queue->queue);
 +
-+      str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
-+      /* Ignore read errors and empty reads. */
-+      if (XENBUS_IS_ERR_READ(str)) {
-+              xenbus_transaction_end(xbt, 1);
-+              return;
++      /* Allocate RX buffers */
++      rxq_size = (efx->type->rxd_ring_mask + 1) * sizeof(*rx_queue->buffer);
++      rx_queue->buffer = kzalloc(rxq_size, GFP_KERNEL);
++      if (!rx_queue->buffer) {
++              rc = -ENOMEM;
++              goto fail1;
 +      }
 +
-+      xenbus_write(xbt, "control", "shutdown", "");
-+
-+      err = xenbus_transaction_end(xbt, 0);
-+      if (err == -EAGAIN) {
-+              kfree(str);
-+              goto again;
-+      }
++      rc = falcon_probe_rx(rx_queue);
++      if (rc)
++              goto fail2;
 +
-+      if (strcmp(str, "poweroff") == 0)
-+              shutting_down = SHUTDOWN_POWEROFF;
-+      else if (strcmp(str, "reboot") == 0)
-+              ctrl_alt_del();
-+      else if (strcmp(str, "suspend") == 0)
-+              shutting_down = SHUTDOWN_SUSPEND;
-+      else if (strcmp(str, "halt") == 0)
-+              shutting_down = SHUTDOWN_HALT;
-+      else {
-+              printk("Ignoring shutdown request: %s\n", str);
-+              shutting_down = SHUTDOWN_INVALID;
-+      }
++      return 0;
 +
-+      if (shutting_down != SHUTDOWN_INVALID)
-+              schedule_work(&shutdown_work);
++ fail2:
++      kfree(rx_queue->buffer);
++      rx_queue->buffer = NULL;
++ fail1:
++      /* Mark queue as unused */
++      rx_queue->used = 0;
 +
-+      kfree(str);
++      return rc;
 +}
 +
-+static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
-+                        unsigned int len)
++int efx_init_rx_queue(struct efx_rx_queue *rx_queue)
 +{
-+      char sysrq_key = '\0';
-+      struct xenbus_transaction xbt;
-+      int err;
++      struct efx_nic *efx = rx_queue->efx;
++      unsigned int max_fill, trigger, limit;
 +
-+ again:
-+      err = xenbus_transaction_start(&xbt);
-+      if (err)
-+              return;
-+      if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
-+              printk(KERN_ERR "Unable to read sysrq code in "
-+                     "control/sysrq\n");
-+              xenbus_transaction_end(xbt, 1);
-+              return;
-+      }
++      EFX_LOG(rx_queue->efx, "initialising RX queue %d\n", rx_queue->queue);
 +
-+      if (sysrq_key != '\0')
-+              xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
++      ASSERT_RTNL();
 +
-+      err = xenbus_transaction_end(xbt, 0);
-+      if (err == -EAGAIN)
-+              goto again;
++      /* Initialise ptr fields */
++      rx_queue->added_count = 0;
++      rx_queue->notified_count = 0;
++      rx_queue->removed_count = 0;
++      rx_queue->min_fill = -1U;
++      rx_queue->min_overfill = -1U;
 +
-+#ifdef CONFIG_MAGIC_SYSRQ
-+      if (sysrq_key != '\0')
-+              handle_sysrq(sysrq_key, NULL, NULL);
-+#endif
-+}
++      /* Initialise limit fields */
++      max_fill = efx->type->rxd_ring_mask + 1 - EFX_RXD_HEAD_ROOM;
++      trigger = max_fill * min(rx_refill_threshold, 100U) / 100U;
++      limit = max_fill * min(rx_refill_limit, 100U) / 100U;
 +
-+static struct xenbus_watch shutdown_watch = {
-+      .node = "control/shutdown",
-+      .callback = shutdown_handler
-+};
++      rx_queue->max_fill = max_fill;
++      rx_queue->fast_fill_trigger = trigger;
++      rx_queue->fast_fill_limit = limit;
 +
-+static struct xenbus_watch sysrq_watch = {
-+      .node = "control/sysrq",
-+      .callback = sysrq_handler
-+};
++      /* Set up RX descriptor ring */
++      return falcon_init_rx(rx_queue);
++}
 +
-+static int setup_shutdown_watcher(void)
++void efx_fini_rx_queue(struct efx_rx_queue *rx_queue)
 +{
-+      int err;
++      int i;
++      struct efx_rx_buffer *rx_buf;
 +
-+      xenbus_scanf(XBT_NIL, "control",
-+                   "platform-feature-multiprocessor-suspend",
-+                   "%d", &fast_suspend);
++      EFX_LOG(rx_queue->efx, "shutting down RX queue %d\n", rx_queue->queue);
 +
-+      err = register_xenbus_watch(&shutdown_watch);
-+      if (err) {
-+              printk(KERN_ERR "Failed to set shutdown watcher\n");
-+              return err;
-+      }
++      ASSERT_RTNL();
 +
-+      err = register_xenbus_watch(&sysrq_watch);
-+      if (err) {
-+              printk(KERN_ERR "Failed to set sysrq watcher\n");
-+              return err;
++      /* Flush RX queue and remove descriptor ring */
++      falcon_fini_rx(rx_queue);
++
++      /* Release RX buffers NB start at index 0 not current HW ptr */
++      if (rx_queue->buffer) {
++              for (i = 0; i <= rx_queue->efx->type->rxd_ring_mask; i++) {
++                      rx_buf = efx_rx_buffer(rx_queue, i);
++                      efx_fini_rx_buffer(rx_queue, rx_buf);
++              }
 +      }
 +
-+      return 0;
++      /* For a page that is part-way through splitting into RX buffers */
++      if (rx_queue->buf_page != NULL) {
++              pci_unmap_page(rx_queue->efx->pci_dev, rx_queue->buf_dma_addr,
++                             RX_PAGE_SIZE(rx_queue->efx), PCI_DMA_FROMDEVICE);
++              __free_pages(rx_queue->buf_page,
++                           rx_queue->efx->rx_buffer_order);
++              rx_queue->buf_page = NULL;
++      }
 +}
 +
-+#ifdef CONFIG_XEN
-+
-+static int shutdown_event(struct notifier_block *notifier,
-+                        unsigned long event,
-+                        void *data)
++void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
 +{
-+      setup_shutdown_watcher();
-+      return NOTIFY_DONE;
-+}
++      EFX_LOG(rx_queue->efx, "destroying RX queue %d\n", rx_queue->queue);
 +
-+static int __init setup_shutdown_event(void)
-+{
-+      static struct notifier_block xenstore_notifier = {
-+              .notifier_call = shutdown_event
-+      };
-+      register_xenstore_notifier(&xenstore_notifier);
++      falcon_remove_rx(rx_queue);
 +
-+      return 0;
++      kfree(rx_queue->buffer);
++      rx_queue->buffer = NULL;
++      rx_queue->used = 0;
 +}
 +
-+subsys_initcall(setup_shutdown_event);
 +
-+#else /* !defined(CONFIG_XEN) */
++module_param(rx_alloc_method, int, 0644);
++MODULE_PARM_DESC(rx_alloc_method, "Allocation method used for RX buffers");
 +
-+int xen_reboot_init(void)
-+{
-+      return setup_shutdown_watcher();
-+}
++module_param(rx_refill_threshold, uint, 0444);
++MODULE_PARM_DESC(rx_refill_threshold,
++               "RX descriptor ring fast/slow fill threshold (%)");
 +
-+#endif /* !defined(CONFIG_XEN) */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/smpboot.c linux-2.6.18-xen.hg/drivers/xen/core/smpboot.c
---- linux-2.6.18/drivers/xen/core/smpboot.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/smpboot.c     2007-12-23 11:15:33.674582320 +0100
-@@ -0,0 +1,435 @@
-+/*
-+ *    Xen SMP booting functions
+--- linux-2.6.18.8/drivers/net/sfc/rx.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/rx.h   2008-05-19 00:33:29.321836271 +0300
+@@ -0,0 +1,44 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
 + *
-+ *    See arch/i386/kernel/smpboot.c for copyright and credits for derived
-+ *    portions of this file.
++ * Copyright 2006:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef EFX_RX_H
++#define EFX_RX_H
++
++#include "net_driver.h"
++
++
++int efx_probe_rx_queue(struct efx_rx_queue *rx_queue);
++void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
++int efx_init_rx_queue(struct efx_rx_queue *rx_queue);
++void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);
++
++void efx_rx_strategy(struct efx_channel *channel);
++void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
++void efx_rx_work(struct work_struct *data);
++void __efx_rx_packet(struct efx_channel *channel,
++                   struct efx_rx_buffer *rx_buf, int checksummed);
++
++
++#endif /* EFX_RX_H */
+--- linux-2.6.18.8/drivers/net/sfc/selftest.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/selftest.c     2008-05-19 00:33:29.321836271 +0300
+@@ -0,0 +1,815 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
++#include <linux/netdevice.h>
 +#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/kernel.h>
-+#include <linux/mm.h>
-+#include <linux/sched.h>
++#include <linux/delay.h>
 +#include <linux/kernel_stat.h>
-+#include <linux/smp_lock.h>
-+#include <linux/irq.h>
-+#include <linux/bootmem.h>
-+#include <linux/notifier.h>
-+#include <linux/cpu.h>
-+#include <linux/percpu.h>
-+#include <asm/desc.h>
-+#include <asm/arch_hooks.h>
-+#include <asm/pgalloc.h>
-+#include <xen/evtchn.h>
-+#include <xen/interface/vcpu.h>
-+#include <xen/cpu_hotplug.h>
-+#include <xen/xenbus.h>
++#include <linux/pci.h>
++#include <linux/ethtool.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++#include <linux/udp.h>
++#include <linux/rtnetlink.h>
++#include <asm/io.h>
++#include "net_driver.h"
++#include "ethtool.h"
++#include "efx.h"
++#include "falcon.h"
++#include "selftest.h"
++#include "boards.h"
++#include "workarounds.h"
 +
-+extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *);
-+extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *);
++/* Self tests */
 +
-+extern int local_setup_timer(unsigned int cpu);
-+extern void local_teardown_timer(unsigned int cpu);
++/*
++ * Loopback test packet structure
++ *
++ * The self-test should stress every RSS vector, and unfortunately
++ * Falcon only performs RSS on TCP/UDP packets.
++ */
++struct efx_loopback_payload {
++      struct ethhdr header;
++      struct iphdr ip;
++      struct udphdr udp;
++      __be16 iteration;
++      const char msg[64];
++} __attribute__ ((packed));
 +
-+extern void hypervisor_callback(void);
-+extern void failsafe_callback(void);
-+extern void system_call(void);
-+extern void smp_trap_init(trap_info_t *);
++/* Loopback test source MAC address */
++static const unsigned char payload_source[ETH_ALEN] = {
++      0x00, 0x0f, 0x53, 0x1b, 0x1b, 0x1b,
++};
 +
-+/* Number of siblings per CPU package */
-+int smp_num_siblings = 1;
++static const char *payload_msg =
++      "Hello world! This is an Efx loopback test in progress!";
 +
-+cpumask_t cpu_online_map;
-+EXPORT_SYMBOL(cpu_online_map);
-+cpumask_t cpu_possible_map;
-+EXPORT_SYMBOL(cpu_possible_map);
-+cpumask_t cpu_initialized_map;
++struct efx_selftest_state {
++      /* Drop all packets in  efx_loopback_rx_packet */
++      int flush;
 +
-+struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
-+EXPORT_SYMBOL(cpu_data);
++      /* Number of packets being used in this test */
++      int packet_count;
 +
-+#ifdef CONFIG_HOTPLUG_CPU
-+DEFINE_PER_CPU(int, cpu_state) = { 0 };
-+#endif
++      /* RX good packet count */
++      atomic_t rx_good;
 +
-+static DEFINE_PER_CPU(int, resched_irq);
-+static DEFINE_PER_CPU(int, callfunc_irq);
-+static char resched_name[NR_CPUS][15];
-+static char callfunc_name[NR_CPUS][15];
++      /* RX bad packet count */
++      atomic_t rx_bad;
 +
-+u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
++      /* Payload used in tests */
++      struct efx_loopback_payload payload;
++};
 +
-+cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
-+cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
-+EXPORT_SYMBOL(cpu_core_map);
++/**************************************************************************
++ *
++ * Configurable values
++ *
++ **************************************************************************/
 +
-+#if defined(__i386__)
-+u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = 0xff };
-+EXPORT_SYMBOL(x86_cpu_to_apicid);
-+#elif !defined(CONFIG_X86_IO_APIC)
-+unsigned int maxcpus = NR_CPUS;
-+#endif
++/* Level of loopback testing
++ *
++ * The maximum packet burst length is 16**(n-1), i.e.
++ *
++ * - Level 0 : no packets
++ * - Level 1 : 1 packet
++ * - Level 2 : 17 packets (1 * 1 packet, 1 * 16 packets)
++ * - Level 3 : 273 packets (1 * 1 packet, 1 * 16 packet, 1 * 256 packets)
++ *
++ */
++static unsigned int loopback_test_level = 3;
 +
-+void __init prefill_possible_map(void)
++/**************************************************************************
++ *
++ * Interrupt and event queue testing
++ *
++ **************************************************************************/
++
++/*
++ * Test interrupts
++ *
++ * This generates a test interrupt and waits for it to be received by
++ * a CPU.  This routine must be called from process context and will
++ * sleep.
++ */
++static int efx_test_interrupts(struct efx_nic *efx,
++                             struct efx_self_tests *tests)
 +{
-+      int i, rc;
++      struct efx_channel *channel;
++      unsigned long j_start;
 +
-+      for_each_possible_cpu(i)
-+          if (i != smp_processor_id())
-+              return;
++      EFX_LOG(efx, "testing interrupts\n");
++      tests->interrupt = -1;
 +
-+      for (i = 0; i < NR_CPUS; i++) {
-+              rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
-+              if (rc >= 0)
-+                      cpu_set(i, cpu_possible_map);
++      /* Reset interrupt flag */
++      efx->last_irq_cpu = -1;
++      smp_wmb();
++
++      /* To guarantee that an interrupt is received make sure that the
++       * channels are ack'd at least once, reenabling interrupts.
++       * We will then receive an interrupt, either by explicitly
++       * requesting one, or receiving traffic.
++       */
++      efx_for_each_channel_with_interrupt(channel, efx) {
++              /* Process the eventq synchronously */
++              if (channel->work_pending)
++                      efx_process_channel_now(channel);
++              /* Check if we haven't already received an interrupt */
++              if (efx->last_irq_cpu >= 0)
++                      goto success;
 +      }
-+}
 +
-+void __init smp_alloc_memory(void)
-+{
-+}
++      j_start = jiffies;
 +
-+static inline void
-+set_cpu_sibling_map(int cpu)
-+{
-+      cpu_data[cpu].phys_proc_id = cpu;
-+      cpu_data[cpu].cpu_core_id  = 0;
++      /* Generate test interrupt. */
++      falcon_generate_interrupt(efx);
 +
-+      cpu_sibling_map[cpu] = cpumask_of_cpu(cpu);
-+      cpu_core_map[cpu]    = cpumask_of_cpu(cpu);
++      /* Wait for arrival of test interrupt. */
++      EFX_LOG(efx, "waiting for test interrupt\n");
++      schedule_timeout_uninterruptible(HZ / 10);
++      if (efx->last_irq_cpu >= 0)
++              goto success;
 +
-+      cpu_data[cpu].booted_cores = 1;
++      EFX_ERR(efx, "timed out in %ld jiffies waiting for interrupt\n",
++              jiffies - j_start);
++      return -ETIMEDOUT;
++
++ success:
++      EFX_LOG(efx, "%s test interrupt seen on CPU%d\n", INT_MODE(efx),
++              efx->last_irq_cpu);
++      tests->interrupt = 1;
++      return 0;
 +}
 +
-+static void
-+remove_siblinginfo(int cpu)
++/*
++ * Test capability of events to receive events
++ * This generates a test event and waits for it to be processed
++ * This routine must be called from process context and will sleep.
++ */
++static int efx_test_eventq(struct efx_channel *channel,
++                         struct efx_self_tests *tests)
 +{
-+      cpu_data[cpu].phys_proc_id = BAD_APICID;
-+      cpu_data[cpu].cpu_core_id  = BAD_APICID;
++      unsigned int magic;
 +
-+      cpus_clear(cpu_sibling_map[cpu]);
-+      cpus_clear(cpu_core_map[cpu]);
++      /* Channel specific code, limited to 20 bits */
++      magic = (0x00010150 + channel->channel);
++      EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
++              channel->channel, magic);
 +
-+      cpu_data[cpu].booted_cores = 0;
++      tests->eventq_dma[channel->channel] = -1;
++      tests->eventq_int[channel->channel] = 1;        /* fake pass */
++      tests->eventq_poll[channel->channel] = 1;       /* fake pass */
++
++      /* Reset flag and zero magic word */
++      channel->efx->last_irq_cpu = -1;
++      channel->eventq_magic = 0;
++      smp_wmb();
++
++      /* Generate test event */
++      falcon_generate_test_event(channel, magic);
++      udelay(1);
++
++      efx_process_channel_now(channel);
++      if (channel->eventq_magic != magic) {
++              EFX_ERR(channel->efx, "channel %d  failed to see test event\n",
++                      channel->channel);
++              return -ETIMEDOUT;
++      } else {
++              tests->eventq_dma[channel->channel] = 1;
++      }
++
++      return 0;
 +}
 +
-+static int __cpuinit xen_smp_intr_init(unsigned int cpu)
++
++/*
++ * Test capability of events to generate interrupts
++ * This generates a test event and waits for it to be processed by an
++ * ISR.  This routine must be called from process context and will
++ * sleep.
++ */
++static int efx_test_eventq_irq(struct efx_channel *channel,
++                             struct efx_self_tests *tests)
 +{
-+      int rc;
++      unsigned int magic, count;
++      unsigned long j_start = jiffies;
 +
-+      per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = -1;
++      /* Channel specific code, limited to 20 bits */
++      magic = (0x00010150 + channel->channel);
++      EFX_LOG(channel->efx, "channel %d testing event queue with code %x\n",
++              channel->channel, magic);
 +
-+      sprintf(resched_name[cpu], "resched%d", cpu);
-+      rc = bind_ipi_to_irqhandler(RESCHEDULE_VECTOR,
-+                                  cpu,
-+                                  smp_reschedule_interrupt,
-+                                  SA_INTERRUPT,
-+                                  resched_name[cpu],
-+                                  NULL);
-+      if (rc < 0)
-+              goto fail;
-+      per_cpu(resched_irq, cpu) = rc;
++      tests->eventq_dma[channel->channel] = -1;
++      tests->eventq_int[channel->channel] = -1;
++      tests->eventq_poll[channel->channel] = -1;
 +
-+      sprintf(callfunc_name[cpu], "callfunc%d", cpu);
-+      rc = bind_ipi_to_irqhandler(CALL_FUNCTION_VECTOR,
-+                                  cpu,
-+                                  smp_call_function_interrupt,
-+                                  SA_INTERRUPT,
-+                                  callfunc_name[cpu],
-+                                  NULL);
-+      if (rc < 0)
-+              goto fail;
-+      per_cpu(callfunc_irq, cpu) = rc;
++      /* Reset flag and zero magic word */
++      channel->efx->last_irq_cpu = -1;
++      channel->eventq_magic = 0;
++      smp_wmb();
 +
-+      if ((cpu != 0) && ((rc = local_setup_timer(cpu)) != 0))
-+              goto fail;
++      /* Generate test event */
++      falcon_generate_test_event(channel, magic);
 +
-+      return 0;
++      /* Wait for arrival of interrupt */
++      count = 0;
++      do {
++              schedule_timeout_uninterruptible(HZ / 100);
 +
-+ fail:
-+      if (per_cpu(resched_irq, cpu) >= 0)
-+              unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
-+      if (per_cpu(callfunc_irq, cpu) >= 0)
-+              unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
-+      return rc;
-+}
++              if (channel->work_pending)
++                      efx_process_channel_now(channel);
 +
-+#ifdef CONFIG_HOTPLUG_CPU
-+static void xen_smp_intr_exit(unsigned int cpu)
-+{
-+      if (cpu != 0)
-+              local_teardown_timer(cpu);
++              if (channel->eventq_magic == magic)
++                      goto eventq_ok;
++      }
++      while (++count < 2);
 +
-+      unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
-+      unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
-+}
-+#endif
++      EFX_ERR(channel->efx, "channel %d timed out in %ld jiffies waiting for"
++              " event queue\n", channel->channel, jiffies - j_start);
 +
-+void __cpuinit cpu_bringup(void)
-+{
-+      cpu_init();
-+      identify_cpu(cpu_data + smp_processor_id());
-+      touch_softlockup_watchdog();
-+      preempt_disable();
-+      local_irq_enable();
++      /* See if interrupt arrived */
++      if (channel->efx->last_irq_cpu >= 0) {
++              EFX_ERR(channel->efx, "channel %d saw interrupt on CPU%d "
++                      "during event queue test\n", channel->channel,
++                      raw_smp_processor_id());
++              tests->eventq_int[channel->channel] = 1;
++      }
++
++      /* Check to see if event was received even if interrupt wasn't */
++      efx_process_channel_now(channel);
++      if (channel->eventq_magic == magic) {
++              EFX_ERR(channel->efx, "channel %d event was generated, but "
++                      "failed to trigger an interrupt\n", channel->channel);
++              tests->eventq_dma[channel->channel] = 1;
++      }
++
++      return -ETIMEDOUT;
++ eventq_ok:
++      EFX_LOG(channel->efx, "channel %d event queue passed\n",
++              channel->channel);
++      tests->eventq_dma[channel->channel] = 1;
++      tests->eventq_int[channel->channel] = 1;
++      tests->eventq_poll[channel->channel] = 1;
++      return 0;
 +}
 +
-+static void __cpuinit cpu_bringup_and_idle(void)
++/**************************************************************************
++ *
++ * PHY testing
++ *
++ **************************************************************************/
++
++/*
++ * Check PHY presence
++ * This reads the PHY ID registers via GMII and checks that neither
++ * are all-zeroes or all-ones (indicating a nonexistent or
++ * uncommunicative PHY).
++ */
++static int efx_test_phy(struct efx_nic *efx,
++                      struct efx_self_tests *tests)
 +{
-+      cpu_bringup();
-+      cpu_idle();
++      u16 physid1, physid2;
++      struct mii_if_info *mii = &efx->mii;
++      struct net_device *net_dev = efx->net_dev;
++
++      if (efx->phy_type == PHY_TYPE_NONE)
++              return 0;
++
++      EFX_LOG(efx, "testing PHY presence\n");
++      tests->phy_ok = -1;
++
++      physid1 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID1);
++      physid2 = mii->mdio_read(net_dev, mii->phy_id, MII_PHYSID2);
++
++      if ((physid1 != 0x0000) && (physid1 != 0xffff) &&
++          (physid2 != 0x0000) && (physid2 != 0xffff)) {
++              EFX_LOG(efx, "found MII PHY %d ID 0x%x:%x\n",
++                      mii->phy_id, physid1, physid2);
++              tests->phy_ok = 1;
++              return 0;
++      }
++
++      EFX_ERR(efx, "no MII PHY present with ID %d\n", mii->phy_id);
++      return -ENODEV;
 +}
 +
-+static void __cpuinit cpu_initialize_context(unsigned int cpu)
++/**************************************************************************
++ *
++ * Loopback testing
++ * NB Only one loopback test can be executing concurrently.
++ *
++ **************************************************************************/
++
++/* Loopback test RX callback
++ * This is called for each received packet during loopback testing.
++ */
++void efx_loopback_rx_packet(struct efx_nic *efx,
++                          const char *buf_ptr, int pkt_len)
 +{
-+      vcpu_guest_context_t ctxt;
-+      struct task_struct *idle = idle_task(cpu);
-+#ifdef __x86_64__
-+      struct desc_ptr *gdt_descr = &cpu_gdt_descr[cpu];
-+#else
-+      struct Xgt_desc_struct *gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
-+#endif
++      struct efx_selftest_state *state = efx->loopback_selftest;
++      struct efx_loopback_payload *received;
++      struct efx_loopback_payload *payload;
 +
-+      if (cpu_test_and_set(cpu, cpu_initialized_map))
++      BUG_ON(!buf_ptr);
++
++      /* If we are just flushing, then drop the packet */
++      if ((state == NULL) || state->flush)
 +              return;
 +
-+      memset(&ctxt, 0, sizeof(ctxt));
++      payload = &state->payload;
++
++      /* The packet should have been passed up to us before any LRO/SSR, so
++       * we should be able to compare the data directly. Since the packet
++       * is going to be thrown away by the caller, modify it in place.
++       * efx_test_loopback guarantees to not touch state->payload during
++       * the test */
++      received = (struct efx_loopback_payload *)(char *)buf_ptr;
++      received->ip.saddr = payload->ip.saddr;
++      received->ip.check = payload->ip.check;
++
++      /* Check that header exists */
++      if (pkt_len < sizeof(received->header)) {
++              EFX_ERR(efx, "saw runt RX packet (length %d) "
++                      "in %s loopback test\n", pkt_len,
++                      LOOPBACK_MODE(efx));
++              goto err;
++      }
 +
-+      ctxt.flags = VGCF_IN_KERNEL;
-+      ctxt.user_regs.ds = __USER_DS;
-+      ctxt.user_regs.es = __USER_DS;
-+      ctxt.user_regs.fs = 0;
-+      ctxt.user_regs.gs = 0;
-+      ctxt.user_regs.ss = __KERNEL_DS;
-+      ctxt.user_regs.eip = (unsigned long)cpu_bringup_and_idle;
-+      ctxt.user_regs.eflags = X86_EFLAGS_IF | 0x1000; /* IOPL_RING1 */
++      /* Check that header matches */
++      if (memcmp(&received->header, &payload->header, ETH_HLEN) != 0) {
++              EFX_ERR(efx, "saw non-loopback RX packet in"
++                      " %s loopback test\n",
++                      LOOPBACK_MODE(efx));
++              goto err;
++      }
 +
-+      memset(&ctxt.fpu_ctxt, 0, sizeof(ctxt.fpu_ctxt));
++      /* Check packet length */
++      if (pkt_len != sizeof(*payload)) {
++              EFX_ERR(efx, "saw incorrect RX packet length"
++                      " %d (wanted %d) in %s loopback test\n",
++                      pkt_len, (int)sizeof(*payload),
++                      LOOPBACK_MODE(efx));
++              goto err;
++      }
 +
-+      smp_trap_init(ctxt.trap_ctxt);
++      /* Check that IP header matches */
++      if (memcmp(&received->ip, &payload->ip, sizeof(payload->ip)) != 0) {
++              EFX_ERR(efx, "saw corrupted IP header in %s "
++                      "loopback test\n",
++                      LOOPBACK_MODE(efx));
++              goto err;
++      }
 +
-+      ctxt.ldt_ents = 0;
++      /* Check that msg and padding matches */
++      if (memcmp(&received->msg, &payload->msg, sizeof(received->msg)) != 0) {
++              EFX_ERR(efx, "saw corrupted RX packet in %s "
++                      "loopback test\n",
++                      LOOPBACK_MODE(efx));
++              goto err;
++      }
 +
-+      ctxt.gdt_frames[0] = virt_to_mfn(gdt_descr->address);
-+      ctxt.gdt_ents      = gdt_descr->size / 8;
++      /* Check that iteration matches */
++      if (received->iteration != payload->iteration) {
++              EFX_ERR(efx, "saw RX packet from iteration %d"
++                      " (wanted %d) in %s loopback test\n",
++                      ntohs(received->iteration), ntohs(payload->iteration),
++                      LOOPBACK_MODE(efx));
++              goto err;
++      }
 +
-+#ifdef __i386__
-+      ctxt.user_regs.cs = __KERNEL_CS;
-+      ctxt.user_regs.esp = idle->thread.esp0 - sizeof(struct pt_regs);
++      /* Increase correct RX count */
++      EFX_TRACE(efx, "got loopback RX in %s loopback test\n",
++                LOOPBACK_MODE(efx));
 +
-+      ctxt.kernel_ss = __KERNEL_DS;
-+      ctxt.kernel_sp = idle->thread.esp0;
++      atomic_inc(&state->rx_good);
++      return;
 +
-+      ctxt.event_callback_cs     = __KERNEL_CS;
-+      ctxt.event_callback_eip    = (unsigned long)hypervisor_callback;
-+      ctxt.failsafe_callback_cs  = __KERNEL_CS;
-+      ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
++ err:
++#ifdef EFX_ENABLE_DEBUG
++      if (atomic_read(&state->rx_bad) == 0) {
++              EFX_ERR(efx, "received packet:\n");
++              print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1,
++                             buf_ptr, pkt_len, 0);
++              EFX_ERR(efx, "expected packet:\n");
++              print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 0x10, 1,
++                             &state->payload, sizeof(state->payload), 0);
++      }
++#endif
++      atomic_inc(&state->rx_bad);
++}
++
++/* Initialise an efx_selftest_state for a new iteration */
++static void efx_iterate_state(struct efx_nic *efx)
++{
++      struct efx_selftest_state *state = efx->loopback_selftest;
++      struct net_device *net_dev = efx->net_dev;
++      struct efx_loopback_payload *payload = &state->payload;
++
++      /* Initialise the layerII header */
++      memcpy(&payload->header.h_dest, net_dev->dev_addr, ETH_ALEN);
++      memcpy(&payload->header.h_source, &payload_source, ETH_ALEN);
++      payload->header.h_proto = htons(ETH_P_IP);
++
++      /* saddr set later and used as incrementing count */
++      payload->ip.daddr = htonl(INADDR_LOOPBACK);
++      payload->ip.ihl = 5;
++      payload->ip.check = 0;          /* offloaded */
++      payload->ip.tot_len = htons(sizeof(*payload) - sizeof(struct ethhdr));
++      payload->ip.version = IPVERSION;
++      payload->ip.protocol = IPPROTO_UDP;
++
++      /* Initialise udp header */
++      payload->udp.source = 0;
++      payload->udp.len = htons(sizeof(*payload) - sizeof(struct ethhdr) -
++                               sizeof(struct iphdr));
++      payload->udp.check = 0; /* checksum ignored */
++
++      /* Fill out payload */
++      payload->iteration = htons(ntohs(payload->iteration) + 1);
++      memcpy(&payload->msg, payload_msg, sizeof(payload_msg));
++
++      /* Fill out remaining state members */
++      atomic_set(&state->rx_good, 0);
++      atomic_set(&state->rx_bad, 0);
++      smp_wmb();
++}
 +
-+      ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
-+#else /* __x86_64__ */
-+      ctxt.user_regs.cs = __KERNEL_CS;
-+      ctxt.user_regs.esp = idle->thread.rsp0 - sizeof(struct pt_regs);
++/*
++ * Perform loopback test with N packets
++ *
++ * This will transmit "num_packets" copies of a test packet, and check
++ * that they were both transmitted (i.e. a TX completion event was
++ * received) and received (i.e. the data arrived intact via loopback).
++ * The port must have already been placed into the desired loopback
++ * mode.
++ */
++static int efx_test_loopback(struct efx_nic *efx,
++                           struct efx_tx_queue *tx_queue,
++                           struct efx_loopback_self_tests *lb_tests)
++{
++#if !defined(EFX_HAVE_OLD_NAPI)
++      struct efx_channel *channel;
++#endif
++      struct efx_selftest_state *state = efx->loopback_selftest;
++      struct efx_loopback_payload *payload;
++      struct sk_buff *skb;
++      int rc = 0, i, tx_done, rx_good, rx_bad;
 +
-+      ctxt.kernel_ss = __KERNEL_DS;
-+      ctxt.kernel_sp = idle->thread.rsp0;
++      /* Fill out the packet contents */
++      efx_iterate_state(efx);
 +
-+      ctxt.event_callback_eip    = (unsigned long)hypervisor_callback;
-+      ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
-+      ctxt.syscall_callback_eip  = (unsigned long)system_call;
++      /* Create and fill skb */
++      skb = alloc_skb(sizeof(state->payload), GFP_KERNEL);
++      if (!skb) {
++              rc = -ENOMEM;
++              goto out1;
++      }
++      payload = ((struct efx_loopback_payload *)
++                 skb_put(skb, sizeof(state->payload)));
++      memcpy(payload, &state->payload, sizeof(state->payload));
 +
-+      ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(init_level4_pgt));
++      /* Transmit N copies of buffer */
++      for (i = 0; i < state->packet_count; i++) {
++              /* Set the source address in the copy of the packet.
++               * Incrementing the source address on a per-packet basis
++               * should ensure that we stress all RSS vectors */
++              payload->ip.saddr = htonl(INADDR_LOOPBACK | (i << 2));
++              skb_get(skb);
 +
-+      ctxt.gs_base_kernel = (unsigned long)(cpu_pda(cpu));
-+#endif
++              if (efx_xmit(efx, tx_queue, skb) != NETDEV_TX_OK) {
++                      EFX_ERR(efx, "TX queue %d could not transmit "
++                              "packet %d of %d in %s loopback test\n",
++                              tx_queue->queue, i + 1,
++                              state->packet_count, LOOPBACK_MODE(efx));
++                      rc = -EPIPE;
++                      goto out2;
++              }
 +
-+      BUG_ON(HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, &ctxt));
-+}
++              /* Avoid hogging the PCI bus */
++              udelay(10);
++      }
 +
-+void __init smp_prepare_cpus(unsigned int max_cpus)
-+{
-+      int cpu;
-+      struct task_struct *idle;
-+#ifdef __x86_64__
-+      struct desc_ptr *gdt_descr;
++#if !defined(EFX_HAVE_OLD_NAPI)
++      /* NAPI polling is not enabled, so process channels synchronously */
++      schedule_timeout_uninterruptible(HZ / 50);
++      efx_for_each_channel_with_interrupt(channel, efx) {
++              if (channel->work_pending)
++                      efx_process_channel_now(channel);
++      }
 +#else
-+      struct Xgt_desc_struct *gdt_descr;
++      /* Allow time for processing */
++      schedule_timeout_uninterruptible(HZ / 10);
 +#endif
 +
-+      boot_cpu_data.apicid = 0;
-+      cpu_data[0] = boot_cpu_data;
++      if (state->flush)
++              goto out3;
 +
-+      cpu_2_logical_apicid[0] = 0;
-+      x86_cpu_to_apicid[0] = 0;
++      /* Check TX completion and received packet counts */
++      tx_done = state->packet_count - (atomic_read(&skb->users) - 1);
++      rx_good = atomic_read(&state->rx_good);
++      rx_bad = atomic_read(&state->rx_bad);
++      if (tx_done != state->packet_count) {
++              /* Don't free the skbs; they will be picked up on TX
++               * overflow or channel teardown.
++               */
++              EFX_ERR(efx, "TX queue %d saw only %d out of an "
++                      "expected %d TX completion events in %s loopback "
++                      "test\n", tx_queue->queue, tx_done,
++                      state->packet_count, LOOPBACK_MODE(efx));
++              rc = -ETIMEDOUT;
++              /* Allow to fall through so we see the RX errors as well */
++      }
++
++      /* We may always be up to a flush away from our desired packet total */
++      if (rx_good != state->packet_count) {
++              EFX_LOG(efx, "TX queue %d saw only %d out of an "
++                      "expected %d received packets in %s loopback "
++                      "test\n", tx_queue->queue, rx_good,
++                      state->packet_count, LOOPBACK_MODE(efx));
++              rc = -ETIMEDOUT;
++              /* Fall through */
++      }
++
++      /* Update loopback test structure */
++      lb_tests->tx_sent[tx_queue->queue] += state->packet_count;
++      lb_tests->tx_done[tx_queue->queue] += tx_done;
++      lb_tests->rx_good += rx_good;
++      lb_tests->rx_bad += rx_bad;
++
++ out3:
++ out2:
++      /* Free skb */
++      if (skb) {
++              /* If the selftest failed then the skb needs its reference
++               * count decreasing */
++              while (skb_shared(skb))
++                      kfree_skb(skb);
++              dev_kfree_skb_any(skb);
++      }
 +
-+      current_thread_info()->cpu = 0;
++ out1:
++      return rc;
++}
 +
-+      for (cpu = 0; cpu < NR_CPUS; cpu++) {
-+              cpus_clear(cpu_sibling_map[cpu]);
-+              cpus_clear(cpu_core_map[cpu]);
++/* Perform loopback test safely
++ *
++ * This performs a safe loopback test by starting with a single packet
++ * and only increasing the number of packets while the tests are
++ * passing.  This avoids flooding a network with garbage packets if
++ * e.g. setting the loopback mode fails.
++ */
++static int
++efx_test_loopback_safely(struct efx_nic *efx,
++                       struct efx_tx_queue *tx_queue,
++                       struct efx_loopback_self_tests *lb_tests)
++{
++      struct efx_selftest_state *state = efx->loopback_selftest;
++      int i, rc = 0;
++
++      for (i = 0; i < loopback_test_level; i++) {
++              /* Determine how many packets to send */
++              state->packet_count = (efx->type->txd_ring_mask + 1) / 3;
++              state->packet_count = min(1 << (i << 2), state->packet_count);
++              state->flush = 0;
++
++              EFX_LOG(efx, "TX queue %d testing %s loopback"
++                      " with %d packets\n", tx_queue->queue,
++                      LOOPBACK_MODE(efx), state->packet_count);
++
++              rc = efx_test_loopback(efx, tx_queue, lb_tests);
++              if (rc) {
++                      /* Wait a while to ensure there are no packets
++                       * floating around after a failure.
++                       */
++                      schedule_timeout_uninterruptible(HZ / 5);
++                      return rc;
++              }
 +      }
 +
-+      set_cpu_sibling_map(0);
++      EFX_LOG(efx, "TX queue %d passed %s loopback test "
++              "with a burst length of %d packets\n",
++              tx_queue->queue, LOOPBACK_MODE(efx), state->packet_count);
 +
-+      if (xen_smp_intr_init(0))
-+              BUG();
++      return rc;
++}
 +
-+      cpu_initialized_map = cpumask_of_cpu(0);
++static int efx_test_loopbacks(struct efx_nic *efx,
++                            struct efx_self_tests *tests,
++                            unsigned int loopback_modes)
++{
++      struct efx_selftest_state *state = efx->loopback_selftest;
++      struct ethtool_cmd ecmd, ecmd_loopback;
++      struct efx_tx_queue *tx_queue;
++      enum efx_loopback_mode old_mode, mode;
++      int old_powered, count, rc = 0;
++      int retry = EFX_WORKAROUND_8909(efx);
 +
-+      /* Restrict the possible_map according to max_cpus. */
-+      while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) {
-+              for (cpu = NR_CPUS-1; !cpu_isset(cpu, cpu_possible_map); cpu--)
-+                      continue;
-+              cpu_clear(cpu, cpu_possible_map);
++      /* Get current PHY settings */
++      rc = efx_ethtool_get_settings(efx->net_dev, &ecmd);
++      if (rc) {
++              EFX_ERR(efx, "could not get GMII settings\n");
++              return rc;
 +      }
++      old_mode = efx->loopback_mode;
++      old_powered = efx->phy_powered;
 +
-+      for_each_possible_cpu (cpu) {
-+              if (cpu == 0)
-+                      continue;
++      /* Disable autonegotiation for the purposes of loopback */
++      memcpy(&ecmd_loopback, &ecmd, sizeof(ecmd_loopback));
++      if (ecmd_loopback.autoneg == AUTONEG_ENABLE) {
++              ecmd_loopback.autoneg = AUTONEG_DISABLE;
++              ecmd_loopback.duplex = DUPLEX_FULL;
++              ecmd_loopback.speed = EFX_IS10G(efx) ?
++                      SPEED_10000 : SPEED_1000;
++      }
 +
-+#ifdef __x86_64__
-+              gdt_descr = &cpu_gdt_descr[cpu];
-+#else
-+              gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
-+#endif
-+              gdt_descr->address = get_zeroed_page(GFP_KERNEL);
-+              if (unlikely(!gdt_descr->address)) {
-+                      printk(KERN_CRIT "CPU%d failed to allocate GDT\n",
-+                             cpu);
++      rc = efx_ethtool_set_settings(efx->net_dev, &ecmd_loopback);
++      if (rc) {
++              EFX_ERR(efx, "could not disable autonegotiation\n");
++              goto out;
++      }
++      tests->loopback_speed = ecmd_loopback.speed;
++      tests->loopback_full_duplex = ecmd_loopback.duplex;
++
++      /* Test all supported loopback modes */
++      for (mode = LOOPBACK_NONE; mode < LOOPBACK_TEST_MAX; mode++) {
++              if (!(loopback_modes & (1 << mode)))
 +                      continue;
++
++              /* Move the port into the specified loopback mode. */
++              state->flush = 1;
++              efx->phy_powered = 1;
++              efx->loopback_mode = mode;
++              efx_reconfigure_port(efx, 0);
++
++              /* Wait for the PHY to signal the link is up */
++              count = 0;
++              do {
++                      struct efx_channel *channel = &efx->channel[0];
++
++                      (void) efx->mac_op->check_hw(efx);
++                      schedule_timeout_uninterruptible(HZ / 10);
++                      if (channel->work_pending)
++                              efx_process_channel_now(channel);
++                      /* Wait for PHY events to be processed */
++                      flush_workqueue(efx->workqueue);
++                      rmb();
++              } while ((++count < 20) && !efx->link_up);
++
++              /* The link should now be up. If it isn't, there is no point
++               * in attempting a loopback test */
++              if (!efx->link_up) {
++                      EFX_ERR(efx, "loopback %s never came up\n",
++                              LOOPBACK_MODE(efx));
++                      rc = -EIO;
++                      goto out;
 +              }
-+              gdt_descr->size = GDT_SIZE;
-+              memcpy((void *)gdt_descr->address, cpu_gdt_table, GDT_SIZE);
-+              make_page_readonly(
-+                      (void *)gdt_descr->address,
-+                      XENFEAT_writable_descriptor_tables);
 +
-+              cpu_data[cpu] = boot_cpu_data;
-+              cpu_data[cpu].apicid = cpu;
++              EFX_LOG(efx, "link came up in %s loopback in %d iterations\n",
++                      LOOPBACK_MODE(efx), count);
 +
-+              cpu_2_logical_apicid[cpu] = cpu;
-+              x86_cpu_to_apicid[cpu] = cpu;
++              /* Test every TX queue */
++              efx_for_each_tx_queue(tx_queue, efx) {
++                      rc |= efx_test_loopback_safely(efx, tx_queue,
++                                                     &tests->loopback[mode]);
++                      if (rc)
++                              goto fail;
++              }
 +
-+              idle = fork_idle(cpu);
-+              if (IS_ERR(idle))
-+                      panic("failed fork for CPU %d", cpu);
++              continue;
 +
-+#ifdef __x86_64__
-+              cpu_pda(cpu)->pcurrent = idle;
-+              cpu_pda(cpu)->cpunumber = cpu;
-+              clear_ti_thread_flag(idle->thread_info, TIF_FORK);
-+#endif
++fail:
++              if (retry) {
++                      /* Give the PHY a kick by pretending to move into
++                       * a Falcon internal loopback mode, then back out */
++                      int first = ffs(efx->loopback_modes) - 1;
 +
-+              irq_ctx_init(cpu);
++                      EFX_INFO(efx, "retrying %s loopback\n",
++                               LOOPBACK_MODE(efx));
 +
-+#ifdef CONFIG_HOTPLUG_CPU
-+              if (is_initial_xendomain())
-+                      cpu_set(cpu, cpu_present_map);
-+#else
-+              cpu_set(cpu, cpu_present_map);
-+#endif
-+      }
++                      state->flush = 1;
++                      efx->loopback_mode = first;
++                      efx_reconfigure_port(efx, 0);
 +
-+      init_xenbus_allowed_cpumask();
++                      retry = rc = 0;
++                      --mode;
++                      continue;
++              }
++              break;
++      }
 +
-+#ifdef CONFIG_X86_IO_APIC
-+      /*
-+       * Here we can be sure that there is an IO-APIC in the system. Let's
-+       * go and set it up:
-+       */
-+      if (!skip_ioapic_setup && nr_ioapics)
-+              setup_IO_APIC();
-+#endif
-+}
++ out:
++      /* Take out of loopback and restore PHY settings */
++      state->flush = 1;
++      efx->loopback_mode = old_mode;
++      efx->phy_powered = old_powered;
++      /* Push the loopback change, and restore any other
++       * settings we may have trodden on */
++      (void) efx_ethtool_set_settings(efx->net_dev, &ecmd);
 +
-+void __devinit smp_prepare_boot_cpu(void)
-+{
-+      prefill_possible_map();
++      return rc;
 +}
 +
-+#ifdef CONFIG_HOTPLUG_CPU
++/**************************************************************************
++ *
++ * Entry points
++ *
++ *************************************************************************/
 +
-+/*
-+ * Initialize cpu_present_map late to skip SMP boot code in init/main.c.
-+ * But do it early enough to catch critical for_each_present_cpu() loops
-+ * in i386-specific code.
++/* Online (i.e. non-disruptive) testing
++ *
++ * This checks interrupt generation, event delivery and PHY presence.
++ * The caller should hold the suspend lock
++ *
 + */
-+static int __init initialize_cpu_present_map(void)
++int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests)
 +{
-+      cpu_present_map = cpu_possible_map;
-+      return 0;
-+}
-+core_initcall(initialize_cpu_present_map);
++      struct efx_channel *channel;
++      int rc = 0;
 +
-+int __cpu_disable(void)
-+{
-+      cpumask_t map = cpu_online_map;
-+      int cpu = smp_processor_id();
++      ASSERT_RTNL();
 +
-+      if (cpu == 0)
-+              return -EBUSY;
++      EFX_LOG(efx, "performing online self-tests\n");
 +
-+      remove_siblinginfo(cpu);
++      rc |= efx_test_interrupts(efx, tests);
++      efx_for_each_channel(channel, efx) {
++              if (channel->has_interrupt)
++                      rc |= efx_test_eventq_irq(channel, tests);
++              else
++                      rc |= efx_test_eventq(channel, tests);
++      }
++      rc |= efx_test_phy(efx, tests);
 +
-+      cpu_clear(cpu, map);
-+      fixup_irqs(map);
-+      cpu_clear(cpu, cpu_online_map);
++      if (rc)
++              EFX_ERR(efx, "failed online self-tests\n");
 +
-+      return 0;
++      return rc;
 +}
 +
-+void __cpu_die(unsigned int cpu)
++/* Offline (i.e. disruptive) testing
++ * This checks MAC and PHY loopback on the specified port. The caller
++ * should hold the rtnl lock
++ */
++int efx_offline_test(struct efx_nic *efx,
++                   struct efx_self_tests *tests, unsigned int loopback_modes)
 +{
-+      while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
-+              current->state = TASK_UNINTERRUPTIBLE;
-+              schedule_timeout(HZ/10);
++      struct efx_selftest_state *state;
++      int rc = 0;
++
++      ASSERT_RTNL();
++
++      EFX_LOG(efx, "performing offline self-tests\n");
++
++      /* Create a selftest_state structure to hold state for the test */
++      state = kzalloc(sizeof(*state), GFP_KERNEL);
++      if (state == NULL) {
++              rc = -ENOMEM;
++              goto out;
 +      }
 +
-+      xen_smp_intr_exit(cpu);
++      /* Set the port loopback_selftest member. From this point on
++       * all received packets will be dropped. Mark the state as
++       * "flushing" so all inflight packets are dropped */
++      BUG_ON(efx->loopback_selftest);
++      state->flush = 1;
++      efx->loopback_selftest = (void *)state;
++      wmb();
 +
-+      if (num_online_cpus() == 1)
-+              alternatives_smp_switch(0);
++      /* Test all loopback  modes */
++      rc = efx_test_loopbacks(efx, tests, loopback_modes);
++
++      /* Tidy up the port test state */
++      efx->loopback_selftest = NULL;
++      wmb();
++      kfree(state);
++
++ out:
++      if (rc)
++              EFX_ERR(efx, "failed offline self-tests\n");
++
++      return rc;
 +}
 +
-+#endif /* CONFIG_HOTPLUG_CPU */
+--- linux-2.6.18.8/drivers/net/sfc/selftest.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/selftest.h     2008-05-19 00:33:29.321836271 +0300
+@@ -0,0 +1,67 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+int __cpuinit __cpu_up(unsigned int cpu)
-+{
-+      int rc;
++#ifndef EFX_SELFTEST_H
++#define EFX_SELFTEST_H
 +
-+      rc = cpu_up_check(cpu);
-+      if (rc)
-+              return rc;
++#include "net_driver.h"
 +
-+      cpu_initialize_context(cpu);
++/*
++ * Self tests
++ */
 +
-+      if (num_online_cpus() == 1)
-+              alternatives_smp_switch(1);
++struct efx_loopback_self_tests {
++      int tx_sent[EFX_MAX_TX_QUEUES];
++      int tx_done[EFX_MAX_TX_QUEUES];
++      int rx_good;
++      int rx_bad;
++};
 +
-+      /* This must be done before setting cpu_online_map */
-+      set_cpu_sibling_map(cpu);
-+      wmb();
++/* Efx self test results
++ * For fields which are not counters, 1 indicates success and -1
++ * indicates failure.
++ */
++struct efx_self_tests {
++      int interrupt;
++      int eventq_dma[EFX_MAX_CHANNELS];
++      int eventq_int[EFX_MAX_CHANNELS];
++      int eventq_poll[EFX_MAX_CHANNELS];
++      int phy_ok;
++      int loopback_speed;
++      int loopback_full_duplex;
++      struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX];
++};
 +
-+      rc = xen_smp_intr_init(cpu);
-+      if (rc) {
-+              remove_siblinginfo(cpu);
-+              return rc;
-+      }
++extern void efx_loopback_rx_packet(struct efx_nic *efx,
++                                 const char *buf_ptr, int pkt_len);
++extern int efx_online_test(struct efx_nic *efx,
++                         struct efx_self_tests *tests);
++extern int efx_offline_test(struct efx_nic *efx,
++                          struct efx_self_tests *tests,
++                          unsigned int loopback_modes);
 +
-+      cpu_set(cpu, cpu_online_map);
++#endif /* EFX_SELFTEST_H */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/Makefile       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/Makefile  2008-05-19 00:33:29.325836502 +0300
+@@ -0,0 +1,15 @@
++obj-$(CONFIG_SFC_RESOURCE) := sfc_resource.o
 +
-+      rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
-+      BUG_ON(rc);
++EXTRA_CFLAGS += -D__CI_HARDWARE_CONFIG_FALCON__
++EXTRA_CFLAGS += -D__ci_driver__ 
++EXTRA_CFLAGS += -Werror
++EXTRA_CFLAGS += -Idrivers/net/sfc -Idrivers/net/sfc/sfc_resource
 +
-+      return 0;
-+}
++sfc_resource-objs := resource_driver.o iopage.o efx_vi_shm.o \
++      driverlink_new.o kernel_proc.o kfifo.o \
++      nic.o eventq.o falcon.o falcon_mac.o falcon_hash.o \
++      assert_valid.o buddy.o buffer_table.o filter_resource.o \
++      iobufset_resource.o resource_manager.o resources.o \
++      vi_resource_alloc.o vi_resource_event.o vi_resource_flush.o \
++      vi_resource_manager.o driver_object.o kernel_compat.o
 +
-+void __init smp_cpus_done(unsigned int max_cpus)
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/assert_valid.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/assert_valid.c    2008-05-19 00:33:29.325836502 +0300
+@@ -0,0 +1,95 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains functions to assert validness of resources and
++ * resource manager in DEBUG build of the resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efrm/sysdep.h>
++
++#ifndef NDEBUG
++#include <ci/efrm/resource.h>
++#include <ci/efrm/driver_private.h>
++#include <ci/efrm/debug.h>
++
++void
++efrm_resource_manager_assert_valid(struct efrm_resource_manager *rm,
++                                 const char *file, int line)
 +{
++      _EFRM_ASSERT(rm, file, line);
++      _EFRM_ASSERT(rm->rm_name, file, line);
++      _EFRM_ASSERT(rm->rm_type < EFRM_RESOURCE_NUM, file, line);
++      _EFRM_ASSERT(rm->rm_table, file, line);
++      _EFRM_ASSERT(rm->rm_table_size > 0, file, line);
++      _EFRM_ASSERT(rm->rm_dtor, file, line);
 +}
++EXPORT_SYMBOL(efrm_resource_manager_assert_valid);
 +
-+#ifndef CONFIG_X86_LOCAL_APIC
-+int setup_profiling_timer(unsigned int multiplier)
++/*
++ * \param rs                    resource to validate
++ * \param ref_count_is_zero     One of 3 values
++ *                                > 0  - check ref count is zero
++ *                                = 0  - check ref count is non-zero
++ *                                < 0  - ref count could be any value
++ */
++void
++efrm_resource_assert_valid(struct efrm_resource *rs, int ref_count_is_zero,
++                         const char *file, int line)
 +{
-+      return -EINVAL;
++      struct efrm_resource_manager *rm;
++
++      _EFRM_ASSERT(rs, file, line);
++
++      if (ref_count_is_zero >= 0) {
++              if (!(ref_count_is_zero || atomic_read(&rs->rs_ref_count) > 0)
++                  || !(!ref_count_is_zero
++                       || atomic_read(&rs->rs_ref_count) == 0))
++                      EFRM_WARN("%s: check %szero ref=%d " EFRM_RESOURCE_FMT,
++                                __FUNCTION__,
++                                ref_count_is_zero == 0 ? "non-" : "",
++                                atomic_read(&rs->rs_ref_count),
++                                EFRM_RESOURCE_PRI_ARG(rs->rs_handle));
++
++              _EFRM_ASSERT(!(ref_count_is_zero == 0) ||
++                           atomic_read(&rs->rs_ref_count) != 0, file, line);
++              _EFRM_ASSERT(!(ref_count_is_zero > 0) ||
++                           atomic_read(&rs->rs_ref_count) == 0, file, line);
++      }
++
++      rm = efrm_rm_table[EFRM_RESOURCE_TYPE(rs->rs_handle)];
++      efrm_resource_manager_assert_valid(rm, file, line);
 +}
++EXPORT_SYMBOL(efrm_resource_assert_valid);
++
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/xencomm.c linux-2.6.18-xen.hg/drivers/xen/core/xencomm.c
---- linux-2.6.18/drivers/xen/core/xencomm.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/xencomm.c     2007-12-23 11:15:33.867925803 +0100
-@@ -0,0 +1,229 @@
-+/*
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
-+ * 
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/buddy.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/buddy.c   2008-05-19 00:33:29.325836502 +0300
+@@ -0,0 +1,307 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains implementation of a buddy allocator.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
-+ * 
++ *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-+ *
-+ * Copyright (C) IBM Corp. 2006
-+ *
-+ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <linux/gfp.h>
-+#include <linux/mm.h>
-+#include <asm/page.h>
-+#include <xen/xencomm.h>
-+#include <xen/interface/xen.h>
-+#ifdef __ia64__
-+#include <asm/xen/xencomm.h>  /* for is_kern_addr() */
-+#endif
++#include <ci/efhw/common.h> /* get uintXX types on win32 */
++#include <ci/efrm/sysdep.h>
++#include <ci/efrm/buddy.h>
++#include <ci/efrm/debug.h>
 +
-+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
-+#include <xen/platform-compat.h>
++#if 1
++#define DEBUG_ALLOC(x)
++#else
++#define DEBUG_ALLOC(x) x
++
++static inline void efrm_buddy_dump(struct efrm_buddy_allocator *b)
++{
++      unsigned o;
++
++      EFRM_NOTICE("%s: dump allocator with order %u",
++                  __FUNCTION__, b->order);
++      for (o = 0; o <= b->order; o++) {
++              struct list_head *l = &b->free_lists[o];
++              while (l->next != &b->free_lists[o]) {
++                      l = l->next;
++                      EFRM_NOTICE("%s: order %x: %zx", __FUNCTION__, o,
++                                  l - b->links);
++              }
++      }
++}
 +#endif
 +
-+static int xencomm_init(struct xencomm_desc *desc,
-+                      void *buffer, unsigned long bytes)
++/*
++ * The purpose of the following inline functions is to give the
++ * understandable names to the simple actions.
++ */
++static inline void
++efrm_buddy_free_list_add(struct efrm_buddy_allocator *b,
++                       unsigned order, unsigned addr)
 +{
-+      unsigned long recorded = 0;
-+      int i = 0;
++      list_add(&b->links[addr], &b->free_lists[order]);
++      b->orders[addr] = (uint8_t) b->order;
++}
++static inline void
++efrm_buddy_free_list_del(struct efrm_buddy_allocator *b, unsigned addr)
++{
++      list_del(&b->links[addr]);
++      b->links[addr].next = NULL;
++}
++static inline int
++efrm_buddy_free_list_empty(struct efrm_buddy_allocator *b, unsigned order)
++{
++      return list_empty(&b->free_lists[order]);
++}
++static inline unsigned
++efrm_buddy_free_list_pop(struct efrm_buddy_allocator *b, unsigned order)
++{
++      struct list_head *l = list_pop(&b->free_lists[order]);
++      l->next = NULL;
++      return (unsigned)(l - b->links);
++}
++static inline int
++efrm_buddy_addr_in_free_list(struct efrm_buddy_allocator *b, unsigned addr)
++{
++      return b->links[addr].next != NULL;
++}
++static inline unsigned
++efrm_buddy_free_list_first(struct efrm_buddy_allocator *b, unsigned order)
++{
++      return (unsigned)(b->free_lists[order].next - b->links);
++}
 +
-+      while ((recorded < bytes) && (i < desc->nr_addrs)) {
-+              unsigned long vaddr = (unsigned long)buffer + recorded;
-+              unsigned long paddr;
-+              int offset;
-+              int chunksz;
++int efrm_buddy_ctor(struct efrm_buddy_allocator *b, unsigned order)
++{
++      unsigned o;
++      unsigned size = 1 << order;
 +
-+              offset = vaddr % PAGE_SIZE; /* handle partial pages */
-+              chunksz = min(PAGE_SIZE - offset, bytes - recorded);
++      DEBUG_ALLOC(EFRM_NOTICE("%s(%u)", __FUNCTION__, order));
++      EFRM_ASSERT(b);
++      EFRM_ASSERT(order <= sizeof(unsigned) * 8 - 1);
 +
-+              paddr = xencomm_vtop(vaddr);
-+              if (paddr == ~0UL) {
-+                      printk("%s: couldn't translate vaddr %lx\n",
-+                             __func__, vaddr);
-+                      return -EINVAL;
-+              }
++      b->order = order;
++      b->free_lists = vmalloc((order + 1) * sizeof(struct list_head));
++      if (b->free_lists == NULL)
++              goto fail1;
 +
-+              desc->address[i++] = paddr;
-+              recorded += chunksz;
-+      }
++      b->links = vmalloc(size * sizeof(struct list_head));
++      if (b->links == NULL)
++              goto fail2;
 +
-+      if (recorded < bytes) {
-+              printk("%s: could only translate %ld of %ld bytes\n",
-+                     __func__, recorded, bytes);
-+              return -ENOSPC;
-+      }
++      b->orders = vmalloc(size);
++      if (b->orders == NULL)
++              goto fail3;
 +
-+      /* mark remaining addresses invalid (just for safety) */
-+      while (i < desc->nr_addrs)
-+              desc->address[i++] = XENCOMM_INVALID;
++      memset(b->links, 0, size * sizeof(struct list_head));
 +
-+      desc->magic = XENCOMM_MAGIC;
++      for (o = 0; o <= b->order; ++o)
++              INIT_LIST_HEAD(b->free_lists + o);
++
++      efrm_buddy_free_list_add(b, b->order, 0);
 +
 +      return 0;
++
++fail3:
++      vfree(b->links);
++fail2:
++      vfree(b->free_lists);
++fail1:
++      return -ENOMEM;
 +}
 +
-+static struct xencomm_desc *xencomm_alloc(gfp_t gfp_mask,
-+                                        void *buffer, unsigned long bytes)
++void efrm_buddy_dtor(struct efrm_buddy_allocator *b)
 +{
-+      struct xencomm_desc *desc;
-+      unsigned long buffer_ulong = (unsigned long)buffer;
-+      unsigned long start = buffer_ulong & PAGE_MASK;
-+      unsigned long end = (buffer_ulong + bytes) | ~PAGE_MASK;
-+      unsigned long nr_addrs = (end - start + 1) >> PAGE_SHIFT;
-+      unsigned long size = sizeof(*desc) +
-+              sizeof(desc->address[0]) * nr_addrs;
++      EFRM_ASSERT(b);
 +
-+      /*
-+       * slab allocator returns at least sizeof(void*) aligned pointer.
-+       * When sizeof(*desc) > sizeof(void*), struct xencomm_desc might
-+       * cross page boundary.
++      vfree(b->free_lists);
++      vfree(b->links);
++      vfree(b->orders);
++}
++
++int efrm_buddy_alloc(struct efrm_buddy_allocator *b, unsigned order)
++{
++      unsigned smallest;
++      unsigned addr;
++
++      DEBUG_ALLOC(EFRM_NOTICE("%s(%u)", __FUNCTION__, order));
++      EFRM_ASSERT(b);
++
++      /* Find smallest chunk that is big enough.  ?? Can optimise this by
++       ** keeping array of pointers to smallest chunk for each order.
 +       */
-+      if (sizeof(*desc) > sizeof(void*)) {
-+              unsigned long order = get_order(size);
-+              desc = (struct xencomm_desc *)__get_free_pages(gfp_mask,
-+                                                             order);
-+              if (desc == NULL)
-+                      return NULL;
++      smallest = order;
++      while (smallest <= b->order &&
++             efrm_buddy_free_list_empty(b, smallest))
++              ++smallest;
 +
-+              desc->nr_addrs =
-+                      ((PAGE_SIZE << order) - sizeof(struct xencomm_desc)) /
-+                      sizeof(*desc->address);
-+      } else {
-+              desc = kmalloc(size, gfp_mask);
-+              if (desc == NULL)
-+                      return NULL;
++      if (smallest > b->order) {
++              DEBUG_ALLOC(EFRM_NOTICE
++                          ("buddy - alloc order %d failed - max order %d",
++                           order, b->order););
++              return -ENOMEM;
++      }
 +
-+              desc->nr_addrs = nr_addrs;
++      /* Split blocks until we get one of the correct size. */
++      addr = efrm_buddy_free_list_pop(b, smallest);
++
++      DEBUG_ALLOC(EFRM_NOTICE("buddy - alloc %x order %d cut from order %d",
++                              addr, order, smallest););
++      while (smallest-- > order)
++              efrm_buddy_free_list_add(b, smallest, addr + (1 << smallest));
++
++      EFRM_DO_DEBUG(b->orders[addr] = (uint8_t) order);
++
++      EFRM_ASSERT(addr < 1u << b->order);
++      return addr;
++}
++
++void
++efrm_buddy_free(struct efrm_buddy_allocator *b, unsigned addr,
++              unsigned order)
++{
++      unsigned buddy_addr;
++
++      DEBUG_ALLOC(EFRM_NOTICE("%s(%u, %u)", __FUNCTION__, addr, order));
++      EFRM_ASSERT(b);
++      EFRM_ASSERT(order <= b->order);
++      EFRM_ASSERT((unsigned long)addr + ((unsigned long)1 << order) <=
++                  (unsigned long)1 << b->order);
++      EFRM_ASSERT(!efrm_buddy_addr_in_free_list(b, addr));
++      EFRM_ASSERT(b->orders[addr] == order);
++
++      /* merge free blocks */
++      while (order < b->order) {
++              buddy_addr = addr ^ (1 << order);
++              if (!efrm_buddy_addr_in_free_list(b, buddy_addr) ||
++                  b->orders[buddy_addr] != order)
++                      break;
++              efrm_buddy_free_list_del(b, addr);
++              if (buddy_addr < addr)
++                      addr = buddy_addr;
++              ++order;
 +      }
-+      return desc;
++
++      DEBUG_ALLOC(EFRM_NOTICE
++                  ("buddy - free %x merged into order %d", addr, order););
++      efrm_buddy_free_list_add(b, order, addr);
 +}
 +
-+void xencomm_free(struct xencomm_handle *desc)
++void efrm_buddy_reserve_at_start(struct efrm_buddy_allocator *b, unsigned n)
 +{
-+      if (desc && !((ulong)desc & XENCOMM_INLINE_FLAG)) {
-+              struct xencomm_desc *desc__ = (struct xencomm_desc*)desc;
-+              if (sizeof(*desc__) > sizeof(void*)) {
-+                      unsigned long size = sizeof(*desc__) +
-+                              sizeof(desc__->address[0]) * desc__->nr_addrs;
-+                      unsigned long order = get_order(size);
-+                      free_pages((unsigned long)__va(desc), order);
-+              } else
-+                      kfree(__va(desc));
++      int addr;
++      unsigned o;
++      EFRM_DO_DEBUG(int n_save = n);
++
++      DEBUG_ALLOC(EFRM_NOTICE("%s(%u)", __FUNCTION__, n));
++      EFRM_ASSERT(b);
++      EFRM_ASSERT(n <= 1u << b->order && n > 0);
++      /* Whole space must be free. */
++      EFRM_ASSERT(!efrm_buddy_free_list_empty(b, b->order));
++
++      o = fls(n);
++
++      while (n) {
++              while (((unsigned)1 << o) > n)
++                      --o;
++              EFRM_ASSERT(((unsigned)1 << o) <= n);
++              addr = efrm_buddy_alloc(b, o);
++              EFRM_ASSERT(addr + (1 << o) <= n_save);
++              n -= 1 << o;
 +      }
 +}
 +
-+static int xencomm_create(void *buffer, unsigned long bytes, struct xencomm_desc **ret, gfp_t gfp_mask)
++static int
++__efrm_buddy_reserve_at_end(struct efrm_buddy_allocator *b, unsigned order,
++                          int threshold)
 +{
-+      struct xencomm_desc *desc;
-+      int rc;
++      unsigned o, addr;
 +
-+      pr_debug("%s: %p[%ld]\n", __func__, buffer, bytes);
++      DEBUG_ALLOC(EFRM_NOTICE("%s(%u, %d)", __FUNCTION__, order, threshold));
++      EFRM_ASSERT(b);
 +
-+      if (bytes == 0) {
-+              /* don't create a descriptor; Xen recognizes NULL. */
-+              BUG_ON(buffer != NULL);
-+              *ret = NULL;
-+              return 0;
++      /* Find largest block; there must be one big enough (or caller has
++       ** goofed).
++       */
++      for (o = b->order;; --o) {
++              if (efrm_buddy_free_list_empty(b, o))
++                      continue;
++              addr = efrm_buddy_free_list_first(b, o);
++              if (addr + (1 << o) <= (unsigned)threshold)
++                      continue;
++              break;
 +      }
++      EFRM_ASSERT(o >= order);
 +
-+      BUG_ON(buffer == NULL); /* 'bytes' is non-zero */
++      /* Split down (keeping second half) until we reach
++       * the requested size. */
++      addr = efrm_buddy_free_list_pop(b, o);
 +
-+      desc = xencomm_alloc(gfp_mask, buffer, bytes);
-+      if (!desc) {
-+              printk("%s failure\n", "xencomm_alloc");
-+              return -ENOMEM;
++      while (o-- > order) {
++              efrm_buddy_free_list_add(b, o, addr);
++              addr += 1 << o;
 +      }
 +
-+      rc = xencomm_init(desc, buffer, bytes);
-+      if (rc) {
-+              printk("%s failure: %d\n", "xencomm_init", rc);
-+              xencomm_free((struct xencomm_handle *)__pa(desc));
-+              return rc;
-+      }
++      EFRM_DO_DEBUG(b->orders[addr] = (uint8_t) order);
 +
-+      *ret = desc;
-+      return 0;
++      return addr;
 +}
 +
-+/* check if memory address is within VMALLOC region  */
-+static int is_phys_contiguous(unsigned long addr)
++void efrm_buddy_reserve_at_end(struct efrm_buddy_allocator *b, unsigned n)
 +{
-+      if (!is_kernel_addr(addr))
-+              return 0;
++      int addr, threshold;
++      unsigned o;
++      EFRM_DO_DEBUG(int n_save = n);
 +
-+      return (addr < VMALLOC_START) || (addr >= VMALLOC_END);
-+}
++      DEBUG_ALLOC(EFRM_NOTICE("%s(%u)", __FUNCTION__, n));
++      DEBUG_ALLOC(efrm_buddy_dump(b));
++      EFRM_ASSERT(b);
++      EFRM_ASSERT(n <= 1u << b->order);
 +
-+static struct xencomm_handle *xencomm_create_inline(void *ptr)
-+{
-+      unsigned long paddr;
++      if (!n)
++        return;
 +
-+      BUG_ON(!is_phys_contiguous((unsigned long)ptr));
++      threshold = (1 << b->order) - n;
++      o = fls(n);
 +
-+      paddr = (unsigned long)xencomm_pa(ptr);
-+      BUG_ON(paddr & XENCOMM_INLINE_FLAG);
-+      return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG);
++      while (n) {
++              while (((unsigned)1 << o) > n)
++                      --o;
++              EFRM_ASSERT(((unsigned)1 << o) <= n);
++              addr = __efrm_buddy_reserve_at_end(b, o, threshold);
++              EFRM_ASSERT(addr >= (1 << b->order) - n_save);
++              n -= 1 << o;
++      }
++      DEBUG_ALLOC(efrm_buddy_dump(b));
 +}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/buffer_table.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/buffer_table.c    2008-05-19 00:33:29.325836502 +0300
+@@ -0,0 +1,210 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains abstraction of the buffer table on the NIC.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+/* "mini" routine, for stack-based communications: */
-+static int xencomm_create_mini(void *buffer,
-+      unsigned long bytes, struct xencomm_mini *xc_desc,
-+      struct xencomm_desc **ret)
-+{
-+      int rc = 0;
-+      struct xencomm_desc *desc;
-+      BUG_ON(((unsigned long)xc_desc) % sizeof(*xc_desc) != 0);
-+
-+      desc = (void *)xc_desc; 
++/*
++** Might be worth keeping a bitmap of which entries are clear.  Then we
++** wouldn't need to clear them all again when we free an allocation.
++*/
 +
-+      desc->nr_addrs = XENCOMM_MINI_ADDRS;
++#include <ci/efrm/debug.h>
++#include <ci/driver/efab/hardware.h>
++#include <ci/efrm/nic_table.h>
++#include <ci/efrm/buffer_table.h>
++#include <ci/efrm/buddy.h>
 +
-+      if (!(rc = xencomm_init(desc, buffer, bytes)))
-+              *ret = desc;
++/*! Comment? */
++struct efrm_buffer_table {
++      spinlock_t lock;
++      struct efrm_buddy_allocator buddy;
++};
 +
-+      return rc;
-+}
++/* Efab buffer state. */
++static struct efrm_buffer_table efrm_buffers;
 +
-+struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes)
++int efrm_buffer_table_ctor(unsigned low, unsigned high)
 +{
-+      int rc;
-+      struct xencomm_desc *desc;
++      int log2_n_entries, rc;
 +
-+      if (is_phys_contiguous((unsigned long)ptr))
-+              return xencomm_create_inline(ptr);
++      EFRM_ASSERT(high > 0);
++      EFRM_ASSERT(low < high);
 +
-+      rc = xencomm_create(ptr, bytes, &desc, GFP_KERNEL);
++      EFRM_TRACE("efrm_buffer_table_ctor: low=%u high=%u", low, high);
++      EFRM_NOTICE("efrm_buffer_table_ctor: low=%u high=%u", low, high);
 +
-+      if (rc || desc == NULL)
-+              return NULL;
++      log2_n_entries = fls(high - 1);
 +
-+      return xencomm_pa(desc);
-+}
++      rc = efrm_buddy_ctor(&efrm_buffers.buddy, log2_n_entries);
++      if (rc < 0) {
++              EFRM_ERR("efrm_buffer_table_ctor: efrm_buddy_ctor(%d) "
++                       "failed (%d)", log2_n_entries, rc);
++              return rc;
++      }
 +
-+struct xencomm_handle *__xencomm_map_no_alloc(void *ptr, unsigned long bytes, 
-+                      struct xencomm_mini *xc_desc)
-+{
-+      int rc;
-+      struct xencomm_desc *desc = NULL;
++      spin_lock_init(&efrm_buffers.lock);
 +
-+      if (is_phys_contiguous((unsigned long)ptr))
-+              return xencomm_create_inline(ptr);
++      efrm_buddy_reserve_at_start(&efrm_buffers.buddy, low);
++      efrm_buddy_reserve_at_end(&efrm_buffers.buddy,
++                                (1 << log2_n_entries) - high);
 +
-+      rc = xencomm_create_mini(ptr, bytes, xc_desc,
-+                              &desc);
++      EFRM_TRACE("efrm_buffer_table_ctor: done");
 +
-+      if (rc)
-+              return NULL;
-+ 
-+      return xencomm_pa(desc);
++      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/xen_proc.c linux-2.6.18-xen.hg/drivers/xen/core/xen_proc.c
---- linux-2.6.18/drivers/xen/core/xen_proc.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/xen_proc.c    2007-12-23 11:15:33.674582320 +0100
-@@ -0,0 +1,23 @@
 +
-+#include <linux/module.h>
-+#include <linux/proc_fs.h>
-+#include <xen/xen_proc.h>
++void efrm_buffer_table_dtor(void)
++{
++      /* ?? debug check that all allocations have been freed? */
 +
-+static struct proc_dir_entry *xen_base;
++      spin_lock_destroy(&efrm_buffers.lock);
++      efrm_buddy_dtor(&efrm_buffers.buddy);
 +
-+struct proc_dir_entry *create_xen_proc_entry(const char *name, mode_t mode)
-+{
-+      if ( xen_base == NULL )
-+              if ( (xen_base = proc_mkdir("xen", &proc_root)) == NULL )
-+                      panic("Couldn't create /proc/xen");
-+      return create_proc_entry(name, mode, xen_base);
++      EFRM_TRACE("efrm_buffer_table_dtor: done");
 +}
 +
-+EXPORT_SYMBOL_GPL(create_xen_proc_entry); 
++/**********************************************************************/
 +
-+void remove_xen_proc_entry(const char *name)
++int
++efrm_buffer_table_alloc(unsigned order,
++                      struct efhw_buffer_table_allocation *a)
 +{
-+      remove_proc_entry(name, xen_base);
-+}
++      irq_flags_t lock_flags;
++      int rc;
 +
-+EXPORT_SYMBOL_GPL(remove_xen_proc_entry); 
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/core/xen_sysfs.c linux-2.6.18-xen.hg/drivers/xen/core/xen_sysfs.c
---- linux-2.6.18/drivers/xen/core/xen_sysfs.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/core/xen_sysfs.c   2007-12-23 11:15:33.867925803 +0100
-@@ -0,0 +1,378 @@
-+/*
-+ *  copyright (c) 2006 IBM Corporation
-+ *  Authored by: Mike D. Day <ncmike@us.ibm.com>
-+ *
-+ *  This program is free software; you can redistribute it and/or modify
-+ *  it under the terms of the GNU General Public License version 2 as
-+ *  published by the Free Software Foundation.
-+ */
++      EFRM_ASSERT(&efrm_buffers.buddy);
++      EFRM_ASSERT(a);
 +
-+#include <linux/err.h>
-+#include <linux/kernel.h>
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <asm/hypervisor.h>
-+#include <xen/features.h>
-+#include <xen/hypervisor_sysfs.h>
-+#include <xen/xenbus.h>
++      /* Round up to multiple of two, as the buffer clear logic works in
++       * pairs when not in "full" mode. */
++      order = max_t(unsigned, order, 1);
 +
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR("Mike D. Day <ncmike@us.ibm.com>");
++      spin_lock_irqsave(&efrm_buffers.lock, lock_flags);
++      rc = efrm_buddy_alloc(&efrm_buffers.buddy, order);
++      spin_unlock_irqrestore(&efrm_buffers.lock, lock_flags);
 +
-+static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer)
-+{
-+      return sprintf(buffer, "xen\n");
-+}
++      if (rc < 0) {
++              EFRM_ERR("efrm_buffer_table_alloc: failed (n=%ld) rc %d",
++                       1ul << order, rc);
++              return rc;
++      }
 +
-+HYPERVISOR_ATTR_RO(type);
++      EFRM_TRACE("efrm_buffer_table_alloc: base=%d n=%ld",
++                 rc, 1ul << order);
++      a->order = order;
++      a->base = (unsigned)rc;
++      return 0;
++}
 +
-+static int __init xen_sysfs_type_init(void)
++void efrm_buffer_table_free(struct efhw_buffer_table_allocation *a)
 +{
-+      return sysfs_create_file(&hypervisor_subsys.kset.kobj, &type_attr.attr);
++      irq_flags_t lock_flags;
++      struct efhw_nic *nic;
++      int nic_i;
++
++      EFRM_ASSERT(&efrm_buffers.buddy);
++      EFRM_ASSERT(a);
++      EFRM_ASSERT(a->base != -1);
++      EFRM_ASSERT((unsigned long)a->base + (1ul << a->order) <=
++                  efrm_buddy_size(&efrm_buffers.buddy));
++
++      EFRM_TRACE("efrm_buffer_table_free: base=%d n=%ld",
++                 a->base, (1ul << a->order));
++
++      EFRM_FOR_EACH_NIC(nic_i, nic)
++          efhw_nic_buffer_table_clear(nic, a->base, 1ul << a->order);
++
++      spin_lock_irqsave(&efrm_buffers.lock, lock_flags);
++      efrm_buddy_free(&efrm_buffers.buddy, a->base, a->order);
++      spin_unlock_irqrestore(&efrm_buffers.lock, lock_flags);
++
++      EFRM_DO_DEBUG(a->base = a->order = -1);
 +}
 +
-+static void xen_sysfs_type_destroy(void)
++/**********************************************************************/
++
++void
++efrm_buffer_table_set(struct efhw_buffer_table_allocation *a,
++                    unsigned i, dma_addr_t dma_addr, int owner)
 +{
-+      sysfs_remove_file(&hypervisor_subsys.kset.kobj, &type_attr.attr);
++      struct efhw_nic *nic;
++      int nic_i;
++
++      EFRM_ASSERT(a);
++      EFRM_ASSERT(i < (unsigned)1 << a->order);
++      EFRM_FOR_EACH_NIC(nic_i, nic)
++          efhw_nic_buffer_table_set(nic, dma_addr, EFHW_NIC_PAGE_SIZE,
++                                    0, owner, a->base + i);
++      /* NB. No commit Caller should call efrm_buffer_table_commit. There
++         are underlying hardware constraints regarding the number of
++         buffer table entries which can be pushed before commiting. */
 +}
 +
-+/* xen version attributes */
-+static ssize_t major_show(struct hyp_sysfs_attr *attr, char *buffer)
++unsigned long efrm_buffer_table_size(void)
 +{
-+      int version = HYPERVISOR_xen_version(XENVER_version, NULL);
-+      if (version)
-+              return sprintf(buffer, "%d\n", version >> 16);
-+      return -ENODEV;
++      return efrm_buddy_size(&efrm_buffers.buddy);
 +}
 +
-+HYPERVISOR_ATTR_RO(major);
++/**********************************************************************/
 +
-+static ssize_t minor_show(struct hyp_sysfs_attr *attr, char *buffer)
++int
++efrm_page_register(dma_addr_t dma_addr, int owner,
++                 efhw_buffer_addr_t *buf_addr_out)
 +{
-+      int version = HYPERVISOR_xen_version(XENVER_version, NULL);
-+      if (version)
-+              return sprintf(buffer, "%d\n", version & 0xff);
-+      return -ENODEV;
++      struct efhw_buffer_table_allocation alloc;
++      int rc;
++
++      rc = efrm_buffer_table_alloc(0, &alloc);
++      if (rc == 0) {
++              efrm_buffer_table_set(&alloc, 0, dma_addr, owner);
++              efrm_buffer_table_commit();
++              *buf_addr_out = EFHW_BUFFER_ADDR(alloc.base, 0);
++      }
++      return rc;
 +}
++EXPORT_SYMBOL(efrm_page_register);
 +
-+HYPERVISOR_ATTR_RO(minor);
-+
-+static ssize_t extra_show(struct hyp_sysfs_attr *attr, char *buffer)
++void efrm_page_unregister(efhw_buffer_addr_t buf_addr)
 +{
-+      int ret = -ENOMEM;
-+      char *extra;
++      struct efhw_buffer_table_allocation alloc;
 +
-+      extra = kmalloc(XEN_EXTRAVERSION_LEN, GFP_KERNEL);
-+      if (extra) {
-+              ret = HYPERVISOR_xen_version(XENVER_extraversion, extra);
-+              if (!ret)
-+                      ret = sprintf(buffer, "%s\n", extra);
-+              kfree(extra);
-+      }
++      alloc.order = 0;
++      alloc.base = EFHW_BUFFER_PAGE(buf_addr);
++      efrm_buffer_table_free(&alloc);
++}
++EXPORT_SYMBOL(efrm_page_unregister);
 +
-+      return ret;
++void efrm_buffer_table_commit(void)
++{
++      struct efhw_nic *nic;
++      int nic_i;
++
++      EFRM_FOR_EACH_NIC(nic_i, nic)
++          efhw_nic_buffer_table_commit(nic);
 +}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/common.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/common.h  2008-05-19 00:33:29.329836732 +0300
+@@ -0,0 +1,68 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides EtherFabric NIC hardware interface common
++ * definitions.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_DRIVER_EFAB_HARDWARE_COMMON_H__
++#define __CI_DRIVER_EFAB_HARDWARE_COMMON_H__
++
++/*----------------------------------------------------------------------------
++ *
++ * EtherFabric constants
++ *
++ *---------------------------------------------------------------------------*/
++
++#define EFHW_1K               0x00000400u
++#define EFHW_2K               0x00000800u
++#define EFHW_4K               0x00001000u
++#define EFHW_8K               0x00002000u
++#define EFHW_16K      0x00004000u
++#define EFHW_32K      0x00008000u
++#define EFHW_64K      0x00010000u
++#define EFHW_128K     0x00020000u
++#define EFHW_256K     0x00040000u
++#define EFHW_512K     0x00080000u
++#define EFHW_1M               0x00100000u
++#define EFHW_2M               0x00200000u
++#define EFHW_4M               0x00400000u
++#define EFHW_8M               0x00800000u
++#define EFHW_16M      0x01000000u
++#define EFHW_32M      0x02000000u
++#define EFHW_48M      0x03000000u
++#define EFHW_64M      0x04000000u
++#define EFHW_128M     0x08000000u
++#define EFHW_256M     0x10000000u
++#define EFHW_512M     0x20000000u
++#define EFHW_1G       0x40000000u
++#define EFHW_2G               0x80000000u
++#define EFHW_4G               0x100000000ULL
++#define EFHW_8G               0x200000000ULL
++
++#endif /* __CI_DRIVER_EFAB_HARDWARE_COMMON_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_core.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_core.h      2008-05-19 00:33:29.329836732 +0300
+@@ -0,0 +1,1149 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) core register
++ * definitions.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#define  FALCON_EXTENDED_P_BAR 1
++
++/*************---- Bus Interface Unit Registers C Header ----*************/
++#define IOM_IND_ADR_REG_OFST 0x0 /* IO-mapped indirect access address
++                                  register */
++  #define IOM_AUTO_ADR_INC_EN_LBN 16
++  #define IOM_AUTO_ADR_INC_EN_WIDTH 1
++  #define IOM_IND_ADR_LBN 0
++  #define IOM_IND_ADR_WIDTH 16
++#define IOM_IND_DAT_REG_OFST 0x4 /* IO-mapped indirect access data register */
++  #define IOM_IND_DAT_LBN 0
++  #define IOM_IND_DAT_WIDTH 32
++#define ADR_REGION_REG_KER_OFST 0x0 /* Address region register */
++#define ADR_REGION_REG_OFST 0x0 /* Address region register */
++  #define ADR_REGION3_LBN 96
++  #define ADR_REGION3_WIDTH 18
++  #define ADR_REGION2_LBN 64
++  #define ADR_REGION2_WIDTH 18
++  #define ADR_REGION1_LBN 32
++  #define ADR_REGION1_WIDTH 18
++  #define ADR_REGION0_LBN 0
++  #define ADR_REGION0_WIDTH 18
++#define INT_EN_REG_KER_OFST 0x10 /* Kernel driver Interrupt enable register */
++  #define KER_INT_CHAR_LBN 4
++  #define KER_INT_CHAR_WIDTH 1
++  #define KER_INT_KER_LBN 3
++  #define KER_INT_KER_WIDTH 1
++  #define ILL_ADR_ERR_INT_EN_KER_LBN 2
++  #define ILL_ADR_ERR_INT_EN_KER_WIDTH 1
++  #define SRM_PERR_INT_EN_KER_LBN 1
++  #define SRM_PERR_INT_EN_KER_WIDTH 1
++  #define DRV_INT_EN_KER_LBN 0
++  #define DRV_INT_EN_KER_WIDTH 1
++#define INT_EN_REG_CHAR_OFST 0x20 /* Char Driver interrupt enable register */
++  #define CHAR_INT_CHAR_LBN 4
++  #define CHAR_INT_CHAR_WIDTH 1
++  #define CHAR_INT_KER_LBN 3
++  #define CHAR_INT_KER_WIDTH 1
++  #define ILL_ADR_ERR_INT_EN_CHAR_LBN 2
++  #define ILL_ADR_ERR_INT_EN_CHAR_WIDTH 1
++  #define SRM_PERR_INT_EN_CHAR_LBN 1
++  #define SRM_PERR_INT_EN_CHAR_WIDTH 1
++  #define DRV_INT_EN_CHAR_LBN 0
++  #define DRV_INT_EN_CHAR_WIDTH 1
++#define INT_ADR_REG_KER_OFST 0x30 /* Interrupt host address for Kernel driver */
++  #define INT_ADR_KER_LBN 0
++  #define INT_ADR_KER_WIDTH 64
++  #define DRV_INT_KER_LBN 32
++  #define DRV_INT_KER_WIDTH 1
++  #define EV_FF_HALF_INT_KER_LBN 3
++  #define EV_FF_HALF_INT_KER_WIDTH 1
++  #define EV_FF_FULL_INT_KER_LBN 2
++  #define EV_FF_FULL_INT_KER_WIDTH 1
++  #define ILL_ADR_ERR_INT_KER_LBN 1
++  #define ILL_ADR_ERR_INT_KER_WIDTH 1
++  #define SRAM_PERR_INT_KER_LBN 0
++  #define SRAM_PERR_INT_KER_WIDTH 1
++#define INT_ADR_REG_CHAR_OFST 0x40 /* Interrupt host address for Char driver */
++  #define INT_ADR_CHAR_LBN 0
++  #define INT_ADR_CHAR_WIDTH 64
++  #define DRV_INT_CHAR_LBN 32
++  #define DRV_INT_CHAR_WIDTH 1
++  #define EV_FF_HALF_INT_CHAR_LBN 3
++  #define EV_FF_HALF_INT_CHAR_WIDTH 1
++  #define EV_FF_FULL_INT_CHAR_LBN 2
++  #define EV_FF_FULL_INT_CHAR_WIDTH 1
++  #define ILL_ADR_ERR_INT_CHAR_LBN 1
++  #define ILL_ADR_ERR_INT_CHAR_WIDTH 1
++  #define SRAM_PERR_INT_CHAR_LBN 0
++  #define SRAM_PERR_INT_CHAR_WIDTH 1
++#define INT_ISR0_B0_OFST 0x90 /* B0 only */
++#define INT_ISR1_B0_OFST 0xA0
++#define INT_ACK_REG_KER_A1_OFST 0x50 /* Kernel interrupt acknowledge register */
++  #define RESERVED_LBN 0
++  #define RESERVED_WIDTH 32
++#define INT_ACK_REG_CHAR_A1_OFST 0x60 /* CHAR interrupt acknowledge register */
++  #define RESERVED_LBN 0
++  #define RESERVED_WIDTH 32
++/*************---- Global CSR Registers C Header ----*************/
++#define STRAP_REG_KER_OFST 0x200 /* ASIC strap status register */
++#define STRAP_REG_OFST 0x200 /* ASIC strap status register */
++  #define ONCHIP_SRAM_LBN 16
++  #define ONCHIP_SRAM_WIDTH 0
++  #define STRAP_ISCSI_EN_LBN 3
++  #define STRAP_ISCSI_EN_WIDTH 1
++  #define STRAP_PINS_LBN 0
++  #define STRAP_PINS_WIDTH 3
++#define GPIO_CTL_REG_KER_OFST 0x210 /* GPIO control register */
++#define GPIO_CTL_REG_OFST 0x210 /* GPIO control register */
++  #define GPIO_OEN_LBN 24
++  #define GPIO_OEN_WIDTH 4
++  #define GPIO_OUT_LBN 16
++  #define GPIO_OUT_WIDTH 4
++  #define GPIO_IN_LBN 8
++  #define GPIO_IN_WIDTH 4
++  #define GPIO_PWRUP_VALUE_LBN 0
++  #define GPIO_PWRUP_VALUE_WIDTH 4
++#define GLB_CTL_REG_KER_OFST 0x220 /* Global control register */
++#define GLB_CTL_REG_OFST 0x220 /* Global control register */
++  #define SWRST_LBN 0
++  #define SWRST_WIDTH 1
++#define FATAL_INTR_REG_KER_OFST 0x230 /* Fatal interrupt register for Kernel */
++  #define PCI_BUSERR_INT_KER_EN_LBN 43
++  #define PCI_BUSERR_INT_KER_EN_WIDTH 1
++  #define SRAM_OOB_INT_KER_EN_LBN 42
++  #define SRAM_OOB_INT_KER_EN_WIDTH 1
++  #define BUFID_OOB_INT_KER_EN_LBN 41
++  #define BUFID_OOB_INT_KER_EN_WIDTH 1
++  #define MEM_PERR_INT_KER_EN_LBN 40
++  #define MEM_PERR_INT_KER_EN_WIDTH 1
++  #define RBUF_OWN_INT_KER_EN_LBN 39
++  #define RBUF_OWN_INT_KER_EN_WIDTH 1
++  #define TBUF_OWN_INT_KER_EN_LBN 38
++  #define TBUF_OWN_INT_KER_EN_WIDTH 1
++  #define RDESCQ_OWN_INT_KER_EN_LBN 37
++  #define RDESCQ_OWN_INT_KER_EN_WIDTH 1
++  #define TDESCQ_OWN_INT_KER_EN_LBN 36
++  #define TDESCQ_OWN_INT_KER_EN_WIDTH 1
++  #define EVQ_OWN_INT_KER_EN_LBN 35
++  #define EVQ_OWN_INT_KER_EN_WIDTH 1
++  #define EVFF_OFLO_INT_KER_EN_LBN 34
++  #define EVFF_OFLO_INT_KER_EN_WIDTH 1
++  #define ILL_ADR_INT_KER_EN_LBN 33
++  #define ILL_ADR_INT_KER_EN_WIDTH 1
++  #define SRM_PERR_INT_KER_EN_LBN 32
++  #define SRM_PERR_INT_KER_EN_WIDTH 1
++  #define PCI_BUSERR_INT_KER_LBN 11
++  #define PCI_BUSERR_INT_KER_WIDTH 1
++  #define SRAM_OOB_INT_KER_LBN 10
++  #define SRAM_OOB_INT_KER_WIDTH 1
++  #define BUFID_OOB_INT_KER_LBN 9
++  #define BUFID_OOB_INT_KER_WIDTH 1
++  #define MEM_PERR_INT_KER_LBN 8
++  #define MEM_PERR_INT_KER_WIDTH 1
++  #define RBUF_OWN_INT_KER_LBN 7
++  #define RBUF_OWN_INT_KER_WIDTH 1
++  #define TBUF_OWN_INT_KER_LBN 6
++  #define TBUF_OWN_INT_KER_WIDTH 1
++  #define RDESCQ_OWN_INT_KER_LBN 5
++  #define RDESCQ_OWN_INT_KER_WIDTH 1
++  #define TDESCQ_OWN_INT_KER_LBN 4
++  #define TDESCQ_OWN_INT_KER_WIDTH 1
++  #define EVQ_OWN_INT_KER_LBN 3
++  #define EVQ_OWN_INT_KER_WIDTH 1
++  #define EVFF_OFLO_INT_KER_LBN 2
++  #define EVFF_OFLO_INT_KER_WIDTH 1
++  #define ILL_ADR_INT_KER_LBN 1
++  #define ILL_ADR_INT_KER_WIDTH 1
++  #define SRM_PERR_INT_KER_LBN 0
++  #define SRM_PERR_INT_KER_WIDTH 1
++#define FATAL_INTR_REG_OFST 0x240 /* Fatal interrupt register for Char */
++  #define PCI_BUSERR_INT_CHAR_EN_LBN 43
++  #define PCI_BUSERR_INT_CHAR_EN_WIDTH 1
++  #define SRAM_OOB_INT_CHAR_EN_LBN 42
++  #define SRAM_OOB_INT_CHAR_EN_WIDTH 1
++  #define BUFID_OOB_INT_CHAR_EN_LBN 41
++  #define BUFID_OOB_INT_CHAR_EN_WIDTH 1
++  #define MEM_PERR_INT_CHAR_EN_LBN 40
++  #define MEM_PERR_INT_CHAR_EN_WIDTH 1
++  #define RBUF_OWN_INT_CHAR_EN_LBN 39
++  #define RBUF_OWN_INT_CHAR_EN_WIDTH 1
++  #define TBUF_OWN_INT_CHAR_EN_LBN 38
++  #define TBUF_OWN_INT_CHAR_EN_WIDTH 1
++  #define RDESCQ_OWN_INT_CHAR_EN_LBN 37
++  #define RDESCQ_OWN_INT_CHAR_EN_WIDTH 1
++  #define TDESCQ_OWN_INT_CHAR_EN_LBN 36
++  #define TDESCQ_OWN_INT_CHAR_EN_WIDTH 1
++  #define EVQ_OWN_INT_CHAR_EN_LBN 35
++  #define EVQ_OWN_INT_CHAR_EN_WIDTH 1
++  #define EVFF_OFLO_INT_CHAR_EN_LBN 34
++  #define EVFF_OFLO_INT_CHAR_EN_WIDTH 1
++  #define ILL_ADR_INT_CHAR_EN_LBN 33
++  #define ILL_ADR_INT_CHAR_EN_WIDTH 1
++  #define SRM_PERR_INT_CHAR_EN_LBN 32
++  #define SRM_PERR_INT_CHAR_EN_WIDTH 1
++  #define FATAL_INTR_REG_EN_BITS    0xffffffffffffffffULL
++  #define PCI_BUSERR_INT_CHAR_LBN 11
++  #define PCI_BUSERR_INT_CHAR_WIDTH 1
++  #define SRAM_OOB_INT_CHAR_LBN 10
++  #define SRAM_OOB_INT_CHAR_WIDTH 1
++  #define BUFID_OOB_INT_CHAR_LBN 9
++  #define BUFID_OOB_INT_CHAR_WIDTH 1
++  #define MEM_PERR_INT_CHAR_LBN 8
++  #define MEM_PERR_INT_CHAR_WIDTH 1
++  #define RBUF_OWN_INT_CHAR_LBN 7
++  #define RBUF_OWN_INT_CHAR_WIDTH 1
++  #define TBUF_OWN_INT_CHAR_LBN 6
++  #define TBUF_OWN_INT_CHAR_WIDTH 1
++  #define RDESCQ_OWN_INT_CHAR_LBN 5
++  #define RDESCQ_OWN_INT_CHAR_WIDTH 1
++  #define TDESCQ_OWN_INT_CHAR_LBN 4
++  #define TDESCQ_OWN_INT_CHAR_WIDTH 1
++  #define EVQ_OWN_INT_CHAR_LBN 3
++  #define EVQ_OWN_INT_CHAR_WIDTH 1
++  #define EVFF_OFLO_INT_CHAR_LBN 2
++  #define EVFF_OFLO_INT_CHAR_WIDTH 1
++  #define ILL_ADR_INT_CHAR_LBN 1
++  #define ILL_ADR_INT_CHAR_WIDTH 1
++  #define SRM_PERR_INT_CHAR_LBN 0
++  #define SRM_PERR_INT_CHAR_WIDTH 1
++#define DP_CTRL_REG_OFST 0x250 /* Datapath control register */
++  #define FLS_EVQ_ID_LBN 0
++  #define FLS_EVQ_ID_WIDTH 12
++#define MEM_STAT_REG_KER_OFST 0x260 /* Memory status register */
++#define MEM_STAT_REG_OFST 0x260 /* Memory status register */
++  #define MEM_PERR_VEC_LBN 53
++  #define MEM_PERR_VEC_WIDTH 38
++  #define MBIST_CORR_LBN 38
++  #define MBIST_CORR_WIDTH 15
++  #define MBIST_ERR_LBN 0
++  #define MBIST_ERR_WIDTH 38
++#define DEBUG_REG_KER_OFST 0x270 /* Debug register */
++#define DEBUG_REG_OFST 0x270 /* Debug register */
++  #define DEBUG_BLK_SEL2_LBN 47
++  #define DEBUG_BLK_SEL2_WIDTH 3
++  #define DEBUG_BLK_SEL1_LBN 44
++  #define DEBUG_BLK_SEL1_WIDTH 3
++  #define DEBUG_BLK_SEL0_LBN 41
++  #define DEBUG_BLK_SEL0_WIDTH 3
++  #define MISC_DEBUG_ADDR_LBN 36
++  #define MISC_DEBUG_ADDR_WIDTH 5
++  #define SERDES_DEBUG_ADDR_LBN 31
++  #define SERDES_DEBUG_ADDR_WIDTH 5
++  #define EM_DEBUG_ADDR_LBN 26
++  #define EM_DEBUG_ADDR_WIDTH 5
++  #define SR_DEBUG_ADDR_LBN 21
++  #define SR_DEBUG_ADDR_WIDTH 5
++  #define EV_DEBUG_ADDR_LBN 16
++  #define EV_DEBUG_ADDR_WIDTH 5
++  #define RX_DEBUG_ADDR_LBN 11
++  #define RX_DEBUG_ADDR_WIDTH 5
++  #define TX_DEBUG_ADDR_LBN 6
++  #define TX_DEBUG_ADDR_WIDTH 5
++  #define BIU_DEBUG_ADDR_LBN 1
++  #define BIU_DEBUG_ADDR_WIDTH 5
++  #define DEBUG_EN_LBN 0
++  #define DEBUG_EN_WIDTH 1
++#define DRIVER_REG0_KER_OFST 0x280 /* Driver scratch register 0 */
++#define DRIVER_REG0_OFST 0x280 /* Driver scratch register 0 */
++  #define DRIVER_DW0_LBN 0
++  #define DRIVER_DW0_WIDTH 32
++#define DRIVER_REG1_KER_OFST 0x290 /* Driver scratch register 1 */
++#define DRIVER_REG1_OFST 0x290 /* Driver scratch register 1 */
++  #define DRIVER_DW1_LBN 0
++  #define DRIVER_DW1_WIDTH 32
++#define DRIVER_REG2_KER_OFST 0x2A0 /* Driver scratch register 2 */
++#define DRIVER_REG2_OFST 0x2A0 /* Driver scratch register 2 */
++  #define DRIVER_DW2_LBN 0
++  #define DRIVER_DW2_WIDTH 32
++#define DRIVER_REG3_KER_OFST 0x2B0 /* Driver scratch register 3 */
++#define DRIVER_REG3_OFST 0x2B0 /* Driver scratch register 3 */
++  #define DRIVER_DW3_LBN 0
++  #define DRIVER_DW3_WIDTH 32
++#define DRIVER_REG4_KER_OFST 0x2C0 /* Driver scratch register 4 */
++#define DRIVER_REG4_OFST 0x2C0 /* Driver scratch register 4 */
++  #define DRIVER_DW4_LBN 0
++  #define DRIVER_DW4_WIDTH 32
++#define DRIVER_REG5_KER_OFST 0x2D0 /* Driver scratch register 5 */
++#define DRIVER_REG5_OFST 0x2D0 /* Driver scratch register 5 */
++  #define DRIVER_DW5_LBN 0
++  #define DRIVER_DW5_WIDTH 32
++#define DRIVER_REG6_KER_OFST 0x2E0 /* Driver scratch register 6 */
++#define DRIVER_REG6_OFST 0x2E0 /* Driver scratch register 6 */
++  #define DRIVER_DW6_LBN 0
++  #define DRIVER_DW6_WIDTH 32
++#define DRIVER_REG7_KER_OFST 0x2F0 /* Driver scratch register 7 */
++#define DRIVER_REG7_OFST 0x2F0 /* Driver scratch register 7 */
++  #define DRIVER_DW7_LBN 0
++  #define DRIVER_DW7_WIDTH 32
++#define ALTERA_BUILD_REG_OFST 0x300 /* Altera build register */
++#define ALTERA_BUILD_REG_OFST 0x300 /* Altera build register */
++  #define ALTERA_BUILD_VER_LBN 0
++  #define ALTERA_BUILD_VER_WIDTH 32
++
++/* so called CSR spare register
++    - contains separate parity enable bits for the various internal memory
++    blocks */
++#define MEM_PARITY_ERR_EN_REG_KER 0x310
++#define MEM_PARITY_ALL_BLOCKS_EN_LBN 64
++#define MEM_PARITY_ALL_BLOCKS_EN_WIDTH 38
++#define MEM_PARITY_TX_DATA_EN_LBN   72
++#define MEM_PARITY_TX_DATA_EN_WIDTH 2
++
++/*************---- Event & Timer Module Registers C Header ----*************/
++
++#if FALCON_EXTENDED_P_BAR
++#define EVQ_RPTR_REG_KER_OFST 0x11B00 /* Event queue read pointer register */
++#else
++#define EVQ_RPTR_REG_KER_OFST 0x1B00 /* Event queue read pointer register */
++#endif
 +
-+HYPERVISOR_ATTR_RO(extra);
++#define EVQ_RPTR_REG_OFST 0xFA0000 /* Event queue read pointer register
++                                    array. */
++  #define EVQ_RPTR_LBN 0
++  #define EVQ_RPTR_WIDTH 15
 +
-+static struct attribute *version_attrs[] = {
-+      &major_attr.attr,
-+      &minor_attr.attr,
-+      &extra_attr.attr,
-+      NULL
-+};
++#if FALCON_EXTENDED_P_BAR
++#define EVQ_PTR_TBL_KER_OFST 0x11A00 /* Event queue pointer table for kernel
++                                      access */
++#else
++#define EVQ_PTR_TBL_KER_OFST 0x1A00 /* Event queue pointer table for kernel
++                                     access */
++#endif
++
++#define EVQ_PTR_TBL_CHAR_OFST 0xF60000 /* Event queue pointer table for char
++                                        direct access */
++  #define EVQ_WKUP_OR_INT_EN_LBN 39
++  #define EVQ_WKUP_OR_INT_EN_WIDTH 1
++  #define EVQ_NXT_WPTR_LBN 24
++  #define EVQ_NXT_WPTR_WIDTH 15
++  #define EVQ_EN_LBN 23
++  #define EVQ_EN_WIDTH 1
++  #define EVQ_SIZE_LBN 20
++  #define EVQ_SIZE_WIDTH 3
++  #define EVQ_BUF_BASE_ID_LBN 0
++  #define EVQ_BUF_BASE_ID_WIDTH 20
++#define TIMER_CMD_REG_KER_OFST 0x420 /* Timer table for kernel access.
++                                      Page-mapped */
++#define TIMER_CMD_REG_PAGE4_OFST 0x8420 /* Timer table for user-level access.
++                                         Page-mapped. For lowest 1K queues.
++                                       */
++#define TIMER_CMD_REG_PAGE123K_OFST 0x1000420 /* Timer table for user-level
++                                               access. Page-mapped.
++                                               For upper 3K queues. */
++#define TIMER_TBL_OFST 0xF70000 /* Timer table for char driver direct access */
++  #define TIMER_MODE_LBN 12
++  #define TIMER_MODE_WIDTH 2
++  #define TIMER_VAL_LBN 0
++  #define TIMER_VAL_WIDTH 12
++  #define TIMER_MODE_INT_HLDOFF 2
++  #define EVQ_BUF_SIZE_LBN 0
++  #define EVQ_BUF_SIZE_WIDTH 1
++#define DRV_EV_REG_KER_OFST 0x440 /* Driver generated event register */
++#define DRV_EV_REG_OFST 0x440 /* Driver generated event register */
++  #define DRV_EV_QID_LBN 64
++  #define DRV_EV_QID_WIDTH 12
++  #define DRV_EV_DATA_LBN 0
++  #define DRV_EV_DATA_WIDTH 64
++#define EVQ_CTL_REG_KER_OFST 0x450 /* Event queue control register */
++#define EVQ_CTL_REG_OFST 0x450 /* Event queue control register */
++  #define RX_EVQ_WAKEUP_MASK_B0_LBN 15
++  #define RX_EVQ_WAKEUP_MASK_B0_WIDTH 6
++  #define EVQ_OWNERR_CTL_LBN 14
++  #define EVQ_OWNERR_CTL_WIDTH 1
++  #define EVQ_FIFO_AF_TH_LBN 8
++  #define EVQ_FIFO_AF_TH_WIDTH 6
++  #define EVQ_FIFO_NOTAF_TH_LBN 0
++  #define EVQ_FIFO_NOTAF_TH_WIDTH 6
++/*************---- SRAM Module Registers C Header ----*************/
++#define BUF_TBL_CFG_REG_KER_OFST 0x600 /* Buffer table configuration register */
++#define BUF_TBL_CFG_REG_OFST 0x600 /* Buffer table configuration register */
++  #define BUF_TBL_MODE_LBN 3
++  #define BUF_TBL_MODE_WIDTH 1
++#define SRM_RX_DC_CFG_REG_KER_OFST 0x610 /* SRAM receive descriptor cache
++                                          configuration register */
++#define SRM_RX_DC_CFG_REG_OFST 0x610 /* SRAM receive descriptor cache
++                                      configuration register */
++  #define SRM_RX_DC_BASE_ADR_LBN 0
++  #define SRM_RX_DC_BASE_ADR_WIDTH 21
++#define SRM_TX_DC_CFG_REG_KER_OFST 0x620 /* SRAM transmit descriptor cache
++                                          configuration register */
++#define SRM_TX_DC_CFG_REG_OFST 0x620 /* SRAM transmit descriptor cache
++                                      configuration register */
++  #define SRM_TX_DC_BASE_ADR_LBN 0
++  #define SRM_TX_DC_BASE_ADR_WIDTH 21
++#define SRM_CFG_REG_KER_OFST 0x630 /* SRAM configuration register */
++#define SRM_CFG_REG_OFST 0x630 /* SRAM configuration register */
++  #define SRAM_OOB_ADR_INTEN_LBN 5
++  #define SRAM_OOB_ADR_INTEN_WIDTH 1
++  #define SRAM_OOB_BUF_INTEN_LBN 4
++  #define SRAM_OOB_BUF_INTEN_WIDTH 1
++  #define SRAM_BT_INIT_EN_LBN 3
++  #define SRAM_BT_INIT_EN_WIDTH 1
++  #define SRM_NUM_BANK_LBN 2
++  #define SRM_NUM_BANK_WIDTH 1
++  #define SRM_BANK_SIZE_LBN 0
++  #define SRM_BANK_SIZE_WIDTH 2
++#define BUF_TBL_UPD_REG_KER_OFST 0x650 /* Buffer table update register */
++#define BUF_TBL_UPD_REG_OFST 0x650 /* Buffer table update register */
++  #define BUF_UPD_CMD_LBN 63
++  #define BUF_UPD_CMD_WIDTH 1
++  #define BUF_CLR_CMD_LBN 62
++  #define BUF_CLR_CMD_WIDTH 1
++  #define BUF_CLR_END_ID_LBN 32
++  #define BUF_CLR_END_ID_WIDTH 20
++  #define BUF_CLR_START_ID_LBN 0
++  #define BUF_CLR_START_ID_WIDTH 20
++#define SRM_UPD_EVQ_REG_KER_OFST 0x660 /* Buffer table update register */
++#define SRM_UPD_EVQ_REG_OFST 0x660 /* Buffer table update register */
++  #define SRM_UPD_EVQ_ID_LBN 0
++  #define SRM_UPD_EVQ_ID_WIDTH 12
++#define SRAM_PARITY_REG_KER_OFST 0x670 /* SRAM parity register. */
++#define SRAM_PARITY_REG_OFST 0x670 /* SRAM parity register. */
++  #define FORCE_SRAM_PERR_LBN 0
++  #define FORCE_SRAM_PERR_WIDTH 1
++
++#if FALCON_EXTENDED_P_BAR
++#define BUF_HALF_TBL_KER_OFST 0x18000 /* Buffer table in half buffer table
++                                       mode direct access by kernel driver */
++#else
++#define BUF_HALF_TBL_KER_OFST 0x8000 /* Buffer table in half buffer table
++                                      mode direct access by kernel driver */
++#endif
 +
-+static struct attribute_group version_group = {
-+      .name = "version",
-+      .attrs = version_attrs,
-+};
 +
-+static int __init xen_sysfs_version_init(void)
-+{
-+      return sysfs_create_group(&hypervisor_subsys.kset.kobj,
-+                                &version_group);
-+}
++#define BUF_HALF_TBL_OFST 0x800000 /* Buffer table in half buffer table mode
++                                    direct access by char driver */
++  #define BUF_ADR_HBUF_ODD_LBN 44
++  #define BUF_ADR_HBUF_ODD_WIDTH 20
++  #define BUF_OWNER_ID_HBUF_ODD_LBN 32
++  #define BUF_OWNER_ID_HBUF_ODD_WIDTH 12
++  #define BUF_ADR_HBUF_EVEN_LBN 12
++  #define BUF_ADR_HBUF_EVEN_WIDTH 20
++  #define BUF_OWNER_ID_HBUF_EVEN_LBN 0
++  #define BUF_OWNER_ID_HBUF_EVEN_WIDTH 12
 +
-+static void xen_sysfs_version_destroy(void)
-+{
-+      sysfs_remove_group(&hypervisor_subsys.kset.kobj, &version_group);
-+}
 +
-+/* UUID */
++#if FALCON_EXTENDED_P_BAR
++#define BUF_FULL_TBL_KER_OFST 0x18000 /* Buffer table in full buffer table
++                                       mode direct access by kernel driver */
++#else
++#define BUF_FULL_TBL_KER_OFST 0x8000 /* Buffer table in full buffer table mode
++                                      direct access by kernel driver */
++#endif
 +
-+static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
-+{
-+      char *vm, *val;
-+      int ret;
 +
-+      vm = xenbus_read(XBT_NIL, "vm", "", NULL);
-+      if (IS_ERR(vm))
-+              return PTR_ERR(vm);
-+      val = xenbus_read(XBT_NIL, vm, "uuid", NULL);
-+      kfree(vm);
-+      if (IS_ERR(val))
-+              return PTR_ERR(val);
-+      ret = sprintf(buffer, "%s\n", val);
-+      kfree(val);
-+      return ret;
-+}
 +
-+HYPERVISOR_ATTR_RO(uuid);
 +
-+static int __init xen_sysfs_uuid_init(void)
-+{
-+      return sysfs_create_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr);
-+}
++#define BUF_FULL_TBL_OFST 0x800000 /* Buffer table in full buffer table mode
++                                    direct access by char driver */
++  #define IP_DAT_BUF_SIZE_LBN 50
++  #define IP_DAT_BUF_SIZE_WIDTH 1
++  #define BUF_ADR_REGION_LBN 48
++  #define BUF_ADR_REGION_WIDTH 2
++  #define BUF_ADR_FBUF_LBN 14
++  #define BUF_ADR_FBUF_WIDTH 34
++  #define BUF_OWNER_ID_FBUF_LBN 0
++  #define BUF_OWNER_ID_FBUF_WIDTH 14
++#define SRM_DBG_REG_OFST 0x3000000 /* SRAM debug access */
++  #define SRM_DBG_LBN 0
++  #define SRM_DBG_WIDTH 64
++/*************---- RX Datapath Registers C Header ----*************/
 +
-+static void xen_sysfs_uuid_destroy(void)
-+{
-+      sysfs_remove_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr);
-+}
++#define RX_CFG_REG_KER_OFST 0x800 /* Receive configuration register */
++#define RX_CFG_REG_OFST 0x800 /* Receive configuration register */
 +
-+/* xen compilation attributes */
++#if !defined(FALCON_64K_RXFIFO) && !defined(FALCON_PRE_02020029)
++# if !defined(FALCON_128K_RXFIFO)
++#  define FALCON_128K_RXFIFO
++# endif
++#endif
 +
-+static ssize_t compiler_show(struct hyp_sysfs_attr *attr, char *buffer)
-+{
-+      int ret = -ENOMEM;
-+      struct xen_compile_info *info;
++#if defined(FALCON_128K_RXFIFO)
++
++/* new for B0 */
++  #define RX_TOEP_TCP_SUPPRESS_B0_LBN 48
++  #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1
++  #define RX_INGR_EN_B0_LBN 47
++  #define RX_INGR_EN_B0_WIDTH 1
++  #define RX_TOEP_IPV4_B0_LBN 46
++  #define RX_TOEP_IPV4_B0_WIDTH 1
++  #define RX_HASH_ALG_B0_LBN 45
++  #define RX_HASH_ALG_B0_WIDTH 1
++  #define RX_HASH_INSERT_HDR_B0_LBN 44
++  #define RX_HASH_INSERT_HDR_B0_WIDTH 1
++/* moved for B0 */
++  #define RX_DESC_PUSH_EN_B0_LBN 43
++  #define RX_DESC_PUSH_EN_B0_WIDTH 1
++  #define RX_RDW_PATCH_EN_LBN 42 /* Non head of line blocking */
++  #define RX_RDW_PATCH_EN_WIDTH 1
++  #define RX_PCI_BURST_SIZE_B0_LBN 39
++  #define RX_PCI_BURST_SIZE_B0_WIDTH 3
++  #define RX_OWNERR_CTL_B0_LBN 38
++  #define RX_OWNERR_CTL_B0_WIDTH 1
++  #define RX_XON_TX_TH_B0_LBN 33
++  #define RX_XON_TX_TH_B0_WIDTH 5
++  #define RX_XOFF_TX_TH_B0_LBN 28
++  #define RX_XOFF_TX_TH_B0_WIDTH 5
++  #define RX_USR_BUF_SIZE_B0_LBN 19
++  #define RX_USR_BUF_SIZE_B0_WIDTH 9
++  #define RX_XON_MAC_TH_B0_LBN 10
++  #define RX_XON_MAC_TH_B0_WIDTH 9
++  #define RX_XOFF_MAC_TH_B0_LBN 1
++  #define RX_XOFF_MAC_TH_B0_WIDTH 9
++  #define RX_XOFF_MAC_EN_B0_LBN 0
++  #define RX_XOFF_MAC_EN_B0_WIDTH 1
++
++#elif !defined(FALCON_PRE_02020029)
++/* new for B0 */
++  #define RX_TOEP_TCP_SUPPRESS_B0_LBN 46
++  #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1
++  #define RX_INGR_EN_B0_LBN 45
++  #define RX_INGR_EN_B0_WIDTH 1
++  #define RX_TOEP_IPV4_B0_LBN 44
++  #define RX_TOEP_IPV4_B0_WIDTH 1
++  #define RX_HASH_ALG_B0_LBN 43
++  #define RX_HASH_ALG_B0_WIDTH 41
++  #define RX_HASH_INSERT_HDR_B0_LBN 42
++  #define RX_HASH_INSERT_HDR_B0_WIDTH 1
++/* moved for B0 */
++  #define RX_DESC_PUSH_EN_B0_LBN 41
++  #define RX_DESC_PUSH_EN_B0_WIDTH 1
++  #define RX_PCI_BURST_SIZE_B0_LBN 37
++  #define RX_PCI_BURST_SIZE_B0_WIDTH 3
++  #define RX_OWNERR_CTL_B0_LBN 36
++  #define RX_OWNERR_CTL_B0_WIDTH 1
++  #define RX_XON_TX_TH_B0_LBN 31
++  #define RX_XON_TX_TH_B0_WIDTH 5
++  #define RX_XOFF_TX_TH_B0_LBN 26
++  #define RX_XOFF_TX_TH_B0_WIDTH 5
++  #define RX_USR_BUF_SIZE_B0_LBN 17
++  #define RX_USR_BUF_SIZE_B0_WIDTH 9
++  #define RX_XON_MAC_TH_B0_LBN 9
++  #define RX_XON_MAC_TH_B0_WIDTH 8
++  #define RX_XOFF_MAC_TH_B0_LBN 1
++  #define RX_XOFF_MAC_TH_B0_WIDTH 8
++  #define RX_XOFF_MAC_EN_B0_LBN 0
++  #define RX_XOFF_MAC_EN_B0_WIDTH 1
 +
-+      info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
-+      if (info) {
-+              ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
-+              if (!ret)
-+                      ret = sprintf(buffer, "%s\n", info->compiler);
-+              kfree(info);
-+      }
++#else
++/* new for B0 */
++  #define RX_TOEP_TCP_SUPPRESS_B0_LBN 44
++  #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1
++  #define RX_INGR_EN_B0_LBN 43
++  #define RX_INGR_EN_B0_WIDTH 1
++  #define RX_TOEP_IPV4_B0_LBN 42
++  #define RX_TOEP_IPV4_B0_WIDTH 1
++  #define RX_HASH_ALG_B0_LBN 41
++  #define RX_HASH_ALG_B0_WIDTH 41
++  #define RX_HASH_INSERT_HDR_B0_LBN 40
++  #define RX_HASH_INSERT_HDR_B0_WIDTH 1
++/* moved for B0 */
++  #define RX_DESC_PUSH_EN_B0_LBN 35
++  #define RX_DESC_PUSH_EN_B0_WIDTH 1
++  #define RX_PCI_BURST_SIZE_B0_LBN 35
++  #define RX_PCI_BURST_SIZE_B0_WIDTH 2
++  #define RX_OWNERR_CTL_B0_LBN 34
++  #define RX_OWNERR_CTL_B0_WIDTH 1
++  #define RX_XON_TX_TH_B0_LBN 29
++  #define RX_XON_TX_TH_B0_WIDTH 5
++  #define RX_XOFF_TX_TH_B0_LBN 24
++  #define RX_XOFF_TX_TH_B0_WIDTH 5
++  #define RX_USR_BUF_SIZE_B0_LBN 15
++  #define RX_USR_BUF_SIZE_B0_WIDTH 9
++  #define RX_XON_MAC_TH_B0_LBN 8
++  #define RX_XON_MAC_TH_B0_WIDTH 7
++  #define RX_XOFF_MAC_TH_B0_LBN 1
++  #define RX_XOFF_MAC_TH_B0_WIDTH 7
++  #define RX_XOFF_MAC_EN_B0_LBN 0
++  #define RX_XOFF_MAC_EN_B0_WIDTH 1
++
++#endif
++
++/* A0/A1 */
++  #define RX_PUSH_EN_A1_LBN 35
++  #define RX_PUSH_EN_A1_WIDTH 1
++  #define RX_PCI_BURST_SIZE_A1_LBN 31
++  #define RX_PCI_BURST_SIZE_A1_WIDTH 3
++  #define RX_OWNERR_CTL_A1_LBN 30
++  #define RX_OWNERR_CTL_A1_WIDTH 1
++  #define RX_XON_TX_TH_A1_LBN 25
++  #define RX_XON_TX_TH_A1_WIDTH 5
++  #define RX_XOFF_TX_TH_A1_LBN 20
++  #define RX_XOFF_TX_TH_A1_WIDTH 5
++  #define RX_USR_BUF_SIZE_A1_LBN 11
++  #define RX_USR_BUF_SIZE_A1_WIDTH 9
++  #define RX_XON_MAC_TH_A1_LBN 6
++  #define RX_XON_MAC_TH_A1_WIDTH 5
++  #define RX_XOFF_MAC_TH_A1_LBN 1
++  #define RX_XOFF_MAC_TH_A1_WIDTH 5
++  #define RX_XOFF_MAC_EN_A1_LBN 0
++  #define RX_XOFF_MAC_EN_A1_WIDTH 1
++
++#define RX_FILTER_CTL_REG_OFST 0x810 /* Receive filter control registers */
++  #define SCATTER_ENBL_NO_MATCH_Q_B0_LBN 40
++  #define SCATTER_ENBL_NO_MATCH_Q_B0_WIDTH 1
++  #define UDP_FULL_SRCH_LIMIT_LBN 32
++  #define UDP_FULL_SRCH_LIMIT_WIDTH 8
++  #define NUM_KER_LBN 24
++  #define NUM_KER_WIDTH 2
++  #define UDP_WILD_SRCH_LIMIT_LBN 16
++  #define UDP_WILD_SRCH_LIMIT_WIDTH 8
++  #define TCP_WILD_SRCH_LIMIT_LBN 8
++  #define TCP_WILD_SRCH_LIMIT_WIDTH 8
++  #define TCP_FULL_SRCH_LIMIT_LBN 0
++  #define TCP_FULL_SRCH_LIMIT_WIDTH 8
++#define RX_FLUSH_DESCQ_REG_KER_OFST 0x820 /* Receive flush descriptor queue
++                                           register */
++#define RX_FLUSH_DESCQ_REG_OFST 0x820 /* Receive flush descriptor queue
++                                       register */
++  #define RX_FLUSH_DESCQ_CMD_LBN 24
++  #define RX_FLUSH_DESCQ_CMD_WIDTH 1
++  #define RX_FLUSH_EVQ_ID_LBN 12
++  #define RX_FLUSH_EVQ_ID_WIDTH 12
++  #define RX_FLUSH_DESCQ_LBN 0
++  #define RX_FLUSH_DESCQ_WIDTH 12
++#define RX_DESC_UPD_REG_KER_OFST 0x830 /* Kernel  receive descriptor update
++                                        register. Page-mapped */
++#define RX_DESC_UPD_REG_PAGE4_OFST 0x8830 /* Char & user receive descriptor
++                                           update register. Page-mapped.
++                                           For lowest 1K queues. */
++#define RX_DESC_UPD_REG_PAGE123K_OFST 0x1000830 /* Char & user receive
++                                                 descriptor update register.
++                                                 Page-mapped. For upper
++                                                 3K queues. */
++  #define RX_DESC_WPTR_LBN 96
++  #define RX_DESC_WPTR_WIDTH 12
++  #define RX_DESC_PUSH_CMD_LBN 95
++  #define RX_DESC_PUSH_CMD_WIDTH 1
++  #define RX_DESC_LBN 0
++  #define RX_DESC_WIDTH 64
++  #define RX_KER_DESC_LBN 0
++  #define RX_KER_DESC_WIDTH 64
++  #define RX_USR_DESC_LBN 0
++  #define RX_USR_DESC_WIDTH 32
++#define RX_DC_CFG_REG_KER_OFST 0x840 /* Receive descriptor cache
++                                      configuration register */
++#define RX_DC_CFG_REG_OFST 0x840 /* Receive descriptor cache
++                                  configuration register */
++  #define RX_DC_SIZE_LBN 0
++  #define RX_DC_SIZE_WIDTH 2
++#define RX_DC_PF_WM_REG_KER_OFST 0x850 /* Receive descriptor cache pre-fetch
++                                        watermark register */
++#define RX_DC_PF_WM_REG_OFST 0x850 /* Receive descriptor cache pre-fetch
++                                    watermark register */
++  #define RX_DC_PF_LWM_LO_LBN 0
++  #define RX_DC_PF_LWM_LO_WIDTH 6
++
++#define RX_RSS_TKEY_B0_OFST 0x860 /* RSS Toeplitz hash key (B0 only) */
++
++#define RX_NODESC_DROP_REG 0x880
++  #define RX_NODESC_DROP_CNT_LBN 0
++  #define RX_NODESC_DROP_CNT_WIDTH 16
++
++#define XM_TX_CFG_REG_OFST 0x1230
++  #define XM_AUTO_PAD_LBN 5
++  #define XM_AUTO_PAD_WIDTH 1
++
++#define RX_FILTER_TBL0_OFST 0xF00000 /* Receive filter table - even entries */
++  #define RSS_EN_0_B0_LBN 110
++  #define RSS_EN_0_B0_WIDTH 1
++  #define SCATTER_EN_0_B0_LBN 109
++  #define SCATTER_EN_0_B0_WIDTH 1
++  #define TCP_UDP_0_LBN 108
++  #define TCP_UDP_0_WIDTH 1
++  #define RXQ_ID_0_LBN 96
++  #define RXQ_ID_0_WIDTH 12
++  #define DEST_IP_0_LBN 64
++  #define DEST_IP_0_WIDTH 32
++  #define DEST_PORT_TCP_0_LBN 48
++  #define DEST_PORT_TCP_0_WIDTH 16
++  #define SRC_IP_0_LBN 16
++  #define SRC_IP_0_WIDTH 32
++  #define SRC_TCP_DEST_UDP_0_LBN 0
++  #define SRC_TCP_DEST_UDP_0_WIDTH 16
++#define RX_FILTER_TBL1_OFST 0xF00010 /* Receive filter table - odd entries */
++  #define RSS_EN_1_B0_LBN 110
++  #define RSS_EN_1_B0_WIDTH 1
++  #define SCATTER_EN_1_B0_LBN 109
++  #define SCATTER_EN_1_B0_WIDTH 1
++  #define TCP_UDP_1_LBN 108
++  #define TCP_UDP_1_WIDTH 1
++  #define RXQ_ID_1_LBN 96
++  #define RXQ_ID_1_WIDTH 12
++  #define DEST_IP_1_LBN 64
++  #define DEST_IP_1_WIDTH 32
++  #define DEST_PORT_TCP_1_LBN 48
++  #define DEST_PORT_TCP_1_WIDTH 16
++  #define SRC_IP_1_LBN 16
++  #define SRC_IP_1_WIDTH 32
++  #define SRC_TCP_DEST_UDP_1_LBN 0
++  #define SRC_TCP_DEST_UDP_1_WIDTH 16
++
++#if FALCON_EXTENDED_P_BAR
++#define RX_DESC_PTR_TBL_KER_OFST 0x11800 /* Receive descriptor pointer
++                                          kernel access */
++#else
++#define RX_DESC_PTR_TBL_KER_OFST 0x1800 /* Receive descriptor pointer
++                                         kernel access */
++#endif
++
++
++#define RX_DESC_PTR_TBL_OFST 0xF40000 /* Receive descriptor pointer table */
++  #define RX_ISCSI_DDIG_EN_LBN 88
++  #define RX_ISCSI_DDIG_EN_WIDTH 1
++  #define RX_ISCSI_HDIG_EN_LBN 87
++  #define RX_ISCSI_HDIG_EN_WIDTH 1
++  #define RX_DESC_PREF_ACT_LBN 86
++  #define RX_DESC_PREF_ACT_WIDTH 1
++  #define RX_DC_HW_RPTR_LBN 80
++  #define RX_DC_HW_RPTR_WIDTH 6
++  #define RX_DESCQ_HW_RPTR_LBN 68
++  #define RX_DESCQ_HW_RPTR_WIDTH 12
++  #define RX_DESCQ_SW_WPTR_LBN 56
++  #define RX_DESCQ_SW_WPTR_WIDTH 12
++  #define RX_DESCQ_BUF_BASE_ID_LBN 36
++  #define RX_DESCQ_BUF_BASE_ID_WIDTH 20
++  #define RX_DESCQ_EVQ_ID_LBN 24
++  #define RX_DESCQ_EVQ_ID_WIDTH 12
++  #define RX_DESCQ_OWNER_ID_LBN 10
++  #define RX_DESCQ_OWNER_ID_WIDTH 14
++  #define RX_DESCQ_LABEL_LBN 5
++  #define RX_DESCQ_LABEL_WIDTH 5
++  #define RX_DESCQ_SIZE_LBN 3
++  #define RX_DESCQ_SIZE_WIDTH 2
++  #define RX_DESCQ_TYPE_LBN 2
++  #define RX_DESCQ_TYPE_WIDTH 1
++  #define RX_DESCQ_JUMBO_LBN 1
++  #define RX_DESCQ_JUMBO_WIDTH 1
++  #define RX_DESCQ_EN_LBN 0
++  #define RX_DESCQ_EN_WIDTH 1
++
++
++#define RX_RSS_INDIR_TBL_B0_OFST 0xFB0000 /* RSS indirection table (B0 only) */
++  #define RX_RSS_INDIR_ENT_B0_LBN 0
++  #define RX_RSS_INDIR_ENT_B0_WIDTH 6
++
++/*************---- TX Datapath Registers C Header ----*************/
++#define TX_FLUSH_DESCQ_REG_KER_OFST 0xA00 /* Transmit flush descriptor
++                                           queue register */
++#define TX_FLUSH_DESCQ_REG_OFST 0xA00 /* Transmit flush descriptor queue
++                                       register */
++  #define TX_FLUSH_DESCQ_CMD_LBN 12
++  #define TX_FLUSH_DESCQ_CMD_WIDTH 1
++  #define TX_FLUSH_DESCQ_LBN 0
++  #define TX_FLUSH_DESCQ_WIDTH 12
++#define TX_DESC_UPD_REG_KER_OFST 0xA10 /* Kernel transmit descriptor update
++                                        register. Page-mapped */
++#define TX_DESC_UPD_REG_PAGE4_OFST 0x8A10 /* Char & user transmit descriptor
++                                           update register. Page-mapped */
++#define TX_DESC_UPD_REG_PAGE123K_OFST 0x1000A10 /* Char & user transmit
++                                                 descriptor update register.
++                                                 Page-mapped */
++  #define TX_DESC_WPTR_LBN 96
++  #define TX_DESC_WPTR_WIDTH 12
++  #define TX_DESC_PUSH_CMD_LBN 95
++  #define TX_DESC_PUSH_CMD_WIDTH 1
++  #define TX_DESC_LBN 0
++  #define TX_DESC_WIDTH 95
++  #define TX_KER_DESC_LBN 0
++  #define TX_KER_DESC_WIDTH 64
++  #define TX_USR_DESC_LBN 0
++  #define TX_USR_DESC_WIDTH 64
++#define TX_DC_CFG_REG_KER_OFST 0xA20 /* Transmit descriptor cache
++                                      configuration register */
++#define TX_DC_CFG_REG_OFST 0xA20 /* Transmit descriptor cache configuration
++                                  register */
++  #define TX_DC_SIZE_LBN 0
++  #define TX_DC_SIZE_WIDTH 2
++
++#if FALCON_EXTENDED_P_BAR
++#define TX_DESC_PTR_TBL_KER_OFST 0x11900 /* Transmit descriptor pointer. */
++#else
++#define TX_DESC_PTR_TBL_KER_OFST 0x1900 /* Transmit descriptor pointer. */
++#endif
++
++
++#define TX_DESC_PTR_TBL_OFST 0xF50000 /* Transmit descriptor pointer */
++  #define TX_NON_IP_DROP_DIS_B0_LBN 91
++  #define TX_NON_IP_DROP_DIS_B0_WIDTH 1
++  #define TX_IP_CHKSM_DIS_B0_LBN 90
++  #define TX_IP_CHKSM_DIS_B0_WIDTH 1
++  #define TX_TCP_CHKSM_DIS_B0_LBN 89
++  #define TX_TCP_CHKSM_DIS_B0_WIDTH 1
++  #define TX_DESCQ_EN_LBN 88
++  #define TX_DESCQ_EN_WIDTH 1
++  #define TX_ISCSI_DDIG_EN_LBN 87
++  #define TX_ISCSI_DDIG_EN_WIDTH 1
++  #define TX_ISCSI_HDIG_EN_LBN 86
++  #define TX_ISCSI_HDIG_EN_WIDTH 1
++  #define TX_DC_HW_RPTR_LBN 80
++  #define TX_DC_HW_RPTR_WIDTH 6
++  #define TX_DESCQ_HW_RPTR_LBN 68
++  #define TX_DESCQ_HW_RPTR_WIDTH 12
++  #define TX_DESCQ_SW_WPTR_LBN 56
++  #define TX_DESCQ_SW_WPTR_WIDTH 12
++  #define TX_DESCQ_BUF_BASE_ID_LBN 36
++  #define TX_DESCQ_BUF_BASE_ID_WIDTH 20
++  #define TX_DESCQ_EVQ_ID_LBN 24
++  #define TX_DESCQ_EVQ_ID_WIDTH 12
++  #define TX_DESCQ_OWNER_ID_LBN 10
++  #define TX_DESCQ_OWNER_ID_WIDTH 14
++  #define TX_DESCQ_LABEL_LBN 5
++  #define TX_DESCQ_LABEL_WIDTH 5
++  #define TX_DESCQ_SIZE_LBN 3
++  #define TX_DESCQ_SIZE_WIDTH 2
++  #define TX_DESCQ_TYPE_LBN 1
++  #define TX_DESCQ_TYPE_WIDTH 2
++  #define TX_DESCQ_FLUSH_LBN 0
++  #define TX_DESCQ_FLUSH_WIDTH 1
++#define TX_CFG_REG_KER_OFST 0xA50 /* Transmit configuration register */
++#define TX_CFG_REG_OFST 0xA50 /* Transmit configuration register */
++  #define TX_IP_ID_P1_OFS_LBN 32
++  #define TX_IP_ID_P1_OFS_WIDTH 15
++  #define TX_IP_ID_P0_OFS_LBN 16
++  #define TX_IP_ID_P0_OFS_WIDTH 15
++  #define TX_TURBO_EN_LBN 3
++  #define TX_TURBO_EN_WIDTH 1
++  #define TX_OWNERR_CTL_LBN 2
++  #define TX_OWNERR_CTL_WIDTH 2
++  #define TX_NON_IP_DROP_DIS_LBN 1
++  #define TX_NON_IP_DROP_DIS_WIDTH 1
++  #define TX_IP_ID_REP_EN_LBN 0
++  #define TX_IP_ID_REP_EN_WIDTH 1
++#define TX_RESERVED_REG_KER_OFST 0xA80 /* Transmit configuration register */
++#define TX_RESERVED_REG_OFST 0xA80 /* Transmit configuration register */
++  #define TX_CSR_PUSH_EN_LBN 89
++  #define TX_CSR_PUSH_EN_WIDTH 1
++  #define TX_RX_SPACER_LBN 64
++  #define TX_RX_SPACER_WIDTH 8
++  #define TX_SW_EV_EN_LBN 59
++  #define TX_SW_EV_EN_WIDTH 1
++  #define TX_RX_SPACER_EN_LBN 57
++  #define TX_RX_SPACER_EN_WIDTH 1
++  #define TX_CSR_PREF_WD_TMR_LBN 24
++  #define TX_CSR_PREF_WD_TMR_WIDTH 16
++  #define TX_CSR_ONLY1TAG_LBN 21
++  #define TX_CSR_ONLY1TAG_WIDTH 1
++  #define TX_PREF_THRESHOLD_LBN 19
++  #define TX_PREF_THRESHOLD_WIDTH 2
++  #define TX_ONE_PKT_PER_Q_LBN 18
++  #define TX_ONE_PKT_PER_Q_WIDTH 1
++  #define TX_DIS_NON_IP_EV_LBN 17
++  #define TX_DIS_NON_IP_EV_WIDTH 1
++  #define TX_DMA_SPACER_LBN 8
++  #define TX_DMA_SPACER_WIDTH 8
++  #define TX_FLUSH_MIN_LEN_EN_B0_LBN 7
++  #define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1
++  #define TX_TCP_DIS_A1_LBN 7
++  #define TX_TCP_DIS_A1_WIDTH 1
++  #define TX_IP_DIS_A1_LBN 6
++  #define TX_IP_DIS_A1_WIDTH 1
++  #define TX_MAX_CPL_LBN 2
++  #define TX_MAX_CPL_WIDTH 2
++  #define TX_MAX_PREF_LBN 0
++  #define TX_MAX_PREF_WIDTH 2
++#define TX_VLAN_REG_OFST 0xAE0 /* Transmit VLAN tag register */
++  #define TX_VLAN_EN_LBN 127
++  #define TX_VLAN_EN_WIDTH 1
++  #define TX_VLAN7_PORT1_EN_LBN 125
++  #define TX_VLAN7_PORT1_EN_WIDTH 1
++  #define TX_VLAN7_PORT0_EN_LBN 124
++  #define TX_VLAN7_PORT0_EN_WIDTH 1
++  #define TX_VLAN7_LBN 112
++  #define TX_VLAN7_WIDTH 12
++  #define TX_VLAN6_PORT1_EN_LBN 109
++  #define TX_VLAN6_PORT1_EN_WIDTH 1
++  #define TX_VLAN6_PORT0_EN_LBN 108
++  #define TX_VLAN6_PORT0_EN_WIDTH 1
++  #define TX_VLAN6_LBN 96
++  #define TX_VLAN6_WIDTH 12
++  #define TX_VLAN5_PORT1_EN_LBN 93
++  #define TX_VLAN5_PORT1_EN_WIDTH 1
++  #define TX_VLAN5_PORT0_EN_LBN 92
++  #define TX_VLAN5_PORT0_EN_WIDTH 1
++  #define TX_VLAN5_LBN 80
++  #define TX_VLAN5_WIDTH 12
++  #define TX_VLAN4_PORT1_EN_LBN 77
++  #define TX_VLAN4_PORT1_EN_WIDTH 1
++  #define TX_VLAN4_PORT0_EN_LBN 76
++  #define TX_VLAN4_PORT0_EN_WIDTH 1
++  #define TX_VLAN4_LBN 64
++  #define TX_VLAN4_WIDTH 12
++  #define TX_VLAN3_PORT1_EN_LBN 61
++  #define TX_VLAN3_PORT1_EN_WIDTH 1
++  #define TX_VLAN3_PORT0_EN_LBN 60
++  #define TX_VLAN3_PORT0_EN_WIDTH 1
++  #define TX_VLAN3_LBN 48
++  #define TX_VLAN3_WIDTH 12
++  #define TX_VLAN2_PORT1_EN_LBN 45
++  #define TX_VLAN2_PORT1_EN_WIDTH 1
++  #define TX_VLAN2_PORT0_EN_LBN 44
++  #define TX_VLAN2_PORT0_EN_WIDTH 1
++  #define TX_VLAN2_LBN 32
++  #define TX_VLAN2_WIDTH 12
++  #define TX_VLAN1_PORT1_EN_LBN 29
++  #define TX_VLAN1_PORT1_EN_WIDTH 1
++  #define TX_VLAN1_PORT0_EN_LBN 28
++  #define TX_VLAN1_PORT0_EN_WIDTH 1
++  #define TX_VLAN1_LBN 16
++  #define TX_VLAN1_WIDTH 12
++  #define TX_VLAN0_PORT1_EN_LBN 13
++  #define TX_VLAN0_PORT1_EN_WIDTH 1
++  #define TX_VLAN0_PORT0_EN_LBN 12
++  #define TX_VLAN0_PORT0_EN_WIDTH 1
++  #define TX_VLAN0_LBN 0
++  #define TX_VLAN0_WIDTH 12
++#define TX_FIL_CTL_REG_OFST 0xAF0 /* Transmit filter control register */
++  #define TX_MADR1_FIL_EN_LBN 65
++  #define TX_MADR1_FIL_EN_WIDTH 1
++  #define TX_MADR0_FIL_EN_LBN 64
++  #define TX_MADR0_FIL_EN_WIDTH 1
++  #define TX_IPFIL31_PORT1_EN_LBN 63
++  #define TX_IPFIL31_PORT1_EN_WIDTH 1
++  #define TX_IPFIL31_PORT0_EN_LBN 62
++  #define TX_IPFIL31_PORT0_EN_WIDTH 1
++  #define TX_IPFIL30_PORT1_EN_LBN 61
++  #define TX_IPFIL30_PORT1_EN_WIDTH 1
++  #define TX_IPFIL30_PORT0_EN_LBN 60
++  #define TX_IPFIL30_PORT0_EN_WIDTH 1
++  #define TX_IPFIL29_PORT1_EN_LBN 59
++  #define TX_IPFIL29_PORT1_EN_WIDTH 1
++  #define TX_IPFIL29_PORT0_EN_LBN 58
++  #define TX_IPFIL29_PORT0_EN_WIDTH 1
++  #define TX_IPFIL28_PORT1_EN_LBN 57
++  #define TX_IPFIL28_PORT1_EN_WIDTH 1
++  #define TX_IPFIL28_PORT0_EN_LBN 56
++  #define TX_IPFIL28_PORT0_EN_WIDTH 1
++  #define TX_IPFIL27_PORT1_EN_LBN 55
++  #define TX_IPFIL27_PORT1_EN_WIDTH 1
++  #define TX_IPFIL27_PORT0_EN_LBN 54
++  #define TX_IPFIL27_PORT0_EN_WIDTH 1
++  #define TX_IPFIL26_PORT1_EN_LBN 53
++  #define TX_IPFIL26_PORT1_EN_WIDTH 1
++  #define TX_IPFIL26_PORT0_EN_LBN 52
++  #define TX_IPFIL26_PORT0_EN_WIDTH 1
++  #define TX_IPFIL25_PORT1_EN_LBN 51
++  #define TX_IPFIL25_PORT1_EN_WIDTH 1
++  #define TX_IPFIL25_PORT0_EN_LBN 50
++  #define TX_IPFIL25_PORT0_EN_WIDTH 1
++  #define TX_IPFIL24_PORT1_EN_LBN 49
++  #define TX_IPFIL24_PORT1_EN_WIDTH 1
++  #define TX_IPFIL24_PORT0_EN_LBN 48
++  #define TX_IPFIL24_PORT0_EN_WIDTH 1
++  #define TX_IPFIL23_PORT1_EN_LBN 47
++  #define TX_IPFIL23_PORT1_EN_WIDTH 1
++  #define TX_IPFIL23_PORT0_EN_LBN 46
++  #define TX_IPFIL23_PORT0_EN_WIDTH 1
++  #define TX_IPFIL22_PORT1_EN_LBN 45
++  #define TX_IPFIL22_PORT1_EN_WIDTH 1
++  #define TX_IPFIL22_PORT0_EN_LBN 44
++  #define TX_IPFIL22_PORT0_EN_WIDTH 1
++  #define TX_IPFIL21_PORT1_EN_LBN 43
++  #define TX_IPFIL21_PORT1_EN_WIDTH 1
++  #define TX_IPFIL21_PORT0_EN_LBN 42
++  #define TX_IPFIL21_PORT0_EN_WIDTH 1
++  #define TX_IPFIL20_PORT1_EN_LBN 41
++  #define TX_IPFIL20_PORT1_EN_WIDTH 1
++  #define TX_IPFIL20_PORT0_EN_LBN 40
++  #define TX_IPFIL20_PORT0_EN_WIDTH 1
++  #define TX_IPFIL19_PORT1_EN_LBN 39
++  #define TX_IPFIL19_PORT1_EN_WIDTH 1
++  #define TX_IPFIL19_PORT0_EN_LBN 38
++  #define TX_IPFIL19_PORT0_EN_WIDTH 1
++  #define TX_IPFIL18_PORT1_EN_LBN 37
++  #define TX_IPFIL18_PORT1_EN_WIDTH 1
++  #define TX_IPFIL18_PORT0_EN_LBN 36
++  #define TX_IPFIL18_PORT0_EN_WIDTH 1
++  #define TX_IPFIL17_PORT1_EN_LBN 35
++  #define TX_IPFIL17_PORT1_EN_WIDTH 1
++  #define TX_IPFIL17_PORT0_EN_LBN 34
++  #define TX_IPFIL17_PORT0_EN_WIDTH 1
++  #define TX_IPFIL16_PORT1_EN_LBN 33
++  #define TX_IPFIL16_PORT1_EN_WIDTH 1
++  #define TX_IPFIL16_PORT0_EN_LBN 32
++  #define TX_IPFIL16_PORT0_EN_WIDTH 1
++  #define TX_IPFIL15_PORT1_EN_LBN 31
++  #define TX_IPFIL15_PORT1_EN_WIDTH 1
++  #define TX_IPFIL15_PORT0_EN_LBN 30
++  #define TX_IPFIL15_PORT0_EN_WIDTH 1
++  #define TX_IPFIL14_PORT1_EN_LBN 29
++  #define TX_IPFIL14_PORT1_EN_WIDTH 1
++  #define TX_IPFIL14_PORT0_EN_LBN 28
++  #define TX_IPFIL14_PORT0_EN_WIDTH 1
++  #define TX_IPFIL13_PORT1_EN_LBN 27
++  #define TX_IPFIL13_PORT1_EN_WIDTH 1
++  #define TX_IPFIL13_PORT0_EN_LBN 26
++  #define TX_IPFIL13_PORT0_EN_WIDTH 1
++  #define TX_IPFIL12_PORT1_EN_LBN 25
++  #define TX_IPFIL12_PORT1_EN_WIDTH 1
++  #define TX_IPFIL12_PORT0_EN_LBN 24
++  #define TX_IPFIL12_PORT0_EN_WIDTH 1
++  #define TX_IPFIL11_PORT1_EN_LBN 23
++  #define TX_IPFIL11_PORT1_EN_WIDTH 1
++  #define TX_IPFIL11_PORT0_EN_LBN 22
++  #define TX_IPFIL11_PORT0_EN_WIDTH 1
++  #define TX_IPFIL10_PORT1_EN_LBN 21
++  #define TX_IPFIL10_PORT1_EN_WIDTH 1
++  #define TX_IPFIL10_PORT0_EN_LBN 20
++  #define TX_IPFIL10_PORT0_EN_WIDTH 1
++  #define TX_IPFIL9_PORT1_EN_LBN 19
++  #define TX_IPFIL9_PORT1_EN_WIDTH 1
++  #define TX_IPFIL9_PORT0_EN_LBN 18
++  #define TX_IPFIL9_PORT0_EN_WIDTH 1
++  #define TX_IPFIL8_PORT1_EN_LBN 17
++  #define TX_IPFIL8_PORT1_EN_WIDTH 1
++  #define TX_IPFIL8_PORT0_EN_LBN 16
++  #define TX_IPFIL8_PORT0_EN_WIDTH 1
++  #define TX_IPFIL7_PORT1_EN_LBN 15
++  #define TX_IPFIL7_PORT1_EN_WIDTH 1
++  #define TX_IPFIL7_PORT0_EN_LBN 14
++  #define TX_IPFIL7_PORT0_EN_WIDTH 1
++  #define TX_IPFIL6_PORT1_EN_LBN 13
++  #define TX_IPFIL6_PORT1_EN_WIDTH 1
++  #define TX_IPFIL6_PORT0_EN_LBN 12
++  #define TX_IPFIL6_PORT0_EN_WIDTH 1
++  #define TX_IPFIL5_PORT1_EN_LBN 11
++  #define TX_IPFIL5_PORT1_EN_WIDTH 1
++  #define TX_IPFIL5_PORT0_EN_LBN 10
++  #define TX_IPFIL5_PORT0_EN_WIDTH 1
++  #define TX_IPFIL4_PORT1_EN_LBN 9
++  #define TX_IPFIL4_PORT1_EN_WIDTH 1
++  #define TX_IPFIL4_PORT0_EN_LBN 8
++  #define TX_IPFIL4_PORT0_EN_WIDTH 1
++  #define TX_IPFIL3_PORT1_EN_LBN 7
++  #define TX_IPFIL3_PORT1_EN_WIDTH 1
++  #define TX_IPFIL3_PORT0_EN_LBN 6
++  #define TX_IPFIL3_PORT0_EN_WIDTH 1
++  #define TX_IPFIL2_PORT1_EN_LBN 5
++  #define TX_IPFIL2_PORT1_EN_WIDTH 1
++  #define TX_IPFIL2_PORT0_EN_LBN 4
++  #define TX_IPFIL2_PORT0_EN_WIDTH 1
++  #define TX_IPFIL1_PORT1_EN_LBN 3
++  #define TX_IPFIL1_PORT1_EN_WIDTH 1
++  #define TX_IPFIL1_PORT0_EN_LBN 2
++  #define TX_IPFIL1_PORT0_EN_WIDTH 1
++  #define TX_IPFIL0_PORT1_EN_LBN 1
++  #define TX_IPFIL0_PORT1_EN_WIDTH 1
++  #define TX_IPFIL0_PORT0_EN_LBN 0
++  #define TX_IPFIL0_PORT0_EN_WIDTH 1
++#define TX_IPFIL_TBL_OFST 0xB00 /* Transmit IP source address filter table */
++  #define TX_IPFIL_MASK_LBN 32
++  #define TX_IPFIL_MASK_WIDTH 32
++  #define TX_IP_SRC_ADR_LBN 0
++  #define TX_IP_SRC_ADR_WIDTH 32
++#define TX_PACE_REG_A1_OFST 0xF80000 /* Transmit pace control register */
++#define TX_PACE_REG_B0_OFST 0xA90    /* Transmit pace control register */
++  #define TX_PACE_SB_AF_LBN 19
++  #define TX_PACE_SB_AF_WIDTH 10
++  #define TX_PACE_SB_NOTAF_LBN 9
++  #define TX_PACE_SB_NOTAF_WIDTH 10
++  #define TX_PACE_FB_BASE_LBN 5
++  #define TX_PACE_FB_BASE_WIDTH 4
++  #define TX_PACE_BIN_TH_LBN 0
++  #define TX_PACE_BIN_TH_WIDTH 5
++#define TX_PACE_TBL_A1_OFST 0xF80040 /* Transmit pacing table */
++#define TX_PACE_TBL_FIRST_QUEUE_A1 4
++#define TX_PACE_TBL_B0_OFST 0xF80000 /* Transmit pacing table */
++#define TX_PACE_TBL_FIRST_QUEUE_B0 0
++  #define TX_PACE_LBN 0
++  #define TX_PACE_WIDTH 5
++
++/*************---- EE/Flash Registers C Header ----*************/
++#define EE_SPI_HCMD_REG_KER_OFST 0x100 /* SPI host command register */
++#define EE_SPI_HCMD_REG_OFST 0x100 /* SPI host command register */
++  #define EE_SPI_HCMD_CMD_EN_LBN 31
++  #define EE_SPI_HCMD_CMD_EN_WIDTH 1
++  #define EE_WR_TIMER_ACTIVE_LBN 28
++  #define EE_WR_TIMER_ACTIVE_WIDTH 1
++  #define EE_SPI_HCMD_SF_SEL_LBN 24
++  #define EE_SPI_HCMD_SF_SEL_WIDTH 1
++  #define EE_SPI_HCMD_DABCNT_LBN 16
++  #define EE_SPI_HCMD_DABCNT_WIDTH 5
++  #define EE_SPI_HCMD_READ_LBN 15
++  #define EE_SPI_HCMD_READ_WIDTH 1
++  #define EE_SPI_HCMD_DUBCNT_LBN 12
++  #define EE_SPI_HCMD_DUBCNT_WIDTH 2
++  #define EE_SPI_HCMD_ADBCNT_LBN 8
++  #define EE_SPI_HCMD_ADBCNT_WIDTH 2
++  #define EE_SPI_HCMD_ENC_LBN 0
++  #define EE_SPI_HCMD_ENC_WIDTH 8
++#define EE_SPI_HADR_REG_KER_OFST 0X110 /* SPI host address register */
++#define EE_SPI_HADR_REG_OFST 0X110 /* SPI host address register */
++  #define EE_SPI_HADR_DUBYTE_LBN 24
++  #define EE_SPI_HADR_DUBYTE_WIDTH 8
++  #define EE_SPI_HADR_ADR_LBN 0
++  #define EE_SPI_HADR_ADR_WIDTH 24
++#define EE_SPI_HDATA_REG_KER_OFST 0x120 /* SPI host data register */
++#define EE_SPI_HDATA_REG_OFST 0x120 /* SPI host data register */
++  #define EE_SPI_HDATA3_LBN 96
++  #define EE_SPI_HDATA3_WIDTH 32
++  #define EE_SPI_HDATA2_LBN 64
++  #define EE_SPI_HDATA2_WIDTH 32
++  #define EE_SPI_HDATA1_LBN 32
++  #define EE_SPI_HDATA1_WIDTH 32
++  #define EE_SPI_HDATA0_LBN 0
++  #define EE_SPI_HDATA0_WIDTH 32
++#define EE_BASE_PAGE_REG_KER_OFST 0x130 /* Expansion ROM base mirror register */
++#define EE_BASE_PAGE_REG_OFST 0x130 /* Expansion ROM base mirror register */
++  #define EE_EXP_ROM_WINDOW_BASE_LBN 16
++  #define EE_EXP_ROM_WINDOW_BASE_WIDTH 13
++  #define EE_EXPROM_MASK_LBN 0
++  #define EE_EXPROM_MASK_WIDTH 13
++#define EE_VPD_CFG0_REG_KER_OFST 0X140 /* SPI/VPD configuration register */
++#define EE_VPD_CFG0_REG_OFST 0X140 /* SPI/VPD configuration register */
++  #define EE_SF_FASTRD_EN_LBN 127
++  #define EE_SF_FASTRD_EN_WIDTH 1
++  #define EE_SF_CLOCK_DIV_LBN 120
++  #define EE_SF_CLOCK_DIV_WIDTH 7
++  #define EE_VPD_WIP_POLL_LBN 119
++  #define EE_VPD_WIP_POLL_WIDTH 1
++  #define EE_VPDW_LENGTH_LBN 80
++  #define EE_VPDW_LENGTH_WIDTH 15
++  #define EE_VPDW_BASE_LBN 64
++  #define EE_VPDW_BASE_WIDTH 15
++  #define EE_VPD_WR_CMD_EN_LBN 56
++  #define EE_VPD_WR_CMD_EN_WIDTH 8
++  #define EE_VPD_BASE_LBN 32
++  #define EE_VPD_BASE_WIDTH 24
++  #define EE_VPD_LENGTH_LBN 16
++  #define EE_VPD_LENGTH_WIDTH 13
++  #define EE_VPD_AD_SIZE_LBN 8
++  #define EE_VPD_AD_SIZE_WIDTH 5
++  #define EE_VPD_ACCESS_ON_LBN 5
++  #define EE_VPD_ACCESS_ON_WIDTH 1
++#define EE_VPD_SW_CNTL_REG_KER_OFST 0X150 /* VPD access SW control register */
++#define EE_VPD_SW_CNTL_REG_OFST 0X150 /* VPD access SW control register */
++  #define EE_VPD_CYCLE_PENDING_LBN 31
++  #define EE_VPD_CYCLE_PENDING_WIDTH 1
++  #define EE_VPD_CYC_WRITE_LBN 28
++  #define EE_VPD_CYC_WRITE_WIDTH 1
++  #define EE_VPD_CYC_ADR_LBN 0
++  #define EE_VPD_CYC_ADR_WIDTH 15
++#define EE_VPD_SW_DATA_REG_KER_OFST 0x160 /* VPD access SW data register */
++#define EE_VPD_SW_DATA_REG_OFST 0x160 /* VPD access SW data register */
++  #define EE_VPD_CYC_DAT_LBN 0
++  #define EE_VPD_CYC_DAT_WIDTH 32
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_desc.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_desc.h      2008-05-19 00:33:29.333836963 +0300
+@@ -0,0 +1,75 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) descriptor
++ * definitions.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++/*************---- Descriptors C Headers ----*************/
++/* Receive Kernel IP Descriptor */
++  #define RX_KER_BUF_SIZE_LBN 48
++  #define RX_KER_BUF_SIZE_WIDTH 14
++  #define RX_KER_BUF_REGION_LBN 46
++  #define RX_KER_BUF_REGION_WIDTH 2
++      #define RX_KER_BUF_REGION0_DECODE 0
++      #define RX_KER_BUF_REGION1_DECODE 1
++      #define RX_KER_BUF_REGION2_DECODE 2
++      #define RX_KER_BUF_REGION3_DECODE 3
++  #define RX_KER_BUF_ADR_LBN 0
++  #define RX_KER_BUF_ADR_WIDTH 46
++/* Receive User IP Descriptor */
++  #define RX_USR_2BYTE_OFS_LBN 20
++  #define RX_USR_2BYTE_OFS_WIDTH 12
++  #define RX_USR_BUF_ID_LBN 0
++  #define RX_USR_BUF_ID_WIDTH 20
++/* Transmit Kernel IP Descriptor */
++  #define TX_KER_PORT_LBN 63
++  #define TX_KER_PORT_WIDTH 1
++  #define TX_KER_CONT_LBN 62
++  #define TX_KER_CONT_WIDTH 1
++  #define TX_KER_BYTE_CNT_LBN 48
++  #define TX_KER_BYTE_CNT_WIDTH 14
++  #define TX_KER_BUF_REGION_LBN 46
++  #define TX_KER_BUF_REGION_WIDTH 2
++      #define TX_KER_BUF_REGION0_DECODE 0
++      #define TX_KER_BUF_REGION1_DECODE 1
++      #define TX_KER_BUF_REGION2_DECODE 2
++      #define TX_KER_BUF_REGION3_DECODE 3
++  #define TX_KER_BUF_ADR_LBN 0
++  #define TX_KER_BUF_ADR_WIDTH 46
++/* Transmit User IP Descriptor */
++  #define TX_USR_PORT_LBN 47
++  #define TX_USR_PORT_WIDTH 1
++  #define TX_USR_CONT_LBN 46
++  #define TX_USR_CONT_WIDTH 1
++  #define TX_USR_BYTE_CNT_LBN 33
++  #define TX_USR_BYTE_CNT_WIDTH 13
++  #define TX_USR_BUF_ID_LBN 13
++  #define TX_USR_BUF_ID_WIDTH 20
++  #define TX_USR_BYTE_OFS_LBN 0
++  #define TX_USR_BYTE_OFS_WIDTH 13
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_event.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_event.h     2008-05-19 00:33:29.333836963 +0300
+@@ -0,0 +1,155 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) event
++ * definitions.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++/*************---- Events Format C Header ----*************/
++/*************---- Event entry ----*************/
++  #define EV_CODE_LBN 60
++  #define EV_CODE_WIDTH 4
++      #define RX_IP_EV_DECODE 0
++      #define TX_IP_EV_DECODE 2
++      #define DRIVER_EV_DECODE 5
++      #define GLOBAL_EV_DECODE 6
++      #define DRV_GEN_EV_DECODE 7
++  #define EV_DATA_LBN 0
++  #define EV_DATA_WIDTH 60
++/******---- Receive IP events for both Kernel & User event queues ----******/
++  #define RX_EV_PKT_OK_LBN 56
++  #define RX_EV_PKT_OK_WIDTH 1
++  #define RX_EV_BUF_OWNER_ID_ERR_LBN 54
++  #define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
++  #define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
++  #define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
++  #define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
++  #define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
++  #define RX_EV_ETH_CRC_ERR_LBN 50
++  #define RX_EV_ETH_CRC_ERR_WIDTH 1
++  #define RX_EV_FRM_TRUNC_LBN 49
++  #define RX_EV_FRM_TRUNC_WIDTH 1
++  #define RX_EV_DRIB_NIB_LBN 48
++  #define RX_EV_DRIB_NIB_WIDTH 1
++  #define RX_EV_TOBE_DISC_LBN 47
++  #define RX_EV_TOBE_DISC_WIDTH 1
++  #define RX_EV_PKT_TYPE_LBN 44
++  #define RX_EV_PKT_TYPE_WIDTH 3
++      #define RX_EV_PKT_TYPE_ETH_DECODE 0
++      #define RX_EV_PKT_TYPE_LLC_DECODE 1
++      #define RX_EV_PKT_TYPE_JUMBO_DECODE 2
++      #define RX_EV_PKT_TYPE_VLAN_DECODE 3
++      #define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4
++      #define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5
++  #define RX_EV_HDR_TYPE_LBN 42
++  #define RX_EV_HDR_TYPE_WIDTH 2
++      #define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0
++      #define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1
++      #define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2
++      #define RX_EV_HDR_TYPE_NON_IP_DECODE 3
++  #define RX_EV_DESC_Q_EMPTY_LBN 41
++  #define RX_EV_DESC_Q_EMPTY_WIDTH 1
++  #define RX_EV_MCAST_HASH_MATCH_LBN 40
++  #define RX_EV_MCAST_HASH_MATCH_WIDTH 1
++  #define RX_EV_MCAST_PKT_LBN 39
++  #define RX_EV_MCAST_PKT_WIDTH 1
++  #define RX_EV_Q_LABEL_LBN 32
++  #define RX_EV_Q_LABEL_WIDTH 5
++  #define RX_JUMBO_CONT_LBN 31
++  #define RX_JUMBO_CONT_WIDTH 1
++  #define RX_SOP_LBN 15
++  #define RX_SOP_WIDTH 1
++  #define RX_PORT_LBN 30
++  #define RX_PORT_WIDTH 1
++  #define RX_EV_BYTE_CNT_LBN 16
++  #define RX_EV_BYTE_CNT_WIDTH 14
++  #define RX_iSCSI_PKT_OK_LBN 14
++  #define RX_iSCSI_PKT_OK_WIDTH 1
++  #define RX_ISCSI_DDIG_ERR_LBN 13
++  #define RX_ISCSI_DDIG_ERR_WIDTH 1
++  #define RX_ISCSI_HDIG_ERR_LBN 12
++  #define RX_ISCSI_HDIG_ERR_WIDTH 1
++  #define RX_EV_DESC_PTR_LBN 0
++  #define RX_EV_DESC_PTR_WIDTH 12
++/******---- Transmit IP events for both Kernel & User event queues ----******/
++  #define TX_EV_PKT_ERR_LBN 38
++  #define TX_EV_PKT_ERR_WIDTH 1
++  #define TX_EV_PKT_TOO_BIG_LBN 37
++  #define TX_EV_PKT_TOO_BIG_WIDTH 1
++  #define TX_EV_Q_LABEL_LBN 32
++  #define TX_EV_Q_LABEL_WIDTH 5
++  #define TX_EV_PORT_LBN 16
++  #define TX_EV_PORT_WIDTH 1
++  #define TX_EV_WQ_FF_FULL_LBN 15
++  #define TX_EV_WQ_FF_FULL_WIDTH 1
++  #define TX_EV_BUF_OWNER_ID_ERR_LBN 14
++  #define TX_EV_BUF_OWNER_ID_ERR_WIDTH 1
++  #define TX_EV_COMP_LBN 12
++  #define TX_EV_COMP_WIDTH 1
++  #define TX_EV_DESC_PTR_LBN 0
++  #define TX_EV_DESC_PTR_WIDTH 12
++/*************---- Char or Kernel driver events ----*************/
++  #define DRIVER_EV_SUB_CODE_LBN 56
++  #define DRIVER_EV_SUB_CODE_WIDTH 4
++      #define TX_DESCQ_FLS_DONE_EV_DECODE 0x0
++      #define RX_DESCQ_FLS_DONE_EV_DECODE 0x1
++      #define EVQ_INIT_DONE_EV_DECODE 0x2
++      #define EVQ_NOT_EN_EV_DECODE 0x3
++      #define RX_DESCQ_FLSFF_OVFL_EV_DECODE 0x4
++      #define SRM_UPD_DONE_EV_DECODE 0x5
++      #define WAKE_UP_EV_DECODE 0x6
++      #define TX_PKT_NON_TCP_UDP_DECODE 0x9
++      #define TIMER_EV_DECODE 0xA
++      #define RX_DSC_ERROR_EV_DECODE 0xE
++  #define DRIVER_EV_TX_DESCQ_ID_LBN 0
++  #define DRIVER_EV_TX_DESCQ_ID_WIDTH 12
++  #define DRIVER_EV_RX_DESCQ_ID_LBN 0
++  #define DRIVER_EV_RX_DESCQ_ID_WIDTH 12
++  #define DRIVER_EV_EVQ_ID_LBN 0
++  #define DRIVER_EV_EVQ_ID_WIDTH 12
++  #define DRIVER_TMR_ID_LBN 0
++  #define DRIVER_TMR_ID_WIDTH 12
++  #define DRIVER_EV_SRM_UPD_LBN 0
++  #define DRIVER_EV_SRM_UPD_WIDTH 2
++      #define SRM_CLR_EV_DECODE 0
++      #define SRM_UPD_EV_DECODE 1
++      #define SRM_ILLCLR_EV_DECODE 2
++/********---- Global events. Sent to both event queue 0 and 4. ----********/
++  #define XFP_PHY_INTR_LBN 10
++  #define XFP_PHY_INTR_WIDTH 1
++  #define XG_PHY_INTR_LBN 9
++  #define XG_PHY_INTR_WIDTH 1
++  #define G_PHY1_INTR_LBN 8
++  #define G_PHY1_INTR_WIDTH 1
++  #define G_PHY0_INTR_LBN 7
++  #define G_PHY0_INTR_WIDTH 1
++/*************---- Driver generated events ----*************/
++  #define DRV_GEN_EV_CODE_LBN 60
++  #define DRV_GEN_EV_CODE_WIDTH 4
++  #define DRV_GEN_EV_DATA_LBN 0
++  #define DRV_GEN_EV_DATA_WIDTH 60
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_grmon.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_grmon.h     2008-05-19 00:33:29.333836963 +0300
+@@ -0,0 +1,129 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) 1G MAC
++ * counters.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++/*************---- 1G MAC Statistical Counters C Header ----*************/
++#define GRxGoodOct_offset 0x0
++    #define GRxGoodOct_WIDTH 48
++#define GRxBadOct_offset 0x8
++    #define GRxBadOct_WIDTH 48
++#define GRxMissPkt_offset 0x10
++    #define GRxMissPkt_WIDTH 32
++#define GRxFalseCRS_offset 0x14
++    #define GRxFalseCRS_WIDTH 32
++#define GRxPausePkt_offset 0x18
++    #define GRxPausePkt_WIDTH 32
++#define GRxBadPkt_offset 0x1C
++    #define GRxBadPkt_WIDTH 32
++#define GRxUcastPkt_offset 0x20
++    #define GRxUcastPkt_WIDTH 32
++#define GRxMcastPkt_offset 0x24
++    #define GRxMcastPkt_WIDTH 32
++#define GRxBcastPkt_offset 0x28
++    #define GRxBcastPkt_WIDTH 32
++#define GRxGoodLt64Pkt_offset 0x2C
++    #define GRxGoodLt64Pkt_WIDTH 32
++#define GRxBadLt64Pkt_offset 0x30
++    #define GRxBadLt64Pkt_WIDTH 32
++#define GRx64Pkt_offset 0x34
++    #define GRx64Pkt_WIDTH 32
++#define GRx65to127Pkt_offset 0x38
++    #define GRx65to127Pkt_WIDTH 32
++#define GRx128to255Pkt_offset 0x3C
++    #define GRx128to255Pkt_WIDTH 32
++#define GRx256to511Pkt_offset 0x40
++    #define GRx256to511Pkt_WIDTH 32
++#define GRx512to1023Pkt_offset 0x44
++    #define GRx512to1023Pkt_WIDTH 32
++#define GRx1024to15xxPkt_offset 0x48
++    #define GRx1024to15xxPkt_WIDTH 32
++#define GRx15xxtoJumboPkt_offset 0x4C
++    #define GRx15xxtoJumboPkt_WIDTH 32
++#define GRxGtJumboPkt_offset 0x50
++    #define GRxGtJumboPkt_WIDTH 32
++#define GRxFcsErr64to15xxPkt_offset 0x54
++    #define GRxFcsErr64to15xxPkt_WIDTH 32
++#define GRxFcsErr15xxtoJumboPkt_offset 0x58
++    #define GRxFcsErr15xxtoJumboPkt_WIDTH 32
++#define GRxFcsErrGtJumboPkt_offset 0x5C
++    #define GRxFcsErrGtJumboPkt_WIDTH 32
++#define GTxGoodBadOct_offset 0x80
++    #define GTxGoodBadOct_WIDTH 48
++#define GTxGoodOct_offset 0x88
++    #define GTxGoodOct_WIDTH 48
++#define GTxSglColPkt_offset 0x90
++    #define GTxSglColPkt_WIDTH 32
++#define GTxMultColPkt_offset 0x94
++    #define GTxMultColPkt_WIDTH 32
++#define GTxExColPkt_offset 0x98
++    #define GTxExColPkt_WIDTH 32
++#define GTxDefPkt_offset 0x9C
++    #define GTxDefPkt_WIDTH 32
++#define GTxLateCol_offset 0xA0
++    #define GTxLateCol_WIDTH 32
++#define GTxExDefPkt_offset 0xA4
++    #define GTxExDefPkt_WIDTH 32
++#define GTxPausePkt_offset 0xA8
++    #define GTxPausePkt_WIDTH 32
++#define GTxBadPkt_offset 0xAC
++    #define GTxBadPkt_WIDTH 32
++#define GTxUcastPkt_offset 0xB0
++    #define GTxUcastPkt_WIDTH 32
++#define GTxMcastPkt_offset 0xB4
++    #define GTxMcastPkt_WIDTH 32
++#define GTxBcastPkt_offset 0xB8
++    #define GTxBcastPkt_WIDTH 32
++#define GTxLt64Pkt_offset 0xBC
++    #define GTxLt64Pkt_WIDTH 32
++#define GTx64Pkt_offset 0xC0
++    #define GTx64Pkt_WIDTH 32
++#define GTx65to127Pkt_offset 0xC4
++    #define GTx65to127Pkt_WIDTH 32
++#define GTx128to255Pkt_offset 0xC8
++    #define GTx128to255Pkt_WIDTH 32
++#define GTx256to511Pkt_offset 0xCC
++    #define GTx256to511Pkt_WIDTH 32
++#define GTx512to1023Pkt_offset 0xD0
++    #define GTx512to1023Pkt_WIDTH 32
++#define GTx1024to15xxPkt_offset 0xD4
++    #define GTx1024to15xxPkt_WIDTH 32
++#define GTx15xxtoJumboPkt_offset 0xD8
++    #define GTx15xxtoJumboPkt_WIDTH 32
++#define GTxGtJumboPkt_offset 0xDC
++    #define GTxGtJumboPkt_WIDTH 32
++#define GTxNonTcpUdpPkt_offset 0xE0
++    #define GTxNonTcpUdpPkt_WIDTH 16
++#define GTxMacSrcErrPkt_offset 0xE4
++    #define GTxMacSrcErrPkt_WIDTH 16
++#define GTxIpSrcErrPkt_offset 0xE8
++    #define GTxIpSrcErrPkt_WIDTH 16
++#define GDmaDone_offset 0xEC
++    #define GDmaDone_WIDTH 32
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_intr_vec.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_intr_vec.h  2008-05-19 00:33:29.333836963 +0300
+@@ -0,0 +1,44 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) interrupt
++ * vector definitions.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++/*************---- Interrupt Vector Format C Header ----*************/
++#define DW0_OFST 0x0 /* Double-word 0: Event queue FIFO interrupts */
++  #define EVQ_FIFO_HF_LBN 1
++  #define EVQ_FIFO_HF_WIDTH 1
++  #define EVQ_FIFO_AF_LBN 0
++  #define EVQ_FIFO_AF_WIDTH 1
++#define DW1_OFST 0x4 /* Double-word 1: Interrupt indicator */
++  #define INT_FLAG_LBN 0
++  #define INT_FLAG_WIDTH 1
++#define DW2_OFST 0x8 /* Double-word 2: Fatal interrupts */
++  #define FATAL_INT_LBN 0
++  #define FATAL_INT_WIDTH 1
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_mac.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_mac.h       2008-05-19 00:33:29.337837194 +0300
+@@ -0,0 +1,711 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) MAC register
++ * definitions.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++/*********---- 1G/10G Ethernet MAC Wrapper Registers C Header ----*********/
++#define MD_TXD_REG_KER_OFST 0xC00 /* PHY management transmit data register */
++#define MD_TXD_REG_OFST 0xC00 /* PHY management transmit data register */
++  #define MD_TXD_LBN 0
++  #define MD_TXD_WIDTH 16
++#define MD_RXD_REG_KER_OFST 0xC10 /* PHY management receive data register */
++#define MD_RXD_REG_OFST 0xC10 /* PHY management receive data register */
++  #define MD_RXD_LBN 0
++  #define MD_RXD_WIDTH 16
++#define MD_CS_REG_KER_OFST 0xC20 /* PHY management configuration &
++                                  status register */
++#define MD_CS_REG_OFST 0xC20 /* PHY management configuration &
++                              status register */
++  #define MD_PT_LBN 7
++  #define MD_PT_WIDTH 3
++  #define MD_PL_LBN 6
++  #define MD_PL_WIDTH 1
++  #define MD_INT_CLR_LBN 5
++  #define MD_INT_CLR_WIDTH 1
++  #define MD_GC_LBN 4
++  #define MD_GC_WIDTH 1
++  #define MD_PRSP_LBN 3
++  #define MD_PRSP_WIDTH 1
++  #define MD_RIC_LBN 2
++  #define MD_RIC_WIDTH 1
++  #define MD_RDC_LBN 1
++  #define MD_RDC_WIDTH 1
++  #define MD_WRC_LBN 0
++  #define MD_WRC_WIDTH 1
++#define MD_PHY_ADR_REG_KER_OFST 0xC30 /* PHY management PHY address register */
++#define MD_PHY_ADR_REG_OFST 0xC30 /* PHY management PHY address register */
++  #define MD_PHY_ADR_LBN 0
++  #define MD_PHY_ADR_WIDTH 16
++#define MD_ID_REG_KER_OFST 0xC40 /* PHY management ID register */
++#define MD_ID_REG_OFST 0xC40 /* PHY management ID register */
++  #define MD_PRT_ADR_LBN 11
++  #define MD_PRT_ADR_WIDTH 5
++  #define MD_DEV_ADR_LBN 6
++  #define MD_DEV_ADR_WIDTH 5
++#define MD_STAT_REG_KER_OFST 0xC50 /* PHY management status & mask register */
++#define MD_STAT_REG_OFST 0xC50 /* PHY management status & mask register */
++  #define MD_PINT_LBN 4
++  #define MD_PINT_WIDTH 1
++  #define MD_DONE_LBN 3
++  #define MD_DONE_WIDTH 1
++  #define MD_BSERR_LBN 2
++  #define MD_BSERR_WIDTH 1
++  #define MD_LNFL_LBN 1
++  #define MD_LNFL_WIDTH 1
++  #define MD_BSY_LBN 0
++  #define MD_BSY_WIDTH 1
++#define MAC0_STAT_DMA_REG_KER_OFST 0xC60 /* Port 0 MAC statistical counter
++                                          DMA register */
++#define MAC0_STAT_DMA_REG_OFST 0xC60 /* Port 0 MAC statistical counter
++                                      DMA register */
++  #define MAC0_STAT_DMA_CMD_LBN 48
++  #define MAC0_STAT_DMA_CMD_WIDTH 1
++  #define MAC0_STAT_DMA_ADR_LBN 0
++  #define MAC0_STAT_DMA_ADR_WIDTH 48
++#define MAC1_STAT_DMA_REG_KER_OFST 0xC70 /* Port 1 MAC statistical counter
++                                          DMA register */
++#define MAC1_STAT_DMA_REG_OFST 0xC70 /* Port 1 MAC statistical counter
++                                      DMA register */
++  #define MAC1_STAT_DMA_CMD_LBN 48
++  #define MAC1_STAT_DMA_CMD_WIDTH 1
++  #define MAC1_STAT_DMA_ADR_LBN 0
++  #define MAC1_STAT_DMA_ADR_WIDTH 48
++#define MAC0_CTRL_REG_KER_OFST 0xC80 /* Port 0 MAC control register */
++#define MAC0_CTRL_REG_OFST 0xC80 /* Port 0 MAC control register */
++  #define MAC0_XOFF_VAL_LBN 16
++  #define MAC0_XOFF_VAL_WIDTH 16
++  #define MAC0_BCAD_ACPT_LBN 4
++  #define MAC0_BCAD_ACPT_WIDTH 1
++  #define MAC0_UC_PROM_LBN 3
++  #define MAC0_UC_PROM_WIDTH 1
++  #define MAC0_LINK_STATUS_LBN 2
++  #define MAC0_LINK_STATUS_WIDTH 1
++  #define MAC0_SPEED_LBN 0
++  #define MAC0_SPEED_WIDTH 2
++#define MAC1_CTRL_REG_KER_OFST 0xC90 /* Port 1 MAC control register */
++#define MAC1_CTRL_REG_OFST 0xC90 /* Port 1 MAC control register */
++  #define MAC1_XOFF_VAL_LBN 16
++  #define MAC1_XOFF_VAL_WIDTH 16
++  #define MAC1_BCAD_ACPT_LBN 4
++  #define MAC1_BCAD_ACPT_WIDTH 1
++  #define MAC1_UC_PROM_LBN 3
++  #define MAC1_UC_PROM_WIDTH 1
++  #define MAC1_LINK_STATUS_LBN 2
++  #define MAC1_LINK_STATUS_WIDTH 1
++  #define MAC1_SPEED_LBN 0
++  #define MAC1_SPEED_WIDTH 2
++#define MAC_MC_HASH_REG0_KER_OFST 0xCA0 /* Multicast address hash table */
++#define MAC_MC_HASH_REG0_OFST 0xCA0 /* Multicast address hash table */
++  #define MAC_MCAST_HASH0_LBN 0
++  #define MAC_MCAST_HASH0_WIDTH 128
++#define MAC_MC_HASH_REG1_KER_OFST 0xCB0 /* Multicast address hash table */
++#define MAC_MC_HASH_REG1_OFST 0xCB0 /* Multicast address hash table */
++  #define MAC_MCAST_HASH1_LBN 0
++  #define MAC_MCAST_HASH1_WIDTH 128
++/*************---- 1G MAC Port 0 Registers C Header ----*************/
++#define GM_P0_BASE 0xE00
++#define GM_P1_BASE 0x1000
++#define GM_CFG1_REG_KER_OFST 0x00 /* GMAC configuration register 1 */
++#define GM_CFG1_REG_OFST 0x00 /* GMAC configuration register 1 */
++  #define GM_SW_RST_LBN 31
++  #define GM_SW_RST_WIDTH 1
++  #define GM_SIM_RST_LBN 30
++  #define GM_SIM_RST_WIDTH 1
++  #define GM_RST_RX_MAC_CTL_LBN 19
++  #define GM_RST_RX_MAC_CTL_WIDTH 1
++  #define GM_RST_TX_MAC_CTL_LBN 18
++  #define GM_RST_TX_MAC_CTL_WIDTH 1
++  #define GM_RST_RX_FUNC_LBN 17
++  #define GM_RST_RX_FUNC_WIDTH 1
++  #define GM_RST_TX_FUNC_LBN 16
++  #define GM_RST_TX_FUNC_WIDTH 1
++  #define GM_LOOP_LBN 8
++  #define GM_LOOP_WIDTH 1
++  #define GM_RX_FC_EN_LBN 5
++  #define GM_RX_FC_EN_WIDTH 1
++  #define GM_TX_FC_EN_LBN 4
++  #define GM_TX_FC_EN_WIDTH 1
++  #define GM_SYNC_RXEN_LBN 3
++  #define GM_SYNC_RXEN_WIDTH 1
++  #define GM_RX_EN_LBN 2
++  #define GM_RX_EN_WIDTH 1
++  #define GM_SYNC_TXEN_LBN 1
++  #define GM_SYNC_TXEN_WIDTH 1
++  #define GM_TX_EN_LBN 0
++  #define GM_TX_EN_WIDTH 1
++#define GM_CFG2_REG_KER_OFST 0x10 /* GMAC configuration register 2 */
++#define GM_CFG2_REG_OFST 0x10 /* GMAC configuration register 2 */
++  #define GM_PAMBL_LEN_LBN 12
++  #define GM_PAMBL_LEN_WIDTH 4
++  #define GM_IF_MODE_LBN 8
++  #define GM_IF_MODE_WIDTH 2
++  #define GM_HUGE_FRM_EN_LBN 5
++  #define GM_HUGE_FRM_EN_WIDTH 1
++  #define GM_LEN_CHK_LBN 4
++  #define GM_LEN_CHK_WIDTH 1
++  #define GM_PAD_CRC_EN_LBN 2
++  #define GM_PAD_CRC_EN_WIDTH 1
++  #define GM_CRC_EN_LBN 1
++  #define GM_CRC_EN_WIDTH 1
++  #define GM_FD_LBN 0
++  #define GM_FD_WIDTH 1
++#define GM_IPG_REG_KER_OFST 0x20 /* GMAC IPG register */
++#define GM_IPG_REG_OFST 0x20 /* GMAC IPG register */
++  #define GM_NONB2B_IPG1_LBN 24
++  #define GM_NONB2B_IPG1_WIDTH 7
++  #define GM_NONB2B_IPG2_LBN 16
++  #define GM_NONB2B_IPG2_WIDTH 7
++  #define GM_MIN_IPG_ENF_LBN 8
++  #define GM_MIN_IPG_ENF_WIDTH 8
++  #define GM_B2B_IPG_LBN 0
++  #define GM_B2B_IPG_WIDTH 7
++#define GM_HD_REG_KER_OFST 0x30 /* GMAC half duplex register */
++#define GM_HD_REG_OFST 0x30 /* GMAC half duplex register */
++  #define GM_ALT_BOFF_VAL_LBN 20
++  #define GM_ALT_BOFF_VAL_WIDTH 4
++  #define GM_ALT_BOFF_EN_LBN 19
++  #define GM_ALT_BOFF_EN_WIDTH 1
++  #define GM_BP_NO_BOFF_LBN 18
++  #define GM_BP_NO_BOFF_WIDTH 1
++  #define GM_DIS_BOFF_LBN 17
++  #define GM_DIS_BOFF_WIDTH 1
++  #define GM_EXDEF_TX_EN_LBN 16
++  #define GM_EXDEF_TX_EN_WIDTH 1
++  #define GM_RTRY_LIMIT_LBN 12
++  #define GM_RTRY_LIMIT_WIDTH 4
++  #define GM_COL_WIN_LBN 0
++  #define GM_COL_WIN_WIDTH 10
++#define GM_MAX_FLEN_REG_KER_OFST 0x40 /* GMAC maximum frame length register */
++#define GM_MAX_FLEN_REG_OFST 0x40 /* GMAC maximum frame length register */
++  #define GM_MAX_FLEN_LBN 0
++  #define GM_MAX_FLEN_WIDTH 16
++#define GM_TEST_REG_KER_OFST 0x70 /* GMAC test register */
++#define GM_TEST_REG_OFST 0x70 /* GMAC test register */
++  #define GM_MAX_BOFF_LBN 3
++  #define GM_MAX_BOFF_WIDTH 1
++  #define GM_REG_TX_FLOW_EN_LBN 2
++  #define GM_REG_TX_FLOW_EN_WIDTH 1
++  #define GM_TEST_PAUSE_LBN 1
++  #define GM_TEST_PAUSE_WIDTH 1
++  #define GM_SHORT_SLOT_LBN 0
++  #define GM_SHORT_SLOT_WIDTH 1
++#define GM_ADR1_REG_KER_OFST 0x100 /* GMAC station address register 1 */
++#define GM_ADR1_REG_OFST 0x100 /* GMAC station address register 1 */
++  #define GM_ADR1_LBN 0
++  #define GM_ADR1_WIDTH 32
++#define GM_ADR2_REG_KER_OFST 0x110 /* GMAC station address register 2 */
++#define GM_ADR2_REG_OFST 0x110 /* GMAC station address register 2 */
++  #define GM_ADR2_LBN 16
++  #define GM_ADR2_WIDTH 16
++#define GMF_CFG0_REG_KER_OFST 0x120 /* GMAC FIFO configuration register 0 */
++#define GMF_CFG0_REG_OFST 0x120 /* GMAC FIFO configuration register 0 */
++  #define GMF_FTFENRPLY_LBN 20
++  #define GMF_FTFENRPLY_WIDTH 1
++  #define GMF_STFENRPLY_LBN 19
++  #define GMF_STFENRPLY_WIDTH 1
++  #define GMF_FRFENRPLY_LBN 18
++  #define GMF_FRFENRPLY_WIDTH 1
++  #define GMF_SRFENRPLY_LBN 17
++  #define GMF_SRFENRPLY_WIDTH 1
++  #define GMF_WTMENRPLY_LBN 16
++  #define GMF_WTMENRPLY_WIDTH 1
++  #define GMF_FTFENREQ_LBN 12
++  #define GMF_FTFENREQ_WIDTH 1
++  #define GMF_STFENREQ_LBN 11
++  #define GMF_STFENREQ_WIDTH 1
++  #define GMF_FRFENREQ_LBN 10
++  #define GMF_FRFENREQ_WIDTH 1
++  #define GMF_SRFENREQ_LBN 9
++  #define GMF_SRFENREQ_WIDTH 1
++  #define GMF_WTMENREQ_LBN 8
++  #define GMF_WTMENREQ_WIDTH 1
++  #define GMF_HSTRSTFT_LBN 4
++  #define GMF_HSTRSTFT_WIDTH 1
++  #define GMF_HSTRSTST_LBN 3
++  #define GMF_HSTRSTST_WIDTH 1
++  #define GMF_HSTRSTFR_LBN 2
++  #define GMF_HSTRSTFR_WIDTH 1
++  #define GMF_HSTRSTSR_LBN 1
++  #define GMF_HSTRSTSR_WIDTH 1
++  #define GMF_HSTRSTWT_LBN 0
++  #define GMF_HSTRSTWT_WIDTH 1
++#define GMF_CFG1_REG_KER_OFST 0x130 /* GMAC FIFO configuration register 1 */
++#define GMF_CFG1_REG_OFST 0x130 /* GMAC FIFO configuration register 1 */
++  #define GMF_CFGFRTH_LBN 16
++  #define GMF_CFGFRTH_WIDTH 5
++  #define GMF_CFGXOFFRTX_LBN 0
++  #define GMF_CFGXOFFRTX_WIDTH 16
++#define GMF_CFG2_REG_KER_OFST 0x140 /* GMAC FIFO configuration register 2 */
++#define GMF_CFG2_REG_OFST 0x140 /* GMAC FIFO configuration register 2 */
++  #define GMF_CFGHWM_LBN 16
++  #define GMF_CFGHWM_WIDTH 6
++  #define GMF_CFGLWM_LBN 0
++  #define GMF_CFGLWM_WIDTH 6
++#define GMF_CFG3_REG_KER_OFST 0x150 /* GMAC FIFO configuration register 3 */
++#define GMF_CFG3_REG_OFST 0x150 /* GMAC FIFO configuration register 3 */
++  #define GMF_CFGHWMFT_LBN 16
++  #define GMF_CFGHWMFT_WIDTH 6
++  #define GMF_CFGFTTH_LBN 0
++  #define GMF_CFGFTTH_WIDTH 6
++#define GMF_CFG4_REG_KER_OFST 0x160 /* GMAC FIFO configuration register 4 */
++#define GMF_CFG4_REG_OFST 0x160 /* GMAC FIFO configuration register 4 */
++  #define GMF_HSTFLTRFRM_LBN 0
++  #define GMF_HSTFLTRFRM_WIDTH 18
++#define GMF_CFG5_REG_KER_OFST 0x170 /* GMAC FIFO configuration register 5 */
++#define GMF_CFG5_REG_OFST 0x170 /* GMAC FIFO configuration register 5 */
++  #define GMF_CFGHDPLX_LBN 22
++  #define GMF_CFGHDPLX_WIDTH 1
++  #define GMF_SRFULL_LBN 21
++  #define GMF_SRFULL_WIDTH 1
++  #define GMF_HSTSRFULLCLR_LBN 20
++  #define GMF_HSTSRFULLCLR_WIDTH 1
++  #define GMF_CFGBYTMODE_LBN 19
++  #define GMF_CFGBYTMODE_WIDTH 1
++  #define GMF_HSTDRPLT64_LBN 18
++  #define GMF_HSTDRPLT64_WIDTH 1
++  #define GMF_HSTFLTRFRMDC_LBN 0
++  #define GMF_HSTFLTRFRMDC_WIDTH 18
++/*************---- 10G MAC Registers C Header ----*************/
++#define XM_ADR_LO_REG_KER_P0_OFST 0x1200 /* XGMAC address register low -
++                                          port 0 */
++#define XM_ADR_LO_REG_P0_OFST 0x1200 /* XGMAC address register low -
++                                      port 0 */
++  #define XM_ADR_LO_LBN 0
++  #define XM_ADR_LO_WIDTH 32
++#define XM_ADR_HI_REG_KER_P0_OFST 0x1210 /* XGMAC address register high -
++                                          port 0 */
++#define XM_ADR_HI_REG_P0_OFST 0x1210 /* XGMAC address register high -
++                                      port 0 */
++  #define XM_ADR_HI_LBN 0
++  #define XM_ADR_HI_WIDTH 16
++#define XM_GLB_CFG_REG_KER_P0_OFST 0x1220 /* XGMAC global configuration -
++                                           port 0 */
++#define XM_GLB_CFG_REG_P0_OFST 0x1220 /* XGMAC global configuration -
++                                       port 0 */
++  #define XM_LINE_LB_DEEP_RSVD_LBN 28
++  #define XM_LINE_LB_DEEP_RSVD_WIDTH 1
++  #define XM_RMTFLT_GEN_LBN 17
++  #define XM_RMTFLT_GEN_WIDTH 1
++  #define XM_DEBUG_MODE_LBN 16
++  #define XM_DEBUG_MODE_WIDTH 1
++  #define XM_RX_STAT_EN_LBN 11
++  #define XM_RX_STAT_EN_WIDTH 1
++  #define XM_TX_STAT_EN_LBN 10
++  #define XM_TX_STAT_EN_WIDTH 1
++  #define XM_CUT_THRU_MODE_LBN 7
++  #define XM_CUT_THRU_MODE_WIDTH 1
++  #define XM_RX_JUMBO_MODE_LBN 6
++  #define XM_RX_JUMBO_MODE_WIDTH 1
++  #define XM_WAN_MODE_LBN 5
++  #define XM_WAN_MODE_WIDTH 1
++  #define XM_AUTOCLR_MODE_LBN 4
++  #define XM_AUTOCLR_MODE_WIDTH 1
++  #define XM_INTCLR_MODE_LBN 3
++  #define XM_INTCLR_MODE_WIDTH 1
++  #define XM_CORE_RST_LBN 0
++  #define XM_CORE_RST_WIDTH 1
++#define XM_TX_CFG_REG_KER_P0_OFST 0x1230 /* XGMAC transmit configuration -
++                                          port 0 */
++#define XM_TX_CFG_REG_P0_OFST 0x1230 /* XGMAC transmit configuration -
++                                      port 0 */
++  #define XM_TX_PROG_LBN 24
++  #define XM_TX_PROG_WIDTH 1
++  #define XM_IPG_LBN 16
++  #define XM_IPG_WIDTH 4
++  #define XM_FCNTL_LBN 10
++  #define XM_FCNTL_WIDTH 1
++  #define XM_TXCRC_LBN 8
++  #define XM_TXCRC_WIDTH 1
++  #define XM_EDRC_LBN 6
++  #define XM_EDRC_WIDTH 1
++  #define XM_AUTO_PAD_LBN 5
++  #define XM_AUTO_PAD_WIDTH 1
++  #define XM_TX_PRMBL_LBN 2
++  #define XM_TX_PRMBL_WIDTH 1
++  #define XM_TXEN_LBN 1
++  #define XM_TXEN_WIDTH 1
++  #define XM_TX_RST_LBN 0
++  #define XM_TX_RST_WIDTH 1
++#define XM_RX_CFG_REG_KER_P0_OFST 0x1240 /* XGMAC receive configuration -
++                                          port 0 */
++#define XM_RX_CFG_REG_P0_OFST 0x1240 /* XGMAC receive configuration -
++                                      port 0 */
++  #define XM_PASS_LENERR_LBN 26
++  #define XM_PASS_LENERR_WIDTH 1
++  #define XM_PASS_CRC_ERR_LBN 25
++  #define XM_PASS_CRC_ERR_WIDTH 1
++  #define XM_PASS_PRMBLE_ERR_LBN 24
++  #define XM_PASS_PRMBLE_ERR_WIDTH 1
++  #define XM_REJ_UCAST_LBN 18
++  #define XM_REJ_UCAST_WIDTH 1
++  #define XM_BSC_EN_LBN 17
++  #define XM_BSC_EN_WIDTH 1
++  #define XM_ACPT_ALL_MCAST_LBN 11
++  #define XM_ACPT_ALL_MCAST_WIDTH 1
++  #define XM_PASS_SAP_LBN 10
++  #define XM_PASS_SAP_WIDTH 1
++  #define XM_ACPT_ALL_UCAST_LBN 9
++  #define XM_ACPT_ALL_UCAST_WIDTH 1
++  #define XM_AUTO_DEPAD_LBN 8
++  #define XM_AUTO_DEPAD_WIDTH 1
++  #define XM_RXCRC_LBN 3
++  #define XM_RXCRC_WIDTH 1
++  #define XM_RX_PRMBL_LBN 2
++  #define XM_RX_PRMBL_WIDTH 1
++  #define XM_RXEN_LBN 1
++  #define XM_RXEN_WIDTH 1
++  #define XM_RX_RST_LBN 0
++  #define XM_RX_RST_WIDTH 1
++#define XM_FC_REG_KER_P0_OFST 0x1270 /* XGMAC flow control register -
++                                      port 0 */
++#define XM_FC_REG_P0_OFST 0x1270 /* XGMAC flow control register -
++                                  port 0 */
++  #define XM_PAUSE_TIME_LBN 16
++  #define XM_PAUSE_TIME_WIDTH 16
++  #define XM_RX_MAC_STAT_LBN 11
++  #define XM_RX_MAC_STAT_WIDTH 1
++  #define XM_TX_MAC_STAT_LBN 10
++  #define XM_TX_MAC_STAT_WIDTH 1
++  #define XM_MCNTL_PASS_LBN 8
++  #define XM_MCNTL_PASS_WIDTH 2
++  #define XM_REJ_CNTL_UCAST_LBN 6
++  #define XM_REJ_CNTL_UCAST_WIDTH 1
++  #define XM_REJ_CNTL_MCAST_LBN 5
++  #define XM_REJ_CNTL_MCAST_WIDTH 1
++  #define XM_AUTO_XMIT_ZPAUSE_LBN 4
++  #define XM_AUTO_XMIT_ZPAUSE_WIDTH 1
++  #define XM_AUTO_XMIT_PAUSE_LBN 3
++  #define XM_AUTO_XMIT_PAUSE_WIDTH 1
++  #define XM_ZPAUSE_LBN 2
++  #define XM_ZPAUSE_WIDTH 1
++  #define XM_XMIT_PAUSE_LBN 1
++  #define XM_XMIT_PAUSE_WIDTH 1
++  #define XM_DIS_FCNTL_LBN 0
++  #define XM_DIS_FCNTL_WIDTH 1
++#define XM_PAUSE_TIME_REG_KER_P0_OFST 0x1290 /* XGMAC pause time register -
++                                              port 0 */
++#define XM_PAUSE_TIME_REG_P0_OFST 0x1290 /* XGMAC pause time register -
++                                          port 0 */
++  #define XM_TX_PAUSE_CNT_LBN 16
++  #define XM_TX_PAUSE_CNT_WIDTH 16
++  #define XM_RX_PAUSE_CNT_LBN 0
++  #define XM_RX_PAUSE_CNT_WIDTH 16
++#define XM_TX_PARAM_REG_KER_P0_OFST 0x12D0 /* XGMAC transmit parameter
++                                            register - port 0 */
++#define XM_TX_PARAM_REG_P0_OFST 0x12D0 /* XGMAC transmit parameter register -
++                                        port 0 */
++  #define XM_TX_JUMBO_MODE_LBN 31
++  #define XM_TX_JUMBO_MODE_WIDTH 1
++  #define XM_MAX_TX_FRM_SIZE_LBN 16
++  #define XM_MAX_TX_FRM_SIZE_WIDTH 14
++  #define XM_PAD_CHAR_LBN 0
++  #define XM_PAD_CHAR_WIDTH 8
++#define XM_RX_PARAM_REG_KER_P0_OFST 0x12E0 /* XGMAC receive parameter
++                                            register - port 0 */
++#define XM_RX_PARAM_REG_P0_OFST 0x12E0 /* XGMAC receive parameter register -
++                                        port 0 */
++  #define XM_MAX_RX_FRM_SIZE_LBN 0
++  #define XM_MAX_RX_FRM_SIZE_WIDTH 14
++#define XX_PWR_RST_REG_KER_P0_OFST 0x1300 /* XGXS/XAUI powerdown/reset
++                                           register */
++#define XX_PWR_RST_REG_P0_OFST 0x1300 /* XGXS/XAUI powerdown/reset register */
++  #define XX_PWRDND_SIG_LBN 31
++  #define XX_PWRDND_SIG_WIDTH 1
++  #define XX_PWRDNC_SIG_LBN 30
++  #define XX_PWRDNC_SIG_WIDTH 1
++  #define XX_PWRDNB_SIG_LBN 29
++  #define XX_PWRDNB_SIG_WIDTH 1
++  #define XX_PWRDNA_SIG_LBN 28
++  #define XX_PWRDNA_SIG_WIDTH 1
++  #define XX_SIM_MODE_LBN 27
++  #define XX_SIM_MODE_WIDTH 1
++  #define XX_RSTPLLCD_SIG_LBN 25
++  #define XX_RSTPLLCD_SIG_WIDTH 1
++  #define XX_RSTPLLAB_SIG_LBN 24
++  #define XX_RSTPLLAB_SIG_WIDTH 1
++  #define XX_RESETD_SIG_LBN 23
++  #define XX_RESETD_SIG_WIDTH 1
++  #define XX_RESETC_SIG_LBN 22
++  #define XX_RESETC_SIG_WIDTH 1
++  #define XX_RESETB_SIG_LBN 21
++  #define XX_RESETB_SIG_WIDTH 1
++  #define XX_RESETA_SIG_LBN 20
++  #define XX_RESETA_SIG_WIDTH 1
++  #define XX_RSTXGXSTX_SIG_LBN 18
++  #define XX_RSTXGXSTX_SIG_WIDTH 1
++  #define XX_RSTXGXSRX_SIG_LBN 17
++  #define XX_RSTXGXSRX_SIG_WIDTH 1
++  #define XX_SD_RST_ACT_LBN 16
++  #define XX_SD_RST_ACT_WIDTH 1
++  #define XX_PWRDND_EN_LBN 15
++  #define XX_PWRDND_EN_WIDTH 1
++  #define XX_PWRDNC_EN_LBN 14
++  #define XX_PWRDNC_EN_WIDTH 1
++  #define XX_PWRDNB_EN_LBN 13
++  #define XX_PWRDNB_EN_WIDTH 1
++  #define XX_PWRDNA_EN_LBN 12
++  #define XX_PWRDNA_EN_WIDTH 1
++  #define XX_RSTPLLCD_EN_LBN 9
++  #define XX_RSTPLLCD_EN_WIDTH 1
++  #define XX_RSTPLLAB_EN_LBN 8
++  #define XX_RSTPLLAB_EN_WIDTH 1
++  #define XX_RESETD_EN_LBN 7
++  #define XX_RESETD_EN_WIDTH 1
++  #define XX_RESETC_EN_LBN 6
++  #define XX_RESETC_EN_WIDTH 1
++  #define XX_RESETB_EN_LBN 5
++  #define XX_RESETB_EN_WIDTH 1
++  #define XX_RESETA_EN_LBN 4
++  #define XX_RESETA_EN_WIDTH 1
++  #define XX_RSTXGXSTX_EN_LBN 2
++  #define XX_RSTXGXSTX_EN_WIDTH 1
++  #define XX_RSTXGXSRX_EN_LBN 1
++  #define XX_RSTXGXSRX_EN_WIDTH 1
++  #define XX_RST_XX_EN_LBN 0
++  #define XX_RST_XX_EN_WIDTH 1
++#define XX_SD_CTL_REG_KER_P0_OFST 0x1310 /* XGXS/XAUI powerdown/reset control
++                                          register */
++#define XX_SD_CTL_REG_P0_OFST 0x1310 /* XGXS/XAUI powerdown/reset control
++                                      register */
++  #define XX_TERMADJ1_LBN 17
++  #define XX_TERMADJ1_WIDTH 1
++  #define XX_TERMADJ0_LBN 16
++  #define XX_TERMADJ0_WIDTH 1
++  #define XX_HIDRVD_LBN 15
++  #define XX_HIDRVD_WIDTH 1
++  #define XX_LODRVD_LBN 14
++  #define XX_LODRVD_WIDTH 1
++  #define XX_HIDRVC_LBN 13
++  #define XX_HIDRVC_WIDTH 1
++  #define XX_LODRVC_LBN 12
++  #define XX_LODRVC_WIDTH 1
++  #define XX_HIDRVB_LBN 11
++  #define XX_HIDRVB_WIDTH 1
++  #define XX_LODRVB_LBN 10
++  #define XX_LODRVB_WIDTH 1
++  #define XX_HIDRVA_LBN 9
++  #define XX_HIDRVA_WIDTH 1
++  #define XX_LODRVA_LBN 8
++  #define XX_LODRVA_WIDTH 1
++  #define XX_LPBKD_LBN 3
++  #define XX_LPBKD_WIDTH 1
++  #define XX_LPBKC_LBN 2
++  #define XX_LPBKC_WIDTH 1
++  #define XX_LPBKB_LBN 1
++  #define XX_LPBKB_WIDTH 1
++  #define XX_LPBKA_LBN 0
++  #define XX_LPBKA_WIDTH 1
++#define XX_TXDRV_CTL_REG_KER_P0_OFST 0x1320 /* XAUI SerDes transmit drive
++                                             control register */
++#define XX_TXDRV_CTL_REG_P0_OFST 0x1320 /* XAUI SerDes transmit drive
++                                         control register */
++  #define XX_DEQD_LBN 28
++  #define XX_DEQD_WIDTH 4
++  #define XX_DEQC_LBN 24
++  #define XX_DEQC_WIDTH 4
++  #define XX_DEQB_LBN 20
++  #define XX_DEQB_WIDTH 4
++  #define XX_DEQA_LBN 16
++  #define XX_DEQA_WIDTH 4
++  #define XX_DTXD_LBN 12
++  #define XX_DTXD_WIDTH 4
++  #define XX_DTXC_LBN 8
++  #define XX_DTXC_WIDTH 4
++  #define XX_DTXB_LBN 4
++  #define XX_DTXB_WIDTH 4
++  #define XX_DTXA_LBN 0
++  #define XX_DTXA_WIDTH 4
++#define XX_PRBS_CTL_REG_KER_P0_OFST 0x1330 /* XAUI PRBS control register */
++#define XX_PRBS_CTL_REG_P0_OFST 0x1330 /* XAUI PRBS control register */
++  #define XX_CH3_RX_PRBS_SEL_LBN 30
++  #define XX_CH3_RX_PRBS_SEL_WIDTH 2
++  #define XX_CH3_RX_PRBS_INV_LBN 29
++  #define XX_CH3_RX_PRBS_INV_WIDTH 1
++  #define XX_CH3_RX_PRBS_CHKEN_LBN 28
++  #define XX_CH3_RX_PRBS_CHKEN_WIDTH 1
++  #define XX_CH2_RX_PRBS_SEL_LBN 26
++  #define XX_CH2_RX_PRBS_SEL_WIDTH 2
++  #define XX_CH2_RX_PRBS_INV_LBN 25
++  #define XX_CH2_RX_PRBS_INV_WIDTH 1
++  #define XX_CH2_RX_PRBS_CHKEN_LBN 24
++  #define XX_CH2_RX_PRBS_CHKEN_WIDTH 1
++  #define XX_CH1_RX_PRBS_SEL_LBN 22
++  #define XX_CH1_RX_PRBS_SEL_WIDTH 2
++  #define XX_CH1_RX_PRBS_INV_LBN 21
++  #define XX_CH1_RX_PRBS_INV_WIDTH 1
++  #define XX_CH1_RX_PRBS_CHKEN_LBN 20
++  #define XX_CH1_RX_PRBS_CHKEN_WIDTH 1
++  #define XX_CH0_RX_PRBS_SEL_LBN 18
++  #define XX_CH0_RX_PRBS_SEL_WIDTH 2
++  #define XX_CH0_RX_PRBS_INV_LBN 17
++  #define XX_CH0_RX_PRBS_INV_WIDTH 1
++  #define XX_CH0_RX_PRBS_CHKEN_LBN 16
++  #define XX_CH0_RX_PRBS_CHKEN_WIDTH 1
++  #define XX_CH3_TX_PRBS_SEL_LBN 14
++  #define XX_CH3_TX_PRBS_SEL_WIDTH 2
++  #define XX_CH3_TX_PRBS_INV_LBN 13
++  #define XX_CH3_TX_PRBS_INV_WIDTH 1
++  #define XX_CH3_TX_PRBS_CHKEN_LBN 12
++  #define XX_CH3_TX_PRBS_CHKEN_WIDTH 1
++  #define XX_CH2_TX_PRBS_SEL_LBN 10
++  #define XX_CH2_TX_PRBS_SEL_WIDTH 2
++  #define XX_CH2_TX_PRBS_INV_LBN 9
++  #define XX_CH2_TX_PRBS_INV_WIDTH 1
++  #define XX_CH2_TX_PRBS_CHKEN_LBN 8
++  #define XX_CH2_TX_PRBS_CHKEN_WIDTH 1
++  #define XX_CH1_TX_PRBS_SEL_LBN 6
++  #define XX_CH1_TX_PRBS_SEL_WIDTH 2
++  #define XX_CH1_TX_PRBS_INV_LBN 5
++  #define XX_CH1_TX_PRBS_INV_WIDTH 1
++  #define XX_CH1_TX_PRBS_CHKEN_LBN 4
++  #define XX_CH1_TX_PRBS_CHKEN_WIDTH 1
++  #define XX_CH0_TX_PRBS_SEL_LBN 2
++  #define XX_CH0_TX_PRBS_SEL_WIDTH 2
++  #define XX_CH0_TX_PRBS_INV_LBN 1
++  #define XX_CH0_TX_PRBS_INV_WIDTH 1
++  #define XX_CH0_TX_PRBS_CHKEN_LBN 0
++  #define XX_CH0_TX_PRBS_CHKEN_WIDTH 1
++#define XX_PRBS_CHK_REG_KER_P0_OFST 0x1340 /* XAUI PRBS checker control
++                                            register */
++#define XX_PRBS_CHK_REG_P0_OFST 0x1340 /* XAUI PRBS checker control
++                                        register */
++  #define XX_REV_LB_EN_LBN 16
++  #define XX_REV_LB_EN_WIDTH 1
++  #define XX_CH3_DEG_DET_LBN 15
++  #define XX_CH3_DEG_DET_WIDTH 1
++  #define XX_CH3_LFSR_LOCK_IND_LBN 14
++  #define XX_CH3_LFSR_LOCK_IND_WIDTH 1
++  #define XX_CH3_PRBS_FRUN_LBN 13
++  #define XX_CH3_PRBS_FRUN_WIDTH 1
++  #define XX_CH3_ERR_CHK_LBN 12
++  #define XX_CH3_ERR_CHK_WIDTH 1
++  #define XX_CH2_DEG_DET_LBN 11
++  #define XX_CH2_DEG_DET_WIDTH 1
++  #define XX_CH2_LFSR_LOCK_IND_LBN 10
++  #define XX_CH2_LFSR_LOCK_IND_WIDTH 1
++  #define XX_CH2_PRBS_FRUN_LBN 9
++  #define XX_CH2_PRBS_FRUN_WIDTH 1
++  #define XX_CH2_ERR_CHK_LBN 8
++  #define XX_CH2_ERR_CHK_WIDTH 1
++  #define XX_CH1_DEG_DET_LBN 7
++  #define XX_CH1_DEG_DET_WIDTH 1
++  #define XX_CH1_LFSR_LOCK_IND_LBN 6
++  #define XX_CH1_LFSR_LOCK_IND_WIDTH 1
++  #define XX_CH1_PRBS_FRUN_LBN 5
++  #define XX_CH1_PRBS_FRUN_WIDTH 1
++  #define XX_CH1_ERR_CHK_LBN 4
++  #define XX_CH1_ERR_CHK_WIDTH 1
++  #define XX_CH0_DEG_DET_LBN 3
++  #define XX_CH0_DEG_DET_WIDTH 1
++  #define XX_CH0_LFSR_LOCK_IND_LBN 2
++  #define XX_CH0_LFSR_LOCK_IND_WIDTH 1
++  #define XX_CH0_PRBS_FRUN_LBN 1
++  #define XX_CH0_PRBS_FRUN_WIDTH 1
++  #define XX_CH0_ERR_CHK_LBN 0
++  #define XX_CH0_ERR_CHK_WIDTH 1
++#define XX_PRBS_ERR_REG_KER_P0_OFST 0x1350 /* XAUI PRBS checker error
++                                            count register */
++#define XX_PRBS_ERR_REG_P0_OFST 0x1350 /* XAUI PRBS checker error count
++                                        register */
++  #define XX_CH3_PRBS_ERR_CNT_LBN 24
++  #define XX_CH3_PRBS_ERR_CNT_WIDTH 8
++  #define XX_CH2_PRBS_ERR_CNT_LBN 16
++  #define XX_CH2_PRBS_ERR_CNT_WIDTH 8
++  #define XX_CH1_PRBS_ERR_CNT_LBN 8
++  #define XX_CH1_PRBS_ERR_CNT_WIDTH 8
++  #define XX_CH0_PRBS_ERR_CNT_LBN 0
++  #define XX_CH0_PRBS_ERR_CNT_WIDTH 8
++#define XX_CORE_STAT_REG_KER_P0_OFST 0x1360 /* XAUI XGXS core status
++                                             register */
++#define XX_CORE_STAT_REG_P0_OFST 0x1360 /* XAUI XGXS core status register */
++  #define XX_FORCE_SIG3_LBN 31
++  #define XX_FORCE_SIG3_WIDTH 1
++  #define XX_FORCE_SIG3_VAL_LBN 30
++  #define XX_FORCE_SIG3_VAL_WIDTH 1
++  #define XX_FORCE_SIG2_LBN 29
++  #define XX_FORCE_SIG2_WIDTH 1
++  #define XX_FORCE_SIG2_VAL_LBN 28
++  #define XX_FORCE_SIG2_VAL_WIDTH 1
++  #define XX_FORCE_SIG1_LBN 27
++  #define XX_FORCE_SIG1_WIDTH 1
++  #define XX_FORCE_SIG1_VAL_LBN 26
++  #define XX_FORCE_SIG1_VAL_WIDTH 1
++  #define XX_FORCE_SIG0_LBN 25
++  #define XX_FORCE_SIG0_WIDTH 1
++  #define XX_FORCE_SIG0_VAL_LBN 24
++  #define XX_FORCE_SIG0_VAL_WIDTH 1
++  #define XX_XGXS_LB_EN_LBN 23
++  #define XX_XGXS_LB_EN_WIDTH 1
++  #define XX_XGMII_LB_EN_LBN 22
++  #define XX_XGMII_LB_EN_WIDTH 1
++  #define XX_MATCH_FAULT_LBN 21
++  #define XX_MATCH_FAULT_WIDTH 1
++  #define XX_ALIGN_DONE_LBN 20
++  #define XX_ALIGN_DONE_WIDTH 1
++  #define XX_SYNC_STAT3_LBN 19
++  #define XX_SYNC_STAT3_WIDTH 1
++  #define XX_SYNC_STAT2_LBN 18
++  #define XX_SYNC_STAT2_WIDTH 1
++  #define XX_SYNC_STAT1_LBN 17
++  #define XX_SYNC_STAT1_WIDTH 1
++  #define XX_SYNC_STAT0_LBN 16
++  #define XX_SYNC_STAT0_WIDTH 1
++  #define XX_COMMA_DET_CH3_LBN 15
++  #define XX_COMMA_DET_CH3_WIDTH 1
++  #define XX_COMMA_DET_CH2_LBN 14
++  #define XX_COMMA_DET_CH2_WIDTH 1
++  #define XX_COMMA_DET_CH1_LBN 13
++  #define XX_COMMA_DET_CH1_WIDTH 1
++  #define XX_COMMA_DET_CH0_LBN 12
++  #define XX_COMMA_DET_CH0_WIDTH 1
++  #define XX_CGRP_ALIGN_CH3_LBN 11
++  #define XX_CGRP_ALIGN_CH3_WIDTH 1
++  #define XX_CGRP_ALIGN_CH2_LBN 10
++  #define XX_CGRP_ALIGN_CH2_WIDTH 1
++  #define XX_CGRP_ALIGN_CH1_LBN 9
++  #define XX_CGRP_ALIGN_CH1_WIDTH 1
++  #define XX_CGRP_ALIGN_CH0_LBN 8
++  #define XX_CGRP_ALIGN_CH0_WIDTH 1
++  #define XX_CHAR_ERR_CH3_LBN 7
++  #define XX_CHAR_ERR_CH3_WIDTH 1
++  #define XX_CHAR_ERR_CH2_LBN 6
++  #define XX_CHAR_ERR_CH2_WIDTH 1
++  #define XX_CHAR_ERR_CH1_LBN 5
++  #define XX_CHAR_ERR_CH1_WIDTH 1
++  #define XX_CHAR_ERR_CH0_LBN 4
++  #define XX_CHAR_ERR_CH0_WIDTH 1
++  #define XX_DISPERR_CH3_LBN 3
++  #define XX_DISPERR_CH3_WIDTH 1
++  #define XX_DISPERR_CH2_LBN 2
++  #define XX_DISPERR_CH2_WIDTH 1
++  #define XX_DISPERR_CH1_LBN 1
++  #define XX_DISPERR_CH1_WIDTH 1
++  #define XX_DISPERR_CH0_LBN 0
++  #define XX_DISPERR_CH0_WIDTH 1
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_xgrmon.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon/falcon_xgrmon.h    2008-05-19 00:33:29.341837424 +0300
+@@ -0,0 +1,125 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) 10G MAC
++ * statistics register definitions.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++/*************---- 10G MAC Statistical Counters C Header ----*************/
++#define XgRxOctets_offset 0x0
++    #define XgRxOctets_WIDTH 48
++#define XgRxOctetsOK_offset 0x8
++    #define XgRxOctetsOK_WIDTH 48
++#define XgRxPkts_offset 0x10
++    #define XgRxPkts_WIDTH 32
++#define XgRxPktsOK_offset 0x14
++    #define XgRxPktsOK_WIDTH 32
++#define XgRxBroadcastPkts_offset 0x18
++    #define XgRxBroadcastPkts_WIDTH 32
++#define XgRxMulticastPkts_offset 0x1C
++    #define XgRxMulticastPkts_WIDTH 32
++#define XgRxUnicastPkts_offset 0x20
++    #define XgRxUnicastPkts_WIDTH 32
++#define XgRxUndersizePkts_offset 0x24
++    #define XgRxUndersizePkts_WIDTH 32
++#define XgRxOversizePkts_offset 0x28
++    #define XgRxOversizePkts_WIDTH 32
++#define XgRxJabberPkts_offset 0x2C
++    #define XgRxJabberPkts_WIDTH 32
++#define XgRxUndersizeFCSerrorPkts_offset 0x30
++    #define XgRxUndersizeFCSerrorPkts_WIDTH 32
++#define XgRxDropEvents_offset 0x34
++    #define XgRxDropEvents_WIDTH 32
++#define XgRxFCSerrorPkts_offset 0x38
++    #define XgRxFCSerrorPkts_WIDTH 32
++#define XgRxAlignError_offset 0x3C
++    #define XgRxAlignError_WIDTH 32
++#define XgRxSymbolError_offset 0x40
++    #define XgRxSymbolError_WIDTH 32
++#define XgRxInternalMACError_offset 0x44
++    #define XgRxInternalMACError_WIDTH 32
++#define XgRxControlPkts_offset 0x48
++    #define XgRxControlPkts_WIDTH 32
++#define XgRxPausePkts_offset 0x4C
++    #define XgRxPausePkts_WIDTH 32
++#define XgRxPkts64Octets_offset 0x50
++    #define XgRxPkts64Octets_WIDTH 32
++#define XgRxPkts65to127Octets_offset 0x54
++    #define XgRxPkts65to127Octets_WIDTH 32
++#define XgRxPkts128to255Octets_offset 0x58
++    #define XgRxPkts128to255Octets_WIDTH 32
++#define XgRxPkts256to511Octets_offset 0x5C
++    #define XgRxPkts256to511Octets_WIDTH 32
++#define XgRxPkts512to1023Octets_offset 0x60
++    #define XgRxPkts512to1023Octets_WIDTH 32
++#define XgRxPkts1024to15xxOctets_offset 0x64
++    #define XgRxPkts1024to15xxOctets_WIDTH 32
++#define XgRxPkts15xxtoMaxOctets_offset 0x68
++    #define XgRxPkts15xxtoMaxOctets_WIDTH 32
++#define XgRxLengthError_offset 0x6C
++    #define XgRxLengthError_WIDTH 32
++#define XgTxPkts_offset 0x80
++    #define XgTxPkts_WIDTH 32
++#define XgTxOctets_offset 0x88
++    #define XgTxOctets_WIDTH 48
++#define XgTxMulticastPkts_offset 0x90
++    #define XgTxMulticastPkts_WIDTH 32
++#define XgTxBroadcastPkts_offset 0x94
++    #define XgTxBroadcastPkts_WIDTH 32
++#define XgTxUnicastPkts_offset 0x98
++    #define XgTxUnicastPkts_WIDTH 32
++#define XgTxControlPkts_offset 0x9C
++    #define XgTxControlPkts_WIDTH 32
++#define XgTxPausePkts_offset 0xA0
++    #define XgTxPausePkts_WIDTH 32
++#define XgTxPkts64Octets_offset 0xA4
++    #define XgTxPkts64Octets_WIDTH 32
++#define XgTxPkts65to127Octets_offset 0xA8
++    #define XgTxPkts65to127Octets_WIDTH 32
++#define XgTxPkts128to255Octets_offset 0xAC
++    #define XgTxPkts128to255Octets_WIDTH 32
++#define XgTxPkts256to511Octets_offset 0xB0
++    #define XgTxPkts256to511Octets_WIDTH 32
++#define XgTxPkts512to1023Octets_offset 0xB4
++    #define XgTxPkts512to1023Octets_WIDTH 32
++#define XgTxPkts1024to15xxOctets_offset 0xB8
++    #define XgTxPkts1024to15xxOctets_WIDTH 32
++#define XgTxPkts1519toMaxOctets_offset 0xBC
++    #define XgTxPkts1519toMaxOctets_WIDTH 32
++#define XgTxUndersizePkts_offset 0xC0
++    #define XgTxUndersizePkts_WIDTH 32
++#define XgTxOversizePkts_offset 0xC4
++    #define XgTxOversizePkts_WIDTH 32
++#define xGTxNonTcpUdpPkt_offset 0xC8
++    #define xGTxNonTcpUdpPkt_WIDTH 16
++#define xGTxMacSrcErrPkt_offset 0xCC
++    #define xGTxMacSrcErrPkt_WIDTH 16
++#define xGTxIpSrcErrPkt_offset 0xD0
++    #define xGTxIpSrcErrPkt_WIDTH 16
++#define XgDmaDone_offset 0xD4
++    #define XgDmaDone_WIDTH 32
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/falcon.h  2008-05-19 00:33:29.329836732 +0300
+@@ -0,0 +1,420 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides EtherFabric NIC - EFXXXX (aka Falcon) specific
++ * definitions.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_DRIVER_EFAB_HARDWARE_FALCON_H__
++#define __CI_DRIVER_EFAB_HARDWARE_FALCON_H__
++
++/*----------------------------------------------------------------------------
++ * Compile options
++ *---------------------------------------------------------------------------*/
++
++/* Falcon has an 8K maximum page size. */
++#define FALCON_MAX_PAGE_SIZE EFHW_8K
++
++/* include the register definitions */
++#include <ci/driver/efab/hardware/falcon/falcon_core.h>
++#include <ci/driver/efab/hardware/falcon/falcon_desc.h>
++#include <ci/driver/efab/hardware/falcon/falcon_event.h>
++#include <ci/driver/efab/hardware/falcon/falcon_mac.h>
++#include <ci/driver/efab/hardware/falcon/falcon_grmon.h>
++#include <ci/driver/efab/hardware/falcon/falcon_xgrmon.h>
++#include <ci/driver/efab/hardware/falcon/falcon_intr_vec.h>
++
++#define FALCON_DMA_TX_DESC_BYTES      8
++#define FALCON_DMA_RX_PHYS_DESC_BYTES 8
++#define FALCON_DMA_RX_BUF_DESC_BYTES  4
++
++
++/* ---- efhw_event_t helpers --- */
++
++#ifndef EFHW_IS_LITTLE_ENDIAN
++#error This needs lots of cpu_to_le64s() in
++#endif
++
++/*!\ TODO look at whether there is an efficiency gain to be had by
++  treating the event codes to 32bit masks as is done for EF1
++
++  These masks apply to the full 64 bits of the event to extract the
++  event code - followed by the common event codes to expect
++ */
++#define __FALCON_OPEN_MASK(WIDTH)  ((((uint64_t)1) << (WIDTH)) - 1)
++#define FALCON_EVENT_CODE_MASK \
++      (__FALCON_OPEN_MASK(EV_CODE_WIDTH) << EV_CODE_LBN)
++#define FALCON_EVENT_EV_Q_ID_MASK \
++      (__FALCON_OPEN_MASK(DRIVER_EV_EVQ_ID_WIDTH) << DRIVER_EV_EVQ_ID_LBN)
++#define FALCON_EVENT_TX_FLUSH_Q_ID_MASK \
++      (__FALCON_OPEN_MASK(DRIVER_EV_TX_DESCQ_ID_WIDTH) << \
++       DRIVER_EV_TX_DESCQ_ID_LBN)
++#define FALCON_EVENT_RX_FLUSH_Q_ID_MASK \
++      (__FALCON_OPEN_MASK(DRIVER_EV_RX_DESCQ_ID_WIDTH) << \
++       DRIVER_EV_RX_DESCQ_ID_LBN)
++#define FALCON_EVENT_DRV_SUBCODE_MASK \
++      (__FALCON_OPEN_MASK(DRIVER_EV_SUB_CODE_WIDTH) << \
++       DRIVER_EV_SUB_CODE_LBN)
++
++#define FALCON_EVENT_FMT         "[ev:%x:%08x:%08x]"
++#define FALCON_EVENT_PRI_ARG(e) \
++      ((unsigned)(((e).u64 & FALCON_EVENT_CODE_MASK) >> EV_CODE_LBN)), \
++      ((unsigned)((e).u64 >> 32)), ((unsigned)((e).u64 & 0xFFFFFFFF))
++
++#define FALCON_EVENT_CODE(evp)                ((evp)->u64 & FALCON_EVENT_CODE_MASK)
++#define FALCON_EVENT_WAKE_EVQ_ID(evp) \
++      (((evp)->u64 & FALCON_EVENT_EV_Q_ID_MASK) >> DRIVER_EV_EVQ_ID_LBN)
++#define FALCON_EVENT_TX_FLUSH_Q_ID(evp) \
++      (((evp)->u64 & FALCON_EVENT_TX_FLUSH_Q_ID_MASK) >> \
++       DRIVER_EV_TX_DESCQ_ID_LBN)
++#define FALCON_EVENT_RX_FLUSH_Q_ID(evp) \
++      (((evp)->u64 & FALCON_EVENT_RX_FLUSH_Q_ID_MASK) >> \
++       DRIVER_EV_RX_DESCQ_ID_LBN)
++#define FALCON_EVENT_DRIVER_SUBCODE(evp) \
++      (((evp)->u64 & FALCON_EVENT_DRV_SUBCODE_MASK) >> \
++       DRIVER_EV_SUB_CODE_LBN)
++
++#define FALCON_EVENT_CODE_CHAR        ((uint64_t)DRIVER_EV_DECODE << EV_CODE_LBN)
++#define FALCON_EVENT_CODE_SW  ((uint64_t)DRV_GEN_EV_DECODE << EV_CODE_LBN)
++
++
++/* so this is the size in bytes of an awful lot of things */
++#define FALCON_REGISTER128          (16)
++
++/* we define some unique dummy values as a debug aid */
++#ifdef _WIN32
++#define FALCON_ATOMIC_BASE            0xdeadbeef00000000ui64
++#else
++#define FALCON_ATOMIC_BASE            0xdeadbeef00000000ULL
++#endif
++#define FALCON_ATOMIC_UPD_REG         (FALCON_ATOMIC_BASE | 0x1)
++#define FALCON_ATOMIC_PTR_TBL_REG     (FALCON_ATOMIC_BASE | 0x2)
++#define FALCON_ATOMIC_SRPM_UDP_EVQ_REG        (FALCON_ATOMIC_BASE | 0x3)
++#define FALCON_ATOMIC_RX_FLUSH_DESCQ  (FALCON_ATOMIC_BASE | 0x4)
++#define FALCON_ATOMIC_TX_FLUSH_DESCQ  (FALCON_ATOMIC_BASE | 0x5)
++#define FALCON_ATOMIC_INT_EN_REG      (FALCON_ATOMIC_BASE | 0x6)
++#define FALCON_ATOMIC_TIMER_CMD_REG   (FALCON_ATOMIC_BASE | 0x7)
++#define FALCON_ATOMIC_PACE_REG                (FALCON_ATOMIC_BASE | 0x8)
++#define FALCON_ATOMIC_INT_ACK_REG     (FALCON_ATOMIC_BASE | 0x9)
++/* XXX It crashed with odd value in FALCON_ATOMIC_INT_ADR_REG */
++#define FALCON_ATOMIC_INT_ADR_REG     (FALCON_ATOMIC_BASE | 0xa)
 +
-+      return ret;
-+}
++/*----------------------------------------------------------------------------
++ *
++ * PCI control blocks for Falcon -
++ *          (P) primary is for NET
++ *          (S) secondary is for CHAR
++ *
++ *---------------------------------------------------------------------------*/
 +
-+HYPERVISOR_ATTR_RO(compiler);
++#define FALCON_P_CTR_AP_BAR   2
++#define FALCON_S_CTR_AP_BAR   0
++#define FALCON_S_DEVID                0x6703
 +
-+static ssize_t compiled_by_show(struct hyp_sysfs_attr *attr, char *buffer)
-+{
-+      int ret = -ENOMEM;
-+      struct xen_compile_info *info;
 +
-+      info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
-+      if (info) {
-+              ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
-+              if (!ret)
-+                      ret = sprintf(buffer, "%s\n", info->compile_by);
-+              kfree(info);
-+      }
++/*----------------------------------------------------------------------------
++ *
++ * Falcon constants
++ *
++ *---------------------------------------------------------------------------*/
 +
-+      return ret;
-+}
++#define FALCON_DMAQ_NUM               (EFHW_4K)
++#define FALCON_EVQ_TBL_NUM    (EFHW_4K)
++#define FALCON_TIMERS_NUM     (EFHW_4K)
 +
-+HYPERVISOR_ATTR_RO(compiled_by);
++/* This value is an upper limit on the total number of filter table
++ * entries, including odd and even banks.  The actual size of filter table
++ * is determined at runtime, as it can vary.
++ */
++#define FALCON_FILTER_TBL_NUM         (EFHW_16K)
 +
-+static ssize_t compile_date_show(struct hyp_sysfs_attr *attr, char *buffer)
-+{
-+      int ret = -ENOMEM;
-+      struct xen_compile_info *info;
++/* max number of buffers which can be pushed before commiting */
++#define FALCON_BUFFER_UPD_MAX         (128)
 +
-+      info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
-+      if (info) {
-+              ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
-+              if (!ret)
-+                      ret = sprintf(buffer, "%s\n", info->compile_date);
-+              kfree(info);
-+      }
++/* We can tell falcon to write its RX buffers in 32 byte quantums,
++   and since we pad packets 2 bytes to the right we can't use
++   a full page (not unless we use jumbo mode for all queues)
 +
-+      return ret;
-+}
++   NOTE: tests/nic/dma.c assumes that the value here is the real NIC
++   value, so we explicitly round it down to the nearest 32 bytes */
 +
-+HYPERVISOR_ATTR_RO(compile_date);
++/* #define FALCON_RX_USR_BUF_SIZE    round_down(4096-2,32) */
++#define FALCON_RX_USR_BUF_SIZE                4064
 +
-+static struct attribute *xen_compile_attrs[] = {
-+      &compiler_attr.attr,
-+      &compiled_by_attr.attr,
-+      &compile_date_attr.attr,
-+      NULL
-+};
++#define FALCON_EVQ_RPTR_REG_P0                0x400
 +
-+static struct attribute_group xen_compilation_group = {
-+      .name = "compilation",
-+      .attrs = xen_compile_attrs,
++/*----------------------------------------------------------------------------
++ *
++ * Falcon requires user-space descriptor pushes to be:
++ *    dword[0-2]; wiob(); dword[3]
++ *
++ * Driver register access must be locked against other threads from
++ * the same driver but can be in any order: i.e dword[0-3]; wiob()
++ *
++ * The following helpers ensure that valid dword orderings are exercised
++ *
++ *---------------------------------------------------------------------------*/
++
++/* A union to allow writting 64bit values as 32bit values, without
++ * hitting the compilers aliasing rules. We hope the compiler optimises
++ * away the copy's anyway */
++union __u64to32 {
++      uint64_t u64;
++      struct {
++#ifdef EFHW_IS_LITTLE_ENDIAN
++              uint32_t a;
++              uint32_t b;
++#else
++              uint32_t b;
++              uint32_t a;
++#endif
++      } s;
 +};
 +
-+int __init static xen_compilation_init(void)
++static inline void
++falcon_write_ddd_d(efhw_ioaddr_t kva,
++                 uint32_t d0, uint32_t d1, uint32_t d2, uint32_t d3)
 +{
-+      return sysfs_create_group(&hypervisor_subsys.kset.kobj,
-+                                &xen_compilation_group);
++      writel(d0, kva + 0);
++      writel(d1, kva + 4);
++      writel(d2, kva + 8);
++      mmiowb();
++      writel(d3, kva + 12);
 +}
 +
-+static void xen_compilation_destroy(void)
++static inline void falcon_write_q(efhw_ioaddr_t kva, uint64_t q)
 +{
-+      sysfs_remove_group(&hypervisor_subsys.kset.kobj,
-+                         &xen_compilation_group);
-+}
++      union __u64to32 u;
++      u.u64 = q;
 +
-+/* xen properties info */
++      writel(u.s.a, kva);
++      mmiowb();
++      writel(u.s.b, kva + 4);
++}
 +
-+static ssize_t capabilities_show(struct hyp_sysfs_attr *attr, char *buffer)
++static inline void falcon_read_q(efhw_ioaddr_t addr, uint64_t *q0)
 +{
-+      int ret = -ENOMEM;
-+      char *caps;
-+
-+      caps = kmalloc(XEN_CAPABILITIES_INFO_LEN, GFP_KERNEL);
-+      if (caps) {
-+              ret = HYPERVISOR_xen_version(XENVER_capabilities, caps);
-+              if (!ret)
-+                      ret = sprintf(buffer, "%s\n", caps);
-+              kfree(caps);
-+      }
++      /* It is essential that we read dword0 first, so that
++       * the shadow register is updated with the latest value
++       * and we get a self consistent value.
++       */
++      union __u64to32 u;
++      u.s.a = readl(addr);
++      rmb();
++      u.s.b = readl(addr + 4);
 +
-+      return ret;
++      *q0 = u.u64;
 +}
 +
-+HYPERVISOR_ATTR_RO(capabilities);
++static inline void
++falcon_write_qq(efhw_ioaddr_t kva, uint64_t q0, uint64_t q1)
++{
++      writeq(q0, kva + 0);
++      falcon_write_q(kva + 8, q1);
++}
 +
-+static ssize_t changeset_show(struct hyp_sysfs_attr *attr, char *buffer)
++static inline void
++falcon_read_qq(efhw_ioaddr_t addr, uint64_t *q0, uint64_t *q1)
 +{
-+      int ret = -ENOMEM;
-+      char *cset;
++      falcon_read_q(addr, q0);
++      *q1 = readq(addr + 8);
++}
 +
-+      cset = kmalloc(XEN_CHANGESET_INFO_LEN, GFP_KERNEL);
-+      if (cset) {
-+              ret = HYPERVISOR_xen_version(XENVER_changeset, cset);
-+              if (!ret)
-+                      ret = sprintf(buffer, "%s\n", cset);
-+              kfree(cset);
-+      }
 +
-+      return ret;
-+}
 +
-+HYPERVISOR_ATTR_RO(changeset);
++/*----------------------------------------------------------------------------
++ *
++ * Buffer virtual addresses (4K buffers)
++ *
++ *---------------------------------------------------------------------------*/
 +
-+static ssize_t virtual_start_show(struct hyp_sysfs_attr *attr, char *buffer)
-+{
-+      int ret = -ENOMEM;
-+      struct xen_platform_parameters *parms;
++/* Form a buffer virtual address from buffer ID and offset.  If the offset
++** is larger than the buffer size, then the buffer indexed will be
++** calculated appropriately.  It is the responsibility of the caller to
++** ensure that they have valid buffers programmed at that address.
++*/
++#define FALCON_VADDR_8K_S     (13)
++#define FALCON_VADDR_4K_S     (12)
++#define FALCON_VADDR_M                0xfffff /* post shift mask  */
 +
-+      parms = kmalloc(sizeof(struct xen_platform_parameters), GFP_KERNEL);
-+      if (parms) {
-+              ret = HYPERVISOR_xen_version(XENVER_platform_parameters,
-+                                           parms);
-+              if (!ret)
-+                      ret = sprintf(buffer, "%lx\n", parms->virt_start);
-+              kfree(parms);
-+      }
++#define FALCON_BUFFER_8K_ADDR(id, off)        (((id) << FALCON_VADDR_8K_S) + (off))
++#define FALCON_BUFFER_8K_PAGE(vaddr) \
++      (((vaddr) >> FALCON_VADDR_8K_S) & FALCON_VADDR_M)
++#define FALCON_BUFFER_8K_OFF(vaddr) \
++      ((vaddr) & __FALCON_MASK32(FALCON_VADDR_8K_S))
 +
-+      return ret;
-+}
++#define FALCON_BUFFER_4K_ADDR(id, off)        (((id) << FALCON_VADDR_4K_S) + (off))
++#define FALCON_BUFFER_4K_PAGE(vaddr) \
++      (((vaddr) >> FALCON_VADDR_4K_S) & FALCON_VADDR_M)
++#define FALCON_BUFFER_4K_OFF(vaddr) \
++      ((vaddr) & __FALCON_MASK32(FALCON_VADDR_4K_S))
 +
-+HYPERVISOR_ATTR_RO(virtual_start);
++/*----------------------------------------------------------------------------
++ *
++ * Timer helpers
++ *
++ *---------------------------------------------------------------------------*/
 +
-+static ssize_t pagesize_show(struct hyp_sysfs_attr *attr, char *buffer)
++static inline int falcon_timer_page_addr(uint idx)
 +{
-+      int ret;
 +
-+      ret = HYPERVISOR_xen_version(XENVER_pagesize, NULL);
-+      if (ret > 0)
-+              ret = sprintf(buffer, "%x\n", ret);
++      EFHW_ASSERT(TIMER_CMD_REG_KER_OFST ==
++                  (TIMER_CMD_REG_PAGE4_OFST - 4 * EFHW_8K));
 +
-+      return ret;
++      EFHW_ASSERT(idx < FALCON_TIMERS_NUM);
++
++      if (idx < 4)
++              return TIMER_CMD_REG_KER_OFST + (idx * EFHW_8K);
++      else if (idx < 1024)
++              return TIMER_CMD_REG_PAGE4_OFST + ((idx - 4) * EFHW_8K);
++      else
++              return TIMER_CMD_REG_PAGE123K_OFST + ((idx - 1024) * EFHW_8K);
 +}
 +
-+HYPERVISOR_ATTR_RO(pagesize);
++#define FALCON_TIMER_PAGE_MASK                (EFHW_8K-1)
 +
-+/* eventually there will be several more features to export */
-+static ssize_t xen_feature_show(int index, char *buffer)
++static inline int falcon_timer_page_offset(uint idx)
 +{
-+      int ret = -ENOMEM;
-+      struct xen_feature_info *info;
++      return falcon_timer_page_addr(idx) & FALCON_TIMER_PAGE_MASK;
++}
 +
-+      info = kmalloc(sizeof(struct xen_feature_info), GFP_KERNEL);
-+      if (info) {
-+              info->submap_idx = index;
-+              ret = HYPERVISOR_xen_version(XENVER_get_features, info);
-+              if (!ret)
-+                      ret = sprintf(buffer, "%d\n", info->submap);
-+              kfree(info);
-+      }
++/*----------------------------------------------------------------------------
++ *
++ * DMA Queue helpers
++ *
++ *---------------------------------------------------------------------------*/
 +
-+      return ret;
-+}
++/* iSCSI queue for A1; see bug 5427 for more details. */
++#define FALCON_A1_ISCSI_DMAQ 4
 +
-+static ssize_t writable_pt_show(struct hyp_sysfs_attr *attr, char *buffer)
++/*! returns an address within a bar of the TX DMA doorbell */
++static inline uint falcon_tx_dma_page_addr(uint dmaq_idx)
 +{
-+      return xen_feature_show(XENFEAT_writable_page_tables, buffer);
-+}
++      uint page;
 +
-+HYPERVISOR_ATTR_RO(writable_pt);
++      EFHW_ASSERT((((TX_DESC_UPD_REG_PAGE123K_OFST) & (EFHW_8K - 1)) ==
++                   (((TX_DESC_UPD_REG_PAGE4_OFST) & (EFHW_8K - 1)))));
 +
-+static struct attribute *xen_properties_attrs[] = {
-+      &capabilities_attr.attr,
-+      &changeset_attr.attr,
-+      &virtual_start_attr.attr,
-+      &pagesize_attr.attr,
-+      &writable_pt_attr.attr,
-+      NULL
-+};
++      EFHW_ASSERT(dmaq_idx < FALCON_DMAQ_NUM);
 +
-+static struct attribute_group xen_properties_group = {
-+      .name = "properties",
-+      .attrs = xen_properties_attrs,
-+};
++      if (dmaq_idx < 1024)
++              page = TX_DESC_UPD_REG_PAGE4_OFST + ((dmaq_idx - 4) * EFHW_8K);
++      else
++              page =
++                  TX_DESC_UPD_REG_PAGE123K_OFST +
++                  ((dmaq_idx - 1024) * EFHW_8K);
 +
-+static int __init xen_properties_init(void)
-+{
-+      return sysfs_create_group(&hypervisor_subsys.kset.kobj,
-+                                &xen_properties_group);
++      return page;
 +}
 +
-+static void xen_properties_destroy(void)
++/*! returns an address within a bar of the RX DMA doorbell */
++static inline uint falcon_rx_dma_page_addr(uint dmaq_idx)
 +{
-+      sysfs_remove_group(&hypervisor_subsys.kset.kobj,
-+                         &xen_properties_group);
-+}
++      uint page;
 +
-+static int __init hyper_sysfs_init(void)
-+{
-+      int ret;
++      EFHW_ASSERT((((RX_DESC_UPD_REG_PAGE123K_OFST) & (EFHW_8K - 1)) ==
++                   ((RX_DESC_UPD_REG_PAGE4_OFST) & (EFHW_8K - 1))));
 +
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++      EFHW_ASSERT(dmaq_idx < FALCON_DMAQ_NUM);
 +
-+      ret = xen_sysfs_type_init();
-+      if (ret)
-+              goto out;
-+      ret = xen_sysfs_version_init();
-+      if (ret)
-+              goto version_out;
-+      ret = xen_compilation_init();
-+      if (ret)
-+              goto comp_out;
-+      ret = xen_sysfs_uuid_init();
-+      if (ret)
-+              goto uuid_out;
-+      ret = xen_properties_init();
-+      if (!ret)
-+              goto out;
++      if (dmaq_idx < 1024)
++              page = RX_DESC_UPD_REG_PAGE4_OFST + ((dmaq_idx - 4) * EFHW_8K);
++      else
++              page =
++                  RX_DESC_UPD_REG_PAGE123K_OFST +
++                  ((dmaq_idx - 1024) * EFHW_8K);
 +
-+      xen_sysfs_uuid_destroy();
-+uuid_out:
-+      xen_compilation_destroy();
-+comp_out:
-+      xen_sysfs_version_destroy();
-+version_out:
-+      xen_sysfs_type_destroy();
-+out:
-+      return ret;
++      return page;
 +}
 +
-+static void __exit hyper_sysfs_exit(void)
-+{
-+      xen_properties_destroy();
-+      xen_compilation_destroy();
-+      xen_sysfs_uuid_destroy();
-+      xen_sysfs_version_destroy();
-+      xen_sysfs_type_destroy();
++/*! "page"=NIC-dependent register set size */
++#define FALCON_DMA_PAGE_MASK  (EFHW_8K-1)
 +
++/*! returns an address within a bar of the start of the "page"
++    containing the TX DMA doorbell */
++static inline int falcon_tx_dma_page_base(uint dma_idx)
++{
++      return falcon_tx_dma_page_addr(dma_idx) & ~FALCON_DMA_PAGE_MASK;
 +}
 +
-+module_init(hyper_sysfs_init);
-+module_exit(hyper_sysfs_exit);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/evtchn/evtchn.c linux-2.6.18-xen.hg/drivers/xen/evtchn/evtchn.c
---- linux-2.6.18/drivers/xen/evtchn/evtchn.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/evtchn/evtchn.c    2007-12-23 11:15:33.867925803 +0100
-@@ -0,0 +1,556 @@
-+/******************************************************************************
-+ * evtchn.c
-+ * 
-+ * Driver for receiving and demuxing event-channel signals.
-+ * 
-+ * Copyright (c) 2004-2005, K A Fraser
-+ * Multi-process extensions Copyright (c) 2004, Steven Smith
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
++/*! returns an address within a bar of the start of the "page"
++    containing the RX DMA doorbell */
++static inline int falcon_rx_dma_page_base(uint dma_idx)
++{
++      return falcon_rx_dma_page_addr(dma_idx) & ~FALCON_DMA_PAGE_MASK;
++}
 +
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+#include <linux/errno.h>
-+#include <linux/fs.h>
-+#include <linux/errno.h>
-+#include <linux/miscdevice.h>
-+#include <linux/major.h>
-+#include <linux/proc_fs.h>
-+#include <linux/stat.h>
-+#include <linux/poll.h>
-+#include <linux/irq.h>
-+#include <linux/init.h>
-+#include <linux/gfp.h>
-+#include <linux/mutex.h>
-+#include <linux/cpu.h>
-+#include <xen/evtchn.h>
-+#include <xen/public/evtchn.h>
++/*! returns an offset within a "page" of the TX DMA doorbell */
++static inline int falcon_tx_dma_page_offset(uint dma_idx)
++{
++      return falcon_tx_dma_page_addr(dma_idx) & FALCON_DMA_PAGE_MASK;
++}
 +
-+struct per_user_data {
-+      /* Notification ring, accessed via /dev/xen/evtchn. */
-+#define EVTCHN_RING_SIZE     (PAGE_SIZE / sizeof(evtchn_port_t))
-+#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
-+      evtchn_port_t *ring;
-+      unsigned int ring_cons, ring_prod, ring_overflow;
-+      struct mutex ring_cons_mutex; /* protect against concurrent readers */
++/*! returns an offset within a "page" of the RX DMA doorbell */
++static inline int falcon_rx_dma_page_offset(uint dma_idx)
++{
++      return falcon_rx_dma_page_addr(dma_idx) & FALCON_DMA_PAGE_MASK;
++}
 +
-+      /* Processes wait on this queue when ring is empty. */
-+      wait_queue_head_t evtchn_wait;
-+      struct fasync_struct *evtchn_async_queue;
++/*----------------------------------------------------------------------------
++ *
++ * Events
++ *
++ *---------------------------------------------------------------------------*/
 +
-+      int bind_cpu;
-+      int nr_event_wrong_delivery;
-+};
++/* Falcon nails down the event queue mappings */
++#define FALCON_EVQ_KERNEL0   (0)      /* hardwired for net driver */
++#define FALCON_EVQ_CHAR      (4)      /* char driver's event queue      */
++#define FALCON_EVQ_NONIRQ    (5)      /* char driver's non interrupting
++                                         queue. Subsequent queues are
++                                         available for user apps */
 +
-+/* Who's bound to each port? */
-+static struct per_user_data *port_user[NR_EVENT_CHANNELS];
-+static spinlock_t port_user_lock;
++/* reserved by the drivers */
++#define FALCON_EVQ_TBL_RESERVED          (8)
 +
-+void evtchn_device_upcall(int port)
-+{
-+      struct per_user_data *u;
++/* default DMA-Q sizes */
++#define FALCON_DMA_Q_DEFAULT_TX_SIZE  512
 +
-+      spin_lock(&port_user_lock);
++#define FALCON_DMA_Q_DEFAULT_RX_SIZE  512
 +
-+      mask_evtchn(port);
-+      clear_evtchn(port);
++#define FALCON_DMA_Q_DEFAULT_MMAP \
++      (FALCON_DMA_Q_DEFAULT_TX_SIZE * (FALCON_DMA_TX_DESC_BYTES * 2))
 +
-+      if ((u = port_user[port]) != NULL) {
-+              if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
-+                      u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port;
-+                      if (u->ring_cons == u->ring_prod++) {
-+                              wake_up_interruptible(&u->evtchn_wait);
-+                              kill_fasync(&u->evtchn_async_queue,
-+                                          SIGIO, POLL_IN);
-+                      }
-+              } else {
-+                      u->ring_overflow = 1;
-+              }
-+      }
++/*----------------------------------------------------------------------------
++ *
++ * DEBUG - Analyser trigger
++ *
++ *---------------------------------------------------------------------------*/
 +
-+      spin_unlock(&port_user_lock);
++static inline void falcon_deadbeef(efhw_ioaddr_t efhw_kva, unsigned what)
++{
++      writel(what, efhw_kva + 0x300);
++      mmiowb();
 +}
++#endif /* __CI_DRIVER_EFAB_HARDWARE_FALCON_H__ */
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/workarounds.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware/workarounds.h     2008-05-19 00:33:29.341837424 +0300
+@@ -0,0 +1,75 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides workaround settings for EtherFabric NICs.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static void evtchn_check_wrong_delivery(struct per_user_data *u)
-+{
-+      evtchn_port_t port;
-+      unsigned int current_cpu = smp_processor_id();
++#ifndef __CI_DRIVER_EFAB_WORKAROUNDS_H__
++#define __CI_DRIVER_EFAB_WORKAROUNDS_H__
 +
-+      /* Delivered to correct CPU? All is good. */
-+      if (u->bind_cpu == current_cpu) {
-+              u->nr_event_wrong_delivery = 0;
-+              return;
-+      }
++/*----------------------------------------------------------------------------
++ *
++ * Hardware workarounds which have global scope
++ *
++ *---------------------------------------------------------------------------*/
 +
-+      /* Tolerate up to 100 consecutive misdeliveries. */
-+      if (++u->nr_event_wrong_delivery < 100)
-+              return;
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
 +
-+      spin_lock_irq(&port_user_lock);
++#if defined(__CI_HARDWARE_CONFIG_FALCON_B0__)
++/*------------------------------- B0 ---------------------------------------*/
 +
-+      for (port = 0; port < NR_EVENT_CHANNELS; port++)
-+              if (port_user[port] == u)
-+                      rebind_evtchn_to_cpu(port, current_cpu);
++#define BUG2175_WORKAROUND 0  /* TX event batching for dual port operation.
++                                 This removes the effect (dup TX events)
++                                 of the fix
++                                 (TX event per packet + batch events) */
++#define BUG5302_WORKAROUND 0  /* unstick TX DMAQ after out-of-range wr ptr */
++#define BUG5475_WORKAROUND 1  /* 10G SNAP encapsulation broken */
++#define BUG5762_WORKAROUND 0  /* Set all queues to jumbo mode */
++#define BUG5391_WORKAROUND 0  /* Misaligned TX can't span 512-byte boundary */
++#define BUG7916_WORKAROUND 0  /* RX flush gets lost */
 +
-+      u->bind_cpu = current_cpu;
-+      u->nr_event_wrong_delivery = 0;
++#else
++/*------------------------------- A0/A1 ------------------------------------*/
 +
-+      spin_unlock_irq(&port_user_lock);
-+}
++#define BUG2175_WORKAROUND 1  /* TX event batching for dual port operation.
++                                 This removes the effect (dup TX events)
++                                 of the fix
++                                 (TX event per packet + batch events) */
++#define BUG5302_WORKAROUND 1  /* unstick TX DMAQ after out-of-range wr ptr */
++#define BUG5475_WORKAROUND 1  /* 10G SNAP encapsulation broken */
++#define BUG5762_WORKAROUND 1  /* Set all queues to jumbo mode */
++#define BUG5391_WORKAROUND 1  /* Misaligned TX can't span 512-byte boundary */
++#define BUG7916_WORKAROUND 1  /* RX flush gets lost */
 +
-+static ssize_t evtchn_read(struct file *file, char __user *buf,
-+                         size_t count, loff_t *ppos)
-+{
-+      int rc;
-+      unsigned int c, p, bytes1 = 0, bytes2 = 0;
-+      struct per_user_data *u = file->private_data;
++#endif /* B0/A01 */
 +
-+      /* Whole number of ports. */
-+      count &= ~(sizeof(evtchn_port_t)-1);
++#else
++# error Need hw support.
++#endif
 +
-+      if (count == 0)
-+              return 0;
++#endif /* __CI_DRIVER_EFAB_WORKAROUNDS_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/efab/hardware.h 2008-05-19 00:33:29.329836732 +0300
+@@ -0,0 +1,199 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides EtherFabric NIC hardware interface.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      if (count > PAGE_SIZE)
-+              count = PAGE_SIZE;
++#ifndef __CI_DRIVER_EFAB_HARDWARE_H__
++#define __CI_DRIVER_EFAB_HARDWARE_H__
 +
-+      for (;;) {
-+              mutex_lock(&u->ring_cons_mutex);
++#include "ci/driver/efab/hardware/workarounds.h"
++#include <ci/efhw/hardware_sysdep.h>
 +
-+              rc = -EFBIG;
-+              if (u->ring_overflow)
-+                      goto unlock_out;
 +
-+              if ((c = u->ring_cons) != (p = u->ring_prod))
-+                      break;
++/*----------------------------------------------------------------------------
++ *
++ * Common EtherFabric definitions
++ *
++ *---------------------------------------------------------------------------*/
 +
-+              mutex_unlock(&u->ring_cons_mutex);
++#include <ci/efhw/debug.h>
++#include <ci/efhw/common.h>
++#include <ci/driver/efab/hardware/common.h>
 +
-+              if (file->f_flags & O_NONBLOCK)
-+                      return -EAGAIN;
++/*----------------------------------------------------------------------------
++ *
++ * EtherFabric varients
++ *
++ *---------------------------------------------------------------------------*/
 +
-+              rc = wait_event_interruptible(
-+                      u->evtchn_wait, u->ring_cons != u->ring_prod);
-+              if (rc)
-+                      return rc;
-+      }
++#include <ci/driver/efab/hardware/falcon.h>
 +
-+      /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
-+      if (((c ^ p) & EVTCHN_RING_SIZE) != 0) {
-+              bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) *
-+                      sizeof(evtchn_port_t);
-+              bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t);
-+      } else {
-+              bytes1 = (p - c) * sizeof(evtchn_port_t);
-+              bytes2 = 0;
-+      }
++/*----------------------------------------------------------------------------
++ *
++ * EtherFabric Portable Hardware Layer defines
++ *
++ *---------------------------------------------------------------------------*/
 +
-+      /* Truncate chunks according to caller's maximum byte count. */
-+      if (bytes1 > count) {
-+              bytes1 = count;
-+              bytes2 = 0;
-+      } else if ((bytes1 + bytes2) > count) {
-+              bytes2 = count - bytes1;
-+      }
++  /*-------------- Initialisation ------------ */
++#define efhw_nic_close_hardware(nic) \
++      ((nic)->efhw_func->close_hardware(nic))
 +
-+      rc = -EFAULT;
-+      if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) ||
-+          ((bytes2 != 0) &&
-+           copy_to_user(&buf[bytes1], &u->ring[0], bytes2)))
-+              goto unlock_out;
-+      
-+      evtchn_check_wrong_delivery(u);
++#define efhw_nic_init_hardware(nic, ev_handlers, mac_addr) \
++      ((nic)->efhw_func->init_hardware((nic), (ev_handlers), (mac_addr)))
 +
-+      u->ring_cons += (bytes1 + bytes2) / sizeof(evtchn_port_t);
-+      rc = bytes1 + bytes2;
++/*-------------- Interrupt support  ------------ */
++/** Handle interrupt.  Return 0 if not handled, 1 if handled. */
++#define efhw_nic_interrupt(nic) \
++      ((nic)->efhw_func->interrupt(nic))
 +
-+ unlock_out:
-+      mutex_unlock(&u->ring_cons_mutex);
-+      return rc;
-+}
++#define efhw_nic_interrupt_enable(nic, index) \
++      ((nic)->efhw_func->interrupt_enable(nic, index))
 +
-+static ssize_t evtchn_write(struct file *file, const char __user *buf,
-+                          size_t count, loff_t *ppos)
-+{
-+      int rc, i;
-+      evtchn_port_t *kbuf = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
-+      struct per_user_data *u = file->private_data;
++#define efhw_nic_interrupt_disable(nic, index) \
++      ((nic)->efhw_func->interrupt_disable(nic, index))
 +
-+      if (kbuf == NULL)
-+              return -ENOMEM;
++#define efhw_nic_set_interrupt_moderation(nic, index, val) \
++      ((nic)->efhw_func->set_interrupt_moderation(nic, index, val))
 +
-+      /* Whole number of ports. */
-+      count &= ~(sizeof(evtchn_port_t)-1);
++/*-------------- Event support  ------------ */
 +
-+      rc = 0;
-+      if (count == 0)
-+              goto out;
++#define efhw_nic_event_queue_enable(nic, evq, size, q_base, buf_base) \
++      ((nic)->efhw_func->event_queue_enable(nic, evq, size, q_base, \
++                                            buf_base))
 +
-+      if (count > PAGE_SIZE)
-+              count = PAGE_SIZE;
++#define efhw_nic_event_queue_disable(nic, evq, timer_only) \
++      ((nic)->efhw_func->event_queue_disable(nic, evq, timer_only))
 +
-+      rc = -EFAULT;
-+      if (copy_from_user(kbuf, buf, count) != 0)
-+              goto out;
++#define efhw_nic_wakeup_request(nic, q_base, index, evq) \
++      ((nic)->efhw_func->wakeup_request(nic, q_base, index, evq))
 +
-+      spin_lock_irq(&port_user_lock);
-+      for (i = 0; i < (count/sizeof(evtchn_port_t)); i++)
-+              if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u))
-+                      unmask_evtchn(kbuf[i]);
-+      spin_unlock_irq(&port_user_lock);
++#define efhw_nic_sw_event(nic, data, ev) \
++      ((nic)->efhw_func->sw_event(nic, data, ev))
 +
-+      rc = count;
++/*-------------- Filter support  ------------ */
++#define efhw_nic_ipfilter_set(nic, type, index, dmaq,         \
++                            saddr, sport, daddr, dport)       \
++      ((nic)->efhw_func->ipfilter_set(nic, type, index, dmaq, \
++                                      saddr, sport, daddr, dport))
 +
-+ out:
-+      free_page((unsigned long)kbuf);
-+      return rc;
-+}
++#define efhw_nic_ipfilter_attach(nic, index, dmaq) \
++      ((nic)->efhw_func->ipfilter_attach(nic, index, dmaq))
 +
-+static unsigned int next_bind_cpu(cpumask_t map)
-+{
-+      static unsigned int bind_cpu;
-+      bind_cpu = next_cpu(bind_cpu, map);
-+      if (bind_cpu >= NR_CPUS)
-+              bind_cpu = first_cpu(map);
-+      return bind_cpu;
-+}
++#define efhw_nic_ipfilter_detach(nic, index) \
++      ((nic)->efhw_func->ipfilter_detach(nic, index))
 +
-+static void evtchn_bind_to_user(struct per_user_data *u, int port)
-+{
-+      spin_lock_irq(&port_user_lock);
++#define efhw_nic_ipfilter_clear(nic, index) \
++      ((nic)->efhw_func->ipfilter_clear(nic, index))
 +
-+      BUG_ON(port_user[port] != NULL);
-+      port_user[port] = u;
++/*-------------- DMA support  ------------ */
++#define efhw_nic_dmaq_tx_q_init(nic, dmaq, evq, owner, tag,           \
++                              dmaq_size, index, flags)                \
++      ((nic)->efhw_func->dmaq_tx_q_init(nic, dmaq, evq, owner, tag,   \
++                                        dmaq_size, index, flags))
 +
-+      if (u->bind_cpu == -1)
-+              u->bind_cpu = next_bind_cpu(cpu_online_map);
++#define efhw_nic_dmaq_rx_q_init(nic, dmaq, evq, owner, tag,           \
++                              dmaq_size, index, flags) \
++      ((nic)->efhw_func->dmaq_rx_q_init(nic, dmaq, evq, owner, tag,   \
++                                        dmaq_size, index, flags))
 +
-+      rebind_evtchn_to_cpu(port, u->bind_cpu);
++#define efhw_nic_dmaq_tx_q_disable(nic, dmaq) \
++      ((nic)->efhw_func->dmaq_tx_q_disable(nic, dmaq))
 +
-+      unmask_evtchn(port);
++#define efhw_nic_dmaq_rx_q_disable(nic, dmaq) \
++      ((nic)->efhw_func->dmaq_rx_q_disable(nic, dmaq))
 +
-+      spin_unlock_irq(&port_user_lock);
-+}
++#define efhw_nic_flush_tx_dma_channel(nic, dmaq) \
++      ((nic)->efhw_func->flush_tx_dma_channel(nic, dmaq))
 +
-+static long evtchn_ioctl(struct file *file,
-+                       unsigned int cmd, unsigned long arg)
-+{
-+      int rc;
-+      struct per_user_data *u = file->private_data;
-+      void __user *uarg = (void __user *) arg;
++#define efhw_nic_flush_rx_dma_channel(nic, dmaq) \
++      ((nic)->efhw_func->flush_rx_dma_channel(nic, dmaq))
 +
-+      switch (cmd) {
-+      case IOCTL_EVTCHN_BIND_VIRQ: {
-+              struct ioctl_evtchn_bind_virq bind;
-+              struct evtchn_bind_virq bind_virq;
++/*-------------- MAC Low level interface ---- */
++#define efhw_gmac_get_mac_addr(nic) \
++      ((nic)->gmac->get_mac_addr((nic)->gmac))
 +
-+              rc = -EFAULT;
-+              if (copy_from_user(&bind, uarg, sizeof(bind)))
-+                      break;
++/*-------------- Buffer table -------------- */
++#define efhw_nic_buffer_table_set(nic, addr, bufsz, region,           \
++                                own_id, buf_id)                       \
++      ((nic)->efhw_func->buffer_table_set(nic, addr, bufsz, region,   \
++                                          own_id, buf_id))
 +
-+              bind_virq.virq = bind.virq;
-+              bind_virq.vcpu = 0;
-+              rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
-+                                               &bind_virq);
-+              if (rc != 0)
-+                      break;
++#define efhw_nic_buffer_table_set_n(nic, buf_id, addr, bufsz,         \
++                                  region, n_pages, own_id) \
++      ((nic)->efhw_func->buffer_table_set_n(nic, buf_id, addr, bufsz, \
++                                            region, n_pages, own_id))
 +
-+              rc = bind_virq.port;
-+              evtchn_bind_to_user(u, rc);
-+              break;
-+      }
++#define efhw_nic_buffer_table_clear(nic, id, num) \
++      ((nic)->efhw_func->buffer_table_clear(nic, id, num))
 +
-+      case IOCTL_EVTCHN_BIND_INTERDOMAIN: {
-+              struct ioctl_evtchn_bind_interdomain bind;
-+              struct evtchn_bind_interdomain bind_interdomain;
++#define efhw_nic_buffer_table_commit(nic) \
++      ((nic)->efhw_func->buffer_table_commit(nic))
 +
-+              rc = -EFAULT;
-+              if (copy_from_user(&bind, uarg, sizeof(bind)))
-+                      break;
++/*----------------------------------------------------------------------------
++ * Hardware specific portability macros for performance critical code.
++ *
++ * Warning: and driver code which is using these defines is not
++ * capable of supporting multiple NIC varients and should be built and
++ * marked appropriately
++ *
++ *---------------------------------------------------------------------------*/
 +
-+              bind_interdomain.remote_dom  = bind.remote_domain;
-+              bind_interdomain.remote_port = bind.remote_port;
-+              rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
-+                                               &bind_interdomain);
-+              if (rc != 0)
-+                      break;
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
 +
-+              rc = bind_interdomain.local_port;
-+              evtchn_bind_to_user(u, rc);
-+              break;
-+      }
++/* --- DMA --- */
++#define EFHW_DMA_ADDRMASK             (0xffffffffffffffffULL)
 +
-+      case IOCTL_EVTCHN_BIND_UNBOUND_PORT: {
-+              struct ioctl_evtchn_bind_unbound_port bind;
-+              struct evtchn_alloc_unbound alloc_unbound;
++/* --- Buffers --- */
++#define EFHW_BUFFER_ADDR              FALCON_BUFFER_4K_ADDR
++#define EFHW_BUFFER_PAGE              FALCON_BUFFER_4K_PAGE
++#define EFHW_BUFFER_OFF                       FALCON_BUFFER_4K_OFF
 +
-+              rc = -EFAULT;
-+              if (copy_from_user(&bind, uarg, sizeof(bind)))
-+                      break;
++/* --- Filters --- */
++#define EFHW_IP_FILTER_NUM            FALCON_FILTER_TBL_NUM
 +
-+              alloc_unbound.dom        = DOMID_SELF;
-+              alloc_unbound.remote_dom = bind.remote_domain;
-+              rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
-+                                               &alloc_unbound);
-+              if (rc != 0)
-+                      break;
++#define EFHW_MAX_PAGE_SIZE            FALCON_MAX_PAGE_SIZE
 +
-+              rc = alloc_unbound.port;
-+              evtchn_bind_to_user(u, rc);
-+              break;
-+      }
++#else
++# error no hardware definition found
++#endif
 +
-+      case IOCTL_EVTCHN_UNBIND: {
-+              struct ioctl_evtchn_unbind unbind;
-+              struct evtchn_close close;
-+              int ret;
++#if PAGE_SIZE <= EFHW_MAX_PAGE_SIZE
++#define EFHW_NIC_PAGE_SIZE PAGE_SIZE
++#else
++#define EFHW_NIC_PAGE_SIZE EFHW_MAX_PAGE_SIZE
++#endif
++#define EFHW_NIC_PAGE_MASK (~(EFHW_NIC_PAGE_SIZE-1))
 +
-+              rc = -EFAULT;
-+              if (copy_from_user(&unbind, uarg, sizeof(unbind)))
-+                      break;
++#endif /* __CI_DRIVER_EFAB_HARDWARE_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/resource/efx_vi.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/resource/efx_vi.h       2008-05-19 00:33:29.341837424 +0300
+@@ -0,0 +1,276 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains public EFX VI API to Solarflare resource manager.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+              rc = -EINVAL;
-+              if (unbind.port >= NR_EVENT_CHANNELS)
-+                      break;
++#ifndef __CI_DRIVER_RESOURCE_EFX_VI_H__
++#define __CI_DRIVER_RESOURCE_EFX_VI_H__
 +
-+              spin_lock_irq(&port_user_lock);
-+    
-+              rc = -ENOTCONN;
-+              if (port_user[unbind.port] != u) {
-+                      spin_unlock_irq(&port_user_lock);
-+                      break;
-+              }
++/* Default size of event queue in the efx_vi resource.  Copied from
++ * CI_CFG_NETIF_EVENTQ_SIZE */
++#define EFX_VI_EVENTQ_SIZE_DEFAULT 1024
 +
-+              port_user[unbind.port] = NULL;
-+              mask_evtchn(unbind.port);
++extern int efx_vi_eventq_size;
 +
-+              spin_unlock_irq(&port_user_lock);
++/**************************************************************************
++ * efx_vi_state types, allocation and free
++ **************************************************************************/
 +
-+              close.port = unbind.port;
-+              ret = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
-+              BUG_ON(ret);
++/*! Handle for refering to a efx_vi */
++struct efx_vi_state;
 +
-+              rc = 0;
-+              break;
-+      }
++/*!
++ * Allocate an efx_vi, including event queue and pt_endpoint
++ *
++ * \param vih_out Pointer to a handle that is set on success
++ * \param nic_index Index of NIC to apply this resource to
++ * \return Zero on success (and vih_out set), non-zero on failure.
++ */
++extern int
++efx_vi_alloc(struct efx_vi_state **vih_out, int nic_index);
 +
-+      case IOCTL_EVTCHN_NOTIFY: {
-+              struct ioctl_evtchn_notify notify;
++/*!
++ * Free a previously allocated efx_vi
++ *
++ * \param vih The handle of the efx_vi to free
++ */
++extern void
++efx_vi_free(struct efx_vi_state *vih);
 +
-+              rc = -EFAULT;
-+              if (copy_from_user(&notify, uarg, sizeof(notify)))
-+                      break;
++/*!
++ * Reset a previously allocated efx_vi
++ *
++ * \param vih The handle of the efx_vi to reset
++ */
++extern void
++efx_vi_reset(struct efx_vi_state *vih);
 +
-+              if (notify.port >= NR_EVENT_CHANNELS) {
-+                      rc = -EINVAL;
-+              } else if (port_user[notify.port] != u) {
-+                      rc = -ENOTCONN;
-+              } else {
-+                      notify_remote_via_evtchn(notify.port);
-+                      rc = 0;
-+              }
-+              break;
-+      }
++/**************************************************************************
++ * efx_vi_eventq types and functions
++ **************************************************************************/
 +
-+      case IOCTL_EVTCHN_RESET: {
-+              /* Initialise the ring to empty. Clear errors. */
-+              mutex_lock(&u->ring_cons_mutex);
-+              spin_lock_irq(&port_user_lock);
-+              u->ring_cons = u->ring_prod = u->ring_overflow = 0;
-+              spin_unlock_irq(&port_user_lock);
-+              mutex_unlock(&u->ring_cons_mutex);
-+              rc = 0;
-+              break;
-+      }
++/*!
++ * Register a function to receive callbacks when event queue timeouts
++ * or wakeups occur.  Only one function per efx_vi can be registered
++ * at once.
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param callback The function to callback
++ * \param context An argument to pass to the callback function
++ * \return Zero on success, non-zero on failure.
++ */
++extern int
++efx_vi_eventq_register_callback(struct efx_vi_state *vih,
++                              void (*callback)(void *context, int is_timeout),
++                              void *context);
 +
-+      default:
-+              rc = -ENOSYS;
-+              break;
-+      }
++/*!
++ * Remove the current eventq timeout or wakeup callback function
++ *
++ * \param vih The handle to identify the efx_vi
++ * \return Zero on success, non-zero on failure
++ */
++extern int
++efx_vi_eventq_kill_callback(struct efx_vi_state *vih);
 +
-+      return rc;
-+}
++/**************************************************************************
++ * efx_vi_dma_map types and functions
++ **************************************************************************/
 +
-+static unsigned int evtchn_poll(struct file *file, poll_table *wait)
-+{
-+      unsigned int mask = POLLOUT | POLLWRNORM;
-+      struct per_user_data *u = file->private_data;
++/*!
++ * Handle for refering to a efx_vi
++ */
++struct efx_vi_dma_map_state;
 +
-+      poll_wait(file, &u->evtchn_wait, wait);
-+      if (u->ring_cons != u->ring_prod)
-+              mask |= POLLIN | POLLRDNORM;
-+      if (u->ring_overflow)
-+              mask = POLLERR;
-+      return mask;
-+}
++/*!
++ * Map a list of buffer pages so they are registered with the hardware
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param addrs An array of page pointers to map
++ * \param n_addrs Length of the page pointer array.  Must be a power of two.
++ * \param dmh_out Set on success to a handle used to refer to this mapping
++ * \return Zero on success, non-zero on failure.
++ */
++extern int
++efx_vi_dma_map_pages(struct efx_vi_state *vih, struct page **pages,
++                       int n_pages, struct efx_vi_dma_map_state **dmh_out);
++extern int
++efx_vi_dma_map_addrs(struct efx_vi_state *vih,
++                   unsigned long long *dev_bus_addrs, int n_pages,
++                   struct efx_vi_dma_map_state **dmh_out);
 +
-+static int evtchn_fasync(int fd, struct file *filp, int on)
-+{
-+      struct per_user_data *u = filp->private_data;
-+      return fasync_helper(fd, filp, on, &u->evtchn_async_queue);
-+}
++/*!
++ * Unmap a previously mapped set of pages so they are no longer registered
++ * with the hardware.
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param dmh The handle to identify the dma mapping
++ */
++extern void
++efx_vi_dma_unmap_pages(struct efx_vi_state *vih,
++                     struct efx_vi_dma_map_state *dmh);
++extern void
++efx_vi_dma_unmap_addrs(struct efx_vi_state *vih,
++                     struct efx_vi_dma_map_state *dmh);
 +
-+static int evtchn_open(struct inode *inode, struct file *filp)
-+{
-+      struct per_user_data *u;
++/*!
++ * Retrieve the buffer address of the mapping
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param dmh The handle to identify the buffer mapping
++ * \return The buffer address on success, or zero on failure
++ */
++extern unsigned
++efx_vi_dma_get_map_addr(struct efx_vi_state *vih,
++                      struct efx_vi_dma_map_state *dmh);
 +
-+      if ((u = kmalloc(sizeof(*u), GFP_KERNEL)) == NULL)
-+              return -ENOMEM;
++/**************************************************************************
++ * efx_vi filter functions
++ **************************************************************************/
 +
-+      memset(u, 0, sizeof(*u));
-+      init_waitqueue_head(&u->evtchn_wait);
++#define EFX_VI_STATIC_FILTERS 32
 +
-+      u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
-+      if (u->ring == NULL) {
-+              kfree(u);
-+              return -ENOMEM;
-+      }
++/*! Handle to refer to a filter instance */
++struct filter_resource_t;
 +
-+      mutex_init(&u->ring_cons_mutex);
++/*!
++ * Allocate and add a filter
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param protocol The protocol of the new filter: UDP or TCP
++ * \param ip_addr_be32 The local ip address of the filter
++ * \param port_le16 The local port of the filter
++ * \param fh_out Set on success to be a handle to refer to this filter
++ * \return Zero on success, non-zero on failure.
++ */
++extern int
++efx_vi_filter(struct efx_vi_state *vih, int protocol, unsigned ip_addr_be32,
++            int port_le16, struct filter_resource_t **fh_out);
 +
-+      filp->private_data = u;
++/*!
++ * Remove a filter and free resources associated with it
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param fh The handle to identify the filter
++ * \return Zero on success, non-zero on failure
++ */
++extern int
++efx_vi_filter_stop(struct efx_vi_state *vih, struct filter_resource_t *fh);
++
++/**************************************************************************
++ * efx_vi hw resources types and functions
++ **************************************************************************/
++
++/*! Constants for the type field in efx_vi_hw_resource */
++#define EFX_VI_HW_RESOURCE_TXDMAQ    0x0      /* PFN of TX DMA Q */
++#define EFX_VI_HW_RESOURCE_RXDMAQ    0x1      /* PFN of RX DMA Q */
++#define EFX_VI_HW_RESOURCE_TXBELL    0x2      /* PFN of TX Doorbell (EF1) */
++#define EFX_VI_HW_RESOURCE_RXBELL    0x3      /* PFN of RX Doorbell (EF1) */
++#define EFX_VI_HW_RESOURCE_EVQTIMER  0x4      /* Address of event q timer */
++
++/* Address of event q pointer (EF1) */
++#define EFX_VI_HW_RESOURCE_EVQPTR    0x5
++/* Address of register pointer (Falcon A) */
++#define EFX_VI_HW_RESOURCE_EVQRPTR   0x6
++/* Offset of register pointer (Falcon B) */
++#define EFX_VI_HW_RESOURCE_EVQRPTR_OFFSET 0x7
++/* Address of mem KVA */
++#define EFX_VI_HW_RESOURCE_EVQMEMKVA 0x8
++/* PFN of doorbell page (Falcon) */
++#define EFX_VI_HW_RESOURCE_BELLPAGE  0x9
++
++/*! How large an array to allocate for the get_() functions - smaller
++  than the total number of constants as some are mutually exclusive */
++#define EFX_VI_HW_RESOURCE_MAXSIZE   0x7
++
++/*! Constants for the mem_type field in efx_vi_hw_resource */
++#define EFX_VI_HW_RESOURCE_IOBUFFER   0       /* Host memory */
++#define EFX_VI_HW_RESOURCE_PERIPHERAL 1       /* Card memory/registers */
++
++/*!
++ * Data structure providing information on a hardware resource mapping
++ */
++struct efx_vi_hw_resource {
++      u8 type;                /*!< What this resource represents */
++      u8 mem_type;            /*!< What type of memory is it in, eg,
++                               * host or iomem */
++      u8 more_to_follow;      /*!< Is this part of a multi-region resource */
++      u32 length;             /*!< Length of the resource in bytes */
++      unsigned long address;  /*!< Address of this resource */
++};
++
++/*!
++ * Metadata concerning the list of hardware resource mappings
++ */
++struct efx_vi_hw_resource_metadata {
++      int version;
++      int evq_order;
++      int evq_offs;
++      int evq_capacity;
++      int instance;
++      unsigned rx_capacity;
++      unsigned tx_capacity;
++      int nic_arch;
++      int nic_revision;
++      char nic_variant;
++};
++
++/*!
++ * Obtain a list of hardware resource mappings, using virtual addresses
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param mdata Pointer to a structure to receive the metadata
++ * \param hw_res_array An array to receive the list of hardware resources
++ * \param length The length of hw_res_array.  Updated on success to contain
++ * the number of entries in the supplied array that were used.
++ * \return Zero on success, non-zero on failure
++ */
++extern int
++efx_vi_hw_resource_get_virt(struct efx_vi_state *vih,
++                          struct efx_vi_hw_resource_metadata *mdata,
++                          struct efx_vi_hw_resource *hw_res_array,
++                          int *length);
 +
-+      u->bind_cpu = -1;
++/*!
++ * Obtain a list of hardware resource mappings, using physical addresses
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param mdata Pointer to a structure to receive the metadata
++ * \param hw_res_array An array to receive the list of hardware resources
++ * \param length The length of hw_res_array.  Updated on success to contain
++ * the number of entries in the supplied array that were used.
++ * \return Zero on success, non-zero on failure
++ */
++extern int
++efx_vi_hw_resource_get_phys(struct efx_vi_state *vih,
++                          struct efx_vi_hw_resource_metadata *mdata,
++                          struct efx_vi_hw_resource *hw_res_array,
++                          int *length);
++
++#endif /* __CI_DRIVER_RESOURCE_EFX_VI_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/driver/resource/linux_efhw_nic.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/driver/resource/linux_efhw_nic.h       2008-05-19 00:33:29.341837424 +0300
+@@ -0,0 +1,76 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains definition of the public type struct linux_efhw_nic.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      return 0;
-+}
++#ifndef __CI_DRIVER_RESOURCE_LINUX_RESOURCE__
++#define __CI_DRIVER_RESOURCE_LINUX_RESOURCE__
 +
-+static int evtchn_release(struct inode *inode, struct file *filp)
-+{
-+      int i;
-+      struct per_user_data *u = filp->private_data;
-+      struct evtchn_close close;
++#ifndef __linux__
++# error Silly
++#endif
++#ifndef __KERNEL__
++# error Silly
++#endif
 +
-+      spin_lock_irq(&port_user_lock);
++#include <ci/efhw/efhw_types.h>
++#include <linux/interrupt.h>
 +
-+      free_page((unsigned long)u->ring);
 +
-+      for (i = 0; i < NR_EVENT_CHANNELS; i++) {
-+              int ret;
-+              if (port_user[i] != u)
-+                      continue;
++/************************************************************************
++ * Per-nic structure in the resource driver                             *
++ ************************************************************************/
 +
-+              port_user[i] = NULL;
-+              mask_evtchn(i);
++struct linux_efhw_nic {
++      struct efhw_nic nic;
 +
-+              close.port = i;
-+              ret = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
-+              BUG_ON(ret);
-+      }
++      struct pci_dev *pci_dev;        /*!< pci descriptor */
++      struct tasklet_struct tasklet;  /*!< for interrupt bottom half */
 +
-+      spin_unlock_irq(&port_user_lock);
++      /* Physical addresses of the control aperture bar. */
++      unsigned long ctr_ap_pci_addr;
 +
-+      kfree(u);
++      /*! Callbacks for driverlink, when needed. */
++      struct efx_dl_callbacks *dl_callbacks;
 +
-+      return 0;
-+}
++      /*! Event handlers. */
++      struct efhw_ev_handler *ev_handlers;
 +
-+static const struct file_operations evtchn_fops = {
-+      .owner   = THIS_MODULE,
-+      .read    = evtchn_read,
-+      .write   = evtchn_write,
-+      .unlocked_ioctl = evtchn_ioctl,
-+      .poll    = evtchn_poll,
-+      .fasync  = evtchn_fasync,
-+      .open    = evtchn_open,
-+      .release = evtchn_release,
 +};
 +
-+static struct miscdevice evtchn_miscdev = {
-+      .minor        = MISC_DYNAMIC_MINOR,
-+      .name         = "evtchn",
-+      .fops         = &evtchn_fops,
-+};
++#define linux_efhw_nic(efhw_nic)                \
++  container_of(efhw_nic, struct linux_efhw_nic, nic)
 +
-+static int __cpuinit evtchn_cpu_notify(struct notifier_block *nfb,
-+                      unsigned long action, void *hcpu)
-+{
-+      int hotcpu = (unsigned long)hcpu;
-+      cpumask_t map = cpu_online_map;
-+      int port, newcpu;
-+      struct per_user_data *u;
++#endif /* __CI_DRIVER_RESOURCE_LINUX_RESOURCE__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/checks.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/checks.h  2008-05-19 00:33:29.345837655 +0300
+@@ -0,0 +1,118 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides helpers to turn bit shifts into dword shifts and
++ * check that the bit fields haven't overflown the dword etc.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFHW_CHECK_H__
++#define __CI_EFHW_CHECK_H__
++
++/*----------------------------------------------------------------------------
++ *
++ * Helpers to turn bit shifts into dword shifts and check that the bit fields
++ * haven't overflown the dword etc. Aim is to preserve consistency with the
++ * autogenerated headers - once stable we could hard code.
++ *
++ *---------------------------------------------------------------------------*/
++
++/* mask constructors */
++#define __FALCON_MASK(WIDTH, T)       ((((T)1) << (WIDTH)) - 1)
++#define __FALCON_MASK32(WIDTH)        __FALCON_MASK((WIDTH), uint32_t)
++#define __FALCON_MASK64(WIDTH)        __FALCON_MASK((WIDTH), uint64_t)
++
++#define __FALCON_MASKFIELD32(LBN, WIDTH) \
++      ((uint32_t)(__FALCON_MASK32(WIDTH) << (LBN)))
++
++/* constructors for fields which span the first and second dwords */
++#define __LW(LBN)             (32 - LBN)
++#define __LOW(v, LBN, WIDTH) \
++      ((uint32_t)(((v) & __FALCON_MASK64(__LW((LBN)))) << (LBN)))
++#define __HIGH(v, LBN, WIDTH) \
++      ((uint32_t)(((v) >> __LW((LBN))) & \
++                  __FALCON_MASK64((WIDTH - __LW((LBN))))))
++/* constructors for fields within the second dword */
++#define __DW2(LBN)            ((LBN) - 32)
++
++/* constructors for fields which span the second and third dwords */
++#define __LW2(LBN)            (64 - LBN)
++#define __LOW2(v, LBN, WIDTH) \
++      ((uint32_t)(((v) & __FALCON_MASK64(__LW2((LBN)))) << ((LBN) - 32)))
++#define __HIGH2(v, LBN, WIDTH) \
++      ((uint32_t)(((v) >> __LW2((LBN))) & \
++                  __FALCON_MASK64((WIDTH - __LW2((LBN))))))
++
++/* constructors for fields within the third dword */
++#define __DW3(LBN)            ((LBN) - 64)
++
++/* constructors for fields which span the third and fourth dwords */
++#define __LW3(LBN)            (96 - LBN)
++#define __LOW3(v, LBN, WIDTH) \
++      ((uint32_t)(((v) & __FALCON_MASK64(__LW3((LBN)))) << ((LBN) - 64)))
++#define __HIGH3(v, LBN, WIDTH) \
++      ((ci_unit32)(((v) >> __LW3((LBN))) & \
++                   __FALCON_MASK64((WIDTH - __LW3((LBN))))))
++
++/* constructors for fields within the fourth dword */
++#define __DW4(LBN)            ((LBN) - 96)
++
++/* checks that the autogenerated headers are consistent with our model */
++#define __WIDTHCHCK(a, b)     EFHW_ASSERT((a) == (b))
++#define __RANGECHCK(v, WIDTH) \
++      EFHW_ASSERT(((uint64_t)(v) & ~(__FALCON_MASK64((WIDTH)))) == 0)
++
++/* fields within the first dword */
++#define __DWCHCK(LBN, WIDTH) \
++      EFHW_ASSERT(((LBN) >= 0) && (((LBN)+(WIDTH)) <= 32))
++
++/* fields which span the first and second dwords */
++#define __LWCHK(LBN, WIDTH)   EFHW_ASSERT(WIDTH >= __LW(LBN))
++
++/* fields within the second dword */
++#define __DW2CHCK(LBN, WIDTH) \
++      EFHW_ASSERT(((LBN) >= 32) && (((LBN)+(WIDTH)) <= 64))
++
++/* fields which span the second and third dwords */
++#define __LW2CHK(LBN, WIDTH)  EFHW_ASSERT(WIDTH >= __LW2(LBN))
++
++/* fields within the third dword */
++#define __DW3CHCK(LBN, WIDTH) \
++      EFHW_ASSERT(((LBN) >= 64) && (((LBN)+(WIDTH)) <= 96))
++
++/* fields which span the third and fourth dwords */
++#define __LW3CHK(LBN, WIDTH)  EFHW_ASSERT(WIDTH >= __LW3(LBN))
++
++/* fields within the fourth dword */
++#define __DW4CHCK(LBN, WIDTH) \
++      EFHW_ASSERT(((LBN) >= 96) && (((LBN)+(WIDTH)) <= 128))
++
++/* fields in the first qword */
++#define __QWCHCK(LBN, WIDTH) \
++      EFHW_ASSERT(((LBN) >= 0) && (((LBN)+(WIDTH)) <= 64))
++
++#endif /* __CI_EFHW_CHECK_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/common.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/common.h  2008-05-19 00:33:29.345837655 +0300
+@@ -0,0 +1,102 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides API of the efhw library which may be used both from
++ * the kernel and from the user-space code.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      switch (action) {
-+      case CPU_DOWN_PREPARE:
-+              cpu_clear(hotcpu, map);
-+              spin_lock_irq(&port_user_lock);
-+              for (port = 0; port < NR_EVENT_CHANNELS; port++) {
-+                      if ((u = port_user[port]) != NULL && 
-+                          u->bind_cpu == hotcpu &&
-+                          (newcpu = next_bind_cpu(map)) < NR_CPUS) {
-+                              rebind_evtchn_to_cpu(port, newcpu);
-+                              u->bind_cpu = newcpu;
-+                      }
-+              }
-+              spin_unlock_irq(&port_user_lock);
-+              break;
-+      default:
-+              return NOTIFY_DONE;
-+      }
-+      return NOTIFY_OK;
-+}
++#ifndef __CI_EFHW_COMMON_H__
++#define __CI_EFHW_COMMON_H__
 +
-+static struct notifier_block __cpuinitdata evtchn_cpu_nfb = {
-+      .notifier_call = evtchn_cpu_notify
-+};
++#include <ci/efhw/common_sysdep.h>
 +
-+static int __init evtchn_init(void)
-+{
-+      int err;
++enum efhw_arch {
++      EFHW_ARCH_FALCON,
++      EFHW_ARCH_SIENA,
++};
 +
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++typedef uint32_t efhw_buffer_addr_t;
++#define EFHW_BUFFER_ADDR_FMT  "[ba:%"PRIx32"]"
 +
-+      spin_lock_init(&port_user_lock);
-+      memset(port_user, 0, sizeof(port_user));
++/*! Comment? */
++typedef union {
++      uint64_t u64;
++      struct {
++              uint32_t a;
++              uint32_t b;
++      } opaque;
++      struct {
++              uint32_t code;
++              uint32_t status;
++      } ev1002;
++} efhw_event_t;
++
++/* Flags for TX/RX queues */
++#define EFHW_VI_JUMBO_EN           0x01  /*! scatter RX over multiple desc */
++#define EFHW_VI_ISCSI_RX_HDIG_EN   0x02  /*! iscsi rx header digest */
++#define EFHW_VI_ISCSI_TX_HDIG_EN   0x04  /*! iscsi tx header digest */
++#define EFHW_VI_ISCSI_RX_DDIG_EN   0x08  /*! iscsi rx data digest */
++#define EFHW_VI_ISCSI_TX_DDIG_EN   0x10  /*! iscsi tx data digest */
++#define EFHW_VI_TX_PHYS_ADDR_EN    0x20  /*! TX physical address mode */
++#define EFHW_VI_RX_PHYS_ADDR_EN    0x40  /*! RX physical address mode */
++#define EFHW_VI_RM_WITH_INTERRUPT  0x80  /*! VI with an interrupt */
++#define EFHW_VI_TX_IP_CSUM_DIS     0x100 /*! enable ip checksum generation */
++#define EFHW_VI_TX_TCPUDP_CSUM_DIS 0x200 /*! enable tcp/udp checksum
++                                         generation */
++#define EFHW_VI_TX_TCPUDP_ONLY     0x400 /*! drop non-tcp/udp packets */
++
++/* Types of hardware filter */
++/* Each of these values implicitly selects scatter filters on B0 - or in
++   EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK if a non-scatter filter is required */
++#define EFHW_IP_FILTER_TYPE_UDP_WILDCARD  (0) /* dest host only */
++#define EFHW_IP_FILTER_TYPE_UDP_FULL      (1) /* dest host and port */
++#define EFHW_IP_FILTER_TYPE_TCP_WILDCARD  (2) /* dest based filter */
++#define EFHW_IP_FILTER_TYPE_TCP_FULL      (3) /* src  filter */
++/* Same again, but with RSS (for B0 only) */
++#define EFHW_IP_FILTER_TYPE_UDP_WILDCARD_RSS_B0  (4)
++#define EFHW_IP_FILTER_TYPE_UDP_FULL_RSS_B0      (5)
++#define EFHW_IP_FILTER_TYPE_TCP_WILDCARD_RSS_B0  (6)
++#define EFHW_IP_FILTER_TYPE_TCP_FULL_RSS_B0      (7)
++
++#define EFHW_IP_FILTER_TYPE_FULL_MASK      (0x1) /* Mask for full / wildcard */
++#define EFHW_IP_FILTER_TYPE_TCP_MASK       (0x2) /* Mask for TCP type */
++#define EFHW_IP_FILTER_TYPE_RSS_B0_MASK    (0x4) /* Mask for B0 RSS enable */
++#define EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK (0x8) /* Mask for B0 SCATTER dsbl */
++
++#define EFHW_IP_FILTER_TYPE_MASK      (0xffff) /* Mask of types above */
++
++#define EFHW_IP_FILTER_BROADCAST      (0x10000) /* driverlink filter
++                                                   support */
++
++#endif /* __CI_EFHW_COMMON_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/common_sysdep.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/common_sysdep.h   2008-05-19 00:33:29.365838808 +0300
+@@ -0,0 +1,71 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides version-independent Linux kernel API for
++ * userland-to-kernel interfaces.
++ * Only kernels >=2.6.9 are supported.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      /* Create '/dev/misc/evtchn'. */
-+      err = misc_register(&evtchn_miscdev);
-+      if (err != 0) {
-+              printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
-+              return err;
-+      }
++#ifndef __CI_EFHW_COMMON_LINUX_H__
++#define __CI_EFHW_COMMON_LINUX_H__
 +
-+      register_cpu_notifier(&evtchn_cpu_nfb);
++#include <linux/types.h>
++#include <linux/version.h>
 +
-+      printk("Event-channel device installed.\n");
++/* Dirty hack, but Linux kernel does not provide DMA_ADDR_T_FMT */
++#if BITS_PER_LONG == 64 || defined(CONFIG_HIGHMEM64G)
++#define DMA_ADDR_T_FMT "%llx"
++#else
++#define DMA_ADDR_T_FMT "%x"
++#endif
 +
-+      return 0;
-+}
++/* Linux kernel also does not provide PRIx32... Sigh. */
++#define PRIx32 "x"
 +
-+static void __exit evtchn_cleanup(void)
-+{
-+      misc_deregister(&evtchn_miscdev);
-+      unregister_cpu_notifier(&evtchn_cpu_nfb);
-+}
++#ifdef __ia64__
++# define PRIx64 "lx"
++#else
++# define PRIx64 "llx"
++#endif
 +
-+module_init(evtchn_init);
-+module_exit(evtchn_cleanup);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++enum {
++      false = 0,
++      true = 1
++};
 +
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/evtchn/Makefile linux-2.6.18-xen.hg/drivers/xen/evtchn/Makefile
---- linux-2.6.18/drivers/xen/evtchn/Makefile   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/evtchn/Makefile    2007-12-23 11:15:33.867925803 +0100
-@@ -0,0 +1,2 @@
++typedef _Bool bool;
++#endif /* LINUX_VERSION_CODE < 2.6.19 */
 +
-+obj-y := evtchn.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/fbfront/Makefile linux-2.6.18-xen.hg/drivers/xen/fbfront/Makefile
---- linux-2.6.18/drivers/xen/fbfront/Makefile  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/fbfront/Makefile   2007-12-23 11:15:33.871259312 +0100
-@@ -0,0 +1,2 @@
-+obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o
-+obj-$(CONFIG_XEN_KEYBOARD)    += xenkbd.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/fbfront/xenfb.c linux-2.6.18-xen.hg/drivers/xen/fbfront/xenfb.c
---- linux-2.6.18/drivers/xen/fbfront/xenfb.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/fbfront/xenfb.c    2007-12-23 11:15:33.871259312 +0100
-@@ -0,0 +1,758 @@
-+/*
-+ * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device
++#endif /* __CI_EFHW_COMMON_LINUX_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/debug.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/debug.h   2008-05-19 00:33:29.365838808 +0300
+@@ -0,0 +1,84 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
 + *
-+ * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com>
-+ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
++ * This file provides debug-related API for efhw library using Linux kernel
++ * primitives.
 + *
-+ *  Based on linux/drivers/video/q40fb.c
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
 + *
-+ *  This file is subject to the terms and conditions of the GNU General Public
-+ *  License. See the file COPYING in the main directory of this archive for
-+ *  more details.
-+ */
-+
-+/*
-+ * TODO:
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
 + *
-+ * Switch to grant tables when they become capable of dealing with the
-+ * frame buffer.
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/fb.h>
-+#include <linux/module.h>
-+#include <linux/vmalloc.h>
-+#include <linux/mm.h>
-+#include <linux/mutex.h>
-+#include <asm/hypervisor.h>
-+#include <xen/evtchn.h>
-+#include <xen/interface/io/fbif.h>
-+#include <xen/interface/io/protocols.h>
-+#include <xen/xenbus.h>
-+#include <linux/kthread.h>
++#ifndef __CI_EFHW_DEBUG_LINUX_H__
++#define __CI_EFHW_DEBUG_LINUX_H__
 +
-+struct xenfb_mapping
-+{
-+      struct list_head        link;
-+      struct vm_area_struct   *vma;
-+      atomic_t                map_refs;
-+      int                     faults;
-+      struct xenfb_info       *info;
-+};
++#define EFHW_PRINTK_PREFIX "[sfc efhw] "
 +
-+struct xenfb_info
-+{
-+      struct task_struct      *kthread;
-+      wait_queue_head_t       wq;
++#define EFHW_PRINTK(level, fmt, ...) \
++      printk(level EFHW_PRINTK_PREFIX fmt "\n", __VA_ARGS__)
 +
-+      unsigned char           *fb;
-+      struct fb_info          *fb_info;
-+      struct timer_list       refresh;
-+      int                     dirty;
-+      int                     x1, y1, x2, y2; /* dirty rectangle,
-+                                                 protected by dirty_lock */
-+      spinlock_t              dirty_lock;
-+      struct mutex            mm_lock;
-+      int                     nr_pages;
-+      struct page             **pages;
-+      struct list_head        mappings; /* protected by mm_lock */
++/* Following macros should be used with non-zero format parameters
++ * due to __VA_ARGS__ limitations.  Use "%s" with __FUNCTION__ if you can't
++ * find better parameters. */
++#define EFHW_ERR(fmt, ...)     EFHW_PRINTK(KERN_ERR, fmt, __VA_ARGS__)
++#define EFHW_WARN(fmt, ...)    EFHW_PRINTK(KERN_WARNING, fmt, __VA_ARGS__)
++#define EFHW_NOTICE(fmt, ...)  EFHW_PRINTK(KERN_NOTICE, fmt, __VA_ARGS__)
++#if 0 && !defined(NDEBUG)
++#define EFHW_TRACE(fmt, ...) EFHW_PRINTK(KERN_DEBUG, fmt, __VA_ARGS__)
++#else
++#define EFHW_TRACE(fmt, ...)
++#endif
 +
-+      int                     irq;
-+      struct xenfb_page       *page;
-+      unsigned long           *mfns;
-+      int                     update_wanted; /* XENFB_TYPE_UPDATE wanted */
++#ifndef NDEBUG
++#define EFHW_ASSERT(cond)  BUG_ON((cond) == 0)
++#define EFHW_DO_DEBUG(expr) expr
++#else
++#define EFHW_ASSERT(cond)
++#define EFHW_DO_DEBUG(expr)
++#endif
 +
-+      struct xenbus_device    *xbdev;
-+};
++#define EFHW_TEST(expr)                       \
++      do {                            \
++              if (unlikely(!(expr)))  \
++              BUG();                  \
++      } while (0)
 +
-+/*
-+ * How the locks work together
++/* Build time asserts. We paste the line number into the type name
++ * so that the macro can be used more than once per file even if the
++ * compiler objects to multiple identical typedefs. Collisions
++ * between use in different header files is still possible. */
++#ifndef EFHW_BUILD_ASSERT
++#define __EFHW_BUILD_ASSERT_NAME(_x) __EFHW_BUILD_ASSERT_ILOATHECPP(_x)
++#define __EFHW_BUILD_ASSERT_ILOATHECPP(_x)  __EFHW_BUILD_ASSERT__ ##_x
++#define EFHW_BUILD_ASSERT(e) \
++      typedef char __EFHW_BUILD_ASSERT_NAME(__LINE__)[(e) ? 1 : -1]
++#endif
++
++#endif /* __CI_EFHW_DEBUG_LINUX_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/efhw_config.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/efhw_config.h     2008-05-19 00:33:29.365838808 +0300
+@@ -0,0 +1,43 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
 + *
-+ * There are two locks: spinlock dirty_lock protecting the dirty
-+ * rectangle, and mutex mm_lock protecting mappings.
++ * This file provides some limits used in both kernel and userland code.
 + *
-+ * The problem is that dirty rectangle and mappings aren't
-+ * independent: the dirty rectangle must cover all faulted pages in
-+ * mappings.  We need to prove that our locking maintains this
-+ * invariant.
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
 + *
-+ * There are several kinds of critical regions:
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
 + *
-+ * 1. Holding only dirty_lock: xenfb_refresh().  May run in
-+ *    interrupts.  Extends the dirty rectangle.  Trivially preserves
-+ *    invariant.
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
 + *
-+ * 2. Holding only mm_lock: xenfb_mmap() and xenfb_vm_close().  Touch
-+ *    only mappings.  The former creates unfaulted pages.  Preserves
-+ *    invariant.  The latter removes pages.  Preserves invariant.
 + *
-+ * 3. Holding both locks: xenfb_vm_nopage().  Extends the dirty
-+ *    rectangle and updates mappings consistently.  Preserves
-+ *    invariant.
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
 + *
-+ * 4. The ugliest one: xenfb_update_screen().  Clear the dirty
-+ *    rectangle and update mappings consistently.
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
 + *
-+ *    We can't simply hold both locks, because zap_page_range() cannot
-+ *    be called with a spinlock held.
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFHW_EFAB_CONFIG_H__
++#define __CI_EFHW_EFAB_CONFIG_H__
++
++#define EFHW_MAX_NR_DEVS 5    /* max number of efhw devices supported */
++
++#endif /* __CI_EFHW_EFAB_CONFIG_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/efhw_types.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/efhw_types.h      2008-05-19 00:33:29.365838808 +0300
+@@ -0,0 +1,342 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
 + *
-+ *    Therefore, we first clear the dirty rectangle with both locks
-+ *    held.  Then we unlock dirty_lock and update the mappings.
-+ *    Critical regions that hold only dirty_lock may interfere with
-+ *    that.  This can only be region 1: xenfb_refresh().  But that
-+ *    just extends the dirty rectangle, which can't harm the
-+ *    invariant.
++ * This file provides struct efhw_nic and some related types.
 + *
-+ * But FIXME: the invariant is too weak.  It misses that the fault
-+ * record in mappings must be consistent with the mapping of pages in
-+ * the associated address space!  do_no_page() updates the PTE after
-+ * xenfb_vm_nopage() returns, i.e. outside the critical region.  This
-+ * allows the following race:
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
 + *
-+ * X writes to some address in the Xen frame buffer
-+ * Fault - call do_no_page()
-+ *     call xenfb_vm_nopage()
-+ *         grab mm_lock
-+ *         map->faults++;
-+ *         release mm_lock
-+ *     return back to do_no_page()
-+ * (preempted, or SMP)
-+ * Xen worker thread runs.
-+ *      grab mm_lock
-+ *      look at mappings
-+ *          find this mapping, zaps its pages (but page not in pte yet)
-+ *          clear map->faults
-+ *      releases mm_lock
-+ * (back to X process)
-+ *     put page in X's pte
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
 + *
-+ * Oh well, we wont be updating the writes to this page anytime soon.
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+static int xenfb_fps = 20;
-+static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8;
++#ifndef __CI_EFHW_EFAB_TYPES_H__
++#define __CI_EFHW_EFAB_TYPES_H__
 +
-+static int xenfb_remove(struct xenbus_device *);
-+static void xenfb_init_shared_page(struct xenfb_info *);
-+static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *);
-+static void xenfb_disconnect_backend(struct xenfb_info *);
++#include <ci/efhw/efhw_config.h>
++#include <ci/efhw/hardware_sysdep.h>
++#include <ci/efhw/iopage_types.h>
++#include <ci/efhw/sysdep.h>
 +
-+static void xenfb_do_update(struct xenfb_info *info,
-+                          int x, int y, int w, int h)
-+{
-+      union xenfb_out_event event;
-+      __u32 prod;
++/*--------------------------------------------------------------------
++ *
++ * hardware limits used in the types
++ *
++ *--------------------------------------------------------------------*/
 +
-+      event.type = XENFB_TYPE_UPDATE;
-+      event.update.x = x;
-+      event.update.y = y;
-+      event.update.width = w;
-+      event.update.height = h;
++#define EFHW_KEVENTQ_MAX    8
 +
-+      prod = info->page->out_prod;
-+      /* caller ensures !xenfb_queue_full() */
-+      mb();                   /* ensure ring space available */
-+      XENFB_OUT_RING_REF(info->page, prod) = event;
-+      wmb();                  /* ensure ring contents visible */
-+      info->page->out_prod = prod + 1;
++/*--------------------------------------------------------------------
++ *
++ * forward type declarations
++ *
++ *--------------------------------------------------------------------*/
 +
-+      notify_remote_via_irq(info->irq);
-+}
++struct efhw_nic;
 +
-+static int xenfb_queue_full(struct xenfb_info *info)
-+{
-+      __u32 cons, prod;
++/*--------------------------------------------------------------------
++ *
++ * Managed interface
++ *
++ *--------------------------------------------------------------------*/
 +
-+      prod = info->page->out_prod;
-+      cons = info->page->out_cons;
-+      return prod - cons == XENFB_OUT_RING_LEN;
-+}
++struct efhw_buffer_table_allocation{
++      unsigned base;
++      unsigned order;
++};
 +
-+static void xenfb_update_screen(struct xenfb_info *info)
-+{
-+      unsigned long flags;
-+      int y1, y2, x1, x2;
-+      struct xenfb_mapping *map;
++struct eventq_resource_hardware {
++      /*!iobuffer allocated for eventq - can be larger than eventq */
++      efhw_iopages_t iobuff;
++      unsigned iobuff_off;
++      struct efhw_buffer_table_allocation buf_tbl_alloc;
++      int capacity;           /*!< capacity of event queue */
++};
 +
-+      if (!info->update_wanted)
-+              return;
-+      if (xenfb_queue_full(info))
-+              return;
++/*--------------------------------------------------------------------
++ *
++ * event queues and event driven callbacks
++ *
++ *--------------------------------------------------------------------*/
 +
-+      mutex_lock(&info->mm_lock);
++struct efhw_keventq {
++      volatile int lock;
++      caddr_t evq_base;
++      int32_t evq_ptr;
++      uint32_t evq_mask;
++      unsigned instance;
++      struct eventq_resource_hardware hw;
++      struct efhw_ev_handler *ev_handlers;
++};
 +
-+      spin_lock_irqsave(&info->dirty_lock, flags);
-+      y1 = info->y1;
-+      y2 = info->y2;
-+      x1 = info->x1;
-+      x2 = info->x2;
-+      info->x1 = info->y1 = INT_MAX;
-+      info->x2 = info->y2 = 0;
-+      spin_unlock_irqrestore(&info->dirty_lock, flags);
++/**********************************************************************
++ * Portable HW interface. ***************************************
++ **********************************************************************/
 +
-+      list_for_each_entry(map, &info->mappings, link) {
-+              if (!map->faults)
-+                      continue;
-+              zap_page_range(map->vma, map->vma->vm_start,
-+                             map->vma->vm_end - map->vma->vm_start, NULL);
-+              map->faults = 0;
-+      }
++/*--------------------------------------------------------------------
++ *
++ * EtherFabric Functional units - configuration and control
++ *
++ *--------------------------------------------------------------------*/
 +
-+      mutex_unlock(&info->mm_lock);
++struct efhw_func_ops {
 +
-+      if (x2 < x1 || y2 < y1) {
-+              printk("xenfb_update_screen bogus rect %d %d %d %d\n",
-+                     x1, x2, y1, y2);
-+              WARN_ON(1);
-+      }
-+      xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1);
-+}
++  /*-------------- Initialisation ------------ */
 +
-+static int xenfb_thread(void *data)
-+{
-+      struct xenfb_info *info = data;
++      /*! close down all hardware functional units - leaves NIC in a safe
++         state for driver unload */
++      void (*close_hardware) (struct efhw_nic *nic);
 +
-+      while (!kthread_should_stop()) {
-+              if (info->dirty) {
-+                      info->dirty = 0;
-+                      xenfb_update_screen(info);
-+              }
-+              wait_event_interruptible(info->wq,
-+                      kthread_should_stop() || info->dirty);
-+              try_to_freeze();
-+      }
-+      return 0;
-+}
++      /*! initialise all hardware functional units */
++      int (*init_hardware) (struct efhw_nic *nic,
++                            struct efhw_ev_handler *,
++                            const uint8_t *mac_addr);
 +
-+static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
-+                         unsigned blue, unsigned transp,
-+                         struct fb_info *info)
-+{
-+      u32 v;
++  /*-------------- Interrupt support  ------------ */
 +
-+      if (regno > info->cmap.len)
-+              return 1;
++      /*! Main interrupt routine
++       **        This function returns,
++       **  - zero,       if the IRQ was not generated by EF1
++       **  - non-zero,   if EF1 was the source of the IRQ
++       **
++       **
++       ** opaque is an OS provided pointer for use by the OS callbacks
++       ** e.g in Windows used to indicate DPC scheduled
++       */
++      int (*interrupt) (struct efhw_nic *nic);
 +
-+      red   >>= (16 - info->var.red.length);
-+      green >>= (16 - info->var.green.length);
-+      blue  >>= (16 - info->var.blue.length);
++      /*! Enable given interrupt mask for the given IRQ unit */
++      void (*interrupt_enable) (struct efhw_nic *nic, uint idx);
 +
-+      v = (red << info->var.red.offset) |
-+          (green << info->var.green.offset) |
-+          (blue << info->var.blue.offset);
++      /*! Disable given interrupt mask for the given IRQ unit */
++      void (*interrupt_disable) (struct efhw_nic *nic, uint idx);
 +
-+      /* FIXME is this sane?  check against xxxfb_setcolreg()!  */
-+      switch (info->var.bits_per_pixel) {
-+      case 16:
-+      case 24:
-+      case 32:
-+              ((u32 *)info->pseudo_palette)[regno] = v;
-+              break;
-+      }
-+      
-+      return 0;
-+}
++      /*! Set interrupt moderation strategy for the given IRQ unit
++       ** val is in usec
++       */
++      void (*set_interrupt_moderation)(struct efhw_nic *nic,
++                                       uint idx, uint val);
 +
-+static void xenfb_timer(unsigned long data)
-+{
-+      struct xenfb_info *info = (struct xenfb_info *)data;
-+      wake_up(&info->wq);
-+}
++  /*-------------- Event support  ------------ */
 +
-+static void __xenfb_refresh(struct xenfb_info *info,
-+                          int x1, int y1, int w, int h)
-+{
-+      int y2, x2;
++      /*! Enable the given event queue
++         depending on the underlying implementation (EF1 or Falcon) then
++         either a q_base_addr in host memory, or a buffer base id should
++         be proivded
++       */
++      void (*event_queue_enable) (struct efhw_nic *nic,
++                                  uint evq,   /* evnt queue index */
++                                  uint evq_size,      /* units of #entries */
++                                  dma_addr_t q_base_addr, uint buf_base_id);
 +
-+      y2 = y1 + h;
-+      x2 = x1 + w;
++      /*! Disable the given event queue (and any associated timer) */
++      void (*event_queue_disable) (struct efhw_nic *nic, uint evq,
++                                   int timer_only);
 +
-+      if (info->y1 > y1)
-+              info->y1 = y1;
-+      if (info->y2 < y2)
-+              info->y2 = y2;
-+      if (info->x1 > x1)
-+              info->x1 = x1;
-+      if (info->x2 < x2)
-+              info->x2 = x2;
-+      info->dirty = 1;
++      /*! request wakeup from the NIC on a given event Q */
++      void (*wakeup_request) (struct efhw_nic *nic, dma_addr_t q_base_addr,
++                              int next_i, int evq);
 +
-+      if (timer_pending(&info->refresh))
-+              return;
++      /*! Push a SW event on a given eventQ */
++      void (*sw_event) (struct efhw_nic *nic, int data, int evq);
 +
-+      mod_timer(&info->refresh, jiffies + HZ/xenfb_fps);
-+}
++  /*-------------- Filter support  ------------ */
 +
-+static void xenfb_refresh(struct xenfb_info *info,
-+                        int x1, int y1, int w, int h)
-+{
-+      unsigned long flags;
++      /*! Setup a given filter - The software can request a filter_i,
++       * but some EtherFabric implementations will override with
++       * a more suitable index
++       */
++      int (*ipfilter_set) (struct efhw_nic *nic, int type,
++                           int *filter_i, int dmaq,
++                           unsigned saddr_be32, unsigned sport_be16,
++                           unsigned daddr_be32, unsigned dport_be16);
 +
-+      spin_lock_irqsave(&info->dirty_lock, flags);
-+      __xenfb_refresh(info, x1, y1, w, h);
-+      spin_unlock_irqrestore(&info->dirty_lock, flags);
-+}
++      /*! Attach a given filter to a DMAQ */
++      void (*ipfilter_attach) (struct efhw_nic *nic, int filter_idx,
++                               int dmaq_idx);
 +
-+static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
-+{
-+      struct xenfb_info *info = p->par;
++      /*! Detach a filter from its DMAQ */
++      void (*ipfilter_detach) (struct efhw_nic *nic, int filter_idx);
 +
-+      cfb_fillrect(p, rect);
-+      xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);
-+}
++      /*! Clear down a given filter */
++      void (*ipfilter_clear) (struct efhw_nic *nic, int filter_idx);
 +
-+static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image)
-+{
-+      struct xenfb_info *info = p->par;
++  /*-------------- DMA support  ------------ */
 +
-+      cfb_imageblit(p, image);
-+      xenfb_refresh(info, image->dx, image->dy, image->width, image->height);
-+}
++      /*! Initialise NIC state for a given TX DMAQ */
++      void (*dmaq_tx_q_init) (struct efhw_nic *nic,
++                              uint dmaq, uint evq, uint owner, uint tag,
++                              uint dmaq_size, uint buf_idx, uint flags);
 +
-+static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
-+{
-+      struct xenfb_info *info = p->par;
++      /*! Initialise NIC state for a given RX DMAQ */
++      void (*dmaq_rx_q_init) (struct efhw_nic *nic,
++                              uint dmaq, uint evq, uint owner, uint tag,
++                              uint dmaq_size, uint buf_idx, uint flags);
 +
-+      cfb_copyarea(p, area);
-+      xenfb_refresh(info, area->dx, area->dy, area->width, area->height);
-+}
++      /*! Disable a given TX DMAQ */
++      void (*dmaq_tx_q_disable) (struct efhw_nic *nic, uint dmaq);
 +
-+static void xenfb_vm_open(struct vm_area_struct *vma)
-+{
-+      struct xenfb_mapping *map = vma->vm_private_data;
-+      atomic_inc(&map->map_refs);
-+}
++      /*! Disable a given RX DMAQ */
++      void (*dmaq_rx_q_disable) (struct efhw_nic *nic, uint dmaq);
 +
-+static void xenfb_vm_close(struct vm_area_struct *vma)
-+{
-+      struct xenfb_mapping *map = vma->vm_private_data;
-+      struct xenfb_info *info = map->info;
++      /*! Flush a given TX DMA channel */
++      int (*flush_tx_dma_channel) (struct efhw_nic *nic, uint dmaq);
 +
-+      mutex_lock(&info->mm_lock);
-+      if (atomic_dec_and_test(&map->map_refs)) {
-+              list_del(&map->link);
-+              kfree(map);
-+      }
-+      mutex_unlock(&info->mm_lock);
-+}
++      /*! Flush a given RX DMA channel */
++      int (*flush_rx_dma_channel) (struct efhw_nic *nic, uint dmaq);
 +
-+static struct page *xenfb_vm_nopage(struct vm_area_struct *vma,
-+                                  unsigned long vaddr, int *type)
-+{
-+      struct xenfb_mapping *map = vma->vm_private_data;
-+      struct xenfb_info *info = map->info;
-+      int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT;
-+      unsigned long flags;
-+      struct page *page;
-+      int y1, y2;
++  /*-------------- Buffer table Support ------------ */
 +
-+      if (pgnr >= info->nr_pages)
-+              return NOPAGE_SIGBUS;
++      /*! Initialise a buffer table page */
++      void (*buffer_table_set) (struct efhw_nic *nic,
++                                dma_addr_t dma_addr,
++                                uint bufsz, uint region,
++                                int own_id, int buffer_id);
 +
-+      mutex_lock(&info->mm_lock);
-+      spin_lock_irqsave(&info->dirty_lock, flags);
-+      page = info->pages[pgnr];
-+      get_page(page);
-+      map->faults++;
++      /*! Initialise a block of buffer table pages */
++      void (*buffer_table_set_n) (struct efhw_nic *nic, int buffer_id,
++                                  dma_addr_t dma_addr,
++                                  uint bufsz, uint region,
++                                  int n_pages, int own_id);
 +
-+      y1 = pgnr * PAGE_SIZE / info->fb_info->fix.line_length;
-+      y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fb_info->fix.line_length;
-+      if (y2 > info->fb_info->var.yres)
-+              y2 = info->fb_info->var.yres;
-+      __xenfb_refresh(info, 0, y1, info->fb_info->var.xres, y2 - y1);
-+      spin_unlock_irqrestore(&info->dirty_lock, flags);
-+      mutex_unlock(&info->mm_lock);
++      /*! Clear a block of buffer table pages */
++      void (*buffer_table_clear) (struct efhw_nic *nic, int buffer_id,
++                                  int num);
 +
-+      if (type)
-+              *type = VM_FAULT_MINOR;
++      /*! Commit a buffer table update  */
++      void (*buffer_table_commit) (struct efhw_nic *nic);
 +
-+      return page;
-+}
++};
 +
-+static struct vm_operations_struct xenfb_vm_ops = {
-+      .open   = xenfb_vm_open,
-+      .close  = xenfb_vm_close,
-+      .nopage = xenfb_vm_nopage,
++
++/*----------------------------------------------------------------------------
++ *
++ * NIC type
++ *
++ *---------------------------------------------------------------------------*/
++
++struct efhw_device_type {
++      int  arch;            /* enum efhw_arch */
++      char variant;         /* 'A', 'B', ... */
++      int  revision;        /* 0, 1, ... */
 +};
 +
-+static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma)
-+{
-+      struct xenfb_info *info = fb_info->par;
-+      struct xenfb_mapping *map;
-+      int map_pages;
 +
-+      if (!(vma->vm_flags & VM_WRITE))
-+              return -EINVAL;
-+      if (!(vma->vm_flags & VM_SHARED))
-+              return -EINVAL;
-+      if (vma->vm_pgoff != 0)
-+              return -EINVAL;
++/*----------------------------------------------------------------------------
++ *
++ * EtherFabric NIC instance - nic.c for HW independent functions
++ *
++ *---------------------------------------------------------------------------*/
 +
-+      map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT;
-+      if (map_pages > info->nr_pages)
-+              return -EINVAL;
++/*! */
++struct efhw_nic {
++      /*! zero base index in efrm_nic_table.nic array */
++      volatile int index;
++      int ifindex;            /*!< OS level nic index */
++#ifdef HAS_NET_NAMESPACE
++      struct net *nd_net;
++#endif
 +
-+      map = kzalloc(sizeof(*map), GFP_KERNEL);
-+      if (map == NULL)
-+              return -ENOMEM;
++      struct efhw_device_type devtype;
 +
-+      map->vma = vma;
-+      map->faults = 0;
-+      map->info = info;
-+      atomic_set(&map->map_refs, 1);
++      /*! Options that can be set by user. */
++      unsigned options;
++# define NIC_OPT_EFTEST             0x1       /* owner is an eftest app */
 +
-+      mutex_lock(&info->mm_lock);
-+      list_add(&map->link, &info->mappings);
-+      mutex_unlock(&info->mm_lock);
++# define NIC_OPT_DEFAULT            0
 +
-+      vma->vm_ops = &xenfb_vm_ops;
-+      vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED);
-+      vma->vm_private_data = map;
++      /*! Internal flags that indicate hardware properties at runtime. */
++      unsigned flags;
++# define NIC_FLAG_NO_INTERRUPT          0x01 /* to be set at init time only */
++# define NIC_FLAG_TRY_MSI               0x02
++# define NIC_FLAG_MSI                   0x04
++# define NIC_FLAG_OS_IRQ_EN             0x08
++# define NIC_FLAG_10G                   0x10
 +
-+      return 0;
-+}
++      unsigned mtu;           /*!< MAC MTU (includes MAC hdr) */
 +
-+static struct fb_ops xenfb_fb_ops = {
-+      .owner          = THIS_MODULE,
-+      .fb_setcolreg   = xenfb_setcolreg,
-+      .fb_fillrect    = xenfb_fillrect,
-+      .fb_copyarea    = xenfb_copyarea,
-+      .fb_imageblit   = xenfb_imageblit,
-+      .fb_mmap        = xenfb_mmap,
-+};
++      /* hardware resources */
 +
-+static irqreturn_t xenfb_event_handler(int rq, void *dev_id,
-+                                     struct pt_regs *regs)
-+{
-+      /*
-+       * No in events recognized, simply ignore them all.
-+       * If you need to recognize some, see xenbkd's input_handler()
-+       * for how to do that.
-+       */
-+      struct xenfb_info *info = dev_id;
-+      struct xenfb_page *page = info->page;
++      /*! I/O address of the start of the bar */
++      efhw_ioaddr_t bar_ioaddr;
 +
-+      if (page->in_cons != page->in_prod) {
-+              info->page->in_cons = info->page->in_prod;
-+              notify_remote_via_irq(info->irq);
-+      }
-+      return IRQ_HANDLED;
-+}
++      /*! Bar number of control aperture. */
++      unsigned ctr_ap_bar;
++      /*! Length of control aperture in bytes. */
++      unsigned ctr_ap_bytes;
 +
-+static unsigned long vmalloc_to_mfn(void *address)
-+{
-+      return pfn_to_mfn(vmalloc_to_pfn(address));
-+}
++      uint8_t mac_addr[ETH_ALEN];     /*!< mac address  */
 +
-+static int __devinit xenfb_probe(struct xenbus_device *dev,
-+                               const struct xenbus_device_id *id)
-+{
-+      struct xenfb_info *info;
-+      struct fb_info *fb_info;
-+      int ret;
++      /*! EtherFabric Functional Units -- functions */
++      const struct efhw_func_ops *efhw_func;
 +
-+      info = kzalloc(sizeof(*info), GFP_KERNEL);
-+      if (info == NULL) {
-+              xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
-+              return -ENOMEM;
-+      }
-+      dev->dev.driver_data = info;
-+      info->xbdev = dev;
-+      info->irq = -1;
-+      info->x1 = info->y1 = INT_MAX;
-+      spin_lock_init(&info->dirty_lock);
-+      mutex_init(&info->mm_lock);
-+      init_waitqueue_head(&info->wq);
-+      init_timer(&info->refresh);
-+      info->refresh.function = xenfb_timer;
-+      info->refresh.data = (unsigned long)info;
-+      INIT_LIST_HEAD(&info->mappings);
++      /* Value read from FPGA version register.  Zero for asic. */
++      unsigned fpga_version;
 +
-+      info->fb = vmalloc(xenfb_mem_len);
-+      if (info->fb == NULL)
-+              goto error_nomem;
-+      memset(info->fb, 0, xenfb_mem_len);
++      /*! This lock protects a number of misc NIC resources.  It should
++       * only be used for things that can be at the bottom of the lock
++       * order.  ie. You mustn't attempt to grab any other lock while
++       * holding this one.
++       */
++      spinlock_t *reg_lock;
++      spinlock_t the_reg_lock;
 +
-+      info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
++      int buf_commit_outstanding;     /*!< outstanding buffer commits */
 +
-+      info->pages = kmalloc(sizeof(struct page *) * info->nr_pages,
-+                            GFP_KERNEL);
-+      if (info->pages == NULL)
-+              goto error_nomem;
++      /*! interrupt callbacks (hard-irq) */
++      void (*irq_handler) (struct efhw_nic *, int unit);
 +
-+      info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
-+      if (!info->mfns)
-+              goto error_nomem;
++      /*! event queues per driver */
++      struct efhw_keventq evq[EFHW_KEVENTQ_MAX];
 +
-+      /* set up shared page */
-+      info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
-+      if (!info->page)
-+              goto error_nomem;
++/* for marking when we are not using an IRQ unit
++      - 0 is a valid offset to an IRQ unit on EF1! */
++#define EFHW_IRQ_UNIT_UNUSED  0xffff
++      /*! interrupt unit in use  */
++      unsigned int irq_unit[EFHW_KEVENTQ_MAX];
++      efhw_iopage_t irq_iobuff;       /*!<  Falcon SYSERR interrupt */
 +
-+      xenfb_init_shared_page(info);
++      /* The new driverlink infrastructure. */
++      struct efx_dl_device *net_driver_dev;
++      struct efx_dlfilt_cb_s *dlfilter_cb;
 +
-+      fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
-+                              /* see fishy hackery below */
-+      if (fb_info == NULL)
-+              goto error_nomem;
++      /*! Bit masks of the sizes of event queues and dma queues supported
++       * by the nic. */
++      unsigned evq_sizes;
++      unsigned rxq_sizes;
++      unsigned txq_sizes;
 +
-+      /* FIXME fishy hackery */
-+      fb_info->pseudo_palette = fb_info->par;
-+      fb_info->par = info;
-+      /* /FIXME */
-+      fb_info->screen_base = info->fb;
++      /* Size of filter table (including odd and even banks). */
++      unsigned filter_tbl_size;
++};
 +
-+      fb_info->fbops = &xenfb_fb_ops;
-+      fb_info->var.xres_virtual = fb_info->var.xres = info->page->width;
-+      fb_info->var.yres_virtual = fb_info->var.yres = info->page->height;
-+      fb_info->var.bits_per_pixel = info->page->depth;
 +
-+      fb_info->var.red = (struct fb_bitfield){16, 8, 0};
-+      fb_info->var.green = (struct fb_bitfield){8, 8, 0};
-+      fb_info->var.blue = (struct fb_bitfield){0, 8, 0};
++#define EFHW_KVA(nic)       ((nic)->bar_ioaddr)
 +
-+      fb_info->var.activate = FB_ACTIVATE_NOW;
-+      fb_info->var.height = -1;
-+      fb_info->var.width = -1;
-+      fb_info->var.vmode = FB_VMODE_NONINTERLACED;
 +
-+      fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
-+      fb_info->fix.line_length = info->page->line_length;
-+      fb_info->fix.smem_start = 0;
-+      fb_info->fix.smem_len = xenfb_mem_len;
-+      strcpy(fb_info->fix.id, "xen");
-+      fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
-+      fb_info->fix.accel = FB_ACCEL_NONE;
++#endif /* __CI_EFHW_EFHW_TYPES_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/eventq.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/eventq.h  2008-05-19 00:33:29.369839038 +0300
+@@ -0,0 +1,73 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains API provided by efhw/eventq.c file.  This file is not
++ * designed for use outside of the SFC resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFHW_EVENTQ_H__
++#define __CI_EFHW_EVENTQ_H__
++
++#include <ci/efhw/efhw_types.h>
++#include <ci/efhw/eventq_macros.h>
++
++/*! Poll the event queue. */
++extern int efhw_keventq_poll(struct efhw_nic *, struct efhw_keventq *);
++
++/*! Callbacks for handling events. */
++struct efhw_ev_handler {
++      void (*wakeup_fn)(struct efhw_nic *nic, efhw_event_t *ev);
++      void (*timeout_fn)(struct efhw_nic *nic, efhw_event_t *ev);
++      void (*sw_fn)(struct efhw_nic *nic, efhw_event_t *ev);
++      void (*dmaq_flushed_fn) (struct efhw_nic *, int, int);
++};
++
++extern int efhw_keventq_ctor(struct efhw_nic *, int instance,
++                           struct efhw_keventq *, struct efhw_ev_handler *);
++extern void efhw_keventq_dtor(struct efhw_nic *, struct efhw_keventq *);
++
++extern void efhw_handle_txdmaq_flushed(struct efhw_nic *,
++                                     struct efhw_ev_handler *,
++                                     efhw_event_t *);
++extern void efhw_handle_rxdmaq_flushed(struct efhw_nic *,
++                                     struct efhw_ev_handler *,
++                                     efhw_event_t *);
++extern void efhw_handle_wakeup_event(struct efhw_nic *,
++                                   struct efhw_ev_handler *,
++                                   efhw_event_t *);
++extern void efhw_handle_timeout_event(struct efhw_nic *,
++                                    struct efhw_ev_handler *,
++                                    efhw_event_t *);
++
++#endif /* __CI_EFHW_EVENTQ_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/eventq_macros.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/eventq_macros.h   2008-05-19 00:33:29.369839038 +0300
+@@ -0,0 +1,81 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides some event-related macros.  This file is designed for
++ * use from kernel and from the userland contexts.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      fb_info->flags = FBINFO_FLAG_DEFAULT;
++#ifndef __CI_EFHW_EVENTQ_MACROS_H__
++#define __CI_EFHW_EVENTQ_MACROS_H__
 +
-+      ret = fb_alloc_cmap(&fb_info->cmap, 256, 0);
-+      if (ret < 0) {
-+              framebuffer_release(fb_info);
-+              xenbus_dev_fatal(dev, ret, "fb_alloc_cmap");
-+              goto error;
-+      }
++#include <ci/efhw/common.h>
 +
-+      ret = register_framebuffer(fb_info);
-+      if (ret) {
-+              fb_dealloc_cmap(&info->fb_info->cmap);
-+              framebuffer_release(fb_info);
-+              xenbus_dev_fatal(dev, ret, "register_framebuffer");
-+              goto error;
-+      }
-+      info->fb_info = fb_info;
++/*--------------------------------------------------------------------
++ *
++ * Event Queue manipulation
++ *
++ *--------------------------------------------------------------------*/
 +
-+      /* FIXME should this be delayed until backend XenbusStateConnected? */
-+      info->kthread = kthread_run(xenfb_thread, info, "xenfb thread");
-+      if (IS_ERR(info->kthread)) {
-+              ret = PTR_ERR(info->kthread);
-+              info->kthread = NULL;
-+              xenbus_dev_fatal(dev, ret, "register_framebuffer");
-+              goto error;
-+      }
++#define EFHW_EVENT_OFFSET(q, s, i)                                    \
++      (((s)->evq_ptr - (i) * (int32_t)sizeof(efhw_event_t))           \
++       & (q)->evq_mask)
 +
-+      ret = xenfb_connect_backend(dev, info);
-+      if (ret < 0)
-+              goto error;
++#define EFHW_EVENT_PTR(q, s, i)                                               \
++      ((efhw_event_t *)((q)->evq_base + EFHW_EVENT_OFFSET(q, s, i)))
 +
-+      return 0;
++#define EFHW_EVENTQ_NEXT(s)                                           \
++      do { ((s)->evq_ptr += sizeof(efhw_event_t)); } while (0)
 +
-+ error_nomem:
-+      ret = -ENOMEM;
-+      xenbus_dev_fatal(dev, ret, "allocating device memory");
-+ error:
-+      xenfb_remove(dev);
-+      return ret;
-+}
++#define EFHW_EVENTQ_PREV(s)                                           \
++      do { ((s)->evq_ptr -= sizeof(efhw_event_t)); } while (0)
 +
-+static int xenfb_resume(struct xenbus_device *dev)
-+{
-+      struct xenfb_info *info = dev->dev.driver_data;
++/* Be worried about this on byteswapped machines */
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++  /* Due to crazy chipsets, we see the event words being written in
++   ** arbitrary order (bug4539).  So test for presence of event must ensure
++   ** that both halves have changed from the null.
++   */
++      #define EFHW_IS_EVENT(evp)                      \
++              (((evp)->opaque.a != (uint32_t)-1) &&   \
++               ((evp)->opaque.b != (uint32_t)-1))
++      #define EFHW_CLEAR_EVENT(evp)       ((evp)->u64 = (uint64_t)-1)
++      #define EFHW_CLEAR_EVENT_VALUE      0xff
++#else
++      #error Fixme - unknown hardware configuration
++#endif
 +
-+      xenfb_disconnect_backend(info);
-+      xenfb_init_shared_page(info);
-+      return xenfb_connect_backend(dev, info);
-+}
++#define EFHW_EVENT_OVERFLOW(evq, s)                   \
++      (EFHW_IS_EVENT(EFHW_EVENT_PTR(evq, s, 1)))
 +
-+static int xenfb_remove(struct xenbus_device *dev)
-+{
-+      struct xenfb_info *info = dev->dev.driver_data;
++#endif /* __CI_EFHW_EVENTQ_MACROS_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/falcon.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/falcon.h  2008-05-19 00:33:29.369839038 +0300
+@@ -0,0 +1,93 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains API provided by efhw/falcon.c file.  This file is not
++ * designed for use outside of the SFC resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      del_timer(&info->refresh);
-+      if (info->kthread)
-+              kthread_stop(info->kthread);
-+      xenfb_disconnect_backend(info);
-+      if (info->fb_info) {
-+              unregister_framebuffer(info->fb_info);
-+              fb_dealloc_cmap(&info->fb_info->cmap);
-+              framebuffer_release(info->fb_info);
-+      }
-+      free_page((unsigned long)info->page);
-+      vfree(info->mfns);
-+      kfree(info->pages);
-+      vfree(info->fb);
-+      kfree(info);
++#ifndef __CI_EFHW_FALCON_H__
++#define __CI_EFHW_FALCON_H__
 +
-+      return 0;
-+}
++#include <ci/efhw/efhw_types.h>
++#include <ci/efhw/common.h>
 +
-+static void xenfb_init_shared_page(struct xenfb_info *info)
-+{
-+      int i;
++/*----------------------------------------------------------------------------
++ *
++ * Locks - unfortunately required
++ *
++ *---------------------------------------------------------------------------*/
 +
-+      for (i = 0; i < info->nr_pages; i++)
-+              info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE);
++#define FALCON_LOCK_DECL        irq_flags_t lock_state
++#define FALCON_LOCK_LOCK(nic) \
++      spin_lock_irqsave((nic)->reg_lock, lock_state)
++#define FALCON_LOCK_UNLOCK(nic) \
++      spin_unlock_irqrestore((nic)->reg_lock, lock_state)
 +
-+      for (i = 0; i < info->nr_pages; i++)
-+              info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
++extern struct efhw_func_ops falcon_char_functional_units;
 +
-+      info->page->pd[0] = vmalloc_to_mfn(info->mfns);
-+      info->page->pd[1] = 0;
-+      info->page->width = XENFB_WIDTH;
-+      info->page->height = XENFB_HEIGHT;
-+      info->page->depth = XENFB_DEPTH;
-+      info->page->line_length = (info->page->depth / 8) * info->page->width;
-+      info->page->mem_length = xenfb_mem_len;
-+      info->page->in_cons = info->page->in_prod = 0;
-+      info->page->out_cons = info->page->out_prod = 0;
-+}
++/*! specify a pace value for a TX DMA Queue */
++extern void falcon_nic_pace(struct efhw_nic *nic, uint dmaq, uint pace);
 +
-+static int xenfb_connect_backend(struct xenbus_device *dev,
-+                               struct xenfb_info *info)
-+{
-+      int ret;
-+      struct xenbus_transaction xbt;
++/*! confirm buffer table updates - should be used for items where
++   loss of data would be unacceptable. E.g for the buffers that back
++   an event or DMA queue */
++extern void falcon_nic_buffer_table_confirm(struct efhw_nic *nic);
 +
-+      ret = bind_listening_port_to_irqhandler(
-+              dev->otherend_id, xenfb_event_handler, 0, "xenfb", info);
-+      if (ret < 0) {
-+              xenbus_dev_fatal(dev, ret,
-+                               "bind_listening_port_to_irqhandler");
-+              return ret;
-+      }
-+      info->irq = ret;
++/*! Reset the all the TX DMA queue pointers. */
++extern void falcon_clobber_tx_dma_ptrs(struct efhw_nic *nic, uint dmaq);
 +
-+ again:
-+      ret = xenbus_transaction_start(&xbt);
-+      if (ret) {
-+              xenbus_dev_fatal(dev, ret, "starting transaction");
-+              return ret;
-+      }
-+      ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
-+                          virt_to_mfn(info->page));
-+      if (ret)
-+              goto error_xenbus;
-+      ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
-+                          irq_to_evtchn_port(info->irq));
-+      if (ret)
-+              goto error_xenbus;
-+      ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s",
-+                          XEN_IO_PROTO_ABI_NATIVE);
-+      if (ret)
-+              goto error_xenbus;
-+      ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1");
-+      if (ret)
-+              goto error_xenbus;
-+      ret = xenbus_transaction_end(xbt, 0);
-+      if (ret) {
-+              if (ret == -EAGAIN)
-+                      goto again;
-+              xenbus_dev_fatal(dev, ret, "completing transaction");
-+              return ret;
-+      }
++extern int
++falcon_handle_char_event(struct efhw_nic *nic,
++                       struct efhw_ev_handler *h, efhw_event_t *evp);
 +
-+      xenbus_switch_state(dev, XenbusStateInitialised);
-+      return 0;
++/*! map event queue instance space (0,1,2,..) onto event queue
++  number. This function takes into account the allocation rules for
++  the underlying driver model */
++extern int falcon_idx_to_evq(struct efhw_nic *nic, uint idx);
 +
-+ error_xenbus:
-+      xenbus_transaction_end(xbt, 1);
-+      xenbus_dev_fatal(dev, ret, "writing xenstore");
-+      return ret;
-+}
++/*! Acknowledge to HW that processing is complete on a given event queue */
++extern void falcon_nic_evq_ack(struct efhw_nic *nic, uint evq,        /* evq id */
++                             uint rptr,       /* new read pointer update */
++                             bool wakeup      /* request a wakeup event if
++                                                 ptr's != */
++    );
 +
-+static void xenfb_disconnect_backend(struct xenfb_info *info)
-+{
-+      if (info->irq >= 0)
-+              unbind_from_irqhandler(info->irq, info);
-+      info->irq = -1;
-+}
++extern void
++falcon_nic_buffer_table_set_n(struct efhw_nic *nic, int buffer_id,
++                            dma_addr_t dma_addr, uint bufsz, uint region,
++                            int n_pages, int own_id);
 +
-+static void xenfb_backend_changed(struct xenbus_device *dev,
-+                                enum xenbus_state backend_state)
-+{
-+      struct xenfb_info *info = dev->dev.driver_data;
-+      int val;
++extern void falcon_nic_ipfilter_ctor(struct efhw_nic *nic);
 +
-+      switch (backend_state) {
-+      case XenbusStateInitialising:
-+      case XenbusStateInitialised:
-+      case XenbusStateUnknown:
-+      case XenbusStateClosed:
-+              break;
++#endif /* __CI_EFHW_FALCON_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/falcon_hash.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/falcon_hash.h     2008-05-19 00:33:29.369839038 +0300
+@@ -0,0 +1,58 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains API provided by efhw/falcon_hash.c file.
++ * Function declared in this file are not exported from the Linux
++ * sfc_resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      case XenbusStateInitWait:
-+      InitWait:
-+              xenbus_switch_state(dev, XenbusStateConnected);
-+              break;
++#ifndef __CI_EFHW_FALCON_HASH_H__
++#define __CI_EFHW_FALCON_HASH_H__
 +
-+      case XenbusStateConnected:
-+              /*
-+               * Work around xenbus race condition: If backend goes
-+               * through InitWait to Connected fast enough, we can
-+               * get Connected twice here.
-+               */
-+              if (dev->state != XenbusStateConnected)
-+                      goto InitWait; /* no InitWait seen yet, fudge it */
++/* All LE parameters */
++extern unsigned int
++falcon_hash_get_key(unsigned int src_ip, unsigned int src_port,
++                  unsigned int dest_ip, unsigned int dest_port,
++                  int tcp, int full);
 +
-+              if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
-+                               "request-update", "%d", &val) < 0)
-+                      val = 0;
-+              if (val)
-+                      info->update_wanted = 1;
-+              break;
++unsigned int falcon_hash_function1(unsigned int key, unsigned int nfilters);
 +
-+      case XenbusStateClosing:
-+              // FIXME is this safe in any dev->state?
-+              xenbus_frontend_closed(dev);
-+              break;
-+      }
-+}
++extern unsigned int
++falcon_hash_function2(unsigned int key, unsigned int nfitlers);
 +
-+static struct xenbus_device_id xenfb_ids[] = {
-+      { "vfb" },
-+      { "" }
-+};
-+MODULE_ALIAS("xen:vfb");
++extern unsigned int
++falcon_hash_iterator(unsigned int hash1, unsigned int hash2,
++                   unsigned int n_search, unsigned int nfilters);
 +
-+static struct xenbus_driver xenfb = {
-+      .name = "vfb",
-+      .owner = THIS_MODULE,
-+      .ids = xenfb_ids,
-+      .probe = xenfb_probe,
-+      .remove = xenfb_remove,
-+      .resume = xenfb_resume,
-+      .otherend_changed = xenfb_backend_changed,
-+};
++#endif /* __CI_EFHW_FALCON_HASH_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/hardware_sysdep.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/hardware_sysdep.h 2008-05-19 00:33:29.369839038 +0300
+@@ -0,0 +1,84 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides version-independent Linux kernel API for header files
++ * with hardware-related definitions (in ci/driver/efab/hardware*).
++ * Only kernels >=2.6.9 are supported.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static int __init xenfb_init(void)
-+{
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++#ifndef __CI_EFHW_HARDWARE_LINUX_H__
++#define __CI_EFHW_HARDWARE_LINUX_H__
 +
-+      /* Nothing to do if running in dom0. */
-+      if (is_initial_xendomain())
-+              return -ENODEV;
++#include <asm/io.h>
 +
-+      return xenbus_register_frontend(&xenfb);
-+}
++#ifdef __LITTLE_ENDIAN
++#define EFHW_IS_LITTLE_ENDIAN
++#elif __BIG_ENDIAN
++#define EFHW_IS_BIG_ENDIAN
++#else
++#error Unknown endianness
++#endif
++
++#ifndef mmiowb
++      #if defined(__i386__) || defined(__x86_64__)
++              #define mmiowb()
++      #elif defined(__ia64__)
++              #ifndef ia64_mfa
++                      #define ia64_mfa() asm volatile ("mf.a" ::: "memory")
++              #endif
++      #define mmiowb ia64_mfa
++      #else
++      #error "Need definition for mmiowb()"
++      #endif
++#endif
 +
-+static void __exit xenfb_cleanup(void)
++typedef char *efhw_ioaddr_t;
++
++#ifndef readq
++static inline uint64_t __readq(void __iomem *addr)
 +{
-+      return xenbus_unregister_driver(&xenfb);
++      return *(volatile uint64_t *)addr;
 +}
++#define readq(x) __readq(x)
++#endif
 +
-+module_init(xenfb_init);
-+module_exit(xenfb_cleanup);
++#ifndef writeq
++static inline void __writeq(uint64_t v, void __iomem *addr)
++{
++      *(volatile uint64_t *)addr = v;
++}
++#define writeq(val, addr) __writeq((val), (addr))
++#endif
 +
-+MODULE_LICENSE("GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/fbfront/xenkbd.c linux-2.6.18-xen.hg/drivers/xen/fbfront/xenkbd.c
---- linux-2.6.18/drivers/xen/fbfront/xenkbd.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/fbfront/xenkbd.c   2007-12-23 11:15:33.871259312 +0100
-@@ -0,0 +1,344 @@
-+/*
-+ * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device
++#endif /* __CI_EFHW_HARDWARE_LINUX_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/iopage.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/iopage.h  2008-05-19 00:33:29.369839038 +0300
+@@ -0,0 +1,58 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
 + *
-+ * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
-+ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
++ * This file contains OS-independent API for allocating iopage types.
++ * The implementation of these functions is highly OS-dependent.
++ * This file is not designed for use outside of the SFC resource driver.
 + *
-+ *  Based on linux/drivers/input/mouse/sermouse.c
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
 + *
-+ *  This file is subject to the terms and conditions of the GNU General Public
-+ *  License. See the file COPYING in the main directory of this archive for
-+ *  more details.
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+/*
-+ * TODO:
++#ifndef __CI_DRIVER_RESOURCE_IOPAGE_H__
++#define __CI_DRIVER_RESOURCE_IOPAGE_H__
++
++#include <ci/efhw/efhw_types.h>
++
++/*--------------------------------------------------------------------
 + *
-+ * Switch to grant tables together with xenfb.c.
++ * memory allocation
++ *
++ *--------------------------------------------------------------------*/
++
++extern int efhw_iopage_alloc(struct efhw_nic *, efhw_iopage_t *p);
++extern void efhw_iopage_free(struct efhw_nic *, efhw_iopage_t *p);
++
++extern int efhw_iopages_alloc(struct efhw_nic *, efhw_iopages_t *p,
++                            unsigned order);
++extern void efhw_iopages_free(struct efhw_nic *, efhw_iopages_t *p);
++
++#endif /* __CI_DRIVER_RESOURCE_IOPAGE_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/iopage_types.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/iopage_types.h    2008-05-19 00:33:29.373839269 +0300
+@@ -0,0 +1,188 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides efhw_page_t and efhw_iopage_t for Linux kernel.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <linux/kernel.h>
-+#include <linux/errno.h>
-+#include <linux/module.h>
-+#include <linux/input.h>
-+#include <asm/hypervisor.h>
-+#include <xen/evtchn.h>
-+#include <xen/interface/io/fbif.h>
-+#include <xen/interface/io/kbdif.h>
-+#include <xen/xenbus.h>
++#ifndef __CI_EFHW_IOPAGE_LINUX_H__
++#define __CI_EFHW_IOPAGE_LINUX_H__
 +
-+struct xenkbd_info
-+{
-+      struct input_dev *kbd;
-+      struct input_dev *ptr;
-+      struct xenkbd_page *page;
-+      int irq;
-+      struct xenbus_device *xbdev;
-+      char phys[32];
-+};
++#include <linux/gfp.h>
++#include <linux/hardirq.h>
++#include <ci/efhw/debug.h>
 +
-+static int xenkbd_remove(struct xenbus_device *);
-+static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
-+static void xenkbd_disconnect_backend(struct xenkbd_info *);
++/*--------------------------------------------------------------------
++ *
++ * efhw_page_t: A single page of memory.  Directly mapped in the driver,
++ * and can be mapped to userlevel.
++ *
++ *--------------------------------------------------------------------*/
 +
-+/*
-+ * Note: if you need to send out events, see xenfb_do_update() for how
-+ * to do that.
-+ */
++typedef struct {
++      unsigned long kva;
++} efhw_page_t;
 +
-+static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs)
++static inline int efhw_page_alloc(efhw_page_t *p)
 +{
-+      struct xenkbd_info *info = dev_id;
-+      struct xenkbd_page *page = info->page;
-+      __u32 cons, prod;
++      p->kva = __get_free_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL);
++      return p->kva ? 0 : -ENOMEM;
++}
 +
-+      prod = page->in_prod;
-+      if (prod == page->out_cons)
-+              return IRQ_HANDLED;
-+      rmb();                  /* ensure we see ring contents up to prod */
-+      for (cons = page->in_cons; cons != prod; cons++) {
-+              union xenkbd_in_event *event;
-+              struct input_dev *dev;
-+              event = &XENKBD_IN_RING_REF(page, cons);
++static inline int efhw_page_alloc_zeroed(efhw_page_t *p)
++{
++      p->kva = get_zeroed_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL);
++      return p->kva ? 0 : -ENOMEM;
++}
 +
-+              dev = info->ptr;
-+              switch (event->type) {
-+              case XENKBD_TYPE_MOTION:
-+                      if ( event->motion.rel_z == 1 || event->motion.rel_z == -1 ) {
-+                              input_report_rel(dev, REL_WHEEL, 0 - event->motion.rel_z);
-+                      }           
-+                      else {
-+                              input_report_rel(dev, REL_X, event->motion.rel_x);
-+                              input_report_rel(dev, REL_Y, event->motion.rel_y);
-+                      }
-+                      break;
-+              case XENKBD_TYPE_KEY:
-+                      dev = NULL;
-+                      if (test_bit(event->key.keycode, info->kbd->keybit))
-+                              dev = info->kbd;
-+                      if (test_bit(event->key.keycode, info->ptr->keybit))
-+                              dev = info->ptr;
-+                      if (dev)
-+                              input_report_key(dev, event->key.keycode,
-+                                               event->key.pressed);
-+                      else
-+                              printk("xenkbd: unhandled keycode 0x%x\n",
-+                                     event->key.keycode);
-+                      break;
-+              case XENKBD_TYPE_POS:
-+                      if ( event->pos.abs_z == 1 || event->pos.abs_z == -1 ) {
-+                              input_report_rel(dev, REL_WHEEL, 0 - event->pos.abs_z);
-+                      }
-+                      else {
-+                              input_report_abs(dev, ABS_X, event->pos.abs_x);
-+                              input_report_abs(dev, ABS_Y, event->pos.abs_y);
-+                      }
-+                      break;
-+              }
-+              if (dev)
-+                      input_sync(dev);
-+      }
-+      mb();                   /* ensure we got ring contents */
-+      page->in_cons = cons;
-+      notify_remote_via_irq(info->irq);
++static inline void efhw_page_free(efhw_page_t *p)
++{
++      free_page(p->kva);
++      EFHW_DO_DEBUG(memset(p, 0, sizeof(*p)));
++}
 +
-+      return IRQ_HANDLED;
++static inline char *efhw_page_ptr(efhw_page_t *p)
++{
++      return (char *)p->kva;
 +}
 +
-+int __devinit xenkbd_probe(struct xenbus_device *dev,
-+                         const struct xenbus_device_id *id)
++static inline unsigned efhw_page_pfn(efhw_page_t *p)
 +{
-+      int ret, i;
-+      struct xenkbd_info *info;
-+      struct input_dev *kbd, *ptr;
++      return (unsigned)(__pa(p->kva) >> PAGE_SHIFT);
++}
 +
-+      info = kzalloc(sizeof(*info), GFP_KERNEL);
-+      if (!info) {
-+              xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
-+              return -ENOMEM;
-+      }
-+      dev->dev.driver_data = info;
-+      info->xbdev = dev;
-+      snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
++static inline void efhw_page_mark_invalid(efhw_page_t *p)
++{
++      p->kva = 0;
++}
 +
-+      info->page = (void *)__get_free_page(GFP_KERNEL);
-+      if (!info->page)
-+              goto error_nomem;
-+      info->page->in_cons = info->page->in_prod = 0;
-+      info->page->out_cons = info->page->out_prod = 0;
++static inline int efhw_page_is_valid(efhw_page_t *p)
++{
++      return p->kva != 0;
++}
 +
-+      /* keyboard */
-+      kbd = input_allocate_device();
-+      if (!kbd)
-+              goto error_nomem;
-+      kbd->name = "Xen Virtual Keyboard";
-+      kbd->phys = info->phys;
-+      kbd->id.bustype = BUS_PCI;
-+      kbd->id.vendor = 0x5853;
-+      kbd->id.product = 0xffff;
-+      kbd->evbit[0] = BIT(EV_KEY);
-+      for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
-+              set_bit(i, kbd->keybit);
-+      for (i = KEY_OK; i < KEY_MAX; i++)
-+              set_bit(i, kbd->keybit);
++static inline void efhw_page_init_from_va(efhw_page_t *p, void *va)
++{
++      p->kva = (unsigned long)va;
++}
 +
-+      ret = input_register_device(kbd);
-+      if (ret) {
-+              input_free_device(kbd);
-+              xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
-+              goto error;
-+      }
-+      info->kbd = kbd;
++/*--------------------------------------------------------------------
++ *
++ * efhw_iopage_t: A single page of memory.  Directly mapped in the driver,
++ * and can be mapped to userlevel.  Can also be accessed by the NIC.
++ *
++ *--------------------------------------------------------------------*/
 +
-+      /* pointing device */
-+      ptr = input_allocate_device();
-+      if (!ptr)
-+              goto error_nomem;
-+      ptr->name = "Xen Virtual Pointer";
-+      ptr->phys = info->phys;
-+      ptr->id.bustype = BUS_PCI;
-+      ptr->id.vendor = 0x5853;
-+      ptr->id.product = 0xfffe;
-+      ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
-+      for (i = BTN_LEFT; i <= BTN_TASK; i++)
-+              set_bit(i, ptr->keybit);
-+      ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
-+      input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0);
-+      input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
++typedef struct {
++      efhw_page_t p;
++      dma_addr_t dma_addr;
++} efhw_iopage_t;
 +
-+      ret = input_register_device(ptr);
-+      if (ret) {
-+              input_free_device(ptr);
-+              xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
-+              goto error;
-+      }
-+      info->ptr = ptr;
++static inline dma_addr_t efhw_iopage_dma_addr(efhw_iopage_t *p)
++{
++      return p->dma_addr;
++}
 +
-+      ret = xenkbd_connect_backend(dev, info);
-+      if (ret < 0)
-+              goto error;
++#define efhw_iopage_ptr(iop)          efhw_page_ptr(&(iop)->p)
++#define efhw_iopage_pfn(iop)          efhw_page_pfn(&(iop)->p)
++#define efhw_iopage_mark_invalid(iop) efhw_page_mark_invalid(&(iop)->p)
++#define efhw_iopage_is_valid(iop)     efhw_page_is_valid(&(iop)->p)
 +
-+      return 0;
++/*--------------------------------------------------------------------
++ *
++ * efhw_iopages_t: A set of pages that are contiguous in physical memory.
++ * Directly mapped in the driver, and can be mapped to userlevel.  Can also
++ * be accessed by the NIC.
++ *
++ * NB. The O/S may be unwilling to allocate many, or even any of these.  So
++ * only use this type where the NIC really needs a physically contiguous
++ * buffer.
++ *
++ *--------------------------------------------------------------------*/
 +
-+ error_nomem:
-+      ret = -ENOMEM;
-+      xenbus_dev_fatal(dev, ret, "allocating device memory");
-+ error:
-+      xenkbd_remove(dev);
-+      return ret;
++typedef struct {
++      caddr_t kva;
++      unsigned order;
++      dma_addr_t dma_addr;
++} efhw_iopages_t;
++
++static inline caddr_t efhw_iopages_ptr(efhw_iopages_t *p)
++{
++      return p->kva;
 +}
 +
-+static int xenkbd_resume(struct xenbus_device *dev)
++static inline unsigned efhw_iopages_pfn(efhw_iopages_t *p)
 +{
-+      struct xenkbd_info *info = dev->dev.driver_data;
++      return (unsigned)(__pa(p->kva) >> PAGE_SHIFT);
++}
 +
-+      xenkbd_disconnect_backend(info);
-+      return xenkbd_connect_backend(dev, info);
++static inline dma_addr_t efhw_iopages_dma_addr(efhw_iopages_t *p)
++{
++      return p->dma_addr;
 +}
 +
-+static int xenkbd_remove(struct xenbus_device *dev)
++static inline unsigned efhw_iopages_size(efhw_iopages_t *p)
 +{
-+      struct xenkbd_info *info = dev->dev.driver_data;
++      return 1u << (p->order + PAGE_SHIFT);
++}
 +
-+      xenkbd_disconnect_backend(info);
-+      input_unregister_device(info->kbd);
-+      input_unregister_device(info->ptr);
-+      free_page((unsigned long)info->page);
-+      kfree(info);
-+      return 0;
++/* efhw_iopage_t <-> efhw_iopages_t conversions for handling physically
++ * contiguous allocations in iobufsets for iSCSI.  This allows the
++ * essential information about contiguous allocations from
++ * efhw_iopages_alloc() to be saved away in the efhw_iopage_t array in an
++ * iobufset.  (Changing the iobufset resource to use a union type would
++ * involve a lot of code changes, and make the iobufset's metadata larger
++ * which could be bad as it's supposed to fit into a single page on some
++ * platforms.)
++ */
++static inline void
++efhw_iopage_init_from_iopages(efhw_iopage_t *iopage,
++                          efhw_iopages_t *iopages, unsigned pageno)
++{
++      iopage->p.kva = ((unsigned long)efhw_iopages_ptr(iopages))
++          + (pageno * PAGE_SIZE);
++      iopage->dma_addr = efhw_iopages_dma_addr(iopages) +
++          (pageno * PAGE_SIZE);
 +}
 +
-+static int xenkbd_connect_backend(struct xenbus_device *dev,
-+                                struct xenkbd_info *info)
++static inline void
++efhw_iopages_init_from_iopage(efhw_iopages_t *iopages,
++                          efhw_iopage_t *iopage, unsigned order)
 +{
-+      int ret;
-+      struct xenbus_transaction xbt;
++      iopages->kva = (caddr_t) efhw_iopage_ptr(iopage);
++      EFHW_ASSERT(iopages->kva);
++      iopages->order = order;
++      iopages->dma_addr = efhw_iopage_dma_addr(iopage);
++}
 +
-+      ret = bind_listening_port_to_irqhandler(
-+              dev->otherend_id, input_handler, 0, "xenkbd", info);
-+      if (ret < 0) {
-+              xenbus_dev_fatal(dev, ret,
-+                               "bind_listening_port_to_irqhandler");
-+              return ret;
-+      }
-+      info->irq = ret;
++#endif /* __CI_EFHW_IOPAGE_LINUX_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/nic.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/nic.h     2008-05-19 00:33:29.373839269 +0300
+@@ -0,0 +1,62 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains API provided by efhw/nic.c file.  This file is not
++ * designed for use outside of the SFC resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+ again:
-+      ret = xenbus_transaction_start(&xbt);
-+      if (ret) {
-+              xenbus_dev_fatal(dev, ret, "starting transaction");
++#ifndef __CI_EFHW_NIC_H__
++#define __CI_EFHW_NIC_H__
++
++#include <ci/efhw/efhw_types.h>
++#include <ci/efhw/public.h>
++
++
++/* Convert PCI info to device type.  Returns false when device is not
++ * recognised.
++ */
++extern int efhw_device_type_init(struct efhw_device_type *dt,
++                               int vendor_id, int device_id, int revision);
++
++/* Initialise fields that do not involve touching hardware. */
++extern void efhw_nic_init(struct efhw_nic *nic, unsigned flags,
++                        unsigned options, struct efhw_device_type dev_type);
++
++/*! Destruct NIC resources */
++extern void efhw_nic_dtor(struct efhw_nic *nic);
++
++/*! Shutdown interrupts */
++extern void efhw_nic_close_interrupts(struct efhw_nic *nic);
++
++#endif /* __CI_EFHW_NIC_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/public.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/public.h  2008-05-19 00:33:29.373839269 +0300
+@@ -0,0 +1,83 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides public API of efhw library exported from the SFC
++ * resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFHW_PUBLIC_H__
++#define __CI_EFHW_PUBLIC_H__
++
++#include <ci/efhw/common.h>
++#include <ci/efhw/efhw_types.h>
++
++/*! Returns true if we have some EtherFabric functional units -
++  whether configured or not */
++static inline int efhw_nic_have_functional_units(struct efhw_nic *nic)
++{
++      return nic->efhw_func != 0;
++}
++
++/*! Returns true if the EtherFabric functional units have been configured  */
++static inline int efhw_nic_have_hw(struct efhw_nic *nic)
++{
++      return efhw_nic_have_functional_units(nic) && (EFHW_KVA(nic) != 0);
++}
++
++/*! Helper function to allocate the iobuffer needed by an eventq
++ *   - it ensures the eventq has the correct alignment for the NIC
++ *
++ * \param rm        Event-queue resource manager
++ * \param instance  Event-queue instance (index)
++ * \param buf_bytes Requested size of eventq
++ * \return          < 0 if iobuffer allocation fails
++ */
++int efhw_nic_event_queue_alloc_iobuffer(struct efhw_nic *nic,
++                                      struct eventq_resource_hardware *h,
++                                      int evq_instance, unsigned buf_bytes);
++
++extern void falcon_nic_set_rx_usr_buf_size(struct efhw_nic *,
++                                         int rx_usr_buf_size);
++
++extern void
++falcon_nic_rx_filter_ctl_set(struct efhw_nic *nic, uint32_t tcp_full,
++                           uint32_t tcp_wild,
++                           uint32_t udp_full, uint32_t udp_wild);
++
++extern void
++falcon_nic_rx_filter_ctl_get(struct efhw_nic *nic, uint32_t *tcp_full,
++                           uint32_t *tcp_wild,
++                           uint32_t *udp_full, uint32_t *udp_wild);
++
++#endif /* __CI_EFHW_PUBLIC_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efhw/sysdep.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efhw/sysdep.h  2008-05-19 00:33:29.405841113 +0300
+@@ -0,0 +1,72 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides version-independent Linux kernel API for efhw library.
++ * Only kernels >=2.6.9 are supported.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFHW_SYSDEP_LINUX_H__
++#define __CI_EFHW_SYSDEP_LINUX_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <linux/if_ether.h>
++
++#include <linux/netdevice.h> /* necessary for etherdevice.h on some kernels */
++#include <linux/etherdevice.h>
++
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
++static inline int is_local_ether_addr(const u8 *addr)
++{
++      return (0x02 & addr[0]);
++}
++#endif
++
++typedef unsigned long irq_flags_t;
++
++#define spin_lock_destroy(l_)  do {} while (0)
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++#define HAS_NET_NAMESPACE
++#endif
++
++/* Funny, but linux has round_up for x86 only, defined in
++ * x86-specific header */
++#ifndef round_up
++#define round_up(x, y) (((x) + (y) - 1) & ~((y)-1))
++#endif
++
++#endif /* __CI_EFHW_SYSDEP_LINUX_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/buddy.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/buddy.h   2008-05-19 00:33:29.405841113 +0300
+@@ -0,0 +1,69 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides private API for buddy allocator.  This API is not
++ * designed for use outside of SFC resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_BUDDY_H__
++#define __CI_EFRM_BUDDY_H__
++
++#include <ci/efrm/sysdep.h>
++
++/*! Comment? */
++struct efrm_buddy_allocator {
++      struct list_head *free_lists;   /* array[order+1] */
++      struct list_head *links;        /* array[1<<order] */
++      uint8_t *orders;                /* array[1<<order] */
++      unsigned order;         /*!< total size == (1 << order) */
++      /* ?? Consider recording largest available order + for each order the
++       ** smallest available order that is big enough.
++       */
++};
++
++  /*! Returns total size of managed space. */
++static inline unsigned long efrm_buddy_size(struct efrm_buddy_allocator *b)
++{
++      return 1ul << b->order;
++}
++
++int efrm_buddy_ctor(struct efrm_buddy_allocator *b, unsigned order);
++void efrm_buddy_dtor(struct efrm_buddy_allocator *b);
++int efrm_buddy_alloc(struct efrm_buddy_allocator *b, unsigned order);
++void efrm_buddy_free(struct efrm_buddy_allocator *b, unsigned addr,
++                   unsigned order);
++void efrm_buddy_reserve_at_start(struct efrm_buddy_allocator *b, unsigned n);
++void efrm_buddy_reserve_at_end(struct efrm_buddy_allocator *b, unsigned n);
++
++#endif /* __CI_EFRM_BUDDY_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/buffer_table.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/buffer_table.h    2008-05-19 00:33:29.405841113 +0300
+@@ -0,0 +1,86 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides private buffer table API.  This API is not designed
++ * for use outside of SFC resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_BUFFER_TABLE_H__
++#define __CI_EFRM_BUFFER_TABLE_H__
++
++#include <ci/efhw/efhw_types.h>
++
++/*--------------------------------------------------------------------
++ *
++ * NIC's buffer table.
++ *
++ *--------------------------------------------------------------------*/
++
++/*! Managed interface. */
++
++/*! construct a managed buffer table object, allocated over a region of
++ *  the NICs buffer table space
++ */
++extern int efrm_buffer_table_ctor(unsigned low, unsigned high);
++/*! destructor for above */
++extern void efrm_buffer_table_dtor(void);
++
++/*! allocate a contiguous region of buffer table space */
++extern int efrm_buffer_table_alloc(unsigned order,
++                                 struct efhw_buffer_table_allocation *a);
++
++/*! current size of the buffer table.
++ * FIXME This function should be inline, but it is never used from
++ * the fast path, so let it as-is. */
++unsigned long efrm_buffer_table_size(void);
++
++/*--------------------------------------------------------------------
++ *
++ * buffer table operations through the HW independent API
++ *
++ *--------------------------------------------------------------------*/
++
++/*! free a previously allocated region of buffer table space */
++extern void efrm_buffer_table_free(struct efhw_buffer_table_allocation *a);
++
++/*! commit the update of a buffer table entry to every NIC */
++void efrm_buffer_table_commit(void);
++
++/*! set a given buffer table entry. [pa] should be the physical
++  address of pinned down memory. This function can only be called from
++  the char driver */
++void efrm_buffer_table_set(struct efhw_buffer_table_allocation *a,
++                         unsigned i, dma_addr_t dma_addr, int owner);
++
++#endif /* __CI_EFRM_BUFFER_TABLE_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/debug.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/debug.h   2008-05-19 00:33:29.409841344 +0300
+@@ -0,0 +1,78 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides debug-related API for efrm library using Linux kernel
++ * primitives.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_DEBUG_LINUX_H__
++#define __CI_EFRM_DEBUG_LINUX_H__
++
++#define EFRM_PRINTK_PREFIX "[sfc efrm] "
++
++#define EFRM_PRINTK(level, fmt, ...) \
++      printk(level EFRM_PRINTK_PREFIX fmt "\n", __VA_ARGS__)
++
++/* Following macros should be used with non-zero format parameters
++ * due to __VA_ARGS__ limitations.  Use "%s" with __FUNCTION__ if you can't
++ * find better parameters. */
++#define EFRM_ERR(fmt, ...)     EFRM_PRINTK(KERN_ERR, fmt, __VA_ARGS__)
++#define EFRM_WARN(fmt, ...)    EFRM_PRINTK(KERN_WARNING, fmt, __VA_ARGS__)
++#define EFRM_NOTICE(fmt, ...)  EFRM_PRINTK(KERN_NOTICE, fmt, __VA_ARGS__)
++#if 0 && !defined(NDEBUG)
++#define EFRM_TRACE(fmt, ...) EFRM_PRINTK(KERN_DEBUG, fmt, __VA_ARGS__)
++#else
++#define EFRM_TRACE(fmt, ...)
++#endif
++
++#ifndef NDEBUG
++#define EFRM_ASSERT(cond)  BUG_ON((cond) == 0)
++#define _EFRM_ASSERT(cond, file, line) \
++      do {                                                            \
++              if (unlikely(!(cond))) {                                \
++                      EFRM_ERR("assertion \"%s\" failed at %s %d",    \
++                               #cond, file, line);                    \
++                      BUG();                                          \
++              }                                                       \
++      } while (0)
++
++#define EFRM_DO_DEBUG(expr) expr
++#define EFRM_VERIFY_EQ(expr, val) EFRM_ASSERT((expr) == (val))
++#else
++#define EFRM_ASSERT(cond)
++#define EFRM_DO_DEBUG(expr)
++#define EFRM_VERIFY_EQ(expr, val) expr
++#endif
++
++#endif /* __CI_EFRM_DEBUG_LINUX_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/driver_private.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/driver_private.h  2008-05-19 00:33:29.409841344 +0300
+@@ -0,0 +1,86 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides private API of efrm library to be used from the SFC
++ * resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_DRIVER_PRIVATE_H__
++#define __CI_EFRM_DRIVER_PRIVATE_H__
++
++#include <ci/efrm/resource.h>
++#include <ci/efrm/sysdep.h>
++
++/*--------------------------------------------------------------------
++ *
++ * global variables
++ *
++ *--------------------------------------------------------------------*/
++
++/* Internal structure for resource driver */
++extern struct efrm_resource_manager *efrm_rm_table[];
++
++/*--------------------------------------------------------------------
++ *
++ * efrm_nic_table handling
++ *
++ *--------------------------------------------------------------------*/
++
++extern int efrm_driver_ctor(void);
++extern int efrm_driver_dtor(void);
++extern int efrm_driver_register_nic(struct efhw_nic *, int nic_index);
++extern int efrm_driver_unregister_nic(struct efhw_nic *);
++
++/*--------------------------------------------------------------------
++ *
++ * create/destroy resource managers
++ *
++ *--------------------------------------------------------------------*/
++
++struct vi_resource_dimensions {
++      unsigned evq_int_min, evq_int_max;
++      unsigned evq_timer_min, evq_timer_max;
++      unsigned rxq_min, rxq_max;
++      unsigned txq_min, txq_max;
++};
++
++/*! Initialise resources */
++extern int
++efrm_resources_init(const struct vi_resource_dimensions *,
++                  int buffer_table_min, int buffer_table_max);
++
++/*! Tear down resources */
++extern void efrm_resources_fini(void);
++
++#endif /* __CI_EFRM_DRIVER_PRIVATE_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/filter.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/filter.h  2008-05-19 00:33:29.409841344 +0300
+@@ -0,0 +1,147 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides public API for filter resource.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_FILTER_H__
++#define __CI_EFRM_FILTER_H__
++
++#include <ci/efrm/resource.h>
++#include <ci/efrm/vi_resource.h>
++#include <ci/efrm/nic_set.h>
++#include <ci/efhw/common.h>
++
++/*! Comment? */
++struct filter_resource {
++      struct efrm_resource rs;
++      struct vi_resource *pt;
++      int filter_idx;
++      efrm_nic_set_t nic_set;
++};
++
++#define filter_resource(rs1)  container_of((rs1), struct filter_resource, rs)
++
++/*!
++ * Allocate filter resource.
++ *
++ * \param vi_parent VI resource to use as parent. The function takes
++ *                  reference to the VI resource on success.
++ * \param frs_out   pointer to return the new filter resource
++ *
++ * \return          status code; if non-zero, frs_out is unchanged
++ */
++extern int
++efrm_filter_resource_alloc(struct vi_resource *vi_parent,
++                         struct filter_resource **frs_out);
++
++/* efrm_filter_resource_free should be called only if
++ * __efrm_resource_ref_count_zero() returned true.
++ * The easiest way is to call efrm_filter_resource_release() */
++void efrm_filter_resource_free(struct filter_resource *frs);
++static inline void efrm_filter_resource_release(struct filter_resource *frs)
++{
++      unsigned id;
++
++      EFRM_RESOURCE_ASSERT_VALID(&frs->rs, 0);
++      id = EFRM_RESOURCE_INSTANCE(frs->rs.rs_handle);
++
++      if (atomic_dec_and_test(&frs->rs.rs_ref_count)) {
++              if (__efrm_resource_ref_count_zero(EFRM_RESOURCE_FILTER, id)) {
++                      EFRM_ASSERT(EFRM_RESOURCE_INSTANCE(frs->rs.rs_handle) ==
++                                  id);
++                      efrm_filter_resource_free(frs);
++              }
++      }
++}
++
++/*--------------------------------------------------------------------
++ *!
++ * Called to set/change the PT endpoint of a filter
++ *
++ * Example of use is TCP helper when it finds a wildcard IP filter
++ * needs to change which application it delivers traffic to
++ *
++ * \param frs           filter resource
++ * \param pt_handle     handle of new PT endpoint
++ *
++ * \return              standard error codes
++ *
++ *--------------------------------------------------------------------*/
++extern int
++efrm_filter_resource_set_ptresource(struct filter_resource *frs,
++                                  struct vi_resource *virs);
++
++extern int efrm_filter_resource_clear(struct filter_resource *frs);
++
++extern int __efrm_filter_resource_set(struct filter_resource *frs, int type,
++                                    unsigned saddr_be32, uint16_t sport_be16,
++                                    unsigned daddr_be32, uint16_t dport_be16);
++
++static inline int
++efrm_filter_resource_tcp_set(struct filter_resource *frs,
++                           unsigned saddr, uint16_t sport,
++                           unsigned daddr, uint16_t dport)
++{
++      int type;
++
++      EFRM_ASSERT((saddr && sport) || (!saddr && !sport));
++
++      type =
++          saddr ? EFHW_IP_FILTER_TYPE_TCP_FULL :
++          EFHW_IP_FILTER_TYPE_TCP_WILDCARD;
++
++      return __efrm_filter_resource_set(frs, type,
++                                        saddr, sport, daddr, dport);
++}
++
++static inline int
++efrm_filter_resource_udp_set(struct filter_resource *frs,
++                           unsigned saddr, uint16_t sport,
++                           unsigned daddr, uint16_t dport)
++{
++      int type;
++
++      EFRM_ASSERT((saddr && sport) || (!saddr && !sport));
++
++      type =
++          saddr ? EFHW_IP_FILTER_TYPE_UDP_FULL :
++          EFHW_IP_FILTER_TYPE_UDP_WILDCARD;
++
++      return __efrm_filter_resource_set(frs,
++                                        type, saddr, sport, daddr, dport);
++}
++
++#endif /* __CI_EFRM_FILTER_H__ */
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/iobufset.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/iobufset.h        2008-05-19 00:33:29.409841344 +0300
+@@ -0,0 +1,123 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides public API for iobufset resource.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_IOBUFSET_H__
++#define __CI_EFRM_IOBUFSET_H__
++
++#include <ci/efrm/vi_resource.h>
++
++/*! Iobufset resource structture.
++ * Users should not access the structure fields directly, but use the API
++ * below.
++ * However, this structure should not be moved out of public headers,
++ * because part of API (ex. efrm_iobufset_dma_addr function) is inline and
++ * is used in the fast-path code.
++ */
++struct iobufset_resource {
++      struct efrm_resource rs;
++      struct vi_resource *evq;
++      struct efhw_buffer_table_allocation buf_tbl_alloc;
++      unsigned int faultonaccess;
++      unsigned int n_bufs;
++      unsigned int pages_per_contiguous_chunk;
++      unsigned order;
++      efhw_iopage_t bufs[1];
++      /*!< up to n_bufs can follow this, so this must be the last member */
++};
++
++#define iobufset_resource(rs1) \
++      container_of((rs1), struct iobufset_resource, rs)
++
++/*!
++ * Allocate iobufset resource.
++ *
++ * \param vi_evq    VI resource to use. The function takes
++ *                  reference to the VI resource on success.
++ * \param iobrs_out   pointer to return the new filter resource
++ *
++ * \return          status code; if non-zero, frs_out is unchanged
++ */
++extern int
++efrm_iobufset_resource_alloc(int32_t n_pages,
++                           int32_t pages_per_contiguous_chunk,
++                           struct vi_resource *vi_evq,
++                           bool phys_addr_mode,
++                           uint32_t faultonaccess,
++                           struct iobufset_resource **iobrs_out);
++
++/* efrm_iobufset_resource_free should be called only if
++ * __efrm_resource_ref_count_zero() returned true.
++ * The easiest way is to call efrm_iobufset_resource_release() */
++void efrm_iobufset_resource_free(struct iobufset_resource *rs);
++static inline void
++efrm_iobufset_resource_release(struct iobufset_resource *iobrs)
++{
++      unsigned id;
++
++      EFRM_RESOURCE_ASSERT_VALID(&iobrs->rs, 0);
++      id = EFRM_RESOURCE_INSTANCE(iobrs->rs.rs_handle);
++
++      if (atomic_dec_and_test(&iobrs->rs.rs_ref_count)) {
++              if (__efrm_resource_ref_count_zero(EFRM_RESOURCE_IOBUFSET, id))
++                      efrm_iobufset_resource_free(iobrs);
++      }
++}
++
++static inline char *
++efrm_iobufset_ptr(struct iobufset_resource *rs, unsigned offs)
++{
++      EFRM_ASSERT(offs < (unsigned)(rs->n_bufs << PAGE_SHIFT));
++      return efhw_iopage_ptr(&rs->bufs[offs >> PAGE_SHIFT])
++          + (offs & (PAGE_SIZE - 1));
++}
++
++static inline char *efrm_iobufset_page_ptr(struct iobufset_resource *rs,
++                                     unsigned page_i)
++{
++      EFRM_ASSERT(page_i < (unsigned)rs->n_bufs);
++      return efhw_iopage_ptr(&rs->bufs[page_i]);
++}
++
++static inline dma_addr_t
++efrm_iobufset_dma_addr(struct iobufset_resource *rs, unsigned offs)
++{
++      EFRM_ASSERT(offs < (unsigned)(rs->n_bufs << PAGE_SHIFT));
++      return efhw_iopage_dma_addr(&rs->bufs[offs >> PAGE_SHIFT])
++          + (offs & (PAGE_SIZE - 1));
++}
++
++#endif /* __CI_EFRM_IOBUFSET_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/nic_set.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/nic_set.h 2008-05-19 00:33:29.409841344 +0300
+@@ -0,0 +1,104 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides public API for NIC sets.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_NIC_SET_H__
++#define __CI_EFRM_NIC_SET_H__
++
++#include <ci/efrm/debug.h>
++#include <ci/efhw/common_sysdep.h>
++#include <ci/efhw/efhw_config.h>
++
++/*--------------------------------------------------------------------
++ *
++ * efrm_nic_set_t - tracks which NICs something has been done on
++ *
++ *--------------------------------------------------------------------*/
++
++/* Internal suructure of efrm_nic_set_t should not be referenced outside of
++ * this file.  Add a new accessor if you should do it. */
++typedef struct {
++      uint32_t nics;
++} efrm_nic_set_t;
++
++#if EFHW_MAX_NR_DEVS > 32
++#error change efrm_nic_set to handle EFHW_MAX_NR_DEVS number of devices
++#endif
++
++static inline bool
++efrm_nic_set_read(const efrm_nic_set_t *nic_set, unsigned index)
++{
++      EFRM_ASSERT(nic_set);
++      EFRM_ASSERT(index < EFHW_MAX_NR_DEVS && index < 32);
++      return (nic_set->nics & (1 << index)) ? true : false;
++}
++
++static inline void
++efrm_nic_set_write(efrm_nic_set_t *nic_set, unsigned index, bool value)
++{
++      EFRM_ASSERT(nic_set);
++      EFRM_ASSERT(index < EFHW_MAX_NR_DEVS && index < 32);
++      EFRM_ASSERT(value == false || value == true);
++      nic_set->nics = (nic_set->nics & (~(1 << index))) + (value << index);
++}
++
++static inline void efrm_nic_set_clear(efrm_nic_set_t *nic_set)
++{
++      nic_set->nics = 0;
++}
++
++static inline void efrm_nic_set_all(efrm_nic_set_t *nic_set)
++{
++      nic_set->nics = 0xffffffff;
++}
++
++static inline bool efrm_nic_set_is_all_clear(efrm_nic_set_t *nic_set)
++{
++      return nic_set->nics == 0 ? true : false;
++}
++
++#define EFRM_NIC_SET_FMT "%x"
++
++static inline uint32_t efrm_nic_set_pri_arg(efrm_nic_set_t *nic_set)
++{
++      return nic_set->nics;
++}
++
++#define EFRM_FOR_EACH_NIC_INDEX_IN_SET(_set, _nic_i)                  \
++      for ((_nic_i) = 0; (_nic_i) < EFHW_MAX_NR_DEVS; ++(_nic_i))     \
++              if (efrm_nic_set_read((_set), (_nic_i)))
++
++#endif /* __CI_EFRM_NIC_SET_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/nic_table.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/nic_table.h       2008-05-19 00:33:29.413841574 +0300
+@@ -0,0 +1,98 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides public API for NIC table.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_NIC_TABLE_H__
++#define __CI_EFRM_NIC_TABLE_H__
++
++#include <ci/efhw/efhw_types.h>
++#include <ci/efrm/sysdep.h>
++
++/*--------------------------------------------------------------------
++ *
++ * struct efrm_nic_table - top level driver object keeping all NICs -
++ * implemented in driver_object.c
++ *
++ *--------------------------------------------------------------------*/
++
++/*! Comment? */
++struct efrm_nic_table {
++      /*! nics attached to this driver */
++      struct efhw_nic *nic[EFHW_MAX_NR_DEVS];
++      /*! pointer to an arbitrary struct efhw_nic if one exists;
++       * for code which does not care which NIC it wants but
++       * still needs one. Note you cannot assume nic[0] exists. */
++      struct efhw_nic *a_nic;
++      uint32_t nic_count;     /*!< number of nics attached to this driver */
++      spinlock_t lock;        /*!< lock for table modifications */
++      atomic_t ref_count;     /*!< refcount for users of nic table */
++};
++
++/* Resource driver structures used by other drivers as well */
++extern struct efrm_nic_table efrm_nic_table;
++
++static inline void efrm_nic_table_hold(void)
++{
++      atomic_inc(&efrm_nic_table.ref_count);
++}
++
++static inline void efrm_nic_table_rele(void)
++{
++      atomic_dec(&efrm_nic_table.ref_count);
++}
++
++static inline int efrm_nic_table_held(void)
++{
++      return (atomic_read(&efrm_nic_table.ref_count) != 0);
++}
++
++/* Run code block _x multiple times with variable nic set to each
++ * registered NIC in turn.
++ * DO NOT "break" out of this loop early. */
++#define EFRM_FOR_EACH_NIC(_nic_i, _nic)                                       \
++      for ((_nic_i) = (efrm_nic_table_hold(), 0);                     \
++           (_nic_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0); \
++           (_nic_i)++)                                                \
++              if (((_nic) = efrm_nic_table.nic[_nic_i]))
++
++#define EFRM_FOR_EACH_NIC_IN_SET(_set, _i, _nic)                      \
++      for ((_i) = (efrm_nic_table_hold(), 0);                         \
++           (_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0);     \
++           ++(_i))                                                    \
++              if (((_nic) = efrm_nic_table.nic[_i]) &&                \
++                  efrm_nic_set_read((_set), (_i)))
++
++#endif /* __CI_EFRM_NIC_TABLE_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/private.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/private.h 2008-05-19 00:33:29.413841574 +0300
+@@ -0,0 +1,141 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides private API of efrm library -- resource handling.
++ * This API is not designed for use outside of SFC resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_PRIVATE_H__
++#define __CI_EFRM_PRIVATE_H__
++
++#include <ci/efrm/resource.h>
++#include <ci/efrm/driver_private.h>
++#include <ci/efrm/sysdep.h>
++#include <ci/efrm/debug.h>
++
++/*--------------------------------------------------------------------
++ *
++ * create resource managers
++ *
++ *--------------------------------------------------------------------*/
++
++/*! Create a resource manager for various types of resources
++ */
++extern int
++efrm_create_iobufset_resource_manager(struct efrm_resource_manager **out);
++
++extern int
++efrm_create_filter_resource_manager(struct efrm_resource_manager **out);
++
++extern int
++efrm_create_vi_resource_manager(struct efrm_resource_manager **out,
++                              const struct vi_resource_dimensions *);
++
++/*--------------------------------------------------------------------
++ *
++ * efrm_resource_handle_t handling
++ *
++ *--------------------------------------------------------------------*/
++
++/*! Initialize an area of memory to be used as a resource */
++static inline void efrm_resource_init(struct efrm_resource *rs,
++                                    int type, int instance)
++{
++      EFRM_ASSERT(instance >= 0);
++      EFRM_ASSERT(type >= 0 && type < EFRM_RESOURCE_NUM);
++      atomic_set(&rs->rs_ref_count, 1);
++      rs->rs_handle.handle = (type << 28u) |
++              (((unsigned)jiffies & 0xfff) << 16) | instance;
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Instance pool management
++ *
++ *--------------------------------------------------------------------*/
++
++/*! Allocate instance pool. Use kfifo_vfree to destroy it. */
++static inline int
++efrm_kfifo_id_ctor(struct kfifo **ids_out,
++                 unsigned int base, unsigned int limit, spinlock_t *lock)
++{
++      unsigned int i;
++      struct kfifo *ids;
++      unsigned char *buffer;
++      unsigned int size = roundup_pow_of_two((limit - base) * sizeof(int));
++
++      EFRM_ASSERT(base <= limit);
++      buffer = vmalloc(size);
++      ids = kfifo_init(buffer, size, GFP_KERNEL, lock);
++      if (IS_ERR(ids))
++              return PTR_ERR(ids);
++      for (i = base; i < limit; i++)
++              EFRM_VERIFY_EQ(__kfifo_put(ids, (unsigned char *)&i,
++                                         sizeof(i)), sizeof(i));
++
++      *ids_out = ids;
++      return 0;
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Various private functions
++ *
++ *--------------------------------------------------------------------*/
++
++/*! Initialize the fields in the provided resource manager memory area
++ *   \param rm         The area of memory to be initialized
++ *   \param dtor       A method to destroy the resource manager
++ *   \param name       A Textual name for the resource manager
++ *   \param type       The type of resource managed
++ *   \param initial_table_size Initial size of the ID table
++ *   \param auto_destroy Destroy resource manager on driver onload iff true
++ *
++ * A default table size is provided if the value 0 is provided.
++ */
++extern int
++efrm_resource_manager_ctor(struct efrm_resource_manager *rm,
++                         void (*dtor)(struct efrm_resource_manager *),
++                         const char *name, unsigned type,
++                         int initial_table_size);
++
++extern void efrm_resource_manager_dtor(struct efrm_resource_manager *rm);
++
++/*! Insert a resource into table in the resource manager.
++ *
++ * Caller should free the resource if this function returns non-zero.
++ */
++extern int efrm_resource_manager_insert(struct efrm_resource *rs);
++
++#endif /* __CI_EFRM_PRIVATE_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/resource.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/resource.h        2008-05-19 00:33:29.413841574 +0300
+@@ -0,0 +1,122 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides public interface of efrm library -- resource handling.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_RESOURCE_H__
++#define __CI_EFRM_RESOURCE_H__
++
++/*--------------------------------------------------------------------
++ *
++ * headers for type dependencies
++ *
++ *--------------------------------------------------------------------*/
++
++#include <ci/efhw/efhw_types.h>
++#include <ci/efrm/resource_id.h>
++#include <ci/efrm/sysdep.h>
++#include <ci/efhw/common_sysdep.h>
++
++#ifndef __ci_driver__
++#error "Driver-only file"
++#endif
++
++/*--------------------------------------------------------------------
++ *
++ * struct efrm_resource - represents an allocated resource
++ *                   (eg. pinned pages of memory, or resource on a NIC)
++ *
++ *--------------------------------------------------------------------*/
++
++/*! Representation of an allocated resource */
++struct efrm_resource {
++      atomic_t rs_ref_count; /*!< users count; see
++                              * __efrm_resource_ref_count_zero() */
++      efrm_resource_handle_t rs_handle;
++};
++
++/*--------------------------------------------------------------------
++ *
++ * managed resource abstraction
++ *
++ *--------------------------------------------------------------------*/
++
++/*! Factory for resources of a specific type */
++struct efrm_resource_manager {
++      const char *rm_name;    /*!< human readable only */
++      spinlock_t rm_lock;
++#ifndef NDEBUG
++      unsigned rm_type;
++#endif
++      int rm_resources;
++      int rm_resources_hiwat;
++      /*! table of allocated resources */
++      struct efrm_resource **rm_table;
++      unsigned rm_table_size;
++      /**
++       * Destructor for the resource manager. Other resource managers
++       * might be already dead, although the system guarantees that
++       * managers are destructed in the order by which they were created
++       */
++      void (*rm_dtor)(struct efrm_resource_manager *);
++};
++
++#ifdef NDEBUG
++# define EFRM_RESOURCE_ASSERT_VALID(rs, rc_mbz)
++# define EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm)
++#else
++/*! Check validity of resource and report on failure */
++extern void efrm_resource_assert_valid(struct efrm_resource *,
++                                     int rc_may_be_zero,
++                                     const char *file, int line);
++# define EFRM_RESOURCE_ASSERT_VALID(rs, rc_mbz) \
++      efrm_resource_assert_valid((rs), (rc_mbz), __FILE__, __LINE__)
++
++/*! Check validity of resource manager and report on failure */
++extern void efrm_resource_manager_assert_valid(struct efrm_resource_manager *,
++                                             const char *file, int line);
++# define EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm) \
++      efrm_resource_manager_assert_valid((rm), __FILE__, __LINE__)
++#endif
++
++/*! Check the reference count on the resource provided and delete its
++ *  handle it in its owning resource manager if the
++ *  reference count has fallen to zero.
++ *
++ *  Returns TRUE if the caller should really free the resource.
++ */
++extern bool __efrm_resource_ref_count_zero(unsigned type, unsigned instance);
++
++#endif /* __CI_EFRM_RESOURCE_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/resource_id.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/resource_id.h     2008-05-19 00:33:29.413841574 +0300
+@@ -0,0 +1,104 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides public type and definitions resource handle, and the
++ * definitions of resource types.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_DRIVER_EFRM_RESOURCE_ID_H__
++#define __CI_DRIVER_EFRM_RESOURCE_ID_H__
++
++/***********************************************************************
++ * Resource handles
++ *
++ * Resource handles are intended for identifying resources at kernel
++ * level, within the context of a particular NIC. particularly because
++ * for some resource types, the low 16 bites correspond to hardware
++ * IDs. They were historically also used at user level, with a nonce
++ * stored in the bits 16 to 27 (inclusive), but that approach is
++ * deprecated (but sill alive!).
++ *
++ * The handle value 0 is used to mean "no resource".
++ * Identify resources within the context of a file descriptor at user
++ * level.
++ ***********************************************************************/
++
++typedef struct efrm_resource_handle_s {
++      uint32_t handle;
++} efrm_resource_handle_t;
++
++/* You may think these following functions should all have
++ * _HANDLE_ in their names, but really we are providing an abstract set
++ * of methods on a (hypothetical) efrm_resource_t object, with
++ * efrm_resource_handle_t being just the reference one holds to access
++ * the object (aka "this" or "self").
++ */
++
++/* Below I use inline instead of macros where possible in order to get
++ * more type checking help from the compiler; hopefully we'll never
++ * have to rewrite these to use #define as we've found some horrible
++ * compiler on which we cannot make static inline do the Right Thing (tm).
++ *
++ * For consistency and to avoid pointless change I spell these
++ * routines as macro names (CAPTILIZE_UNDERSCORED), which also serves
++ * to remind people they are compact and inlined.
++ */
++
++#define EFRM_RESOURCE_FMT  "[rs:%08x]"
++
++static inline unsigned EFRM_RESOURCE_PRI_ARG(efrm_resource_handle_t h)
++{
++      return (h.handle);
++}
++
++static inline unsigned EFRM_RESOURCE_INSTANCE(efrm_resource_handle_t h)
++{
++      return (h.handle & 0x0000ffff);
++}
++
++static inline unsigned EFRM_RESOURCE_TYPE(efrm_resource_handle_t h)
++{
++      return (h.handle & 0xf0000000) >> 28;
++}
++
++/***********************************************************************
++ * Resource type codes
++ ***********************************************************************/
++
++#define EFRM_RESOURCE_IOBUFSET          0x0
++#define EFRM_RESOURCE_VI                0x1
++#define EFRM_RESOURCE_FILTER            0x2
++#define EFRM_RESOURCE_NUM               0x3   /* This isn't a resource! */
++
++#define       EFRM_RESOURCE_NAME(type) \
++      ((type) == EFRM_RESOURCE_IOBUFSET?      "IOBUFSET"      : \
++       (type) == EFRM_RESOURCE_VI?            "VI"            : \
++       (type) == EFRM_RESOURCE_FILTER?        "FILTER"        : \
++                                              "<invalid>")
++
++#endif /* __CI_DRIVER_EFRM_RESOURCE_ID_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/sysdep.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/sysdep.h  2008-05-19 00:33:29.413841574 +0300
+@@ -0,0 +1,54 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides Linux-like system-independent API for efrm library.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_SYSDEP_H__
++#define __CI_EFRM_SYSDEP_H__
++
++/* Spinlocks are defined in efhw/sysdep.h */
++#include <ci/efhw/sysdep.h>
++
++#if defined(__linux__) && defined(__KERNEL__)
++
++# include <ci/efrm/sysdep_linux.h>
++
++#else
++
++# include <ci/efrm/sysdep_ci2linux.h>
++
++#endif
++
++#endif /* __CI_EFRM_SYSDEP_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/sysdep_linux.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/sysdep_linux.h    2008-05-19 00:33:29.417841805 +0300
+@@ -0,0 +1,248 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides version-independent Linux kernel API for efrm library.
++ * Only kernels >=2.6.9 are supported.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Kfifo API is partially stolen from linux-2.6.22/include/linux/list.h
++ * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_SYSDEP_LINUX_H__
++#define __CI_EFRM_SYSDEP_LINUX_H__
++
++#include <linux/version.h>
++#include <linux/list.h>
++#include <linux/vmalloc.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/workqueue.h>
++#include <linux/gfp.h>
++#include <linux/slab.h>
++#include <linux/hardirq.h>
++#include <linux/kernel.h>
++#include <linux/if_ether.h>
++#include <linux/completion.h>
++#include <linux/in.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++/* get roundup_pow_of_two(), which was in kernel.h in early kernel versions */
++#include <linux/log2.h>
++#endif
++
++/********************************************************************
++ *
++ * List API
++ *
++ ********************************************************************/
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++static inline void
++list_replace_init(struct list_head *old, struct list_head *new)
++{
++      new->next = old->next;
++      new->next->prev = new;
++      new->prev = old->prev;
++      new->prev->next = new;
++      INIT_LIST_HEAD(old);
++}
++#endif
++
++static inline struct list_head *list_pop(struct list_head *list)
++{
++      struct list_head *link = list->next;
++      list_del(link);
++      return link;
++}
++
++static inline struct list_head *list_pop_tail(struct list_head *list)
++{
++      struct list_head *link = list->prev;
++      list_del(link);
++      return link;
++}
++
++/********************************************************************
++ *
++ * Workqueue API
++ *
++ ********************************************************************/
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++#define NEED_OLD_WORK_API
++
++/**
++ * The old and new work function prototypes just change
++ * the type of the pointer in the only argument, so it's
++ * safe to cast one function type to the other
++ */
++typedef void (*efrm_old_work_func_t) (void *p);
++
++#undef INIT_WORK
++#define INIT_WORK(_work, _func)                                       \
++      do {                                                    \
++              INIT_LIST_HEAD(&(_work)->entry);                \
++              (_work)->pending = 0;                           \
++              PREPARE_WORK((_work),                           \
++                           (efrm_old_work_func_t) (_func),    \
++                           (_work));                          \
++      } while (0)
++
++#endif
++
++/********************************************************************
++ *
++ * Kfifo API
++ *
++ ********************************************************************/
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
++
++#if !defined(RHEL_RELEASE_CODE) || (RHEL_RELEASE_CODE < 1029)
++typedef unsigned gfp_t;
++#endif
++
++#define HAS_NO_KFIFO
++
++struct kfifo {
++      unsigned char *buffer;  /* the buffer holding the data */
++      unsigned int size;      /* the size of the allocated buffer */
++      unsigned int in;        /* data is added at offset (in % size) */
++      unsigned int out;       /* data is extracted from off. (out % size) */
++      spinlock_t *lock;       /* protects concurrent modifications */
++};
++
++extern struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
++                              gfp_t gfp_mask, spinlock_t *lock);
++extern struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask,
++                               spinlock_t *lock);
++extern void kfifo_free(struct kfifo *fifo);
++extern unsigned int __kfifo_put(struct kfifo *fifo,
++                              unsigned char *buffer, unsigned int len);
++extern unsigned int __kfifo_get(struct kfifo *fifo,
++                              unsigned char *buffer, unsigned int len);
++
++/**
++ * kfifo_put - puts some data into the FIFO
++ * @fifo: the fifo to be used.
++ * @buffer: the data to be added.
++ * @len: the length of the data to be added.
++ *
++ * This function copies at most @len bytes from the @buffer into
++ * the FIFO depending on the free space, and returns the number of
++ * bytes copied.
++ */
++static inline unsigned int
++kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
++{
++      unsigned long flags;
++      unsigned int ret;
++
++      spin_lock_irqsave(fifo->lock, flags);
++
++      ret = __kfifo_put(fifo, buffer, len);
++
++      spin_unlock_irqrestore(fifo->lock, flags);
++
++      return ret;
++}
++
++/**
++ * kfifo_get - gets some data from the FIFO
++ * @fifo: the fifo to be used.
++ * @buffer: where the data must be copied.
++ * @len: the size of the destination buffer.
++ *
++ * This function copies at most @len bytes from the FIFO into the
++ * @buffer and returns the number of copied bytes.
++ */
++static inline unsigned int
++kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
++{
++      unsigned long flags;
++      unsigned int ret;
++
++      spin_lock_irqsave(fifo->lock, flags);
++
++      ret = __kfifo_get(fifo, buffer, len);
++
++      /*
++       * optimization: if the FIFO is empty, set the indices to 0
++       * so we don't wrap the next time
++       */
++      if (fifo->in == fifo->out)
++              fifo->in = fifo->out = 0;
++
++      spin_unlock_irqrestore(fifo->lock, flags);
++
++      return ret;
++}
++
++/**
++ * __kfifo_len - returns the number of bytes available in the FIFO, no locking version
++ * @fifo: the fifo to be used.
++ */
++static inline unsigned int __kfifo_len(struct kfifo *fifo)
++{
++      return fifo->in - fifo->out;
++}
++
++/**
++ * kfifo_len - returns the number of bytes available in the FIFO
++ * @fifo: the fifo to be used.
++ */
++static inline unsigned int kfifo_len(struct kfifo *fifo)
++{
++      unsigned long flags;
++      unsigned int ret;
++
++      spin_lock_irqsave(fifo->lock, flags);
++
++      ret = __kfifo_len(fifo);
++
++      spin_unlock_irqrestore(fifo->lock, flags);
++
++      return ret;
++}
++
++#else
++#include <linux/kfifo.h>
++#endif
++
++static inline void kfifo_vfree(struct kfifo *fifo)
++{
++      vfree(fifo->buffer);
++      kfree(fifo);
++}
++
++#endif /* __CI_EFRM_SYSDEP_LINUX_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource.h     2008-05-19 00:33:29.417841805 +0300
+@@ -0,0 +1,171 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains public API for VI resource.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_VI_RESOURCE_H__
++#define __CI_EFRM_VI_RESOURCE_H__
++
++#include <ci/efhw/efhw_types.h>
++#include <ci/efrm/resource.h>
++#include <ci/efrm/debug.h>
++
++struct vi_resource;
++
++/* Make these inline instead of macros for type checking */
++static inline struct vi_resource *
++efrm_to_vi_resource(struct efrm_resource *rs)
++{
++      EFRM_ASSERT(EFRM_RESOURCE_TYPE(rs->rs_handle) == EFRM_RESOURCE_VI);
++      return (struct vi_resource *) rs;
++}
++static inline struct
++efrm_resource *efrm_from_vi_resource(struct vi_resource *rs)
++{
++      return (struct efrm_resource *)rs;
++}
++
++#define EFAB_VI_RESOURCE_INSTANCE(virs) \
++    EFRM_RESOURCE_INSTANCE(efrm_from_vi_resource(virs)->rs_handle)
++
++#define EFAB_VI_RESOURCE_PRI_ARG(virs) \
++    EFRM_RESOURCE_PRI_ARG(efrm_from_vi_resource(virs)->rs_handle)
++
++extern int
++efrm_vi_resource_alloc(struct vi_resource *evq_virs,
++                     uint16_t vi_flags, int32_t evq_capacity,
++                     int32_t txq_capacity, int32_t rxq_capacity,
++                     uint8_t tx_q_tag, uint8_t rx_q_tag,
++                     struct vi_resource **virs_in_out,
++                     uint32_t *out_io_mmap_bytes,
++                     uint32_t *out_mem_mmap_bytes,
++                     uint32_t *out_txq_capacity,
++                     uint32_t *out_rxq_capacity);
++
++static inline void efrm_vi_resource_ref(struct vi_resource *virs)
++{
++      atomic_inc(&efrm_from_vi_resource(virs)->rs_ref_count);
++}
++
++/* efrm_vi_resource_free should be called only if
++ * __efrm_resource_ref_count_zero() returned true.
++ * The easiest way is to call efrm_vi_resource_release() */
++extern void efrm_vi_resource_free(struct vi_resource *virs);
++static inline void efrm_vi_resource_release(struct vi_resource *virs)
++{
++      unsigned id;
++      struct efrm_resource *rs = efrm_from_vi_resource(virs);
++
++      id = EFRM_RESOURCE_INSTANCE(rs->rs_handle);
++
++      if (atomic_dec_and_test(&rs->rs_ref_count)) {
++              if (__efrm_resource_ref_count_zero(EFRM_RESOURCE_VI, id)) {
++                      EFRM_ASSERT(EFRM_RESOURCE_INSTANCE(rs->rs_handle) ==
++                                  id);
++                      efrm_vi_resource_free(virs);
++              }
++      }
++}
++
++/*--------------------------------------------------------------------
++ *
++ * eventq handling
++ *
++ *--------------------------------------------------------------------*/
++
++/*! Reset an event queue and clear any associated timers */
++extern void efrm_eventq_reset(struct vi_resource *virs, int nic_index);
++
++/*! Register a kernel-level handler for the event queue.  This function is
++ * called whenever a timer expires, or whenever the event queue is woken
++ * but no thread is blocked on it.
++ *
++ * This function returns -EBUSY if a callback is already installed.
++ *
++ * \param rs      Event-queue resource
++ * \param handler Callback-handler
++ * \param arg     Argument to pass to callback-handler
++ * \return        Status code
++ */
++extern int
++efrm_eventq_register_callback(struct vi_resource *rs,
++                            void (*handler)(void *arg, int is_timeout,
++                                            struct efhw_nic *nic),
++                            void *arg);
++
++/*! Kill the kernel-level callback.
++ *
++ * This function stops the timer from running and unregisters the callback
++ * function.  It waits for any running timeout handlers to complete before
++ * returning.
++ *
++ * \param rs      Event-queue resource
++ * \return        Nothing
++ */
++extern void efrm_eventq_kill_callback(struct vi_resource *rs);
++
++/*! Ask the NIC to generate a wakeup when an event is next delivered. */
++extern void efrm_eventq_request_wakeup(struct vi_resource *rs,
++                                     unsigned current_ptr,
++                                     unsigned nic_index);
++
++/*! Register a kernel-level handler for flush completions.
++ * \TODO Currently, it is unsafe to install a callback more than once.
++ *
++ * \param rs      VI resource being flushed.
++ * \param handler Callback handler function.
++ * \param arg     Argument to be passed to handler.
++ */
++extern void
++efrm_vi_register_flush_callback(struct vi_resource *rs,
++                              void (*handler)(void *),
++                              void *arg);
++
++int efrm_vi_resource_flush_retry(struct vi_resource *virs);
++
++/*! Comment? */
++extern int efrm_pt_flush(struct vi_resource *);
++
++/*! Comment? */
++extern int efrm_pt_pace(struct vi_resource *, unsigned int val);
++
++uint32_t efrm_vi_rm_txq_bytes(struct vi_resource *virs
++                            /*,struct efhw_nic *nic */ );
++uint32_t efrm_vi_rm_rxq_bytes(struct vi_resource *virs
++                            /*,struct efhw_nic *nic */ );
++uint32_t efrm_vi_rm_evq_bytes(struct vi_resource *virs
++                            /*,struct efhw_nic *nic */ );
++
++#endif /* __CI_EFRM_VI_RESOURCE_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_manager.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_manager.h     2008-05-19 00:33:29.417841805 +0300
+@@ -0,0 +1,182 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains type definitions for VI resource.  These types
++ * may be used outside of the SFC resource driver, but such use is not
++ * recommended.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_DRIVER_EFAB_VI_RESOURCE_MANAGER_H__
++#define __CI_DRIVER_EFAB_VI_RESOURCE_MANAGER_H__
++
++#include <ci/efhw/common.h>
++#include <ci/efrm/vi_resource.h>
++#include <ci/efrm/nic_set.h>
++
++#define EFRM_VI_RM_DMA_QUEUE_COUNT 2
++#define EFRM_VI_RM_DMA_QUEUE_TX    0
++#define EFRM_VI_RM_DMA_QUEUE_RX    1
++
++/** Numbers of bits which can be set in the evq_state member of
++ * vi_resource_evq_info. */
++enum {
++  /** This bit is set if a wakeup has been requested on the NIC. */
++      VI_RESOURCE_EVQ_STATE_WAKEUP_PENDING,
++  /** This bit is set if the wakeup is valid for the sleeping
++   * process. */
++      VI_RESOURCE_EVQ_STATE_CALLBACK_REGISTERED,
++  /** This bit is set if a wakeup or timeout event is currently being
++   * processed. */
++      VI_RESOURCE_EVQ_STATE_BUSY,
++};
++#define VI_RESOURCE_EVQ_STATE(X) \
++      (((int32_t)1) << (VI_RESOURCE_EVQ_STATE_##X))
++
++/** Information about an event queue. */
++struct vi_resource_evq_info {
++  /** Flag bits indicating the state of wakeups. */
++      unsigned long evq_state;
++  /** A pointer to the resource instance for this queue.  This member
++   * is only valid if evq_state is non-zero or the resource is known
++   * to have a non-zero reference count. */
++      struct vi_resource *evq_virs;
++};
++
++#ifdef __ci_ul_driver__
++#define EFRM_VI_USE_WORKQUEUE 0
++#else
++#define EFRM_VI_USE_WORKQUEUE 1
++#endif
++
++/*! Global information for the VI resource manager. */
++struct vi_resource_manager {
++      struct efrm_resource_manager rm;
++
++      struct kfifo *instances_with_timer;
++      int with_timer_base;
++      int with_timer_limit;
++      struct kfifo *instances_with_interrupt;
++      int with_interrupt_base;
++      int with_interrupt_limit;
++
++      bool iscsi_dmaq_instance_is_free;
++      struct vi_resource_evq_info *evq_infos;
++
++      /* We keep VI resources which need flushing on these lists.  The VI
++       * is put on the outstanding list when the flush request is issued
++       * to the hardware and removed when the flush event arrives.  The
++       * hardware can only handle a limited number of RX flush requests at
++       * once, so VIs are placed in the waiting list until the flush can
++       * be issued.  Flushes can be requested by the client or internally
++       * by the VI resource manager.  In the former case, the reference
++       * count must be non-zero for the duration of the flush and in the
++       * later case, the reference count must be zero. */
++      struct list_head rx_flush_waiting_list;
++      struct list_head rx_flush_outstanding_list;
++      struct list_head tx_flush_outstanding_list;
++      int rx_flush_outstanding_count;
++
++      /* once the flush has happened we push the close into the work queue
++       * so its OK on Windows to free the resources (Bug 3469).  Resources
++       * on this list have zero reference count.
++       */
++      struct list_head close_pending;
++      struct work_struct work_item;
++#if EFRM_VI_USE_WORKQUEUE
++      struct workqueue_struct *workqueue;
++#endif
++};
++
++struct vi_resource_nic_info {
++      struct eventq_resource_hardware evq_pages;
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++      efhw_iopages_t dmaq_pages[EFRM_VI_RM_DMA_QUEUE_COUNT];
++#endif
++};
++
++struct vi_resource {
++      /* Some macros make the assumption that the struct efrm_resource is
++       * the first member of a struct vi_resource. */
++      struct efrm_resource rs;
++      atomic_t evq_refs;      /*!< Number of users of the event queue. */
++
++      efrm_nic_set_t nic_set;
++
++      uint32_t bar_mmap_bytes;
++      uint32_t mem_mmap_bytes;
++
++      int32_t evq_capacity;
++      int32_t dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_COUNT];
++
++      uint8_t dmaq_tag[EFRM_VI_RM_DMA_QUEUE_COUNT];
++      uint16_t flags;
++
++      /* we keep PT endpoints that have been destroyed on a list
++       * until we have seen their TX and RX DMAQs flush complete
++       * (see Bug 1217)
++       */
++      struct list_head rx_flush_link;
++      struct list_head tx_flush_link;
++      efrm_nic_set_t rx_flush_nic_set;
++      efrm_nic_set_t rx_flush_outstanding_nic_set;
++      efrm_nic_set_t tx_flush_nic_set;
++      uint64_t flush_time;
++      int flush_count;
++
++      void (*flush_callback_fn)(void *);
++      void *flush_callback_arg;
++
++      void (*evq_callback_fn) (void *arg, int is_timeout,
++                               struct efhw_nic *nic);
++      void *evq_callback_arg;
++
++      struct vi_resource *evq_virs;   /*!< EVQ for DMA queues */
++
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++       struct efhw_buffer_table_allocation
++          dmaq_buf_tbl_alloc[EFRM_VI_RM_DMA_QUEUE_COUNT];
++#endif
++
++      struct vi_resource_nic_info nic_info[EFHW_MAX_NR_DEVS];
++};
++
++#undef vi_resource
++#define vi_resource(rs1)  container_of((rs1), struct vi_resource, rs)
++
++static inline dma_addr_t
++efrm_eventq_dma_addr(struct vi_resource *virs, uint32_t nic_index)
++{
++      struct eventq_resource_hardware *hw;
++      EFRM_ASSERT(efrm_nic_set_read(&virs->nic_set, nic_index));
++
++      hw = &(virs->nic_info[nic_index].evq_pages);
++
++      return efhw_iopages_dma_addr(&(hw->iobuff)) + hw->iobuff_off;
++}
++
++#endif /* __CI_DRIVER_EFAB_VI_RESOURCE_MANAGER_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_private.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/ci/efrm/vi_resource_private.h     2008-05-19 00:33:29.417841805 +0300
+@@ -0,0 +1,83 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains private API for VI resource.  The API is not designed
++ * to be used outside of the SFC resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFRM_VI_RESOURCE_PRIVATE_H__
++#define __CI_EFRM_VI_RESOURCE_PRIVATE_H__
++
++#include <ci/efhw/common.h>
++#include <ci/efrm/vi_resource_manager.h>
++
++extern struct vi_resource_manager *efrm_vi_manager;
++
++/*************************************************************************/
++
++extern void efrm_vi_rm_delayed_free(struct work_struct *data);
++
++extern void efrm_vi_rm_salvage_flushed_vis(void);
++
++void efrm_vi_rm_free_flushed_resource(struct vi_resource *virs);
++
++void efrm_vi_rm_init_dmaq(struct vi_resource *virs, int queue_index,
++                        struct efhw_nic *nic);
++
++static inline int
++efrm_eventq_bytes(struct vi_resource *virs, uint32_t nic_index)
++{
++      EFRM_ASSERT(efrm_nic_set_read(&virs->nic_set, nic_index));
++
++      return efrm_vi_rm_evq_bytes(virs);
++}
++
++static inline efhw_event_t *
++efrm_eventq_base(struct vi_resource *virs, uint32_t nic_index)
++{
++      struct eventq_resource_hardware *hw;
++
++      EFRM_ASSERT(efrm_nic_set_read(&virs->nic_set, nic_index));
++
++      hw = &(virs->nic_info[nic_index].evq_pages);
++
++      return (efhw_event_t *) (efhw_iopages_ptr(&(hw->iobuff)) +
++                               hw->iobuff_off);
++}
++
++/*! Wakeup handler, see efhw_ev_handler_t for prototype */
++extern void efrm_handle_wakeup_event(struct efhw_nic *nic, efhw_event_t *ev);
++
++/*! Timeout handler, see efhw_ev_handler_t for prototype */
++extern void efrm_handle_timeout_event(struct efhw_nic *nic, efhw_event_t *ev);
++
++/*! DMA flush handler, see efhw_ev_handler_t for prototype */
++extern void efrm_handle_dmaq_flushed(struct efhw_nic *nic, int instance,
++                                 int rx_flush);
++
++#endif /* __CI_EFRM_VI_RESOURCE_PRIVATE_H__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/driver_object.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/driver_object.c   2008-05-19 00:33:29.417841805 +0300
+@@ -0,0 +1,174 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains support for the global driver variables.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efrm/nic_table.h>
++#include <ci/efrm/resource.h>
++#include <ci/efrm/debug.h>
++
++/* We use #define rather than static inline here so that the Windows
++ * "prefast" compiler can see its own locking primitive when these
++ * two function are used (and then perform extra checking where they
++ * are used)
++ *
++ * Both macros operate on an irq_flags_t
++*/
++
++#define efrm_driver_lock(irqlock_state) \
++      spin_lock_irqsave(&efrm_nic_table.lock, irqlock_state)
++
++#define efrm_driver_unlock(irqlock_state)             \
++      spin_unlock_irqrestore(&efrm_nic_table.lock,    \
++                             irqlock_state);
++
++/* These routines are all methods on the architecturally singleton
++   global variables: efrm_nic_table, efrm_rm_table.
++
++   I hope we never find a driver model that does not allow global
++   structure variables :) (but that would break almost every driver I've
++   ever seen).
++*/
++
++/*! Exported driver state */
++struct efrm_nic_table efrm_nic_table;
++EXPORT_SYMBOL(efrm_nic_table);
++
++/* Internal table with resource managers.
++ * We'd like to not export it, but we are still using efrm_rm_table
++ * in the char driver. So, it is declared in the private header with
++ * a purpose. */
++struct efrm_resource_manager *efrm_rm_table[EFRM_RESOURCE_NUM];
++EXPORT_SYMBOL(efrm_rm_table);
++
++int efrm_driver_ctor(void)
++{
++      memset(&efrm_nic_table, 0, sizeof(efrm_nic_table));
++      memset(&efrm_rm_table, 0, sizeof(efrm_rm_table));
++
++      spin_lock_init(&efrm_nic_table.lock);
++
++      EFRM_TRACE("%s: driver created", __FUNCTION__);
++      return 0;
++}
++
++int efrm_driver_dtor(void)
++{
++      EFRM_ASSERT(!efrm_nic_table_held());
++
++      spin_lock_destroy(&efrm_nic_table.lock);
++      EFRM_TRACE("%s: driver deleted", __FUNCTION__);
++      return 0;
++}
++
++int efrm_driver_register_nic(struct efhw_nic *nic, int nic_index)
++{
++      int rc = 0;
++      irq_flags_t lock_flags;
++
++      EFRM_ASSERT(nic_index >= 0);
++
++      efrm_driver_lock(lock_flags);
++
++      if (efrm_nic_table_held()) {
++              EFRM_WARN("%s: driver object is in use", __FUNCTION__);
++              rc = -EBUSY;
++              goto done;
++      }
++
++      if (efrm_nic_table.nic_count == EFHW_MAX_NR_DEVS) {
++              EFRM_WARN("%s: filled up NIC table size %d", __FUNCTION__,
++                        EFHW_MAX_NR_DEVS);
++              rc = -E2BIG;
++              goto done;
++      }
++
++      EFRM_ASSERT(efrm_nic_table.nic[nic_index] == NULL);
++      efrm_nic_table.nic[nic_index] = nic;
++      nic->index = nic_index;
++
++      if (efrm_nic_table.a_nic == NULL)
++              efrm_nic_table.a_nic = nic;
++
++      efrm_nic_table.nic_count++;
++      efrm_driver_unlock(lock_flags);
++      return rc;
++
++done:
++      efrm_driver_unlock(lock_flags);
++      return rc;
++}
++
++int efrm_driver_unregister_nic(struct efhw_nic *nic)
++{
++      int rc = 0;
++      int nic_index = nic->index;
++      irq_flags_t lock_flags;
++
++      EFRM_ASSERT(nic_index >= 0);
++
++      efrm_driver_lock(lock_flags);
++
++      if (efrm_nic_table_held()) {
++              EFRM_WARN("%s: driver object is in use", __FUNCTION__);
++              rc = -EBUSY;
++              goto done;
++      }
++
++      EFRM_ASSERT(efrm_nic_table.nic[nic_index] == nic);
++
++      nic->index = -1;
++      efrm_nic_table.nic[nic_index] = NULL;
++
++      --efrm_nic_table.nic_count;
++
++      if (efrm_nic_table.a_nic == nic) {
++              if (efrm_nic_table.nic_count == 0) {
++                      efrm_nic_table.a_nic = NULL;
++              } else {
++                      for (nic_index = 0; nic_index < EFHW_MAX_NR_DEVS;
++                           nic_index++) {
++                              if (efrm_nic_table.nic[nic_index] != NULL)
++                                      efrm_nic_table.a_nic =
++                                          efrm_nic_table.nic[nic_index];
++                      }
++                      EFRM_ASSERT(efrm_nic_table.a_nic);
++              }
++      }
++
++done:
++      efrm_driver_unlock(lock_flags);
++      return rc;
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/driverlink_new.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/driverlink_new.c  2008-05-19 00:33:29.421842036 +0300
+@@ -0,0 +1,290 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains driverlink code which interacts with the sfc network
++ * driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include "linux_resource_internal.h"
++#include "driverlink_api.h"
++#include "kernel_compat.h"
++#include <ci/efhw/falcon.h>
++
++#include <linux/rtnetlink.h>
++#include <linux/netdevice.h>
++
++/* The DL driver and associated calls */
++static int efrm_dl_probe(struct efx_dl_device *efrm_dev,
++                       const struct net_device *net_dev,
++                       const struct efx_dl_device_info *dev_info,
++                       const char *silicon_rev);
++
++static void efrm_dl_remove(struct efx_dl_device *efrm_dev);
++
++static void efrm_dl_reset_suspend(struct efx_dl_device *efrm_dev);
++
++static void efrm_dl_reset_resume(struct efx_dl_device *efrm_dev, int ok);
++
++static void efrm_dl_mtu_changed(struct efx_dl_device *, int);
++static void efrm_dl_event_falcon(struct efx_dl_device *efx_dev, void *p_event);
++
++static struct efx_dl_driver efrm_dl_driver = {
++      .name = "resource",
++      .probe = efrm_dl_probe,
++      .remove = efrm_dl_remove,
++      .reset_suspend = efrm_dl_reset_suspend,
++      .reset_resume = efrm_dl_reset_resume
++};
++
++static void
++init_vi_resource_dimensions(struct vi_resource_dimensions *rd,
++                          const struct efx_dl_falcon_resources *res)
++{
++      rd->evq_timer_min = res->evq_timer_min;
++      rd->evq_timer_max = res->evq_timer_max;
++      rd->evq_int_min = res->evq_int_min;
++      rd->evq_int_max = res->evq_int_max;
++      rd->rxq_min = res->rxq_min;
++      rd->rxq_max = res->rxq_max;
++      rd->txq_min = res->txq_min;
++      rd->txq_max = res->txq_max;
++      EFRM_TRACE
++          ("Using evq_int(%d-%d) evq_timer(%d-%d) RXQ(%d-%d) TXQ(%d-%d)",
++           res->evq_int_min, res->evq_int_max, res->evq_timer_min,
++           res->evq_timer_max, res->rxq_min, res->rxq_max, res->txq_min,
++           res->txq_max);
++}
++
++#if defined(EFX_NOT_UPSTREAM)
++/* We have a module parameter that can tell us to only load the char driver
++ * for 1 NIC (if there are multiple NICs in the system), and if so which one.
++ * This tells us the PCI bus and slot of the NIC to load for, or -1 to just
++ * load on all NICs (the default).
++ * Value is a hex number in the format
++ *   bbbbss
++ * where:
++ *   bbbb - PCI bus number
++ *   ss   - PCI slot number
++ */
++unsigned int only_NIC = -1;
++
++/** @ingroup module_params */
++module_param(only_NIC, uint, 0444);
++MODULE_PARM_DESC(only_NIC,
++               "Initialise sfc_resource driver for one NIC only, "
++               "with specified PCI bus and slot");
++#endif
++
++static int
++efrm_dl_probe(struct efx_dl_device *efrm_dev,
++            const struct net_device *net_dev,
++            const struct efx_dl_device_info *dev_info,
++            const char *silicon_rev)
++{
++      struct vi_resource_dimensions res_dim;
++      struct efx_dl_falcon_resources *res;
++      struct linux_efhw_nic *lnic;
++      struct pci_dev *dev;
++      struct efhw_nic *nic;
++      unsigned probe_flags = 0;
++      int rc;
++
++      efrm_dev->priv = NULL;
++
++      efx_dl_for_each_device_info_matching(dev_info, EFX_DL_FALCON_RESOURCES,
++                                           struct efx_dl_falcon_resources,
++                                           hdr, res) {
++              /* break out, leaving res pointing at the falcon resources */
++              break;
++      }
++
++      if (res == NULL) {
++              EFRM_ERR("%s: Unable to find falcon driverlink resources",
++                       __FUNCTION__);
++              return -EINVAL;
++      }
++
++      if (res->flags & EFX_DL_FALCON_USE_MSI)
++              probe_flags |= NIC_FLAG_TRY_MSI;
++
++      dev = efrm_dev->pci_dev;
++      if (res->flags & EFX_DL_FALCON_DUAL_FUNC) {
++              unsigned vendor = dev->vendor;
++              EFRM_ASSERT(dev->bus != NULL);
++              dev = NULL;
++
++#if defined(EFX_NOT_UPSTREAM)
++              if (only_NIC != -1 &&
++                  (efrm_dev->pci_dev->bus->number !=
++                   ((only_NIC >> 8) & 0xFFFF)
++                   || PCI_SLOT(efrm_dev->pci_dev->devfn) !=
++                   (only_NIC & 0xFF))) {
++                      EFRM_NOTICE("Hiding char device %x:%x",
++                                  efrm_dev->pci_dev->bus->number,
++                                  PCI_SLOT(efrm_dev->pci_dev->devfn));
++                      return -ENODEV;
++              }
++#endif
++
++              while ((dev = pci_get_device(vendor, FALCON_S_DEVID, dev))
++                     != NULL) {
++                      EFRM_ASSERT(dev->bus != NULL);
++                      /* With PCIe (since it's point to point)
++                       * the slot ID is usually 0 and
++                       * the bus ID changes NIC to NIC, so we really
++                       * need to check both. */
++                      if (PCI_SLOT(dev->devfn) ==
++                          PCI_SLOT(efrm_dev->pci_dev->devfn)
++                          && dev->bus->number ==
++                          efrm_dev->pci_dev->bus->number)
++                              break;
++              }
++              if (dev == NULL) {
++                      EFRM_ERR("%s: Unable to find falcon secondary "
++                               "PCI device.", __FUNCTION__);
++                      return -ENODEV;
++              }
++              pci_dev_put(dev);
++      }
++
++      init_vi_resource_dimensions(&res_dim, res);
++
++      rc = efrm_nic_add(dev, probe_flags, net_dev->dev_addr, &lnic,
++                        res->biu_lock,
++                        res->buffer_table_min, res->buffer_table_max,
++                        &res_dim);
++      if (rc != 0)
++              return rc;
++
++      nic = &lnic->nic;
++      nic->mtu = net_dev->mtu + ETH_HLEN;
++      nic->net_driver_dev = efrm_dev;
++      nic->ifindex = net_dev->ifindex;
++#ifdef HAS_NET_NAMESPACE
++      nic->nd_net = net_dev->nd_net;
++#endif
++      efrm_dev->priv = nic;
++
++      /* Register a callback so we're told when MTU changes.
++       * We dynamically allocate efx_dl_callbacks, because
++       * the callbacks that we want depends on the NIC type.
++       */
++      lnic->dl_callbacks =
++          kmalloc(sizeof(struct efx_dl_callbacks), GFP_KERNEL);
++      if (!lnic->dl_callbacks) {
++              EFRM_ERR("Out of memory (%s)", __FUNCTION__);
++              efrm_nic_del(lnic);
++              return -ENOMEM;
++      }
++      memset(lnic->dl_callbacks, 0, sizeof(*lnic->dl_callbacks));
++      lnic->dl_callbacks->mtu_changed = efrm_dl_mtu_changed;
++
++      if ((res->flags & EFX_DL_FALCON_DUAL_FUNC) == 0) {
++              /* Net driver receives all management events.
++               * Register a callback to receive the ones
++               * we're interested in. */
++              lnic->dl_callbacks->event = efrm_dl_event_falcon;
++      }
++
++      rc = efx_dl_register_callbacks(efrm_dev, lnic->dl_callbacks);
++      if (rc < 0) {
++              EFRM_ERR("%s: efx_dl_register_callbacks failed (%d)",
++                       __FUNCTION__, rc);
++              kfree(lnic->dl_callbacks);
++              efrm_nic_del(lnic);
++              return rc;
++      }
++
++      return 0;
++}
++
++/* When we unregister ourselves on module removal, this function will be
++ * called for all the devices we claimed */
++static void efrm_dl_remove(struct efx_dl_device *efrm_dev)
++{
++      struct efhw_nic *nic = efrm_dev->priv;
++      struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
++      EFRM_TRACE("%s called", __FUNCTION__);
++      if (lnic->dl_callbacks) {
++              efx_dl_unregister_callbacks(efrm_dev, lnic->dl_callbacks);
++              kfree(lnic->dl_callbacks);
++      }
++      if (efrm_dev->priv)
++              efrm_nic_del(lnic);
++      EFRM_TRACE("%s OK", __FUNCTION__);
++}
++
++static void efrm_dl_reset_suspend(struct efx_dl_device *efrm_dev)
++{
++      EFRM_NOTICE("%s:", __FUNCTION__);
++}
++
++static void efrm_dl_reset_resume(struct efx_dl_device *efrm_dev, int ok)
++{
++      EFRM_NOTICE("%s: ok=%d", __FUNCTION__, ok);
++}
++
++int efrm_driverlink_register(void)
++{
++      EFRM_TRACE("%s:", __FUNCTION__);
++      return efx_dl_register_driver(&efrm_dl_driver);
++}
++
++void efrm_driverlink_unregister(void)
++{
++      EFRM_TRACE("%s:", __FUNCTION__);
++      efx_dl_unregister_driver(&efrm_dl_driver);
++}
++
++static void efrm_dl_mtu_changed(struct efx_dl_device *efx_dev, int mtu)
++{
++      struct efhw_nic *nic = efx_dev->priv;
++
++      ASSERT_RTNL();  /* Since we're looking at efx_dl_device::port_net_dev */
++
++      EFRM_TRACE("%s: old=%d new=%d", __FUNCTION__, nic->mtu, mtu + ETH_HLEN);
++      /* If this happened we must have agreed to it above */
++      nic->mtu = mtu + ETH_HLEN;
++}
++
++static void efrm_dl_event_falcon(struct efx_dl_device *efx_dev, void *p_event)
++{
++      struct efhw_nic *nic = efx_dev->priv;
++      struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
++      efhw_event_t *ev = p_event;
++
++      switch (FALCON_EVENT_CODE(ev)) {
++      case FALCON_EVENT_CODE_CHAR:
++              falcon_handle_char_event(nic, lnic->ev_handlers, ev);
++              break;
++      default:
++              EFRM_WARN("%s: unknown event type=%x", __FUNCTION__,
++                        (unsigned)FALCON_EVENT_CODE(ev));
++              break;
++      }
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/efx_vi_shm.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/efx_vi_shm.c      2008-05-19 00:33:29.421842036 +0300
+@@ -0,0 +1,701 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides implementation of EFX VI API, used from Xen
++ * acceleration driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include "linux_resource_internal.h"
++#include <ci/efrm/nic_table.h>
++#include <ci/efrm/vi_resource_manager.h>
++#include <ci/driver/resource/efx_vi.h>
++#include <ci/efrm/filter.h>
++#include <ci/efrm/buffer_table.h>
++#include <linux/pci.h>
++#include "kernel_compat.h"
++
++#if EFX_VI_STATIC_FILTERS
++struct filter_list_t {
++      struct filter_list_t *next;
++      struct filter_resource *fres;
++};
++#endif
++
++struct efx_vi_state {
++      struct vi_resource *vi_res;
++
++      int nic_index;
++
++      void (*callback_fn)(void *arg, int is_timeout);
++      void *callback_arg;
++
++      struct completion flush_completion;
++
++#if EFX_VI_STATIC_FILTERS
++      struct filter_list_t fres[EFX_VI_STATIC_FILTERS];
++      struct filter_list_t *free_fres;
++      struct filter_list_t *used_fres;
++#endif
++};
++
++static void efx_vi_flush_complete(void *state_void)
++{
++      struct efx_vi_state *state = (struct efx_vi_state *)state_void;
++
++      complete(&state->flush_completion);
++}
++
++static inline int alloc_ep(struct efx_vi_state *state)
++{
++      int rc;
++
++      rc = efrm_vi_resource_alloc(NULL, EFHW_VI_JUMBO_EN,
++                                  efx_vi_eventq_size,
++                                  FALCON_DMA_Q_DEFAULT_TX_SIZE,
++                                  FALCON_DMA_Q_DEFAULT_RX_SIZE,
++                                  0, 0, &state->vi_res, NULL, NULL, NULL,
++                                  NULL);
++      if (rc < 0) {
++              EFRM_ERR("%s: ERROR efrm_vi_resource_alloc error %d",
++                       __FUNCTION__, rc);
++              return rc;
++      }
++
++      efrm_vi_register_flush_callback(state->vi_res, &efx_vi_flush_complete,
++                                      (void *)state);
++
++      return 0;
++}
++
++static int free_ep(struct efx_vi_state *efx_state)
++{
++      efrm_vi_resource_release(efx_state->vi_res);
++
++      return 0;
++}
++
++#if EFX_VI_STATIC_FILTERS
++static int efx_vi_alloc_static_filters(struct efx_vi_state *efx_state)
++{
++      int i;
++      int rc;
++
++      efx_state->free_fres = efx_state->used_fres = NULL;
++
++      for (i = 0; i < EFX_VI_STATIC_FILTERS; i++) {
++              rc = efrm_filter_resource_alloc(efx_state->vi_res,
++                                              &efx_state->fres[i].fres);
++              if (rc < 0) {
++                      EFRM_ERR("%s: efrm_filter_resource_alloc failed: %d",
++                           __FUNCTION__, rc);
++                      while (i > 0) {
++                              i--;
++                              efrm_filter_resource_release(efx_state->
++                                                           fres[i].fres);
++                      }
++                      efx_state->free_fres = NULL;
++                      return rc;
++              }
++              efx_state->fres[i].next = efx_state->free_fres;
++              efx_state->free_fres = &efx_state->fres[i];
++      }
++
++      return 0;
++}
++#endif
++
++int efx_vi_alloc(struct efx_vi_state **vih_out, int nic_index)
++{
++      struct efx_vi_state *efx_state;
++      int rc;
++
++      BUG_ON(nic_index < 0 || nic_index >= EFHW_MAX_NR_DEVS);
++
++      efx_state = kmalloc(sizeof(struct efx_vi_state), GFP_KERNEL);
++
++      if (!efx_state) {
++              EFRM_ERR("%s: failed to allocate memory for efx_vi_state",
++                       __FUNCTION__);
++              rc = -ENOMEM;
++              goto fail;
++      }
++
++      efx_state->nic_index = nic_index;
++      init_completion(&efx_state->flush_completion);
++
++      /* basically allocate_pt_endpoint() */
++      rc = alloc_ep(efx_state);
++      if (rc) {
++              EFRM_ERR("%s: alloc_ep failed: %d", __FUNCTION__, rc);
++              goto fail_no_pt;
++      }
++#if EFX_VI_STATIC_FILTERS
++      /* Statically allocate a set of filter resources - removes the
++         restriction on not being able to use efx_vi_filter() from
++         in_atomic() */
++      rc = efx_vi_alloc_static_filters(efx_state);
++      if (rc)
++              goto fail_no_filters;
++#endif
++
++      *vih_out = efx_state;
++
++      return 0;
++#if EFX_VI_STATIC_FILTERS
++fail_no_filters:
++      free_ep(efx_state);
++#endif
++fail_no_pt:
++      kfree(efx_state);
++fail:
++      return rc;
++}
++EXPORT_SYMBOL(efx_vi_alloc);
++
++void efx_vi_free(struct efx_vi_state *vih)
++{
++      struct efx_vi_state *efx_state = vih;
++
++      /* TODO flush dma channels, init dma queues?.  See ef_free_vnic() */
++#if EFX_VI_STATIC_FILTERS
++      int i;
++
++      for (i = 0; i < EFX_VI_STATIC_FILTERS; i++)
++              efrm_filter_resource_release(efx_state->fres[i].fres);
++#endif
++
++      if (efx_state->vi_res)
++              free_ep(efx_state);
++
++      kfree(efx_state);
++}
++EXPORT_SYMBOL(efx_vi_free);
++
++void efx_vi_reset(struct efx_vi_state *vih)
++{
++      struct efx_vi_state *efx_state = vih;
++
++      efrm_pt_flush(efx_state->vi_res);
++
++      while (wait_for_completion_timeout(&efx_state->flush_completion, HZ)
++             == 0)
++              efrm_vi_resource_flush_retry(efx_state->vi_res);
++
++      /* Bosch the eventq */
++      efrm_eventq_reset(efx_state->vi_res, 0);
++      return;
++}
++EXPORT_SYMBOL(efx_vi_reset);
++
++static void
++efx_vi_eventq_callback(void *context, int is_timeout, struct efhw_nic *nic)
++{
++      struct efx_vi_state *efx_state = (struct efx_vi_state *)context;
++
++      EFRM_ASSERT(efx_state->callback_fn);
++
++      return efx_state->callback_fn(efx_state->callback_arg, is_timeout);
++}
++
++int
++efx_vi_eventq_register_callback(struct efx_vi_state *vih,
++                      void (*callback)(void *context, int is_timeout),
++                      void *context)
++{
++      struct efx_vi_state *efx_state = vih;
++
++      efx_state->callback_fn = callback;
++      efx_state->callback_arg = context;
++
++      /* Register the eventq timeout event callback */
++      efrm_eventq_register_callback(efx_state->vi_res,
++                                    efx_vi_eventq_callback, efx_state);
++
++      return 0;
++}
++EXPORT_SYMBOL(efx_vi_eventq_register_callback);
++
++int efx_vi_eventq_kill_callback(struct efx_vi_state *vih)
++{
++      struct efx_vi_state *efx_state = vih;
++
++      if (efx_state->vi_res->evq_callback_fn)
++              efrm_eventq_kill_callback(efx_state->vi_res);
++
++      efx_state->callback_fn = NULL;
++      efx_state->callback_arg = NULL;
++
++      return 0;
++}
++EXPORT_SYMBOL(efx_vi_eventq_kill_callback);
++
++struct efx_vi_dma_map_state {
++      struct efhw_buffer_table_allocation bt_handle;
++      int n_pages;
++      dma_addr_t *dma_addrs;
++};
++
++int
++efx_vi_dma_map_pages(struct efx_vi_state *vih, struct page **pages,
++                   int n_pages, struct efx_vi_dma_map_state **dmh_out)
++{
++      struct efx_vi_state *efx_state = vih;
++      int order = fls(n_pages - 1), rc, i, evq_id;
++      dma_addr_t dma_addr;
++      struct efx_vi_dma_map_state *dm_state;
++
++      if (n_pages != (1 << order)) {
++              EFRM_WARN("%s: Can only allocate buffers in power of 2 "
++                        "sizes (not %d)", __FUNCTION__, n_pages);
++              return -EINVAL;
++      }
++
++      dm_state = kmalloc(sizeof(struct efx_vi_dma_map_state), GFP_KERNEL);
++      if (!dm_state)
++              return -ENOMEM;
++
++      dm_state->dma_addrs = kmalloc(sizeof(dma_addr_t) * n_pages,
++                                    GFP_KERNEL);
++      if (!dm_state->dma_addrs) {
++              kfree(dm_state);
++              return -ENOMEM;
++      }
++
++      rc = efrm_buffer_table_alloc(order, &dm_state->bt_handle);
++      if (rc < 0) {
++              kfree(dm_state->dma_addrs);
++              kfree(dm_state);
++              return rc;
++      }
++
++      evq_id = EFRM_RESOURCE_INSTANCE(efx_state->vi_res->rs.rs_handle);
++      for (i = 0; i < n_pages; i++) {
++              /* TODO do we need to get_page() here ? */
++
++              dma_addr = pci_map_page
++                  (linux_efhw_nic(efrm_nic_table.nic[efx_state->nic_index])->
++                   pci_dev, pages[i], 0, PAGE_SIZE, PCI_DMA_TODEVICE);
++
++              efrm_buffer_table_set(&dm_state->bt_handle, i, dma_addr,
++                                    evq_id);
++
++              dm_state->dma_addrs[i] = dma_addr;
++
++              /* Would be nice to not have to call commit each time, but
++               * comment says there are hardware restrictions on how often
++               * you can go without it, so do this to be safe */
++              efrm_buffer_table_commit();
++      }
++
++      dm_state->n_pages = n_pages;
++
++      *dmh_out = dm_state;
++
++      return 0;
++}
++EXPORT_SYMBOL(efx_vi_dma_map_pages);
++
++/* Function needed as Xen can't get pages for grants in dom0, but can
++   get dma address */
++int
++efx_vi_dma_map_addrs(struct efx_vi_state *vih,
++                   unsigned long long *bus_dev_addrs,
++                   int n_pages, struct efx_vi_dma_map_state **dmh_out)
++{
++      struct efx_vi_state *efx_state = vih;
++      int order = fls(n_pages - 1), rc, i, evq_id;
++      dma_addr_t dma_addr;
++      struct efx_vi_dma_map_state *dm_state;
++
++      if (n_pages != (1 << order)) {
++              EFRM_WARN("%s: Can only allocate buffers in power of 2 "
++                        "sizes (not %d)", __FUNCTION__, n_pages);
++              return -EINVAL;
++      }
++
++      dm_state = kmalloc(sizeof(struct efx_vi_dma_map_state), GFP_KERNEL);
++      if (!dm_state)
++              return -ENOMEM;
++
++      dm_state->dma_addrs = kmalloc(sizeof(dma_addr_t) * n_pages,
++                                    GFP_KERNEL);
++      if (!dm_state->dma_addrs) {
++              kfree(dm_state);
++              return -ENOMEM;
++      }
++
++      rc = efrm_buffer_table_alloc(order, &dm_state->bt_handle);
++      if (rc < 0) {
++              kfree(dm_state->dma_addrs);
++              kfree(dm_state);
++              return rc;
++      }
++
++      evq_id = EFRM_RESOURCE_INSTANCE(efx_state->vi_res->rs.rs_handle);
++#if 0
++      EFRM_WARN("%s: mapping %d pages to evq %d, bt_ids %d-%d\n",
++                __FUNCTION__, n_pages, evq_id,
++                dm_state->bt_handle.base,
++                dm_state->bt_handle.base + n_pages);
++#endif
++      for (i = 0; i < n_pages; i++) {
++
++              dma_addr = (dma_addr_t)bus_dev_addrs[i];
++
++              efrm_buffer_table_set(&dm_state->bt_handle, i, dma_addr,
++                                    evq_id);
++
++              dm_state->dma_addrs[i] = dma_addr;
++
++              /* Would be nice to not have to call commit each time, but
++               * comment says there are hardware restrictions on how often
++               * you can go without it, so do this to be safe */
++              efrm_buffer_table_commit();
++      }
++
++      dm_state->n_pages = n_pages;
++
++      *dmh_out = dm_state;
++
++      return 0;
++}
++EXPORT_SYMBOL(efx_vi_dma_map_addrs);
++
++void
++efx_vi_dma_unmap_pages(struct efx_vi_state *vih,
++                     struct efx_vi_dma_map_state *dmh)
++{
++      struct efx_vi_state *efx_state = vih;
++      struct efx_vi_dma_map_state *dm_state =
++          (struct efx_vi_dma_map_state *)dmh;
++      int i;
++
++      efrm_buffer_table_free(&dm_state->bt_handle);
++
++      for (i = 0; i < dm_state->n_pages; ++i)
++              pci_unmap_page(linux_efhw_nic
++                      (efrm_nic_table.nic[efx_state->nic_index])->pci_dev,
++                      dm_state->dma_addrs[i], PAGE_SIZE, PCI_DMA_TODEVICE);
++
++      kfree(dm_state->dma_addrs);
++      kfree(dm_state);
++
++      return;
++}
++EXPORT_SYMBOL(efx_vi_dma_unmap_pages);
++
++void
++efx_vi_dma_unmap_addrs(struct efx_vi_state *vih,
++                     struct efx_vi_dma_map_state *dmh)
++{
++      struct efx_vi_dma_map_state *dm_state =
++          (struct efx_vi_dma_map_state *)dmh;
++
++      efrm_buffer_table_free(&dm_state->bt_handle);
++
++      kfree(dm_state->dma_addrs);
++      kfree(dm_state);
++
++      return;
++}
++EXPORT_SYMBOL(efx_vi_dma_unmap_addrs);
++
++unsigned
++efx_vi_dma_get_map_addr(struct efx_vi_state *vih,
++                      struct efx_vi_dma_map_state *dmh)
++{
++      struct efx_vi_dma_map_state *dm_state =
++          (struct efx_vi_dma_map_state *)dmh;
++
++      return EFHW_BUFFER_ADDR(dm_state->bt_handle.base, 0);
++}
++EXPORT_SYMBOL(efx_vi_dma_get_map_addr);
++
++#if EFX_VI_STATIC_FILTERS
++static int
++get_filter(struct efx_vi_state *efx_state,
++         efrm_resource_handle_t pthandle, struct filter_resource **fres_out)
++{
++      struct filter_list_t *flist;
++      if (efx_state->free_fres == NULL)
++              return -ENOMEM;
++      else {
++              flist = efx_state->free_fres;
++              efx_state->free_fres = flist->next;
++              flist->next = efx_state->used_fres;
++              efx_state->used_fres = flist;
++              *fres_out = flist->fres;
++              return 0;
++      }
++}
++#endif
++
++static void
++release_filter(struct efx_vi_state *efx_state, struct filter_resource *fres)
++{
++#if EFX_VI_STATIC_FILTERS
++      struct filter_list_t *flist = efx_state->used_fres, *prev = NULL;
++      while (flist) {
++              if (flist->fres == fres) {
++                      if (prev)
++                              prev->next = flist->next;
++                      else
++                              efx_state->used_fres = flist->next;
++                      flist->next = efx_state->free_fres;
++                      efx_state->free_fres = flist;
++                      return;
++              }
++              prev = flist;
++              flist = flist->next;
++      }
++      EFRM_ERR("%s: couldn't find filter", __FUNCTION__);
++#else
++      return efrm_filter_resource_release(fres);
++#endif
++}
++
++int
++efx_vi_filter(struct efx_vi_state *vih, int protocol,
++            unsigned ip_addr_be32, int port_le16,
++            struct filter_resource_t **fh_out)
++{
++      struct efx_vi_state *efx_state = vih;
++      struct filter_resource *frs;
++      int rc;
++
++#if EFX_VI_STATIC_FILTERS
++      rc = get_filter(efx_state, efx_state->vi_res->rs.rs_handle, &frs);
++#else
++      rc = efrm_filter_resource_alloc(efx_state->vi_res, &frs);
++#endif
++      if (rc < 0)
++              return rc;
++
++      /* Add the hardware filter. We pass in the source port and address
++       * as 0 (wildcard) to minimise the number of filters needed. */
++      if (protocol == IPPROTO_TCP) {
++              rc = efrm_filter_resource_tcp_set(frs, 0, 0, ip_addr_be32,
++                                                port_le16);
++      } else {
++              rc = efrm_filter_resource_udp_set(frs, 0, 0, ip_addr_be32,
++                                                port_le16);
++      }
++
++      *fh_out = (struct filter_resource_t *)frs;
++
++      return rc;
++}
++EXPORT_SYMBOL(efx_vi_filter);
++
++int
++efx_vi_filter_stop(struct efx_vi_state *vih, struct filter_resource_t *fh)
++{
++      struct efx_vi_state *efx_state = vih;
++      struct filter_resource *frs = (struct filter_resource *)fh;
++      int rc;
++
++      rc = efrm_filter_resource_clear(frs);
++      release_filter(efx_state, frs);
++
++      return rc;
++}
++EXPORT_SYMBOL(efx_vi_filter_stop);
++
++int
++efx_vi_hw_resource_get_virt(struct efx_vi_state *vih,
++                          struct efx_vi_hw_resource_metadata *mdata,
++                          struct efx_vi_hw_resource *hw_res_array,
++                          int *length)
++{
++      EFRM_NOTICE("%s: TODO!", __FUNCTION__);
++
++      return 0;
++}
++EXPORT_SYMBOL(efx_vi_hw_resource_get_virt);
++
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++int
++efx_vi_hw_resource_get_phys(struct efx_vi_state *vih,
++                          struct efx_vi_hw_resource_metadata *mdata,
++                          struct efx_vi_hw_resource *hw_res_array,
++                          int *length)
++{
++      struct efx_vi_state *efx_state = vih;
++      int i, ni = efx_state->nic_index;
++      struct linux_efhw_nic *lnic = linux_efhw_nic(efrm_nic_table.nic[ni]);
++      unsigned long phys = lnic->ctr_ap_pci_addr;
++      struct efrm_resource *ep_res = &efx_state->vi_res->rs;
++      unsigned ep_mmap_bytes;
++
++      if (*length < EFX_VI_HW_RESOURCE_MAXSIZE)
++              return -EINVAL;
++
++      mdata->version = 0;
++
++      mdata->nic_arch = efrm_nic_table.nic[ni]->devtype.arch;
++      mdata->nic_variant = efrm_nic_table.nic[ni]->devtype.variant;
++      mdata->nic_revision = efrm_nic_table.nic[ni]->devtype.revision;
++
++      mdata->evq_order =
++          efx_state->vi_res->nic_info[ni].evq_pages.iobuff.order;
++      mdata->evq_offs = efx_state->vi_res->nic_info[ni].evq_pages.iobuff_off;
++      mdata->evq_capacity = efx_vi_eventq_size;
++      mdata->instance = EFRM_RESOURCE_INSTANCE(ep_res->rs_handle);
++      mdata->rx_capacity = FALCON_DMA_Q_DEFAULT_RX_SIZE;
++      mdata->tx_capacity = FALCON_DMA_Q_DEFAULT_TX_SIZE;
++
++      ep_mmap_bytes = FALCON_DMA_Q_DEFAULT_MMAP;
++      EFRM_ASSERT(ep_mmap_bytes == PAGE_SIZE * 2);
++
++#ifndef NDEBUG
++      {
++              /* Sanity about doorbells */
++              unsigned long tx_dma_page_addr, rx_dma_page_addr;
++
++              /* get rx doorbell address */
++              rx_dma_page_addr =
++                  phys + falcon_rx_dma_page_addr(mdata->instance);
++              /* get tx doorbell address */
++              tx_dma_page_addr =
++                  phys + falcon_tx_dma_page_addr(mdata->instance);
++
++              /* Check the lower bits of the TX doorbell will be
++               * consistent. */
++              EFRM_ASSERT((TX_DESC_UPD_REG_PAGE4_OFST &
++                           FALCON_DMA_PAGE_MASK) ==
++                          (TX_DESC_UPD_REG_PAGE123K_OFST &
++                           FALCON_DMA_PAGE_MASK));
++
++              /* Check the lower bits of the RX doorbell will be
++               * consistent. */
++              EFRM_ASSERT((RX_DESC_UPD_REG_PAGE4_OFST &
++                           FALCON_DMA_PAGE_MASK) ==
++                          (RX_DESC_UPD_REG_PAGE123K_OFST &
++                           FALCON_DMA_PAGE_MASK));
++
++              /* Check that the doorbells will be in the same page. */
++              EFRM_ASSERT((TX_DESC_UPD_REG_PAGE4_OFST & PAGE_MASK) ==
++                          (RX_DESC_UPD_REG_PAGE4_OFST & PAGE_MASK));
++
++              /* Check that the doorbells are in the same page. */
++              EFRM_ASSERT((tx_dma_page_addr & PAGE_MASK) ==
++                          (rx_dma_page_addr & PAGE_MASK));
++
++              /* Check that the TX doorbell offset is correct. */
++              EFRM_ASSERT((TX_DESC_UPD_REG_PAGE4_OFST & ~PAGE_MASK) ==
++                          (tx_dma_page_addr & ~PAGE_MASK));
++
++              /* Check that the RX doorbell offset is correct. */
++              EFRM_ASSERT((RX_DESC_UPD_REG_PAGE4_OFST & ~PAGE_MASK) ==
++                          (rx_dma_page_addr & ~PAGE_MASK));
++      }
++#endif
++
++      i = 0;
++      hw_res_array[i].type = EFX_VI_HW_RESOURCE_TXDMAQ;
++      hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
++      hw_res_array[i].more_to_follow = 0;
++      hw_res_array[i].length = PAGE_SIZE;
++      hw_res_array[i].address =
++              (unsigned long)efx_state->vi_res->nic_info[ni].
++                      dmaq_pages[EFRM_VI_RM_DMA_QUEUE_TX].kva;
++
++      i++;
++      hw_res_array[i].type = EFX_VI_HW_RESOURCE_RXDMAQ;
++      hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
++      hw_res_array[i].more_to_follow = 0;
++      hw_res_array[i].length = PAGE_SIZE;
++      hw_res_array[i].address =
++              (unsigned long)efx_state->vi_res->nic_info[ni].
++                      dmaq_pages[EFRM_VI_RM_DMA_QUEUE_RX].kva;
++
++      /* NB EFX_VI_HW_RESOURCE_TXBELL not used on Falcon */
++      /* NB EFX_VI_HW_RESOURCE_RXBELL not used on Falcon */
++
++      i++;
++      hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQTIMER;
++      hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
++      hw_res_array[i].more_to_follow = 0;
++      hw_res_array[i].length = PAGE_SIZE;
++      hw_res_array[i].address =
++              (unsigned long)phys + falcon_timer_page_addr(mdata->instance);
++
++      /* NB EFX_VI_HW_RESOURCE_EVQPTR not used on Falcon */
++
++      i++;
++      switch (efrm_nic_table.nic[ni]->devtype.variant) {
++      case 'A':
++              hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQRPTR;
++              hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
++              hw_res_array[i].more_to_follow = 0;
++              hw_res_array[i].length = PAGE_SIZE;
++              hw_res_array[i].address = (unsigned long)phys +
++                      EVQ_RPTR_REG_OFST +
++                      (FALCON_REGISTER128 * mdata->instance);
++              break;
++      case 'B':
++              hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQRPTR_OFFSET;
++              hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
++              hw_res_array[i].more_to_follow = 0;
++              hw_res_array[i].length = PAGE_SIZE;
++              hw_res_array[i].address =
++                      (unsigned long)FALCON_EVQ_RPTR_REG_P0;
++              break;
++      default:
++              EFRM_ASSERT(0);
++              break;
++      }
++
++      i++;
++      hw_res_array[i].type = EFX_VI_HW_RESOURCE_EVQMEMKVA;
++      hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_IOBUFFER;
++      hw_res_array[i].more_to_follow = 0;
++      hw_res_array[i].length = PAGE_SIZE;
++      hw_res_array[i].address = (unsigned long)efx_state->vi_res->
++              nic_info[ni].evq_pages.iobuff.kva;
++
++      i++;
++      hw_res_array[i].type = EFX_VI_HW_RESOURCE_BELLPAGE;
++      hw_res_array[i].mem_type = EFX_VI_HW_RESOURCE_PERIPHERAL;
++      hw_res_array[i].more_to_follow = 0;
++      hw_res_array[i].length = PAGE_SIZE;
++      hw_res_array[i].address =
++              (unsigned long)(phys +
++                              falcon_tx_dma_page_addr(mdata->instance))
++              >> PAGE_SHIFT;
++
++      i++;
++
++      EFRM_ASSERT(i <= *length);
++
++      *length = i;
++
++      return 0;
++}
++EXPORT_SYMBOL(efx_vi_hw_resource_get_phys);
++#endif
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/eventq.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/eventq.c  2008-05-19 00:33:29.421842036 +0300
+@@ -0,0 +1,320 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains event queue support.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efhw/debug.h>
++#include <ci/efhw/iopage.h>
++#include <ci/driver/efab/hardware.h>
++#include <ci/efhw/eventq.h>
++#include <ci/efhw/falcon.h>
++#include <ci/efhw/nic.h>
++
++#define KEVENTQ_MAGIC 0x07111974
++
++/*! Helper function to allocate the iobuffer needed by an eventq
++ *   - it ensures the eventq has the correct alignment for the NIC
++ *
++ * \param rm        Event-queue resource manager
++ * \param instance  Event-queue instance (index)
++ * \param buf_bytes Requested size of eventq
++ * \return          < 0 if iobuffer allocation fails
++ */
++int
++efhw_nic_event_queue_alloc_iobuffer(struct efhw_nic *nic,
++                                  struct eventq_resource_hardware *h,
++                                  int evq_instance, unsigned buf_bytes)
++{
++      unsigned int page_order;
++      int rc;
++
++      /* Allocate an iobuffer. */
++      page_order = get_order(buf_bytes);
++
++      h->iobuff_off = 0;
++
++      EFHW_TRACE("allocating eventq size %x",
++                 1u << (page_order + PAGE_SHIFT));
++      rc = efhw_iopages_alloc(nic, &h->iobuff, page_order);
++      if (rc < 0) {
++              EFHW_WARN("%s: failed to allocate %u pages",
++                        __FUNCTION__, 1u << page_order);
++              return rc;
++      }
++
++      /* Set the eventq pages to match EFHW_CLEAR_EVENT() */
++      if (EFHW_CLEAR_EVENT_VALUE)
++              memset(efhw_iopages_ptr(&h->iobuff) + h->iobuff_off,
++                     EFHW_CLEAR_EVENT_VALUE, (1u << page_order) * PAGE_SIZE);
++
++      EFHW_TRACE("%s: allocated %u pages", __FUNCTION__, 1u << (page_order));
++
++      /* For Falcon the NIC is programmed with the base buffer address of a
++       * contiguous region of buffer space. This means that larger than a
++       * PAGE event queues can be expected to allocate even when the host's
++       * physical memory is fragmented */
++      EFHW_ASSERT(efhw_nic_have_hw(nic));
++      EFHW_ASSERT(page_order <= h->buf_tbl_alloc.order);
++
++      /* Initialise the buffer table entries. */
++      falcon_nic_buffer_table_set_n(nic, h->buf_tbl_alloc.base,
++                                    efhw_iopages_dma_addr(&h->iobuff) +
++                                    h->iobuff_off, EFHW_NIC_PAGE_SIZE, 0,
++                                    1 << page_order, 0);
++
++      if (evq_instance >= FALCON_EVQ_TBL_RESERVED)
++              falcon_nic_buffer_table_confirm(nic);
++      return 0;
++}
++
++/**********************************************************************
++ * Kernel event queue management.
++ */
++
++/* Values for [struct efhw_keventq::lock] field. */
++#define KEVQ_UNLOCKED      0
++#define KEVQ_LOCKED        1
++#define KEVQ_RECHECK       2
++
++int
++efhw_keventq_ctor(struct efhw_nic *nic, int instance,
++                struct efhw_keventq *evq,
++                struct efhw_ev_handler *ev_handlers)
++{
++      int rc;
++      unsigned buf_bytes = evq->hw.capacity * sizeof(efhw_event_t);
++
++      evq->instance = instance;
++      evq->ev_handlers = ev_handlers;
++
++      /* allocate an IObuffer for the eventq */
++      rc = efhw_nic_event_queue_alloc_iobuffer(nic, &evq->hw, evq->instance,
++                                               buf_bytes);
++      if (rc < 0)
++              return rc;
++
++      /* Zero the timer-value for this queue.
++         AND Tell the nic about the event queue. */
++      efhw_nic_event_queue_enable(nic, evq->instance, evq->hw.capacity,
++                                  efhw_iopages_dma_addr(&evq->hw.iobuff) +
++                                  evq->hw.iobuff_off,
++                                  evq->hw.buf_tbl_alloc.base);
++
++      evq->lock = KEVQ_UNLOCKED;
++      evq->evq_base = efhw_iopages_ptr(&evq->hw.iobuff) + evq->hw.iobuff_off;
++      evq->evq_ptr = 0;
++      evq->evq_mask = (evq->hw.capacity * sizeof(efhw_event_t)) - 1u;
++
++      EFHW_TRACE("%s: [%d] base=%p end=%p", __FUNCTION__, evq->instance,
++                 evq->evq_base, evq->evq_base + buf_bytes);
++
++      return 0;
++}
++
++void efhw_keventq_dtor(struct efhw_nic *nic, struct efhw_keventq *evq)
++{
++      EFHW_ASSERT(evq);
++
++      EFHW_TRACE("%s: [%d]", __FUNCTION__, evq->instance);
++
++      /* Zero the timer-value for this queue.
++         And Tell NIC to stop using this event queue. */
++      efhw_nic_event_queue_disable(nic, evq->instance, 0);
++
++      /* free the pages used by the eventq itself */
++      efhw_iopages_free(nic, &evq->hw.iobuff);
++}
++
++void
++efhw_handle_txdmaq_flushed(struct efhw_nic *nic, struct efhw_ev_handler *h,
++                         efhw_event_t *evp)
++{
++      int instance = (int)FALCON_EVENT_TX_FLUSH_Q_ID(evp);
++      EFHW_TRACE("%s: instance=%d", __FUNCTION__, instance);
++
++      if (!h->dmaq_flushed_fn) {
++              EFHW_WARN("%s: no handler registered", __FUNCTION__);
++              return;
++      }
++
++      h->dmaq_flushed_fn(nic, instance, false);
++}
++
++void
++efhw_handle_rxdmaq_flushed(struct efhw_nic *nic, struct efhw_ev_handler *h,
++                         efhw_event_t *evp)
++{
++      int instance = (int)FALCON_EVENT_RX_FLUSH_Q_ID(evp);
++      EFHW_TRACE("%s: instance=%d", __FUNCTION__, instance);
++
++      if (!h->dmaq_flushed_fn) {
++              EFHW_WARN("%s: no handler registered", __FUNCTION__);
++              return;
++      }
++
++      h->dmaq_flushed_fn(nic, instance, true);
++}
++
++void
++efhw_handle_wakeup_event(struct efhw_nic *nic, struct efhw_ev_handler *h,
++                       efhw_event_t *evp)
++{
++      if (!h->wakeup_fn) {
++              EFHW_WARN("%s: no handler registered", __FUNCTION__);
++              return;
++      }
++
++      h->wakeup_fn(nic, evp);
++}
++
++void
++efhw_handle_timeout_event(struct efhw_nic *nic, struct efhw_ev_handler *h,
++                        efhw_event_t *evp)
++{
++      if (!h->timeout_fn) {
++              EFHW_WARN("%s: no handler registered", __FUNCTION__);
++              return;
++      }
++
++      h->timeout_fn(nic, evp);
++}
++
++/**********************************************************************
++ * Kernel event queue event handling.
++ */
++
++int efhw_keventq_poll(struct efhw_nic *nic, struct efhw_keventq *q)
++{
++      efhw_event_t *ev;
++      int l, count = 0;
++
++      EFHW_ASSERT(nic);
++      EFHW_ASSERT(q);
++      EFHW_ASSERT(q->ev_handlers);
++
++      /* Acquire the lock, or mark the queue as needing re-checking. */
++      for (;;) {
++              l = q->lock;
++              if (l == KEVQ_UNLOCKED) {
++                      if ((int)cmpxchg(&q->lock, l, KEVQ_LOCKED) == l)
++                              break;
++              } else if (l == KEVQ_LOCKED) {
++                      if ((int)cmpxchg(&q->lock, l, KEVQ_RECHECK) == l)
++                              return 0;
++              } else {        /* already marked for re-checking */
++                      EFHW_ASSERT(l == KEVQ_RECHECK);
++                      return 0;
++              }
++      }
++
++      if (unlikely(EFHW_EVENT_OVERFLOW(q, q)))
++              goto overflow;
++
++      ev = EFHW_EVENT_PTR(q, q, 0);
++
++#ifndef NDEBUG
++      if (!EFHW_IS_EVENT(ev))
++              EFHW_TRACE("%s: %d NO EVENTS!", __FUNCTION__, q->instance);
++#endif
++
++      for (;;) {
++              /* Convention for return codes for handlers is:
++               **   0   - no error, event consumed
++               **   1   - no error, event not consumed
++               **   -ve - error,    event not consumed
++               */
++              if (likely(EFHW_IS_EVENT(ev))) {
++                      count++;
++
++                      switch (FALCON_EVENT_CODE(ev)) {
++
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++                      case FALCON_EVENT_CODE_CHAR:
++                              falcon_handle_char_event(nic, q->ev_handlers,
++                                                       ev);
++                              break;
++#endif
++
++                      default:
++                              EFHW_ERR("efhw_keventq_poll: [%d] UNEXPECTED "
++                                       "EVENT:"FALCON_EVENT_FMT,
++                                       q->instance,
++                                       FALCON_EVENT_PRI_ARG(*ev));
++                      }
++
++                      EFHW_CLEAR_EVENT(ev);
++                      EFHW_EVENTQ_NEXT(q);
++
++                      ev = EFHW_EVENT_PTR(q, q, 0);
++              } else {
++                      /* No events left.  Release the lock (checking if we
++                       * need to re-poll to avoid race). */
++                      l = q->lock;
++                      if (l == KEVQ_LOCKED) {
++                              if ((int)cmpxchg(&q->lock, l, KEVQ_UNLOCKED)
++                                  == l) {
++                                      EFHW_TRACE
++                                          ("efhw_keventq_poll: %d clean exit",
++                                           q->instance);
++                                      goto clean_exit;
++                              }
++                      }
++
++                      /* Potentially more work to do. */
++                      l = q->lock;
++                      EFHW_ASSERT(l == KEVQ_RECHECK);
++                      EFHW_TEST((int)cmpxchg(&q->lock, l, KEVQ_LOCKED) == l);
++                      EFHW_TRACE("efhw_keventq_poll: %d re-poll required",
++                                 q->instance);
++              }
++      }
++
++      /* shouldn't get here */
++      EFHW_ASSERT(0);
++
++overflow:
++      /* ?? Oh dear.  Should we poll everything that could have possibly
++       ** happened?  Or merely cry out in anguish...
++       */
++      EFHW_WARN("efhw_keventq_poll: %d ***** OVERFLOW nic %d *****",
++                q->instance, nic->index);
++
++      q->lock = KEVQ_UNLOCKED;
++      return count;
++
++clean_exit:
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++      /* Ack the processed events so that this event queue can potentially
++         raise interrupts again */
++      falcon_nic_evq_ack(nic, q->instance,
++                         (EFHW_EVENT_OFFSET(q, q, 0) / sizeof(efhw_event_t)),
++                         false);
++#endif
++      return count;
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/falcon.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/falcon.c  2008-05-19 00:33:29.425842266 +0300
+@@ -0,0 +1,2758 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains Falcon hardware support.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/driver/efab/hardware.h>
++#include <ci/efhw/debug.h>
++#include <ci/efhw/iopage.h>
++#include <ci/efhw/falcon.h>
++#include <ci/efhw/falcon_hash.h>
++#include <ci/efhw/nic.h>
++#include <ci/efhw/eventq.h>
++#include <ci/efhw/checks.h>
++
++
++/*----------------------------------------------------------------------------
++ *
++ * Workarounds and options
++ *
++ *---------------------------------------------------------------------------*/
++
++/* on for debug builds */
++#ifndef NDEBUG
++#  define FALCON_FULL_FILTER_CACHE 1  /* complete SW shadow of filter tbl */
++#  define FALCON_VERIFY_FILTERS    0
++#else /* Also adds duplicate filter check */
++#  define FALCON_FULL_FILTER_CACHE 1  /* keep this on for some security */
++#  define FALCON_VERIFY_FILTERS    0
++#endif
++
++/* options */
++#define RX_FILTER_CTL_SRCH_LIMIT_TCP_FULL 8   /* default search limit */
++#define RX_FILTER_CTL_SRCH_LIMIT_TCP_WILD 8   /* default search limit */
++#define RX_FILTER_CTL_SRCH_LIMIT_UDP_FULL 8   /* default search limit */
++#define RX_FILTER_CTL_SRCH_LIMIT_UDP_WILD 8   /* default search limit */
++#define RX_FILTER_CTL_SRCH_FUDGE_WILD 3       /* increase the search limit */
++#define RX_FILTER_CTL_SRCH_FUDGE_FULL 1       /* increase the search limit */
++
++#define FALCON_MAC_SET_TYPE_BY_SPEED           1
++
++/* FIXME: We should detect mode at runtime. */
++#define FALCON_BUFFER_TABLE_FULL_MODE          1
++
++/*----------------------------------------------------------------------------
++ *
++ * Debug Macros
++ *
++ *---------------------------------------------------------------------------*/
++
++#ifndef __KERNEL__
++#define _DEBUG_SYM_ extern
++#else
++#define _DEBUG_SYM_ static inline
++#endif
++
++ /*----------------------------------------------------------------------------
++  *
++  * Macros and forward declarations
++  *
++  *--------------------------------------------------------------------------*/
++
++#define FALCON_REGION_NUM 4   /* number of supported memory regions */
++
++#define FALCON_BUFFER_TBL_HALF_BYTES 4
++#define FALCON_BUFFER_TBL_FULL_BYTES 8
++
++/* Shadow buffer table - hack for testing only */
++#if FALCON_BUFFER_TABLE_FULL_MODE == 0
++# define FALCON_USE_SHADOW_BUFFER_TABLE 1
++#else
++# define FALCON_USE_SHADOW_BUFFER_TABLE 0
++#endif
++
++#if FALCON_USE_SHADOW_BUFFER_TABLE
++static uint64_t _falcon_buffer_table[FALCON_BUFFER_TBL_NUM];
++#endif
++
++/*----------------------------------------------------------------------------
++ *
++ * Header assertion checks
++ *
++ *---------------------------------------------------------------------------*/
++
++#define FALCON_ASSERT_VALID() /* nothing yet */
++
++/* Falcon has a 128bit register model but most registers have useful
++   defaults or only implement a small number of bits. Some registers
++   can be programmed 32bits UNLOCKED all others should be interlocked
++   against other threads within the same protection domain.
++
++   Aim is for software to perform the minimum number of writes and
++   also to minimise the read-modify-write activity (which generally
++   indicates a lack of clarity in the use model).
++
++   Registers which are programmed in this module are listed below
++   together with the method of access. Care must be taken to ensure
++   remain adequate if the register spec changes.
++
++   All 128bits programmed
++    FALCON_BUFFER_TBL_HALF
++    RX_FILTER_TBL
++    TX_DESC_PTR_TBL
++    RX_DESC_PTR_TBL
++    DRV_EV_REG
++
++   All 64bits programmed
++    FALCON_BUFFER_TBL_FULL
++
++   32 bits are programmed (UNLOCKED)
++    EVQ_RPTR_REG
++
++   Low 64bits programmed remainder are written with a random number
++    RX_DC_CFG_REG
++    TX_DC_CFG_REG
++    SRM_RX_DC_CFG_REG
++    SRM_TX_DC_CFG_REG
++    BUF_TBL_CFG_REG
++    BUF_TBL_UPD_REG
++    SRM_UPD_EVQ_REG
++    EVQ_PTR_TBL
++    TIMER_CMD_REG
++    TX_PACE_TBL
++    FATAL_INTR_REG
++    INT_EN_REG (When enabling interrupts)
++    TX_FLUSH_DESCQ_REG
++    RX_FLUSH_DESCQ
++
++  Read Modify Write on low 32bits remainder are written with a random number
++    INT_EN_REG (When sending a driver interrupt)
++    DRIVER_REGX
++
++  Read Modify Write on low 64bits remainder are written with a random number
++   SRM_CFG_REG_OFST
++   RX_CFG_REG_OFST
++   RX_FILTER_CTL_REG
++
++  Read Modify Write on full 128bits
++   TXDP_RESERVED_REG  (aka TXDP_UNDOCUMENTED)
++   TX_CFG_REG
++
++*/
++
++/*----------------------------------------------------------------------------
++ *
++ * Filters static data
++ *
++ *---------------------------------------------------------------------------*/
++
++/* Defaults are set here to support dma.c */
++static unsigned tcp_full_srch_limit = RX_FILTER_CTL_SRCH_LIMIT_TCP_FULL;
++static unsigned tcp_wild_srch_limit = RX_FILTER_CTL_SRCH_LIMIT_TCP_WILD;
++static unsigned udp_full_srch_limit = RX_FILTER_CTL_SRCH_LIMIT_UDP_FULL;
++static unsigned udp_wild_srch_limit = RX_FILTER_CTL_SRCH_LIMIT_UDP_WILD;
++
++#if FALCON_VERIFY_FILTERS
++static void _falcon_nic_ipfilter_sanity(struct efhw_nic *nic);
++#endif
++
++/*----------------------------------------------------------------------------
++ *
++ * Filters low-level register interface
++ *
++ *---------------------------------------------------------------------------*/
++
++/* Build the filter entry */
++static void
++_falcon_nic_ipfilter_build(struct efhw_nic *nic,
++                         int tcp, int full, int rss_b0, int scat_b0,
++                         uint filter_i, uint dmaq_id,
++                         unsigned saddr_le32, unsigned sport_le16,
++                         unsigned daddr_le32, unsigned dport_le16,
++                         uint64_t *q0, uint64_t *q1)
++{
++      uint64_t v1, v2, v3, v4;
++      int type = tcp << 4 | full;
++
++      v4 = (((!tcp) << __DW4(TCP_UDP_1_LBN)) |
++            (dmaq_id << __DW4(RXQ_ID_1_LBN)));
++
++      switch (nic->devtype.variant) {
++      case 'A':
++              EFHW_ASSERT(!rss_b0);
++              break;
++      case 'B':
++              v4 |= scat_b0 << __DW4(SCATTER_EN_1_B0_LBN);
++              v4 |= rss_b0 << __DW4(RSS_EN_1_B0_LBN);
++              break;
++      default:
++              EFHW_ASSERT(0);
++              break;
++      }
++
++      v3 = daddr_le32;
++
++      switch (type) {
++
++      case 0x11:              /* TCP_FULL */
++      case 0x01:              /* UDP_FULL */
++              v2 = ((dport_le16 << __DW2(DEST_PORT_TCP_1_LBN)) |
++                    (__HIGH(saddr_le32, SRC_IP_1_LBN, SRC_IP_1_WIDTH)));
++              v1 = ((__LOW(saddr_le32, SRC_IP_1_LBN, SRC_IP_1_WIDTH)) |
++                    (sport_le16 << SRC_TCP_DEST_UDP_1_LBN));
++              break;
++
++      case 0x10:              /* TCP_WILD */
++              v2 = ((uint64_t) dport_le16 << __DW2(DEST_PORT_TCP_1_LBN));
++              v1 = 0;
++              break;
++
++      case 0x00:              /* UDP_WILD */
++              v2 = 0;
++              v1 = ((uint64_t) dport_le16 << SRC_TCP_DEST_UDP_0_LBN);
++              break;
++
++      default:
++              EFHW_ASSERT(0);
++              v2 = 0;
++              v1 = 0;
++      }
++
++      *q0 = (v2 << 32) | v1;
++      *q1 = (v4 << 32) | v3;
++}
++
++static void
++_falcon_nic_ipfilter_set(struct efhw_nic *nic, int tcp,
++                       int full, int rss_b0, int scat_b0,
++                       uint filter_i, uint dmaq_id,
++                       unsigned saddr_le32, unsigned sport_le16,
++                       unsigned daddr_le32, unsigned dport_le16)
++{
++      uint64_t q0, q1;
++
++      /* wish you wouldn't do this */
++      EFHW_BUILD_ASSERT(RX_FILTER_TBL1_OFST ==
++                        RX_FILTER_TBL0_OFST + FALCON_REGISTER128);
++      EFHW_BUILD_ASSERT(TCP_UDP_1_LBN == TCP_UDP_0_LBN);
++      EFHW_BUILD_ASSERT(RXQ_ID_1_LBN == RXQ_ID_0_LBN);
++      EFHW_BUILD_ASSERT(DEST_IP_1_LBN == DEST_IP_0_LBN);
++      EFHW_BUILD_ASSERT(DEST_PORT_TCP_1_LBN == DEST_PORT_TCP_0_LBN);
++      EFHW_BUILD_ASSERT(SRC_IP_1_LBN == SRC_IP_0_LBN);
++      EFHW_BUILD_ASSERT(SRC_TCP_DEST_UDP_1_LBN == SRC_TCP_DEST_UDP_0_LBN);
++      EFHW_BUILD_ASSERT(SCATTER_EN_1_B0_LBN == SCATTER_EN_0_B0_LBN);
++      EFHW_BUILD_ASSERT(RSS_EN_1_B0_LBN == RSS_EN_0_B0_LBN);
++
++      EFHW_BUILD_ASSERT(TCP_UDP_1_WIDTH == TCP_UDP_0_WIDTH);
++      EFHW_BUILD_ASSERT(RXQ_ID_1_WIDTH == RXQ_ID_0_WIDTH);
++      EFHW_BUILD_ASSERT(DEST_IP_1_WIDTH == DEST_IP_0_WIDTH);
++      EFHW_BUILD_ASSERT(DEST_PORT_TCP_1_WIDTH == DEST_PORT_TCP_0_WIDTH);
++      EFHW_BUILD_ASSERT(SRC_IP_1_WIDTH == SRC_IP_0_WIDTH);
++      EFHW_BUILD_ASSERT(SRC_TCP_DEST_UDP_1_WIDTH == SRC_TCP_DEST_UDP_0_WIDTH);
++      EFHW_BUILD_ASSERT(SCATTER_EN_1_B0_WIDTH == SCATTER_EN_0_B0_WIDTH);
++      EFHW_BUILD_ASSERT(RSS_EN_1_B0_WIDTH == RSS_EN_0_B0_WIDTH);
++
++      /* TODO: Use filter table 1 as well */
++      ulong offset = RX_FILTER_TBL0_OFST + filter_i * 2 * FALCON_REGISTER128;
++
++      EFHW_TRACE("%s[%x]: offset=%lx", __FUNCTION__, filter_i, offset);
++
++      EFHW_TRACE("%s[%x]: filter %d tcp %d full %d src=%x:%x dest=%x:%x%s%s",
++                 __FUNCTION__, filter_i, tcp, full, dmaq_id,
++                 saddr_le32, sport_le16, daddr_le32, dport_le16,
++                 rss_b0 ? " RSS" : "", scat_b0 ? " SCAT" : "");
++
++      EFHW_ASSERT(filter_i < nic->filter_tbl_size);
++
++      /* dword 4 */
++      __DW4CHCK(TCP_UDP_1_LBN, TCP_UDP_1_WIDTH);
++      __DW4CHCK(RXQ_ID_1_LBN, RXQ_ID_1_WIDTH);
++
++      __RANGECHCK(tcp, TCP_UDP_1_WIDTH);
++      __RANGECHCK(dmaq_id, RXQ_ID_1_WIDTH);
++
++      /* dword 3 */
++      __DW3CHCK(DEST_IP_1_LBN, DEST_IP_1_WIDTH);
++      __RANGECHCK(daddr_le32, DEST_IP_1_WIDTH);
++
++      /* dword 2 */
++      __DW2CHCK(DEST_PORT_TCP_1_LBN, DEST_PORT_TCP_1_WIDTH);
++      __LWCHK(SRC_IP_1_LBN, SRC_IP_1_WIDTH);
++      __RANGECHCK(saddr_le32, SRC_IP_1_WIDTH);
++
++      /* dword 1 */
++      __DWCHCK(SRC_TCP_DEST_UDP_1_LBN, SRC_TCP_DEST_UDP_1_WIDTH);
++      __RANGECHCK(sport_le16, SRC_TCP_DEST_UDP_1_WIDTH);
++      __RANGECHCK(dport_le16, SRC_TCP_DEST_UDP_1_WIDTH);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      _falcon_nic_ipfilter_build(nic, tcp, full, rss_b0, scat_b0,
++                                 filter_i, dmaq_id, saddr_le32, sport_le16,
++                                 daddr_le32, dport_le16, &q0, &q1);
++
++      EFHW_TRACE("%s[%x]@%p+%lx: %" PRIx64 " %" PRIx64, __FUNCTION__,
++                 filter_i, EFHW_KVA(nic), offset, q0, q1);
++
++      falcon_write_qq(EFHW_KVA(nic) + offset, q0, q1);
++      mmiowb();
++
++#if FALCON_VERIFY_FILTERS
++      {
++              uint64_t q0read, q1read;
++
++              /* Read a different entry first - entry BIU flushed shadow */
++              falcon_read_qq(EFHW_KVA(nic) + offset+0x10, &q0read, &q1read);
++              falcon_read_qq(EFHW_KVA(nic) + offset, &q0read, &q1read);
++              EFHW_ASSERT(q0read == q0);
++              EFHW_ASSERT(q1read == q1);
++
++              _falcon_nic_ipfilter_sanity(nic);
++      }
++#endif
++}
++
++static void _falcon_nic_ipfilter_clear(struct efhw_nic *nic, uint filter_i)
++{
++      /* TODO: Use filter table 1 as well */
++      ulong offset = RX_FILTER_TBL0_OFST + filter_i * 2 * FALCON_REGISTER128;
++
++      EFHW_ASSERT(filter_i < nic->filter_tbl_size);
++
++      EFHW_TRACE("%s[%x]", __FUNCTION__, filter_i);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      falcon_write_qq(EFHW_KVA(nic) + offset, 0, 0);
++      mmiowb();
++#if FALCON_VERIFY_FILTERS
++      {
++              uint64_t q0read, q1read;
++
++              /* Read a different entry first - entry BIU flushed shadow */
++              falcon_read_qq(EFHW_KVA(nic) + offset+0x10, &q0read, &q1read);
++              falcon_read_qq(EFHW_KVA(nic) + offset, &q0read, &q1read);
++              EFHW_ASSERT(q0read == 0);
++              EFHW_ASSERT(q1read == 0);
++
++              _falcon_nic_ipfilter_sanity(nic);
++      }
++#endif
++}
++
++/*----------------------------------------------------------------------------
++ *
++ * DMAQ low-level register interface
++ *
++ *---------------------------------------------------------------------------*/
++
++static unsigned dmaq_sizes[] = {
++      512,
++      EFHW_1K,
++      EFHW_2K,
++      EFHW_4K,
++};
++
++#define N_DMAQ_SIZES  (sizeof(dmaq_sizes) / sizeof(dmaq_sizes[0]))
++
++static inline ulong falcon_dma_tx_q_offset(struct efhw_nic *nic, unsigned dmaq)
++{
++      EFHW_ASSERT(dmaq < FALCON_DMAQ_NUM);
++      return TX_DESC_PTR_TBL_OFST + dmaq * FALCON_REGISTER128;
++}
++
++static inline uint falcon_dma_tx_q_size_index(uint dmaq_size)
++{
++      uint i;
++
++      /* size must be one of the various options, otherwise we assert */
++      for (i = 0; i < N_DMAQ_SIZES; i++) {
++              if (dmaq_size == dmaq_sizes[i])
++                      break;
++      }
++      EFHW_ASSERT(i < N_DMAQ_SIZES);
++      return i;
++}
++
++static void
++falcon_dmaq_tx_q_init(struct efhw_nic *nic,
++                    uint dmaq, uint evq_id, uint own_id,
++                    uint tag, uint dmaq_size, uint buf_idx, uint flags)
++{
++      FALCON_LOCK_DECL;
++      uint index, desc_type;
++      uint64_t val1, val2, val3;
++      ulong offset;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      /* Q attributes */
++      int iscsi_hdig_en = ((flags & EFHW_VI_ISCSI_TX_HDIG_EN) != 0);
++      int iscsi_ddig_en = ((flags & EFHW_VI_ISCSI_TX_DDIG_EN) != 0);
++      int csum_ip_dis = ((flags & EFHW_VI_TX_IP_CSUM_DIS) != 0);
++      int csum_tcp_dis = ((flags & EFHW_VI_TX_TCPUDP_CSUM_DIS) != 0);
++      int non_ip_drop_dis = ((flags & EFHW_VI_TX_TCPUDP_ONLY) == 0);
++
++      /* initialise the TX descriptor queue pointer table */
++
++      /* NB physical vs buffer addressing is determined by the Queue ID. */
++
++      offset = falcon_dma_tx_q_offset(nic, dmaq);
++      index = falcon_dma_tx_q_size_index(dmaq_size);
++
++      /* allow VI flag to override this queue's descriptor type */
++      desc_type = (flags & EFHW_VI_TX_PHYS_ADDR_EN) ? 0 : 1;
++
++      /* bug9403: It is dangerous to allow buffer-addressed queues to
++       * have owner_id=0. */
++      EFHW_ASSERT((own_id > 0) || desc_type == 0);
++
++      /* dword 1 */
++      __DWCHCK(TX_DESCQ_FLUSH_LBN, TX_DESCQ_FLUSH_WIDTH);
++      __DWCHCK(TX_DESCQ_TYPE_LBN, TX_DESCQ_TYPE_WIDTH);
++      __DWCHCK(TX_DESCQ_SIZE_LBN, TX_DESCQ_SIZE_WIDTH);
++      __DWCHCK(TX_DESCQ_LABEL_LBN, TX_DESCQ_LABEL_WIDTH);
++      __DWCHCK(TX_DESCQ_OWNER_ID_LBN, TX_DESCQ_OWNER_ID_WIDTH);
++
++      __LWCHK(TX_DESCQ_EVQ_ID_LBN, TX_DESCQ_EVQ_ID_WIDTH);
++
++      __RANGECHCK(1, TX_DESCQ_FLUSH_WIDTH);
++      __RANGECHCK(desc_type, TX_DESCQ_TYPE_WIDTH);
++      __RANGECHCK(index, TX_DESCQ_SIZE_WIDTH);
++      __RANGECHCK(tag, TX_DESCQ_LABEL_WIDTH);
++      __RANGECHCK(own_id, TX_DESCQ_OWNER_ID_WIDTH);
++      __RANGECHCK(evq_id, TX_DESCQ_EVQ_ID_WIDTH);
++
++      val1 = ((desc_type << TX_DESCQ_TYPE_LBN) |
++              (index << TX_DESCQ_SIZE_LBN) |
++              (tag << TX_DESCQ_LABEL_LBN) |
++              (own_id << TX_DESCQ_OWNER_ID_LBN) |
++              (__LOW(evq_id, TX_DESCQ_EVQ_ID_LBN, TX_DESCQ_EVQ_ID_WIDTH)));
++
++      /* dword 2 */
++      __DW2CHCK(TX_DESCQ_BUF_BASE_ID_LBN, TX_DESCQ_BUF_BASE_ID_WIDTH);
++      __RANGECHCK(buf_idx, TX_DESCQ_BUF_BASE_ID_WIDTH);
++
++      val2 = ((__HIGH(evq_id, TX_DESCQ_EVQ_ID_LBN, TX_DESCQ_EVQ_ID_WIDTH)) |
++              (buf_idx << __DW2(TX_DESCQ_BUF_BASE_ID_LBN)));
++
++      /* dword 3 */
++      __DW3CHCK(TX_ISCSI_HDIG_EN_LBN, TX_ISCSI_HDIG_EN_WIDTH);
++      __DW3CHCK(TX_ISCSI_DDIG_EN_LBN, TX_ISCSI_DDIG_EN_WIDTH);
++      __RANGECHCK(iscsi_hdig_en, TX_ISCSI_HDIG_EN_WIDTH);
++      __RANGECHCK(iscsi_ddig_en, TX_ISCSI_DDIG_EN_WIDTH);
++
++      val3 = ((iscsi_hdig_en << __DW3(TX_ISCSI_HDIG_EN_LBN)) |
++              (iscsi_ddig_en << __DW3(TX_ISCSI_DDIG_EN_LBN)) |
++              (1 << __DW3(TX_DESCQ_EN_LBN))); /* queue enable bit */
++
++      switch (nic->devtype.variant) {
++      case 'B':
++              __DW3CHCK(TX_NON_IP_DROP_DIS_B0_LBN,
++                        TX_NON_IP_DROP_DIS_B0_WIDTH);
++              __DW3CHCK(TX_IP_CHKSM_DIS_B0_LBN, TX_IP_CHKSM_DIS_B0_WIDTH);
++              __DW3CHCK(TX_TCP_CHKSM_DIS_B0_LBN, TX_TCP_CHKSM_DIS_B0_WIDTH);
++
++              val3 |= ((non_ip_drop_dis << __DW3(TX_NON_IP_DROP_DIS_B0_LBN))|
++                       (csum_ip_dis << __DW3(TX_IP_CHKSM_DIS_B0_LBN)) |
++                       (csum_tcp_dis << __DW3(TX_TCP_CHKSM_DIS_B0_LBN)));
++              break;
++      case 'A':
++              if (csum_ip_dis || csum_tcp_dis || !non_ip_drop_dis)
++                      EFHW_WARN
++                              ("%s: bad settings for A1 csum_ip_dis=%d "
++                               "csum_tcp_dis=%d non_ip_drop_dis=%d",
++                               __FUNCTION__, csum_ip_dis,
++                               csum_tcp_dis, non_ip_drop_dis);
++              break;
++      default:
++              EFHW_ASSERT(0);
++              break;
++      }
++
++      EFHW_TRACE("%s: txq %x evq %u tag %x id %x buf %x "
++                 "%x:%x:%x->%" PRIx64 ":%" PRIx64 ":%" PRIx64,
++                 __FUNCTION__,
++                 dmaq, evq_id, tag, own_id, buf_idx, dmaq_size,
++                 iscsi_hdig_en, iscsi_ddig_en, val1, val2, val3);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++      return;
++}
++
++static inline ulong
++falcon_dma_rx_q_offset(struct efhw_nic *nic, unsigned dmaq)
++{
++      EFHW_ASSERT(dmaq < FALCON_DMAQ_NUM);
++      return RX_DESC_PTR_TBL_OFST + dmaq * FALCON_REGISTER128;
++}
++
++static void
++falcon_dmaq_rx_q_init(struct efhw_nic *nic,
++                    uint dmaq, uint evq_id, uint own_id,
++                    uint tag, uint dmaq_size, uint buf_idx, uint flags)
++{
++      FALCON_LOCK_DECL;
++      uint i, desc_type = 1;
++      uint64_t val1, val2, val3;
++      ulong offset;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      /* Q attributes */
++#if BUG5762_WORKAROUND
++      int jumbo = 1;          /* Queues must not have mixed types */
++#else
++      int jumbo = ((flags & EFHW_VI_JUMBO_EN) != 0);
++#endif
++      int iscsi_hdig_en = ((flags & EFHW_VI_ISCSI_RX_HDIG_EN) != 0);
++      int iscsi_ddig_en = ((flags & EFHW_VI_ISCSI_RX_DDIG_EN) != 0);
++
++      /* initialise the TX descriptor queue pointer table */
++      offset = falcon_dma_rx_q_offset(nic, dmaq);
++
++      /* size must be one of the various options, otherwise we assert */
++      for (i = 0; i < N_DMAQ_SIZES; i++) {
++              if (dmaq_size == dmaq_sizes[i])
++                      break;
++      }
++      EFHW_ASSERT(i < N_DMAQ_SIZES);
++
++      /* allow VI flag to override this queue's descriptor type */
++      desc_type = (flags & EFHW_VI_RX_PHYS_ADDR_EN) ? 0 : 1;
++
++      /* bug9403: It is dangerous to allow buffer-addressed queues to have
++       * owner_id=0 */
++      EFHW_ASSERT((own_id > 0) || desc_type == 0);
++
++      /* dword 1 */
++      __DWCHCK(RX_DESCQ_EN_LBN, RX_DESCQ_EN_WIDTH);
++      __DWCHCK(RX_DESCQ_JUMBO_LBN, RX_DESCQ_JUMBO_WIDTH);
++      __DWCHCK(RX_DESCQ_TYPE_LBN, RX_DESCQ_TYPE_WIDTH);
++      __DWCHCK(RX_DESCQ_SIZE_LBN, RX_DESCQ_SIZE_WIDTH);
++      __DWCHCK(RX_DESCQ_LABEL_LBN, RX_DESCQ_LABEL_WIDTH);
++      __DWCHCK(RX_DESCQ_OWNER_ID_LBN, RX_DESCQ_OWNER_ID_WIDTH);
++
++      __LWCHK(RX_DESCQ_EVQ_ID_LBN, RX_DESCQ_EVQ_ID_WIDTH);
++
++      __RANGECHCK(1, RX_DESCQ_EN_WIDTH);
++      __RANGECHCK(jumbo, RX_DESCQ_JUMBO_WIDTH);
++      __RANGECHCK(desc_type, RX_DESCQ_TYPE_WIDTH);
++      __RANGECHCK(i, RX_DESCQ_SIZE_WIDTH);
++      __RANGECHCK(tag, RX_DESCQ_LABEL_WIDTH);
++      __RANGECHCK(own_id, RX_DESCQ_OWNER_ID_WIDTH);
++      __RANGECHCK(evq_id, RX_DESCQ_EVQ_ID_WIDTH);
++
++      val1 = ((1 << RX_DESCQ_EN_LBN) |
++              (jumbo << RX_DESCQ_JUMBO_LBN) |
++              (desc_type << RX_DESCQ_TYPE_LBN) |
++              (i << RX_DESCQ_SIZE_LBN) |
++              (tag << RX_DESCQ_LABEL_LBN) |
++              (own_id << RX_DESCQ_OWNER_ID_LBN) |
++              (__LOW(evq_id, RX_DESCQ_EVQ_ID_LBN, RX_DESCQ_EVQ_ID_WIDTH)));
++
++      /* dword 2 */
++      __DW2CHCK(RX_DESCQ_BUF_BASE_ID_LBN, RX_DESCQ_BUF_BASE_ID_WIDTH);
++      __RANGECHCK(buf_idx, RX_DESCQ_BUF_BASE_ID_WIDTH);
++
++      val2 = ((__HIGH(evq_id, RX_DESCQ_EVQ_ID_LBN, RX_DESCQ_EVQ_ID_WIDTH)) |
++              (buf_idx << __DW2(RX_DESCQ_BUF_BASE_ID_LBN)));
++
++      /* dword 3 */
++      __DW3CHCK(RX_ISCSI_HDIG_EN_LBN, RX_ISCSI_HDIG_EN_WIDTH);
++      __DW3CHCK(RX_ISCSI_DDIG_EN_LBN, RX_ISCSI_DDIG_EN_WIDTH);
++      __RANGECHCK(iscsi_hdig_en, RX_ISCSI_HDIG_EN_WIDTH);
++      __RANGECHCK(iscsi_ddig_en, RX_ISCSI_DDIG_EN_WIDTH);
++
++      val3 = (iscsi_hdig_en << __DW3(RX_ISCSI_HDIG_EN_LBN)) |
++          (iscsi_ddig_en << __DW3(RX_ISCSI_DDIG_EN_LBN));
++
++      EFHW_TRACE("%s: rxq %x evq %u tag %x id %x buf %x %s "
++                 "%x:%x:%x -> %" PRIx64 ":%" PRIx64 ":%" PRIx64,
++                 __FUNCTION__,
++                 dmaq, evq_id, tag, own_id, buf_idx,
++                 jumbo ? "jumbo" : "normal", dmaq_size,
++                 iscsi_hdig_en, iscsi_ddig_en, val1, val2, val3);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++      return;
++}
++
++static void falcon_dmaq_tx_q_disable(struct efhw_nic *nic, uint dmaq)
++{
++      FALCON_LOCK_DECL;
++      uint64_t val1, val2, val3;
++      ulong offset;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      /* initialise the TX descriptor queue pointer table */
++
++      offset = falcon_dma_tx_q_offset(nic, dmaq);
++
++      /* dword 1 */
++      __DWCHCK(TX_DESCQ_TYPE_LBN, TX_DESCQ_TYPE_WIDTH);
++
++      val1 = ((uint64_t) 1 << TX_DESCQ_TYPE_LBN);
++
++      /* dword 2 */
++      val2 = 0;
++
++      /* dword 3 */
++      val3 = (0 << __DW3(TX_DESCQ_EN_LBN));   /* queue enable bit */
++
++      EFHW_TRACE("%s: %x->%" PRIx64 ":%" PRIx64 ":%" PRIx64,
++                 __FUNCTION__, dmaq, val1, val2, val3);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++      return;
++}
++
++static void falcon_dmaq_rx_q_disable(struct efhw_nic *nic, uint dmaq)
++{
++      FALCON_LOCK_DECL;
++      uint64_t val1, val2, val3;
++      ulong offset;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      /* initialise the TX descriptor queue pointer table */
++      offset = falcon_dma_rx_q_offset(nic, dmaq);
++
++      /* dword 1 */
++      __DWCHCK(RX_DESCQ_EN_LBN, RX_DESCQ_EN_WIDTH);
++      __DWCHCK(RX_DESCQ_TYPE_LBN, RX_DESCQ_TYPE_WIDTH);
++
++      val1 = ((0 << RX_DESCQ_EN_LBN) | (1 << RX_DESCQ_TYPE_LBN));
++
++      /* dword 2 */
++      val2 = 0;
++
++      /* dword 3 */
++      val3 = 0;
++
++      EFHW_TRACE("falcon_dmaq_rx_q_disable: %x->%"
++                 PRIx64 ":%" PRIx64 ":%" PRIx64,
++                 dmaq, val1, val2, val3);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(efhw_kva + offset, ((val2 << 32) | val1), val3);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++      return;
++}
++
++
++/*----------------------------------------------------------------------------
++ *
++ * Buffer Table low-level register interface
++ *
++ *---------------------------------------------------------------------------*/
++
++/*! Convert a (potentially) 64-bit physical address to 32-bits.  Every use
++** of this function is a place where we're not 64-bit clean.
++*/
++static inline uint32_t dma_addr_to_u32(dma_addr_t addr)
++{
++      /* Top bits had better be zero! */
++      EFHW_ASSERT(addr == (addr & 0xffffffff));
++      return (uint32_t) addr;
++}
++
++static inline uint32_t
++falcon_nic_buffer_table_entry32_mk(dma_addr_t dma_addr, int own_id)
++{
++      uint32_t dma_addr32 = FALCON_BUFFER_4K_PAGE(dma_addr_to_u32(dma_addr));
++
++      /* don't do this to me */
++      EFHW_BUILD_ASSERT(BUF_ADR_HBUF_ODD_LBN == BUF_ADR_HBUF_EVEN_LBN + 32);
++      EFHW_BUILD_ASSERT(BUF_OWNER_ID_HBUF_ODD_LBN ==
++                        BUF_OWNER_ID_HBUF_EVEN_LBN + 32);
++
++      EFHW_BUILD_ASSERT(BUF_OWNER_ID_HBUF_ODD_WIDTH ==
++                        BUF_OWNER_ID_HBUF_EVEN_WIDTH);
++      EFHW_BUILD_ASSERT(BUF_ADR_HBUF_ODD_WIDTH == BUF_ADR_HBUF_EVEN_WIDTH);
++
++      __DWCHCK(BUF_ADR_HBUF_EVEN_LBN, BUF_ADR_HBUF_EVEN_WIDTH);
++      __DWCHCK(BUF_OWNER_ID_HBUF_EVEN_LBN, BUF_OWNER_ID_HBUF_EVEN_WIDTH);
++
++      __RANGECHCK(dma_addr32, BUF_ADR_HBUF_EVEN_WIDTH);
++      __RANGECHCK(own_id, BUF_OWNER_ID_HBUF_EVEN_WIDTH);
++
++      return ((dma_addr32 << BUF_ADR_HBUF_EVEN_LBN) |
++              (own_id << BUF_OWNER_ID_HBUF_EVEN_LBN));
++}
++
++static inline uint64_t
++falcon_nic_buffer_table_entry64_mk(dma_addr_t dma_addr,
++                                 int bufsz,   /* bytes */
++                                 int region, int own_id)
++{
++      __DW2CHCK(IP_DAT_BUF_SIZE_LBN, IP_DAT_BUF_SIZE_WIDTH);
++      __DW2CHCK(BUF_ADR_REGION_LBN, BUF_ADR_REGION_WIDTH);
++      __LWCHK(BUF_ADR_FBUF_LBN, BUF_ADR_FBUF_WIDTH);
++      __DWCHCK(BUF_OWNER_ID_FBUF_LBN, BUF_OWNER_ID_FBUF_WIDTH);
++
++      EFHW_ASSERT((bufsz == EFHW_4K) || (bufsz == EFHW_8K));
++
++      dma_addr = (dma_addr >> 12) & __FALCON_MASK64(BUF_ADR_FBUF_WIDTH);
++
++      __RANGECHCK(dma_addr, BUF_ADR_FBUF_WIDTH);
++      __RANGECHCK(1, IP_DAT_BUF_SIZE_WIDTH);
++      __RANGECHCK(region, BUF_ADR_REGION_WIDTH);
++      __RANGECHCK(own_id, BUF_OWNER_ID_FBUF_WIDTH);
++
++      return (((uint64_t) (bufsz == EFHW_8K) << IP_DAT_BUF_SIZE_LBN) |
++              ((uint64_t) region << BUF_ADR_REGION_LBN) |
++              ((uint64_t) dma_addr << BUF_ADR_FBUF_LBN) |
++              ((uint64_t) own_id << BUF_OWNER_ID_FBUF_LBN));
++}
++
++static inline void
++_falcon_nic_buffer_table_set32(struct efhw_nic *nic,
++                             dma_addr_t dma_addr, uint bufsz,
++                             uint region, /* not used */
++                             int own_id, int buffer_id)
++{
++      /* programming the half table needs to be done in pairs. */
++      uint64_t entry, val, shift;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      efhw_ioaddr_t offset;
++
++      EFHW_BUILD_ASSERT(BUF_ADR_HBUF_ODD_LBN == BUF_ADR_HBUF_EVEN_LBN + 32);
++      EFHW_BUILD_ASSERT(BUF_OWNER_ID_HBUF_ODD_LBN ==
++                        BUF_OWNER_ID_HBUF_EVEN_LBN + 32);
++
++      shift = (buffer_id & 1) ? 32 : 0;
++
++      offset = (efhw_kva + BUF_HALF_TBL_OFST +
++                ((buffer_id & ~1) * FALCON_BUFFER_TBL_HALF_BYTES));
++
++      entry = falcon_nic_buffer_table_entry32_mk(dma_addr_to_u32(dma_addr),
++                                                 own_id);
++
++#if FALCON_USE_SHADOW_BUFFER_TABLE
++      val = _falcon_buffer_table[buffer_id & ~1];
++#else
++      /* This will not work unless we've completed
++       * the buffer table updates */
++      falcon_read_q(offset, &val);
++#endif
++      val &= ~(((uint64_t) 0xffffffff) << shift);
++      val |= (entry << shift);
++
++      EFHW_TRACE("%s[%x]: " ci_dma_addr_fmt ":%x:%" PRIx64 "->%x = %"
++                 PRIx64, __FUNCTION__, buffer_id, dma_addr, own_id, entry,
++                 (unsigned)(offset - efhw_kva), val);
++
++      /* Falcon requires that access to this register is serialised */
++      falcon_write_q(offset, val);
++
++      /* NB. No mmiowb().  Caller should do that e.g by calling commit  */
++
++#if FALCON_USE_SHADOW_BUFFER_TABLE
++      _falcon_buffer_table[buffer_id & ~1] = val;
++#endif
++
++      /* Confirm the entry if the event queues haven't been set up. */
++      if (!nic->irq_handler) {
++              uint64_t new_val;
++              int count = 0;
++              while (1) {
++                      mmiowb();
++                      falcon_read_q(offset, &new_val);
++                      if (new_val == val)
++                              break;
++                      count++;
++                      if (count > 1000) {
++                              EFHW_WARN("%s: poll Timeout", __FUNCTION__);
++                              break;
++                      }
++                      udelay(1);
++              }
++      }
++}
++
++static inline void
++_falcon_nic_buffer_table_set64(struct efhw_nic *nic,
++                             dma_addr_t dma_addr, uint bufsz,
++                             uint region, int own_id, int buffer_id)
++{
++      efhw_ioaddr_t offset;
++      uint64_t entry;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      EFHW_ASSERT(region < FALCON_REGION_NUM);
++
++      EFHW_ASSERT((bufsz == EFHW_4K) ||
++                  (bufsz == EFHW_8K && FALCON_BUFFER_TABLE_FULL_MODE));
++
++      offset = (efhw_kva + BUF_FULL_TBL_OFST +
++                (buffer_id * FALCON_BUFFER_TBL_FULL_BYTES));
++
++      entry = falcon_nic_buffer_table_entry64_mk(dma_addr, bufsz, region,
++                                                 own_id);
++
++      EFHW_TRACE("%s[%x]: " ci_dma_addr_fmt
++                 ":bufsz=%x:region=%x:ownid=%x",
++                 __FUNCTION__, buffer_id, dma_addr, bufsz, region, own_id);
++
++      EFHW_TRACE("%s: BUF[%x]:NIC[%x]->%" PRIx64,
++                 __FUNCTION__, buffer_id,
++                 (unsigned int)(offset - efhw_kva), entry);
++
++      /* Falcon requires that access to this register is serialised */
++      falcon_write_q(offset, entry);
++
++      /* NB. No mmiowb().  Caller should do that e.g by calling commit */
++
++      /* Confirm the entry if the event queues haven't been set up. */
++      if (!nic->irq_handler) {
++              uint64_t new_entry;
++              int count = 0;
++              while (1) {
++                      mmiowb();
++                      falcon_read_q(offset, &new_entry);
++                      if (new_entry == entry)
++                              return;
++                      count++;
++                      if (count > 1000) {
++                              EFHW_WARN("%s: poll Timeout waiting for "
++                                        "value %"PRIx64
++                                        " (last was %"PRIx64")",
++                                        __FUNCTION__, entry, new_entry);
++                              break;
++                      }
++                      udelay(1);
++              }
++      }
++}
++
++#if FALCON_BUFFER_TABLE_FULL_MODE
++#define _falcon_nic_buffer_table_set _falcon_nic_buffer_table_set64
++#else
++#define _falcon_nic_buffer_table_set _falcon_nic_buffer_table_set32
++#endif
++
++static inline void _falcon_nic_buffer_table_commit(struct efhw_nic *nic)
++{
++      /* MUST be called holding the FALCON_LOCK */
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      uint64_t cmd;
++
++      EFHW_BUILD_ASSERT(BUF_TBL_UPD_REG_KER_OFST == BUF_TBL_UPD_REG_OFST);
++
++      __DW2CHCK(BUF_UPD_CMD_LBN, BUF_UPD_CMD_WIDTH);
++      __RANGECHCK(1, BUF_UPD_CMD_WIDTH);
++
++      cmd = ((uint64_t) 1 << BUF_UPD_CMD_LBN);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      falcon_write_qq(efhw_kva + BUF_TBL_UPD_REG_OFST,
++                      cmd, FALCON_ATOMIC_UPD_REG);
++      mmiowb();
++
++      nic->buf_commit_outstanding++;
++      EFHW_TRACE("COMMIT REQ out=%d", nic->buf_commit_outstanding);
++}
++
++static void falcon_nic_buffer_table_commit(struct efhw_nic *nic)
++{
++      /* nothing to do */
++}
++
++static inline void
++_falcon_nic_buffer_table_clear(struct efhw_nic *nic, int buffer_id, int num)
++{
++      uint64_t cmd;
++      uint64_t start_id = buffer_id;
++      uint64_t end_id = buffer_id + num - 1;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      efhw_ioaddr_t offset = (efhw_kva + BUF_TBL_UPD_REG_OFST);
++
++      EFHW_BUILD_ASSERT(BUF_TBL_UPD_REG_KER_OFST == BUF_TBL_UPD_REG_OFST);
++
++#if !FALCON_BUFFER_TABLE_FULL_MODE
++      /* buffer_ids in half buffer mode reference pairs of buffers */
++      EFHW_ASSERT(buffer_id % 1 == 0);
++      EFHW_ASSERT(num % 1 == 0);
++      start_id = start_id >> 1;
++      end_id = end_id >> 1;
++#endif
++
++      EFHW_ASSERT(num >= 1);
++
++      __DWCHCK(BUF_CLR_START_ID_LBN, BUF_CLR_START_ID_WIDTH);
++      __DW2CHCK(BUF_CLR_END_ID_LBN, BUF_CLR_END_ID_WIDTH);
++
++      __DW2CHCK(BUF_CLR_CMD_LBN, BUF_CLR_CMD_WIDTH);
++      __RANGECHCK(1, BUF_CLR_CMD_WIDTH);
++
++      __RANGECHCK(start_id, BUF_CLR_START_ID_WIDTH);
++      __RANGECHCK(end_id, BUF_CLR_END_ID_WIDTH);
++
++      cmd = (((uint64_t) 1 << BUF_CLR_CMD_LBN) |
++             (start_id << BUF_CLR_START_ID_LBN) |
++             (end_id << BUF_CLR_END_ID_LBN));
++
++      /* Falcon requires 128 bit atomic access for this register */
++      falcon_write_qq(offset, cmd, FALCON_ATOMIC_UPD_REG);
++      mmiowb();
++
++      nic->buf_commit_outstanding++;
++      EFHW_TRACE("COMMIT CLEAR out=%d", nic->buf_commit_outstanding);
++}
++
++/*----------------------------------------------------------------------------
++ *
++ * Events low-level register interface
++ *
++ *---------------------------------------------------------------------------*/
++
++static unsigned eventq_sizes[] = {
++      512,
++      EFHW_1K,
++      EFHW_2K,
++      EFHW_4K,
++      EFHW_8K,
++      EFHW_16K,
++      EFHW_32K
++};
++
++#define N_EVENTQ_SIZES  (sizeof(eventq_sizes) / sizeof(eventq_sizes[0]))
++
++static inline void falcon_nic_srm_upd_evq(struct efhw_nic *nic, int evq)
++{
++      /* set up the eventq which will receive events from the SRAM module.
++       * i.e buffer table updates and clears, TX and RX aperture table
++       * updates */
++
++      FALCON_LOCK_DECL;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      EFHW_BUILD_ASSERT(SRM_UPD_EVQ_REG_OFST == SRM_UPD_EVQ_REG_KER_OFST);
++
++      EFHW_ASSERT((evq == FALCON_EVQ_KERNEL0) || (evq == FALCON_EVQ_CHAR) ||
++                  (evq == FALCON_EVQ_NONIRQ));
++
++      __DWCHCK(SRM_UPD_EVQ_ID_LBN, SRM_UPD_EVQ_ID_WIDTH);
++      __RANGECHCK(evq, SRM_UPD_EVQ_ID_WIDTH);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(efhw_kva + SRM_UPD_EVQ_REG_OFST,
++                      ((uint64_t) evq << SRM_UPD_EVQ_ID_LBN),
++                      FALCON_ATOMIC_SRPM_UDP_EVQ_REG);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++}
++
++static inline void
++falcon_nic_evq_ptr_tbl(struct efhw_nic *nic,
++                     uint evq,        /* evq id */
++                     uint enable,     /* 1 to enable, 0 to disable */
++                     uint buf_base_id,/* Buffer table base for EVQ */
++                     uint evq_size    /* Number of events */ )
++{
++      FALCON_LOCK_DECL;
++      uint i, val;
++      ulong offset;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      /* size must be one of the various options, otherwise we assert */
++      for (i = 0; i < N_EVENTQ_SIZES; i++) {
++              if (evq_size <= eventq_sizes[i])
++                      break;
++      }
++      EFHW_ASSERT(i < N_EVENTQ_SIZES);
++
++      __DWCHCK(EVQ_BUF_BASE_ID_LBN, EVQ_BUF_BASE_ID_WIDTH);
++      __DWCHCK(EVQ_SIZE_LBN, EVQ_SIZE_WIDTH);
++      __DWCHCK(EVQ_EN_LBN, EVQ_EN_WIDTH);
++
++      __RANGECHCK(i, EVQ_SIZE_WIDTH);
++      __RANGECHCK(buf_base_id, EVQ_BUF_BASE_ID_WIDTH);
++      __RANGECHCK(1, EVQ_EN_WIDTH);
++
++      /* if !enable then only evq needs to be correct, although valid
++       * values need to be passed in for other arguments to prevent
++       * assertions */
++
++      val = ((i << EVQ_SIZE_LBN) | (buf_base_id << EVQ_BUF_BASE_ID_LBN) |
++             (enable ? (1 << EVQ_EN_LBN) : 0));
++
++      EFHW_ASSERT(evq < FALCON_EVQ_TBL_NUM);
++
++      offset = EVQ_PTR_TBL_CHAR_OFST;
++      offset += evq * FALCON_REGISTER128;
++
++      EFHW_TRACE("%s: evq %u en=%x:buf=%x:size=%x->%x at %lx",
++                 __FUNCTION__, evq, enable, buf_base_id, evq_size, val,
++                 offset);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(efhw_kva + offset, val, FALCON_ATOMIC_PTR_TBL_REG);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++
++      /* caller must wait for an update done event before writing any more
++         table entries */
++
++      return;
++}
++
++void
++falcon_nic_evq_ack(struct efhw_nic *nic,
++                 uint evq,    /* evq id */
++                 uint rptr,   /* new read pointer update */
++                 bool wakeup  /* request a wakeup event if ptr's != */
++    )
++{
++      uint val;
++      ulong offset;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      EFHW_BUILD_ASSERT(FALCON_EVQ_CHAR == 4);
++
++      __DWCHCK(EVQ_RPTR_LBN, EVQ_RPTR_WIDTH);
++      __RANGECHCK(rptr, EVQ_RPTR_WIDTH);
++
++      val = (rptr << EVQ_RPTR_LBN);
++
++      EFHW_ASSERT(evq < FALCON_EVQ_TBL_NUM);
++
++      if (evq < FALCON_EVQ_CHAR) {
++              offset = EVQ_RPTR_REG_KER_OFST;
++              offset += evq * FALCON_REGISTER128;
++
++              EFHW_ASSERT(!wakeup);   /* don't try this at home */
++      } else {
++              offset = EVQ_RPTR_REG_OFST + (FALCON_EVQ_CHAR *
++                                            FALCON_REGISTER128);
++              offset += (evq - FALCON_EVQ_CHAR) * FALCON_REGISTER128;
++
++              /* nothing to do for interruptless event queues which do
++               * not want a wakeup */
++              if (evq != FALCON_EVQ_CHAR && !wakeup)
++                      return;
++      }
++
++      EFHW_TRACE("%s: %x %x %x->%x", __FUNCTION__, evq, rptr, wakeup, val);
++
++      writel(val, efhw_kva + offset);
++      mmiowb();
++}
++
++/*----------------------------------------------------------------------------
++ *
++ * Helper for evq mapping
++ *
++ * idx = 0 && char   => hw eventq[4]
++ * idx = 0 && net    => hw eventq[0]
++ *   0 < idx < 5     => hw eventq[idx]  (5 is non-interrupting)
++ *
++ *
++ *---------------------------------------------------------------------------*/
++
++int falcon_idx_to_evq(struct efhw_nic *nic, uint idx)
++{
++      EFHW_BUILD_ASSERT(FALCON_EVQ_CHAR == 4);
++      EFHW_ASSERT(idx <= FALCON_EVQ_NONIRQ);
++      return (idx > 0) ? idx : FALCON_EVQ_CHAR;
++}
++
++static inline int falcon_evq_is_interrupting(struct efhw_nic *nic, uint idx)
++{
++      EFHW_BUILD_ASSERT(FALCON_EVQ_CHAR == 4);
++      EFHW_ASSERT(idx <= FALCON_EVQ_NONIRQ);
++
++      /* only the first CHAR driver event queue is interrupting */
++      return (idx == FALCON_EVQ_CHAR);
++}
++
++static inline void
++falcon_drv_ev(struct efhw_nic *nic, uint64_t data, uint qid)
++{
++      FALCON_LOCK_DECL;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      /* send an event from one driver to the other */
++      EFHW_BUILD_ASSERT(DRV_EV_REG_KER_OFST == DRV_EV_REG_OFST);
++      EFHW_BUILD_ASSERT(DRV_EV_DATA_LBN == 0);
++      EFHW_BUILD_ASSERT(DRV_EV_DATA_WIDTH == 64);
++      EFHW_BUILD_ASSERT(DRV_EV_QID_LBN == 64);
++      EFHW_BUILD_ASSERT(DRV_EV_QID_WIDTH == 12);
++
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(efhw_kva + DRV_EV_REG_OFST, data, qid);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++}
++
++_DEBUG_SYM_ void
++falcon_timer_cmd(struct efhw_nic *nic,
++               uint evq,      /* timer id */
++               uint mode,     /* mode bits */
++               uint countdown /* counting value to set */ )
++{
++      FALCON_LOCK_DECL;
++      uint val;
++      ulong offset;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      EFHW_BUILD_ASSERT(TIMER_VAL_LBN == 0);
++
++      __DWCHCK(TIMER_MODE_LBN, TIMER_MODE_WIDTH);
++      __DWCHCK(TIMER_VAL_LBN, TIMER_VAL_WIDTH);
++
++      __RANGECHCK(mode, TIMER_MODE_WIDTH);
++      __RANGECHCK(countdown, TIMER_VAL_WIDTH);
++
++      val = ((mode << TIMER_MODE_LBN) | (countdown << TIMER_VAL_LBN));
++
++      if (evq < FALCON_EVQ_CHAR) {
++              offset = TIMER_CMD_REG_KER_OFST;
++              offset += evq * EFHW_8K;        /* PAGE mapped register */
++      } else {
++              offset = TIMER_TBL_OFST;
++              offset += evq * FALCON_REGISTER128;
++      }
++      EFHW_ASSERT(evq < FALCON_EVQ_TBL_NUM);
++
++      EFHW_TRACE("%s: evq %u mode %x (%s) time %x -> %08x",
++                 __FUNCTION__, evq, mode,
++                 mode == 0 ? "DISABLE" :
++                 mode == 1 ? "IMMED" :
++                 mode == 2 ? (evq < 5 ? "HOLDOFF" : "RX_TRIG") :
++                 "<BAD>", countdown, val);
++
++      /* Falcon requires 128 bit atomic access for this register when
++       * accessed from the driver. User access to timers is paged mapped
++       */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(efhw_kva + offset, val, FALCON_ATOMIC_TIMER_CMD_REG);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++      return;
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Rate pacing - Low level interface
++ *
++ *--------------------------------------------------------------------*/
++void falcon_nic_pace(struct efhw_nic *nic, uint dmaq, uint pace)
++{
++      /* Pace specified in 2^(units of microseconds). This is the minimum
++         additional delay imposed over and above the IPG.
++
++         Pacing only available on the virtual interfaces
++       */
++      FALCON_LOCK_DECL;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      ulong offset;
++
++      if (pace > 20)
++              pace = 20;      /* maxm supported value */
++
++      __DWCHCK(TX_PACE_LBN, TX_PACE_WIDTH);
++      __RANGECHCK(pace, TX_PACE_WIDTH);
++
++      switch (nic->devtype.variant) {
++      case 'A':
++              EFHW_ASSERT(dmaq >= TX_PACE_TBL_FIRST_QUEUE_A1);
++              offset = TX_PACE_TBL_A1_OFST;
++              offset += (dmaq - TX_PACE_TBL_FIRST_QUEUE_A1) * 16;
++              break;
++      case 'B':
++              /* Would be nice to assert this, but as dmaq is unsigned and
++               * TX_PACE_TBL_FIRST_QUEUE_B0 is 0, it makes no sense
++               * EFHW_ASSERT(dmaq >= TX_PACE_TBL_FIRST_QUEUE_B0);
++               */
++              offset = TX_PACE_TBL_B0_OFST;
++              offset += (dmaq - TX_PACE_TBL_FIRST_QUEUE_B0) * 16;
++              break;
++      default:
++              EFHW_ASSERT(0);
++              offset = 0;
++              break;
++      }
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(efhw_kva + offset, pace, FALCON_ATOMIC_PACE_REG);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++
++      EFHW_TRACE("%s: txq %d offset=%lx pace=2^%x",
++                 __FUNCTION__, dmaq, offset, pace);
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Interrupt - Low level interface
++ *
++ *--------------------------------------------------------------------*/
++
++static void falcon_nic_handle_fatal_int(struct efhw_nic *nic)
++{
++      FALCON_LOCK_DECL;
++      efhw_ioaddr_t offset;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      uint64_t val;
++
++      offset = (efhw_kva + FATAL_INTR_REG_OFST);
++
++      /* Falcon requires 32 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      val = readl(offset);
++      FALCON_LOCK_UNLOCK(nic);
++
++      /* ?? BUG3249 - need to disable illegal address interrupt */
++      /* ?? BUG3114 - need to backport interrupt storm protection code */
++      EFHW_ERR("fatal interrupt: %s%s%s%s%s%s%s%s%s%s%s%s[%" PRIx64 "]",
++               val & (1 << PCI_BUSERR_INT_CHAR_LBN) ? "PCI-bus-error " : "",
++               val & (1 << SRAM_OOB_INT_CHAR_LBN) ? "SRAM-oob " : "",
++               val & (1 << BUFID_OOB_INT_CHAR_LBN) ? "bufid-oob " : "",
++               val & (1 << MEM_PERR_INT_CHAR_LBN) ? "int-parity " : "",
++               val & (1 << RBUF_OWN_INT_CHAR_LBN) ? "rx-bufid-own " : "",
++               val & (1 << TBUF_OWN_INT_CHAR_LBN) ? "tx-bufid-own " : "",
++               val & (1 << RDESCQ_OWN_INT_CHAR_LBN) ? "rx-desc-own " : "",
++               val & (1 << TDESCQ_OWN_INT_CHAR_LBN) ? "tx-desc-own " : "",
++               val & (1 << EVQ_OWN_INT_CHAR_LBN) ? "evq-own " : "",
++               val & (1 << EVFF_OFLO_INT_CHAR_LBN) ? "evq-fifo " : "",
++               val & (1 << ILL_ADR_INT_CHAR_LBN) ? "ill-addr " : "",
++               val & (1 << SRM_PERR_INT_CHAR_LBN) ? "sram-parity " : "", val);
++}
++
++static void falcon_nic_interrupt_hw_enable(struct efhw_nic *nic)
++{
++      FALCON_LOCK_DECL;
++      uint val;
++      efhw_ioaddr_t offset;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      EFHW_BUILD_ASSERT(DRV_INT_EN_CHAR_WIDTH == 1);
++
++      if (nic->flags & NIC_FLAG_NO_INTERRUPT)
++              return;
++
++      offset = (efhw_kva + INT_EN_REG_CHAR_OFST);
++      val = 1 << DRV_INT_EN_CHAR_LBN;
++
++      EFHW_NOTICE("%s: %x -> %x", __FUNCTION__, (int)(offset - efhw_kva),
++                  val);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(offset, val, FALCON_ATOMIC_INT_EN_REG);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++}
++
++static void falcon_nic_interrupt_hw_disable(struct efhw_nic *nic)
++{
++      FALCON_LOCK_DECL;
++      efhw_ioaddr_t offset;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      EFHW_BUILD_ASSERT(SRAM_PERR_INT_KER_WIDTH == 1);
++      EFHW_BUILD_ASSERT(DRV_INT_EN_KER_LBN == 0);
++      EFHW_BUILD_ASSERT(SRAM_PERR_INT_CHAR_WIDTH == 1);
++      EFHW_BUILD_ASSERT(DRV_INT_EN_CHAR_LBN == 0);
++      EFHW_BUILD_ASSERT(SRAM_PERR_INT_KER_LBN == SRAM_PERR_INT_CHAR_LBN);
++      EFHW_BUILD_ASSERT(DRV_INT_EN_KER_LBN == DRV_INT_EN_CHAR_LBN);
++
++      if (nic->flags & NIC_FLAG_NO_INTERRUPT)
++              return;
++
++      offset = (efhw_kva + INT_EN_REG_CHAR_OFST);
++
++      EFHW_NOTICE("%s: %x -> 0", __FUNCTION__, (int)(offset - efhw_kva));
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(offset, 0, FALCON_ATOMIC_INT_EN_REG);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++}
++
++#ifndef __ci_ul_driver__
++
++static void falcon_nic_irq_addr_set(struct efhw_nic *nic, dma_addr_t dma_addr)
++{
++      FALCON_LOCK_DECL;
++      efhw_ioaddr_t offset;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++
++      offset = (efhw_kva + INT_ADR_REG_CHAR_OFST);
++
++      EFHW_NOTICE("%s: %x -> " DMA_ADDR_T_FMT, __FUNCTION__,
++                  (int)(offset - efhw_kva), dma_addr);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(offset, dma_addr, FALCON_ATOMIC_INT_ADR_REG);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++}
++
++#endif
++
++
++/*--------------------------------------------------------------------
++ *
++ * RXDP - low level interface
++ *
++ *--------------------------------------------------------------------*/
++
++void
++falcon_nic_set_rx_usr_buf_size(struct efhw_nic *nic, int usr_buf_bytes)
++{
++      FALCON_LOCK_DECL;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      uint64_t val, val2, usr_buf_size = usr_buf_bytes / 32;
++      int rubs_lbn, rubs_width, roec_lbn;
++
++      EFHW_BUILD_ASSERT(RX_CFG_REG_OFST == RX_CFG_REG_KER_OFST);
++
++      switch (nic->devtype.variant) {
++      default:
++              EFHW_ASSERT(0);
++              /* Fall-through to avoid compiler warnings. */
++      case 'A':
++              rubs_lbn = RX_USR_BUF_SIZE_A1_LBN;
++              rubs_width = RX_USR_BUF_SIZE_A1_WIDTH;
++              roec_lbn = RX_OWNERR_CTL_A1_LBN;
++              break;
++      case 'B':
++              rubs_lbn = RX_USR_BUF_SIZE_B0_LBN;
++              rubs_width = RX_USR_BUF_SIZE_B0_WIDTH;
++              roec_lbn = RX_OWNERR_CTL_B0_LBN;
++              break;
++      }
++
++      __DWCHCK(rubs_lbn, rubs_width);
++      __QWCHCK(roec_lbn, 1);
++      __RANGECHCK(usr_buf_size, rubs_width);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_read_qq(efhw_kva + RX_CFG_REG_OFST, &val, &val2);
++
++      val &= ~((__FALCON_MASK64(rubs_width)) << rubs_lbn);
++      val |= (usr_buf_size << rubs_lbn);
++
++      /* shouldn't be needed for a production driver */
++      val |= ((uint64_t) 1 << roec_lbn);
++
++      falcon_write_qq(efhw_kva + RX_CFG_REG_OFST, val, val2);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++}
++EXPORT_SYMBOL(falcon_nic_set_rx_usr_buf_size);
++
++void
++falcon_nic_rx_filter_ctl_get(struct efhw_nic *nic, uint32_t *tcp_full,
++                           uint32_t *tcp_wild,
++                           uint32_t *udp_full, uint32_t *udp_wild)
++{
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      FALCON_LOCK_DECL;
++      uint64_t val;
++
++      FALCON_LOCK_LOCK(nic);
++      falcon_read_q(efhw_kva + RX_FILTER_CTL_REG_OFST, &val);
++      FALCON_LOCK_UNLOCK(nic);
++
++      *tcp_full = (uint32_t)((val >> TCP_FULL_SRCH_LIMIT_LBN) &
++                             (__FALCON_MASK64(TCP_FULL_SRCH_LIMIT_WIDTH)));
++
++      *tcp_wild = (uint32_t)((val >> TCP_WILD_SRCH_LIMIT_LBN) &
++                             (__FALCON_MASK64(TCP_WILD_SRCH_LIMIT_WIDTH)));
++
++      *udp_full = (uint32_t)((val >> UDP_FULL_SRCH_LIMIT_LBN) &
++                             (__FALCON_MASK64(UDP_FULL_SRCH_LIMIT_WIDTH)));
++
++      *udp_wild = (uint32_t)((val >> UDP_WILD_SRCH_LIMIT_LBN) &
++                             (__FALCON_MASK64(UDP_WILD_SRCH_LIMIT_WIDTH)));
++}
++EXPORT_SYMBOL(falcon_nic_rx_filter_ctl_get);
++
++void
++falcon_nic_rx_filter_ctl_set(struct efhw_nic *nic, uint32_t tcp_full,
++                           uint32_t tcp_wild,
++                           uint32_t udp_full, uint32_t udp_wild)
++{
++      uint64_t val, val2;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      FALCON_LOCK_DECL;
++
++      EFHW_ASSERT(tcp_full < nic->filter_tbl_size);
++      EFHW_ASSERT(tcp_wild < nic->filter_tbl_size);
++      EFHW_ASSERT(udp_full < nic->filter_tbl_size);
++      EFHW_ASSERT(udp_wild < nic->filter_tbl_size);
++
++      /* until we implement a dynamic scaling of search limits we wish to
++       * maintain the same limits set up by default in the net driver
++       * when we initialize the char driver */
++      tcp_full_srch_limit = tcp_full;
++      tcp_wild_srch_limit = tcp_wild;
++      udp_full_srch_limit = udp_full;
++      udp_wild_srch_limit = udp_wild;
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_read_qq(efhw_kva + RX_FILTER_CTL_REG_OFST, &val, &val2);
++
++      /* Search limits */
++      val &= ~((__FALCON_MASK64(TCP_FULL_SRCH_LIMIT_WIDTH))
++               << TCP_FULL_SRCH_LIMIT_LBN);
++
++      val |= ((uint64_t)tcp_full + RX_FILTER_CTL_SRCH_FUDGE_FULL)
++          << TCP_FULL_SRCH_LIMIT_LBN;
++
++      val &= ~((__FALCON_MASK64(TCP_WILD_SRCH_LIMIT_WIDTH))
++               << TCP_WILD_SRCH_LIMIT_LBN);
++
++      val |= ((uint64_t)tcp_wild + RX_FILTER_CTL_SRCH_FUDGE_WILD)
++          << TCP_WILD_SRCH_LIMIT_LBN;
++
++      val &= ~((__FALCON_MASK64(UDP_FULL_SRCH_LIMIT_WIDTH))
++               << UDP_FULL_SRCH_LIMIT_LBN);
++
++      val |= ((uint64_t)udp_full + RX_FILTER_CTL_SRCH_FUDGE_FULL)
++          << UDP_FULL_SRCH_LIMIT_LBN;
++
++      val &= ~((__FALCON_MASK64(UDP_WILD_SRCH_LIMIT_WIDTH))
++               << UDP_WILD_SRCH_LIMIT_LBN);
++
++      val |= ((uint64_t)udp_wild + RX_FILTER_CTL_SRCH_FUDGE_WILD)
++          << UDP_WILD_SRCH_LIMIT_LBN;
++
++      falcon_write_qq(efhw_kva + RX_FILTER_CTL_REG_OFST, val, val2);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++}
++EXPORT_SYMBOL(falcon_nic_rx_filter_ctl_set);
++
++/*--------------------------------------------------------------------
++ *
++ * TXDP - low level interface
++ *
++ *--------------------------------------------------------------------*/
++
++_DEBUG_SYM_ void falcon_nic_tx_cfg(struct efhw_nic *nic, int unlocked)
++{
++      FALCON_LOCK_DECL;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      uint64_t val1, val2;
++
++      EFHW_BUILD_ASSERT(TX_CFG_REG_OFST == TX_CFG_REG_KER_OFST);
++      __DWCHCK(TX_OWNERR_CTL_LBN, TX_OWNERR_CTL_WIDTH);
++      __DWCHCK(TX_NON_IP_DROP_DIS_LBN, TX_NON_IP_DROP_DIS_WIDTH);
++
++      FALCON_LOCK_LOCK(nic);
++      falcon_read_qq(efhw_kva + TX_CFG_REG_OFST, &val1, &val2);
++
++      /* Will flag fatal interrupts on owner id errors. This should not be
++         on for production code because there is otherwise a denial of
++         serivce attack possible */
++      val1 |= (1 << TX_OWNERR_CTL_LBN);
++
++      /* Setup user queue TCP/UDP only packet security */
++      if (unlocked)
++              val1 |= (1 << TX_NON_IP_DROP_DIS_LBN);
++      else
++              val1 &= ~(1 << TX_NON_IP_DROP_DIS_LBN);
++
++      falcon_write_qq(efhw_kva + TX_CFG_REG_OFST, val1, val2);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Random thresholds - Low level interface (Would like these to be op
++ * defaults wherever possible)
++ *
++ *--------------------------------------------------------------------*/
++
++static void falcon_nic_pace_cfg(struct efhw_nic *nic)
++{
++      FALCON_LOCK_DECL;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      unsigned offset = 0;
++      uint64_t val;
++
++      val = 0xa81682;         /* !!!! */
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      switch (nic->devtype.variant) {
++      case 'A':  offset = TX_PACE_REG_A1_OFST;  break;
++      case 'B':  offset = TX_PACE_REG_B0_OFST;  break;
++      default:   EFHW_ASSERT(0);                break;
++      }
++      falcon_write_qq(efhw_kva + offset, val, 0);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++}
++
++/**********************************************************************
++ * Supporting modules. ************************************************
++ **********************************************************************/
++
++/*--------------------------------------------------------------------
++ *
++ * Filter support
++ *
++ *--------------------------------------------------------------------*/
++
++/*! \TODO this table should be per nic */
++struct falcon_cached_ipfilter {
++#if FALCON_FULL_FILTER_CACHE
++      unsigned dmaq;
++      unsigned saddr_le32;
++      unsigned daddr_le32;
++      unsigned sport_le16;
++      unsigned dport_le16;
++      unsigned tcp:1;
++      unsigned full:1;
++      unsigned rss_b0:1;
++      unsigned scat_b0:1;
++#endif
++      unsigned addr_valid:1;
++
++};
++
++
++/* TODO: Dynamically allocate this and store in struct efhw_nic. */
++static struct falcon_cached_ipfilter
++    host_ipfilter_cache[EFHW_MAX_NR_DEVS][FALCON_FILTER_TBL_NUM];
++
++
++static inline void host_ipfilter_cache_init(struct efhw_nic *nic)
++{
++      memset(host_ipfilter_cache[nic->index], 0,
++             sizeof(host_ipfilter_cache[0][0]) * nic->filter_tbl_size);
++}
++
++static inline int host_ipfilter_cache_active(struct efhw_nic *nic, uint idx)
++{
++      EFHW_ASSERT(nic->index < EFHW_MAX_NR_DEVS);
++      EFHW_ASSERT(idx < nic->filter_tbl_size);
++
++      return (host_ipfilter_cache[nic->index][idx].addr_valid);
++
++}
++
++static inline void host_ipfilter_cache_flush(struct efhw_nic *nic, uint idx)
++{
++      EFHW_ASSERT(nic->index < EFHW_MAX_NR_DEVS);
++      EFHW_ASSERT(idx < nic->filter_tbl_size);
++
++      memset(&host_ipfilter_cache[nic->index][idx], 0,
++             sizeof(struct falcon_cached_ipfilter));
++      mmiowb();
++}
++
++static inline void
++host_ipfilter_cache_set_addr(struct efhw_nic *nic, uint idx, uint dmaq,
++                           unsigned tcp, unsigned full,
++                           unsigned rss_b0, unsigned scat_b0,
++                           unsigned saddr_le32, unsigned sport_le16,
++                           unsigned daddr_le32, unsigned dport_le16)
++{
++      unsigned nic_i = nic->index;
++
++      EFHW_ASSERT(nic_i < EFHW_MAX_NR_DEVS);
++      EFHW_ASSERT(idx < nic->filter_tbl_size);
++      EFHW_ASSERT(!host_ipfilter_cache[nic_i][idx].addr_valid);
++
++      __RANGECHCK(sport_le16, SRC_TCP_DEST_UDP_1_WIDTH);
++      __RANGECHCK(dport_le16, SRC_TCP_DEST_UDP_1_WIDTH);
++
++#if FALCON_FULL_FILTER_CACHE
++      host_ipfilter_cache[nic_i][idx].dmaq = dmaq;
++      host_ipfilter_cache[nic_i][idx].saddr_le32 = saddr_le32;
++      host_ipfilter_cache[nic_i][idx].daddr_le32 = daddr_le32;
++      host_ipfilter_cache[nic_i][idx].sport_le16 = sport_le16;
++      host_ipfilter_cache[nic_i][idx].dport_le16 = dport_le16;
++      host_ipfilter_cache[nic_i][idx].tcp = tcp;
++      host_ipfilter_cache[nic_i][idx].full = full;
++      host_ipfilter_cache[nic_i][idx].rss_b0 = rss_b0;
++      host_ipfilter_cache[nic_i][idx].scat_b0 = scat_b0;
++#endif
++      host_ipfilter_cache[nic_i][idx].addr_valid = 1;
++      mmiowb();
++}
++
++#if FALCON_VERIFY_FILTERS
++/* Check that all active filters still exist by reading from H/W */
++static void _falcon_nic_ipfilter_sanity(struct efhw_nic *nic)
++{
++      unsigned i;
++      struct falcon_cached_ipfilter *f;
++      uint64_t q0_expect, q1_expect, q0_got, q1_got;
++
++      for (i = 0; i < nic->filter_tbl_size; i++) {
++              f = host_ipfilter_cache[nic->index] + i;
++              if (!f->addr_valid)
++                      continue;
++
++              _falcon_nic_ipfilter_build(nic, f->tcp, f->full,
++                                         f->rss_b0, f->scat_b0, i, f->dmaq,
++                                         f->saddr_le32, f->sport_le16,
++                                         f->daddr_le32, f->dport_le16,
++                                         &q0_expect, &q1_expect);
++
++              falcon_read_qq(EFHW_KVA(nic) + RX_FILTER_TBL0_OFST +
++                             i * 2 * FALCON_REGISTER128,
++                             &q0_got, &q1_got);
++
++              if ((q0_got != q0_expect) || (q1_got != q1_expect)) {
++                      falcon_write_qq(EFHW_KVA(nic) + 0x300,
++                                      q0_got, q1_got);
++                      EFHW_ERR("ERROR: RX-filter[%d][%d] was "
++                               "%"PRIx64":%" PRIx64" expected "
++                               "%"PRIx64":%"PRIx64,
++                               nic->index, i, q0_got, q1_got,
++                               q0_expect, q1_expect);
++              }
++      }
++}
++#endif /* FALCON_VERIFY_FILTERS */
++
++#if FALCON_FULL_FILTER_CACHE
++static inline int
++host_ipfilter_cache_check_not(uint nic, uint idx, int tcp, int full,
++                            unsigned saddr_le32, unsigned sport_le16,
++                            unsigned daddr_le32, unsigned dport_le16)
++{
++      return ((host_ipfilter_cache[nic][idx].saddr_le32 != saddr_le32) ||
++              (host_ipfilter_cache[nic][idx].daddr_le32 != daddr_le32) ||
++              (host_ipfilter_cache[nic][idx].sport_le16 != sport_le16) ||
++              (host_ipfilter_cache[nic][idx].dport_le16 != dport_le16) ||
++              (host_ipfilter_cache[nic][idx].tcp != tcp) ||
++              (host_ipfilter_cache[nic][idx].full != full));
++}
++#endif
++
++#define host_ipfilter_cache_saddr_le32(nic, idx) \
++              host_ipfilter_cache[nic][idx].saddr_le32
++#define host_ipfilter_cache_daddr_le32(nic, idx) \
++              host_ipfilter_cache[nic][idx].daddr_le32
++#define host_ipfilter_cache_sport_le16(nic, idx) \
++              host_ipfilter_cache[nic][idx].sport_le16
++#define host_ipfilter_cache_dport_le16(nic, idx) \
++              host_ipfilter_cache[nic][idx].dport_le16
++#define host_ipfilter_cache_tcp(nic, idx) \
++              host_ipfilter_cache[nic][idx].tcp
++#define host_ipfilter_cache_full(nic, idx) \
++              host_ipfilter_cache[nic][idx].full
++
++/**********************************************************************
++ * Implementation of the HAL. ********************************************
++ **********************************************************************/
++
++/*----------------------------------------------------------------------------
++ *
++ * Initialisation and configuration discovery
++ *
++ *---------------------------------------------------------------------------*/
++
++#ifdef __ci_ul_driver__
++
++static int falcon_nic_init_irq_channel(struct efhw_nic *nic, int enable)
++{
++      EFHW_ERR("%s: not implemented for ul driver", __FUNCTION__);
++      return -EOPNOTSUPP;
++}
++
++#else
++
++static int falcon_nic_init_irq_channel(struct efhw_nic *nic, int enable)
++{
++      /* create a buffer for the irq channel */
++      int rc;
++
++      if (enable) {
++              rc = efhw_iopage_alloc(nic, &nic->irq_iobuff);
++              if (rc < 0)
++                      return rc;
++
++              falcon_nic_irq_addr_set(nic,
++                              efhw_iopage_dma_addr(&nic->irq_iobuff));
++      } else {
++              if (efhw_iopage_is_valid(&nic->irq_iobuff))
++                      efhw_iopage_free(nic, &nic->irq_iobuff);
++
++              efhw_iopage_mark_invalid(&nic->irq_iobuff);
++              falcon_nic_irq_addr_set(nic, 0);
++      }
++
++      EFHW_TRACE("%s: " ci_dma_addr_fmt " %sable", __FUNCTION__,
++                 efhw_iopage_dma_addr(&nic->irq_iobuff), enable ?
++                      "en" : "dis");
++
++      return 0;
++}
++
++#endif
++
++static void falcon_nic_close_hardware(struct efhw_nic *nic)
++{
++      /* check we are in possession of some hardware */
++      if (!efhw_nic_have_hw(nic))
++              return;
++
++      falcon_nic_init_irq_channel(nic, 0);
++
++      EFHW_NOTICE("%s:", __FUNCTION__);
++}
++
++#ifdef __ci_ul_driver__
++extern
++#else
++static
++#endif
++int falcon_nic_get_mac_config(struct efhw_nic *nic)
++{
++      efhw_ioaddr_t efhw_kva = nic->bar_ioaddr;
++      int is_mac_type_1g;
++      uint32_t strap, altera;
++      uint64_t rx_cfg, r;
++
++      altera = readl(efhw_kva + ALTERA_BUILD_REG_OFST);
++      strap = readl(efhw_kva + STRAP_REG_KER_OFST) & 0x7;
++
++      switch (nic->devtype.variant) {
++      case 'A':
++              if ((altera & 0x0fff0000) == 0x1130000) {
++                      strap = 2;      /* FPGA - PCI-X 2G */
++              } else if ((altera & 0x00ff0000) == 0x140000) {
++                      /* should be 114 */
++                      strap = 4;      /* FPGA - PCI-X 4G */
++              } else if (strap < 2 || strap > 5) {
++                      EFHW_ERR("Invalid strap option %d altera_buid_ver=%x",
++                               strap, altera);
++                      return -EINVAL;
++              }
++              is_mac_type_1g = (0 != (strap & 2));
++              break;
++      case 'B':
++              /* Runtime check that the hardware and software agree about
++               * the size of the RXFIFO. Write binary 11 across the left
++               * most bit, and assert we get 1 back.
++               */
++              r = 1LL << RX_TOEP_TCP_SUPPRESS_B0_LBN;
++              r |= (r << 1);
++
++              /* Save the original value */
++              falcon_read_q(efhw_kva + RX_CFG_REG_OFST, &rx_cfg);
++
++              /* Write and ready the dummy value */
++              falcon_write_qq(efhw_kva + RX_CFG_REG_OFST, r, 0);
++              falcon_read_q(efhw_kva + RX_CFG_REG_OFST, &r);
++
++              /* Restore the original value */
++              falcon_write_qq(efhw_kva + RX_CFG_REG_OFST, rx_cfg, 0);
++
++              if (r != (1LL << RX_TOEP_TCP_SUPPRESS_B0_LBN)) {
++                      EFHW_ERR("The FPGA build (%x) RXFIFO size does not "
++                               "match the software", altera);
++                      return -EINVAL;
++              }
++              is_mac_type_1g = (0 != (strap & 2));
++#if FALCON_MAC_SET_TYPE_BY_SPEED
++              /* Check the selected strap pins against the MAC speed -
++               * and adjust if necessary.
++               */
++              {
++                      int speed;
++                      speed = readl(efhw_kva + MAC0_CTRL_REG_OFST) & 0x3;
++                      is_mac_type_1g = (speed <= 2);
++              }
++#endif
++              break;
++      default:
++              EFHW_ASSERT(0);
++              is_mac_type_1g = 0;
++              break;
++      }
++
++      nic->fpga_version = altera;
++
++      /* We can now set the MAC type correctly based on the strap pins. */
++      if (is_mac_type_1g) {
++              nic->flags &= ~NIC_FLAG_10G;
++      } else {
++              /* strap & 4 must be set according to checks above */
++              nic->flags |= NIC_FLAG_10G;
++      }
++      EFHW_NOTICE("Board has %s MAC: strap=%d",
++                  0 != (nic->flags & NIC_FLAG_10G) ? "10G" : "1G", strap);
++      return 0;
++}
++
++static int
++falcon_nic_init_hardware(struct efhw_nic *nic,
++                       struct efhw_ev_handler *ev_handlers,
++                       const uint8_t *mac_addr)
++{
++      int rc;
++
++      /* header sanity checks */
++      FALCON_ASSERT_VALID();
++
++      rc = falcon_nic_get_mac_config(nic);
++      if (rc < 0)
++              return rc;
++
++      /* Initialise supporting modules */
++      falcon_nic_ipfilter_ctor(nic);
++
++#if FALCON_USE_SHADOW_BUFFER_TABLE
++      CI_ZERO_ARRAY(_falcon_buffer_table, FALCON_BUFFER_TBL_NUM);
++#endif
++
++      /* Initialise the top level hardware blocks */
++      memcpy(nic->mac_addr, mac_addr, ETH_ALEN);
++
++      EFHW_TRACE("%s:", __FUNCTION__);
++
++      /* nic.c:efhw_nic_init marks all the interrupt units as unused.
++
++         ?? TODO we should be able to request the non-interrupting event
++         queue and the net driver's (for a net driver that is using libefhw)
++         additional RSS queues here.
++
++         Result would be that that net driver could call
++         nic.c:efhw_nic_allocate_common_hardware_resources() and that the
++         IFDEF FALCON's can be removed from
++         nic.c:efhw_nic_allocate_common_hardware_resources()
++       */
++      nic->irq_unit[0] = INT_EN_REG_CHAR_OFST;
++
++      /*****************************************************************
++       * The rest of this function deals with initialization of the NICs
++       * hardware (as opposed to the initialization of the
++       * struct efhw_nic data structure */
++
++      /* char driver grabs SRM events onto the non interrupting
++       * event queue */
++      falcon_nic_srm_upd_evq(nic, FALCON_EVQ_NONIRQ);
++
++      /* RXDP tweaks */
++
++      /* ?? bug2396 rx_cfg should be ok so long as the net driver
++       * always pushes buffers big enough for the link MTU */
++
++      /* set the RX buffer cutoff size to be the same as PAGE_SIZE.
++       * Use this value when we think that there will be a lot of
++       * jumbo frames.
++       *
++       * The default value 1600 is useful when packets are small,
++       * but would means that jumbo frame RX queues would need more
++       * descriptors pushing */
++      falcon_nic_set_rx_usr_buf_size(nic, FALCON_RX_USR_BUF_SIZE);
++
++      /* TXDP tweaks */
++      /* ?? bug2396 looks ok */
++      falcon_nic_tx_cfg(nic, /*unlocked(for non-UDP/TCP)= */ 0);
++      falcon_nic_pace_cfg(nic);
++
++      /* ?? bug2396
++       * netdriver must load first or else must RMW this register */
++      falcon_nic_rx_filter_ctl_set(nic, RX_FILTER_CTL_SRCH_LIMIT_TCP_FULL,
++                                   RX_FILTER_CTL_SRCH_LIMIT_TCP_WILD,
++                                   RX_FILTER_CTL_SRCH_LIMIT_UDP_FULL,
++                                   RX_FILTER_CTL_SRCH_LIMIT_UDP_WILD);
++
++      if (!(nic->flags & NIC_FLAG_NO_INTERRUPT)) {
++              rc = efhw_keventq_ctor(nic, FALCON_EVQ_CHAR, &nic->evq[0],
++                                     ev_handlers);
++              if (rc < 0) {
++                      EFHW_ERR("%s: efhw_keventq_ctor() failed (%d) evq=%d",
++                               __FUNCTION__, rc, FALCON_EVQ_CHAR);
++                      return rc;
++              }
++      }
++      rc = efhw_keventq_ctor(nic, FALCON_EVQ_NONIRQ,
++                             &nic->evq[FALCON_EVQ_NONIRQ], NULL);
++      if (rc < 0) {
++              EFHW_ERR("%s: efhw_keventq_ctor() failed (%d) evq=%d",
++                       __FUNCTION__, rc, FALCON_EVQ_NONIRQ);
++              return rc;
++      }
++
++      /* allocate IRQ channel */
++      rc = falcon_nic_init_irq_channel(nic, 1);
++      /* ignore failure at user-level for eftest */
++      if ((rc < 0) && !(nic->options & NIC_OPT_EFTEST))
++              return rc;
++
++      return 0;
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Interrupt
++ *
++ *--------------------------------------------------------------------*/
++
++static void
++falcon_nic_interrupt_enable(struct efhw_nic *nic, unsigned idx)
++{
++      int evq;
++
++      if (idx || (nic->flags & NIC_FLAG_NO_INTERRUPT))
++              return;
++
++      /* Enable driver interrupts */
++      EFHW_NOTICE("%s: enable master interrupt", __FUNCTION__);
++      falcon_nic_interrupt_hw_enable(nic);
++
++      /* An interrupting eventq must start of day ack its read pointer */
++      evq = falcon_idx_to_evq(nic, idx);
++
++      if (falcon_evq_is_interrupting(nic, evq)) {
++              struct efhw_keventq *q = &nic->evq[idx];
++              unsigned rdptr =
++                  EFHW_EVENT_OFFSET(q, q, 1) / sizeof(efhw_event_t);
++              falcon_nic_evq_ack(nic, evq, rdptr, false);
++              EFHW_NOTICE("%s: ACK evq[%d]:%x", __FUNCTION__, evq, rdptr);
++      }
++}
++
++static void falcon_nic_interrupt_disable(struct efhw_nic *nic, uint idx)
++{
++      /* NB. No need to check for NIC_FLAG_NO_INTERRUPT, as
++       ** falcon_nic_interrupt_hw_disable() will do it. */
++      if (idx)
++              return;
++      falcon_nic_interrupt_hw_disable(nic);
++}
++
++static void
++falcon_nic_set_interrupt_moderation(struct efhw_nic *nic, uint idx,
++                                  uint32_t val)
++{
++      falcon_timer_cmd(nic, falcon_idx_to_evq(nic, idx),
++                       TIMER_MODE_INT_HLDOFF, val / 5);
++}
++
++static inline void legacy_irq_ack(struct efhw_nic *nic)
++{
++      EFHW_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT));
++
++      if (!(nic->flags & NIC_FLAG_MSI)) {
++              writel(1, EFHW_KVA(nic) + INT_ACK_REG_CHAR_A1_OFST);
++              mmiowb();
++              /* ?? FIXME: We should be doing a read here to ensure IRQ is
++               * thoroughly acked before we return from ISR. */
++      }
++}
++
++static int falcon_nic_interrupt(struct efhw_nic *nic)
++{
++      volatile uint32_t *syserr_ptr =
++          (uint32_t *) efhw_iopage_ptr(&nic->irq_iobuff);
++      int handled = 0;
++      int done_ack = 0;
++
++      EFHW_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT));
++      EFHW_ASSERT(syserr_ptr);
++
++      /* FIFO fill level interrupt - just log it. */
++      if (unlikely(*(syserr_ptr + (DW0_OFST / 4)))) {
++              EFHW_WARN("%s: *** FIFO *** %x", __FUNCTION__,
++                        *(syserr_ptr + (DW0_OFST / 4)));
++              *(syserr_ptr + (DW0_OFST / 4)) = 0;
++              handled++;
++      }
++
++      /* Fatal interrupts. */
++      if (unlikely(*(syserr_ptr + (DW2_OFST / 4)))) {
++              *(syserr_ptr + (DW2_OFST / 4)) = 0;
++              falcon_nic_handle_fatal_int(nic);
++              handled++;
++      }
++
++      /* Event queue interrupt.  For legacy interrupts we have to check
++       * that the interrupt is for us, because it could be shared. */
++      if (*(syserr_ptr + (DW1_OFST / 4))) {
++              *(syserr_ptr + (DW1_OFST / 4)) = 0;
++              /* ACK must come before callback to handler fn. */
++              legacy_irq_ack(nic);
++              done_ack = 1;
++              handled++;
++              if (nic->irq_handler)
++                      nic->irq_handler(nic, 0);
++      }
++
++      if (unlikely(!done_ack)) {
++              if (!handled)
++                      /* Shared interrupt line (hopefully). */
++                      return 0;
++              legacy_irq_ack(nic);
++      }
++
++      EFHW_TRACE("%s: handled %d", __FUNCTION__, handled);
++      return 1;
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Event Management - and SW event posting
++ *
++ *--------------------------------------------------------------------*/
++
++static void
++falcon_nic_event_queue_enable(struct efhw_nic *nic, uint evq, uint evq_size,
++                            dma_addr_t q_base_addr,   /* not used */
++                            uint buf_base_id)
++{
++      EFHW_ASSERT(nic);
++
++      /*!\ TODO we can be more efficient if we know whether or not there
++       * is a timer attached */
++      falcon_timer_cmd(nic, evq, 0 /* disable */ , 0);
++
++      falcon_nic_evq_ptr_tbl(nic, evq, 1, buf_base_id, evq_size);
++      EFHW_TRACE("%s: enable evq %u size %u", __FUNCTION__, evq, evq_size);
++}
++
++static void
++falcon_nic_event_queue_disable(struct efhw_nic *nic, uint evq, int timer_only)
++{
++      EFHW_ASSERT(nic);
++
++      /*!\ TODO we can be more efficient if we know whether or not there
++       * is a timer attached */
++      falcon_timer_cmd(nic, evq, 0 /* disable */ , 0);
++
++      if (!timer_only)
++              falcon_nic_evq_ptr_tbl(nic, evq, 0, 0, 0);
++      EFHW_TRACE("%s: disenable evq %u", __FUNCTION__, evq);
++}
++
++static void
++falcon_nic_wakeup_request(struct efhw_nic *nic, dma_addr_t q_base_addr,
++                        int next_i, int evq)
++{
++      EFHW_ASSERT(evq > FALCON_EVQ_CHAR);
++      falcon_nic_evq_ack(nic, evq, next_i, true);
++      EFHW_TRACE("%s: evq %d next_i %d", __FUNCTION__, evq, next_i);
++}
++
++static void falcon_nic_sw_event(struct efhw_nic *nic, int data, int evq)
++{
++      uint64_t ev_data = data;
++
++      ev_data &= ~FALCON_EVENT_CODE_MASK;
++      ev_data |= FALCON_EVENT_CODE_SW;
++
++      falcon_drv_ev(nic, ev_data, evq);
++      EFHW_NOTICE("%s: evq[%d]->%x", __FUNCTION__, evq, data);
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Filter support - TODO vary the depth of the search
++ *
++ *--------------------------------------------------------------------*/
++
++void
++falcon_nic_ipfilter_ctor(struct efhw_nic *nic)
++{
++      if (nic->devtype.variant == 'B' && nic->fpga_version)
++              nic->filter_tbl_size = 8 * 1024;
++      else
++              nic->filter_tbl_size = 16 * 1024;
++
++      host_ipfilter_cache_init(nic);
++}
++
++
++static int
++falcon_nic_ipfilter_set(struct efhw_nic *nic, int type, int *_filter_idx,
++                      int dmaq,
++                      unsigned saddr_be32, unsigned sport_be16,
++                      unsigned daddr_be32, unsigned dport_be16)
++{
++      FALCON_LOCK_DECL;
++      int tcp;
++      int full;
++      int rss_b0;
++      int scat_b0;
++      int key, hash1, hash2, idx = -1;
++      int k;
++      int rc = 0;
++      unsigned max_srch = -1;
++
++      /* oh joy of joys .. maybe one day we'll optimise  */
++      unsigned int saddr = ntohl(saddr_be32);
++      unsigned int daddr = ntohl(daddr_be32);
++      unsigned int sport = ntohs(sport_be16);
++      unsigned int dport = ntohs(dport_be16);
++
++      __RANGECHCK(sport, SRC_TCP_DEST_UDP_1_WIDTH);
++      __RANGECHCK(dport, SRC_TCP_DEST_UDP_1_WIDTH);
++
++      tcp = ((type & EFHW_IP_FILTER_TYPE_TCP_MASK) != 0) ? 1 : 0;
++      full = ((type & EFHW_IP_FILTER_TYPE_FULL_MASK) != 0) ? 1 : 0;
++      rss_b0 = ((type & EFHW_IP_FILTER_TYPE_RSS_B0_MASK) != 0) ? 1 : 0;
++      scat_b0 = ((type & EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK) != 0) ? 0 : 1;
++      if (tcp && full)
++              max_srch = tcp_full_srch_limit;
++      else if (tcp && !full)
++              max_srch = tcp_wild_srch_limit;
++      else if (!tcp && full)
++              max_srch = udp_full_srch_limit;
++      else if (!tcp && !full)
++              max_srch = udp_wild_srch_limit;
++
++      EFHW_TRACE("%s: %x tcp %d full %d max_srch=%d",
++                 __FUNCTION__, type, tcp, full, max_srch);
++
++      /* The second hash function is simply
++       * h2(key) = 13 LSB of (key * 2 -  1)
++       * And the index(k), or the filter table address for kth search is
++       * index(k) = 13 LSB of (h1(key) + k * h2(key))
++       */
++      key = falcon_hash_get_key(saddr, sport, daddr, dport, tcp, full);
++      hash1 = falcon_hash_function1(key, nic->filter_tbl_size);
++      hash2 = falcon_hash_function2(key, nic->filter_tbl_size);
++
++      /* Avoid race to claim a filter entry */
++      FALCON_LOCK_LOCK(nic);
++
++      for (k = 0; (unsigned)k < max_srch; k++) {
++              idx = falcon_hash_iterator(hash1, hash2, k,
++                                         nic->filter_tbl_size);
++
++              EFHW_TRACE("ipfilter_set[%d:%d:%d]: src=%x:%d dest=%x:%d %s",
++                         *_filter_idx, idx, k,
++                         saddr, sport, daddr, dport,
++                         host_ipfilter_cache_active(nic, idx) ?
++                         "Active" : "Clear");
++
++              if (!host_ipfilter_cache_active(nic, idx))
++                      break;
++
++#if FALCON_FULL_FILTER_CACHE
++              /* Check that we are not duplicating the filter */
++              if (!host_ipfilter_cache_check_not(nic->index, idx, tcp, full,
++                                                 saddr, sport, daddr,
++                                                 dport)) {
++                      EFHW_WARN("%s: ERROR: duplicate filter (disabling "
++                                "interrupts)", __FUNCTION__);
++                      FALCON_LOCK_UNLOCK(nic);
++                      falcon_nic_interrupt_hw_disable(nic);
++                      return -EINVAL;
++              }
++#endif
++
++      }
++      if (k == max_srch) {
++              rc = -EADDRINUSE;
++              idx = -1;
++              goto fail1;
++      }
++
++      EFHW_ASSERT(idx < (int)nic->filter_tbl_size);
++
++      host_ipfilter_cache_set_addr(nic, idx, dmaq, tcp, full, rss_b0,
++                                   scat_b0, saddr, sport, daddr, dport);
++
++      _falcon_nic_ipfilter_set(nic, tcp, full, rss_b0,
++                               scat_b0, idx, dmaq,
++                               saddr, sport, daddr, dport);
++
++      *_filter_idx = idx;
++
++      EFHW_TRACE("%s: filter %x rxq %d src " NIPQUAD_FMT
++                 ":%d dest " NIPQUAD_FMT ":%d set in %d",
++                 __FUNCTION__, idx, dmaq,
++                 NIPQUAD(&saddr), sport, NIPQUAD(&daddr), dport, k);
++
++fail1:
++      FALCON_LOCK_UNLOCK(nic);
++      return rc;
++}
++
++static void
++falcon_nic_ipfilter_attach(struct efhw_nic *nic, int filter_idx, int dmaq_idx)
++{
++      /* Intentionally empty - Falcon attaches and sets the filter
++       * in filter_set */
++      EFHW_TRACE("%s: attach filter %x with rxq %d - ignored",
++                 __FUNCTION__, filter_idx, dmaq_idx);
++}
++
++static void falcon_nic_ipfilter_detach(struct efhw_nic *nic, int filter_idx)
++{
++      /* Intentionally empty - Falcon attaches and sets the filter
++       * in filter_clear */
++      EFHW_TRACE("%s: detach filter %x from rxq - ignored",
++                 __FUNCTION__, filter_idx);
++}
++
++static void falcon_nic_ipfilter_clear(struct efhw_nic *nic, int filter_idx)
++{
++      FALCON_LOCK_DECL;
++
++      EFHW_TRACE("%s: filter %x", __FUNCTION__, filter_idx);
++
++      /* In case the filter has already been freed */
++      if (filter_idx == -1)
++              return;
++
++      FALCON_LOCK_LOCK(nic);
++
++      /* if we flush a chained hash then all we need to do is zero it out */
++      host_ipfilter_cache_flush(nic, filter_idx);
++      _falcon_nic_ipfilter_clear(nic, filter_idx);
++
++      FALCON_LOCK_UNLOCK(nic);
++      return;
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Buffer table - helpers
++ *
++ *--------------------------------------------------------------------*/
++
++#define FALCON_LAZY_COMMIT_HWM (FALCON_BUFFER_UPD_MAX - 16)
++
++/* Note re.:
++ *  falcon_nic_buffer_table_lazy_commit(struct efhw_nic *nic)
++ *  falcon_nic_buffer_table_update_poll(struct efhw_nic *nic)
++ *  falcon_nic_buffer_table_confirm(struct efhw_nic *nic)
++ * -- these are no-ops in the user-level driver because it would need to
++ * coordinate with the real driver on the number of outstanding commits.
++ *
++ * An exception is made for eftest apps, which manage the hardware without
++ * using the char driver.
++ */
++
++static inline void falcon_nic_buffer_table_lazy_commit(struct efhw_nic *nic)
++{
++#if defined(__ci_ul_driver__)
++      if (!(nic->options & NIC_OPT_EFTEST))
++              return;
++#endif
++
++      /* Do nothing if operating in synchronous mode. */
++      if (!nic->irq_handler)
++              return;
++}
++
++static inline void falcon_nic_buffer_table_update_poll(struct efhw_nic *nic)
++{
++      FALCON_LOCK_DECL;
++      int count = 0, rc = 0;
++
++#if defined(__ci_ul_driver__)
++      if (!(nic->options & NIC_OPT_EFTEST))
++              return;
++#endif
++
++      /* We can be called here early days */
++      if (!nic->irq_handler)
++              return;
++
++      /* If we need to gather buffer update events then poll the
++         non-interrupting event queue */
++
++      /* For each _buffer_table_commit there will be an update done
++         event. We don't keep track of how many buffers each commit has
++         committed, just make sure that all the expected events have been
++         gathered */
++      FALCON_LOCK_LOCK(nic);
++
++      EFHW_TRACE("%s: %d", __FUNCTION__, nic->buf_commit_outstanding);
++
++      while (nic->buf_commit_outstanding > 0) {
++              /* we're not expecting to handle any events that require
++               * upcalls into the core driver */
++              struct efhw_ev_handler handler;
++              memset(&handler, 0, sizeof(handler));
++              nic->evq[FALCON_EVQ_NONIRQ].ev_handlers = &handler;
++              rc = efhw_keventq_poll(nic, &nic->evq[FALCON_EVQ_NONIRQ]);
++              nic->evq[FALCON_EVQ_NONIRQ].ev_handlers = NULL;
++
++              if (rc < 0) {
++                      EFHW_ERR("%s: poll ERROR (%d:%d) ***** ",
++                               __FUNCTION__, rc,
++                               nic->buf_commit_outstanding);
++                      goto out;
++              }
++
++              FALCON_LOCK_UNLOCK(nic);
++
++              if (count++)
++                      udelay(1);
++
++              if (count > 1000) {
++                      EFHW_WARN("%s: poll Timeout ***** (%d)", __FUNCTION__,
++                                nic->buf_commit_outstanding);
++                      nic->buf_commit_outstanding = 0;
++                      return;
++              }
++              FALCON_LOCK_LOCK(nic);
++      }
++
++out:
++      FALCON_LOCK_UNLOCK(nic);
++      return;
++}
++
++void falcon_nic_buffer_table_confirm(struct efhw_nic *nic)
++{
++      /* confirm buffer table updates - should be used for items where
++         loss of data would be unacceptable. E.g for the buffers that back
++         an event or DMA queue */
++      FALCON_LOCK_DECL;
++
++#if defined(__ci_ul_driver__)
++      if (!(nic->options & NIC_OPT_EFTEST))
++              return;
++#endif
++
++      /* Do nothing if operating in synchronous mode. */
++      if (!nic->irq_handler)
++              return;
++
++      FALCON_LOCK_LOCK(nic);
++
++      _falcon_nic_buffer_table_commit(nic);
++
++      FALCON_LOCK_UNLOCK(nic);
++
++      falcon_nic_buffer_table_update_poll(nic);
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Buffer table - API
++ *
++ *--------------------------------------------------------------------*/
++
++static void
++falcon_nic_buffer_table_clear(struct efhw_nic *nic, int buffer_id, int num)
++{
++      FALCON_LOCK_DECL;
++      FALCON_LOCK_LOCK(nic);
++      _falcon_nic_buffer_table_clear(nic, buffer_id, num);
++      FALCON_LOCK_UNLOCK(nic);
++}
++
++static void
++falcon_nic_buffer_table_set(struct efhw_nic *nic, dma_addr_t dma_addr,
++                          uint bufsz, uint region,
++                          int own_id, int buffer_id)
++{
++      FALCON_LOCK_DECL;
++
++      EFHW_ASSERT(region < FALCON_REGION_NUM);
++
++      EFHW_ASSERT((bufsz == EFHW_4K) ||
++                  (bufsz == EFHW_8K && FALCON_BUFFER_TABLE_FULL_MODE));
++
++      falcon_nic_buffer_table_update_poll(nic);
++
++      FALCON_LOCK_LOCK(nic);
++
++      _falcon_nic_buffer_table_set(nic, dma_addr, bufsz, region, own_id,
++                                   buffer_id);
++
++      falcon_nic_buffer_table_lazy_commit(nic);
++
++      FALCON_LOCK_UNLOCK(nic);
++}
++
++void
++falcon_nic_buffer_table_set_n(struct efhw_nic *nic, int buffer_id,
++                            dma_addr_t dma_addr, uint bufsz, uint region,
++                            int n_pages, int own_id)
++{
++      /* used to set up a contiguous range of buffers */
++      FALCON_LOCK_DECL;
++
++      EFHW_ASSERT(region < FALCON_REGION_NUM);
++
++      EFHW_ASSERT((bufsz == EFHW_4K) ||
++                  (bufsz == EFHW_8K && FALCON_BUFFER_TABLE_FULL_MODE));
++
++      while (n_pages--) {
++
++              falcon_nic_buffer_table_update_poll(nic);
++
++              FALCON_LOCK_LOCK(nic);
++
++              _falcon_nic_buffer_table_set(nic, dma_addr, bufsz, region,
++                                           own_id, buffer_id++);
++
++              falcon_nic_buffer_table_lazy_commit(nic);
++
++              FALCON_LOCK_UNLOCK(nic);
++
++              dma_addr += bufsz;
++      }
++}
++
++/*--------------------------------------------------------------------
++ *
++ * DMA Queues - mid level API
++ *
++ *--------------------------------------------------------------------*/
++
++#if BUG5302_WORKAROUND
++
++/* Tx queues can get stuck if the software write pointer is set to an index
++ * beyond the configured size of the queue, such that they will not flush.
++ * This code can be run before attempting a flush; it will detect the bogus
++ * value and reset it.  This fixes most instances of this problem, although
++ * sometimes it does not work, or we may not detect it in the first place,
++ * if the out-of-range value was replaced by an in-range value earlier.
++ * (In those cases we have to apply a bigger hammer later, if we see that
++ * the queue is still not flushing.)
++ */
++static void
++falcon_check_for_bogus_tx_dma_wptr(struct efhw_nic *nic, uint dmaq)
++{
++      FALCON_LOCK_DECL;
++      uint64_t val_low64, val_high64;
++      uint64_t size, hwptr, swptr, val;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      ulong offset = falcon_dma_tx_q_offset(nic, dmaq);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_read_qq(efhw_kva + offset, &val_low64, &val_high64);
++      FALCON_LOCK_UNLOCK(nic);
++
++      size = (val_low64 >> TX_DESCQ_SIZE_LBN)
++          & __FALCON_MASK64(TX_DESCQ_SIZE_WIDTH);
++      size = (1 << size) * 512;
++      hwptr = (val_high64 >> __DW3(TX_DESCQ_HW_RPTR_LBN))
++          & __FALCON_MASK64(TX_DESCQ_HW_RPTR_WIDTH);
++      swptr = (val_low64 >> TX_DESCQ_SW_WPTR_LBN)
++          & __FALCON_MASK64(__LW2(TX_DESCQ_SW_WPTR_LBN));
++      val = (val_high64)
++          &
++          __FALCON_MASK64(__DW3
++                          (TX_DESCQ_SW_WPTR_LBN + TX_DESCQ_SW_WPTR_WIDTH));
++      val = val << __LW2(TX_DESCQ_SW_WPTR_LBN);
++      swptr = swptr | val;
++
++      if (swptr >= size) {
++              EFHW_WARN("Resetting bad write pointer for TXQ[%d]", dmaq);
++              writel((uint32_t) ((hwptr + 0) & (size - 1)),
++                     efhw_kva + falcon_tx_dma_page_addr(dmaq) + 12);
++              mmiowb();
++      }
++}
++
++/* Here's that "bigger hammer": we reset all the pointers (hardware read,
++ * hardware descriptor cache read, software write) to zero.
++ */
++void falcon_clobber_tx_dma_ptrs(struct efhw_nic *nic, uint dmaq)
++{
++      FALCON_LOCK_DECL;
++      uint64_t val_low64, val_high64;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      ulong offset = falcon_dma_tx_q_offset(nic, dmaq);
++
++      EFHW_WARN("Recovering stuck TXQ[%d]", dmaq);
++      FALCON_LOCK_LOCK(nic);
++      falcon_read_qq(efhw_kva + offset, &val_low64, &val_high64);
++      val_high64 &= ~(__FALCON_MASK64(TX_DESCQ_HW_RPTR_WIDTH)
++                      << __DW3(TX_DESCQ_HW_RPTR_LBN));
++      val_high64 &= ~(__FALCON_MASK64(TX_DC_HW_RPTR_WIDTH)
++                      << __DW3(TX_DC_HW_RPTR_LBN));
++      falcon_write_qq(efhw_kva + offset, val_low64, val_high64);
++      mmiowb();
++      writel(0, efhw_kva + falcon_tx_dma_page_addr(dmaq) + 12);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++}
++
++#endif
++
++static inline int
++__falcon_really_flush_tx_dma_channel(struct efhw_nic *nic, uint dmaq)
++{
++      FALCON_LOCK_DECL;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      uint val;
++
++      EFHW_BUILD_ASSERT(TX_FLUSH_DESCQ_REG_KER_OFST ==
++                        TX_FLUSH_DESCQ_REG_OFST);
++
++      __DWCHCK(TX_FLUSH_DESCQ_CMD_LBN, TX_FLUSH_DESCQ_CMD_WIDTH);
++      __DWCHCK(TX_FLUSH_DESCQ_LBN, TX_FLUSH_DESCQ_WIDTH);
++      __RANGECHCK(dmaq, TX_FLUSH_DESCQ_WIDTH);
++
++      val = ((1 << TX_FLUSH_DESCQ_CMD_LBN) | (dmaq << TX_FLUSH_DESCQ_LBN));
++
++      EFHW_TRACE("TX DMA flush[%d]", dmaq);
++
++#if BUG5302_WORKAROUND
++      falcon_check_for_bogus_tx_dma_wptr(nic, dmaq);
++#endif
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(efhw_kva + TX_FLUSH_DESCQ_REG_OFST,
++                      val, FALCON_ATOMIC_TX_FLUSH_DESCQ);
++
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++      return 0;
++}
++
++static inline int
++__falcon_is_tx_dma_channel_flushed(struct efhw_nic *nic, uint dmaq)
++{
++      FALCON_LOCK_DECL;
++      uint64_t val_low64, val_high64;
++      uint64_t enable, flush_pending;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      ulong offset = falcon_dma_tx_q_offset(nic, dmaq);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_read_qq(efhw_kva + offset, &val_low64, &val_high64);
++      FALCON_LOCK_UNLOCK(nic);
++
++      /* should see one of three values for these 2 bits
++       *   1, queue enabled no flush pending
++       *      - i.e. first flush request
++       *   2, queue enabled, flush pending
++       *      - i.e. request to reflush before flush finished
++       *   3, queue disabled (no flush pending)
++       *      - flush complete
++       */
++      __DWCHCK(TX_DESCQ_FLUSH_LBN, TX_DESCQ_FLUSH_WIDTH);
++      __DW3CHCK(TX_DESCQ_EN_LBN, TX_DESCQ_EN_WIDTH);
++      enable = val_high64 & (1 << __DW3(TX_DESCQ_EN_LBN));
++      flush_pending = val_low64 & (1 << TX_DESCQ_FLUSH_LBN);
++
++      if (enable && !flush_pending)
++              return 0;
++
++      EFHW_TRACE("%d, %s: %s, %sflush pending", dmaq, __FUNCTION__,
++                 enable ? "enabled" : "disabled",
++                 flush_pending ? "" : "NO ");
++      /* still in progress */
++      if (enable && flush_pending)
++              return -EALREADY;
++
++      return -EAGAIN;
++}
++
++static int falcon_flush_tx_dma_channel(struct efhw_nic *nic, uint dmaq)
++{
++      int rc;
++      rc = __falcon_is_tx_dma_channel_flushed(nic, dmaq);
++      if (rc < 0) {
++              EFHW_WARN("%s: failed %d", __FUNCTION__, rc);
++              return rc;
++      }
++      return __falcon_really_flush_tx_dma_channel(nic, dmaq);
++}
++
++static int
++__falcon_really_flush_rx_dma_channel(struct efhw_nic *nic, uint dmaq)
++{
++      FALCON_LOCK_DECL;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      uint val;
++
++      EFHW_BUILD_ASSERT(RX_FLUSH_DESCQ_REG_KER_OFST ==
++                        RX_FLUSH_DESCQ_REG_OFST);
++
++      __DWCHCK(RX_FLUSH_DESCQ_CMD_LBN, RX_FLUSH_DESCQ_CMD_WIDTH);
++      __DWCHCK(RX_FLUSH_DESCQ_LBN, RX_FLUSH_DESCQ_WIDTH);
++      __RANGECHCK(dmaq, RX_FLUSH_DESCQ_WIDTH);
++
++      val = ((1 << RX_FLUSH_DESCQ_CMD_LBN) | (dmaq << RX_FLUSH_DESCQ_LBN));
++
++      EFHW_TRACE("RX DMA flush[%d]", dmaq);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_write_qq(efhw_kva + RX_FLUSH_DESCQ_REG_OFST, val,
++                      FALCON_ATOMIC_RX_FLUSH_DESCQ);
++      mmiowb();
++      FALCON_LOCK_UNLOCK(nic);
++      return 0;
++}
++
++static inline int
++__falcon_is_rx_dma_channel_flushed(struct efhw_nic *nic, uint dmaq)
++{
++      FALCON_LOCK_DECL;
++      uint64_t val;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      ulong offset = falcon_dma_rx_q_offset(nic, dmaq);
++
++      /* Falcon requires 128 bit atomic access for this register */
++      FALCON_LOCK_LOCK(nic);
++      falcon_read_q(efhw_kva + offset, &val);
++      FALCON_LOCK_UNLOCK(nic);
++
++      __DWCHCK(RX_DESCQ_EN_LBN, RX_DESCQ_EN_WIDTH);
++
++      /* is it enabled? */
++      return (val & (1 << RX_DESCQ_EN_LBN))
++          ? 0 : -EAGAIN;
++}
++
++static int falcon_flush_rx_dma_channel(struct efhw_nic *nic, uint dmaq)
++{
++      int rc;
++      rc = __falcon_is_rx_dma_channel_flushed(nic, dmaq);
++      if (rc < 0) {
++              EFHW_ERR("%s: failed %d", __FUNCTION__, rc);
++              return rc;
++      }
++      return __falcon_really_flush_rx_dma_channel(nic, dmaq);
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Falcon specific event callbacks
++ *
++ *--------------------------------------------------------------------*/
++
++int
++falcon_handle_char_event(struct efhw_nic *nic, struct efhw_ev_handler *h,
++                       efhw_event_t *ev)
++{
++      EFHW_TRACE("DRIVER EVENT: "FALCON_EVENT_FMT,
++                 FALCON_EVENT_PRI_ARG(*ev));
++
++      switch (FALCON_EVENT_DRIVER_SUBCODE(ev)) {
++
++      case TX_DESCQ_FLS_DONE_EV_DECODE:
++              EFHW_TRACE("TX[%d] flushed",
++                         (int)FALCON_EVENT_TX_FLUSH_Q_ID(ev));
++#if !defined(__ci_ul_driver__)
++              efhw_handle_txdmaq_flushed(nic, h, ev);
++#endif
++              break;
++
++      case RX_DESCQ_FLS_DONE_EV_DECODE:
++              EFHW_TRACE("RX[%d] flushed",
++                         (int)FALCON_EVENT_TX_FLUSH_Q_ID(ev));
++#if !defined(__ci_ul_driver__)
++              efhw_handle_rxdmaq_flushed(nic, h, ev);
++#endif
++              break;
++
++      case SRM_UPD_DONE_EV_DECODE:
++              nic->buf_commit_outstanding =
++                  max(0, nic->buf_commit_outstanding - 1);
++              EFHW_TRACE("COMMIT DONE %d", nic->buf_commit_outstanding);
++              break;
++
++      case EVQ_INIT_DONE_EV_DECODE:
++              EFHW_TRACE("EVQ INIT");
++              break;
++
++      case WAKE_UP_EV_DECODE:
++              EFHW_TRACE("WAKE UP");
++              efhw_handle_wakeup_event(nic, h, ev);
++              break;
++
++      case TIMER_EV_DECODE:
++              EFHW_TRACE("TIMER");
++              efhw_handle_timeout_event(nic, h, ev);
++              break;
++
++      case RX_DESCQ_FLSFF_OVFL_EV_DECODE:
++              /* This shouldn't happen. */
++              EFHW_ERR("%s: RX flush fifo overflowed", __FUNCTION__);
++              return -EINVAL;
++
++      default:
++              EFHW_TRACE("UNKOWN DRIVER EVENT: " FALCON_EVENT_FMT,
++                         FALCON_EVENT_PRI_ARG(*ev));
++              break;
++      }
++      return 0;
++}
++
++/*--------------------------------------------------------------------
++ *
++ * Abstraction Layer Hooks
++ *
++ *--------------------------------------------------------------------*/
++
++struct efhw_func_ops falcon_char_functional_units = {
++      falcon_nic_close_hardware,
++      falcon_nic_init_hardware,
++      falcon_nic_interrupt,
++      falcon_nic_interrupt_enable,
++      falcon_nic_interrupt_disable,
++      falcon_nic_set_interrupt_moderation,
++      falcon_nic_event_queue_enable,
++      falcon_nic_event_queue_disable,
++      falcon_nic_wakeup_request,
++      falcon_nic_sw_event,
++      falcon_nic_ipfilter_set,
++      falcon_nic_ipfilter_attach,
++      falcon_nic_ipfilter_detach,
++      falcon_nic_ipfilter_clear,
++      falcon_dmaq_tx_q_init,
++      falcon_dmaq_rx_q_init,
++      falcon_dmaq_tx_q_disable,
++      falcon_dmaq_rx_q_disable,
++      falcon_flush_tx_dma_channel,
++      falcon_flush_rx_dma_channel,
++      falcon_nic_buffer_table_set,
++      falcon_nic_buffer_table_set_n,
++      falcon_nic_buffer_table_clear,
++      falcon_nic_buffer_table_commit,
++};
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/falcon_hash.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/falcon_hash.c     2008-05-19 00:33:29.425842266 +0300
+@@ -0,0 +1,178 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains EtherFabric NIC hash algorithms implementation.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efhw/debug.h>
++#include <ci/driver/efab/hardware.h>
++
++
++/* this mask is per filter bank hence /2 */
++#define FILTER_MASK(n)  ((n) / 2u - 1u)
++
++/*
++ *  Main Functions related to the Hash Table Generation
++ *  Author: Srinivasaih, Nataraj
++ * Created: Thu May 13:32:41 PDT 2004
++ * $Id$
++ */
++/***************************************************************************
++Class Maximum number of       Valid address ranges
++      hosts per network
++A     16777214                1.0.0.1 through 9.255.255.254
++                              11.0.0.1 through 126.255.255.254
++B     65534                   128.0.0.1 through 172.15.255.254
++                              172.32.0.1 through 191.255.255.254
++C     254                     192.0.0.1 through 192.167.255.254
++                              192.169.0.1 through 223.255.255.254
++P     16777214                10.0.0.1 through 10.255.255.254 (10/8)
++      1048574                 172.16.0.1 through 172.31.255.254 (172.16/12)
++      65534                   192.168.0.1 through 192.168.255.254 (192.168/16)
++
++R     -                       0.0.0.0 through 0.255.255.255
++                              (used if host will be assigned a
++                              valid address dynamically)
++                              127.0.0.0 through 127.255.255.255
++                              (loopback addresses)
++
++P : Private internets only
++R : Reserved
++****************************************************************************/
++
++/* All LE parameters */
++unsigned int
++falcon_hash_get_key(unsigned int src_ip, unsigned int src_port,
++                  unsigned int dest_ip, unsigned int dest_port,
++                  int tcp, int full)
++{
++
++      unsigned int result = 0;
++      int net_type;
++
++      EFHW_ASSERT(tcp == 0 || tcp == 1);
++      EFHW_ASSERT(full == 0 || full == 1);
++
++      net_type = tcp << 4 | full;
++
++      /* Note that src_ip and src_port ignored if a wildcard filter */
++      switch (net_type) {
++      case 0x01:              /* UDP Full */
++              result = ((dest_ip & 0xfffffffe) | (!(dest_ip & 1))) ^
++                  (((dest_port << 16) & 0xFFFF0000) |
++                   ((src_ip >> 16) & 0x0000FFFF)) ^
++                  (((src_ip << 16) & 0xFFFF0000) |
++                   ((src_port & 0x0000FFFF)));
++              EFHW_TRACE("falcon_hash_get_key: UDP Full %x", result);
++              break;
++      case 0x00:              /* UDP Wild Card */
++              result = ((dest_ip & 0xfffffffe) | (!(dest_ip & 1))) ^
++                  (((dest_port << 16) & 0x00000000) |
++                   ((src_ip >> 16) & 0x00000000)) ^
++                  (((src_ip << 16) & 0x00000000) |
++                   ((dest_port & 0x0000FFFF)));
++              EFHW_TRACE("falcon_hash_get_key: UDP Wildcard %x", result);
++              break;
++      case 0x10:              /* TCP Wild Card */
++              result = (dest_ip) ^
++                  (((dest_port << 16) & 0xFFFF0000) |
++                   ((src_ip >> 16) & 0x00000000)) ^
++                  (((src_ip << 16) & 0x00000000) |
++                   ((src_port & 0x00000000)));
++              EFHW_TRACE("falcon_hash_get_key: TCP Wildcard %x", result);
++              break;
++      case 0x11:              /* TCP Full */
++              result = (dest_ip) ^
++                  (((dest_port << 16) & 0xFFFF0000) |
++                   ((src_ip >> 16) & 0x0000FFFF)) ^
++                  (((src_ip << 16) & 0xFFFF0000) |
++                   ((src_port & 0x0000FFFF)));
++              EFHW_TRACE("falcon_hash_get_key: TCP Full %x", result);
++              break;
++      default:
++              EFHW_ASSERT(0);
++
++      }
++      return (result);
++}
++
++/* This function generates the First Hash key */
++unsigned int falcon_hash_function1(unsigned int key, unsigned int nfilters)
++{
++
++      unsigned short int lfsr_reg;
++      unsigned int tmp_key;
++      int index;
++
++      unsigned short int lfsr_input;
++      unsigned short int single_bit_key;
++      unsigned short int bit16_lfsr;
++      unsigned short int bit3_lfsr;
++
++      lfsr_reg = 0xFFFF;
++      tmp_key = key;
++
++      /* For Polynomial equation X^16+X^3+1 */
++      for (index = 0; index < 32; index++) {
++              /* Get the bit from key and shift the key */
++              single_bit_key = (tmp_key & 0x80000000) >> 31;
++              tmp_key = tmp_key << 1;
++
++              /* get the Tap bits to XOR operation */
++              bit16_lfsr = (lfsr_reg & 0x8000) >> 15;
++              bit3_lfsr = (lfsr_reg & 0x0004) >> 2;
++
++              /* Get the Input value to the LFSR */
++              lfsr_input = ((bit16_lfsr ^ bit3_lfsr) ^ single_bit_key);
++
++              /* Shift and store out of the two TAPs */
++              lfsr_reg = lfsr_reg << 1;
++              lfsr_reg = lfsr_reg | (lfsr_input & 0x0001);
++
++      }
++
++      lfsr_reg = lfsr_reg & FILTER_MASK(nfilters);
++
++      return lfsr_reg;
++}
++
++/* This function generates the Second Hash */
++unsigned int
++falcon_hash_function2(unsigned int key, unsigned int nfilters)
++{
++      return (unsigned int)(((unsigned long long)key * 2 - 1) &
++                            FILTER_MASK(nfilters));
++}
++
++/* This function iterates through the hash table */
++unsigned int
++falcon_hash_iterator(unsigned int hash1, unsigned int hash2,
++                   unsigned int n_search, unsigned int nfilters)
++{
++      return ((hash1 + (n_search * hash2)) & FILTER_MASK(nfilters));
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/falcon_mac.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/falcon_mac.c      2008-05-19 00:33:29.425842266 +0300
+@@ -0,0 +1,171 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains MACs (Mentor MAC & GDACT1 ) support for Falcon.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efhw/falcon.h>
++#include <ci/driver/efab/hardware.h>
++
++/********************************************************************
++ * Mentor MAC
++ */
++
++#define _PRE(x)       GM##x
++
++/*--------------------------------------------------------------------
++ *
++ * Debug Support
++ *
++ *--------------------------------------------------------------------*/
++
++#define MENTOR_MAC_ASSERT_VALID()                                     \
++    EFHW_ASSERT(nic);                                                 \
++    EFHW_ASSERT(EFHW_KVA(nic));                                               \
++    EFHW_ASSERT(_PRE(_CFG1_REG_OFST) == _PRE(_CFG1_REG_KER_OFST));    \
++    EFHW_ASSERT(_PRE(_CFG2_REG_OFST) == _PRE(_CFG2_REG_KER_OFST));    \
++    EFHW_ASSERT(_PRE(_IPG_REG_OFST) == _PRE(_IPG_REG_KER_OFST));      \
++    EFHW_ASSERT(_PRE(_HD_REG_OFST) == _PRE(_HD_REG_KER_OFST));                \
++    EFHW_ASSERT(_PRE(_MAX_FLEN_REG_OFST) == _PRE(_MAX_FLEN_REG_KER_OFST)); \
++    EFHW_ASSERT(_PRE(_TEST_REG_OFST) == _PRE(_TEST_REG_KER_OFST));    \
++    EFHW_ASSERT(_PRE(_ADR1_REG_OFST) == _PRE(_ADR1_REG_KER_OFST));    \
++    EFHW_ASSERT(_PRE(_ADR2_REG_OFST) == _PRE(_ADR2_REG_KER_OFST));    \
++    EFHW_ASSERT(_PRE(F_CFG0_REG_OFST) == _PRE(F_CFG0_REG_KER_OFST));  \
++    EFHW_ASSERT(_PRE(F_CFG1_REG_OFST) == _PRE(F_CFG1_REG_KER_OFST));  \
++    EFHW_ASSERT(_PRE(F_CFG2_REG_OFST) == _PRE(F_CFG2_REG_KER_OFST));  \
++    EFHW_ASSERT(_PRE(F_CFG3_REG_OFST) == _PRE(F_CFG3_REG_KER_OFST));  \
++    EFHW_ASSERT(_PRE(F_CFG4_REG_OFST) == _PRE(F_CFG4_REG_KER_OFST));  \
++    EFHW_ASSERT(_PRE(F_CFG5_REG_OFST) == _PRE(F_CFG5_REG_KER_OFST));
++
++/*! Get MAC current address - i.e not necessarily the one in the EEPROM */
++static inline void mentormac_get_mac_addr(struct efhw_nic *nic)
++{
++      efhw_ioaddr_t mac_kva;
++      uint val1, val2;
++
++      MENTOR_MAC_ASSERT_VALID();
++
++      mac_kva = GM_P0_BASE + EFHW_KVA(nic);
++
++      val1 = readl(mac_kva + _PRE(_ADR1_REG_OFST));
++      val2 = readl(mac_kva + _PRE(_ADR2_REG_OFST));
++
++#if 0
++      nic->mac_addr[0] = (val1 & 0xff000000) >> 24;
++      nic->mac_addr[1] = (val1 & 0x00ff0000) >> 16;
++      nic->mac_addr[2] = (val1 & 0x0000ff00) >> 8;
++      nic->mac_addr[3] = (val1 & 0x000000ff) >> 0;
++      nic->mac_addr[4] = (val2 & 0xff000000) >> 24;
++      nic->mac_addr[5] = (val2 & 0x00ff0000) >> 16;
++#else
++      nic->mac_addr[5] = (val1 & 0xff000000) >> 24;
++      nic->mac_addr[4] = (val1 & 0x00ff0000) >> 16;
++      nic->mac_addr[3] = (val1 & 0x0000ff00) >> 8;
++      nic->mac_addr[2] = (val1 & 0x000000ff) >> 0;
++      nic->mac_addr[1] = (val2 & 0xff000000) >> 24;
++      nic->mac_addr[0] = (val2 & 0x00ff0000) >> 16;
++#endif
++}
++
++
++/********************************************************************
++ * GDACT10 MAC
++ */
++
++/*--------------------------------------------------------------------
++ *
++ * Debug Support
++ *
++ *--------------------------------------------------------------------*/
++
++#define GDACT10_MAC_ASSERT_VALID()                                    \
++    EFHW_ASSERT(nic);                                                 \
++    EFHW_ASSERT(EFHW_KVA(nic));                                               \
++    EFHW_ASSERT(XM_GLB_CFG_REG_P0_OFST == XM_GLB_CFG_REG_KER_P0_OFST);        \
++    EFHW_ASSERT(XM_TX_CFG_REG_P0_OFST  == XM_TX_CFG_REG_KER_P0_OFST); \
++    EFHW_ASSERT(XM_RX_CFG_REG_P0_OFST  == XM_RX_CFG_REG_KER_P0_OFST); \
++    EFHW_ASSERT(MAC0_SPEED_LBN         == MAC1_SPEED_LBN);            \
++    EFHW_ASSERT(MAC0_SPEED_WIDTH       == MAC1_SPEED_WIDTH);          \
++    EFHW_ASSERT(MAC0_LINK_STATUS_LBN   == MAC1_LINK_STATUS_LBN);      \
++    EFHW_ASSERT(MAC0_LINK_STATUS_WIDTH == MAC1_LINK_STATUS_WIDTH);    \
++    EFHW_ASSERT(MAC1_BCAD_ACPT_LBN     == MAC0_BCAD_ACPT_LBN);                \
++    EFHW_ASSERT(MAC1_UC_PROM_LBN       == MAC0_UC_PROM_LBN);          \
++    EFHW_ASSERT(MAC0_CTRL_REG_KER_OFST == MAC0_CTRL_REG_OFST);                \
++    EFHW_ASSERT(MAC1_CTRL_REG_KER_OFST == MAC1_CTRL_REG_OFST);                \
++    EFHW_ASSERT(XM_ADR_LO_REG_KER_P0_OFST  == XM_ADR_LO_REG_P0_OFST); \
++    EFHW_ASSERT(XM_ADR_HI_REG_KER_P0_OFST  == XM_ADR_HI_REG_P0_OFST); \
++    EFHW_ASSERT(XM_RX_PARAM_REG_KER_P0_OFST == XM_RX_PARAM_REG_P0_OFST);
++
++/*--------------------------------------------------------------------
++ *
++ * Information gathering
++ *
++ *--------------------------------------------------------------------*/
++
++/*! Get MAC current address - i.e not necessarily the one in the EEPROM */
++static inline void GDACT10mac_get_mac_addr(struct efhw_nic *nic)
++{
++      uint val1, val2;
++      efhw_ioaddr_t efhw_kva = EFHW_KVA(nic);
++      FALCON_LOCK_DECL;
++
++      GDACT10_MAC_ASSERT_VALID();
++
++      EFHW_ASSERT(XM_ADR_LO_LBN == 0);
++      EFHW_ASSERT(XM_ADR_LO_WIDTH == 32);
++      EFHW_ASSERT(XM_ADR_HI_LBN == 0);
++      EFHW_ASSERT(XM_ADR_HI_WIDTH == 16);
++
++      FALCON_LOCK_LOCK(nic);
++
++      val1 = readl(efhw_kva + XM_ADR_LO_REG_P0_OFST);
++      val2 = readl(efhw_kva + XM_ADR_HI_REG_P0_OFST);
++
++      FALCON_LOCK_UNLOCK(nic);
++
++      /* The HW scores no points for consistency */
++      nic->mac_addr[5] = (val2 & 0x0000ff00) >> 8;
++      nic->mac_addr[4] = (val2 & 0x000000ff) >> 0;
++      nic->mac_addr[3] = (val1 & 0xff000000) >> 24;
++      nic->mac_addr[2] = (val1 & 0x00ff0000) >> 16;
++      nic->mac_addr[1] = (val1 & 0x0000ff00) >> 8;
++      nic->mac_addr[0] = (val1 & 0x000000ff) >> 0;
++}
++
++
++/********************************************************************
++ * Call one or another function
++ */
++
++void falcon_get_mac_addr(struct efhw_nic *nic)
++{
++      if (nic->flags & NIC_FLAG_10G)
++              GDACT10mac_get_mac_addr(nic);
++      else
++              mentormac_get_mac_addr(nic);
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/filter_resource.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/filter_resource.c 2008-05-19 00:33:29.425842266 +0300
+@@ -0,0 +1,317 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains filters support.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efrm/nic_table.h>
++#include <ci/driver/efab/hardware.h>
++#include <ci/efhw/falcon.h>
++#include <ci/efrm/vi_resource_manager.h>
++#include <ci/efrm/private.h>
++#include <ci/efrm/filter.h>
++#include <ci/efrm/buffer_table.h>
++
++struct filter_resource_manager {
++      struct efrm_resource_manager rm;
++      struct kfifo *free_ids;
++};
++
++static struct filter_resource_manager *efrm_filter_manager;
++
++void efrm_filter_resource_free(struct filter_resource *frs)
++{
++      struct efhw_nic *nic;
++      int nic_i;
++      int id;
++
++      EFRM_RESOURCE_ASSERT_VALID(&frs->rs, 1);
++
++      EFRM_TRACE("%s: " EFRM_RESOURCE_FMT, __FUNCTION__,
++                 EFRM_RESOURCE_PRI_ARG(frs->rs.rs_handle));
++
++      /* if we have a PT endpoint */
++      if (NULL != frs->pt) {
++              /* Detach the filter */
++              EFRM_FOR_EACH_NIC_IN_SET(&frs->nic_set, nic_i, nic)
++                  efhw_nic_ipfilter_detach(nic, frs->filter_idx);
++
++              /* Release our ref to the PT resource. */
++              EFRM_TRACE("%s: releasing PT resource reference",
++                         __FUNCTION__);
++              efrm_vi_resource_release(frs->pt);
++      }
++
++      /* Disable the filter. */
++      EFRM_FOR_EACH_NIC_IN_SET(&frs->nic_set, nic_i, nic)
++          efhw_nic_ipfilter_clear(nic, frs->filter_idx);
++
++      /* Free this filter. */
++      id = EFRM_RESOURCE_INSTANCE(frs->rs.rs_handle);
++      EFRM_VERIFY_EQ(kfifo_put(efrm_filter_manager->free_ids,
++                               (unsigned char *)&id, sizeof(id)),
++                     sizeof(id));
++
++      EFRM_DO_DEBUG(memset(frs, 0, sizeof(*frs)));
++      kfree(frs);
++}
++EXPORT_SYMBOL(efrm_filter_resource_free);
++
++static void filter_rm_dtor(struct efrm_resource_manager *rm)
++{
++      EFRM_TRACE("filter_rm_dtor");
++
++      EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_filter_manager->rm);
++      EFRM_ASSERT(&efrm_filter_manager->rm == rm);
++
++      kfifo_vfree(efrm_filter_manager->free_ids);
++      EFRM_TRACE("filter_rm_dtor: done");
++}
++
++/**********************************************************************/
++/**********************************************************************/
++/**********************************************************************/
++
++int efrm_create_filter_resource_manager(struct efrm_resource_manager **rm_out)
++{
++      int rc;
++
++      EFRM_ASSERT(rm_out);
++
++      efrm_filter_manager =
++          kmalloc(sizeof(struct filter_resource_manager), GFP_KERNEL);
++      if (efrm_filter_manager == 0)
++              return -ENOMEM;
++      memset(efrm_filter_manager, 0, sizeof(*efrm_filter_manager));
++
++      rc = efrm_resource_manager_ctor(&efrm_filter_manager->rm,
++                                      filter_rm_dtor, "FILTER",
++                                      EFRM_RESOURCE_FILTER, 0);
++      if (rc < 0)
++              goto fail1;
++
++      /* Create a pool of free instances */
++      rc = efrm_kfifo_id_ctor(&efrm_filter_manager->free_ids,
++                              0, EFHW_IP_FILTER_NUM,
++                              &efrm_filter_manager->rm.rm_lock);
++      if (rc != 0)
++              goto fail2;
++
++      *rm_out = &efrm_filter_manager->rm;
++      EFRM_TRACE("%s: filter resources created - %d IDs",
++                 __FUNCTION__, kfifo_len(efrm_filter_manager->free_ids));
++      return 0;
++
++fail2:
++      efrm_resource_manager_dtor(&efrm_filter_manager->rm);
++fail1:
++      memset(efrm_filter_manager, 0, sizeof(*efrm_filter_manager));
++      kfree(efrm_filter_manager);
++      return rc;
++
++}
++
++/*--------------------------------------------------------------------
++ *!
++ * Called to set/change the PT endpoint of a filter
++ *
++ * Example of use is TCP helper when it finds a wildcard IP filter
++ * needs to change which application it delivers traffic to
++ *
++ * \param frs           filter resource
++ * \param pt_handle     handle of new PT endpoint
++ *
++ * \return              standard error codes
++ *
++ *--------------------------------------------------------------------*/
++int
++efrm_filter_resource_set_ptresource(struct filter_resource *frs,
++                                  struct vi_resource *ptrs)
++{
++      int rc, pti, nic_i;
++      struct efhw_nic *nic;
++
++      EFRM_ASSERT(frs);
++
++      /* if filter is attached to a valid PT endpoint */
++      if (NULL != frs->pt) {
++
++              EFRM_TRACE("%s: detaching PT resource " EFRM_RESOURCE_FMT
++                         " from filter ",
++                         __FUNCTION__,
++                         EFRM_RESOURCE_PRI_ARG(frs->rs.rs_handle));
++              /* Detach the filter */
++              EFRM_FOR_EACH_NIC_IN_SET(&frs->nic_set, nic_i, nic)
++                  efhw_nic_ipfilter_detach(nic, frs->filter_idx);
++
++              /* release reference */
++              efrm_vi_resource_release(frs->pt);
++              frs->pt = NULL;
++      }
++
++      if (ptrs != NULL) {
++              /* get PT endpoint index */
++              EFRM_RESOURCE_ASSERT_VALID(&ptrs->rs, 0);
++              EFRM_ASSERT(EFRM_RESOURCE_TYPE(ptrs->rs.rs_handle) ==
++                          EFRM_RESOURCE_VI);
++              pti = EFRM_RESOURCE_INSTANCE(ptrs->rs.rs_handle);
++              if (pti == 0) {
++                      EFRM_ERR("%s: cannot filter for channel 0",
++                               __FUNCTION__);
++                      rc = -EINVAL;
++                      goto fail2;
++              }
++              frs->pt = ptrs;
++              EFRM_TRACE("%s: attaching PT resource " EFRM_RESOURCE_FMT
++                         " to filter",
++                         __FUNCTION__,
++                         EFRM_RESOURCE_PRI_ARG(frs->pt->rs.rs_handle));
++              EFRM_FOR_EACH_NIC_IN_SET(&frs->nic_set, nic_i, nic)
++                  efhw_nic_ipfilter_attach(nic, frs->filter_idx, pti);
++              efrm_vi_resource_ref(frs->pt);
++      }
++      return 0;
++
++fail2:
++      efrm_vi_resource_release(frs->pt);
++      return rc;
++}
++EXPORT_SYMBOL(efrm_filter_resource_set_ptresource);
++
++int efrm_filter_resource_clear(struct filter_resource *frs)
++{
++      struct efhw_nic *nic;
++      int nic_i;
++
++      EFRM_ASSERT(frs);
++      EFRM_FOR_EACH_NIC_IN_SET(&frs->nic_set, nic_i, nic)
++          efhw_nic_ipfilter_clear(nic, frs->filter_idx);
++
++      return 0;
++}
++EXPORT_SYMBOL(efrm_filter_resource_clear);
++
++int
++__efrm_filter_resource_set(struct filter_resource *frs, int type,
++                         unsigned saddr, uint16_t sport,
++                         unsigned daddr, uint16_t dport)
++{
++      struct efhw_nic *nic;
++      int nic_i, rc = 0;
++      unsigned instance = EFRM_RESOURCE_INSTANCE(frs->pt->rs.rs_handle);
++
++      EFRM_ASSERT(frs);
++      EFRM_ASSERT(frs->pt);
++
++      if (efrm_nic_table.a_nic->devtype.variant >= 'B') {
++              /* Scatter setting must match the setting for
++               * the corresponding RX queue */
++              if (!(frs->pt->flags & EFHW_VI_JUMBO_EN))
++                      type |= EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK;
++      }
++
++      EFRM_FOR_EACH_NIC_IN_SET(&frs->nic_set, nic_i, nic)
++          if (rc >= 0)
++              rc = efhw_nic_ipfilter_set(nic, type, &frs->filter_idx,
++                                         instance,
++                                         saddr, sport, daddr, dport);
++
++      return rc;
++}
++EXPORT_SYMBOL(__efrm_filter_resource_set);;
++
++int
++efrm_filter_resource_alloc(struct vi_resource *vi_parent,
++                         struct filter_resource **frs_out)
++{
++      struct efhw_nic *nic;
++      int nic_i, rc, instance;
++      struct filter_resource *frs;
++
++      EFRM_ASSERT(frs_out);
++      EFRM_ASSERT(efrm_filter_manager);
++      EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_filter_manager->rm);
++      EFRM_ASSERT(vi_parent == NULL ||
++                  EFRM_RESOURCE_TYPE(vi_parent->rs.rs_handle) ==
++                  EFRM_RESOURCE_VI);
++
++      /* Allocate resource data structure. */
++      frs = kmalloc(sizeof(struct filter_resource), GFP_KERNEL);
++      if (!frs)
++              return -ENOMEM;
++      efrm_nic_set_clear(&frs->nic_set);
++
++      /* Allocate an instance. */
++      rc = kfifo_get(efrm_filter_manager->free_ids,
++                     (unsigned char *)&instance, sizeof(instance));
++      if (rc != sizeof(instance)) {
++              EFRM_TRACE("%s: out of instances", __FUNCTION__);
++              EFRM_ASSERT(rc == 0);
++              rc = -EBUSY;
++              goto fail1;
++      }
++
++      /* Initialise the resource DS. */
++      efrm_resource_init(&frs->rs, EFRM_RESOURCE_FILTER, instance);
++      frs->pt = vi_parent;
++      if (frs->pt)
++              efrm_vi_resource_ref(frs->pt);
++      frs->filter_idx = -1;
++      EFRM_FOR_EACH_NIC(nic_i, nic)
++          efrm_nic_set_write(&frs->nic_set, nic_i, true);
++
++      EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " Q %d idx %x",
++                 __FUNCTION__,
++                 EFRM_RESOURCE_PRI_ARG(frs->rs.rs_handle),
++                 vi_parent == NULL ? -1 :
++                 EFRM_RESOURCE_INSTANCE(vi_parent->rs.rs_handle),
++                 frs->filter_idx);
++
++      /* Put it into the resource manager's table. */
++      rc = efrm_resource_manager_insert(&frs->rs);
++      if (rc != 0) {
++              if (atomic_dec_and_test(&frs->rs.rs_ref_count))
++                      efrm_filter_resource_free(frs);
++              return rc;
++      }
++
++      *frs_out = frs;
++      return 0;
++
++fail1:
++      memset(frs, 0, sizeof(*frs));
++      kfree(frs);
++      return rc;
++}
++EXPORT_SYMBOL(efrm_filter_resource_alloc);
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/iobufset_resource.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/iobufset_resource.c       2008-05-19 00:33:29.429842497 +0300
+@@ -0,0 +1,373 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains non-contiguous I/O buffers support.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efrm/nic_table.h>
++#include <ci/efhw/iopage.h>
++#include <ci/driver/efab/hardware.h>
++#include <ci/efrm/private.h>
++#include <ci/efrm/iobufset.h>
++#include <ci/efrm/vi_resource_manager.h>
++#include <ci/efrm/buffer_table.h>
++
++#define EFRM_IOBUFSET_MAX_NUM_INSTANCES 0x00010000
++
++struct iobufset_resource_manager {
++      struct efrm_resource_manager rm;
++      struct kfifo *free_ids;
++};
++
++struct iobufset_resource_manager *efrm_iobufset_manager;
++
++#define iobsrs(rs1)  iobufset_resource(rs1)
++
++/* Returns size of iobufset resource data structure. */
++static inline size_t iobsrs_size(int no_pages)
++{
++      return offsetof(struct iobufset_resource, bufs) +
++          no_pages * sizeof(efhw_iopage_t);
++}
++
++void efrm_iobufset_resource_free(struct iobufset_resource *rs)
++{
++      unsigned int no_pages;
++      unsigned int i;
++      int id;
++
++      EFRM_RESOURCE_ASSERT_VALID(&rs->rs, 1);
++      no_pages = rs->n_bufs;
++
++      if (rs->buf_tbl_alloc.base != (unsigned)-1)
++              efrm_buffer_table_free(&rs->buf_tbl_alloc);
++
++      /* see comment on call to efhw_iopage_alloc in the alloc routine above
++         for discussion on use of efrm_nic_table.a_nic here */
++      EFRM_ASSERT(efrm_nic_table.a_nic);
++      if (rs->order == 0) {
++              for (i = 0; i < rs->n_bufs; ++i)
++                      efhw_iopage_free(efrm_nic_table.a_nic, &rs->bufs[i]);
++      } else {
++              /* it is important that this is executed in increasing page
++               * order because some implementations of
++               * efhw_iopages_init_from_iopage() assume this */
++              for (i = 0; i < rs->n_bufs;
++                   i += rs->pages_per_contiguous_chunk) {
++                      efhw_iopages_t iopages;
++                      efhw_iopages_init_from_iopage(&iopages, &rs->bufs[i],
++                                                  rs->order);
++                      efhw_iopages_free(efrm_nic_table.a_nic, &iopages);
++              }
++      }
++
++      /* free the instance number */
++      id = EFRM_RESOURCE_INSTANCE(rs->rs.rs_handle);
++      EFRM_VERIFY_EQ(kfifo_put(efrm_iobufset_manager->free_ids,
++                               (unsigned char *)&id, sizeof(id)), sizeof(id));
++
++      efrm_vi_resource_release(rs->evq);
++
++      EFRM_DO_DEBUG(memset(rs, 0, sizeof(*rs)));
++      if (iobsrs_size(no_pages) < PAGE_SIZE) {
++              kfree(rs);
++      } else {
++              vfree(rs);
++      }
++}
++EXPORT_SYMBOL(efrm_iobufset_resource_free);
++
++int
++efrm_iobufset_resource_alloc(int32_t n_pages,
++                           int32_t pages_per_contiguous_chunk,
++                           struct vi_resource *vi_evq,
++                           bool phys_addr_mode,
++                           uint32_t faultonaccess,
++                           struct iobufset_resource **iobrs_out)
++{
++      struct iobufset_resource *iobrs;
++      int rc, instance, object_size;
++      unsigned int i;
++
++      EFRM_ASSERT(iobrs_out);
++      EFRM_ASSERT(efrm_iobufset_manager);
++      EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_iobufset_manager->rm);
++      EFRM_RESOURCE_ASSERT_VALID(&vi_evq->rs, 0);
++      EFRM_ASSERT(EFRM_RESOURCE_TYPE(vi_evq->rs.rs_handle) ==
++                  EFRM_RESOURCE_VI);
++      EFRM_ASSERT(efrm_nic_table.a_nic);
++
++      /* allocate the resource data structure. */
++      object_size = iobsrs_size(n_pages);
++      if (object_size < PAGE_SIZE) {
++              /* this should be OK from a tasklet */
++              /* Necessary to do atomic alloc() as this
++                 can be called from a weird-ass iSCSI context that is
++                 !in_interrupt but is in_atomic - See BUG3163 */
++              iobrs = kmalloc(object_size, GFP_ATOMIC);
++      } else {                /* can't do this within a tasklet */
++#ifndef NDEBUG
++              if (in_interrupt() || in_atomic()) {
++                      EFRM_ERR("%s(): alloc->u.iobufset.in_n_pages=%d",
++                               __FUNCTION__, n_pages);
++                      EFRM_ASSERT(!in_interrupt());
++                      EFRM_ASSERT(!in_atomic());
++              }
++#endif
++              iobrs = (struct iobufset_resource *) vmalloc(object_size);
++      }
++      if (iobrs == 0) {
++              rc = -ENOMEM;
++              goto fail1;
++      }
++
++      /* Allocate an instance number. */
++      rc = kfifo_get(efrm_iobufset_manager->free_ids,
++                     (unsigned char *)&instance, sizeof(instance));
++      if (rc != sizeof(instance)) {
++              EFRM_TRACE("%s: out of instances", __FUNCTION__);
++              EFRM_ASSERT(rc == 0);
++              rc = -EBUSY;
++              goto fail3;
++      }
++
++      efrm_resource_init(&iobrs->rs, EFRM_RESOURCE_IOBUFSET, instance);
++
++      iobrs->evq = vi_evq;
++      efrm_vi_resource_ref(iobrs->evq);
++
++      iobrs->n_bufs = n_pages;
++      iobrs->pages_per_contiguous_chunk = pages_per_contiguous_chunk;
++      iobrs->order = fls(iobrs->pages_per_contiguous_chunk - 1);
++      iobrs->faultonaccess = faultonaccess;
++
++      EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " %u pages", __FUNCTION__,
++                 EFRM_RESOURCE_PRI_ARG(iobrs->rs.rs_handle), iobrs->n_bufs);
++
++      /* Allocate the iobuffers. */
++      if (iobrs->order == 0) {
++              /* make sure iobufs are in a known state in case we don't
++               * finish our allocation */
++              for (i = 0; i < iobrs->n_bufs; ++i)
++                      memset(&iobrs->bufs[i], 0, sizeof(iobrs->bufs[i]));
++
++              for (i = 0; i < iobrs->n_bufs; ++i) {
++                      /* due to bug2426 we have to specifiy a NIC when
++                       * allocating a DMAable page, which is a bit messy.
++                       * For now we assume that if the page is suitable
++                       * (e.g. DMAable) by one nic (efrm_nic_table.a_nic),
++                       * it is suitable for all NICs.
++                       * XXX I bet that breaks in Solaris.
++                       */
++                      rc = efhw_iopage_alloc(efrm_nic_table.a_nic,
++                                           &iobrs->bufs[i]);
++                      if (rc < 0) {
++                              EFRM_ERR("%s: failed (rc %d) to allocate "
++                                       "page (i=%u)", __FUNCTION__, rc, i);
++                              goto fail4;
++                      }
++              }
++      } else {
++              efhw_iopages_t iopages;
++              unsigned j;
++
++              /* make sure iobufs are in a known state in case we don't
++               * finish our allocation */
++              for (i = 0; i < iobrs->n_bufs; ++i)
++                      memset(&iobrs->bufs[i], 0, sizeof(iobrs->bufs[i]));
++
++              for (i = 0; i < iobrs->n_bufs;
++                   i += iobrs->pages_per_contiguous_chunk) {
++                      rc = efhw_iopages_alloc(efrm_nic_table.a_nic,
++                                              &iopages, iobrs->order);
++                      if (rc < 0) {
++                              EFRM_ERR("%s: failed (rc %d) to allocate "
++                                       "pages (i=%u order %d)",
++                                       __FUNCTION__, rc, i, iobrs->order);
++                              goto fail4;
++                      }
++                      for (j = 0; j < iobrs->pages_per_contiguous_chunk;
++                           j++) {
++                              /* some implementation of
++                               * efhw_iopage_init_from_iopages() rely on
++                               * this function being called for
++                               * _all_ pages in the chunk */
++                              efhw_iopage_init_from_iopages(
++                                                      &iobrs->bufs[i + j],
++                                                      &iopages, j);
++                      }
++              }
++      }
++
++      iobrs->buf_tbl_alloc.base = (unsigned)-1;
++
++      if (!phys_addr_mode) {
++              unsigned instance = EFAB_VI_RESOURCE_INSTANCE(iobrs->evq);
++              /* Allocate space in the NIC's buffer table. */
++              rc = efrm_buffer_table_alloc(fls(iobrs->n_bufs - 1),
++                                           &iobrs->buf_tbl_alloc);
++              if (rc < 0) {
++                      EFRM_ERR("%s: failed (%d) to alloc %d buffer table "
++                               "entries", __FUNCTION__, rc, iobrs->n_bufs);
++                      goto fail5;
++              }
++              EFRM_ASSERT(((unsigned)1 << iobrs->buf_tbl_alloc.order) >=
++                          (unsigned)iobrs->n_bufs);
++
++              /* Initialise the buffer table entries. */
++              for (i = 0; i < iobrs->n_bufs; ++i) {
++                      /*\ ?? \TODO burst them! */
++                      efrm_buffer_table_set(&iobrs->buf_tbl_alloc, i,
++                                            efhw_iopage_dma_addr(&iobrs->
++                                                               bufs[i]),
++                                            instance);
++              }
++              efrm_buffer_table_commit();
++      }
++
++      EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " %d pages @ "
++                 EFHW_BUFFER_ADDR_FMT, __FUNCTION__,
++                 EFRM_RESOURCE_PRI_ARG(iobrs->rs.rs_handle),
++                 iobrs->n_bufs, EFHW_BUFFER_ADDR(iobrs->buf_tbl_alloc.base,
++                                                 0));
++
++      /* Put it into the resource manager's table. */
++      rc = efrm_resource_manager_insert(&iobrs->rs);
++      if (rc != 0) {
++              if (atomic_dec_and_test(&iobrs->rs.rs_ref_count))
++                      efrm_iobufset_resource_free(iobrs);
++              return rc;
++      }
++
++      *iobrs_out = iobrs;
++      return 0;
++
++fail5:
++      i = iobrs->n_bufs;
++fail4:
++      /* see comment on call to efhw_iopage_alloc above for a discussion
++       * on use of efrm_nic_table.a_nic here */
++      if (iobrs->order == 0) {
++              while (i--) {
++                      efhw_iopage_t *page = &iobrs->bufs[i];
++                      efhw_iopage_free(efrm_nic_table.a_nic, page);
++              }
++      } else {
++              unsigned int j;
++              for (j = 0; j < i; j += iobrs->pages_per_contiguous_chunk) {
++                      efhw_iopages_t iopages;
++
++                      EFRM_ASSERT(j % iobrs->pages_per_contiguous_chunk
++                                  == 0);
++                      /* it is important that this is executed in increasing
++                       * page order because some implementations of
++                       * efhw_iopages_init_from_iopage() assume this */
++                      efhw_iopages_init_from_iopage(&iopages,
++                                                    &iobrs->bufs[j],
++                                                    iobrs->order);
++                      efhw_iopages_free(efrm_nic_table.a_nic, &iopages);
++              }
++      }
++      efrm_vi_resource_release(iobrs->evq);
++fail3:
++      if (object_size < PAGE_SIZE) {
++              kfree(iobrs);
++      } else {
++              vfree(iobrs);
++      }
++fail1:
++      return rc;
++}
++EXPORT_SYMBOL(efrm_iobufset_resource_alloc);
++
++static void iobufset_rm_dtor(struct efrm_resource_manager *rm)
++{
++      EFRM_ASSERT(&efrm_iobufset_manager->rm == rm);
++      kfifo_vfree(efrm_iobufset_manager->free_ids);
++}
++
++int
++efrm_create_iobufset_resource_manager(struct efrm_resource_manager **rm_out)
++{
++      int rc, max;
++
++      EFRM_ASSERT(rm_out);
++
++      efrm_iobufset_manager =
++          kmalloc(sizeof(*efrm_iobufset_manager), GFP_KERNEL);
++      if (efrm_iobufset_manager == 0)
++              return -ENOMEM;
++      memset(efrm_iobufset_manager, 0, sizeof(*efrm_iobufset_manager));
++
++      /*
++       * Bug 1145, 1370: We need to set initial size of both the resource
++       * table and instance id table so they never need to grow as we
++       * want to be allocate new iobufset at tasklet time. Lets make
++       * a pessimistic guess at maximum number of iobufsets possible.
++       * Could be less because
++       *   - jumbo frames have same no of packets per iobufset BUT more
++       *     pages per buffer
++       *   - buffer table entries used independently of iobufsets by
++       *     sendfile
++       *
++       * Based on TCP/IP stack setting of PKTS_PER_SET_S=5 ...
++       *  - can't use this define here as it breaks the layering.
++       */
++#define MIN_PAGES_PER_IOBUFSET  (1 << 4)
++
++      max = efrm_buffer_table_size() / MIN_PAGES_PER_IOBUFSET;
++      max = min_t(int, max, EFRM_IOBUFSET_MAX_NUM_INSTANCES);
++
++      rc = efrm_kfifo_id_ctor(&efrm_iobufset_manager->free_ids,
++                              0, max, &efrm_iobufset_manager->rm.rm_lock);
++      if (rc != 0)
++              goto fail1;
++
++      rc = efrm_resource_manager_ctor(&efrm_iobufset_manager->rm,
++                                      iobufset_rm_dtor, "IOBUFSET",
++                                      EFRM_RESOURCE_IOBUFSET, max);
++      if (rc < 0)
++              goto fail2;
++
++      *rm_out = &efrm_iobufset_manager->rm;
++      return 0;
++
++fail2:
++      kfifo_vfree(efrm_iobufset_manager->free_ids);
++fail1:
++      EFRM_DO_DEBUG(memset(efrm_iobufset_manager, 0,
++                           sizeof(*efrm_iobufset_manager)));
++      kfree(efrm_iobufset_manager);
++      return rc;
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/iopage.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/iopage.c  2008-05-19 00:33:29.429842497 +0300
+@@ -0,0 +1,101 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides Linux-specific implementation for iopage API used
++ * from efhw library.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/driver/resource/linux_efhw_nic.h>
++#include "kernel_compat.h"
++#include <ci/efhw/common_sysdep.h> /* for dma_addr_t */
++
++int efhw_iopage_alloc(struct efhw_nic *nic, efhw_iopage_t *p)
++{
++      struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
++      dma_addr_t handle;
++      void *kva;
++
++      kva = efrm_pci_alloc_consistent(lnic->pci_dev, PAGE_SIZE,
++                                      &handle);
++      if (kva == 0)
++              return -ENOMEM;
++
++      EFHW_ASSERT((handle & ~PAGE_MASK) == 0);
++
++      memset((void *)kva, 0, PAGE_SIZE);
++      efhw_page_init_from_va(&p->p, kva);
++
++      p->dma_addr = handle;
++
++      return 0;
++}
++
++void efhw_iopage_free(struct efhw_nic *nic, efhw_iopage_t *p)
++{
++      struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
++      EFHW_ASSERT(efhw_page_is_valid(&p->p));
++
++      efrm_pci_free_consistent(lnic->pci_dev, PAGE_SIZE,
++                               efhw_iopage_ptr(p), p->dma_addr);
++}
++
++int efhw_iopages_alloc(struct efhw_nic *nic, efhw_iopages_t *p, unsigned order)
++{
++      unsigned bytes = 1u << (order + PAGE_SHIFT);
++      struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
++      dma_addr_t handle;
++      caddr_t addr;
++      int gfp_flag;
++
++      /* Set __GFP_COMP if available to make reference counting work.
++       * This is recommended here:
++       *   http://www.forbiddenweb.org/viewtopic.php?id=83167&page=4#348331
++       */
++      gfp_flag = ((in_atomic() ? GFP_ATOMIC : GFP_KERNEL) | __GFP_COMP);
++      addr = efrm_dma_alloc_coherent(&lnic->pci_dev->dev, bytes, &handle,
++                                     gfp_flag);
++      if (addr == NULL)
++              return -ENOMEM;
++
++      EFHW_ASSERT((handle & ~PAGE_MASK) == 0);
++
++      p->order = order;
++      p->dma_addr = handle;
++      p->kva = addr;
++
++      return 0;
++}
++
++void efhw_iopages_free(struct efhw_nic *nic, efhw_iopages_t *p)
++{
++      unsigned bytes = 1u << (p->order + PAGE_SHIFT);
++      struct linux_efhw_nic *lnic = linux_efhw_nic(nic);
++
++      efrm_dma_free_coherent(&lnic->pci_dev->dev, bytes,
++                             (void *)p->kva, p->dma_addr);
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/kernel_compat.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/kernel_compat.c   2008-05-19 00:33:29.429842497 +0300
+@@ -0,0 +1,584 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides compatibility layer for various Linux kernel versions
++ * (starting from 2.6.9 RHEL kernel).
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#define IN_KERNEL_COMPAT_C
++#include <linux/types.h>
++#include <ci/efrm/debug.h>
++#include "kernel_compat.h"
++
++/* Set this to 1 to enable very basic counting of iopage(s) allocations, then
++ * call dump_iopage_counts() to show the number of current allocations of
++ * orders 0-7.
++ */
++#define EFRM_IOPAGE_COUNTS_ENABLED 0
++
++
++
++/* I admit that it's a bit ugly going straight to the field, but it
++ * seems easiest given that get_page followed by put_page on a page
++ * with PG_reserved set will increment the ref count on 2.6.14 and
++ * below, but not 2.6.15.  Also, RedHat have hidden put_page_testzero
++ * in a header file which produces warnings when compiled.  This
++ * doesn't agree with our use of -Werror.
++ */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,5)
++# define page_count_field(pg)  ((pg)->count)
++#else
++# define page_count_field(pg)  ((pg)->_count)
++#endif
++
++#define inc_page_count(page)   atomic_inc(&page_count_field(page))
++#define dec_page_count(page)   atomic_dec(&page_count_field(page))
++
++/* Bug 5531: set_page_count doesn't work if the new page count is an
++ * expression. */
++#define ci_set_page_count(page, n) set_page_count(page, (n))
++
++  /* Bug 3965: Gak!  Reference counts just don't work on memory
++   * allocated through pci_alloc_consistent.  Different versions and
++   * architectures do different things.  There are several interacting
++   * bugs/features which have been described below and then summarised
++   * in a table for each kernel version.  For each feature, there is a
++   * question, a short description, a hint at how to examine the
++   * kernel code for this feature and a description of the keys in the
++   * table.
++   *
++   * A. Is PG_compound set on multi-page allocations?
++   *
++   *    When a multi-page allocation succeeds, the kernel sets the
++   *    reference count of the first page to one and the count of the
++   *    remaining pages to zero.  This is an immediate problem because
++   *    if these pages are mapped into user space, the VM will do
++   *    get_page followed by put_page, at which point the reference
++   *    count will return to zero and the page will be freed.
++   *    PG_compound was introduced in 2.6.0 and back-ported to rhel3
++   *    kernels.  When it is set, all the pages have a pointer to the
++   *    first page so that they can share the reference count.  If
++   *    PG_compound is set, calling get_page(pg+1) can change
++   *    page_count(pg).  It was originally set on all multi-page
++   *    allocations, but later only set if the __GFP_COMP flag was
++   *    provided to the allocator.
++   *
++   *    See mm/page_alloc.c
++   *      Does prep_compound_page get called when __GFP_COMP not set?
++   *
++   * Keys:
++   *    NotDef - prep_compound_page and PG_compound are not defined.
++   *    Comp   - prep_compound_page is called for any multi-page allocation.
++   *    Opt    - prep_compound_page is only called if __GFP_COMP is set.
++   *    OptInv - prep_compound_page is only called if __GFP_NO_COMP is not set.
++   *
++   * B. Are bounce buffers ever used to satisfy pci_alloc_consistent?
++   *    (x86_64 only)
++   *
++   *    2.6 kernels introduced bounce buffers on x86_64 machines to access
++   *    memory above 4G when using the DMA mapping API.  At some point,
++   *    code was added to allow pci_alloc_consistent/dma_alloc_coherent to
++   *    allocate memory from the bounce buffers if the general purpose
++   *    allocator produced memory which wasn't suitable.  Such memory can
++   *    be recognised by the PG_reserved bit being set.  At a later point,
++   *    the __GFP_DMA32 flag was added and used to restrict the allocator
++   *    to below 4G.  The effect of this later change was that 4G capable
++   *    cards would no longer get memory from the bounce buffers, although
++   *    a card which can address less than 4G might get memory from the
++   *    bounce buffers.
++   *
++   *    See dma_alloc_coherent or pci_alloc_consistent in
++   *    arch/x86_64/kernel/pci-gart.c or arch/x86/kernel/pci-dma_64.c
++   *      Is (gfp |= GFP_DMA32) before dma_alloc_pages?
++   *      Is swiotlb_alloc_coherent called?
++   *
++   * Keys:
++   *    NU     - bounce buffers are Never Used
++   *    Used   - bounce buffers are sometimes used
++   *
++   * C. Does munmap decrement the reference count of a PG_reserved page?
++   *
++   *    Originally, the munmap code would not decrement the reference count
++   *    of a page which had PG_reserved set.  At some point in the 2.6
++   *    series, VM_PFNMAP was introduced and could be set on a vma to
++   *    indicate that no pages in that vma should have the reference count
++   *    decremented (unless they are copy-on-write copies).  At that point,
++   *    the check for PG_reserved pages in the munmap code path was
++   *    removed.  Some hackery in vm_normal_page means that a VM_PFNMAP vma
++   *    must map contiguous physical pages.  As a result, such pages should
++   *    be mapped during mmap using remap_pfn_range (for an example, see
++   *    drivers/char/mem.c).
++   *
++   *    In 2.6 kernels: See release_pages in mm/swap.c
++   *      Does PageReserved get tested?
++   *    In 2.6 kernels: See mm/memory.c
++   *      Is VM_PFNMAP used?
++   *    In 2.4 kernels: See __free_pte in mm/memory.c
++   *      Does PageReserved get tested?
++   *    In 2.4 kernels: See __free_pages in mm/page_alloc.c
++   *      Does PageReserved get tested?
++   *
++   * Keys:
++   *    resv   - The reference count is not touched for PG_reserved pages.
++   *    pfnmap - The VM_PFNMAP flag is checked instead of PG_reserved.
++   *
++   * D. Does munmap honour the PG_compound bit?
++   *
++   *    When PG_compound was originally introduced, the munmap code path
++   *    didn't check it before decrementing the reference count on the
++   *    page.  As a result, the wrong reference count would be updated if a
++   *    PG_compound page was ever mapped into user space.
++   *
++   *    In 2.6 kernels: See release_pages in mm/swap.c
++   *      Does PageCompound get tested?
++   *    In 2.4 kernels: See __free_pages in mm/page_alloc.c
++   *      Does PageCompound get tested?
++   *
++   * Keys:
++   *    NotHon - The PG_compound bit isn't honoured by munmap.
++   *    Hon    - The PG_compound bit is honoured by munmap.
++   *
++   *                 OS      A       B       C       D
++   * 2.4.18                  NotDef  NU      resv    NotHon
++   * 2.4.29                  NotDef  NU      resv    NotHon
++   * 2.4.20-31.9     rhl9    NotDef  NU      resv    NotHon
++   *
++   * 2.4.21-4.EL     rhel3   Comp    NU      resv    Hon
++   * 2.4.21-15.EL    rhel3   Comp    NU      resv    Hon
++   * 2.4.21-32.EL    rhel3   Comp    NU      resv    Hon
++   * 2.4.21-40.EL    rhel3   Comp    NU      resv    Hon
++   *
++   * 2.6.0                   Comp    NU      resv    NotHon
++   *
++   * 2.6.5-7.97      sles9   OptInv  NU      resv    NotHon
++   * 2.6.9           rhel4   Opt     NU      resv    NotHon
++   *
++   * 2.6.11          fc4     ?       ?       ?       ?
++   * 2.6.12          fc4     Opt     Used    resv    NotHon
++   * 2.6.13                  Opt     Used    resv    NotHon
++   *
++   * 2.6.15                  Opt     NU      pfnmap  NotHon
++   *
++   * 2.6.16                  Opt     NU      pfnmap  Hon
++   * 2.6.16.9                Opt     NU      pfnmap  Hon
++   * 2.6.17.2                Opt     NU      pfnmap  Hon
++   * 2.6.24-rc7      k.org   Opt     NU      pfnmap  Hon
++   *
++   * This LKML thread gives some low down on mapping pages into user
++   * space and using DMA.
++   *  http://www.forbiddenweb.org/viewtopic.php?id=83167&page=1
++   *
++   * There is no problem with single page allocations (until some
++   * kernel hands us a PG_reserved page and expects us to use
++   * VM_PFNMAP on the vma).
++   *
++   * Bug 5450: Most kernels set the reference count to one on the
++   * first sub-page of a high-order page allocation and zero on
++   * subsequent sub-pages.  Some kernels, however, set the page count
++   * to one on all the sub-pages.  The SLES 9 range are affected, as
++   * are kernels built without CONFIG_MMU defined.
++   *
++   * Possible strategies for multi-page allocations:
++   *
++   * EFRM_MMAP_USE_COMPOUND
++   * 1. Allocate a compound page.  Reference counting should then work
++   *    on the whole allocation.  This is a good theory, but is broken
++   *    by bug/feature D (above).
++   *
++   * EFRM_MMAP_USE_SPLIT
++   * 2. Convert the multi-page allocation to many single page
++   *    allocations.  This involves incrementing the reference counts
++   *    and clearing PG_compound on all the pages (including the
++   *    first).  The references should be released _after_ calling
++   *    pci_free_consistent so that that call doesn't release the
++   *    memory.
++   *
++   * EFRM_MMAP_USE_INCREMENT
++   * 3. Increment the reference count on all the pages after
++   *    allocating and decrement them again before freeing.  This gets
++   *    round the zero reference count problem.  It doesn't handle the
++   *    case where someone else is holding a reference to one of our
++   *    pages when we free the pages, but we think VM_IO stops this
++   *    from happening.
++   */
++
++/* Should we use strategy 1?  This can be forced on us by the OS. */
++#if defined(PG_compound)
++#define EFRM_MMAP_USE_COMPOUND 1
++#else
++#define EFRM_MMAP_USE_COMPOUND 0
++#endif
++
++/* Should we use strategy 2?  This can be used even if strategy 1 is
++ * used. */
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
++#define EFRM_MMAP_USE_SPLIT    1
++#else
++#define EFRM_MMAP_USE_SPLIT    0
++#endif
++
++/* Should we use strategy 3?  There's no point doing this if either
++ * strategy 1 or strategy 2 is used. */
++#if !EFRM_MMAP_USE_COMPOUND && !EFRM_MMAP_USE_SPLIT
++#error "We shouldn't have to use this strategy."
++#define EFRM_MMAP_USE_INCREMENT 1
++#else
++#define EFRM_MMAP_USE_INCREMENT 0
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
++#define EFRM_MMAP_RESET_REFCNT  1
++#else
++#define EFRM_MMAP_RESET_REFCNT  0
++#endif
++
++/* NB. 2.6.17 has renamed SetPageCompound to __SetPageCompound and
++ * ClearPageCompound to __ClearPageCompound. */
++#if ((defined(PageCompound)        !=  defined(PG_compound)) ||       \
++     (defined(SetPageCompound)     !=  defined(PG_compound) &&        \
++      defined(__SetPageCompound)   !=  defined(PG_compound)) ||       \
++     (defined(ClearPageCompound)   !=  defined(PG_compound) &&        \
++      defined(__ClearPageCompound) !=  defined(PG_compound)) ||       \
++     (defined(__GFP_COMP)          && !defined(PG_compound)))
++#error Mismatch of defined page-flags.
++#endif
++
++extern int use_pci_alloc;     /* Use pci_alloc_consistent to alloc iopages */
++
++/****************************************************************************
++ *
++ * allocate a buffer suitable for DMA to/from the NIC
++ *
++ ****************************************************************************/
++
++static inline void pci_mmap_pages_hack_after_alloc(caddr_t kva, unsigned order)
++{
++      unsigned pfn = __pa(kva) >> PAGE_SHIFT;
++      struct page *start_pg = pfn_to_page(pfn);
++#if !defined(NDEBUG) || EFRM_MMAP_USE_SPLIT
++      struct page *end_pg = start_pg + (1 << order);
++      struct page *pg;
++#endif
++
++      /* Compound pages don't get created for order 0 pages and there's no
++       * fixing up needs to be done. */
++      if (order == 0)
++              return;
++
++      /* If we've been given a reserved page then it must have come from
++       * the bounce buffer pool. */
++      if (PageReserved(start_pg)) {
++#if defined(VM_PFNMAP) || !defined(__x86_64__)
++              /* Kernel allocated reserved pages when not expected */
++              BUG();
++#endif
++              return;
++      }
++
++      /* Check the page count and PG_compound bit. */
++#ifndef NDEBUG
++#  if defined(PG_compound)
++      EFRM_ASSERT(PageCompound(start_pg) == EFRM_MMAP_USE_COMPOUND);
++#  endif
++      EFRM_ASSERT(page_count(start_pg) == 1);
++
++      {
++              /* Some kernels have the page count field hold (ref_count-1)
++               * rather than (ref_count).  This is so that decrementing the
++               * reference count to "zero" causes the internal value to change
++               * from 0 to -1 which sets the carry flag.  Other kernels store
++               * the real reference count value in the obvious way.  We handle
++               * this here by reading the reference count field of the first
++               * page, which is always 1. */
++              int pg_count_zero;
++              pg_count_zero = atomic_read(&page_count_field(start_pg)) - 1;
++              for (pg = start_pg + 1; pg < end_pg; pg++) {
++                      int pg_count;
++#  if defined(PG_compound)
++                      EFRM_ASSERT(PageCompound(pg) == EFRM_MMAP_USE_COMPOUND);
++#  endif
++
++                      /* Bug 5450: Some kernels initialise the page count
++                       * to one for pages other than the first and some
++                       * leave it at zero.  We allow either behaviour
++                       * here, but disallow anything strange.  Newer
++                       * kernels only define set_page_count in an
++                       * internal header file, so we have to make do with
++                       * incrementing and decrementing the reference
++                       * count.  Fortunately, those kernels don't set the
++                       * reference count to one on all the pages. */
++                      pg_count = atomic_read(&page_count_field(pg));
++#  if EFRM_MMAP_RESET_REFCNT
++                      if (pg_count != pg_count_zero)
++                              EFRM_ASSERT(pg_count == pg_count_zero + 1);
++#  else
++                      EFRM_ASSERT(pg_count == pg_count_zero);
++#  endif
++              }
++      }
++#endif
++
++      /* Split the multi-page allocation if necessary. */
++#if EFRM_MMAP_USE_SPLIT
++      for (pg = start_pg; pg < end_pg; pg++) {
++
++              /* This is no longer a compound page. */
++#  if EFRM_MMAP_USE_COMPOUND
++              ClearPageCompound(pg);
++              EFRM_ASSERT(PageCompound(pg) == 0);
++#  endif
++
++#  ifndef NDEBUG
++              {
++                      int pg_count = page_count(pg);
++                      /* Bug 5450: The page count can be zero or one here. */
++                      if (pg == start_pg) {
++                              EFRM_ASSERT(pg_count == 1);
++                      } else {
++#    if EFRM_MMAP_RESET_REFCNT
++                              if (pg_count != 0)
++                                      EFRM_ASSERT(pg_count == 1);
++#    else
++                              EFRM_ASSERT(pg_count == 0);
++#    endif
++                      }
++              }
++#  endif
++
++              /* Get a reference which will be released after the pages have
++               * been passed back to pci_free_consistent. */
++#  if EFRM_MMAP_RESET_REFCNT
++              /* Bug 5450: Reset the reference count since the count might
++               * already be 1. */
++              ci_set_page_count(pg, (pg == start_pg) ? 2 : 1);
++#  else
++              get_page(pg);
++#  endif
++      }
++#endif
++
++      /* Fudge the reference count if necessary. */
++#if EFRM_MMAP_USE_INCREMENT
++      for (pg = start_pg; pg < end_pg; pg++)
++              inc_page_count(pg);
++#endif
++}
++
++static inline void pci_mmap_pages_hack_before_free(caddr_t kva, unsigned order)
++{
++#if EFRM_MMAP_USE_INCREMENT || !defined(NDEBUG)
++      /* Drop the references taken in pci_mmap_pages_hack_after_alloc */
++      unsigned pfn = __pa(kva) >> PAGE_SHIFT;
++      struct page *start_pg = pfn_to_page(pfn);
++      struct page *end_pg = start_pg + (1 << order);
++      struct page *pg;
++
++      /* Compound pages don't get created for order 0 pages and there's no
++       * fixing up needs to be done. */
++      if (order == 0)
++              return;
++
++      if (PageReserved(start_pg))
++              return;
++
++#  if EFRM_MMAP_USE_INCREMENT
++      for (pg = start_pg; pg < end_pg; pg++)
++              dec_page_count(pg);
++#  endif
++
++#if !defined(NDEBUG)
++      EFRM_ASSERT(page_count(start_pg) == 1+EFRM_MMAP_USE_SPLIT);
++
++#  if EFRM_MMAP_USE_COMPOUND && !EFRM_MMAP_USE_SPLIT
++      for (pg = start_pg; pg < end_pg; pg++)
++              EFRM_ASSERT(PageCompound(pg));
++#  else
++      for (pg = start_pg+1; pg < end_pg; pg++) {
++              unsigned exp_pg_count = EFRM_MMAP_USE_SPLIT;
++              /* NB.  If this assertion fires, either we've messed up the
++               * page counting or someone is holding on to a reference.
++               */
++              EFRM_ASSERT(page_count(pg) == exp_pg_count);
++      }
++#  endif
++#endif
++
++#endif
++}
++
++static inline void pci_mmap_pages_hack_after_free(caddr_t kva, unsigned order)
++{
++#if EFRM_MMAP_USE_SPLIT
++      /* Drop the references taken in pci_mmap_pages_hack_after_alloc */
++      unsigned pfn = __pa(kva) >> PAGE_SHIFT;
++      struct page *start_pg = pfn_to_page(pfn);
++      struct page *end_pg = start_pg + (1 << order);
++      struct page *pg;
++
++      /* Compound pages don't get created for order 0 pages and there's no
++       * fixing up needs to be done. */
++      if (order == 0)
++              return;
++
++      if (PageReserved(start_pg))
++              return;
++
++      for (pg = start_pg; pg < end_pg; pg++) {
++              EFRM_ASSERT(page_count(pg) == 1);
++              put_page(pg);
++      }
++#endif
++}
++
++
++#if EFRM_IOPAGE_COUNTS_ENABLED
++
++static int iopage_counts[8];
++
++void dump_iopage_counts(void)
++{
++      EFRM_NOTICE("iopage counts: %d %d %d %d %d %d %d %d", iopage_counts[0],
++                  iopage_counts[1], iopage_counts[2], iopage_counts[3],
++                  iopage_counts[4], iopage_counts[5], iopage_counts[6],
++                  iopage_counts[7]);
++}
++
++#endif
++
++
++
++/*********** pci_alloc_consistent / pci_free_consistent ***********/
++
++void *efrm_dma_alloc_coherent(struct device *dev, size_t size,
++                            dma_addr_t *dma_addr, int flag)
++{
++      struct pci_dev *pci_dev;
++      void *ptr;
++      unsigned order;
++      EFRM_IOMMU_DECL;
++
++      order = __ffs(size/PAGE_SIZE);
++      EFRM_ASSERT(size == (PAGE_SIZE<<order));
++
++      /* NB. The caller may well set __GFP_COMP.  However we can't
++       * rely on this working on older kernels.  2.6.9 only acts on
++       * __GFP_COMP if CONFIG_HUGETLB_PAGE is defined.  If the flag
++       * did have an effect then PG_compound will be set on the
++       * pages. */
++
++      if (use_pci_alloc) {
++              /* Can't take a spinlock here since the allocation can
++               * block. */
++              ptr = dma_alloc_coherent(dev, size, dma_addr, flag);
++              if (ptr == NULL)
++                      return ptr;
++      } else {
++#ifdef CONFIG_SWIOTLB         /* BUG1340 */
++              if (swiotlb) {
++                      EFRM_ERR("%s: This kernel is using DMA bounce "
++                               "buffers.  Please upgrade kernel to "
++                               "linux2.6 or reduce the amount of RAM "
++                               "with mem=XXX.", __FUNCTION__);
++                      return NULL;
++              }
++#endif
++              ptr = (void *)__get_free_pages(flag, order);
++
++              if (ptr == NULL)
++                      return NULL;
++
++              EFRM_IOMMU_LOCK();
++              pci_dev = container_of(dev, struct pci_dev, dev);
++              *dma_addr = pci_map_single(pci_dev, ptr, size,
++                                         PCI_DMA_BIDIRECTIONAL);
++              EFRM_IOMMU_UNLOCK();
++              if (pci_dma_mapping_error(*dma_addr)) {
++                      free_pages((unsigned long)ptr, order);
++                      return NULL;
++              }
++      }
++
++#ifndef CONFIG_IA64
++      pci_mmap_pages_hack_after_alloc(ptr, order);
++#endif
++
++#if EFRM_IOPAGE_COUNTS_ENABLED
++      if (order < 8)
++              iopage_counts[order]++;
++      else
++              EFRM_ERR("Huge iopages alloc (order=%d) ??? (not counted)",
++                       order);
++#endif
++
++      return ptr;
++}
++
++void efrm_dma_free_coherent(struct device *dev, size_t size,
++                          void *ptr, dma_addr_t dma_addr)
++{
++      struct pci_dev *pci_dev;
++      unsigned order;
++      EFRM_IOMMU_DECL;
++
++      order = __ffs(size/PAGE_SIZE);
++      EFRM_ASSERT(size == (PAGE_SIZE<<order));
++
++#if EFRM_IOPAGE_COUNTS_ENABLED
++      if (order < 8)
++              --iopage_counts[order];
++      else
++              EFRM_ERR("Huge iopages free (order=%d) ??? (not counted)",
++                       order);
++#endif
++#ifndef CONFIG_IA64
++      pci_mmap_pages_hack_before_free(ptr, order);
++#endif
++      if (use_pci_alloc) {
++              EFRM_IOMMU_LOCK();
++              dma_free_coherent(dev, size, ptr, dma_addr);
++              EFRM_IOMMU_UNLOCK();
++      } else {
++              pci_dev = container_of(dev, struct pci_dev, dev);
++              EFRM_IOMMU_LOCK();
++              efrm_pci_unmap_single(pci_dev, dma_addr, size,
++                                    PCI_DMA_BIDIRECTIONAL);
++              EFRM_IOMMU_UNLOCK();
++
++              free_pages((unsigned long)ptr, order);
++      }
++
++#ifndef CONFIG_IA64
++      pci_mmap_pages_hack_after_free(ptr, order);
++#endif
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/kernel_compat.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/kernel_compat.h   2008-05-19 00:33:29.429842497 +0300
+@@ -0,0 +1,239 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides compatibility layer for various Linux kernel versions
++ * (starting from 2.6.9 RHEL kernel).
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef DRIVER_LINUX_RESOURCE_KERNEL_COMPAT_H
++#define DRIVER_LINUX_RESOURCE_KERNEL_COMPAT_H
++
++#include <linux/version.h>
++
++/********* wait_for_completion_timeout() ********************/
++#include <linux/sched.h>
++
++/* RHEL_RELEASE_CODE from linux/version.h is only defined for 2.6.9-55EL
++ * UTS_RELEASE is unfortunately unusable
++ * Really only need this fix for <2.6.9-34EL
++ */
++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)) && \
++      !defined(RHEL_RELEASE_CODE)
++
++static inline unsigned long fastcall __sched
++efrm_wait_for_completion_timeout(struct completion *x, unsigned long timeout)
++{
++      might_sleep();
++
++      spin_lock_irq(&x->wait.lock);
++      if (!x->done) {
++              DECLARE_WAITQUEUE(wait, current);
++
++              wait.flags |= WQ_FLAG_EXCLUSIVE;
++              __add_wait_queue_tail(&x->wait, &wait);
++              do {
++                      __set_current_state(TASK_UNINTERRUPTIBLE);
++                      spin_unlock_irq(&x->wait.lock);
++                      timeout = schedule_timeout(timeout);
++                      spin_lock_irq(&x->wait.lock);
++                      if (!timeout) {
++                              __remove_wait_queue(&x->wait, &wait);
++                              goto out;
++                      }
++              } while (!x->done);
++              __remove_wait_queue(&x->wait, &wait);
++      }
++      x->done--;
++out:
++      spin_unlock_irq(&x->wait.lock);
++      return timeout;
++}
++
++#  ifdef wait_for_completion_timeout
++#    undef wait_for_completion_timeout
++#  endif
++#  define wait_for_completion_timeout efrm_wait_for_completion_timeout
++
++#endif
++
++/********* pci_map_*() ********************/
++
++#include <linux/pci.h>
++
++/* Bug 4560: Some kernels leak IOMMU entries under heavy load.  Use a
++ * spinlock to serialise access where possible to alleviate the
++ * problem.
++ *
++ * NB. This is duplicated in the net driver.  Please keep in sync. */
++#if ((LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && \
++     (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)) && \
++      defined(__x86_64__) && defined(CONFIG_SMP))
++
++#define EFRM_HAVE_IOMMU_LOCK 1
++
++#if ((LINUX_VERSION_CODE == KERNEL_VERSION(2,6,5)) && \
++      defined(CONFIG_SUSE_KERNEL))
++#define EFRM_NEED_ALTERNATE_MAX_PFN 1
++#endif
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,15)
++#if defined(CONFIG_GART_IOMMU)
++#define EFRM_NO_IOMMU no_iommu
++#else
++#define EFRM_NO_IOMMU 1
++#endif
++#else
++#define EFRM_NO_IOMMU 0
++#endif
++
++/* Set to 0 if we should never use the lock.  Set to 1 if we should
++ * automatically determine if we should use the lock.  Set to 2 if we
++ * should always use the lock. */
++extern unsigned int efx_use_iommu_lock;
++/* Defined in the net driver. */
++extern spinlock_t efx_iommu_lock;
++/* Non-zero if there is a card which needs the lock. */
++extern int efrm_need_iommu_lock;
++
++/* The IRQ state is needed if the lock is being used.  The flag is
++ * cached to ensure that every lock is followed by an unlock, even
++ * if the global flag changes in the middle of the operation. */
++
++#define EFRM_IOMMU_DECL                               \
++      unsigned long efx_iommu_irq_state = 0;  \
++      int efx_iommu_using_lock;
++#define EFRM_IOMMU_LOCK()                                             \
++      do {                                                            \
++              efx_iommu_using_lock = (efx_use_iommu_lock &&           \
++                                      (efrm_need_iommu_lock ||        \
++                                       efx_use_iommu_lock >= 2));     \
++              if (efx_iommu_using_lock)                               \
++              spin_lock_irqsave(&efx_iommu_lock, efx_iommu_irq_state);\
++      } while (0)
++#define EFRM_IOMMU_UNLOCK()                                           \
++      do {                                                            \
++              if (efx_iommu_using_lock)                               \
++              spin_unlock_irqrestore(&efx_iommu_lock,                 \
++                                     efx_iommu_irq_state);            \
++      } while (0)
++
++#else /* defined(__x86_64__) && defined(CONFIG_SMP) */
++
++#define EFRM_HAVE_IOMMU_LOCK 0
++#define EFRM_IOMMU_DECL
++#define EFRM_IOMMU_LOCK()    do {} while (0)
++#define EFRM_IOMMU_UNLOCK()  do {} while (0)
++
++#endif
++
++static inline dma_addr_t efrm_pci_map_single(struct pci_dev *hwdev, void *ptr,
++                                           size_t size, int direction)
++{
++      dma_addr_t dma_addr;
++      EFRM_IOMMU_DECL;
++
++      EFRM_IOMMU_LOCK();
++      dma_addr = pci_map_single(hwdev, ptr, size, direction);
++      EFRM_IOMMU_UNLOCK();
++
++      return dma_addr;
++}
++
++static inline void efrm_pci_unmap_single(struct pci_dev *hwdev,
++                                       dma_addr_t dma_addr, size_t size,
++                                       int direction)
++{
++      EFRM_IOMMU_DECL;
++
++      EFRM_IOMMU_LOCK();
++      pci_unmap_single(hwdev, dma_addr, size, direction);
++      EFRM_IOMMU_UNLOCK();
++}
++
++static inline dma_addr_t efrm_pci_map_page(struct pci_dev *hwdev,
++                                         struct page *page,
++                                         unsigned long offset, size_t size,
++                                         int direction)
++{
++      dma_addr_t dma_addr;
++      EFRM_IOMMU_DECL;
++
++      EFRM_IOMMU_LOCK();
++      dma_addr = pci_map_page(hwdev, page, offset, size, direction);
++      EFRM_IOMMU_UNLOCK();
++
++      return dma_addr;
++}
++
++static inline void efrm_pci_unmap_page(struct pci_dev *hwdev,
++                                     dma_addr_t dma_addr, size_t size,
++                                     int direction)
++{
++      EFRM_IOMMU_DECL;
++
++      EFRM_IOMMU_LOCK();
++      pci_unmap_page(hwdev, dma_addr, size, direction);
++      EFRM_IOMMU_UNLOCK();
++}
++
++#ifndef IN_KERNEL_COMPAT_C
++#  ifndef __GFP_COMP
++#    define __GFP_COMP 0
++#  endif
++#  ifndef __GFP_ZERO
++#    define __GFP_ZERO 0
++#  endif
++#endif
++
++extern void *efrm_dma_alloc_coherent(struct device *dev, size_t size,
++                                   dma_addr_t *dma_addr, int flag);
++
++extern void efrm_dma_free_coherent(struct device *dev, size_t size,
++                                 void *ptr, dma_addr_t dma_addr);
++
++static inline void *efrm_pci_alloc_consistent(struct pci_dev *hwdev,
++                                            size_t size,
++                                            dma_addr_t *dma_addr)
++{
++      return efrm_dma_alloc_coherent(&hwdev->dev, size, dma_addr,
++                                     GFP_ATOMIC);
++}
++
++static inline void efrm_pci_free_consistent(struct pci_dev *hwdev, size_t size,
++                                          void *ptr, dma_addr_t dma_addr)
++{
++      efrm_dma_free_coherent(&hwdev->dev, size, ptr, dma_addr);
++}
++
++#endif /* DRIVER_LINUX_RESOURCE_KERNEL_COMPAT_H */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/kernel_proc.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/kernel_proc.c     2008-05-19 00:33:29.429842497 +0300
+@@ -0,0 +1,111 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains /proc/driver/sfc_resource/ implementation.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efrm/debug.h>
++#include <ci/efrm/nic_table.h>
++#include <ci/efrm/driver_private.h>
++#include <linux/proc_fs.h>
++
++/** Top level directory for sfc specific stats **/
++static struct proc_dir_entry *efrm_proc_root; /* = NULL */
++
++static int
++efrm_resource_read_proc(char *buf, char **start, off_t offset, int count,
++                      int *eof, void *data);
++
++int efrm_install_proc_entries(void)
++{
++      /* create the top-level directory for etherfabric specific stuff */
++      efrm_proc_root = proc_mkdir("sfc_resource", proc_root_driver);
++      if (!efrm_proc_root)
++              return -ENOMEM;
++      EFRM_ASSERT(efrm_proc_root);
++
++      if (create_proc_read_entry("resources", 0, efrm_proc_root,
++                                 efrm_resource_read_proc, 0) == NULL) {
++              EFRM_WARN("%s: Unable to create /proc/drivers/sfc_resource/"
++                        "resources", __FUNCTION__);
++      }
++      return 0;
++}
++
++void efrm_uninstall_proc_entries(void)
++{
++      EFRM_ASSERT(efrm_proc_root);
++      remove_proc_entry("resources", efrm_proc_root);
++      remove_proc_entry("sfc_resource", proc_root_driver);
++      efrm_proc_root = NULL;
++}
++
++/****************************************************************************
++ *
++ * /proc/drivers/sfc/resources
++ *
++ ****************************************************************************/
++
++#define EFRM_PROC_PRINTF(buf, len, fmt, ...)                          \
++      do {                                                            \
++              if (count - len > 0)                                    \
++                      len += snprintf(buf+len, count-len, (fmt),      \
++                                      __VA_ARGS__);                   \
++      } while (0)
++
++static int
++efrm_resource_read_proc(char *buf, char **start, off_t offset, int count,
++                      int *eof, void *data)
++{
++      irq_flags_t lock_flags;
++      int len = 0;
++      int type;
++      struct efrm_resource_manager *rm;
++
++      for (type = 0; type < EFRM_RESOURCE_NUM; type++) {
++              rm = efrm_rm_table[type];
++              if (rm == NULL)
++                      continue;
++
++              EFRM_PROC_PRINTF(buf, len, "*** %s ***\n", rm->rm_name);
++
++              spin_lock_irqsave(&rm->rm_lock, lock_flags);
++              EFRM_PROC_PRINTF(buf, len, "current = %u\n", rm->rm_resources);
++              EFRM_PROC_PRINTF(buf, len, "    max = %u\n\n",
++                               rm->rm_resources_hiwat);
++              spin_unlock_irqrestore(&rm->rm_lock, lock_flags);
++      }
++
++      return count ? strlen(buf) : 0;
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/kfifo.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/kfifo.c   2008-05-19 00:33:29.433842727 +0300
+@@ -0,0 +1,212 @@
++/*
++ * A simple kernel FIFO implementation.
++ *
++ * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
++ *
++ */
++
++/*
++ * This file is stolen from the Linux kernel sources
++ * (linux-2.6.22/kernel/kfifo.c) into sfc_resource driver.
++ * It should be used for old kernels without kfifo implementation.
++ * Most part of linux/kfifo.h is incorporated into
++ * ci/efrm/sysdep_linux.h.
++ */
++#include <ci/efrm/sysdep_linux.h>
++#ifdef HAS_NO_KFIFO
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/slab.h>
++#include <linux/err.h>
++/*#include <linux/kfifo.h>*/
++
++/**
++ * kfifo_init - allocates a new FIFO using a preallocated buffer
++ * @buffer: the preallocated buffer to be used.
++ * @size: the size of the internal buffer, this have to be a power of 2.
++ * @gfp_mask: get_free_pages mask, passed to kmalloc()
++ * @lock: the lock to be used to protect the fifo buffer
++ *
++ * Do NOT pass the kfifo to kfifo_free() after use! Simply free the
++ * &struct kfifo with kfree().
++ */
++struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
++                       gfp_t gfp_mask, spinlock_t * lock)
++{
++      struct kfifo *fifo;
++
++      /* size must be a power of 2 */
++      BUG_ON(size & (size - 1));
++
++      fifo = kmalloc(sizeof(struct kfifo), gfp_mask);
++      if (!fifo)
++              return ERR_PTR(-ENOMEM);
++
++      fifo->buffer = buffer;
++      fifo->size = size;
++      fifo->in = fifo->out = 0;
++      fifo->lock = lock;
++
++      return fifo;
++}
++
++EXPORT_SYMBOL(kfifo_init);
++
++/**
++ * kfifo_alloc - allocates a new FIFO and its internal buffer
++ * @size: the size of the internal buffer to be allocated.
++ * @gfp_mask: get_free_pages mask, passed to kmalloc()
++ * @lock: the lock to be used to protect the fifo buffer
++ *
++ * The size will be rounded-up to a power of 2.
++ */
++struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask, spinlock_t * lock)
++{
++      unsigned char *buffer;
++      struct kfifo *ret;
++
++      /*
++       * round up to the next power of 2, since our 'let the indices
++       * wrap' tachnique works only in this case.
++       */
++      if (size & (size - 1)) {
++              BUG_ON(size > 0x80000000);
++              size = roundup_pow_of_two(size);
++      }
++
++      buffer = kmalloc(size, gfp_mask);
++      if (!buffer)
++              return ERR_PTR(-ENOMEM);
++
++      ret = kfifo_init(buffer, size, gfp_mask, lock);
++
++      if (IS_ERR(ret))
++              kfree(buffer);
++
++      return ret;
++}
++
++EXPORT_SYMBOL(kfifo_alloc);
++
++/**
++ * kfifo_free - frees the FIFO
++ * @fifo: the fifo to be freed.
++ */
++void kfifo_free(struct kfifo *fifo)
++{
++      kfree(fifo->buffer);
++      kfree(fifo);
++}
++
++EXPORT_SYMBOL(kfifo_free);
++
++/**
++ * __kfifo_put - puts some data into the FIFO, no locking version
++ * @fifo: the fifo to be used.
++ * @buffer: the data to be added.
++ * @len: the length of the data to be added.
++ *
++ * This function copies at most @len bytes from the @buffer into
++ * the FIFO depending on the free space, and returns the number of
++ * bytes copied.
++ *
++ * Note that with only one concurrent reader and one concurrent
++ * writer, you don't need extra locking to use these functions.
++ */
++unsigned int
++__kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
++{
++      unsigned int l;
++
++      len = min(len, fifo->size - fifo->in + fifo->out);
++
++      /*
++       * Ensure that we sample the fifo->out index -before- we
++       * start putting bytes into the kfifo.
++       */
++
++      smp_mb();
++
++      /* first put the data starting from fifo->in to buffer end */
++      l = min(len, fifo->size - (fifo->in & (fifo->size - 1)));
++      memcpy(fifo->buffer + (fifo->in & (fifo->size - 1)), buffer, l);
++
++      /* then put the rest (if any) at the beginning of the buffer */
++      memcpy(fifo->buffer, buffer + l, len - l);
++
++      /*
++       * Ensure that we add the bytes to the kfifo -before-
++       * we update the fifo->in index.
++       */
++
++      smp_wmb();
++
++      fifo->in += len;
++
++      return len;
++}
++
++EXPORT_SYMBOL(__kfifo_put);
++
++/**
++ * __kfifo_get - gets some data from the FIFO, no locking version
++ * @fifo: the fifo to be used.
++ * @buffer: where the data must be copied.
++ * @len: the size of the destination buffer.
++ *
++ * This function copies at most @len bytes from the FIFO into the
++ * @buffer and returns the number of copied bytes.
++ *
++ * Note that with only one concurrent reader and one concurrent
++ * writer, you don't need extra locking to use these functions.
++ */
++unsigned int
++__kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
++{
++      unsigned int l;
++
++      len = min(len, fifo->in - fifo->out);
++
++      /*
++       * Ensure that we sample the fifo->in index -before- we
++       * start removing bytes from the kfifo.
++       */
++
++      smp_rmb();
++
++      /* first get the data from fifo->out until the end of the buffer */
++      l = min(len, fifo->size - (fifo->out & (fifo->size - 1)));
++      memcpy(buffer, fifo->buffer + (fifo->out & (fifo->size - 1)), l);
++
++      /* then get the rest (if any) from the beginning of the buffer */
++      memcpy(buffer + l, fifo->buffer, len - l);
++
++      /*
++       * Ensure that we remove the bytes from the kfifo -before-
++       * we update the fifo->out index.
++       */
++
++      smp_mb();
++
++      fifo->out += len;
++
++      return len;
++}
++
++EXPORT_SYMBOL(__kfifo_get);
++#endif
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/linux_resource_internal.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/linux_resource_internal.h 2008-05-19 00:33:29.433842727 +0300
+@@ -0,0 +1,75 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains Linux-specific API internal for the resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __LINUX_RESOURCE_INTERNAL__
++#define __LINUX_RESOURCE_INTERNAL__
++
++#include <ci/driver/resource/linux_efhw_nic.h>
++#include <ci/efrm/debug.h>
++#include <ci/efrm/driver_private.h>
++#include <ci/driver/efab/hardware.h>
++
++
++/*! Linux specific EtherFabric initialisation */
++extern int
++linux_efrm_nic_ctor(struct linux_efhw_nic *, struct pci_dev *,
++                  spinlock_t *reg_lock,
++                  unsigned nic_flags, unsigned nic_options);
++
++/*! Linux specific EtherFabric initialisation */
++extern void linux_efrm_nic_dtor(struct linux_efhw_nic *);
++
++/*! Linux specific EtherFabric initialisation -- interrupt registration */
++extern int linux_efrm_irq_ctor(struct linux_efhw_nic *);
++
++/*! Linux specific  EtherFabric initialisation -- interrupt deregistration */
++extern void linux_efrm_irq_dtor(struct linux_efhw_nic *);
++
++extern int  efrm_driverlink_register(void);
++extern void efrm_driverlink_unregister(void);
++
++extern int
++efrm_nic_add(struct pci_dev *dev, unsigned int opts, const uint8_t *mac_addr,
++           struct linux_efhw_nic **lnic_out, spinlock_t *reg_lock,
++           int bt_min, int bt_max, const struct vi_resource_dimensions *);
++extern void efrm_nic_del(struct linux_efhw_nic *);
++
++
++extern int efrm_install_proc_entries(void);
++extern void efrm_uninstall_proc_entries(void);
++
++#endif  /* __LINUX_RESOURCE_INTERNAL__ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/nic.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/nic.c     2008-05-19 00:33:29.433842727 +0300
+@@ -0,0 +1,190 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains EtherFabric Generic NIC instance (init, interrupts,
++ * etc)
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efhw/debug.h>
++#include <ci/driver/efab/hardware.h>
++#include <ci/efhw/falcon.h>
++#include <ci/efhw/nic.h>
++#include <ci/efhw/eventq.h>
++
++
++int efhw_device_type_init(struct efhw_device_type *dt,
++                        int vendor_id, int device_id,
++                        int class_revision)
++{
++      if (vendor_id != 0x1924)
++              return 0;
++
++      switch (device_id) {
++      case 0x0703:
++      case 0x6703:
++              dt->arch = EFHW_ARCH_FALCON;
++              dt->variant = 'A';
++              switch (class_revision) {
++              case 0:
++                      dt->revision = 0;
++                      break;
++              case 1:
++                      dt->revision = 1;
++                      break;
++              default:
++                      return 0;
++              }
++              break;
++      case 0x0710:
++              dt->arch = EFHW_ARCH_FALCON;
++              dt->variant = 'B';
++              switch (class_revision) {
++              case 2:
++                      dt->revision = 0;
++                      break;
++              default:
++                      return 0;
++              }
++              break;
++      default:
++              return 0;
++      }
++
++      return 1;
++}
++
++
++/*--------------------------------------------------------------------
++ *
++ * NIC Initialisation
++ *
++ *--------------------------------------------------------------------*/
++
++/* make this separate from initialising data structure
++** to allow this to be called at a later time once we can access PCI
++** config space to find out what hardware we have
++*/
++void efhw_nic_init(struct efhw_nic *nic, unsigned flags, unsigned options,
++                 struct efhw_device_type dev_type)
++{
++      int i;
++
++      nic->devtype = dev_type;
++      nic->flags = flags;
++      nic->options = options;
++      nic->bar_ioaddr = 0;
++      spin_lock_init(&nic->the_reg_lock);
++      nic->reg_lock = &nic->the_reg_lock;
++      nic->mtu = 1500 + ETH_HLEN;
++
++      for (i = 0; i < EFHW_KEVENTQ_MAX; i++)
++              nic->irq_unit[i] = EFHW_IRQ_UNIT_UNUSED;
++
++      switch (nic->devtype.arch) {
++      case EFHW_ARCH_FALCON:
++              nic->evq_sizes = 512 | 1024 | 2048 | 4096 | 8192 |
++                      16384 | 32768;
++              nic->txq_sizes = 512 | 1024 | 2048 | 4096;
++              nic->rxq_sizes = 512 | 1024 | 2048 | 4096;
++              nic->efhw_func = &falcon_char_functional_units;
++              nic->ctr_ap_bytes = EFHW_64M;
++              switch (nic->devtype.variant) {
++              case 'A':
++                      nic->ctr_ap_bar = FALCON_S_CTR_AP_BAR;
++                      break;
++              case 'B':
++                      nic->flags |= NIC_FLAG_NO_INTERRUPT;
++                      nic->ctr_ap_bar = FALCON_P_CTR_AP_BAR;
++                      break;
++              default:
++                      EFHW_ASSERT(0);
++                      break;
++              }
++              break;
++      default:
++              EFHW_ASSERT(0);
++              break;
++      }
++}
++
++
++void efhw_nic_close_interrupts(struct efhw_nic *nic)
++{
++      int i;
++
++      EFHW_ASSERT(nic);
++      if (!efhw_nic_have_hw(nic))
++              return;
++
++      EFHW_ASSERT(efhw_nic_have_hw(nic));
++
++      for (i = 0; i < EFHW_KEVENTQ_MAX; i++) {
++              if (nic->irq_unit[i] != EFHW_IRQ_UNIT_UNUSED)
++                      efhw_nic_interrupt_disable(nic, i);
++      }
++}
++
++void efhw_nic_dtor(struct efhw_nic *nic)
++{
++      EFHW_ASSERT(nic);
++
++      /* Check that we have functional units because the software only
++       * driver doesn't initialise anything hardware related any more */
++
++#ifndef __ci_ul_driver__
++      /* close interrupts is called first because the act of deregistering
++         the driver could cause this driver to change from master to slave
++         and hence the implicit interrupt mappings would be wrong */
++
++      EFHW_TRACE("%s: functional units ... ", __FUNCTION__);
++
++      if (efhw_nic_have_functional_units(nic)) {
++              efhw_nic_close_interrupts(nic);
++              efhw_nic_close_hardware(nic);
++      }
++      EFHW_TRACE("%s: functional units ... done", __FUNCTION__);
++#endif
++
++      /* destroy event queues */
++      EFHW_TRACE("%s: event queues ... ", __FUNCTION__);
++
++#ifndef __ci_ul_driver__
++      {
++              int i;
++              for (i = 0; i < EFHW_KEVENTQ_MAX; ++i)
++                      if (nic->evq[i].evq_mask)
++                              efhw_keventq_dtor(nic, &nic->evq[i]);
++      }
++#endif
++
++      EFHW_TRACE("%s: event queues ... done", __FUNCTION__);
++
++      spin_lock_destroy(&nic->the_reg_lock);
++
++      EFHW_TRACE("%s: DONE", __FUNCTION__);
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/resource_driver.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/resource_driver.c 2008-05-19 00:33:29.433842727 +0300
+@@ -0,0 +1,640 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains main driver entry points.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include "linux_resource_internal.h"
++#include "kernel_compat.h"
++#include <ci/efrm/nic_table.h>
++#include <ci/driver/resource/efx_vi.h>
++#include <ci/efhw/eventq.h>
++#include <ci/efhw/nic.h>
++#include <ci/efrm/buffer_table.h>
++#include <ci/efrm/vi_resource_private.h>
++#include <ci/efrm/driver_private.h>
++
++#if EFRM_HAVE_IOMMU_LOCK
++#ifdef EFRM_NEED_ALTERNATE_MAX_PFN
++extern unsigned long blk_max_pfn;
++#define max_pfn blk_max_pfn
++#else
++#include <linux/bootmem.h>
++#endif
++#endif
++
++MODULE_AUTHOR("Solarflare Communications");
++MODULE_LICENSE("GPL");
++
++static struct efhw_ev_handler ev_handler = {
++      .wakeup_fn = efrm_handle_wakeup_event,
++      .timeout_fn = efrm_handle_timeout_event,
++      .dmaq_flushed_fn = efrm_handle_dmaq_flushed,
++};
++
++#if EFRM_HAVE_IOMMU_LOCK
++int efrm_need_iommu_lock;
++EXPORT_SYMBOL(efrm_need_iommu_lock);
++#endif
++
++const int max_hardware_init_repeats = 10;
++
++/*--------------------------------------------------------------------
++ *
++ * Module load time variables
++ *
++ *--------------------------------------------------------------------*/
++/* See docs/notes/pci_alloc_consistent */
++int use_pci_alloc = 1;                /* Use pci_alloc_consistent to alloc iopages */
++static int do_irq = 1;                /* enable interrupts */
++
++#if defined(CONFIG_X86_XEN)
++static int irq_moderation = 60;       /* interrupt moderation (60 usec) */
++#else
++static int irq_moderation = 20;       /* interrupt moderation (20 usec) */
++#endif
++static int nic_options = NIC_OPT_DEFAULT;
++int efx_vi_eventq_size = EFX_VI_EVENTQ_SIZE_DEFAULT;
++
++module_param(do_irq, int, S_IRUGO);
++MODULE_PARM_DESC(do_irq, "Enable interrupts.  "
++               "Do not turn it off unless you know what are you doing.");
++module_param(irq_moderation, int, S_IRUGO);
++MODULE_PARM_DESC(irq_moderation, "IRQ moderation in usec");
++module_param(nic_options, int, S_IRUGO);
++MODULE_PARM_DESC(nic_options, "Nic options -- see efhw_types.h");
++module_param(use_pci_alloc, int, S_IRUGO);
++MODULE_PARM_DESC(use_pci_alloc, "Use pci_alloc_consistent to alloc iopages "
++               "(autodetected by kernel version)");
++module_param(efx_vi_eventq_size, int, S_IRUGO);
++MODULE_PARM_DESC(efx_vi_eventq_size,
++               "Size of event queue allocated by efx_vi library");
++
++/*--------------------------------------------------------------------
++ *
++ * Linux specific NIC initialisation
++ *
++ *--------------------------------------------------------------------*/
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++# define IRQ_PT_REGS_ARG   , struct pt_regs *regs __attribute__ ((unused))
++#else
++# define IRQ_PT_REGS_ARG
++#endif
++
++#ifndef IRQF_SHARED
++# define IRQF_SHARED SA_SHIRQ
++#endif
++
++static inline irqreturn_t
++linux_efrm_interrupt(int irr, void *dev_id IRQ_PT_REGS_ARG)
++{
++      return efhw_nic_interrupt((struct efhw_nic *)dev_id);
++}
++
++int linux_efrm_irq_ctor(struct linux_efhw_nic *lnic)
++{
++      struct efhw_nic *nic = &lnic->nic;
++
++      nic->flags &= ~NIC_FLAG_MSI;
++      if (nic->flags & NIC_FLAG_TRY_MSI) {
++              int rc = pci_enable_msi(lnic->pci_dev);
++              if (rc < 0) {
++                      EFRM_WARN("%s: Could not enable MSI (%d)",
++                                __FUNCTION__, rc);
++                      EFRM_WARN("%s: Continuing with legacy interrupt mode",
++                                __FUNCTION__);
++              } else {
++                      EFRM_NOTICE("%s: MSI enabled", __FUNCTION__);
++                      nic->flags |= NIC_FLAG_MSI;
++              }
++      }
++
++      if (request_irq(lnic->pci_dev->irq, linux_efrm_interrupt,
++                      IRQF_SHARED, "sfc_resource", nic)) {
++              EFRM_ERR("Request for interrupt #%d failed",
++                       lnic->pci_dev->irq);
++              nic->flags &= ~NIC_FLAG_OS_IRQ_EN;
++              return -EBUSY;
++      }
++      nic->flags |= NIC_FLAG_OS_IRQ_EN;
++
++      return 0;
++}
++
++void linux_efrm_irq_dtor(struct linux_efhw_nic *lnic)
++{
++      EFRM_TRACE("linux_efrm_irq_dtor: start");
++
++      if (lnic->nic.flags & NIC_FLAG_OS_IRQ_EN) {
++              free_irq(lnic->pci_dev->irq, &lnic->nic);
++              lnic->nic.flags &= ~NIC_FLAG_OS_IRQ_EN;
++      }
++
++      if (lnic->nic.flags & NIC_FLAG_MSI) {
++              pci_disable_msi(lnic->pci_dev);
++              lnic->nic.flags &= ~NIC_FLAG_MSI;
++      }
++
++      EFRM_TRACE("linux_efrm_irq_dtor: done");
++}
++
++/* Allocate buffer table entries for a particular NIC.
++ */
++static int efrm_nic_buffer_table_alloc(struct efhw_nic *nic)
++{
++      int capacity;
++      int page_order;
++      int i;
++      int rc;
++
++      /* Choose queue size. */
++      for (capacity = 8192; capacity <= nic->evq_sizes; capacity <<= 1) {
++              if (capacity > nic->evq_sizes) {
++                      EFRM_ERR
++                          ("%s: Unable to choose EVQ size (supported=%x)",
++                           __FUNCTION__, nic->evq_sizes);
++                      return -E2BIG;
++              } else if (capacity & nic->evq_sizes)
++                      break;
++      }
++      for (i = 0; i < EFHW_KEVENTQ_MAX; ++i) {
++              nic->evq[i].hw.capacity = capacity;
++              nic->evq[i].hw.buf_tbl_alloc.base = (unsigned)-1;
++      }
++
++      /* allocate buffer table entries to map onto the iobuffer */
++      page_order = get_order(capacity * sizeof(efhw_event_t));
++      if (!(nic->flags & NIC_FLAG_NO_INTERRUPT)) {
++              rc = efrm_buffer_table_alloc(page_order,
++                                           &nic->evq[0].hw.buf_tbl_alloc);
++              if (rc < 0) {
++                      EFRM_WARN
++                          ("%s: failed (%d) to alloc %d buffer table entries",
++                           __FUNCTION__, rc, page_order);
++                      return rc;
++              }
++      }
++      rc = efrm_buffer_table_alloc(page_order,
++                                   &nic->evq[FALCON_EVQ_NONIRQ].hw.
++                                   buf_tbl_alloc);
++      if (rc < 0) {
++              EFRM_WARN
++                  ("%s: failed (%d) to alloc %d buffer table entries",
++                   __FUNCTION__, rc, page_order);
++              return rc;
++      }
++
++      return 0;
++}
++
++/* Free buffer table entries allocated for a particular NIC.
++ */
++static void efrm_nic_buffer_table_free(struct efhw_nic *nic)
++{
++      int i;
++      for (i = 0; i <= FALCON_EVQ_NONIRQ; i++)
++              if (nic->evq[i].hw.buf_tbl_alloc.base != (unsigned)-1)
++                      efrm_buffer_table_free(&nic->evq[i].hw.buf_tbl_alloc);
++
++}
++
++static int iomap_bar(struct linux_efhw_nic *lnic, size_t len)
++{
++      efhw_ioaddr_t ioaddr;
++
++      ioaddr = ioremap_nocache(lnic->ctr_ap_pci_addr, len);
++      if (ioaddr == 0)
++              return -ENOMEM;
++
++      lnic->nic.bar_ioaddr = ioaddr;
++      return 0;
++}
++
++static int linux_efhw_nic_map_ctr_ap(struct linux_efhw_nic *lnic)
++{
++      struct efhw_nic *nic = &lnic->nic;
++      int rc;
++
++      rc = iomap_bar(lnic, nic->ctr_ap_bytes);
++
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++      /* Bug 5195: workaround for now. */
++      if (rc != 0 && nic->ctr_ap_bytes > 16 * 1024 * 1024) {
++              /* Try half the size for now. */
++              nic->ctr_ap_bytes /= 2;
++              EFRM_WARN("Bug 5195 WORKAROUND: retrying iomap of %d bytes",
++                        nic->ctr_ap_bytes);
++              rc = iomap_bar(lnic, nic->ctr_ap_bytes);
++      }
++#endif
++
++      if (rc < 0) {
++              EFRM_ERR("Failed (%d) to map bar (%d bytes)",
++                       rc, nic->ctr_ap_bytes);
++              return rc;
++      }
++
++      return rc;
++}
++
++int
++linux_efrm_nic_ctor(struct linux_efhw_nic *lnic, struct pci_dev *dev,
++                  spinlock_t *reg_lock,
++                  unsigned nic_flags, unsigned nic_options)
++{
++      struct efhw_device_type dev_type;
++      struct efhw_nic *nic = &lnic->nic;
++      u8 class_revision;
++      int rc;
++
++      rc = pci_read_config_byte(dev, PCI_CLASS_REVISION, &class_revision);
++      if (rc != 0) {
++              EFRM_ERR("%s: pci_read_config_byte failed (%d)",
++                       __FUNCTION__, rc);
++              return rc;
++      }
++
++      if (!efhw_device_type_init(&dev_type, dev->vendor, dev->device,
++                                 class_revision)) {
++              EFRM_ERR("%s: efhw_device_type_init failed %04x:%04x(%d)",
++                       __FUNCTION__, (unsigned) dev->vendor,
++                       (unsigned) dev->device, (int) class_revision);
++              return -ENODEV;
++      }
++
++      EFRM_NOTICE("attaching device type %04x:%04x %d:%c%d",
++                  (unsigned) dev->vendor, (unsigned) dev->device,
++                  dev_type.arch, dev_type.variant, dev_type.revision);
++
++      /* Initialise the adapter-structure. */
++      efhw_nic_init(nic, nic_flags, nic_options, dev_type);
++      lnic->pci_dev = dev;
++
++      rc = pci_enable_device(dev);
++      if (rc < 0) {
++              EFRM_ERR("%s: pci_enable_device failed (%d)",
++                       __FUNCTION__, rc);
++              return rc;
++      }
++
++      lnic->ctr_ap_pci_addr = pci_resource_start(dev, nic->ctr_ap_bar);
++
++      if (!pci_dma_supported(dev, (dma_addr_t)EFHW_DMA_ADDRMASK)) {
++              EFRM_ERR("%s: pci_dma_supported(%lx) failed", __FUNCTION__,
++                       (unsigned long)EFHW_DMA_ADDRMASK);
++              return -ENODEV;
++      }
++
++      if (pci_set_dma_mask(dev, (dma_addr_t)EFHW_DMA_ADDRMASK)) {
++              EFRM_ERR("%s: pci_set_dma_mask(%lx) failed", __FUNCTION__,
++                       (unsigned long)EFHW_DMA_ADDRMASK);
++              return -ENODEV;
++      }
++
++      if (pci_set_consistent_dma_mask(dev, (dma_addr_t)EFHW_DMA_ADDRMASK)) {
++              EFRM_ERR("%s: pci_set_consistent_dma_mask(%lx) failed",
++                       __FUNCTION__, (unsigned long)EFHW_DMA_ADDRMASK);
++              return -ENODEV;
++      }
++
++      rc = linux_efhw_nic_map_ctr_ap(lnic);
++      if (rc < 0)
++              return rc;
++
++      /* By default struct efhw_nic contains its own lock for protecting
++       * access to nic registers.  We override it with a pointer to the
++       * lock in the net driver.  This is needed when resource and net
++       * drivers share a single PCI function (falcon B series).
++       */
++      nic->reg_lock = reg_lock;
++      return 0;
++}
++
++void linux_efrm_nic_dtor(struct linux_efhw_nic *lnic)
++{
++      struct efhw_nic *nic = &lnic->nic;
++      efhw_ioaddr_t bar_ioaddr = nic->bar_ioaddr;
++
++      efhw_nic_dtor(nic);
++
++      efrm_nic_buffer_table_free(nic);
++
++      /* Unmap the bar. */
++      EFRM_ASSERT(bar_ioaddr);
++      iounmap(bar_ioaddr);
++      nic->bar_ioaddr = 0;
++}
++
++/****************************************************************************
++ *
++ * efrm_tasklet - used to poll the eventq which may result in further callbacks
++ *
++ ****************************************************************************/
++
++static void efrm_tasklet(unsigned long pdev)
++{
++      struct efhw_nic *nic = (struct efhw_nic *)pdev;
++
++      EFRM_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT));
++
++      efhw_keventq_poll(nic, &nic->evq[0]);
++      EFRM_TRACE("tasklet complete");
++}
++
++/****************************************************************************
++ *
++ * char driver specific interrupt callbacks -- run at hard IRQL
++ *
++ ****************************************************************************/
++static void efrm_handle_eventq_irq(struct efhw_nic *nic, int evq)
++{
++      /* NB. The interrupt must have already been acked (for legacy mode). */
++
++      EFRM_TRACE("%s: starting tasklet", __FUNCTION__);
++      EFRM_ASSERT(!(nic->flags & NIC_FLAG_NO_INTERRUPT));
++
++      tasklet_schedule(&linux_efhw_nic(nic)->tasklet);
++}
++
++/* A count of how many NICs this driver knows about. */
++static int n_nics_probed;
++
++/****************************************************************************
++ *
++ * efrm_nic_add: add the NIC to the resource driver
++ *
++ * NOTE: the flow of control through this routine is quite subtle
++ * because of the number of operations that can fail. We therefore
++ * take the apporaching of keeping the return code (rc) variable
++ * accurate, and only do operations while it is non-negative. Tear down
++ * is done at the end if rc is negative, depending on what has been set up
++ * by that point.
++ *
++ * So basically just make sure that any code you add checks rc>=0 before
++ * doing any work and you'll be fine.
++ *
++ ****************************************************************************/
++int
++efrm_nic_add(struct pci_dev *dev, unsigned flags, const uint8_t *mac_addr,
++           struct linux_efhw_nic **lnic_out, spinlock_t *reg_lock,
++           int bt_min, int bt_max,
++           const struct vi_resource_dimensions *res_dim)
++{
++      struct linux_efhw_nic *lnic = NULL;
++      struct efhw_nic *nic = NULL;
++      int count = 0, rc = 0, resources_init = 0;
++      int constructed = 0;
++      int registered_nic = 0;
++      int buffers_allocated = 0;
++      static unsigned nic_index; /* = 0; */
++
++      EFRM_TRACE("%s: device detected (Slot '%s', IRQ %d)", __FUNCTION__,
++                 pci_name(dev) ? pci_name(dev) : "?", dev->irq);
++
++      /* Ensure that we have room for the new adapter-structure. */
++      if (efrm_nic_table.nic_count == EFHW_MAX_NR_DEVS) {
++              EFRM_WARN("%s: WARNING: too many devices", __FUNCTION__);
++              rc = -ENOMEM;
++              goto failed;
++      }
++
++      if (n_nics_probed == 0) {
++              rc = efrm_resources_init(res_dim, bt_min, bt_max);
++              if (rc != 0)
++                      goto failed;
++              resources_init = 1;
++      }
++
++      /* Allocate memory for the new adapter-structure. */
++      lnic = kmalloc(sizeof(*lnic), GFP_KERNEL);
++      if (lnic == NULL) {
++              EFRM_ERR("%s: ERROR: failed to allocate memory", __FUNCTION__);
++              rc = -ENOMEM;
++              goto failed;
++      }
++      memset(lnic, 0, sizeof(*lnic));
++      nic = &lnic->nic;
++
++      lnic->ev_handlers = &ev_handler;
++
++      /* OS specific hardware mappings */
++      rc = linux_efrm_nic_ctor(lnic, dev, reg_lock, flags, nic_options);
++      if (rc < 0) {
++              EFRM_ERR("%s: ERROR: initialisation failed", __FUNCTION__);
++              goto failed;
++      }
++
++      constructed = 1;
++
++      /* Tell the driver about the NIC - this needs to be done before the
++         resources managers get created below. Note we haven't initialised
++         the hardware yet, and I don't like doing this before the perhaps
++         unreliable hardware initialisation. However, there's quite a lot
++         of code to review if we wanted to hardware init before bringing
++         up the resource managers. */
++      rc = efrm_driver_register_nic(nic, nic_index++);
++      if (rc < 0) {
++              EFRM_ERR("%s: cannot register nic %d with nic error code %d",
++                       __FUNCTION__, efrm_nic_table.nic_count, rc);
++              goto failed;
++      }
++      registered_nic = 1;
++
++      rc = efrm_nic_buffer_table_alloc(nic);
++      if (rc < 0)
++              goto failed;
++      buffers_allocated = 1;
++
++      /****************************************************/
++      /* hardware bringup                                 */
++      /****************************************************/
++      /* Detecting hardware can be a slightly unreliable process;
++         we want to make sure that we maximise our chances, so we
++         loop a few times until all is good. */
++      for (count = 0; count < max_hardware_init_repeats; count++) {
++              rc = efhw_nic_init_hardware(nic, &ev_handler, mac_addr);
++              if (rc >= 0)
++                      break;
++
++              /* pain */
++              EFRM_ERR
++                  ("error - hardware initialisation failed code %d, "
++                   "attempt %d of %d", rc, count + 1,
++                   max_hardware_init_repeats);
++      }
++      if (rc < 0)
++              goto failed;
++
++      tasklet_init(&lnic->tasklet, efrm_tasklet, (ulong)nic);
++
++      /* set up interrupt handlers (hard-irq) */
++      nic->irq_handler = &efrm_handle_eventq_irq;
++
++      /* this device can now take management interrupts */
++      if (do_irq && !(nic->flags & NIC_FLAG_NO_INTERRUPT)) {
++              rc = linux_efrm_irq_ctor(lnic);
++              if (rc < 0) {
++                      EFRM_ERR("Interrupt initialisation failed (%d)", rc);
++                      goto failed;
++              }
++              efhw_nic_set_interrupt_moderation(nic, 0, irq_moderation);
++              efhw_nic_interrupt_enable(nic, 0);
++      }
++      EFRM_TRACE("interrupts are %sregistered", do_irq ? "" : "not ");
++
++#if EFRM_HAVE_IOMMU_LOCK
++      /* Bug 4560: We need the lock if there is memory which cannot be
++       * accessed by the card and there is an IOMMU to access it.  In that
++       * case, the kernel will use the IOMMU to access the high memory. */
++      if ((dev->dma_mask >> PAGE_SHIFT) < max_pfn && !EFRM_NO_IOMMU)
++              efrm_need_iommu_lock = 1;
++#endif
++
++      *lnic_out = lnic;
++      EFRM_ASSERT(rc == 0);
++      ++n_nics_probed;
++      return 0;
++
++failed:
++      if (buffers_allocated)
++              efrm_nic_buffer_table_free(nic);
++      if (registered_nic)
++              efrm_driver_unregister_nic(nic);
++      if (constructed)
++              linux_efrm_nic_dtor(lnic);
++      kfree(lnic); /* safe in any case */
++      if (resources_init)
++              efrm_resources_fini();
++      return rc;
++}
++
++/****************************************************************************
++ *
++ * efrm_nic_del: Remove the nic from the resource driver structures
++ *
++ ****************************************************************************/
++void efrm_nic_del(struct linux_efhw_nic *lnic)
++{
++      struct efhw_nic *nic = &lnic->nic;
++
++      EFRM_TRACE("%s:", __FUNCTION__);
++      EFRM_ASSERT(nic);
++
++      efrm_driver_unregister_nic(nic);
++
++      /*
++       * Synchronise here with any running ISR.
++       * Remove the OS handler. There should be no IRQs being generated
++       * by our NIC at this point.
++       */
++      if (efhw_nic_have_functional_units(nic)) {
++              efhw_nic_close_interrupts(nic);
++              linux_efrm_irq_dtor(lnic);
++              tasklet_kill(&lnic->tasklet);
++      }
++
++      /* Close down hardware and free resources. */
++      linux_efrm_nic_dtor(lnic);
++      kfree(lnic);
++
++      if (--n_nics_probed == 0)
++              efrm_resources_fini();
++
++      EFRM_TRACE("NIC teardown: Done");
++}
++
++/****************************************************************************
++ *
++ * init_module: register as a PCI driver.
++ *
++ ****************************************************************************/
++static int init_sfc_resource(void)
++{
++      int rc = 0;
++
++      EFRM_TRACE("%s: RESOURCE driver starting", __FUNCTION__);
++
++      rc = efrm_driver_ctor();
++      if (rc < 0) {
++              EFRM_ERR("%s: efrm_driver_ctor: error %d", __FUNCTION__, rc);
++              goto fail_driver_ctor;
++      }
++
++      /* Register the driver so that our 'probe' function is called for
++       * each EtherFabric device in the system.
++       */
++      rc = efrm_driverlink_register();
++      if (rc == -ENODEV)
++              EFRM_ERR("%s: no devices found", __FUNCTION__);
++      if (rc < 0)
++              goto failed_driverlink;
++
++      if (efrm_install_proc_entries() != 0) {
++              /* Do not fail, but print a warning */
++              EFRM_WARN("%s: WARNING: failed to install /proc entries",
++                        __FUNCTION__);
++      }
++
++      return 0;
++
++failed_driverlink:
++      /* No need to release resource managers here since they register
++       * destructors with the driver. */
++      efrm_driver_dtor();
++fail_driver_ctor:
++      EFRM_ASSERT(rc != 0);
++      return rc;
++}
++
++/****************************************************************************
++ *
++ * cleanup_module: module-removal entry-point
++ *
++ ****************************************************************************/
++static void cleanup_sfc_resource(void)
++{
++      efrm_uninstall_proc_entries();
++
++      efrm_driverlink_unregister();
++
++      /* Clean up char-driver specific initialisation.
++         - driver dtor can use both work queue and buffer table entries */
++      efrm_driver_dtor();
++
++      EFRM_TRACE("unloaded");
++}
++
++module_init(init_sfc_resource);
++module_exit(cleanup_sfc_resource);
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/resource_manager.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/resource_manager.c        2008-05-19 00:33:29.445843419 +0300
+@@ -0,0 +1,263 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains generic code for resources and resource managers.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efrm/debug.h>
++#include <ci/efrm/nic_table.h>
++#include <ci/efhw/iopage.h>
++#include <ci/efrm/driver_private.h>
++
++/**********************************************************************
++ * Internal stuff.
++ */
++
++#define EFRM_RM_TABLE_SIZE_INIT 256
++
++static int grow_table(struct efrm_resource_manager *rm, unsigned min_size)
++{
++      irq_flags_t lock_flags;
++      struct efrm_resource **table, **old_table;
++      unsigned new_size;
++
++      EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm);
++
++      spin_lock_irqsave(&rm->rm_lock, lock_flags);
++
++      /* Check whether the size of the table increased whilst the lock was
++       * dropped. */
++      if (min_size <= rm->rm_table_size) {
++              spin_unlock_irqrestore(&rm->rm_lock, lock_flags);
++              return 0;
++      }
++
++      new_size = rm->rm_table_size << 1;
++      if (new_size < min_size)
++              new_size = min_size;
++
++      spin_unlock_irqrestore(&rm->rm_lock, lock_flags);
++      if (in_atomic()) {
++              EFRM_WARN("%s: in_atomic in grow_table()", __FUNCTION__);
++              EFRM_WARN("%s: allocating %u bytes", __FUNCTION__,
++                        (unsigned)(new_size *
++                                   sizeof(struct efrm_resource *)));
++              return -ENOMEM;
++      }
++
++      table =
++          (struct efrm_resource **)vmalloc(new_size *
++                                           sizeof(struct efrm_resource *));
++      spin_lock_irqsave(&rm->rm_lock, lock_flags);
++
++      if (table == 0) {
++              EFRM_ERR("%s: out of memory in grow_table()", __FUNCTION__);
++              EFRM_ERR("%s: allocating %u bytes", __FUNCTION__,
++                       (unsigned)(new_size *
++                                  sizeof(struct efrm_resource *)));
++              spin_unlock_irqrestore(&rm->rm_lock, lock_flags);
++              return -ENOMEM;
++      }
++
++      /* Could have got bigger while we dropped the lock... */
++      if (new_size <= rm->rm_table_size) {
++              spin_unlock_irqrestore(&rm->rm_lock, lock_flags);
++              vfree(table);
++              return 0;
++      }
++
++      memcpy(table, rm->rm_table, rm->rm_table_size * sizeof(*table));
++      memset(table + rm->rm_table_size, 0,
++             sizeof(*table) * (new_size - rm->rm_table_size));
++      /* remember old table so we can free the
++         memory after we drop the lock (bug 1040) */
++      old_table = rm->rm_table;
++      rm->rm_table = table;
++      rm->rm_table_size = new_size;
++      spin_unlock_irqrestore(&rm->rm_lock, lock_flags);
++      vfree(old_table);
++
++      return 0;
++}
++
++/**********************************************************************
++ * struct efrm_resource_manager
++ */
++
++void efrm_resource_manager_dtor(struct efrm_resource_manager *rm)
++{
++      EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm);
++
++      /* call destructor */
++      EFRM_DO_DEBUG(if (rm->rm_resources)
++                    EFRM_ERR("%s: %s leaked %d resources",
++                             __FUNCTION__, rm->rm_name, rm->rm_resources));
++      EFRM_ASSERT(rm->rm_resources == 0);
++
++      rm->rm_dtor(rm);
++
++      /* clear out things built by efrm_resource_manager_ctor */
++      spin_lock_destroy(&rm->rm_lock);
++      vfree(rm->rm_table);
++
++      /* and the free the memory */
++      EFRM_DO_DEBUG(memset(rm, 0, sizeof(*rm)));
++      kfree(rm);
++}
++
++/* Construct a resource manager.  Resource managers are singletons. */
++int
++efrm_resource_manager_ctor(struct efrm_resource_manager *rm,
++                         void (*dtor)(struct efrm_resource_manager *),
++                         const char *name, unsigned type,
++                         int initial_table_size)
++{
++      EFRM_ASSERT(rm);
++      EFRM_ASSERT(dtor);
++
++      rm->rm_name = name;
++      EFRM_DO_DEBUG(rm->rm_type = type);
++      rm->rm_dtor = dtor;
++      spin_lock_init(&rm->rm_lock);
++      rm->rm_resources = 0;
++      rm->rm_resources_hiwat = 0;
++
++      /* if not set then pick a number */
++      rm->rm_table_size = (initial_table_size) ?
++              initial_table_size : EFRM_RM_TABLE_SIZE_INIT;
++
++      rm->rm_table = vmalloc(rm->rm_table_size *
++                             sizeof(struct efrm_resource *));
++
++      if (rm->rm_table == 0) {
++              spin_lock_destroy(&rm->rm_lock);
++              return -ENOMEM;
++      }
++      memset(rm->rm_table, 0, sizeof(*rm->rm_table) * rm->rm_table_size);
++
++      EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm);
++      return 0;
++}
++
++int efrm_resource_manager_insert(struct efrm_resource *rs)
++{
++      irq_flags_t lock_flags;
++      struct efrm_resource_manager *rm;
++      int instance = EFRM_RESOURCE_INSTANCE(rs->rs_handle);
++
++      EFRM_ASSERT(EFRM_RESOURCE_TYPE(rs->rs_handle) < EFRM_RESOURCE_NUM);
++      rm = efrm_rm_table[EFRM_RESOURCE_TYPE(rs->rs_handle)];
++      EFRM_ASSERT(EFRM_RESOURCE_TYPE(rs->rs_handle) == rm->rm_type);
++      EFRM_RESOURCE_ASSERT_VALID(rs, 0);
++
++      /* Put an entry in the resource table. */
++      spin_lock_irqsave(&rm->rm_lock, lock_flags);
++      if ((unsigned)instance >= rm->rm_table_size) {
++              spin_unlock_irqrestore(&rm->rm_lock, lock_flags);
++              if (grow_table(rm, instance + 1) < 0)
++                      return -ENOMEM;
++              spin_lock_irqsave(&rm->rm_lock, lock_flags);
++      }
++      EFRM_ASSERT(rm->rm_table_size > (unsigned)instance);
++      EFRM_ASSERT(rm->rm_table[instance] == NULL);
++      rm->rm_table[instance] = rs;
++      rm->rm_resources++;
++      if (rm->rm_resources > rm->rm_resources_hiwat)
++              rm->rm_resources_hiwat = rm->rm_resources;
++
++      /* Put the resource in the linked list. */
++      /* ?? broken list_add(&rm->rm_resources, &rs->rs_link); */
++      /* DJR wrote that it causes problem on driver unload, and DR tried
++       * it and saw (probably) this cause an assertion failure due to a
++       * bad link structure in
++       * /runbench/results/2005/09/22/0_DupTester_15-16-46 */
++
++      spin_unlock_irqrestore(&rm->rm_lock, lock_flags);
++
++      return 0;
++}
++
++bool __efrm_resource_ref_count_zero(unsigned type, unsigned instance)
++{
++      /* This is rather nasty because when a resource's ref count goes to
++       * zero there is still a pointer to it in the [rm_table].  Thus
++       * arriving here does not guarantee that we have exclusive access
++       * to the resource and can free it.  In fact the resource may
++       * already have been freed by another thread (after we dropped our
++       * ref, but before arriving here).
++       *
++       * At this point the only pointers to this resource should be [rs]
++       * and the one in [rm_table].  EXCEPT: Someone could have got in
++       * and looked-up the resource in the table before we got the lock.
++       * In this case the ref will have been hiked again.
++       *
++       * Therefore, if ref count is non-zero here, we shouldn't do
++       * anything, as someone else holds a ref to the resource, and will
++       * eventually release it.
++       *
++       * Otherwise, we zero-out the table entry.  Therefore we have the
++       * only pointer to the resource, and can kill it safely.
++       */
++      struct efrm_resource_manager *rm = efrm_rm_table[type];
++      irq_flags_t lock_flags;
++      struct efrm_resource *rs;
++      bool do_free = false;
++
++      EFRM_TRACE("efrm_resource_ref_count_zero: type=%d instance=%d",
++                 rm->rm_type, instance);
++
++      EFRM_RESOURCE_MANAGER_ASSERT_VALID(rm);
++      EFRM_ASSERT(rm->rm_table_size > instance);
++
++      spin_lock_irqsave(&rm->rm_lock, lock_flags);
++
++      rs = rm->rm_table[instance];
++      if (rs != NULL) {
++              do_free = atomic_read(&rs->rs_ref_count) == 0;
++              if (do_free) {
++                      EFRM_ASSERT(rm->rm_resources > 0);
++                      --rm->rm_resources;
++                      rm->rm_table[instance] = 0;
++              }
++      }
++
++      spin_unlock_irqrestore(&rm->rm_lock, lock_flags);
++
++      return do_free;
++}
++EXPORT_SYMBOL(__efrm_resource_ref_count_zero);
++
++/*
++ * vi: sw=8:ai:aw
++ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/resources.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/resources.c       2008-05-19 00:33:29.445843419 +0300
+@@ -0,0 +1,94 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains resource managers initialisation functions.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efrm/private.h>
++#include <ci/efrm/buffer_table.h>
++
++int
++efrm_resources_init(const struct vi_resource_dimensions *vi_res_dim,
++                  int buffer_table_min, int buffer_table_max)
++{
++      int i, rc;
++
++      rc = efrm_buffer_table_ctor(buffer_table_min, buffer_table_max);
++      if (rc != 0)
++              return rc;
++
++      /* Create resources in the correct order */
++      for (i = 0; i < EFRM_RESOURCE_NUM; ++i) {
++              struct efrm_resource_manager **rmp = &efrm_rm_table[i];
++
++              EFRM_ASSERT(*rmp == NULL);
++              switch (i) {
++              case EFRM_RESOURCE_VI:
++                      rc = efrm_create_vi_resource_manager(rmp,
++                                                           vi_res_dim);
++                      break;
++              case EFRM_RESOURCE_FILTER:
++                      rc = efrm_create_filter_resource_manager(rmp);
++                      break;
++              case EFRM_RESOURCE_IOBUFSET:
++                      rc = efrm_create_iobufset_resource_manager(rmp);
++                      break;
++              default:
++                      rc = 0;
++                      break;
++              }
++
++              if (rc < 0) {
++                      EFRM_ERR("%s: failed type=%d (%d)",
++                               __FUNCTION__, i, rc);
++                      efrm_buffer_table_dtor();
++                      return rc;
++              }
++      }
++
++      return 0;
++}
++
++void efrm_resources_fini(void)
++{
++      int i;
++
++      for (i = EFRM_RESOURCE_NUM - 1; i >= 0; --i)
++              if (efrm_rm_table[i]) {
++                      efrm_resource_manager_dtor(efrm_rm_table[i]);
++                      efrm_rm_table[i] = NULL;
++              }
++
++      efrm_buffer_table_dtor();
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/vi_resource_alloc.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/vi_resource_alloc.c       2008-05-19 00:33:29.445843419 +0300
+@@ -0,0 +1,876 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains allocation of VI resources.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efrm/nic_table.h>
++#include <ci/efhw/iopage.h>
++#include <ci/driver/efab/hardware.h>
++#include <ci/efhw/public.h>
++#include <ci/efhw/falcon.h>
++#include <ci/efrm/private.h>
++#include <ci/efrm/buffer_table.h>
++#include <ci/efrm/vi_resource_private.h>
++
++/*** Data definitions ****************************************************/
++
++static const char *dmaq_names[] = { "TX", "RX" };
++
++struct vi_resource_manager *efrm_vi_manager;
++
++/*** Forward references **************************************************/
++
++static int
++efrm_vi_resource_alloc_or_free(int alloc, struct vi_resource *evq_virs,
++                             uint16_t vi_flags, int32_t evq_capacity,
++                             int32_t txq_capacity, int32_t rxq_capacity,
++                             uint8_t tx_q_tag, uint8_t rx_q_tag,
++                             struct vi_resource **virs_in_out);
++
++/*** Reference count handling ********************************************/
++
++static inline void efrm_vi_rm_get_ref(struct vi_resource *virs)
++{
++      atomic_inc(&virs->evq_refs);
++}
++
++static inline void efrm_vi_rm_drop_ref(struct vi_resource *virs)
++{
++      EFRM_ASSERT(atomic_read(&virs->evq_refs) != 0);
++      if (atomic_dec_and_test(&virs->evq_refs))
++              efrm_vi_resource_alloc_or_free(false, NULL, 0, 0, 0, 0, 0, 0,
++                                             &virs);
++}
++
++/*** Instance numbers ****************************************************/
++
++static inline int efrm_vi_rm_alloc_id(uint16_t vi_flags, int32_t evq_capacity)
++{
++      irq_flags_t lock_flags;
++      int instance;
++      int rc;
++
++      if (efrm_nic_table.a_nic == NULL)       /* ?? FIXME: surely not right */
++              return -ENODEV;
++
++      spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
++
++      /* Falcon A1 RX phys addr wierdness. */
++      if (efrm_nic_table.a_nic->devtype.variant == 'A' &&
++          (vi_flags & EFHW_VI_RX_PHYS_ADDR_EN)) {
++              if (vi_flags & EFHW_VI_JUMBO_EN) {
++                      /* Falcon-A cannot do phys + scatter. */
++                      EFRM_WARN
++                          ("%s: falcon-A does not support phys+scatter mode",
++                           __FUNCTION__);
++                      instance = -1;
++              } else if (efrm_vi_manager->iscsi_dmaq_instance_is_free
++                         && evq_capacity == 0) {
++                      /* Falcon-A has a single RXQ that gives the correct
++                       * semantics for physical addressing.  However, it
++                       * happens to have the same instance number as the
++                       * 'char' event queue, so we cannot also hand out
++                       * the event queue. */
++                      efrm_vi_manager->iscsi_dmaq_instance_is_free = false;
++                      instance = FALCON_A1_ISCSI_DMAQ;
++              } else {
++                      EFRM_WARN("%s: iSCSI receive queue not free",
++                                __FUNCTION__);
++                      instance = -1;
++              }
++              goto unlock_out;
++      }
++
++      if (vi_flags & EFHW_VI_RM_WITH_INTERRUPT) {
++              rc = __kfifo_get(efrm_vi_manager->instances_with_interrupt,
++                               (unsigned char *)&instance, sizeof(instance));
++              if (rc != sizeof(instance)) {
++                      EFRM_ASSERT(rc == 0);
++                      instance = -1;
++              }
++              goto unlock_out;
++      }
++
++      /* Otherwise a normal run-of-the-mill VI. */
++      rc = __kfifo_get(efrm_vi_manager->instances_with_timer,
++                       (unsigned char *)&instance, sizeof(instance));
++      if (rc != sizeof(instance)) {
++              EFRM_ASSERT(rc == 0);
++              instance = -1;
++      }
++
++unlock_out:
++      spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
++      return instance;
++}
++
++static void efrm_vi_rm_free_id(int instance)
++{
++      irq_flags_t lock_flags;
++      struct kfifo *instances;
++
++      if (efrm_nic_table.a_nic == NULL)       /* ?? FIXME: surely not right */
++              return;
++
++      if (efrm_nic_table.a_nic->devtype.variant == 'A' &&
++          instance == FALCON_A1_ISCSI_DMAQ) {
++              EFRM_ASSERT(efrm_vi_manager->iscsi_dmaq_instance_is_free ==
++                          false);
++              spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
++              efrm_vi_manager->iscsi_dmaq_instance_is_free = true;
++              spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock,
++                                     lock_flags);
++      } else {
++              if (instance >= efrm_vi_manager->with_timer_base &&
++                  instance < efrm_vi_manager->with_timer_limit) {
++                      instances = efrm_vi_manager->instances_with_timer;
++              } else {
++                      EFRM_ASSERT(instance >=
++                                  efrm_vi_manager->with_interrupt_base);
++                      EFRM_ASSERT(instance <
++                                  efrm_vi_manager->with_interrupt_limit);
++                      instances = efrm_vi_manager->instances_with_interrupt;
++              }
++
++              EFRM_VERIFY_EQ(kfifo_put(instances, (unsigned char *)&instance,
++                                       sizeof(instance)), sizeof(instance));
++      }
++}
++
++/*** Queue sizes *********************************************************/
++
++/* NB. This should really take a nic as an argument, but that makes
++ * the buffer table allocation difficult. */
++uint32_t efrm_vi_rm_evq_bytes(struct vi_resource *virs
++                            /*,struct efhw_nic *nic */ )
++{
++      return virs->evq_capacity * sizeof(efhw_event_t);
++}
++EXPORT_SYMBOL(efrm_vi_rm_evq_bytes);
++
++/* NB. This should really take a nic as an argument, but that makes
++ * the buffer table allocation difficult. */
++uint32_t efrm_vi_rm_txq_bytes(struct vi_resource *virs
++                            /*,struct efhw_nic *nic */ )
++{
++      return virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] *
++          FALCON_DMA_TX_DESC_BYTES;
++}
++EXPORT_SYMBOL(efrm_vi_rm_txq_bytes);
++
++/* NB. This should really take a nic as an argument, but that makes
++ * the buffer table allocation difficult. */
++uint32_t efrm_vi_rm_rxq_bytes(struct vi_resource *virs
++                            /*,struct efhw_nic *nic */ )
++{
++      uint32_t bytes_per_desc = ((virs->flags & EFHW_VI_RX_PHYS_ADDR_EN)
++                                 ? FALCON_DMA_RX_PHYS_DESC_BYTES
++                                 : FALCON_DMA_RX_BUF_DESC_BYTES);
++      return virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] * bytes_per_desc;
++}
++EXPORT_SYMBOL(efrm_vi_rm_rxq_bytes);
++
++static int choose_size(int size_rq, unsigned sizes)
++{
++      int size;
++
++      /* size_rq < 0 means default, but we interpret this as 'minimum'. */
++
++      for (size = 256;; size <<= 1)
++              if ((sizes & ~((size - 1) | size)) == 0)
++                      return -1;
++              else if ((size & sizes) && size >= size_rq)
++                      return size;
++}
++
++static int
++efrm_vi_rm_adjust_alloc_request(struct vi_resource *virs, struct efhw_nic *nic)
++{
++      int capacity;
++
++      EFRM_ASSERT(nic->efhw_func);
++
++      if (virs->evq_capacity) {
++              capacity = choose_size(virs->evq_capacity, nic->evq_sizes);
++              if (capacity < 0) {
++                      EFRM_ERR("vi_resource: bad evq size %d (supported=%x)",
++                               virs->evq_capacity, nic->evq_sizes);
++                      return -E2BIG;
++              }
++              virs->evq_capacity = capacity;
++      }
++      if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX]) {
++              capacity =
++                  choose_size(virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX],
++                              nic->txq_sizes);
++              if (capacity < 0) {
++                      EFRM_ERR("vi_resource: bad txq size %d (supported=%x)",
++                               virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX],
++                               nic->txq_sizes);
++                      return -E2BIG;
++              }
++              virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] = capacity;
++      }
++      if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]) {
++              capacity =
++                  choose_size(virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX],
++                              nic->rxq_sizes);
++              if (capacity < 0) {
++                      EFRM_ERR("vi_resource: bad rxq size %d (supported=%x)",
++                               virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX],
++                               nic->rxq_sizes);
++                      return -E2BIG;
++              }
++              virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] = capacity;
++      }
++
++      return 0;
++}
++
++/* remove the reference to the event queue in this VI resource and decrement
++   the event queue's use count */
++static inline void efrm_vi_rm_detach_evq(struct vi_resource *virs)
++{
++      struct vi_resource *evq_virs;
++
++      EFRM_ASSERT(virs != NULL);
++
++      evq_virs = virs->evq_virs;
++
++      if (evq_virs != NULL) {
++              virs->evq_virs = NULL;
++              if (evq_virs == virs) {
++                      EFRM_TRACE("%s: " EFRM_RESOURCE_FMT
++                                 " had internal event queue ", __FUNCTION__,
++                                 EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
++              } else {
++                      efrm_vi_rm_drop_ref(evq_virs);
++                      EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " had event queue "
++                                 EFRM_RESOURCE_FMT, __FUNCTION__,
++                                 EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle),
++                                 EFRM_RESOURCE_PRI_ARG(evq_virs->rs.
++                                                       rs_handle));
++              }
++      } else {
++              EFRM_TRACE("%s: " EFRM_RESOURCE_FMT
++                         " had no event queue (nothing to do)",
++                         __FUNCTION__,
++                         EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
++      }
++}
++
++/*** Buffer Table allocations ********************************************/
++
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++static int
++efrm_vi_rm_alloc_or_free_buffer_table(struct vi_resource *virs, bool is_alloc)
++{
++      uint32_t bytes;
++      int page_order;
++      int rc;
++
++      if (!is_alloc)
++              goto destroy;
++
++      if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX]) {
++              bytes = efrm_vi_rm_txq_bytes(virs);
++              page_order = get_order(bytes);
++              rc = efrm_buffer_table_alloc(page_order,
++                                           (virs->dmaq_buf_tbl_alloc +
++                                            EFRM_VI_RM_DMA_QUEUE_TX));
++              if (rc != 0) {
++                      EFRM_TRACE
++                          ("%s: Error %d allocating TX buffer table entry",
++                           __FUNCTION__, rc);
++                      goto fail_txq_alloc;
++              }
++      }
++
++      if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]) {
++              bytes = efrm_vi_rm_rxq_bytes(virs);
++              page_order = get_order(bytes);
++              rc = efrm_buffer_table_alloc(page_order,
++                                           (virs->dmaq_buf_tbl_alloc +
++                                            EFRM_VI_RM_DMA_QUEUE_RX));
++              if (rc != 0) {
++                      EFRM_TRACE
++                          ("%s: Error %d allocating RX buffer table entry",
++                           __FUNCTION__, rc);
++                      goto fail_rxq_alloc;
++              }
++      }
++      return 0;
++
++destroy:
++      rc = 0;
++
++      if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]) {
++              efrm_buffer_table_free(&virs->
++                                     dmaq_buf_tbl_alloc
++                                     [EFRM_VI_RM_DMA_QUEUE_RX]);
++      }
++fail_rxq_alloc:
++
++      if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX]) {
++              efrm_buffer_table_free(&virs->
++                                     dmaq_buf_tbl_alloc
++                                     [EFRM_VI_RM_DMA_QUEUE_TX]);
++      }
++fail_txq_alloc:
++
++      return rc;
++}
++
++#endif /* defined(__CI_HARDWARE_CONFIG_FALCON__) */
++
++/*** Per-NIC allocations *************************************************/
++
++static inline int
++efrm_vi_rm_init_evq(struct vi_resource *virs, int nic_index)
++{
++      int rc;
++      struct efhw_nic *nic = efrm_nic_table.nic[nic_index];
++      int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++      struct eventq_resource_hardware *evq_hw =
++          &virs->nic_info[nic_index].evq_pages;
++      uint32_t buf_bytes = efrm_vi_rm_evq_bytes(virs);
++
++      if (virs->evq_capacity == 0)
++              return 0;
++      evq_hw->capacity = virs->evq_capacity;
++
++      /* Allocate buffer table entries to map onto the iobuffer.  This
++       * currently allocates its own buffer table entries on Falcon which is
++       * a bit wasteful on a multi-NIC system. */
++      evq_hw->buf_tbl_alloc.base = (unsigned)-1;
++      rc = efrm_buffer_table_alloc(get_order(buf_bytes),
++                                   &evq_hw->buf_tbl_alloc);
++      if (rc < 0) {
++              EFHW_WARN("%s: failed (%d) to alloc %d buffer table entries",
++                        __FUNCTION__, rc, get_order(buf_bytes));
++              return rc;
++      }
++
++      /* Allocate the event queue memory. */
++      rc = efhw_nic_event_queue_alloc_iobuffer(nic, evq_hw, instance,
++                                               buf_bytes);
++      if (rc != 0) {
++              EFRM_ERR("%s: Error allocating iobuffer: %d", __FUNCTION__, rc);
++              efrm_buffer_table_free(&evq_hw->buf_tbl_alloc);
++              return rc;
++      }
++
++      /* Initialise the event queue hardware */
++      efhw_nic_event_queue_enable(nic, instance, virs->evq_capacity,
++                                  efhw_iopages_dma_addr(&evq_hw->iobuff) +
++                                  evq_hw->iobuff_off,
++                                  evq_hw->buf_tbl_alloc.base);
++
++      EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " capacity=%u", __FUNCTION__,
++                 EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle),
++                 virs->evq_capacity);
++
++#if defined(__ia64__)
++      /* Page size may be large, so for now just increase the
++       * size of the requested evq up to a round number of
++       * pages
++       */
++      buf_bytes = CI_ROUND_UP(buf_bytes, PAGE_SIZE);
++#endif
++      EFRM_ASSERT(buf_bytes % PAGE_SIZE == 0);
++
++      virs->mem_mmap_bytes += buf_bytes;
++
++      return 0;
++}
++
++static inline void
++efrm_vi_rm_fini_evq(struct vi_resource *virs, int nic_index)
++{
++      struct efhw_nic *nic = efrm_nic_table.nic[nic_index];
++      int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++      struct vi_resource_nic_info *nic_info = &virs->nic_info[nic_index];
++
++      if (virs->evq_capacity == 0)
++              return;
++
++      /* Zero the timer-value for this queue.
++         And Tell NIC to stop using this event queue. */
++      efhw_nic_event_queue_disable(nic, instance, 0);
++
++      if (nic_info->evq_pages.buf_tbl_alloc.base != (unsigned)-1)
++              efrm_buffer_table_free(&nic_info->evq_pages.buf_tbl_alloc);
++
++      efhw_iopages_free(nic, &nic_info->evq_pages.iobuff);
++}
++
++/*! FIXME: we should make sure this number is never zero (=> unprotected) */
++/*! FIXME: put this definition in a relevant header (e.g. as (evqid)+1) */
++#define EFAB_EVQ_OWNER_ID(evqid) ((evqid))
++
++void
++efrm_vi_rm_init_dmaq(struct vi_resource *virs, int queue_type,
++                   struct efhw_nic *nic)
++{
++      int instance;
++      struct vi_resource *evq_virs;
++      int evq_instance;
++      efhw_buffer_addr_t buf_addr;
++
++      instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++      evq_virs = virs->evq_virs;
++      evq_instance = EFRM_RESOURCE_INSTANCE(evq_virs->rs.rs_handle);
++
++      buf_addr = virs->dmaq_buf_tbl_alloc[queue_type].base;
++
++      if (queue_type == EFRM_VI_RM_DMA_QUEUE_TX) {
++              efhw_nic_dmaq_tx_q_init(nic,
++                      instance,       /* dmaq */
++                      evq_instance,   /* evq */
++                      EFAB_EVQ_OWNER_ID(evq_instance),        /* owner */
++                      virs->dmaq_tag[queue_type],     /* tag */
++                      virs->dmaq_capacity[queue_type], /* size of queue */
++                      buf_addr,       /* buffer index */
++                      virs->flags);   /* user specified Q attrs */
++      } else {
++              efhw_nic_dmaq_rx_q_init(nic,
++                      instance,       /* dmaq */
++                      evq_instance,   /* evq */
++                      EFAB_EVQ_OWNER_ID(evq_instance),        /* owner */
++                      virs->dmaq_tag[queue_type],     /* tag */
++                      virs->dmaq_capacity[queue_type], /* size of queue */
++                      buf_addr,       /* buffer index */
++                      virs->flags);   /* user specified Q attrs */
++      }
++}
++
++static int
++efrm_vi_rm_init_or_fini_dmaq(struct vi_resource *virs,
++                           int queue_type, int init, int nic_index)
++{
++      int rc;
++      struct efhw_nic *nic = efrm_nic_table.nic[nic_index];
++      int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++      uint32_t buf_bytes;
++      struct vi_resource *evq_virs;
++
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++      struct vi_resource_nic_info *nic_info = &virs->nic_info[nic_index];
++      int page_order;
++      uint32_t num_pages;
++      efhw_iopages_t *iobuff;
++#endif
++
++      if (!init)
++              goto destroy;
++
++      /* Ignore disabled queues. */
++      if (virs->dmaq_capacity[queue_type] == 0) {
++              if (queue_type == EFRM_VI_RM_DMA_QUEUE_TX)
++                      efhw_nic_dmaq_tx_q_disable(nic, instance);
++              else
++                      efhw_nic_dmaq_rx_q_disable(nic, instance);
++              return 0;
++      }
++
++      buf_bytes = (queue_type == EFRM_VI_RM_DMA_QUEUE_TX
++                   ? efrm_vi_rm_txq_bytes(virs)
++                   : efrm_vi_rm_rxq_bytes(virs));
++
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++      page_order = get_order(buf_bytes);
++
++      rc = efhw_iopages_alloc(nic, &nic_info->dmaq_pages[queue_type],
++                            page_order);
++      if (rc != 0) {
++              EFRM_ERR("%s: Failed to allocate %s DMA buffer.", __FUNCTION__,
++                       dmaq_names[queue_type]);
++              goto fail_iopages;
++      }
++
++      num_pages = 1 << page_order;
++      iobuff = &nic_info->dmaq_pages[queue_type];
++      efhw_nic_buffer_table_set_n(nic,
++                                  virs->dmaq_buf_tbl_alloc[queue_type].base,
++                                  efhw_iopages_dma_addr(iobuff),
++                                  EFHW_NIC_PAGE_SIZE, 0, num_pages, 0);
++
++      falcon_nic_buffer_table_confirm(nic);
++
++      virs->mem_mmap_bytes += round_up(buf_bytes, PAGE_SIZE);
++#endif /* __CI_HARDWARE_CONFIG_FALCON__ */
++
++      evq_virs = virs->evq_virs;
++      EFRM_ASSERT(evq_virs);
++
++      /* Make sure there is an event queue. */
++      if (evq_virs->evq_capacity <= 0) {
++              EFRM_ERR("%s: Cannot use empty event queue for %s DMA",
++                       __FUNCTION__, dmaq_names[queue_type]);
++              rc = -EINVAL;
++              goto fail_evq;
++      }
++
++      efrm_vi_rm_init_dmaq(virs, queue_type, nic);
++
++      return 0;
++
++destroy:
++      rc = 0;
++
++      /* Ignore disabled queues. */
++      if (virs->dmaq_capacity[queue_type] == 0)
++              return 0;
++
++      /* No need to disable the queue here.  Nobody is using it anyway. */
++
++fail_evq:
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++      efhw_iopages_free(nic, &nic_info->dmaq_pages[queue_type]);
++fail_iopages:
++#endif
++
++      return rc;
++}
++
++static int
++efrm_vi_rm_init_or_fini_nic(struct vi_resource *virs, int init, int nic_index)
++{
++      struct vi_resource *evq_virs;
++      int rc;
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++#ifndef NDEBUG
++      int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++#endif
++#endif
++
++      if (!init)
++              goto destroy;
++
++      evq_virs = virs->evq_virs;
++      if (evq_virs != virs) {
++              if (!efrm_nic_set_read(&evq_virs->nic_set, nic_index)) {
++                      /* Ignore this NIC.  It's not supported by the event
++                       * queue. */
++                      return 0;
++              }
++      }
++
++      rc = efrm_vi_rm_init_evq(virs, nic_index);
++      if (rc != 0)
++              goto fail_evq;
++
++      rc = efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_TX,
++                                        init, nic_index);
++      if (rc != 0)
++              goto fail_txq;
++
++      rc = efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_RX,
++                                        init, nic_index);
++      if (rc != 0)
++              goto fail_rxq;
++
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++      /* Allocate space for the control page. */
++      EFRM_ASSERT(falcon_tx_dma_page_offset(instance) < PAGE_SIZE);
++      EFRM_ASSERT(falcon_rx_dma_page_offset(instance) < PAGE_SIZE);
++      EFRM_ASSERT(falcon_timer_page_offset(instance) < PAGE_SIZE);
++      virs->bar_mmap_bytes += PAGE_SIZE;
++#endif
++
++      /* Mark the NIC as having been initialised. */
++      efrm_nic_set_write(&virs->nic_set, nic_index, true);
++
++      return 0;
++
++destroy:
++      rc = 0;
++
++      efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_RX,
++                                   false, nic_index);
++fail_rxq:
++
++      efrm_vi_rm_init_or_fini_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_TX,
++                                   false, nic_index);
++fail_txq:
++
++      efrm_vi_rm_fini_evq(virs, nic_index);
++fail_evq:
++
++      /* Mark the NIC as having been finalised. */
++      efrm_nic_set_write(&virs->nic_set, nic_index, false);
++      EFRM_ASSERT(rc != 0 || !init);
++
++      return rc;
++}
++
++static int
++efrm_vi_resource_alloc_or_free(int alloc, struct vi_resource *evq_virs,
++                             uint16_t vi_flags, int32_t evq_capacity,
++                             int32_t txq_capacity, int32_t rxq_capacity,
++                             uint8_t tx_q_tag, uint8_t rx_q_tag,
++                             struct vi_resource **virs_in_out)
++{
++      struct vi_resource *virs;
++      int rc;
++      int instance;
++      struct efhw_nic *nic;
++      int nic_i;
++
++      EFRM_ASSERT(virs_in_out);
++      EFRM_ASSERT(efrm_vi_manager);
++      EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_vi_manager->rm);
++
++      if (!alloc)
++              goto destroy;
++
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++      rx_q_tag &= (1 << TX_DESCQ_LABEL_WIDTH) - 1;
++      tx_q_tag &= (1 << RX_DESCQ_LABEL_WIDTH) - 1;
++#endif
++
++      virs = kmalloc(sizeof(*virs), GFP_KERNEL);
++      if (virs == NULL) {
++              EFRM_ERR("%s: Error allocating VI resource object",
++                       __FUNCTION__);
++              rc = -ENOMEM;
++              goto fail_alloc;
++      }
++      memset(virs, 0, sizeof(*virs));
++
++      /* Some macros make the assumption that the struct efrm_resource is
++       * the first member of a struct vi_resource. */
++      EFRM_ASSERT(&virs->rs == (struct efrm_resource *) (virs));
++
++      instance = efrm_vi_rm_alloc_id(vi_flags, evq_capacity);
++      if (instance < 0) {
++              /* Clear out the close list... */
++              efrm_vi_rm_salvage_flushed_vis();
++              instance = efrm_vi_rm_alloc_id(vi_flags, evq_capacity);
++              if (instance >= 0)
++                      EFRM_TRACE("%s: Salvaged a closed VI.", __FUNCTION__);
++      }
++
++      if (instance < 0) {
++              /* Could flush resources and try again here. */
++              EFRM_ERR("%s: Out of appropriate VI resources", __FUNCTION__);
++              rc = -EBUSY;
++              goto fail_alloc_id;
++      }
++
++      EFRM_TRACE("%s: new VI ID %d", __FUNCTION__, instance);
++      efrm_resource_init(&virs->rs, EFRM_RESOURCE_VI, instance);
++
++      /* Start with one reference.  Any external VIs using the EVQ of this
++       * resource will increment this reference rather than the resource
++       * reference to avoid DMAQ flushes from waiting for other DMAQ
++       * flushes to complete.  When the resource reference goes to zero,
++       * the DMAQ flush happens.  When the flush completes, this reference
++       * is decremented.  When this reference reaches zero, the instance
++       * is freed. */
++      atomic_set(&virs->evq_refs, 1);
++
++      efrm_nic_set_clear(&virs->nic_set);
++
++      virs->bar_mmap_bytes = 0;
++      virs->mem_mmap_bytes = 0;
++      virs->evq_capacity = evq_capacity;
++      virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] = txq_capacity;
++      virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] = rxq_capacity;
++      virs->dmaq_tag[EFRM_VI_RM_DMA_QUEUE_TX] = tx_q_tag;
++      virs->dmaq_tag[EFRM_VI_RM_DMA_QUEUE_RX] = rx_q_tag;
++      virs->flags = vi_flags;
++
++      INIT_LIST_HEAD(&virs->tx_flush_link);
++      INIT_LIST_HEAD(&virs->rx_flush_link);
++      efrm_nic_set_clear(&virs->tx_flush_nic_set);
++      efrm_nic_set_clear(&virs->rx_flush_nic_set);
++
++      memset(&efrm_vi_manager->evq_infos[instance], 0,
++             sizeof(struct vi_resource_evq_info));
++      efrm_vi_manager->evq_infos[instance].evq_virs = virs;
++
++      /* Adjust the queue sizes. */
++      rc = 0;
++      EFRM_FOR_EACH_NIC(nic_i, nic)
++          if (rc == 0)
++              rc = efrm_vi_rm_adjust_alloc_request(virs, nic);
++      if (rc != 0)
++              goto fail_adjust_request;
++
++      /* Attach the EVQ early so that we can ensure that the NIC sets
++       * match. */
++      if (evq_virs == NULL) {
++              evq_virs = virs;
++              EFRM_TRACE("%s: " EFRM_RESOURCE_FMT
++                         " has no external event queue", __FUNCTION__,
++                         EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
++      } else {
++              /* Make sure the resource managers are the same. */
++              if (EFRM_RESOURCE_TYPE(evq_virs->rs.rs_handle) !=
++                  EFRM_RESOURCE_VI) {
++                      EFRM_ERR("%s: Mismatched owner for event queue VI "
++                               EFRM_RESOURCE_FMT, __FUNCTION__,
++                               EFRM_RESOURCE_PRI_ARG(evq_virs->rs.rs_handle));
++                      return -EINVAL;
++              }
++              EFRM_ASSERT(atomic_read(&evq_virs->evq_refs) != 0);
++              efrm_vi_rm_get_ref(evq_virs);
++              EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " uses event queue "
++                         EFRM_RESOURCE_FMT,
++                         __FUNCTION__,
++                         EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle),
++                         EFRM_RESOURCE_PRI_ARG(evq_virs->rs.rs_handle));
++      }
++      virs->evq_virs = evq_virs;
++
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++      rc = efrm_vi_rm_alloc_or_free_buffer_table(virs, true);
++      if (rc != 0)
++              goto fail_buffer_table;
++#endif
++
++      rc = 0;
++      EFRM_FOR_EACH_NIC(nic_i, nic)
++          if (rc == 0)
++              /* This updates virs->nic_set for the NICs which need
++               * finalising. */
++              rc = efrm_vi_rm_init_or_fini_nic(virs, true, nic_i);
++      if (rc != 0)
++              goto fail_init_nic;
++
++      /* Put it into the resource manager's table. */
++      rc = efrm_resource_manager_insert(&virs->rs);
++      if (rc != 0) {
++              if (atomic_dec_and_test(&virs->rs.rs_ref_count))
++                      efrm_vi_resource_free(virs);
++              return rc;
++      }
++
++      *virs_in_out = virs;
++      EFRM_TRACE("%s: Allocated " EFRM_RESOURCE_FMT, __FUNCTION__,
++                 EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
++      return 0;
++
++destroy:
++      virs = *virs_in_out;
++      EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 1);
++      instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++
++      EFRM_TRACE("%s: Freeing %d", __FUNCTION__,
++                 EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle));
++
++      /* Destroying the VI.  The reference count must be zero. */
++      EFRM_ASSERT(atomic_read(&virs->evq_refs) == 0);
++
++      /* The EVQ should have gone (and DMA disabled) so that this
++       * function can't be re-entered to destroy the EVQ VI. */
++      EFRM_ASSERT(virs->evq_virs == NULL);
++      rc = 0;
++
++fail_init_nic:
++      EFRM_FOR_EACH_NIC_IN_SET(&virs->nic_set, nic_i, nic)
++          efrm_vi_rm_init_or_fini_nic(virs, false, nic_i);
++
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++      efrm_vi_rm_alloc_or_free_buffer_table(virs, false);
++fail_buffer_table:
++#endif
++
++      efrm_vi_rm_detach_evq(virs);
++
++fail_adjust_request:
++
++      EFRM_ASSERT(virs->evq_callback_fn == NULL);
++      memset(&efrm_vi_manager->evq_infos[instance], 0,
++             sizeof(struct vi_resource_evq_info));
++      EFRM_TRACE("%s: delete VI ID %d", __FUNCTION__, instance);
++      efrm_vi_rm_free_id(instance);
++fail_alloc_id:
++
++      EFRM_DO_DEBUG(memset(virs, 0, sizeof(*virs)));
++      kfree(virs);
++fail_alloc:
++      *virs_in_out = NULL;
++
++      return rc;
++}
++
++/*** Resource object  ****************************************************/
++
++int
++efrm_vi_resource_alloc(struct vi_resource *evq_virs,
++                     uint16_t vi_flags, int32_t evq_capacity,
++                     int32_t txq_capacity, int32_t rxq_capacity,
++                     uint8_t tx_q_tag, uint8_t rx_q_tag,
++                     struct vi_resource **virs_out,
++                     uint32_t *out_io_mmap_bytes,
++                     uint32_t *out_mem_mmap_bytes,
++                     uint32_t *out_txq_capacity, uint32_t *out_rxq_capacity)
++{
++      int rc;
++      rc = efrm_vi_resource_alloc_or_free(true, evq_virs, vi_flags,
++                                          evq_capacity, txq_capacity,
++                                          rxq_capacity, tx_q_tag, rx_q_tag,
++                                          virs_out);
++      if (rc == 0) {
++              if (out_io_mmap_bytes != NULL)
++                      *out_io_mmap_bytes = (*virs_out)->bar_mmap_bytes;
++              if (out_mem_mmap_bytes != NULL)
++                      *out_mem_mmap_bytes = (*virs_out)->mem_mmap_bytes;
++              if (out_txq_capacity != NULL)
++                      *out_txq_capacity =
++                          (*virs_out)->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX];
++              if (out_rxq_capacity != NULL)
++                      *out_rxq_capacity =
++                          (*virs_out)->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX];
++      }
++
++      return rc;
++}
++EXPORT_SYMBOL(efrm_vi_resource_alloc);
++
++void efrm_vi_rm_free_flushed_resource(struct vi_resource *virs)
++{
++      EFRM_ASSERT(virs != NULL);
++      EFRM_ASSERT(atomic_read(&virs->rs.rs_ref_count) == 0);
++
++      EFRM_TRACE("%s: " EFRM_RESOURCE_FMT, __FUNCTION__,
++                 EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
++      /* release the associated event queue then drop our own reference
++       * count */
++      efrm_vi_rm_detach_evq(virs);
++      efrm_vi_rm_drop_ref(virs);
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/vi_resource_event.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/vi_resource_event.c       2008-05-19 00:33:29.445843419 +0300
+@@ -0,0 +1,232 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains event handling for VI resource.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efrm/nic_table.h>
++#include <ci/driver/efab/hardware.h>
++#include <ci/efhw/eventq.h>
++#include <ci/efrm/private.h>
++#include <ci/efrm/vi_resource_private.h>
++
++void
++efrm_eventq_request_wakeup(struct vi_resource *virs, unsigned current_ptr,
++                         unsigned nic_index)
++{
++      struct efhw_nic *nic;
++      int next_i;
++      EFRM_ASSERT(efrm_nic_set_read(&virs->nic_set, nic_index));
++      nic = efrm_nic_table.nic[nic_index];
++      EFRM_ASSERT(nic);
++      next_i = ((current_ptr / sizeof(efhw_event_t)) &
++                (virs->evq_capacity - 1));
++
++      efhw_nic_wakeup_request(nic, efrm_eventq_dma_addr(virs, nic_index),
++                              next_i,
++                              EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle));
++}
++EXPORT_SYMBOL(efrm_eventq_request_wakeup);
++
++void efrm_eventq_reset(struct vi_resource *virs, int nic_index)
++{
++      struct efhw_nic *nic = efrm_nic_table.nic[nic_index];
++      int instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++
++      EFRM_ASSERT(virs->evq_capacity != 0);
++      EFRM_ASSERT(efrm_nic_set_read(&virs->nic_set, nic_index));
++
++      /* FIXME: Protect against concurrent resets. */
++
++      efhw_nic_event_queue_disable(nic, instance, 0);
++
++      memset(efrm_eventq_base(virs, nic_index), EFHW_CLEAR_EVENT_VALUE,
++             efrm_eventq_bytes(virs, nic_index));
++      efhw_nic_event_queue_enable(nic, instance, virs->evq_capacity,
++                                  efrm_eventq_dma_addr(virs, nic_index),
++                                  virs->nic_info[nic_index].evq_pages.
++                                  buf_tbl_alloc.base);
++      EFRM_TRACE("%s: " EFRM_RESOURCE_FMT, __FUNCTION__,
++                 EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle));
++}
++EXPORT_SYMBOL(efrm_eventq_reset);
++
++int
++efrm_eventq_register_callback(struct vi_resource *virs,
++                            void (*handler) (void *, int,
++                                             struct efhw_nic *nic),
++                            void *arg)
++{
++      int instance;
++      int bit;
++
++      EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 0);
++      EFRM_ASSERT(virs->evq_capacity != 0);
++
++      instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++
++      /* The handler can be set only once. */
++      bit = test_and_set_bit(VI_RESOURCE_EVQ_STATE_CALLBACK_REGISTERED,
++                             &efrm_vi_manager->evq_infos[instance].evq_state);
++      if (bit)
++              return -EBUSY;
++
++      /* Store the details. The order is important here. */
++      virs->evq_callback_arg = arg;
++      virs->evq_callback_fn = handler;
++
++      return 0;
++}
++EXPORT_SYMBOL(efrm_eventq_register_callback);
++
++void efrm_eventq_kill_callback(struct vi_resource *virs)
++{
++      int nic_i, instance;
++      struct efhw_nic *nic;
++      struct vi_resource_evq_info *evq_info;
++      int32_t evq_state;
++      int bit;
++
++      EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 0);
++      EFRM_ASSERT(virs->evq_capacity != 0);
++
++      /* Clean out the callback so a new one can be installed. */
++      virs->evq_callback_fn = NULL;
++
++      instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++      evq_info = &efrm_vi_manager->evq_infos[instance];
++
++      /* Disable the event queue. */
++      EFRM_FOR_EACH_NIC_IN_SET(&virs->nic_set, nic_i, nic)
++          efhw_nic_event_queue_disable(nic, instance, /*timer_only */ 1);
++
++      /* Disable the callback. */
++      bit = test_and_clear_bit(VI_RESOURCE_EVQ_STATE_CALLBACK_REGISTERED,
++                               &evq_info->evq_state);
++      EFRM_ASSERT(bit);       /* do not call me twice! */
++
++      /* Spin until the callback is complete. */
++      do {
++              rmb();
++
++              udelay(1);
++              evq_state = evq_info->evq_state;
++      } while ((evq_state & VI_RESOURCE_EVQ_STATE(BUSY)));
++}
++EXPORT_SYMBOL(efrm_eventq_kill_callback);
++
++static void
++efrm_eventq_do_callback(struct efhw_nic *nic, unsigned instance,
++                      bool is_timeout)
++{
++      void (*handler) (void *, int is_timeout, struct efhw_nic *nic);
++      void *arg;
++      struct vi_resource_evq_info *evq_info;
++      int32_t evq_state;
++      int32_t new_evq_state;
++      struct vi_resource *virs;
++      int bit;
++
++      EFRM_TRACE("%s: q=%d %s", __FUNCTION__, instance,
++                 is_timeout ? "timeout" : "wakeup");
++      EFRM_ASSERT(efrm_vi_manager);
++
++      evq_info = &efrm_vi_manager->evq_infos[instance];
++
++      /* Set the BUSY bit and clear WAKEUP_PENDING.  Do this
++       * before waking up the sleeper to avoid races. */
++      while (1) {
++              evq_state = evq_info->evq_state;
++              new_evq_state = evq_state;
++
++              if ((evq_state & VI_RESOURCE_EVQ_STATE(BUSY)) != 0) {
++                      EFRM_ERR("%s:%d: evq_state[%d] corrupted!",
++                               __FUNCTION__, __LINE__, instance);
++                      return;
++              }
++
++              if (!is_timeout)
++                      new_evq_state &= ~VI_RESOURCE_EVQ_STATE(WAKEUP_PENDING);
++
++              if (evq_state & VI_RESOURCE_EVQ_STATE(CALLBACK_REGISTERED)) {
++                      new_evq_state |= VI_RESOURCE_EVQ_STATE(BUSY);
++                      if (cmpxchg(&evq_info->evq_state, evq_state,
++                                  new_evq_state) == evq_state) {
++                              virs = evq_info->evq_virs;
++                              break;
++                      }
++
++              } else {
++                      /* Just update the state if necessary. */
++                      if (new_evq_state == evq_state ||
++                          cmpxchg(&evq_info->evq_state, evq_state,
++                                  new_evq_state) == evq_state)
++                              return;
++              }
++
++              udelay(1);
++      }
++
++      /* Call the callback if any. */
++      if (evq_state & VI_RESOURCE_EVQ_STATE(CALLBACK_REGISTERED)) {
++              /* Retrieve the callback fn. */
++              handler = virs->evq_callback_fn;
++              arg = virs->evq_callback_arg;
++              if (handler != NULL)    /* avoid races */
++                      handler(arg, is_timeout, nic);
++      }
++
++      /* Clear the BUSY bit. */
++      bit =
++          test_and_clear_bit(VI_RESOURCE_EVQ_STATE_BUSY,
++                             &evq_info->evq_state);
++      if (!bit) {
++              EFRM_ERR("%s:%d: evq_state corrupted!",
++                       __FUNCTION__, __LINE__);
++      }
++}
++
++void efrm_handle_wakeup_event(struct efhw_nic *nic, efhw_event_t *ev)
++{
++      efrm_eventq_do_callback(nic,
++                              (unsigned int)FALCON_EVENT_WAKE_EVQ_ID(ev),
++                              false);
++}
++
++void efrm_handle_timeout_event(struct efhw_nic *nic, efhw_event_t *ev)
++{
++      efrm_eventq_do_callback(nic,
++                              (unsigned int)FALCON_EVENT_WAKE_EVQ_ID(ev),
++                              true);
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/vi_resource_flush.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/vi_resource_flush.c       2008-05-19 00:33:29.449843650 +0300
+@@ -0,0 +1,506 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains DMA queue flushing of VI resources.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efrm/nic_table.h>
++#include <ci/driver/efab/hardware.h>
++#include <ci/efhw/falcon.h>
++#include <ci/efrm/private.h>
++#include <ci/efrm/sysdep.h>
++#include <ci/efrm/buffer_table.h>
++#include <ci/efrm/vi_resource_private.h>
++
++#if EFRM_VI_USE_WORKQUEUE
++      /* can fail as workitem can already be scheuled -- ignore failure */
++#define EFRM_VI_RM_DELAYED_FREE(manager) \
++      queue_work(manager->workqueue, &manager->work_item)
++#else
++#define EFRM_VI_RM_DELAYED_FREE(manager) \
++      efrm_vi_rm_delayed_free(&manager->work_item)
++#endif
++
++static const int flush_fifo_hwm = 8 /* TODO should be a HW specific const */ ;
++
++static void
++efrm_vi_resource_rx_flush_done(struct vi_resource *virs, int nic_i,
++                             bool *completed)
++{
++      /* We should only get a flush event if there is a flush
++       * outstanding. */
++      EFRM_ASSERT(efrm_nic_set_read
++                  (&virs->rx_flush_outstanding_nic_set, nic_i));
++
++      efrm_nic_set_write(&virs->rx_flush_outstanding_nic_set, nic_i, false);
++      efrm_nic_set_write(&virs->rx_flush_nic_set, nic_i, false);
++
++      if (efrm_nic_set_is_all_clear(&virs->rx_flush_outstanding_nic_set)) {
++              list_del(&virs->rx_flush_link);
++              efrm_vi_manager->rx_flush_outstanding_count--;
++
++              if (efrm_nic_set_is_all_clear(&virs->tx_flush_nic_set)) {
++                      list_add_tail(&virs->rx_flush_link,
++                                    &efrm_vi_manager->close_pending);
++                      *completed = 1;
++              }
++      }
++}
++
++static void
++efrm_vi_resource_tx_flush_done(struct vi_resource *virs, int nic_i,
++                             bool *completed)
++{
++      /* We should only get a flush event if there is a flush
++       * outstanding. */
++      EFRM_ASSERT(efrm_nic_set_read(&virs->tx_flush_nic_set, nic_i));
++
++      efrm_nic_set_write(&virs->tx_flush_nic_set, nic_i, false);
++
++      if (efrm_nic_set_is_all_clear(&virs->tx_flush_nic_set)) {
++              list_del(&virs->tx_flush_link);
++
++              if (efrm_nic_set_is_all_clear(&virs->rx_flush_nic_set)) {
++                      list_add_tail(&virs->rx_flush_link,
++                                    &efrm_vi_manager->close_pending);
++                      *completed = 1;
++              }
++      }
++}
++
++static void
++efrm_vi_resource_issue_rx_flush(struct vi_resource *virs, bool *completed)
++{
++      struct efhw_nic *nic;
++      int nic_i;
++      int instance;
++      int rc;
++
++      instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++
++      list_add_tail(&virs->rx_flush_link,
++                    &efrm_vi_manager->rx_flush_outstanding_list);
++      virs->rx_flush_outstanding_nic_set = virs->rx_flush_nic_set;
++      efrm_vi_manager->rx_flush_outstanding_count++;
++
++      EFRM_FOR_EACH_NIC_IN_SET(&virs->nic_set, nic_i, nic) {
++              EFRM_TRACE("%s: rx queue %d flush requested for nic %d",
++                         __FUNCTION__, instance, nic->index);
++              rc = efhw_nic_flush_rx_dma_channel(nic, instance);
++              if (rc == -EAGAIN)
++                      efrm_vi_resource_rx_flush_done(virs, nic_i, completed);
++      }
++}
++
++static void
++efrm_vi_resource_issue_tx_flush(struct vi_resource *virs, bool *completed)
++{
++      struct efhw_nic *nic;
++      int nic_i;
++      int instance;
++      int rc;
++
++      instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++
++      list_add_tail(&virs->tx_flush_link,
++                    &efrm_vi_manager->tx_flush_outstanding_list);
++
++      EFRM_FOR_EACH_NIC_IN_SET(&virs->nic_set, nic_i, nic) {
++              EFRM_TRACE("%s: tx queue %d flush requested for nic %d",
++                         __FUNCTION__, instance, nic->index);
++              rc = efhw_nic_flush_tx_dma_channel(nic, instance);
++              if (rc == -EAGAIN)
++                      efrm_vi_resource_tx_flush_done(virs, nic_i, completed);
++      }
++}
++
++static void efrm_vi_resource_process_waiting_flushes(bool *completed)
++{
++      struct vi_resource *virs;
++
++      while (efrm_vi_manager->rx_flush_outstanding_count < flush_fifo_hwm &&
++             !list_empty(&efrm_vi_manager->rx_flush_waiting_list)) {
++              virs =
++                  list_entry(list_pop
++                             (&efrm_vi_manager->rx_flush_waiting_list),
++                             struct vi_resource, rx_flush_link);
++              efrm_vi_resource_issue_rx_flush(virs, completed);
++      }
++}
++
++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
++static void
++efrm_vi_resource_flush_retry_vi(struct vi_resource *virs,
++                              int64_t time_now, bool *completed)
++{
++      struct efhw_nic *nic;
++      int nic_i;
++      int instance;
++
++      instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++
++      virs->flush_count++;
++      virs->flush_time = time_now;
++
++#if BUG7916_WORKAROUND
++      if (!efrm_nic_set_is_all_clear(&virs->rx_flush_outstanding_nic_set)) {
++              EFRM_TRACE("%s: Retrying RX flush on instance %d",
++                         __FUNCTION__, instance);
++
++              list_del(&virs->rx_flush_link);
++              efrm_vi_manager->rx_flush_outstanding_count--;
++              efrm_vi_resource_issue_rx_flush(virs, completed);
++              efrm_vi_resource_process_waiting_flushes(completed);
++      }
++#endif
++
++#if BUG5302_WORKAROUND
++      if (!efrm_nic_set_is_all_clear(&virs->tx_flush_nic_set)) {
++              if (virs->flush_count > 5) {
++                      EFRM_TRACE("%s: VI resource stuck flush pending "
++                                 "(instance=%d, count=%d)",
++                                 __FUNCTION__, instance, virs->flush_count);
++                      EFRM_FOR_EACH_NIC_IN_SET(&virs->tx_flush_nic_set,
++                                              nic_i, nic) {
++                              falcon_clobber_tx_dma_ptrs(nic, instance);
++                      }
++              } else {
++                      EFRM_TRACE("%s: Retrying TX flush on instance %d",
++                                 __FUNCTION__, instance);
++              }
++
++              list_del(&virs->tx_flush_link);
++              efrm_vi_resource_issue_tx_flush(virs, completed);
++      }
++#endif
++}
++#endif
++
++int efrm_vi_resource_flush_retry(struct vi_resource *virs)
++{
++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
++      irq_flags_t lock_flags;
++      bool completed = false;
++
++      if (efrm_nic_set_is_all_clear(&virs->rx_flush_nic_set) &&
++          efrm_nic_set_is_all_clear(&virs->tx_flush_nic_set))
++              return -EALREADY;
++
++      spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
++      efrm_vi_resource_flush_retry_vi(virs, get_jiffies_64(), &completed);
++      spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
++
++      if (completed)
++              EFRM_VI_RM_DELAYED_FREE(efrm_vi_manager);
++#endif
++
++      return 0;
++}
++EXPORT_SYMBOL(efrm_vi_resource_flush_retry);
++
++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
++/* resource manager lock should be taken before this call */
++static void efrm_vi_handle_flush_loss(bool *completed)
++{
++      struct list_head *pos, *temp;
++      struct vi_resource *virs;
++      int64_t time_now, time_pending;
++
++      /* It's possible we miss flushes - the list is sorted in order we
++       * generate flushes, see if any are very old. It's also possible
++       * that we decide an endpoint is flushed even though we've not
++       * received all the flush events. We *should * mark as
++       * completed, reclaim and loop again. ??
++       * THIS NEEDS BACKPORTING FROM THE FALCON branch
++       */
++      time_now = get_jiffies_64();
++
++#if BUG7916_WORKAROUND
++      list_for_each_safe(pos, temp,
++                         &efrm_vi_manager->rx_flush_outstanding_list) {
++              virs = container_of(pos, struct vi_resource, rx_flush_link);
++
++              time_pending = time_now - virs->flush_time;
++
++              /* List entries are held in reverse chronological order.  Only
++               * process the old ones. */
++              if (time_pending <= 0x100000000LL)
++                      break;
++
++              efrm_vi_resource_flush_retry_vi(virs, time_now, completed);
++      }
++#endif
++
++#if BUG5302_WORKAROUND
++      list_for_each_safe(pos, temp,
++                         &efrm_vi_manager->tx_flush_outstanding_list) {
++              virs = container_of(pos, struct vi_resource, tx_flush_link);
++
++              time_pending = time_now - virs->flush_time;
++
++              /* List entries are held in reverse chronological order.
++               * Only process the old ones. */
++              if (time_pending <= 0x100000000LL)
++                      break;
++
++              efrm_vi_resource_flush_retry_vi(virs, time_now, completed);
++      }
++#endif
++}
++#endif
++
++void
++efrm_vi_register_flush_callback(struct vi_resource *virs,
++                              void (*handler)(void *), void *arg)
++{
++      if (handler == NULL) {
++              virs->flush_callback_fn = handler;
++              wmb();
++              virs->flush_callback_arg = arg;
++      } else {
++              virs->flush_callback_arg = arg;
++              wmb();
++              virs->flush_callback_fn = handler;
++      }
++}
++EXPORT_SYMBOL(efrm_vi_register_flush_callback);
++
++int efrm_pt_flush(struct vi_resource *virs)
++{
++      int instance;
++      irq_flags_t lock_flags;
++      bool completed = false;
++
++      instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++
++      EFRM_ASSERT(efrm_nic_set_is_all_clear(&virs->rx_flush_nic_set));
++      EFRM_ASSERT(efrm_nic_set_is_all_clear
++                  (&virs->rx_flush_outstanding_nic_set));
++      EFRM_ASSERT(efrm_nic_set_is_all_clear(&virs->tx_flush_nic_set));
++
++      EFRM_TRACE("%s: " EFRM_RESOURCE_FMT " EVQ=%d TXQ=%d RXQ=%d",
++                 __FUNCTION__, EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle),
++                 virs->evq_capacity,
++                 virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX],
++                 virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX]);
++
++      spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
++
++      if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX] != 0)
++              virs->rx_flush_nic_set = virs->nic_set;
++
++      if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] != 0)
++              virs->tx_flush_nic_set = virs->nic_set;
++
++      /* Clean up immediately if there are no flushes. */
++      if (efrm_nic_set_is_all_clear(&virs->rx_flush_nic_set) &&
++          efrm_nic_set_is_all_clear(&virs->tx_flush_nic_set)) {
++              list_add_tail(&virs->rx_flush_link,
++                            &efrm_vi_manager->close_pending);
++              completed = true;
++      }
++
++      /* Issue the RX flush if possible or queue it for later. */
++      if (!efrm_nic_set_is_all_clear(&virs->rx_flush_nic_set)) {
++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
++              if (efrm_vi_manager->rx_flush_outstanding_count >=
++                  flush_fifo_hwm)
++                      efrm_vi_handle_flush_loss(&completed);
++#endif
++              if (efrm_vi_manager->rx_flush_outstanding_count >=
++                  flush_fifo_hwm) {
++                      list_add_tail(&virs->rx_flush_link,
++                                    &efrm_vi_manager->rx_flush_waiting_list);
++              } else {
++                      efrm_vi_resource_issue_rx_flush(virs, &completed);
++              }
++      }
++
++      /* Issue the TX flush.  There's no limit to the number of
++       * outstanding TX flushes. */
++      if (!efrm_nic_set_is_all_clear(&virs->tx_flush_nic_set))
++              efrm_vi_resource_issue_tx_flush(virs, &completed);
++
++      virs->flush_time = get_jiffies_64();
++
++      spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
++
++      if (completed)
++              EFRM_VI_RM_DELAYED_FREE(efrm_vi_manager);
++
++      return 0;
++}
++EXPORT_SYMBOL(efrm_pt_flush);
++
++static void
++efrm_handle_rx_dmaq_flushed(struct efhw_nic *flush_nic, int instance,
++                          bool *completed)
++{
++      struct list_head *pos, *temp;
++      struct vi_resource *virs;
++
++      list_for_each_safe(pos, temp,
++                         &efrm_vi_manager->rx_flush_outstanding_list) {
++              virs = container_of(pos, struct vi_resource, rx_flush_link);
++
++              if (instance == EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle)) {
++                      efrm_vi_resource_rx_flush_done(virs,
++                                                     flush_nic->index,
++                                                     completed);
++                      efrm_vi_resource_process_waiting_flushes(completed);
++                      return;
++              }
++      }
++      EFRM_TRACE("%s: Unhandled rx flush event, nic %d, instance %d",
++                 __FUNCTION__, flush_nic->index, instance);
++}
++
++static void
++efrm_handle_tx_dmaq_flushed(struct efhw_nic *flush_nic, int instance,
++                          bool *completed)
++{
++      struct list_head *pos, *temp;
++      struct vi_resource *virs;
++
++      list_for_each_safe(pos, temp,
++                         &efrm_vi_manager->tx_flush_outstanding_list) {
++              virs = container_of(pos, struct vi_resource, tx_flush_link);
++
++              if (instance == EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle)) {
++                      efrm_vi_resource_tx_flush_done(virs,
++                                                     flush_nic->index,
++                                                     completed);
++                      return;
++              }
++      }
++      EFRM_TRACE("%s: Unhandled tx flush event, nic %d, instance %d",
++                 __FUNCTION__, flush_nic->index, instance);
++}
++
++void
++efrm_handle_dmaq_flushed(struct efhw_nic *flush_nic, int instance,
++                       int rx_flush)
++{
++      irq_flags_t lock_flags;
++      bool completed = false;
++
++      EFRM_TRACE("%s: nic_i=%d  instance=%d  rx_flush=%d", __FUNCTION__,
++                 flush_nic->index, instance, rx_flush);
++
++      spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
++
++      if (rx_flush)
++              efrm_handle_rx_dmaq_flushed(flush_nic, instance, &completed);
++      else
++              efrm_handle_tx_dmaq_flushed(flush_nic, instance, &completed);
++
++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
++      efrm_vi_handle_flush_loss(&completed);
++#endif
++
++      spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
++
++      if (completed)
++              EFRM_VI_RM_DELAYED_FREE(efrm_vi_manager);
++}
++
++static void
++efrm_vi_rm_reinit_dmaqs(struct vi_resource *virs)
++{
++      struct efhw_nic *nic;
++      int nic_i;
++
++      EFRM_FOR_EACH_NIC_IN_SET(&virs->nic_set, nic_i, nic) {
++              if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_TX] != 0)
++                      efrm_vi_rm_init_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_TX,
++                                           nic);
++              if (virs->dmaq_capacity[EFRM_VI_RM_DMA_QUEUE_RX])
++                      efrm_vi_rm_init_dmaq(virs, EFRM_VI_RM_DMA_QUEUE_RX,
++                                           nic);
++      }
++}
++
++/* free any PT endpoints whose flush has now complete */
++void efrm_vi_rm_delayed_free(struct work_struct *data)
++{
++      irq_flags_t lock_flags;
++      struct list_head close_pending;
++      struct vi_resource *virs;
++
++      EFRM_RESOURCE_MANAGER_ASSERT_VALID(&efrm_vi_manager->rm);
++
++      spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
++      list_replace_init(&efrm_vi_manager->close_pending, &close_pending);
++      spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
++
++      EFRM_TRACE("%s: %p", __FUNCTION__, efrm_vi_manager);
++      while (!list_empty(&close_pending)) {
++              virs =
++                  list_entry(list_pop(&close_pending), struct vi_resource,
++                             rx_flush_link);
++              EFRM_TRACE("%s: flushed VI instance=%d", __FUNCTION__,
++                         EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle));
++
++              if (virs->flush_callback_fn != NULL) {
++                      efrm_vi_rm_reinit_dmaqs(virs);
++                      virs->flush_callback_fn(virs->flush_callback_arg);
++              } else
++                      efrm_vi_rm_free_flushed_resource(virs);
++      }
++}
++
++void efrm_vi_rm_salvage_flushed_vis(void)
++{
++#if BUG7916_WORKAROUND || BUG5302_WORKAROUND
++      irq_flags_t lock_flags;
++      bool completed;
++
++      spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
++      efrm_vi_handle_flush_loss(&completed);
++      spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
++#endif
++
++      efrm_vi_rm_delayed_free(&efrm_vi_manager->work_item);
++}
++
++void efrm_vi_resource_free(struct vi_resource *virs)
++{
++      efrm_vi_register_flush_callback(virs, NULL, NULL);
++      efrm_pt_flush(virs);
++}
++EXPORT_SYMBOL(efrm_vi_resource_free);
++
++/*
++ * vi: sw=8:ai:aw
++ */
+--- linux-2.6.18.8/drivers/net/sfc/sfc_resource/vi_resource_manager.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfc_resource/vi_resource_manager.c     2008-05-19 00:33:29.449843650 +0300
+@@ -0,0 +1,259 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains the VI resource manager.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <ci/efrm/nic_table.h>
++#include <ci/driver/efab/hardware.h>
++#include <ci/efhw/falcon.h>
++#include <ci/efrm/private.h>
++#include <ci/efrm/vi_resource_private.h>
++
++int efrm_pt_pace(struct vi_resource *virs, unsigned int val)
++{
++#if defined(__CI_HARDWARE_CONFIG_FALCON__)
++      int instance, nic_i;
++      struct efhw_nic *nic;
++
++      EFRM_RESOURCE_ASSERT_VALID(&virs->rs, 0);
++      instance = EFRM_RESOURCE_INSTANCE(virs->rs.rs_handle);
++
++      EFRM_FOR_EACH_NIC_IN_SET(&virs->nic_set, nic_i, nic)
++              falcon_nic_pace(nic, instance, val);
++
++      EFRM_TRACE("%s[%d]=%d DONE", __FUNCTION__, instance, val);
++      return 0;
++#else
++      return -EOPNOTSUPP;
++#endif
++}
++EXPORT_SYMBOL(efrm_pt_pace);
++
++/*** Resource manager creation/destruction *******************************/
++
++static void efrm_vi_rm_dtor(struct efrm_resource_manager *rm);
++
++static int
++efrm_create_or_destroy_vi_resource_manager(
++                              struct efrm_resource_manager **rm_in_out,
++                              const struct vi_resource_dimensions *dims,
++                              bool destroy)
++{
++      struct vi_resource *virs;
++      struct list_head *pos, *temp;
++      struct list_head flush_pending;
++      irq_flags_t lock_flags;
++      int rc, i, n_evqs;
++      unsigned dmaq_min, dmaq_max;
++
++      EFRM_ASSERT(rm_in_out);
++
++      if (destroy)
++              goto destroy;
++
++      EFRM_ASSERT(dims);
++      EFRM_NOTICE("vi_resource_manager: evq_int=%u-%u evq_timer=%u-%u",
++                  dims->evq_int_min, dims->evq_int_max,
++                  dims->evq_timer_min, dims->evq_timer_max);
++      EFRM_NOTICE("vi_resource_manager: rxq=%u-%u txq=%u-%u",
++                  dims->rxq_min, dims->rxq_max,
++                  dims->txq_min, dims->txq_max);
++
++      efrm_vi_manager = kmalloc(sizeof(*efrm_vi_manager), GFP_KERNEL);
++      if (efrm_vi_manager == NULL) {
++              rc = -ENOMEM;
++              goto fail_alloc;
++      }
++
++      memset(efrm_vi_manager, 0, sizeof(*efrm_vi_manager));
++
++      efrm_vi_manager->iscsi_dmaq_instance_is_free = true;
++
++      dmaq_min = max(dims->rxq_min, dims->txq_min);
++      dmaq_max = min(dims->rxq_max, dims->txq_max);
++
++      efrm_vi_manager->with_timer_base =
++          max(dmaq_min, dims->evq_timer_min);
++      efrm_vi_manager->with_timer_limit =
++          min(dmaq_max, dims->evq_timer_max);
++      rc = efrm_kfifo_id_ctor(&efrm_vi_manager->instances_with_timer,
++                              efrm_vi_manager->with_timer_base,
++                              efrm_vi_manager->with_timer_limit,
++                              &efrm_vi_manager->rm.rm_lock);
++      if (rc < 0)
++              goto fail_with_timer_id_pool;
++
++      efrm_vi_manager->with_interrupt_base =
++          max(dmaq_min, dims->evq_int_min);
++      efrm_vi_manager->with_interrupt_limit =
++          min(dmaq_max, dims->evq_int_max);
++      efrm_vi_manager->with_interrupt_limit =
++              max(efrm_vi_manager->with_interrupt_limit,
++                  efrm_vi_manager->with_interrupt_base);
++      rc = efrm_kfifo_id_ctor(&efrm_vi_manager->instances_with_interrupt,
++                              efrm_vi_manager->with_interrupt_base,
++                              efrm_vi_manager->with_interrupt_limit,
++                              &efrm_vi_manager->rm.rm_lock);
++      if (rc < 0)
++              goto fail_with_int_id_pool;
++
++      n_evqs = max(efrm_vi_manager->with_timer_limit,
++                   efrm_vi_manager->with_interrupt_limit);
++      rc = -ENOMEM;
++      efrm_vi_manager->evq_infos =
++              vmalloc(n_evqs * sizeof(struct vi_resource_evq_info));
++      if (efrm_vi_manager->evq_infos == NULL)
++              goto fail_alloc_evq_infos;
++
++      for (i = 0; i < n_evqs; ++i) {
++              efrm_vi_manager->evq_infos[i].evq_state = 0;
++              efrm_vi_manager->evq_infos[i].evq_virs = NULL;
++      }
++
++      INIT_LIST_HEAD(&efrm_vi_manager->rx_flush_waiting_list);
++      INIT_LIST_HEAD(&efrm_vi_manager->rx_flush_outstanding_list);
++      INIT_LIST_HEAD(&efrm_vi_manager->tx_flush_outstanding_list);
++      efrm_vi_manager->rx_flush_outstanding_count = 0;
++
++      INIT_LIST_HEAD(&efrm_vi_manager->close_pending);
++#if EFRM_VI_USE_WORKQUEUE
++      efrm_vi_manager->workqueue = create_workqueue("sfc_vi");
++      if (efrm_vi_manager->workqueue == NULL)
++              goto fail_create_workqueue;
++#endif
++      INIT_WORK(&efrm_vi_manager->work_item, efrm_vi_rm_delayed_free);
++
++      /* NB.  This must be the last step to avoid things getting tangled.
++       * efrm_resource_manager_dtor calls the vi_rm_dtor which ends up in
++       * this function. */
++      rc = efrm_resource_manager_ctor(&efrm_vi_manager->rm, efrm_vi_rm_dtor,
++                                      "VI", EFRM_RESOURCE_VI, 0);
++      if (rc < 0)
++              goto fail_rm_ctor;
++
++      *rm_in_out = &efrm_vi_manager->rm;
++      return 0;
++
++destroy:
++      rc = 0;
++      EFRM_RESOURCE_MANAGER_ASSERT_VALID(*rm_in_out);
++
++      /* Abort outstanding flushes.  Note, a VI resource can be on more
++       * than one of these lists.  We handle this by starting with the TX
++       * list and then append VIs to this list if they aren't on the TX
++       * list already.  A VI is on the TX flush list if tx_flush_nic_set
++       * is not empty. */
++      spin_lock_irqsave(&efrm_vi_manager->rm.rm_lock, lock_flags);
++
++      list_replace_init(&efrm_vi_manager->tx_flush_outstanding_list,
++                        &flush_pending);
++
++      list_for_each_safe(pos, temp,
++                         &efrm_vi_manager->rx_flush_waiting_list) {
++              virs = container_of(pos, struct vi_resource, rx_flush_link);
++
++              list_del(&virs->rx_flush_link);
++              if (efrm_nic_set_is_all_clear(&virs->tx_flush_nic_set))
++                      list_add_tail(&virs->tx_flush_link, &flush_pending);
++      }
++
++      list_for_each_safe(pos, temp,
++                         &efrm_vi_manager->rx_flush_outstanding_list) {
++              virs = container_of(pos, struct vi_resource, rx_flush_link);
++
++              list_del(&virs->rx_flush_link);
++              if (efrm_nic_set_is_all_clear(&virs->tx_flush_nic_set))
++                      list_add_tail(&virs->tx_flush_link, &flush_pending);
++      }
++
++      spin_unlock_irqrestore(&efrm_vi_manager->rm.rm_lock, lock_flags);
++
++      while (!list_empty(&flush_pending)) {
++              virs =
++                  list_entry(list_pop(&flush_pending), struct vi_resource,
++                             tx_flush_link);
++              EFRM_TRACE("%s: found PT endpoint " EFRM_RESOURCE_FMT
++                         " with flush pending [Tx=0x%x, Rx=0x%x, RxO=0x%x]",
++                         __FUNCTION__,
++                         EFRM_RESOURCE_PRI_ARG(virs->rs.rs_handle),
++                         virs->tx_flush_nic_set.nics,
++                         virs->rx_flush_nic_set.nics,
++                         virs->rx_flush_outstanding_nic_set.nics);
++              efrm_vi_rm_free_flushed_resource(virs);
++      }
++
++fail_rm_ctor:
++
++      /* Complete outstanding closes. */
++#if EFRM_VI_USE_WORKQUEUE
++      destroy_workqueue(efrm_vi_manager->workqueue);
++fail_create_workqueue:
++#endif
++      EFRM_ASSERT(list_empty(&efrm_vi_manager->close_pending));
++
++      n_evqs = max(efrm_vi_manager->with_timer_limit,
++                   efrm_vi_manager->with_interrupt_limit);
++      vfree(efrm_vi_manager->evq_infos);
++fail_alloc_evq_infos:
++
++      kfifo_vfree(efrm_vi_manager->instances_with_interrupt);
++fail_with_int_id_pool:
++
++      kfifo_vfree(efrm_vi_manager->instances_with_timer);
++fail_with_timer_id_pool:
++
++      if (destroy)
++              return 0;
++
++      EFRM_DO_DEBUG(memset(efrm_vi_manager, 0, sizeof(*efrm_vi_manager)));
++      kfree(efrm_vi_manager);
++fail_alloc:
++
++      *rm_in_out = NULL;
++      EFRM_ERR("%s: failed rc=%d", __FUNCTION__, rc);
++      return rc;
++}
++
++int
++efrm_create_vi_resource_manager(struct efrm_resource_manager **rm_out,
++                              const struct vi_resource_dimensions *dims)
++{
++      return efrm_create_or_destroy_vi_resource_manager(rm_out, dims, false);
++}
++
++static void efrm_vi_rm_dtor(struct efrm_resource_manager *rm)
++{
++      efrm_create_or_destroy_vi_resource_manager(&rm, NULL, true);
++}
+--- linux-2.6.18.8/drivers/net/sfc/sfe4001.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/sfe4001.c      2008-05-19 00:33:29.449843650 +0300
+@@ -0,0 +1,315 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2007:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************/
++
++/*****************************************************************************
++ * Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that
++ * controls the PHY power rails, and for the MAX6647 temp. sensor used to check
++ * the PHY
++ */
++#include <linux/delay.h>
++#include "efx.h"
++#include "phy.h"
++#include "boards.h"
++#include "falcon.h"
++#include "falcon_hwdefs.h"
++
++/**************************************************************************
++ *
++ * I2C IO Expander device
++ *
++ **************************************************************************/
++#define       PCA9539 0x74
++
++#define       P0_IN 0x00
++#define       P0_OUT 0x02
++#define       P0_INVERT 0x04
++#define       P0_CONFIG 0x06
++
++#define       P0_EN_1V0X_LBN 0
++#define       P0_EN_1V0X_WIDTH 1
++#define       P0_EN_1V2_LBN 1
++#define       P0_EN_1V2_WIDTH 1
++#define       P0_EN_2V5_LBN 2
++#define       P0_EN_2V5_WIDTH 1
++#define       P0_EN_3V3X_LBN 3
++#define       P0_EN_3V3X_WIDTH 1
++#define       P0_EN_5V_LBN 4
++#define       P0_EN_5V_WIDTH 1
++#define       P0_SHORTEN_JTAG_LBN 5
++#define       P0_SHORTEN_JTAG_WIDTH 1
++#define       P0_X_TRST_LBN 6
++#define       P0_X_TRST_WIDTH 1
++#define       P0_DSP_RESET_LBN 7
++#define       P0_DSP_RESET_WIDTH 1
++
++#define       P1_IN 0x01
++#define       P1_OUT 0x03
++#define       P1_INVERT 0x05
++#define       P1_CONFIG 0x07
++
++#define       P1_AFE_PWD_LBN 0
++#define       P1_AFE_PWD_WIDTH 1
++#define       P1_DSP_PWD25_LBN 1
++#define       P1_DSP_PWD25_WIDTH 1
++#define       P1_RESERVED_LBN 2
++#define       P1_RESERVED_WIDTH 2
++#define       P1_SPARE_LBN 4
++#define       P1_SPARE_WIDTH 4
++
++
++/**************************************************************************
++ *
++ * Temperature Sensor
++ *
++ **************************************************************************/
++#define       MAX6647 0x4e
++
++#define       RLTS    0x00
++#define       RLTE    0x01
++#define       RSL     0x02
++#define       RCL     0x03
++#define       RCRA    0x04
++#define       RLHN    0x05
++#define       RLLI    0x06
++#define       RRHI    0x07
++#define       RRLS    0x08
++#define       WCRW    0x0a
++#define       WLHO    0x0b
++#define       WRHA    0x0c
++#define       WRLN    0x0e
++#define       OSHT    0x0f
++#define       REET    0x10
++#define       RIET    0x11
++#define       RWOE    0x19
++#define       RWOI    0x20
++#define       HYS     0x21
++#define       QUEUE   0x22
++#define       MFID    0xfe
++#define       REVID   0xff
++
++/* Status bits */
++#define MAX6647_BUSY  (1 << 7)        /* ADC is converting */
++#define MAX6647_LHIGH (1 << 6)        /* Local high temp. alarm */
++#define MAX6647_LLOW  (1 << 5)        /* Local low temp. alarm */
++#define MAX6647_RHIGH (1 << 4)        /* Remote high temp. alarm */
++#define MAX6647_RLOW  (1 << 3)        /* Remote low temp. alarm */
++#define MAX6647_FAULT (1 << 2)        /* DXN/DXP short/open circuit */
++#define MAX6647_EOT   (1 << 1)        /* Remote junction overtemp. */
++#define MAX6647_IOT   (1 << 0)        /* Local junction overtemp. */
++
++static const u8 xgphy_max_temperature = 90;
++
++void sfe4001_poweroff(struct efx_nic *efx)
++{
++      struct efx_i2c_interface *i2c = &efx->i2c;
++
++      u8 cfg, out, in;
++
++      EFX_INFO(efx, "%s\n", __func__);
++
++      /* Turn off all power rails */
++      out = 0xff;
++      (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, EFX_BYTE);
++
++      /* Disable port 1 outputs on IO expander */
++      cfg = 0xff;
++      (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, EFX_BYTE);
++
++      /* Disable port 0 outputs on IO expander */
++      cfg = 0xff;
++      (void) efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, EFX_BYTE);
++
++      /* Clear any over-temperature alert */
++      (void) efx_i2c_read(i2c, MAX6647, RSL, &in, EFX_BYTE);
++}
++
++static int sfe4001_check_hw(struct efx_nic *efx)
++{
++      struct efx_i2c_interface *i2c = &efx->i2c;
++      int rc;
++      u8 status;
++
++      /* Check the powered status of the PHY. Lack of power implies that
++       * the MAX6647 has shut down power to it, probably due to a temp.
++       * alarm. Reading the power status rather than the MAX6647 status
++       * directly because the later is read-to-clear and would thus
++       * start to power up the PHY again when polled, causing us to blip
++       * the power undesirably */
++
++      /* If XAUI link is down, check power status. Reading
++       * power requires a I2C byte read, which is too slow
++       * to poll (see SFC bug 7884). */
++      if (falcon_xaui_link_ok(efx))
++              return 0;
++
++      rc = efx_i2c_read(i2c, PCA9539, P1_IN, &status, EFX_BYTE);
++      status &= ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN));
++
++      /* We know we can read from the IO expander because we did
++       * it during power-on. Assume failure now is bad news. */
++      if (rc != 0 || status == 0) {
++              sfe4001_poweroff(efx);
++
++              /* Note that the PHY is pining for the cooling fans */
++              tenxpress_set_state(efx, TENXPRESS_STATUS_OTEMP);
++
++              /* Log the info */
++              if (status == 0) {
++                      EFX_ERR(efx, "%s: Temperature sensor reports "
++                              "alarm! (0x%x) Shutting down PHY.\n",
++                              __func__, status);
++                      rc = -EIO;
++              } else {
++                      EFX_ERR(efx, "%s: Failed to read PHY status!"
++                              " Shutting down PHY.\n",
++                              __func__);
++              }
++      }
++
++      return rc;
++}
++
++/* This board uses an I2C expander to provider power to the PHY, which needs to
++ * be turned on before the PHY can be used.
++ * Context: Process context, rtnl lock held
++ */
++int sfe4001_poweron(struct efx_nic *efx)
++{
++      struct efx_i2c_interface *i2c = &efx->i2c;
++      unsigned int count;
++      int rc;
++      u8 out, in, cfg;
++      efx_dword_t reg;
++
++      /* 10Xpress has fixed-function LED pins, so there is no board-specific
++       * blink code. */
++      efx->board_info.blink = tenxpress_phy_blink;
++
++      /* Ensure that XGXS and XAUI SerDes are held in reset */
++      EFX_POPULATE_DWORD_7(reg, XX_PWRDNA_EN, 1,
++                           XX_PWRDNB_EN, 1,
++                           XX_RSTPLLAB_EN, 1,
++                           XX_RESETA_EN, 1,
++                           XX_RESETB_EN, 1,
++                           XX_RSTXGXSRX_EN, 1,
++                           XX_RSTXGXSTX_EN, 1);
++      efx->mac_op->mac_writel(efx, &reg, XX_PWR_RST_REG_MAC);
++      udelay(10);
++
++      efx->board_info.monitor = sfe4001_check_hw;
++      efx->board_info.fini = sfe4001_poweroff;
++
++      /* Set DSP over-temperature alert threshold */
++      EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature);
++      rc = efx_i2c_write(i2c, MAX6647, WLHO,
++                         &xgphy_max_temperature, EFX_BYTE);
++      if (rc)
++              goto fail1;
++
++      /* Read it back and verify */
++      rc = efx_i2c_read(i2c, MAX6647, RLHN, &in, EFX_BYTE);
++      if (rc)
++              goto fail1;
++      if (in != xgphy_max_temperature) {
++              rc = -EFAULT;
++              goto fail1;
++      }
++
++      /* Clear any previous over-temperature alert */
++      rc = efx_i2c_read(i2c, MAX6647, RSL, &in, EFX_BYTE);
++      if (rc)
++              goto fail1;
++
++      /* Enable port 0 and port 1 outputs on IO expander */
++      cfg = 0x00;
++      rc = efx_i2c_write(i2c, PCA9539, P0_CONFIG, &cfg, EFX_BYTE);
++      if (rc)
++              goto fail1;
++      cfg = 0xff & ~(1 << P1_SPARE_LBN);
++      rc = efx_i2c_write(i2c, PCA9539, P1_CONFIG, &cfg, EFX_BYTE);
++      if (rc)
++              goto fail2;
++
++      /* Turn all power off then wait 1 sec. This ensures PHY is reset */
++      out = 0xff & ~((0 << P0_EN_1V2_LBN) | (0 << P0_EN_2V5_LBN) |
++                     (0 << P0_EN_3V3X_LBN) | (0 << P0_EN_5V_LBN) |
++                     (0 << P0_EN_1V0X_LBN));
++      rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, EFX_BYTE);
++      if (rc)
++              goto fail3;
++
++      schedule_timeout_uninterruptible(HZ);
++      count = 0;
++      do {
++              /* Turn on 1.2V, 2.5V, 3.3V and 5V power rails */
++              out = 0xff & ~((1 << P0_EN_1V2_LBN) | (1 << P0_EN_2V5_LBN) |
++                             (1 << P0_EN_3V3X_LBN) | (1 << P0_EN_5V_LBN) |
++                             (1 << P0_X_TRST_LBN));
++
++              rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, EFX_BYTE);
++              if (rc)
++                      goto fail3;
++              msleep(10);
++
++              /* Turn on 1V power rail */
++              out &= ~(1 << P0_EN_1V0X_LBN);
++              rc = efx_i2c_write(i2c, PCA9539, P0_OUT, &out, EFX_BYTE);
++              if (rc)
++                      goto fail3;
++
++              EFX_INFO(efx, "waiting for power (attempt %d)...\n", count);
++
++              schedule_timeout_uninterruptible(HZ);
++
++              /* Check DSP is powered */
++              rc = efx_i2c_read(i2c, PCA9539, P1_IN, &in, EFX_BYTE);
++              if (rc)
++                      goto fail3;
++              if (in & (1 << P1_AFE_PWD_LBN))
++                      goto done;
++
++      } while (++count < 20);
++
++      EFX_INFO(efx, "timed out waiting for power\n");
++      rc = -ETIMEDOUT;
++      goto fail3;
++
++done:
++      EFX_INFO(efx, "PHY is powered on\n");
++      return 0;
++
++fail3:
++      /* Turn off all power rails */
++      out = 0xff;
++      (void) efx_i2c_write(i2c, PCA9539, P0_OUT, &out, EFX_BYTE);
++      /* Disable port 1 outputs on IO expander */
++      out = 0xff;
++      (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, EFX_BYTE);
++fail2:
++      /* Disable port 0 outputs on IO expander */
++      out = 0xff;
++      (void) efx_i2c_write(i2c, PCA9539, P1_CONFIG, &out, EFX_BYTE);
++fail1:
++      return rc;
++}
+--- linux-2.6.18.8/drivers/net/sfc/spi.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/spi.h  2008-05-19 00:33:29.449843650 +0300
+@@ -0,0 +1,186 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005:      Fen Systems Ltd.
++ * Copyright 2006:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef EFX_SPI_H
++#define EFX_SPI_H
++
++#include "net_driver.h"
++
++/**************************************************************************
++ *
++ * Basic SPI command set and bit definitions
++ *
++ *************************************************************************/
++
++/*
++ * Commands common to all known devices.
++ *
++ */
++
++/* Write status register */
++#define SPI_WRSR 0x01
++
++/* Write data to memory array */
++#define SPI_WRITE 0x02
++
++/* Read data from memory array */
++#define SPI_READ 0x03
++
++/* Reset write enable latch */
++#define SPI_WRDI 0x04
++
++/* Read status register */
++#define SPI_RDSR 0x05
++
++/* Set write enable latch */
++#define SPI_WREN 0x06
++
++/* SST: Enable write to status register */
++#define SPI_SST_EWSR 0x50
++
++/*
++ * Status register bits.  Not all bits are supported on all devices.
++ *
++ */
++
++/* Write-protect pin enabled */
++#define SPI_STATUS_WPEN 0x80
++
++/* Block protection bit 2 */
++#define SPI_STATUS_BP2 0x10
++
++/* Block protection bit 1 */
++#define SPI_STATUS_BP1 0x08
++
++/* Block protection bit 0 */
++#define SPI_STATUS_BP0 0x04
++
++/* State of the write enable latch */
++#define SPI_STATUS_WEN 0x02
++
++/* Device busy flag */
++#define SPI_STATUS_NRDY 0x01
++
++/**************************************************************************
++ *
++ * Efx SPI devices
++ *
++ **************************************************************************
++ */
++
++/**
++ * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device
++ * @device_id:                Controller's id for the device
++ * @size:             Size (in bytes)
++ * @addr_len:         Number of address bytes in read/write commands
++ * @munge_address:    Flag whether addresses should be munged.
++ *    Some devices with 9-bit addresses (e.g. AT25040A EEPROM)
++ *    use bit 3 of the command byte as address bit A8, rather
++ *    than having a two-byte address.  If this flag is set, then
++ *    commands should be munged in this way.
++ * @erase_command:    Erase command (or 0 if sector erase not needed).
++ * @erase_size:               Erase sector size (in bytes)
++ *    Erase commands affect sectors with this size and alignment.
++ *    This must be a power of two.
++ * @block_size:               Write block size (in bytes).
++ *    Write commands are limited to blocks with this size and alignment.
++ * @read:             Read function for the device
++ * @write:            Write function for the device
++ */
++struct efx_spi_device {
++      int device_id;
++      unsigned int size;
++      unsigned int addr_len;
++      unsigned int munge_address:1;
++      u8 erase_command;
++      unsigned int erase_size;
++      unsigned int block_size;
++      int (*read) (const struct efx_spi_device *spi,
++                   struct efx_nic *efx, unsigned int command,
++                   int address, void *data, unsigned int len);
++      int (*write) (const struct efx_spi_device *spi,
++                    struct efx_nic *efx, unsigned int command,
++                    int address, const void *data, unsigned int len);
++};
++
++/* Maximum length for SPI read or write through Falcon */
++#define FALCON_SPI_MAX_LEN 16U
++
++/**
++ * efx_spi_write_limit - calculate maximum permitted length for write
++ * @spi:              SPI device description
++ * @start:            Starting address
++ *
++ * Return the maximum length for a write starting at the given address
++ * in the device.
++ *
++ * SPI writes must not cross block boundaries.  Devices tend
++ * to wrap addresses at block boundaries; e.g. trying to write 5 bytes
++ * starting at offset 14 with a block size of 16 might write
++ * {14,15,0,1,2} rather than {14,15,16,17,18}.
++ */
++static inline unsigned int
++efx_spi_write_limit(const struct efx_spi_device *spi, unsigned int start)
++{
++      return min(FALCON_SPI_MAX_LEN,
++                 (spi->block_size - (start & (spi->block_size - 1))));
++}
++
++/**
++ * efx_spi_read_limit - calculate maximum permitted length for read
++ * @spi:              SPI device description
++ * @start:            Starting address
++ *
++ * Return the maximum length for a read starting at the given address
++ * in the device.
++ */
++static inline unsigned int
++efx_spi_read_limit(const struct efx_spi_device *spi __attribute__ ((unused)),
++                 unsigned int start __attribute__ ((unused)))
++{
++      return FALCON_SPI_MAX_LEN;
++}
++
++/**
++ * efx_spi_munge_command - adjust command as necessary for given address
++ * @spi:              SPI device description
++ * @command:          Normal SPI command
++ * @address:          Address for command
++ *
++ * Some devices with 9-bit addresses (e.g. AT25040A EEPROM) use bit 3
++ * of the command byte as address bit A8, rather than having a
++ * two-byte address.  This function calculates the appropriate command
++ * byte for the device, taking this munging into account.
++ */
++static inline u8 efx_spi_munge_command(const struct efx_spi_device *spi,
++                                          const u8 command,
++                                          const unsigned int address)
++{
++      return (command | (((address >> 8) & spi->munge_address) << 3));
++}
++
++#endif /* EFX_SPI_H */
+--- linux-2.6.18.8/drivers/net/sfc/tenxpress.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/tenxpress.c    2008-05-19 00:33:29.449843650 +0300
+@@ -0,0 +1,697 @@
++/****************************************************************************
++ * Driver for Solarflare 802.3an compliant PHY
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2007:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************/
++
++#include <linux/delay.h>
++#include <linux/seq_file.h>
++#include "efx.h"
++#include "debugfs.h"
++#include "gmii.h"
++#include "mdio_10g.h"
++#include "falcon.h"
++#include "phy.h"
++#include "falcon_hwdefs.h"
++#include "boards.h"
++
++/* We expect these MMDs to be in the package */
++/* AN not here as mdio_check_mmds() requires STAT2 support */
++#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PMAPMD | \
++                               MDIO_MMDREG_DEVS0_PCS    | \
++                               MDIO_MMDREG_DEVS0_PHYXS)
++
++#define TENXPRESS_LOOPBACKS ((1 << LOOPBACK_PHYXS) |  \
++                           (1 << LOOPBACK_PCS) |      \
++                           (1 << LOOPBACK_PMAPMD) |   \
++                           (1 << LOOPBACK_NETWORK))
++
++/* We complain if we fail to see the link partner as 10G capable this many
++ * times in a row (must be > 1 as sampling the autoneg. registers is racy)
++ */
++#define MAX_BAD_LP_TRIES      (5)
++
++/* SNR operating margin register */
++#define PMA_PMD_SNR_MARGIN_0  (133)
++#define PMA_PMD_SNR_MARGIN_1  (134)
++#define PMA_PMD_SNR_MARGIN_2  (135)
++#define PMA_PMD_SNR_MARGIN_3  (136)
++
++/* Extended control register */
++#define       PMA_PMD_XCONTROL_REG 0xc000
++#define       PMA_PMD_LNPGA_POWERDOWN_LBN 8
++#define       PMA_PMD_LNPGA_POWERDOWN_WIDTH 1
++#define       PMA_PMD_AFE_POWERDOWN_LBN 9
++#define       PMA_PMD_AFE_POWERDOWN_WIDTH 1
++#define       PMA_PMD_DSP_POWERDOWN_LBN 10
++#define       PMA_PMD_DSP_POWERDOWN_WIDTH 1
++#define       PMA_PMD_PHY_POWERDOWN_LBN 11
++#define       PMA_PMD_PHY_POWERDOWN_WI
++
++/* extended status register */
++#define PMA_PMD_XSTATUS_REG 0xc001
++#define PMA_PMD_XSTAT_FLP_LBN   (12)
++
++
++/* LED control register */
++#define PMA_PMD_LED_CTRL_REG  (0xc007)
++#define PMA_PMA_LED_ACTIVITY_LBN      (3)
++
++/* LED function override register */
++#define PMA_PMD_LED_OVERR_REG (0xc009)
++/* Bit positions for different LEDs (there are more but not wired on SFE4001)*/
++#define PMA_PMD_LED_LINK_LBN  (0)
++#define PMA_PMD_LED_SPEED_LBN (2)
++#define PMA_PMD_LED_TX_LBN    (4)
++#define PMA_PMD_LED_RX_LBN    (6)
++/* Override settings */
++#define       PMA_PMD_LED_AUTO        (0)     /* H/W control */
++#define       PMA_PMD_LED_ON          (1)
++#define       PMA_PMD_LED_OFF         (2)
++#define PMA_PMD_LED_FLASH     (3)
++/* All LEDs under hardware control */
++#define PMA_PMD_LED_FULL_AUTO (0)
++/* Green and Amber under hardware control, Red off */
++#define PMA_PMD_LED_DEFAULT   (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN)
++
++
++/* Self test (BIST) control register */
++#define PMA_PMD_BIST_CTRL_REG (0xc014)
++#define PMA_PMD_BIST_BER_LBN  (2)     /* Run BER test */
++#define PMA_PMD_BIST_CONT_LBN (1)     /* Run continuous BIST until cleared */
++#define PMA_PMD_BIST_SINGLE_LBN       (0)     /* Run 1 BIST iteration (self clears) */
++/* Self test status register */
++#define PMA_PMD_BIST_STAT_REG (0xc015)
++#define PMA_PMD_BIST_ENX_LBN  (3)
++#define PMA_PMD_BIST_PMA_LBN  (2)
++#define PMA_PMD_BIST_RXD_LBN  (1)
++#define PMA_PMD_BIST_AFE_LBN  (0)
++
++/* Special Software reset register */
++#define PMA_PMD_EXT_CTRL_REG 49152
++#define PMA_PMD_EXT_SSR_LBN 15
++
++#define BIST_MAX_DELAY        (1000)
++#define BIST_POLL_DELAY       (10)
++
++static const char *bist_names[] = {
++      [PMA_PMD_BIST_AFE_LBN] = "AFE communication",
++      [PMA_PMD_BIST_RXD_LBN] = "RX data path",
++      [PMA_PMD_BIST_PMA_LBN] = "PMA loopback",
++      [PMA_PMD_BIST_ENX_LBN] = "ENX"
++};
++
++/* Identifier registers: each identifier has 4 part number and 2 revision
++ * registers starting at one of these addresses */
++#define PMA_PMD_AFE_ID_REG      49174
++#define PMA_PMD_DSP_ID_REG      49180
++#define PMA_PMD_FIRMWARE_ID_REG 49186
++
++/* Misc register defines */
++#define PCS_CLOCK_CTRL_REG 0xd801
++#define PLL312_RST_N_LBN 2
++
++#define PCS_SOFT_RST2_REG 0xd806
++#define SERDES_RST_N_LBN 13
++#define XGXS_RST_N_LBN 12
++
++#define       PCS_TEST_SELECT_REG 0xd807      /* PRM 10.5.8 */
++#define       CLK312_EN_LBN 3
++
++/* PHYXS registers */
++#define PHYXS_TEST1         (49162)
++#define LOOPBACK_NEAR_LBN   (8)
++#define LOOPBACK_NEAR_WIDTH (1)
++
++/* Boot status register */
++#define PCS_BOOT_STATUS_REG   (0xd000)
++#define PCS_BOOT_FATAL_ERR_LBN        (0)
++#define PCS_BOOT_PROGRESS_LBN (1)
++#define PCS_BOOT_PROGRESS_WIDTH       (2)
++#define PCS_BOOT_COMPLETE_LBN (3)
++
++#define PCS_BOOT_MAX_DELAY    (100)
++#define PCS_BOOT_POLL_DELAY   (10)
++
++#define TENXPRESS_ID_PN_LEN     (8)
++#define TENXPRESS_ID_REV_LEN    (4)
++#define TENXPRESS_ID_LEN        (TENXPRESS_ID_PN_LEN+1+TENXPRESS_ID_REV_LEN)
++
++static const int bist_max = ARRAY_SIZE(bist_names);
++
++/* Time to wait between powering down the LNPGA and turning off the power
++ * rails */
++#define LNPGA_PDOWN_WAIT      (HZ / 5)
++
++
++static int crc_error_reset_threshold = 100;
++module_param(crc_error_reset_threshold, int, 0644);
++MODULE_PARM_DESC(crc_error_reset_threshold,
++               "Max number of CRC errors before XAUI reset");
++
++struct tenxpress_phy_data {
++#ifdef CONFIG_SFC_DEBUGFS
++      char phy_snr[4];
++      char phy_afe_id[TENXPRESS_ID_LEN + 1];
++      char phy_dsp_id[TENXPRESS_ID_LEN + 1];
++      char phy_firmware_id[TENXPRESS_ID_LEN + 1];
++      struct efx_nic *efx;
++#endif
++      enum tenxpress_state state;
++      enum efx_loopback_mode loopback_mode;
++      atomic_t bad_crc_count;
++      int phy_powered;
++      int tx_disabled;
++      int bad_lp_tries;
++};
++
++static int tenxpress_state_is(struct efx_nic *efx, int state)
++{
++      struct tenxpress_phy_data *phy_data = efx->phy_data;
++      return (phy_data != NULL) && (state == phy_data->state);
++}
++
++void tenxpress_set_state(struct efx_nic *efx,
++                              enum tenxpress_state state)
++{
++      struct tenxpress_phy_data *phy_data = efx->phy_data;
++      if (phy_data != NULL)
++              phy_data->state = state;
++}
++
++void tenxpress_crc_err(struct efx_nic *efx)
++{
++      struct tenxpress_phy_data *phy_data = efx->phy_data;
++      if (phy_data != NULL)
++              atomic_inc(&phy_data->bad_crc_count);
++}
++
++#ifdef CONFIG_SFC_DEBUGFS
++
++/* debugfs entries for this PHY */
++static int tenxpress_ber_read(struct seq_file *file, void *data)
++{
++      struct efx_nic *efx = *(struct efx_nic **)data;
++      int reg, ber;
++
++      reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PCS,
++                               MDIO_PCS_10GBT_STATUS2);
++
++      /* Extract the BER */
++      ber = (reg >> MDIO_PCS_10GBT_STATUS2_BER_LBN) &
++              ((1 << MDIO_PCS_10GBT_STATUS2_BER_WIDTH) - 1);
++
++      return seq_printf(file, "%d", ber);
++}
++
++
++static int tenxpress_snr_read(struct seq_file *file, void *data)
++{
++      struct tenxpress_phy_data *phy_data = NULL;
++      struct efx_nic *efx;
++      int lane = *(char *) data;
++      int reg, snr;
++
++      EFX_BUG_ON_PARANOID(lane < 0 || lane >= 4);
++      phy_data = container_of(data, struct tenxpress_phy_data, phy_snr[lane]);
++      efx = phy_data->efx;
++
++      reg = mdio_clause45_read(efx, efx->mii.phy_id,
++                               MDIO_MMD_PMAPMD, PMA_PMD_SNR_MARGIN_0 + lane);
++
++      /* Convert from SNR margin to SNR to match phychk output */
++      snr = (reg - 0x8000 + 238);
++
++      return seq_printf(file, "%d.%d", snr / 10, snr % 10);
++}
++
++
++static struct efx_debugfs_parameter debug_entries[] = {
++      EFX_PER_LANE_PARAMETER("phy_lane", "_snr",
++                             struct tenxpress_phy_data, phy_snr, char,
++                             tenxpress_snr_read),
++      EFX_NAMED_PARAMETER(phy_ber, struct tenxpress_phy_data, efx,
++                          struct efx_nic *, tenxpress_ber_read),
++      EFX_STRING_PARAMETER(struct tenxpress_phy_data, phy_afe_id),
++      EFX_STRING_PARAMETER(struct tenxpress_phy_data, phy_dsp_id),
++      EFX_STRING_PARAMETER(struct tenxpress_phy_data, phy_firmware_id),
++      {NULL}
++};
++
++static void tenxpress_phy_get_id(struct efx_nic *efx,
++                               char *id_buf, int id_addr)
++{
++      int i, reg;
++      char ch;
++
++      for (i = TENXPRESS_ID_PN_LEN / 2 - 1; i >= 0; --i) {
++              reg = mdio_clause45_read(efx, efx->mii.phy_id,
++                                       MDIO_MMD_PMAPMD, id_addr + i);
++              ch = reg & 0xFF;
++              *id_buf++ = ch ? ch : ' ';
++              ch = (reg & 0xFF00) >> 8;
++              *id_buf++ = ch ? ch : ' ';
++      }
++      *id_buf++ = ' ';
++      for (i = TENXPRESS_ID_REV_LEN / 2 - 1; i >= 0; --i) {
++              reg = mdio_clause45_read(efx, efx->mii.phy_id,
++                                       MDIO_MMD_PMAPMD,
++                                       id_addr + TENXPRESS_ID_PN_LEN / 2 + i);
++              ch = reg & 0xFF;
++              *id_buf++ = ch ? ch : ' ';
++              ch = (reg & 0xFF00) >> 8;
++              *id_buf++ = ch ? ch : ' ';
++      }
++}
++
++static int tenxpress_debugfs_init(struct efx_nic *efx)
++{
++      struct tenxpress_phy_data *phy_data = efx->phy_data;
++      int lane, rc;
++
++      for (lane = 0; lane < 4; lane++)
++              phy_data->phy_snr[lane] = lane;
++
++      phy_data->efx = efx;
++      rc = efx_extend_debugfs_port(efx, efx->phy_data,
++                                   debug_entries);
++      if (rc < 0)
++              return rc;
++
++      tenxpress_phy_get_id(efx, phy_data->phy_afe_id,
++                           PMA_PMD_AFE_ID_REG);
++      tenxpress_phy_get_id(efx, phy_data->phy_dsp_id,
++                           PMA_PMD_DSP_ID_REG);
++      tenxpress_phy_get_id(efx, phy_data->phy_firmware_id,
++                           PMA_PMD_FIRMWARE_ID_REG);
++
++      return 0;
++}
++
++#endif /* CONFIG_SFC_DEBUGFS */
++
++/* Check that the C166 has booted successfully */
++static int tenxpress_phy_check(struct efx_nic *efx)
++{
++      int phy_id = efx->mii.phy_id;
++      int count = PCS_BOOT_MAX_DELAY / PCS_BOOT_POLL_DELAY;
++      int boot_stat;
++
++      /* Wait for the boot to complete (or not) */
++      while (count) {
++              boot_stat = mdio_clause45_read(efx, phy_id,
++                                             MDIO_MMD_PCS,
++                                             PCS_BOOT_STATUS_REG);
++              if (boot_stat & (1 << PCS_BOOT_COMPLETE_LBN))
++                      break;
++              count--;
++              udelay(PCS_BOOT_POLL_DELAY);
++      }
++
++      if (!count) {
++              EFX_ERR(efx, "%s: PHY boot timed out. Last status "
++                      "%x\n", __func__,
++                      (boot_stat >> PCS_BOOT_PROGRESS_LBN) &
++                      ((1 << PCS_BOOT_PROGRESS_WIDTH) - 1));
++              return -ETIMEDOUT;
++      }
++
++      return 0;
++}
++
++static void tenxpress_reset_xaui(struct efx_nic *efx);
++
++/* Initialise the part post power on reset or software special reset */
++static int tenxpress_init(struct efx_nic *efx)
++{
++      int rc, reg;
++
++      /* Turn on the clock  */
++      reg = (1 << CLK312_EN_LBN);
++      mdio_clause45_write(efx, efx->mii.phy_id,
++                          MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg);
++
++      rc = tenxpress_phy_check(efx);
++      if (rc < 0)
++              return rc;
++
++      /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
++      reg = mdio_clause45_read(efx, efx->mii.phy_id,
++                               MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG);
++      reg |= (1 << PMA_PMA_LED_ACTIVITY_LBN);
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
++                          PMA_PMD_LED_CTRL_REG, reg);
++
++      reg = PMA_PMD_LED_DEFAULT;
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
++                          PMA_PMD_LED_OVERR_REG, reg);
++
++      return rc;
++}
++
++static int tenxpress_phy_init(struct efx_nic *efx)
++{
++      struct tenxpress_phy_data *phy_data;
++      int rc = 0;
++
++      phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
++      efx->phy_data = phy_data;
++      phy_data->phy_powered = efx->phy_powered;
++
++      tenxpress_set_state(efx, TENXPRESS_STATUS_NORMAL);
++
++      rc = mdio_clause45_wait_reset_mmds(efx,
++                                         TENXPRESS_REQUIRED_DEVS);
++      if (rc < 0)
++              goto fail;
++
++      rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0);
++      if (rc < 0)
++              goto fail;
++
++      rc = tenxpress_init(efx);
++      if (rc < 0)
++              goto fail;
++
++#ifdef CONFIG_SFC_DEBUGFS
++      rc = tenxpress_debugfs_init(efx);
++      if (rc < 0)
++              goto fail;
++#endif
++
++      schedule_timeout_uninterruptible(HZ / 5); /* 200ms */
++
++      /* Let XGXS and SerDes out of reset and resets 10XPress */
++      falcon_reset_xaui(efx);
++
++      return 0;
++
++ fail:
++      kfree(efx->phy_data);
++      efx->phy_data = NULL;
++      return rc;
++}
++
++static int tenxpress_special_reset(struct efx_nic *efx)
++{
++      int rc, reg;
++
++      EFX_TRACE(efx, "%s\n", __func__);
++
++      /* Initiate reset */
++      reg = mdio_clause45_read(efx, efx->mii.phy_id,
++                               MDIO_MMD_PMAPMD, PMA_PMD_EXT_CTRL_REG);
++      reg |= (1 << PMA_PMD_EXT_SSR_LBN);
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
++                          PMA_PMD_EXT_CTRL_REG, reg);
++
++      msleep(200);
++
++      /* Wait for the blocks to come out of reset */
++      rc = mdio_clause45_wait_reset_mmds(efx,
++                                         TENXPRESS_REQUIRED_DEVS);
++      if (rc < 0)
++              return rc;
++
++      /* Try and reconfigure the device */
++      rc = tenxpress_init(efx);
++      if (rc < 0)
++              return rc;
++
++      return 0;
++}
++
++static void tenxpress_set_bad_lp(struct efx_nic *efx, int bad_lp)
++{
++      struct tenxpress_phy_data *pd = efx->phy_data;
++      int reg;
++
++      /* Nothing to do if all is well and was previously so. */
++      if (!(bad_lp || pd->bad_lp_tries))
++              return;
++
++      reg = mdio_clause45_read(efx, efx->mii.phy_id,
++                               MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG);
++
++      if (bad_lp)
++              pd->bad_lp_tries++;
++      else
++              pd->bad_lp_tries = 0;
++
++      if (pd->bad_lp_tries == MAX_BAD_LP_TRIES) {
++              pd->bad_lp_tries = 0;   /* Restart count */
++              reg &= ~(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
++              reg |= (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN);
++              EFX_ERR(efx, "This NIC appears to be plugged into"
++                      " a port that is not 10GBASE-T capable.\n"
++                      " This PHY is 10GBASE-T ONLY, so no link can"
++                      " be established.\n");
++      } else {
++              reg |= (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN);
++      }
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
++                          PMA_PMD_LED_OVERR_REG, reg);
++}
++
++/* Check link status and return a boolean OK value. If the link is NOT
++ * OK we have a quick rummage round to see if we appear to be plugged
++ * into a non-10GBT port and if so warn the user that they won't get
++ * link any time soon as we are 10GBT only, unless caller specified
++ * not to do this check (it isn't useful in loopback) */
++static int tenxpress_link_ok(struct efx_nic *efx, int check_lp)
++{
++      int ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS);
++
++      if (ok) {
++              tenxpress_set_bad_lp(efx, 0);
++      } else if (check_lp) {
++              /* Are we plugged into the wrong sort of link? */
++              int bad_lp = 0;
++              int phy_id = efx->mii.phy_id;
++              int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN,
++                                               MDIO_AN_STATUS);
++              int xphy_stat = mdio_clause45_read(efx, phy_id,
++                                                 MDIO_MMD_PMAPMD,
++                                                 PMA_PMD_XSTATUS_REG);
++              /* Are we plugged into anything that sends FLPs? If
++               * not we can't distinguish between not being plugged
++               * in and being plugged into a non-AN antique. The FLP
++               * bit has the advantage of not clearing when autoneg
++               * restarts. */
++              if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) {
++                      tenxpress_set_bad_lp(efx, 0);
++                      return ok;
++              }
++
++              /* If it can do 10GBT it must be XNP capable */
++              bad_lp = !(an_stat & (1 << MDIO_AN_STATUS_XNP_LBN));
++              if (!bad_lp && (an_stat & (1 << MDIO_AN_STATUS_PAGE_LBN))) {
++                      bad_lp = !(mdio_clause45_read(efx, phy_id,
++                                      MDIO_MMD_AN, MDIO_AN_10GBT_STATUS) &
++                                      (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN));
++              }
++              tenxpress_set_bad_lp(efx, bad_lp);
++      }
++      return ok;
++}
++
++static void tenxpress_phyxs_loopback(struct efx_nic *efx)
++{
++      int phy_id = efx->mii.phy_id;
++      int ctrl1, ctrl2;
++
++      ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS,
++                                         PHYXS_TEST1);
++      if (efx->loopback_mode == LOOPBACK_PHYXS)
++              ctrl2 |= (1 << LOOPBACK_NEAR_LBN);
++      else
++              ctrl2 &= ~(1 << LOOPBACK_NEAR_LBN);
++      if (ctrl1 != ctrl2)
++              mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS,
++                                  PHYXS_TEST1, ctrl2);
++}
++
++static void tenxpress_phy_reconfigure(struct efx_nic *efx)
++{
++      struct tenxpress_phy_data *phy_data = efx->phy_data;
++      int loop_change = LOOPBACK_OUT_OF(phy_data, efx,
++                                        TENXPRESS_LOOPBACKS);
++
++      if (!tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL))
++              return;
++
++      /* When coming out of transmit disable, coming out of low power
++       * mode, or moving out of any PHY internal loopback mode,
++       * perform a special software reset */
++      if (((efx->phy_powered && !efx->tx_disabled) &&
++           (!phy_data->phy_powered || phy_data->tx_disabled)) ||
++          loop_change) {
++              (void) tenxpress_special_reset(efx);
++              falcon_reset_xaui(efx);
++      }
++
++      mdio_clause45_transmit_disable(efx, efx->tx_disabled);
++      mdio_clause45_phy_reconfigure(efx);
++      tenxpress_phyxs_loopback(efx);
++
++      phy_data->tx_disabled = efx->tx_disabled;
++      phy_data->loopback_mode = efx->loopback_mode;
++      phy_data->phy_powered = efx->phy_powered;
++      efx->link_up = tenxpress_link_ok(efx, 0);
++      efx->link_options = GM_LPA_10000FULL;
++}
++
++static void tenxpress_phy_clear_interrupt(struct efx_nic *efx)
++{
++      /* Nothing done here - LASI interrupts aren't reliable so poll  */
++}
++
++
++/* Poll PHY for interrupt */
++static int tenxpress_phy_check_hw(struct efx_nic *efx)
++{
++      struct tenxpress_phy_data *phy_data = efx->phy_data;
++      int phy_up = tenxpress_state_is(efx, TENXPRESS_STATUS_NORMAL);
++      int link_ok, rc = 0;
++
++      link_ok = phy_up && tenxpress_link_ok(efx, 1);
++
++      if (link_ok != efx->link_up) {
++              efx->link_up = link_ok;
++              efx->mac_op->fake_phy_event(efx);
++      }
++
++      /* Nothing to check if we've already shut down the PHY */
++      if (!phy_up)
++              return 0;
++
++      if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) {
++              EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n");
++              falcon_reset_xaui(efx);
++              atomic_set(&phy_data->bad_crc_count, 0);
++      }
++
++      rc = efx->board_info.monitor(efx);
++      if (rc)
++              efx->link_up = 0;
++
++      return rc;
++}
++
++static void tenxpress_phy_fini(struct efx_nic *efx)
++{
++      int reg;
++
++#ifdef CONFIG_SFC_DEBUGFS
++      efx_trim_debugfs_port(efx, debug_entries);
++#endif
++      /* Power down the LNPGA */
++      reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN);
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
++                          PMA_PMD_XCONTROL_REG, reg);
++
++      /* Waiting here ensures that the board fini, which can turn off the
++       * power to the PHY, won't get run until the LNPGA powerdown has been
++       * given long enough to complete. */
++      schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */
++
++      kfree(efx->phy_data);
++      efx->phy_data = NULL;
++}
++
++
++/* Set the RX and TX LEDs and Link LED flashing. The other LEDs
++ * (which probably aren't wired anyway) are left in AUTO mode */
++void tenxpress_phy_blink(struct efx_nic *efx, int blink)
++{
++      int reg;
++
++      if (blink)
++              reg = (PMA_PMD_LED_FLASH << PMA_PMD_LED_TX_LBN) |
++                      (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN) |
++                      (PMA_PMD_LED_FLASH << PMA_PMD_LED_LINK_LBN);
++      else
++              reg = PMA_PMD_LED_DEFAULT;
++
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
++                          PMA_PMD_LED_OVERR_REG, reg);
++}
++
++static void tenxpress_reset_xaui(struct efx_nic *efx)
++{
++      int phy = efx->mii.phy_id;
++      int clk_ctrl, test_select, soft_rst2;
++
++      /* Real work is done on clock_ctrl other resets are thought to be
++       * optional but make the reset more reliable
++       */
++
++      /* Read */
++      clk_ctrl = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
++                                    PCS_CLOCK_CTRL_REG);
++      test_select = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
++                                       PCS_TEST_SELECT_REG);
++      soft_rst2 = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
++                                     PCS_SOFT_RST2_REG);
++
++      /* Modify => put in reset */
++      test_select &= ~(1 << CLK312_EN_LBN);
++      mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
++                          PCS_TEST_SELECT_REG, test_select);
++
++      soft_rst2 &= ~((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
++      mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
++                          PCS_SOFT_RST2_REG, soft_rst2);
++
++      clk_ctrl &= ~(1 << PLL312_RST_N_LBN);
++      mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
++                          PCS_CLOCK_CTRL_REG, clk_ctrl);
++      udelay(10);
++
++      /* Modify => remove reset */
++      clk_ctrl |= (1 << PLL312_RST_N_LBN);
++      mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
++                          PCS_CLOCK_CTRL_REG, clk_ctrl);
++      udelay(10);
++
++      soft_rst2 |= ((1 << XGXS_RST_N_LBN) | (1 << SERDES_RST_N_LBN));
++      mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
++                          PCS_SOFT_RST2_REG, soft_rst2);
++      udelay(10);
++
++      test_select |= (1 << CLK312_EN_LBN);
++      mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
++                          PCS_TEST_SELECT_REG, test_select);
++      udelay(10);
++}
++
++
++struct efx_phy_operations falcon_tenxpress_phy_ops = {
++      .init             = tenxpress_phy_init,
++      .reconfigure      = tenxpress_phy_reconfigure,
++      .check_hw         = tenxpress_phy_check_hw,
++      .fini             = tenxpress_phy_fini,
++      .clear_interrupt  = tenxpress_phy_clear_interrupt,
++      .reset_xaui       = tenxpress_reset_xaui,
++      .mmds             = TENXPRESS_REQUIRED_DEVS,
++      .loopbacks        = TENXPRESS_LOOPBACKS,
++      .startup_loopback = LOOPBACK_PCS,
++};
+--- linux-2.6.18.8/drivers/net/sfc/tx.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/tx.c   2008-05-19 00:33:29.453843880 +0300
+@@ -0,0 +1,522 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2005-2006: Fen Systems Ltd.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include <linux/pci.h>
++#include <linux/tcp.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++#include <linux/if_ether.h>
++#include <linux/version.h>
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++#include <linux/highmem.h>
++#endif
++#include "net_driver.h"
++#include "tx.h"
++#include "efx.h"
++#include "falcon.h"
++#include "workarounds.h"
++
++
++/*
++ * TX descriptor ring full threshold
++ *
++ * The tx_queue descriptor ring fill-level must fall below this value
++ * before we restart the netif queue
++ */
++#define EFX_NETDEV_TX_THRESHOLD(_tx_queue)    \
++      (_tx_queue->efx->type->txd_ring_mask / 2u)
++
++
++
++/* We want to be able to nest calls to netif_stop_queue(), since each
++ * channel can have an individual stop on the queue.
++ */
++void efx_stop_queue(struct efx_nic *efx)
++{
++      spin_lock_bh(&efx->netif_stop_lock);
++      EFX_TRACE(efx, "stop TX queue\n");
++
++      atomic_inc(&efx->netif_stop_count);
++      if (likely(efx->net_dev_registered))
++              netif_stop_queue(efx->net_dev);
++
++      spin_unlock_bh(&efx->netif_stop_lock);
++}
++
++/* Wake netif's TX queue
++ * We want to be able to nest calls to netif_stop_queue(), since each
++ * channel can have an individual stop on the queue.
++ */
++inline void efx_wake_queue(struct efx_nic *efx)
++{
++      local_bh_disable();
++      if (atomic_dec_and_lock(&efx->netif_stop_count,
++                              &efx->netif_stop_lock)) {
++              EFX_TRACE(efx, "waking TX queue\n");
++              if (likely(efx->net_dev_registered))
++                      netif_wake_queue(efx->net_dev);
++              spin_unlock(&efx->netif_stop_lock);
++      }
++      local_bh_enable();
++}
++
++/*
++ * Add a socket buffer to a TX queue
++ *
++ * This maps all fragments of a socket buffer for DMA and adds them to
++ * the TX queue.  The queue's insert pointer will be incremented by
++ * the number of fragments in the socket buffer.
++ *
++ * If any DMA mapping fails, any mapped fragments will be unmapped,
++ * the queue's insert pointer will be restored to its original value.
++ *
++ * Returns NETDEV_TX_OK or NETDEV_TX_BUSY
++ * You must hold netif_tx_lock() to call this function.
++ */
++static inline int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
++                                const struct sk_buff *skb)
++{
++      struct efx_nic *efx = tx_queue->efx;
++      struct pci_dev *pci_dev = efx->pci_dev;
++      struct efx_tx_buffer *buffer;
++      skb_frag_t *fragment;
++      struct page *page;
++      int page_offset;
++      unsigned int len, unmap_len = 0, fill_level, insert_ptr, misalign;
++      dma_addr_t dma_addr, unmap_addr = 0;
++      unsigned int dma_len;
++      unsigned unmap_single;
++      int q_space, i = 0;
++      int rc = NETDEV_TX_OK;
++
++      EFX_BUG_ON_PARANOID(tx_queue->write_count != tx_queue->insert_count);
++
++      /* Get size of the initial fragment */
++      len = skb_headlen(skb);
++
++      fill_level = tx_queue->insert_count - tx_queue->old_read_count;
++      q_space = efx->type->txd_ring_mask - 1 - fill_level;
++
++      /* Map for DMA.  Use pci_map_single rather than pci_map_page
++       * since this is more efficient on machines with sparse
++       * memory.
++       */
++      unmap_single = 1;
++      dma_addr = pci_map_single(pci_dev, skb->data, len, PCI_DMA_TODEVICE);
++
++      /* Process all fragments */
++      while (1) {
++              if (unlikely(pci_dma_mapping_error(dma_addr)))
++                      goto pci_err;
++
++              /* Store fields for marking in the per-fragment final
++               * descriptor */
++              unmap_len = len;
++              unmap_addr = dma_addr;
++
++              /* Add to TX queue, splitting across DMA boundaries */
++              do {
++                      if (unlikely(q_space-- <= 0)) {
++                              /* It might be that completions have
++                               * happened since the xmit path last
++                               * checked.  Update the xmit path's
++                               * copy of read_count.
++                               */
++                              ++tx_queue->stopped;
++                              /* This memory barrier protects the
++                               * change of stopped from the access
++                               * of read_count. */
++                              smp_mb();
++                              tx_queue->old_read_count =
++                                      *(volatile unsigned *)
++                                      &tx_queue->read_count;
++                              fill_level = (tx_queue->insert_count
++                                            - tx_queue->old_read_count);
++                              q_space = (efx->type->txd_ring_mask - 1 -
++                                         fill_level);
++                              if (unlikely(q_space-- <= 0))
++                                      goto stop;
++                              smp_mb();
++                              --tx_queue->stopped;
++                      }
++
++                      insert_ptr = (tx_queue->insert_count &
++                                    efx->type->txd_ring_mask);
++                      buffer = &tx_queue->buffer[insert_ptr];
++                      EFX_BUG_ON_PARANOID(buffer->skb);
++                      EFX_BUG_ON_PARANOID(buffer->len);
++                      EFX_BUG_ON_PARANOID(buffer->continuation != 1);
++                      EFX_BUG_ON_PARANOID(buffer->unmap_len);
++
++                      dma_len = (((~dma_addr) & efx->type->tx_dma_mask) + 1);
++                      if (likely(dma_len > len))
++                              dma_len = len;
++
++                      misalign = (unsigned)dma_addr & efx->type->bug5391_mask;
++                      if (misalign && dma_len + misalign > 512)
++                              dma_len = 512 - misalign;
++
++                      /* Fill out per descriptor fields */
++                      buffer->len = dma_len;
++                      buffer->dma_addr = dma_addr;
++                      len -= dma_len;
++                      dma_addr += dma_len;
++                      ++tx_queue->insert_count;
++              } while (len);
++
++              /* Transfer ownership of the unmapping to the final buffer */
++              buffer->unmap_addr = unmap_addr;
++              buffer->unmap_single = unmap_single;
++              buffer->unmap_len = unmap_len;
++              unmap_len = 0;
++
++              /* Get address and size of next fragment */
++              if (i >= skb_shinfo(skb)->nr_frags)
++                      break;
++              fragment = &skb_shinfo(skb)->frags[i];
++              len = fragment->size;
++              page = fragment->page;
++              page_offset = fragment->page_offset;
++              i++;
++              /* Map for DMA */
++              unmap_single = 0;
++              dma_addr = pci_map_page(pci_dev, page, page_offset, len,
++                                      PCI_DMA_TODEVICE);
++      }
++
++      /* Transfer ownership of the skb to the final buffer */
++      buffer->skb = skb;
++      buffer->continuation = 0;
++
++      /* Pass off to hardware */
++      falcon_push_buffers(tx_queue);
++
++      return NETDEV_TX_OK;
++
++ pci_err:
++      EFX_ERR_RL(efx, " TX queue %d could not map skb with %d bytes %d "
++                 "fragments for DMA\n", tx_queue->queue, skb->len,
++                 skb_shinfo(skb)->nr_frags + 1);
++
++      /* Mark the packet as transmitted, and free the SKB ourselves */
++      dev_kfree_skb_any((struct sk_buff *)skb);
++      goto unwind;
++
++ stop:
++      rc = NETDEV_TX_BUSY;
++
++      /* Stop the queue if it wasn't stopped before. */
++      if (tx_queue->stopped == 1)
++              efx_stop_queue(efx);
++
++ unwind:
++      /* Work backwards until we hit the original insert pointer value */
++      while (tx_queue->insert_count != tx_queue->write_count) {
++              --tx_queue->insert_count;
++              insert_ptr = tx_queue->insert_count & efx->type->txd_ring_mask;
++              buffer = &tx_queue->buffer[insert_ptr];
++              if (buffer->unmap_len) {
++                      if (buffer->unmap_single)
++                              pci_unmap_single(pci_dev, buffer->unmap_addr,
++                                               buffer->unmap_len,
++                                               PCI_DMA_TODEVICE);
++                      else
++                              pci_unmap_page(pci_dev, buffer->unmap_addr,
++                                             buffer->unmap_len,
++                                             PCI_DMA_TODEVICE);
++              }
++              buffer->unmap_len = 0;
++              buffer->len = 0;
++      }
++
++      /* Free the fragment we were mid-way through pushing */
++      if (unmap_len)
++              pci_unmap_page(pci_dev, unmap_addr, unmap_len,
++                             PCI_DMA_TODEVICE);
++
++      return rc;
++}
++
++/* Remove packets from the TX queue
++ *
++ * This removes packets from the TX queue, up to and including the
++ * specified index.
++ */
++static inline void efx_dequeue_buffers(struct efx_tx_queue *tx_queue,
++                                     unsigned int index)
++{
++      struct pci_dev *pci_dev = tx_queue->efx->pci_dev;
++      struct efx_tx_buffer *buffer;
++      unsigned int stop_index, read_ptr;
++
++      /* Calculate the stopping point.  Doing the check this way
++       * avoids wrongly completing every buffer in the ring if we
++       * get called twice with the same index.  (Hardware should
++       * never do this, since it can't complete that many buffers in
++       * one go.)
++       */
++      stop_index = (index + 1) & tx_queue->efx->type->txd_ring_mask;
++      read_ptr = tx_queue->read_count & tx_queue->efx->type->txd_ring_mask;
++
++      while (read_ptr != stop_index) {
++              buffer = &tx_queue->buffer[read_ptr];
++              if (unlikely(buffer->len == 0)) {
++                      EFX_ERR(tx_queue->efx, "TX queue %d spurious TX "
++                              "completion id %x\n", tx_queue->queue,
++                              read_ptr);
++                      atomic_inc(&tx_queue->efx->errors.spurious_tx);
++                      /* Don't reset */
++              } else {
++                      if (buffer->unmap_len) {
++                              if (buffer->unmap_single)
++                                      pci_unmap_single(pci_dev,
++                                                       buffer->unmap_addr,
++                                                       buffer->unmap_len,
++                                                       PCI_DMA_TODEVICE);
++                              else
++                                      pci_unmap_page(pci_dev,
++                                                     buffer->unmap_addr,
++                                                     buffer->unmap_len,
++                                                     PCI_DMA_TODEVICE);
++                              buffer->unmap_single = 0;
++                              buffer->unmap_len = 0;
++                      }
++                      if (buffer->skb) {
++                              dev_kfree_skb_any((struct sk_buff *)
++                                                buffer->skb);
++                              buffer->skb = NULL;
++                              EFX_TRACE(tx_queue->efx, "TX queue %d "
++                                        "transmission id %x complete\n",
++                                        tx_queue->queue, read_ptr);
++                      }
++                      buffer->continuation = 1;
++                      buffer->len = 0;
++              }
++              ++tx_queue->read_count;
++              read_ptr = (tx_queue->read_count &
++                          tx_queue->efx->type->txd_ring_mask);
++      }
++}
++
++/* Initiate a packet transmission on the specified TX queue.
++ * Note that returning anything other than NETDEV_TX_OK will cause the
++ * OS to free the skb.
++ *
++ * This function is split out from efx_hard_start_xmit to allow the
++ * loopback test to direct packets via specific TX queues.  It is
++ * therefore a non-static inline, so as not to penalise performance
++ * for non-loopback transmissions.
++ *
++ * Context: netif_tx_lock held
++ */
++inline int efx_xmit(struct efx_nic *efx,
++                  struct efx_tx_queue *tx_queue, struct sk_buff *skb)
++{
++      int rc;
++
++      /* Map fragments for DMA and add to TX queue */
++      rc = efx_enqueue_skb(tx_queue, skb);
++      if (unlikely(rc != NETDEV_TX_OK))
++              goto out;
++
++      /* Update last TX timer */
++      efx->net_dev->trans_start = jiffies;
++
++ out:
++      return rc;
++}
++
++/* Initiate a packet transmission.  We use one channel per CPU
++ * (sharing when we have more CPUs than channels).  On Falcon, the TX
++ * completion events will be directed back to the CPU that transmitted
++ * the packet, which should be cache-efficient.
++ *
++ * Context: non-blocking.
++ * Note that returning anything other than NETDEV_TX_OK will cause the
++ * OS to free the skb.
++ */
++int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
++{
++      struct efx_nic *efx = net_dev->priv;
++      struct efx_tx_queue *tx_queue;
++      enum efx_veto veto;
++      int rc = NETDEV_TX_OK;
++
++      /* We have one TX queue. */
++      tx_queue = &efx->tx_queue[0];
++
++      /* See if driverlink wants to veto the packet. */
++      veto = EFX_DL_CALLBACK(efx, tx_packet, skb);
++      if (unlikely(veto)) {
++              EFX_LOG(efx, "TX queue %d packet vetoed by "
++                      "driverlink %s driver\n", tx_queue->queue,
++                      efx->dl_cb_dev.tx_packet->driver->name);
++              /* Free the skb; nothing else will do it */
++              dev_kfree_skb_any((struct sk_buff *)skb);
++              goto out;
++      }
++
++      rc = efx_xmit(efx, tx_queue, skb);
++out:
++      return rc;
++}
++
++#if defined(EFX_USE_FASTCALL)
++void fastcall efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
++#else
++void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
++#endif
++{
++      unsigned long flags __attribute__ ((unused));
++      unsigned fill_level;
++      struct efx_nic *efx = tx_queue->efx;
++
++      EFX_BUG_ON_PARANOID(index > efx->type->txd_ring_mask);
++
++      /* Remove buffers from TX queue */
++      efx_dequeue_buffers(tx_queue, index);
++
++      /* See if we need to restart the netif queue.  This barrier
++       * separates the update of read_count from the test of
++       * stopped. */
++      smp_mb();
++      if (unlikely(tx_queue->stopped)) {
++              fill_level = tx_queue->insert_count - tx_queue->read_count;
++              if (fill_level < EFX_NETDEV_TX_THRESHOLD(tx_queue)) {
++                      /* If the port is stopped and the net_dev isn't
++                       * registered, then the caller must be performing
++                       * flow control manually */
++                      if (unlikely(!efx->net_dev_registered))
++                              return;
++
++                      /* Do this under netif_tx_lock(), to avoid racing
++                       * with efx_xmit(). */
++                      netif_tx_lock(efx->net_dev);
++                      if (tx_queue->stopped) {
++                              tx_queue->stopped = 0;
++                              efx_wake_queue(efx);
++                      }
++                      netif_tx_unlock(efx->net_dev);
++              }
++      }
++}
++
++int efx_probe_tx_queue(struct efx_tx_queue *tx_queue)
++{
++      struct efx_nic *efx = tx_queue->efx;
++      unsigned int txq_size;
++      int i, rc;
++
++      EFX_LOG(efx, "creating TX queue %d\n", tx_queue->queue);
++
++      /* Allocate software ring */
++      txq_size = (efx->type->txd_ring_mask + 1) * sizeof(*tx_queue->buffer);
++      tx_queue->buffer = kzalloc(txq_size, GFP_KERNEL);
++      if (!tx_queue->buffer) {
++              rc = -ENOMEM;
++              goto fail1;
++      }
++      for (i = 0; i <= efx->type->txd_ring_mask; ++i)
++              tx_queue->buffer[i].continuation = 1;
++
++      /* Allocate hardware ring */
++      rc = falcon_probe_tx(tx_queue);
++      if (rc)
++              goto fail2;
++
++      return 0;
++
++ fail2:
++      kfree(tx_queue->buffer);
++      tx_queue->buffer = NULL;
++ fail1:
++      /* Mark queue as unused */
++      tx_queue->used = 0;
++
++      return rc;
++}
++
++int efx_init_tx_queue(struct efx_tx_queue *tx_queue)
++{
++      EFX_LOG(tx_queue->efx, "initialising TX queue %d\n", tx_queue->queue);
++
++      ASSERT_RTNL();
++
++      /* Initialise fields */
++      tx_queue->insert_count = 0;
++      tx_queue->write_count = 0;
++      tx_queue->read_count = 0;
++      tx_queue->old_read_count = 0;
++      BUG_ON(tx_queue->stopped);
++
++      /* Set up TX descriptor ring */
++      return falcon_init_tx(tx_queue);
++}
++
++void efx_release_tx_buffers(struct efx_tx_queue *tx_queue)
++{
++      unsigned int last_index, mask;
++      if (tx_queue->buffer) {
++              /* Free any buffers left in the ring */
++              mask = tx_queue->efx->type->txd_ring_mask;
++              last_index = (tx_queue->insert_count - 1) & mask;
++              EFX_LOG(tx_queue->efx, "Will dequeue up to 0x%x from 0x%x\n",
++                      last_index, tx_queue->read_count & mask);
++              efx_dequeue_buffers(tx_queue, last_index);
++      }
++}
++
++void efx_fini_tx_queue(struct efx_tx_queue *tx_queue)
++{
++      EFX_LOG(tx_queue->efx, "shutting down TX queue %d\n", tx_queue->queue);
++
++      ASSERT_RTNL();
++
++      /* Flush TX queue, remove descriptor ring */
++      falcon_fini_tx(tx_queue);
++
++      /* Release TX buffers */
++      efx_release_tx_buffers(tx_queue);
++
++      /* Release queue's stop on port, if any */
++      if (tx_queue->stopped) {
++              tx_queue->stopped = 0;
++              efx_wake_queue(tx_queue->efx);
++      }
++}
++
++void efx_remove_tx_queue(struct efx_tx_queue *tx_queue)
++{
++      EFX_LOG(tx_queue->efx, "destroying TX queue %d\n", tx_queue->queue);
++      falcon_remove_tx(tx_queue);
++
++      kfree(tx_queue->buffer);
++      tx_queue->buffer = NULL;
++      tx_queue->used = 0;
++}
++
++
+--- linux-2.6.18.8/drivers/net/sfc/tx.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/tx.h   2008-05-19 00:33:29.453843880 +0300
+@@ -0,0 +1,41 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2006:      Fen Systems Ltd.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Initially developed by Michael Brown <mbrown@fensystems.co.uk>
++ * Maintained by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef EFX_TX_H
++#define EFX_TX_H
++
++#include "net_driver.h"
++
++int efx_probe_tx_queue(struct efx_tx_queue *tx_queue);
++void efx_remove_tx_queue(struct efx_tx_queue *tx_queue);
++int efx_init_tx_queue(struct efx_tx_queue *tx_queue);
++void efx_fini_tx_queue(struct efx_tx_queue *tx_queue);
++
++int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev);
++void efx_release_tx_buffers(struct efx_tx_queue *tx_queue);
++
++#endif /* EFX_TX_H */
+--- linux-2.6.18.8/drivers/net/sfc/txc43128_phy.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/txc43128_phy.c 2008-05-19 00:33:29.453843880 +0300
+@@ -0,0 +1,725 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++/*
++ * Driver for Transwitch/Mysticom CX4 retimer
++ * see www.transwitch.com, part is TXC-43128
++ */
++
++#include <linux/delay.h>
++#include <linux/seq_file.h>
++#include "efx.h"
++#include "debugfs.h"
++#include "gmii.h"
++#include "mdio_10g.h"
++#include "xenpack.h"
++#include "phy.h"
++#include "lm87_support.h"
++#include "falcon.h"
++#include "workarounds.h"
++
++/* We expect these MMDs to be in the package */
++#define TXC_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PCS |    \
++                         MDIO_MMDREG_DEVS0_PMAPMD |   \
++                         MDIO_MMDREG_DEVS0_PHYXS)
++
++#define TXC_LOOPBACKS ((1 << LOOPBACK_PCS) |          \
++                     (1 << LOOPBACK_PMAPMD) |         \
++                     (1 << LOOPBACK_NETWORK))
++
++/**************************************************************************
++ *
++ * Compile-time config
++ *
++ **************************************************************************
++ */
++#define TXCNAME "TXC43128"
++/* Total length of time we'll wait for the PHY to come out of reset */
++#define TXC_MAX_RESET_TIME 500
++/* Interval between checks */
++#define TXC_RESET_WAIT 10
++/* How long to run BIST: At 10Gbps 50 microseconds should be plenty to get
++ * some stats */
++#define TXC_BIST_DURATION (50)
++
++#define BER_INTERVAL (10 * efx_monitor_interval)
++
++/**************************************************************************
++ *
++ * Register definitions
++ *
++ **************************************************************************
++ */
++#define XAUI_NUM_LANES (4)
++
++/*** Global register bank */
++/* Silicon ID register */
++#define TXC_GLRGS_SLID                (0xc000)
++#define TXC_GLRGS_SLID_MASK   (0x1f)
++
++/* Command register */
++#define TXC_GLRGS_GLCMD               (0xc004)
++/* Useful bits in command register */
++/* Lane power-down */
++#define TXC_GLCMD_L01PD_LBN   (5)
++#define TXC_GLCMD_L23PD_LBN   (6)
++/* Limited SW reset: preserves configuration but
++ * initiates a logic reset. Self-clearing */
++#define TXC_GLCMD_LMTSWRST_LBN        (14)
++
++/* Signal Quality Control */
++#define TXC_GLRGS_GSGQLCTL    (0xc01a)
++/* Enable bit */
++#define TXC_GSGQLCT_SGQLEN_LBN        (15)
++/* Lane selection */
++#define TXC_GSGQLCT_LNSL_LBN  (13)
++#define TXC_GSGQLCT_LNSL_WIDTH        (2)
++
++/* Signal Quality Input */
++#define TXC_GLRGS_GSGQLIN     (0xc01b)
++/*  Signal Quality Grade */
++#define TXC_GLRGS_GSGQLGRD    (0xc01c)
++/* Drift sign */
++#define TXC_GSGQLGRD_DRFTSGN_LBN (15)
++/* Grade valid flag */
++#define TXC_GSGQLGRD_GRDVAL_LBN       (14)
++/* Remaining bits are the actual grade */
++#define TXC_GSGQLGRD_GRADE_LBN        (0)
++#define TXC_GSGQLGRD_GRADE_WIDTH (14)
++
++/*  Signal Quality Drift: 16-bit drift value */
++#define TXC_GLRGS_GSGQLDRFT   (0xc01d)
++
++/**** Analog register bank */
++#define TXC_ALRGS_ATXCTL      (0xc040)
++/* Lane power-down */
++#define TXC_ATXCTL_TXPD3_LBN  (15)
++#define TXC_ATXCTL_TXPD2_LBN  (14)
++#define TXC_ATXCTL_TXPD1_LBN  (13)
++#define TXC_ATXCTL_TXPD0_LBN  (12)
++
++/* Amplitude on lanes 0, 1 */
++#define  TXC_ALRGS_ATXAMP0    (0xc041)
++/* Amplitude on lanes 2, 3 */
++#define  TXC_ALRGS_ATXAMP1    (0xc042)
++/* Bit position of value for lane 0 (or 2) */
++#define TXC_ATXAMP_LANE02_LBN (3)
++/* Bit position of value for lane 1 (or 3) */
++#define TXC_ATXAMP_LANE13_LBN (11)
++
++#define TXC_ATXAMP_1280_mV    (0)
++#define TXC_ATXAMP_1200_mV    (8)
++#define TXC_ATXAMP_1120_mV    (12)
++#define TXC_ATXAMP_1060_mV    (14)
++#define TXC_ATXAMP_0820_mV    (25)
++#define TXC_ATXAMP_0720_mV    (26)
++#define TXC_ATXAMP_0580_mV    (27)
++#define TXC_ATXAMP_0440_mV    (28)
++
++#define TXC_ATXAMP_0820_BOTH                                  \
++      ((TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE02_LBN)          \
++       | (TXC_ATXAMP_0820_mV << TXC_ATXAMP_LANE13_LBN))
++
++#define TXC_ATXAMP_DEFAULT    (0x6060) /* From databook */
++
++/* Preemphasis on lanes 0, 1 */
++#define  TXC_ALRGS_ATXPRE0    (0xc043)
++/* Preemphasis on lanes 2, 3 */
++#define  TXC_ALRGS_ATXPRE1    (0xc044)
++
++#define TXC_ATXPRE_NONE (0)
++#define TXC_ATXPRE_DEFAULT    (0x1010) /* From databook */
++
++#define TXC_ALRGS_ARXCTL      (0xc045)
++/* Lane power-down */
++#define TXC_ARXCTL_RXPD3_LBN  (15)
++#define TXC_ARXCTL_RXPD2_LBN  (14)
++#define TXC_ARXCTL_RXPD1_LBN  (13)
++#define TXC_ARXCTL_RXPD0_LBN  (12)
++
++/*** receiver control registers: Bit Error Rate measurement */
++/* Per lane BER timers */
++#define TXC_RXCTL_BERTMR0     (0xc0d4)
++#define TXC_RXCTL_BERTMR1     (0xc154)
++#define TXC_RXCTL_BERTMR2     (0xc1d4)
++#define TXC_RXCTL_BERTMR3     (0xc254)
++/* Per lane BER counters */
++#define TXC_RXCTL_BERCNT0     (0xc0d5)
++#define TXC_RXCTL_BERCNT1     (0xc155)
++#define TXC_RXCTL_BERCNT2     (0xc1d5)
++#define TXC_RXCTL_BERCNT3     (0xc255)
++
++#define BER_REG_SPACING       (TXC_RXCTL_BERTMR1 - TXC_RXCTL_BERTMR0)
++
++/*** Main user-defined register set */
++/* Main control */
++#define TXC_MRGS_CTL          (0xc340)
++/* Bits in main control */
++#define TXC_MCTL_RESET_LBN    (15)    /* Self clear */
++#define TXC_MCTL_TXLED_LBN    (14)    /* 1 to show align status */
++#define TXC_MCTL_RXLED_LBN    (13)    /* 1 to show align status */
++
++/* GPIO output */
++#define TXC_GPIO_OUTPUT               (0xc346)
++#define TXC_GPIO_DIR          (0xc348)
++
++/*** Vendor-specific BIST registers */
++#define TXC_BIST_CTL          (0xc280)
++#define TXC_BIST_TXFRMCNT     (0xc281)
++#define TXC_BIST_RX0FRMCNT    (0xc282)
++#define TXC_BIST_RX1FRMCNT    (0xc283)
++#define TXC_BIST_RX2FRMCNT    (0xc284)
++#define TXC_BIST_RX3FRMCNT    (0xc285)
++#define TXC_BIST_RX0ERRCNT    (0xc286)
++#define TXC_BIST_RX1ERRCNT    (0xc287)
++#define TXC_BIST_RX2ERRCNT    (0xc288)
++#define TXC_BIST_RX3ERRCNT    (0xc289)
++
++/*** BIST control bits */
++/* BIST type (controls bit patter in test) */
++#define TXC_BIST_CTRL_TYPE_LBN        (10)
++#define       TXC_BIST_CTRL_TYPE_TSD  (0)     /* TranSwitch Deterministic */
++#define TXC_BIST_CTRL_TYPE_CRP        (1)     /* CRPAT standard */
++#define TXC_BIST_CTRL_TYPE_CJP        (2)     /* CJPAT standard */
++#define TXC_BIST_CTRL_TYPE_TSR        (3)     /* TranSwitch pseudo-random */
++/* Set this to 1 for 10 bit and 0 for 8 bit */
++#define TXC_BIST_CTRL_B10EN_LBN       (12)
++/* Enable BIST (write 0 to disable) */
++#define       TXC_BIST_CTRL_ENAB_LBN  (13)
++/*Stop BIST (self-clears when stop complete) */
++#define  TXC_BIST_CTRL_STOP_LBN       (14)
++/* Start BIST (cleared by writing 1 to STOP) */
++#define  TXC_BIST_CTRL_STRT_LBN       (15)
++
++/* Mt. Diablo test configuration */
++#define TXC_MTDIABLO_CTRL     (0xc34f)
++#define TXC_MTDIABLO_CTRL_PMA_LOOP_LBN        (10)
++
++struct txc43128_data {
++#ifdef CONFIG_SFC_DEBUGFS
++      /* BER stats update from check_hw. Note that this is in errors/second,
++       * converting it to errors/bit is left as an exercise for user-space.
++       */
++      unsigned phy_ber_pcs[4];
++      unsigned phy_ber_phyxs[4];
++#endif
++      unsigned bug10934_timer;
++      int phy_powered;
++      int tx_disabled;
++      enum efx_loopback_mode loopback_mode;
++};
++
++/* Perform the bug 10934 workaround every 5s */
++#define BUG10934_RESET_INTERVAL (5 * HZ)
++
++
++/* Perform a reset that doesn't clear configuration changes */
++static void txc_reset_logic(struct efx_nic *efx);
++
++/* Set the output value of a gpio */
++void txc_set_gpio_val(struct efx_nic *efx, int pin, int on)
++{
++      int outputs;
++
++      outputs = mdio_clause45_read(efx, efx->mii.phy_id,
++                                      MDIO_MMD_PHYXS, TXC_GPIO_OUTPUT);
++
++      outputs = (outputs & ~(1 << pin)) | (on << pin);
++
++      mdio_clause45_write(efx, efx->mii.phy_id,
++                                      MDIO_MMD_PHYXS, TXC_GPIO_OUTPUT,
++                                      outputs);
++}
++
++/* Set up the GPIO direction register */
++void txc_set_gpio_dir(struct efx_nic *efx, int pin, int dir)
++{
++      int dirs;
++
++      if (efx->board_info.minor < 3 &&
++                 efx->board_info.major == 0)
++              return;
++
++      dirs = mdio_clause45_read(efx, efx->mii.phy_id,
++                          MDIO_MMD_PHYXS, TXC_GPIO_DIR);
++      dirs = (dir & ~(1 << pin)) | (dir << pin);
++      mdio_clause45_write(efx, efx->mii.phy_id,
++                          MDIO_MMD_PHYXS, TXC_GPIO_DIR, dirs);
++
++}
++
++/* Reset the PMA/PMD MMD. The documentation is explicit that this does a
++ * global reset (it's less clear what reset of other MMDs does).*/
++static int txc_reset_phy(struct efx_nic *efx)
++{
++      int rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PMAPMD,
++                                       TXC_MAX_RESET_TIME / TXC_RESET_WAIT,
++                                       TXC_RESET_WAIT);
++      if (rc < 0)
++              goto fail;
++
++      /* Check that all the MMDs we expect are present and responding. We
++       * expect faults on some if the link is down, but not on the PHY XS */
++      rc = mdio_clause45_check_mmds(efx, TXC_REQUIRED_DEVS, 0);
++      if (rc < 0)
++              goto fail;
++
++      return 0;
++
++ fail:
++      EFX_ERR(efx, TXCNAME ": reset timed out!\n");
++      return rc;
++}
++
++/* Run a single BIST on one MMD*/
++static int txc_bist_one(struct efx_nic *efx, int mmd, int test)
++{
++      int phy = efx->mii.phy_id;
++      int ctrl, bctl;
++      int lane;
++      int rc = 0;
++
++      EFX_INFO(efx, "" TXCNAME ": running BIST on %s MMD\n",
++               mdio_clause45_mmd_name(mmd));
++
++      /* Set PMA to test into loopback using Mt Diablo reg as per app note */
++      ctrl = mdio_clause45_read(efx, phy, MDIO_MMD_PCS,
++                                TXC_MTDIABLO_CTRL);
++      ctrl |= (1 << TXC_MTDIABLO_CTRL_PMA_LOOP_LBN);
++      mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
++                          TXC_MTDIABLO_CTRL, ctrl);
++
++
++      /* The BIST app. note lists these  as 3 distinct steps. */
++      /* Set the BIST type */
++      bctl = (test << TXC_BIST_CTRL_TYPE_LBN);
++      mdio_clause45_write(efx, phy, mmd, TXC_BIST_CTL, bctl);
++
++      /* Set the BSTEN bit in the BIST Control register to enable */
++      bctl |= (1 << TXC_BIST_CTRL_ENAB_LBN);
++      mdio_clause45_write(efx, phy, mmd, TXC_BIST_CTL, bctl);
++
++      /* Set the BSTRT bit in the BIST Control register */
++      mdio_clause45_write(efx, phy, mmd, TXC_BIST_CTL, bctl |
++                          (1 << TXC_BIST_CTRL_STRT_LBN));
++
++      /* Wait. */
++      udelay(TXC_BIST_DURATION);
++
++      /* Set the BSTOP bit in the BIST Control register */
++      bctl |= (1 << TXC_BIST_CTRL_STOP_LBN);
++      mdio_clause45_write(efx, phy, mmd, TXC_BIST_CTL, bctl);
++
++      /* The STOP bit should go off when things have stopped */
++      while (bctl & (1 << TXC_BIST_CTRL_STOP_LBN))
++              bctl = mdio_clause45_read(efx, phy, mmd, TXC_BIST_CTL);
++
++      /* Check all the error counts are 0 and all the frame counts are
++         non-zero */
++      for (lane = 0; lane < 4; lane++) {
++              int count = mdio_clause45_read(efx, phy, mmd,
++                                             TXC_BIST_RX0ERRCNT + lane);
++              if (count != 0) {
++                      EFX_ERR(efx, ""TXCNAME": BIST error. "
++                              "Lane %d had %d errs\n", lane, count);
++                      rc = -EIO;
++              }
++              count = mdio_clause45_read(efx, phy, mmd,
++                                         TXC_BIST_RX0FRMCNT + lane);
++              if (count == 0) {
++                      EFX_ERR(efx, ""TXCNAME": BIST error. "
++                              "Lane %d got 0 frames\n", lane);
++                      rc = -EIO;
++              }
++      }
++
++      if (rc == 0)
++              EFX_INFO(efx, ""TXCNAME": BIST pass\n");
++
++      /* Disable BIST */
++      mdio_clause45_write(efx, phy, mmd, TXC_BIST_CTL, 0);
++
++      /* Turn off loopback */
++      ctrl &= ~(1 << TXC_MTDIABLO_CTRL_PMA_LOOP_LBN);
++      mdio_clause45_write(efx, phy, MDIO_MMD_PCS,
++                          TXC_MTDIABLO_CTRL, ctrl);
++
++      return rc;
++}
++
++/* Run all the desired BIST tests for the PHY */
++static int txc_bist(struct efx_nic *efx)
++{
++      int rc;
++      /*!\todo: experiment with running more of the BIST patterns to
++       * see if it actually shows up more problems. */
++      rc = txc_bist_one(efx, MDIO_MMD_PCS, TXC_BIST_CTRL_TYPE_TSD);
++      return rc;
++}
++
++#ifdef CONFIG_SFC_DEBUGFS
++
++/* debugfs entries for this PHY */
++static struct efx_debugfs_parameter debug_entries[] = {
++      EFX_PER_LANE_PARAMETER("phy_ber_lane", "_pcs",
++                             struct txc43128_data, phy_ber_pcs,
++                             unsigned, efx_debugfs_read_uint),
++      EFX_PER_LANE_PARAMETER("phy_ber_lane", "_phyxs",
++                             struct txc43128_data, phy_ber_phyxs,
++                             unsigned, efx_debugfs_read_uint),
++      EFX_INT_PARAMETER(struct txc43128_data, phy_powered),
++      {NULL}
++};
++
++#endif /* CONFIG_SFC_DEBUGFS */
++
++/* Push the non-configurable defaults into the PHY. This must be
++ * done after every full reset */
++static void txc_apply_defaults(struct efx_nic *efx)
++{
++      int mctrl;
++
++      /* Turn amplitude down and preemphasis off on the host side
++       * (PHY<->MAC) as this is believed less likely to upset Falcon
++       * and no adverse effects have been noted. It probably also
++       * saves a picowatt or two */
++
++      /* Turn off preemphasis */
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PHYXS,
++                          TXC_ALRGS_ATXPRE0, TXC_ATXPRE_NONE);
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PHYXS,
++                          TXC_ALRGS_ATXPRE1, TXC_ATXPRE_NONE);
++
++      /* Turn down the amplitude */
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PHYXS,
++                          TXC_ALRGS_ATXAMP0, TXC_ATXAMP_0820_BOTH);
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PHYXS,
++                          TXC_ALRGS_ATXAMP1, TXC_ATXAMP_0820_BOTH);
++
++      /* Set the line side amplitude and preemphasis to the databook
++       * defaults as an erratum causes them to be 0 on at least some
++       * PHY rev.s */
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
++                          TXC_ALRGS_ATXPRE0, TXC_ATXPRE_DEFAULT);
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
++                          TXC_ALRGS_ATXPRE1, TXC_ATXPRE_DEFAULT);
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
++                          TXC_ALRGS_ATXAMP0, TXC_ATXAMP_DEFAULT);
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
++                          TXC_ALRGS_ATXAMP1, TXC_ATXAMP_DEFAULT);
++
++      /* Set up the LEDs  */
++      mctrl = mdio_clause45_read(efx, efx->mii.phy_id,
++                                 MDIO_MMD_PHYXS, TXC_MRGS_CTL);
++
++      /* Set the Green and Red LEDs to their default modes */
++      mctrl &= ~((1 << TXC_MCTL_TXLED_LBN) | (1 << TXC_MCTL_RXLED_LBN));
++      mdio_clause45_write(efx, efx->mii.phy_id,
++                          MDIO_MMD_PHYXS, TXC_MRGS_CTL, mctrl);
++
++      /* Databook recommends doing this after configuration changes */
++      txc_reset_logic(efx);
++
++      efx->board_info.init_leds(efx);
++}
++
++/* Initialisation entry point for this PHY driver */
++static int txc43128_phy_init(struct efx_nic *efx)
++{
++      u32 devid;
++      int rc = 0;
++      struct txc43128_data *phy_data;
++
++      devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS);
++
++      phy_data = kzalloc(sizeof(*phy_data), GFP_KERNEL);
++      efx->phy_data = phy_data;
++
++      /* This is the default after reset */
++      phy_data->phy_powered = efx->phy_powered;
++      phy_data->tx_disabled = efx->tx_disabled;
++
++#ifdef CONFIG_SFC_DEBUGFS
++      rc = efx_extend_debugfs_port(efx, phy_data, debug_entries);
++      if (rc < 0)
++              goto fail1;
++#endif
++      EFX_INFO(efx, ""TXCNAME ": PHY ID reg %x (OUI %x model %x "
++               "revision %x)\n", devid, MDIO_ID_OUI(devid),
++               MDIO_ID_MODEL(devid), MDIO_ID_REV(devid));
++
++      EFX_INFO(efx, ""TXCNAME ": Silicon ID %x\n",
++               mdio_clause45_read(efx, efx->mii.phy_id,
++                                  MDIO_MMD_PHYXS, TXC_GLRGS_SLID) &
++                                      TXC_GLRGS_SLID_MASK);
++
++      rc = txc_reset_phy(efx);
++      if (rc < 0)
++              goto fail2;
++
++      rc = txc_bist(efx);
++      if (rc < 0)
++              goto fail2;
++
++      txc_apply_defaults(efx);
++
++      return 0;
++
++ fail2:
++#ifdef CONFIG_SFC_DEBUGFS
++      efx_trim_debugfs_port(efx, debug_entries);
++      /* fall-thru */
++ fail1:
++#endif
++      kfree(efx->phy_data);
++      efx->phy_data = NULL;
++      return rc;
++}
++
++/* Set the lane power down state in the global registers */
++static void txc_glrgs_lane_power(struct efx_nic *efx, int mmd)
++{
++      int pd = (1 << TXC_GLCMD_L01PD_LBN) | (1 << TXC_GLCMD_L23PD_LBN);
++      int ctl = mdio_clause45_read(efx, efx->mii.phy_id,
++                                   mmd, TXC_GLRGS_GLCMD);
++
++      if (efx->phy_powered)
++              ctl &= ~pd;
++      else
++              ctl |= pd;
++
++      mdio_clause45_write(efx, efx->mii.phy_id,
++                          mmd, TXC_GLRGS_GLCMD, ctl);
++}
++
++/* Set the lane power down state in the analog control registers */
++static void txc_analog_lane_power(struct efx_nic *efx, int mmd)
++{
++      int txpd = (1 << TXC_ATXCTL_TXPD3_LBN) | (1 << TXC_ATXCTL_TXPD2_LBN)
++              | (1 << TXC_ATXCTL_TXPD1_LBN) | (1 << TXC_ATXCTL_TXPD0_LBN);
++
++      int rxpd = (1 << TXC_ATXCTL_TXPD3_LBN) | (1 << TXC_ATXCTL_TXPD2_LBN)
++              | (1 << TXC_ATXCTL_TXPD1_LBN) | (1 << TXC_ATXCTL_TXPD0_LBN);
++
++      int txctl = mdio_clause45_read(efx, efx->mii.phy_id,
++                                     mmd, TXC_ALRGS_ATXCTL);
++      int rxctl = mdio_clause45_read(efx, efx->mii.phy_id,
++                                     mmd, TXC_ALRGS_ARXCTL);
++
++      if (efx->phy_powered) {
++              txctl &= ~txpd;
++              rxctl &= ~rxpd;
++      } else {
++              txctl |= txpd;
++              rxctl |= rxpd;
++      }
++
++      mdio_clause45_write(efx, efx->mii.phy_id,
++                          mmd, TXC_ALRGS_ATXCTL, txctl);
++      mdio_clause45_write(efx, efx->mii.phy_id,
++                          mmd, TXC_ALRGS_ARXCTL, rxctl);
++}
++
++static void txc_set_power(struct efx_nic *efx)
++{
++      /* According to the data book, all the MMDs can do low power */
++      mdio_clause45_set_mmds_lpower(efx, !efx->phy_powered,
++                                    TXC_REQUIRED_DEVS);
++
++      /* Global register bank is in PCS, PHY XS. These control the host
++       * side and line side settings respectively. */
++      txc_glrgs_lane_power(efx, MDIO_MMD_PCS);
++      txc_glrgs_lane_power(efx, MDIO_MMD_PHYXS);
++
++      /* Analog register bank in PMA/PMD, PHY XS */
++      txc_analog_lane_power(efx, MDIO_MMD_PMAPMD);
++      txc_analog_lane_power(efx, MDIO_MMD_PHYXS);
++}
++
++
++static void txc_reset_logic_mmd(struct efx_nic *efx, int mmd)
++{
++      int portid = efx->mii.phy_id;
++      int val = mdio_clause45_read(efx, portid, mmd, TXC_GLRGS_GLCMD);
++      int tries = 50;
++      val |= (1 << TXC_GLCMD_LMTSWRST_LBN);
++      mdio_clause45_write(efx, portid, mmd, TXC_GLRGS_GLCMD, val);
++      while (tries--) {
++              val = mdio_clause45_read(efx, portid, mmd,
++                                       TXC_GLRGS_GLCMD);
++              if (!(val & (1 << TXC_GLCMD_LMTSWRST_LBN)))
++                      break;
++              udelay(1);
++      }
++      if (!tries)
++              EFX_INFO(efx, TXCNAME " Logic reset timed out!\n");
++}
++
++
++/* Perform a logic reset. This preserves the configuration registers
++ * and is needed for some configuration changes to take effect */
++static void txc_reset_logic(struct efx_nic *efx)
++{
++      /* The data sheet claims we can do the logic reset on either the
++       * PCS or the PHYXS and the result is a reset of both host- and
++       * line-side logic. */
++      txc_reset_logic_mmd(efx, MDIO_MMD_PCS);
++}
++
++static int txc43128_phy_read_link(struct efx_nic *efx)
++{
++      return mdio_clause45_links_ok(efx, TXC_REQUIRED_DEVS);
++}
++
++static void txc43128_phy_reconfigure(struct efx_nic *efx)
++{
++      struct txc43128_data *phy_data = efx->phy_data;
++      int power_change = (efx->phy_powered != phy_data->phy_powered);
++      int loop_change = LOOPBACK_CHANGED(phy_data, efx, TXC_LOOPBACKS);
++      int disable_change = (efx->tx_disabled != phy_data->tx_disabled);
++
++      if (!phy_data->tx_disabled && efx->tx_disabled) {
++              txc_reset_phy(efx);
++              txc_apply_defaults(efx);
++              falcon_reset_xaui(efx);
++              disable_change = 0;
++      }
++
++      mdio_clause45_transmit_disable(efx, efx->tx_disabled);
++      mdio_clause45_phy_reconfigure(efx);
++      if (power_change)
++              txc_set_power(efx);
++
++      /* The data sheet claims this is required after every reconfiguration
++       * (note at end of 7.1), but we mustn't do it when nothing changes as
++       * it glitches the link, and reconfigure gets called on link change,
++       * so we get an IRQ storm on link up. */
++      if (loop_change || power_change || disable_change)
++              txc_reset_logic(efx);
++
++      phy_data->phy_powered = efx->phy_powered;
++      phy_data->loopback_mode = efx->loopback_mode;
++      phy_data->tx_disabled = efx->tx_disabled;
++      efx->link_up = txc43128_phy_read_link(efx);
++      efx->link_options = GM_LPA_10000FULL;
++}
++
++static void txc43128_phy_fini(struct efx_nic *efx)
++{
++      efx->board_info.blink(efx, 0);
++
++      /* Disable link events */
++      xenpack_disable_lasi_irqs(efx);
++
++#ifdef CONFIG_SFC_DEBUGFS
++      /* Remove the extra debug entries and free data */
++      efx_trim_debugfs_port(efx, debug_entries);
++#endif
++      kfree(efx->phy_data);
++      efx->phy_data = NULL;
++}
++
++/* Periodic callback: this exists mainly to poll link status as we currently
++ * don't use LASI interrupts. Also update the BER counters and poll the lm87 */
++static int txc43128_phy_check_hw(struct efx_nic *efx)
++{
++      struct txc43128_data *data = efx->phy_data;
++#ifdef CONFIG_SFC_DEBUGFS
++      int phy = efx->mii.phy_id;
++      int timer, count, i, mmd;
++#endif
++      int rc = 0;
++      int link_up = txc43128_phy_read_link(efx);
++
++      /* Simulate a PHY event if link state has changed */
++      if (link_up != efx->link_up) {
++              efx->link_up = link_up;
++              efx->mac_op->fake_phy_event(efx);
++      } else if (EFX_WORKAROUND_10934(efx)) {
++              if (link_up || (efx->loopback_mode != LOOPBACK_NONE))
++                      data->bug10934_timer = jiffies;
++              else {
++                      int delta = jiffies - data->bug10934_timer;
++                      if (delta >= BUG10934_RESET_INTERVAL) {
++                              data->bug10934_timer = jiffies;
++                              txc_reset_logic(efx);
++                      }
++              }
++      }
++
++      rc = efx->board_info.monitor(efx);
++      if (rc) {
++              EFX_ERR(efx, "" TXCNAME
++                      ": sensor alert! Putting PHY into low power.\n");
++              efx->phy_powered = 0;
++              txc_set_power(efx);
++      }
++
++#ifdef CONFIG_SFC_DEBUGFS
++      /* There are 2 MMDs with RX BER counters: PCS and PHY XS,
++       * which happen to be consecutively numbered */
++      for (mmd = MDIO_MMD_PCS; mmd <= MDIO_MMD_PHYXS; mmd++) {
++              for (i = 0; i < XAUI_NUM_LANES; i++) {
++                      timer = mdio_clause45_read(efx, phy, mmd,
++                                                 TXC_RXCTL_BERTMR0 +
++                                                 i * BER_REG_SPACING);
++                      count = mdio_clause45_read(efx, phy, mmd,
++                                                 TXC_RXCTL_BERCNT0 +
++                                                 i * BER_REG_SPACING);
++                      /* The BER timer counts down in seconds. If it would
++                       * expire before the next check_hw, update the stats &
++                       * restart the timer (clears the count) */
++                      if (timer * HZ < efx_monitor_interval) {
++                              /* Record count, allowing for the fact that the
++                               * timer may not have reached zero */
++                              unsigned ber = (count * BER_INTERVAL) /
++                                      (BER_INTERVAL - timer * HZ);
++                              if (mmd == MDIO_MMD_PCS)
++                                      data->phy_ber_pcs[i] = ber;
++                              else
++                                      data->phy_ber_phyxs[i] = ber;
++                              /* Reprogram the timer */
++                              mdio_clause45_write(efx, phy, mmd,
++                                                  TXC_RXCTL_BERTMR0 +
++                                                  i * BER_REG_SPACING,
++                                                  BER_INTERVAL / HZ);
++                      }
++              }
++              mmd = (mmd == MDIO_MMD_PCS) ? MDIO_MMD_PHYXS : 0;
++      }
++#endif /* CONFIG_SFC_DEBUGFS */
++      return rc;
++}
++
++struct efx_phy_operations falcon_txc_phy_ops = {
++      .init             = txc43128_phy_init,
++      .reconfigure      = txc43128_phy_reconfigure,
++      .check_hw         = txc43128_phy_check_hw,
++      .fini             = txc43128_phy_fini,
++      .clear_interrupt  = efx_port_dummy_op_void,
++      .reset_xaui       = efx_port_dummy_op_void,
++      .mmds             = TXC_REQUIRED_DEVS,
++      .loopbacks        = TXC_LOOPBACKS,
++      .startup_loopback = LOOPBACK_PMAPMD,
++};
+--- linux-2.6.18.8/drivers/net/sfc/workarounds.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/workarounds.h  2008-05-19 00:33:29.453843880 +0300
+@@ -0,0 +1,97 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef EFX_WORKAROUNDS_H
++#define EFX_WORKAROUNDS_H
++
++/*
++ * Hardware workarounds.
++ * Bug numbers are from Solarflare's Bugzilla.
++ */
++
++#define EFX_WORKAROUND_ALWAYS(efx) 1
++#define EFX_WORKAROUND_FALCON_A(efx) (FALCON_REV(efx) <= FALCON_REV_A1)
++#define EFX_WORKAROUND_FALCON_B0FPGA(efx) \
++      (FALCON_REV(efx) == FALCON_REV_B0 && !(efx)->is_asic)
++
++/* XAUI resets if link not detected */
++#define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS
++/* SNAP frames have TOBE_DISC set */
++#define EFX_WORKAROUND_5475 EFX_WORKAROUND_ALWAYS
++/* PHY interrupts can go to the wrong port */
++#define EFX_WORKAROUND_6263 EFX_WORKAROUND_ALWAYS
++/* Reprog PCIe ACK timer to workaround issue in PCIe IP block */
++#define EFX_WORKAROUND_6943 EFX_WORKAROUND_ALWAYS
++/* RX PCIe double split performance issue */
++#define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS
++/* Bit-bashed I2C reads cause performance drop */
++#define EFX_WORKAROUND_7884 EFX_WORKAROUND_ALWAYS
++/* Selftests need to be retried */
++#define EFX_WORKAROUND_8909 EFX_WORKAROUND_ALWAYS
++/* Queued ACKs aren't flushed before L1 entry */
++#define EFX_WORKAROUND_9096 EFX_WORKAROUND_ALWAYS
++/* TX pkt parser problem with <= 16 byte TXes */
++#define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS
++/* XGXS and XAUI reset sequencing in SW */
++#define EFX_WORKAROUND_9388 EFX_WORKAROUND_ALWAYS
++/* Low rate CRC errors require XAUI reset */
++#define EFX_WORKAROUND_10750 EFX_WORKAROUND_ALWAYS
++/* TX_EV_PKT_ERR can be caused by a dangling TX descriptor
++ * or a PCIe error (bug 11028) */
++#define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS
++/* CX4 retimer fails to bring link up after reset */
++#define EFX_WORKAROUND_10934 EFX_WORKAROUND_ALWAYS
++/* Transmit flow control may get disabled */
++#define EFX_WORKAROUND_11482 EFX_WORKAROUND_ALWAYS
++/* Flush events can take a very long time to appear */
++#define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS
++
++/* Spurious parity errors in TSORT buffers */
++#define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
++/* No unaligned TX over 512 byte boundaries */
++#define EFX_WORKAROUND_5391 EFX_WORKAROUND_FALCON_A
++/* iSCSI parsing errors */
++#define EFX_WORKAROUND_5583 EFX_WORKAROUND_FALCON_A
++/* RX events go missing */
++#define EFX_WORKAROUND_5676 EFX_WORKAROUND_FALCON_A
++/* RX_RESET on A1 */
++#define EFX_WORKAROUND_6555 EFX_WORKAROUND_FALCON_A
++/* Spurious duplicate RX events */
++#define EFX_WORKAROUND_7062 EFX_WORKAROUND_FALCON_A
++/* Increase filter depth to avoid RX_RESET */
++#define EFX_WORKAROUND_7244 EFX_WORKAROUND_FALCON_A
++/* Flushes may never complete */
++#define EFX_WORKAROUND_7803 EFX_WORKAROUND_FALCON_A
++/* Leak overlength packets rather than free */
++#define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A
++
++/* Memory needs clearing at start-of-day */
++#define EFX_WORKAROUND_8202 EFX_WORKAROUND_FALCON_B0FPGA
++/* MAC statistics are transient */
++#define EFX_WORKAROUND_8419 EFX_WORKAROUND_FALCON_B0FPGA
++/* Prefetch watchdog timer may trigger erroneously on busy systems */
++#define EFX_WORKAROUND_9008 EFX_WORKAROUND_FALCON_B0FPGA
++
++#endif /* EFX_WORKAROUNDS_H */
+--- linux-2.6.18.8/drivers/net/sfc/xenpack.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/xenpack.h      2008-05-19 00:33:29.457844111 +0300
+@@ -0,0 +1,80 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2006:      Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef EFX_XENPACK_H
++#define EFX_XENPACK_H
++
++/* Exported functions from Xenpack standard PHY control */
++
++#include "mdio_10g.h"
++
++/****************************************************************************/
++/* XENPACK MDIO register extensions */
++#define MDIO_XP_LASI_RX_CTRL  (0x9000)
++#define MDIO_XP_LASI_TX_CTRL  (0x9001)
++#define MDIO_XP_LASI_CTRL     (0x9002)
++#define MDIO_XP_LASI_RX_STAT  (0x9003)
++#define MDIO_XP_LASI_TX_STAT  (0x9004)
++#define MDIO_XP_LASI_STAT     (0x9005)
++
++/* Control/Status bits */
++#define XP_LASI_LS_ALARM      (1 << 0)
++#define XP_LASI_TX_ALARM      (1 << 1)
++#define XP_LASI_RX_ALARM      (1 << 2)
++/* These two are Quake vendor extensions to the standard XENPACK defines */
++#define XP_LASI_LS_INTB               (1 << 3)
++#define XP_LASI_TEST          (1 << 7)
++
++/* Enable LASI interrupts for PHY */
++static inline void xenpack_enable_lasi_irqs(struct efx_nic *efx)
++{
++      int reg;
++      int phy_id = efx->mii.phy_id;
++      /* Read to clear LASI status register */
++      reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
++                               MDIO_XP_LASI_STAT);
++
++      /* Enable LASI interrupts from PMA/PMD */
++      mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
++                          MDIO_XP_LASI_CTRL, XP_LASI_LS_ALARM);
++}
++
++/* Read the LASI interrupt status to clear the interrupt. */
++static inline int xenpack_clear_lasi_irqs(struct efx_nic *efx)
++{
++      /* Read to clear link status alarm */
++      return mdio_clause45_read(efx, efx->mii.phy_id,
++                                MDIO_MMD_PMAPMD, MDIO_XP_LASI_STAT);
++}
++
++/* Turn off LASI interrupts */
++static inline void xenpack_disable_lasi_irqs(struct efx_nic *efx)
++{
++      /* Turn LASI interrupts off */
++      mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
++                          MDIO_XP_LASI_CTRL, 0);
++}
++
++#endif /* EFX_XENPACK_H */
+--- linux-2.6.18.8/drivers/net/sfc/xfp_phy.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/net/sfc/xfp_phy.c      2008-05-19 00:33:29.457844111 +0300
+@@ -0,0 +1,206 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed by Solarflare Communications <linux-net-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++/*
++ * Driver for XFP optical PHYs (plus some support specific to the Quake 2032)
++ * See www.amcc.com for details (search for qt2032)
++ */
++
++#include <linux/timer.h>
++#include <linux/delay.h>
++#include "efx.h"
++#include "gmii.h"
++#include "mdio_10g.h"
++#include "xenpack.h"
++#include "phy.h"
++
++#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PCS |    \
++                         MDIO_MMDREG_DEVS0_PMAPMD |   \
++                         MDIO_MMDREG_DEVS0_PHYXS)
++
++#define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) |          \
++                     (1 << LOOPBACK_PMAPMD) |         \
++                     (1 << LOOPBACK_NETWORK))
++
++/****************************************************************************/
++/* Quake-specific MDIO registers */
++#define MDIO_QUAKE_LED0_REG   (0xD006)
++
++
++void xfp_set_led(struct efx_nic *p, int led, int mode)
++{
++      int addr = MDIO_QUAKE_LED0_REG + led;
++      mdio_clause45_write(p, p->mii.phy_id, MDIO_MMD_PMAPMD, addr,
++                          mode);
++}
++
++struct xfp_phy_data {
++      int phy_powered;
++      int tx_disabled;
++};
++
++
++#define XFP_MAX_RESET_TIME 500
++#define XFP_RESET_WAIT 10
++
++/* Reset the PHYXS MMD. This is documented (for the Quake PHY) as doing
++ * a complete soft reset.
++ */
++static int xfp_reset_phy(struct efx_nic *efx)
++{
++      int rc;
++
++      rc = mdio_clause45_reset_mmd(efx, MDIO_MMD_PHYXS,
++                                   XFP_MAX_RESET_TIME / XFP_RESET_WAIT,
++                                   XFP_RESET_WAIT);
++      if (rc < 0)
++              goto fail;
++
++      /* Wait 250ms for the PHY to complete bootup */
++      msleep(250);
++
++      /* Check that all the MMDs we expect are present and responding. We
++       * expect faults on some if the link is down, but not on the PHY XS */
++      rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS,
++                                    MDIO_MMDREG_DEVS0_PHYXS);
++      if (rc < 0)
++              goto fail;
++
++      efx->board_info.init_leds(efx);
++
++      return rc;
++
++ fail:
++      EFX_ERR(efx, "XFP: reset timed out!\n");
++      return rc;
++}
++
++
++static int xfp_phy_init(struct efx_nic *efx)
++{
++      struct xfp_phy_data *phy_data;
++      u32 devid = mdio_clause45_read_id(efx, MDIO_MMD_PHYXS);
++      int rc;
++
++      phy_data = kzalloc(sizeof(struct xfp_phy_data), GFP_KERNEL);
++      efx->phy_data = (void *) phy_data;
++
++      EFX_INFO(efx, "XFP: PHY ID reg %x (OUI %x model %x revision"
++               " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
++               MDIO_ID_REV(devid));
++
++      phy_data->phy_powered = efx->phy_powered;
++      phy_data->tx_disabled = efx->tx_disabled;
++
++      rc = xfp_reset_phy(efx);
++      if (rc < 0)
++              goto fail;
++
++      EFX_INFO(efx, "XFP: PHY init %s.\n",
++               rc ? "failed" : "successful");
++      return 0;
++
++ fail:
++      kfree(efx->phy_data);
++      efx->phy_data = NULL;
++      return rc;
++}
++
++static void xfp_phy_clear_interrupt(struct efx_nic *efx)
++{
++      xenpack_clear_lasi_irqs(efx);
++}
++
++static int xfp_link_ok(struct efx_nic *efx)
++{
++      return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS);
++}
++
++static int xfp_phy_check_hw(struct efx_nic *efx)
++{
++      int rc = 0;
++      int link_up = xfp_link_ok(efx);
++      /* Simulate a PHY event if link state has changed */
++      if (link_up != efx->link_up) {
++              efx->link_up = link_up;
++              efx->mac_op->fake_phy_event(efx);
++      }
++
++      rc = efx->board_info.monitor(efx);
++      if (rc) {
++              EFX_ERR(efx, ": XFP sensor alert! Putting PHY into "
++                      "low power.\n");
++              efx->phy_powered = 0;
++
++              mdio_clause45_set_mmds_lpower(efx, 1, XFP_REQUIRED_DEVS);
++      }
++
++      return rc;
++}
++
++static void xfp_phy_reconfigure(struct efx_nic *efx)
++{
++      struct xfp_phy_data *phy_data = efx->phy_data;
++
++      /* Reset the PHY when moving from transmitter off or powered off,
++       * to transmitter on and powered on */
++      if ((efx->phy_powered && !efx->tx_disabled) &&
++          (!phy_data->phy_powered || phy_data->tx_disabled))
++              xfp_reset_phy(efx);
++
++      mdio_clause45_transmit_disable(efx, efx->tx_disabled);
++      mdio_clause45_set_mmds_lpower(efx, !efx->phy_powered,
++                                    XFP_REQUIRED_DEVS);
++      mdio_clause45_phy_reconfigure(efx);
++
++      phy_data->tx_disabled = efx->tx_disabled;
++      phy_data->phy_powered = efx->phy_powered;
++      efx->link_up = xfp_link_ok(efx);
++      efx->link_options = GM_LPA_10000FULL;
++}
++
++
++static void xfp_phy_fini(struct efx_nic *efx)
++{
++      /* Clobber the LED if it was blinking */
++      efx->board_info.blink(efx, 0);
++
++      /* Free the context block */
++      kfree(efx->phy_data);
++      efx->phy_data = NULL;
++}
++
++struct efx_phy_operations falcon_xfp_phy_ops = {
++      .init            = xfp_phy_init,
++      .reconfigure     = xfp_phy_reconfigure,
++      .check_hw        = xfp_phy_check_hw,
++      .fini            = xfp_phy_fini,
++      .clear_interrupt = xfp_phy_clear_interrupt,
++      .reset_xaui      = efx_port_dummy_op_void,
++      .mmds            = XFP_REQUIRED_DEVS,
++      .loopbacks       = XFP_LOOPBACKS,
++      /* No loopback appears to be reliable enough for self-test
++       * operation. So don't do it. */
++      .startup_loopback = LOOPBACK_PCS,
++};
+--- linux-2.6.18.8/drivers/oprofile/buffer_sync.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/oprofile/buffer_sync.c 2008-05-19 00:33:32.550022346 +0300
+@@ -6,6 +6,10 @@
+  *
+  * @author John Levon <levon@movementarian.org>
+  *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
++ *
+  * This is the core of the buffer management. Each
+  * CPU buffer is processed and entered into the
+  * global event buffer. Such processing is necessary
+@@ -38,6 +42,7 @@
+ static DEFINE_SPINLOCK(task_mortuary);
+ static void process_task_mortuary(void);
++static int cpu_current_domain[NR_CPUS];
+ /* Take ownership of the task struct and place it on the
+  * list for processing. Only after two full buffer syncs
+@@ -146,6 +151,11 @@
+ int sync_start(void)
+ {
+       int err;
++      int i;
++
++      for (i = 0; i < NR_CPUS; i++) {
++              cpu_current_domain[i] = COORDINATOR_DOMAIN;
++      }
+       start_cpu_work();
+@@ -275,13 +285,29 @@
+       last_cookie = INVALID_COOKIE;
+ }
+-static void add_kernel_ctx_switch(unsigned int in_kernel)
++static void add_cpu_mode_switch(unsigned int cpu_mode)
+ {
+       add_event_entry(ESCAPE_CODE);
+-      if (in_kernel)
++      switch (cpu_mode) {
++      case CPU_MODE_USER:
++              add_event_entry(USER_ENTER_SWITCH_CODE);
++              break;
++      case CPU_MODE_KERNEL:
+               add_event_entry(KERNEL_ENTER_SWITCH_CODE); 
+-      else
+-              add_event_entry(KERNEL_EXIT_SWITCH_CODE); 
++              break;
++      case CPU_MODE_XEN:
++              add_event_entry(XEN_ENTER_SWITCH_CODE);
++              break;
++      default:
++              break;
++      }
++}
++
++static void add_domain_switch(unsigned long domain_id)
++{
++      add_event_entry(ESCAPE_CODE);
++      add_event_entry(DOMAIN_SWITCH_CODE);
++      add_event_entry(domain_id);
+ }
+  
+ static void
+@@ -348,9 +374,9 @@
+  * for later lookup from userspace.
+  */
+ static int
+-add_sample(struct mm_struct * mm, struct op_sample * s, int in_kernel)
++add_sample(struct mm_struct * mm, struct op_sample * s, int cpu_mode)
+ {
+-      if (in_kernel) {
++      if (cpu_mode >= CPU_MODE_KERNEL) {
+               add_sample_entry(s->eip, s->event);
+               return 1;
+       } else if (mm) {
+@@ -496,15 +522,21 @@
+       struct mm_struct *mm = NULL;
+       struct task_struct * new;
+       unsigned long cookie = 0;
+-      int in_kernel = 1;
++      int cpu_mode = 1;
+       unsigned int i;
+       sync_buffer_state state = sb_buffer_start;
+       unsigned long available;
++      int domain_switch = 0;
+       mutex_lock(&buffer_mutex);
+  
+       add_cpu_switch(cpu);
++      /* We need to assign the first samples in this CPU buffer to the
++         same domain that we were processing at the last sync_buffer */
++      if (cpu_current_domain[cpu] != COORDINATOR_DOMAIN) {
++              add_domain_switch(cpu_current_domain[cpu]);
++      }
+       /* Remember, only we can modify tail_pos */
+       available = get_slots(cpu_buf);
+@@ -512,16 +544,18 @@
+       for (i = 0; i < available; ++i) {
+               struct op_sample * s = &cpu_buf->buffer[cpu_buf->tail_pos];
+  
+-              if (is_code(s->eip)) {
+-                      if (s->event <= CPU_IS_KERNEL) {
+-                              /* kernel/userspace switch */
+-                              in_kernel = s->event;
++              if (is_code(s->eip) && !domain_switch) {
++                      if (s->event <= CPU_MODE_XEN) {
++                              /* xen/kernel/userspace switch */
++                              cpu_mode = s->event;
+                               if (state == sb_buffer_start)
+                                       state = sb_sample_start;
+-                              add_kernel_ctx_switch(s->event);
++                              add_cpu_mode_switch(s->event);
+                       } else if (s->event == CPU_TRACE_BEGIN) {
+                               state = sb_bt_start;
+                               add_trace_begin();
++                      } else if (s->event == CPU_DOMAIN_SWITCH) {
++                                      domain_switch = 1;                              
+                       } else {
+                               struct mm_struct * oldmm = mm;
+@@ -535,19 +569,34 @@
+                               add_user_ctx_switch(new, cookie);
+                       }
+               } else {
+-                      if (state >= sb_bt_start &&
+-                          !add_sample(mm, s, in_kernel)) {
++                      if (domain_switch) {
++                              cpu_current_domain[cpu] = s->eip;
++                              add_domain_switch(s->eip);
++                              domain_switch = 0;
++                      } else {
++                              if (cpu_current_domain[cpu] !=
++                                  COORDINATOR_DOMAIN) {
++                                      add_sample_entry(s->eip, s->event);
++                              }
++                              else  if (state >= sb_bt_start &&
++                                  !add_sample(mm, s, cpu_mode)) {
+                               if (state == sb_bt_start) {
+                                       state = sb_bt_ignore;
+                                       atomic_inc(&oprofile_stats.bt_lost_no_mapping);
+                               }
+                       }
+               }
++              }
+               increment_tail(cpu_buf);
+       }
+       release_mm(mm);
++      /* We reset domain to COORDINATOR at each CPU switch */
++      if (cpu_current_domain[cpu] != COORDINATOR_DOMAIN) {
++              add_domain_switch(COORDINATOR_DOMAIN);
++      }
++
+       mark_done(cpu);
+       mutex_unlock(&buffer_mutex);
+--- linux-2.6.18.8/drivers/oprofile/cpu_buffer.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/oprofile/cpu_buffer.c  2008-05-19 00:33:32.566023268 +0300
+@@ -6,6 +6,10 @@
+  *
+  * @author John Levon <levon@movementarian.org>
+  *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
++ *
+  * Each CPU has a local buffer that stores PC value/event
+  * pairs. We also log context switches when we notice them.
+  * Eventually each CPU's buffer is processed into the global
+@@ -34,6 +38,8 @@
+ #define DEFAULT_TIMER_EXPIRE (HZ / 10)
+ static int work_enabled;
++static int32_t current_domain = COORDINATOR_DOMAIN;
++
+ void free_cpu_buffers(void)
+ {
+       int i;
+@@ -57,7 +63,7 @@
+                       goto fail;
+  
+               b->last_task = NULL;
+-              b->last_is_kernel = -1;
++              b->last_cpu_mode = -1;
+               b->tracing = 0;
+               b->buffer_size = buffer_size;
+               b->tail_pos = 0;
+@@ -113,7 +119,7 @@
+        * collected will populate the buffer with proper
+        * values to initialize the buffer
+        */
+-      cpu_buf->last_is_kernel = -1;
++      cpu_buf->last_cpu_mode = -1;
+       cpu_buf->last_task = NULL;
+ }
+@@ -163,13 +169,13 @@
+  * because of the head/tail separation of the writer and reader
+  * of the CPU buffer.
+  *
+- * is_kernel is needed because on some architectures you cannot
++ * cpu_mode is needed because on some architectures you cannot
+  * tell if you are in kernel or user space simply by looking at
+- * pc. We tag this in the buffer by generating kernel enter/exit
+- * events whenever is_kernel changes
++ * pc. We tag this in the buffer by generating kernel/user (and xen)
++ *  enter events whenever cpu_mode changes
+  */
+ static int log_sample(struct oprofile_cpu_buffer * cpu_buf, unsigned long pc,
+-                    int is_kernel, unsigned long event)
++                    int cpu_mode, unsigned long event)
+ {
+       struct task_struct * task;
+@@ -180,18 +186,18 @@
+               return 0;
+       }
+-      is_kernel = !!is_kernel;
+-
+       task = current;
+       /* notice a switch from user->kernel or vice versa */
+-      if (cpu_buf->last_is_kernel != is_kernel) {
+-              cpu_buf->last_is_kernel = is_kernel;
+-              add_code(cpu_buf, is_kernel);
++      if (cpu_buf->last_cpu_mode != cpu_mode) {
++              cpu_buf->last_cpu_mode = cpu_mode;
++              add_code(cpu_buf, cpu_mode);
+       }
+       /* notice a task switch */
+-      if (cpu_buf->last_task != task) {
++      /* if not processing other domain samples */
++      if ((cpu_buf->last_task != task) &&
++          (current_domain == COORDINATOR_DOMAIN)) {
+               cpu_buf->last_task = task;
+               add_code(cpu_buf, (unsigned long)task);
+       }
+@@ -275,6 +281,25 @@
+       add_sample(cpu_buf, pc, 0);
+ }
++int oprofile_add_domain_switch(int32_t domain_id)
++{
++      struct oprofile_cpu_buffer * cpu_buf = &cpu_buffer[smp_processor_id()];
++
++      /* should have space for switching into and out of domain 
++         (2 slots each) plus one sample and one cpu mode switch */
++      if (((nr_available_slots(cpu_buf) < 6) && 
++           (domain_id != COORDINATOR_DOMAIN)) ||
++          (nr_available_slots(cpu_buf) < 2))
++              return 0;
++
++      add_code(cpu_buf, CPU_DOMAIN_SWITCH);
++      add_sample(cpu_buf, domain_id, 0);
++
++      current_domain = domain_id;
++
++      return 1;
++}
++
+ /*
+  * This serves to avoid cpu buffer overflow, and makes sure
+  * the task mortuary progresses
+--- linux-2.6.18.8/drivers/oprofile/cpu_buffer.h       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/oprofile/cpu_buffer.h  2008-05-19 00:33:32.594024882 +0300
+@@ -36,7 +36,7 @@
+       volatile unsigned long tail_pos;
+       unsigned long buffer_size;
+       struct task_struct * last_task;
+-      int last_is_kernel;
++      int last_cpu_mode;
+       int tracing;
+       struct op_sample * buffer;
+       unsigned long sample_received;
+@@ -51,7 +51,10 @@
+ void cpu_buffer_reset(struct oprofile_cpu_buffer * cpu_buf);
+ /* transient events for the CPU buffer -> event buffer */
+-#define CPU_IS_KERNEL 1
+-#define CPU_TRACE_BEGIN 2
++#define CPU_MODE_USER           0
++#define CPU_MODE_KERNEL         1
++#define CPU_MODE_XEN            2
++#define CPU_TRACE_BEGIN         3
++#define CPU_DOMAIN_SWITCH       4
+ #endif /* OPROFILE_CPU_BUFFER_H */
+--- linux-2.6.18.8/drivers/oprofile/event_buffer.h     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/oprofile/event_buffer.h        2008-05-19 00:33:32.598025113 +0300
+@@ -29,15 +29,20 @@
+ #define CPU_SWITCH_CODE               2
+ #define COOKIE_SWITCH_CODE            3
+ #define KERNEL_ENTER_SWITCH_CODE      4
+-#define KERNEL_EXIT_SWITCH_CODE               5
++#define USER_ENTER_SWITCH_CODE                5
+ #define MODULE_LOADED_CODE            6
+ #define CTX_TGID_CODE                 7
+ #define TRACE_BEGIN_CODE              8
+ #define TRACE_END_CODE                        9
++#define XEN_ENTER_SWITCH_CODE         10
++#define DOMAIN_SWITCH_CODE            11
+  
+ #define INVALID_COOKIE ~0UL
+ #define NO_COOKIE 0UL
++/* Constant used to refer to coordinator domain (Xen) */
++#define COORDINATOR_DOMAIN -1
++
+ /* add data to the event buffer */
+ void add_event_entry(unsigned long data);
+  
+--- linux-2.6.18.8/drivers/oprofile/oprof.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/oprofile/oprof.c       2008-05-19 00:33:32.598025113 +0300
+@@ -5,6 +5,10 @@
+  * @remark Read the file COPYING
+  *
+  * @author John Levon <levon@movementarian.org>
++ *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.
+  */
+ #include <linux/kernel.h>
+@@ -33,6 +37,32 @@
+  */
+ static int timer = 0;
++int oprofile_set_active(int active_domains[], unsigned int adomains)
++{
++      int err;
++
++      if (!oprofile_ops.set_active)
++              return -EINVAL;
++
++      mutex_lock(&start_mutex);
++      err = oprofile_ops.set_active(active_domains, adomains);
++      mutex_unlock(&start_mutex);
++      return err;
++}
++
++int oprofile_set_passive(int passive_domains[], unsigned int pdomains)
++{
++      int err;
++
++      if (!oprofile_ops.set_passive)
++              return -EINVAL;
++
++      mutex_lock(&start_mutex);
++      err = oprofile_ops.set_passive(passive_domains, pdomains);
++      mutex_unlock(&start_mutex);
++      return err;
++}
++
+ int oprofile_setup(void)
+ {
+       int err;
+--- linux-2.6.18.8/drivers/oprofile/oprof.h    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/oprofile/oprof.h       2008-05-19 00:33:32.598025113 +0300
+@@ -36,4 +36,7 @@
+ int oprofile_set_backtrace(unsigned long depth);
+  
++int oprofile_set_active(int active_domains[], unsigned int adomains);
++int oprofile_set_passive(int passive_domains[], unsigned int pdomains);
++ 
+ #endif /* OPROF_H */
+--- linux-2.6.18.8/drivers/oprofile/oprofile_files.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/oprofile/oprofile_files.c      2008-05-19 00:33:32.598025113 +0300
+@@ -5,10 +5,16 @@
+  * @remark Read the file COPYING
+  *
+  * @author John Levon <levon@movementarian.org>
++ *
++ * Modified by Aravind Menon for Xen
++ * These modifications are:
++ * Copyright (C) 2005 Hewlett-Packard Co.     
+  */
+ #include <linux/fs.h>
+ #include <linux/oprofile.h>
++#include <asm/uaccess.h>
++#include <linux/ctype.h>
+ #include "event_buffer.h"
+ #include "oprofile_stats.h"
+@@ -118,10 +124,201 @@
+       .write          = dump_write,
+ };
+  
++#define TMPBUFSIZE 512
++
++static unsigned int adomains = 0;
++static int active_domains[MAX_OPROF_DOMAINS + 1];
++static DEFINE_MUTEX(adom_mutex);
++
++static ssize_t adomain_write(struct file * file, char const __user * buf, 
++                           size_t count, loff_t * offset)
++{
++      char *tmpbuf;
++      char *startp, *endp;
++      int i;
++      unsigned long val;
++      ssize_t retval = count;
++      
++      if (*offset)
++              return -EINVAL; 
++      if (count > TMPBUFSIZE - 1)
++              return -EINVAL;
++
++      if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++              return -ENOMEM;
++
++      if (copy_from_user(tmpbuf, buf, count)) {
++              kfree(tmpbuf);
++              return -EFAULT;
++      }
++      tmpbuf[count] = 0;
++
++      mutex_lock(&adom_mutex);
++
++      startp = tmpbuf;
++      /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
++      for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
++              val = simple_strtoul(startp, &endp, 0);
++              if (endp == startp)
++                      break;
++              while (ispunct(*endp) || isspace(*endp))
++                      endp++;
++              active_domains[i] = val;
++              if (active_domains[i] != val)
++                      /* Overflow, force error below */
++                      i = MAX_OPROF_DOMAINS + 1;
++              startp = endp;
++      }
++      /* Force error on trailing junk */
++      adomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
++
++      kfree(tmpbuf);
++
++      if (adomains > MAX_OPROF_DOMAINS
++          || oprofile_set_active(active_domains, adomains)) {
++              adomains = 0;
++              retval = -EINVAL;
++      }
++
++      mutex_unlock(&adom_mutex);
++      return retval;
++}
++
++static ssize_t adomain_read(struct file * file, char __user * buf, 
++                          size_t count, loff_t * offset)
++{
++      char * tmpbuf;
++      size_t len;
++      int i;
++      ssize_t retval;
++
++      if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++              return -ENOMEM;
++
++      mutex_lock(&adom_mutex);
++
++      len = 0;
++      for (i = 0; i < adomains; i++)
++              len += snprintf(tmpbuf + len,
++                              len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
++                              "%u ", active_domains[i]);
++      WARN_ON(len > TMPBUFSIZE);
++      if (len != 0 && len <= TMPBUFSIZE)
++              tmpbuf[len-1] = '\n';
++
++      mutex_unlock(&adom_mutex);
++
++      retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
++
++      kfree(tmpbuf);
++      return retval;
++}
++
++
++static struct file_operations active_domain_ops = {
++      .read           = adomain_read,
++      .write          = adomain_write,
++};
++
++static unsigned int pdomains = 0;
++static int passive_domains[MAX_OPROF_DOMAINS];
++static DEFINE_MUTEX(pdom_mutex);
++
++static ssize_t pdomain_write(struct file * file, char const __user * buf, 
++                           size_t count, loff_t * offset)
++{
++      char *tmpbuf;
++      char *startp, *endp;
++      int i;
++      unsigned long val;
++      ssize_t retval = count;
++      
++      if (*offset)
++              return -EINVAL; 
++      if (count > TMPBUFSIZE - 1)
++              return -EINVAL;
++
++      if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++              return -ENOMEM;
++
++      if (copy_from_user(tmpbuf, buf, count)) {
++              kfree(tmpbuf);
++              return -EFAULT;
++      }
++      tmpbuf[count] = 0;
++
++      mutex_lock(&pdom_mutex);
++
++      startp = tmpbuf;
++      /* Parse one more than MAX_OPROF_DOMAINS, for easy error checking */
++      for (i = 0; i <= MAX_OPROF_DOMAINS; i++) {
++              val = simple_strtoul(startp, &endp, 0);
++              if (endp == startp)
++                      break;
++              while (ispunct(*endp) || isspace(*endp))
++                      endp++;
++              passive_domains[i] = val;
++              if (passive_domains[i] != val)
++                      /* Overflow, force error below */
++                      i = MAX_OPROF_DOMAINS + 1;
++              startp = endp;
++      }
++      /* Force error on trailing junk */
++      pdomains = *startp ? MAX_OPROF_DOMAINS + 1 : i;
++
++      kfree(tmpbuf);
++
++      if (pdomains > MAX_OPROF_DOMAINS
++          || oprofile_set_passive(passive_domains, pdomains)) {
++              pdomains = 0;
++              retval = -EINVAL;
++      }
++
++      mutex_unlock(&pdom_mutex);
++      return retval;
++}
++
++static ssize_t pdomain_read(struct file * file, char __user * buf, 
++                          size_t count, loff_t * offset)
++{
++      char * tmpbuf;
++      size_t len;
++      int i;
++      ssize_t retval;
++
++      if (!(tmpbuf = kmalloc(TMPBUFSIZE, GFP_KERNEL)))
++              return -ENOMEM;
++
++      mutex_lock(&pdom_mutex);
++
++      len = 0;
++      for (i = 0; i < pdomains; i++)
++              len += snprintf(tmpbuf + len,
++                              len < TMPBUFSIZE ? TMPBUFSIZE - len : 0,
++                              "%u ", passive_domains[i]);
++      WARN_ON(len > TMPBUFSIZE);
++      if (len != 0 && len <= TMPBUFSIZE)
++              tmpbuf[len-1] = '\n';
++
++      mutex_unlock(&pdom_mutex);
++
++      retval = simple_read_from_buffer(buf, count, offset, tmpbuf, len);
++
++      kfree(tmpbuf);
++      return retval;
++}
++
++static struct file_operations passive_domain_ops = {
++      .read           = pdomain_read,
++      .write          = pdomain_write,
++};
++
+ void oprofile_create_files(struct super_block * sb, struct dentry * root)
+ {
+       oprofilefs_create_file(sb, root, "enable", &enable_fops);
+       oprofilefs_create_file_perm(sb, root, "dump", &dump_fops, 0666);
++      oprofilefs_create_file(sb, root, "active_domains", &active_domain_ops);
++      oprofilefs_create_file(sb, root, "passive_domains", &passive_domain_ops);
+       oprofilefs_create_file(sb, root, "buffer", &event_buffer_fops);
+       oprofilefs_create_ulong(sb, root, "buffer_size", &fs_buffer_size);
+       oprofilefs_create_ulong(sb, root, "buffer_watershed", &fs_buffer_watershed);
+--- linux-2.6.18.8/drivers/pci/bus.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/pci/bus.c      2008-05-19 00:33:32.938044711 +0300
+@@ -17,6 +17,8 @@
+ #include "pci.h"
++extern int pci_mem_align;
++
+ /**
+  * pci_bus_alloc_resource - allocate a resource from a parent bus
+  * @bus: PCI bus
+@@ -44,6 +46,11 @@
+       type_mask |= IORESOURCE_IO | IORESOURCE_MEM;
++      /* If the boot parameter 'pci-mem-align' was specified then we need to 
++         align the memory addresses, at page size alignment. */
++      if (pci_mem_align && (align < (PAGE_SIZE-1)))
++              align = PAGE_SIZE - 1;
++
+       for (i = 0; i < PCI_BUS_NUM_RESOURCES; i++) {
+               struct resource *r = bus->resource[i];
+               if (!r)
+--- linux-2.6.18.8/drivers/pci/msi-xen.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/pci/msi-xen.c  2008-05-19 00:33:33.654085984 +0300
+@@ -0,0 +1,721 @@
++/*
++ * File:      msi.c
++ * Purpose:   PCI Message Signaled Interrupt (MSI)
++ *
++ * Copyright (C) 2003-2004 Intel
++ * Copyright (C) Tom Long Nguyen (tom.l.nguyen@intel.com)
++ */
++
++#include <linux/mm.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/smp_lock.h>
++#include <linux/pci.h>
++#include <linux/proc_fs.h>
++
++#include <asm/errno.h>
++#include <asm/io.h>
++#include <asm/smp.h>
++
++#include "pci.h"
++#include "msi.h"
++
++static int pci_msi_enable = 1;
++
++static struct msi_ops *msi_ops;
++
++int msi_register(struct msi_ops *ops)
++{
++      msi_ops = ops;
++      return 0;
++}
++
++static LIST_HEAD(msi_dev_head);
++DEFINE_SPINLOCK(msi_dev_lock);
++
++struct msi_dev_list {
++      struct pci_dev *dev;
++      struct list_head list;
++      spinlock_t pirq_list_lock;
++      struct list_head pirq_list_head;
++};
++
++struct msi_pirq_entry {
++      struct list_head list;
++      int pirq;
++      int entry_nr;
++};
++
++static struct msi_dev_list *get_msi_dev_pirq_list(struct pci_dev *dev)
++{
++      struct msi_dev_list *msi_dev_list, *ret = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&msi_dev_lock, flags);
++
++      list_for_each_entry(msi_dev_list, &msi_dev_head, list)
++              if ( msi_dev_list->dev == dev )
++                      ret = msi_dev_list;
++
++      if ( ret ) {
++              spin_unlock_irqrestore(&msi_dev_lock, flags);
++              return ret;
++      }
++
++      /* Has not allocate msi_dev until now. */
++      ret = kmalloc(sizeof(struct msi_dev_list), GFP_ATOMIC);
++
++      /* Failed to allocate msi_dev structure */
++      if ( !ret ) {
++              spin_unlock_irqrestore(&msi_dev_lock, flags);
++              return NULL;
++      }
++
++      spin_lock_init(&ret->pirq_list_lock);
++      INIT_LIST_HEAD(&ret->pirq_list_head);
++      list_add_tail(&ret->list, &msi_dev_head);
++      spin_unlock_irqrestore(&msi_dev_lock, flags);
++      return ret;
++}
++
++static int attach_pirq_entry(int pirq, int entry_nr,
++                             struct msi_dev_list *msi_dev_entry)
++{
++      struct msi_pirq_entry *entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
++      unsigned long flags;
++
++      if (!entry)
++              return -ENOMEM;
++      entry->pirq = pirq;
++      entry->entry_nr = entry_nr;
++      spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
++      list_add_tail(&entry->list, &msi_dev_entry->pirq_list_head);
++      spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
++      return 0;
++}
++
++static void detach_pirq_entry(int entry_nr,
++                                                      struct msi_dev_list *msi_dev_entry)
++{
++      unsigned long flags;
++      struct msi_pirq_entry *pirq_entry;
++
++      list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head, list) {
++              if (pirq_entry->entry_nr == entry_nr) {
++                      spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
++                      list_del(&pirq_entry->list);
++                      spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
++                      kfree(pirq_entry);
++                      return;
++              }
++      }
++}
++
++/*
++ * pciback will provide device's owner
++ */
++int (*get_owner)(struct pci_dev *dev);
++
++int register_msi_get_owner(int (*func)(struct pci_dev *dev))
++{
++      if (get_owner) {
++              printk(KERN_WARNING "register msi_get_owner again\n");
++              return -EEXIST;
++      }
++      get_owner = func;
++      return 0;
++}
++
++int unregister_msi_get_owner(int (*func)(struct pci_dev *dev))
++{
++      if (get_owner == func)
++              get_owner = NULL;
++      return 0;
++}
++
++static int msi_get_dev_owner(struct pci_dev *dev)
++{
++      int owner = DOMID_SELF;
++
++      BUG_ON(!is_initial_xendomain());
++      if (get_owner && (owner = get_owner(dev)) >=0 ) {
++              printk(KERN_INFO "get owner for dev %x get %x \n",
++                                  dev->devfn, owner);
++              return owner;
++      }
++      else
++              return DOMID_SELF;
++}
++
++static int msi_unmap_pirq(struct pci_dev *dev, int pirq)
++{
++      struct physdev_unmap_pirq unmap;
++      int rc;
++      domid_t domid = DOMID_SELF;
++
++      domid = msi_get_dev_owner(dev);
++      unmap.domid = domid;
++      unmap.pirq = pirq;
++
++      if ((rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap)))
++              printk(KERN_WARNING "unmap irq %x failed\n", pirq);
++
++      if (rc < 0)
++              return rc;
++    return 0;
++}
++
++/*
++ * Protected by msi_lock
++ */
++static int msi_map_pirq_to_vector(struct pci_dev *dev, int pirq,
++                                  int entry_nr, int msi)
++{
++      struct physdev_map_pirq map_irq;
++      int rc;
++      domid_t domid = DOMID_SELF;
++
++      domid = msi_get_dev_owner(dev);
++
++      map_irq.domid = domid;
++      map_irq.type = MAP_PIRQ_TYPE_MSI;
++      map_irq.index = -1;
++      map_irq.pirq = pirq;
++    map_irq.msi_info.bus = dev->bus->number;
++    map_irq.msi_info.devfn = dev->devfn;
++      map_irq.msi_info.entry_nr = entry_nr;
++    map_irq.msi_info.msi = msi;
++
++      if ((rc = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq)))
++              printk(KERN_WARNING "map irq failed\n");
++
++      if (rc < 0)
++              return rc;
++
++      return map_irq.pirq;
++}
++
++static int msi_map_vector(struct pci_dev *dev, int entry_nr, int msi)
++{
++      return msi_map_pirq_to_vector(dev, -1, entry_nr, msi);
++}
++
++static int msi_init(void)
++{
++      static int status = 0;
++
++      if (pci_msi_quirk) {
++              pci_msi_enable = 0;
++              printk(KERN_WARNING "PCI: MSI quirk detected. MSI disabled.\n");
++              status = -EINVAL;
++      }
++
++      return status;
++}
++
++void pci_scan_msi_device(struct pci_dev *dev) { }
++
++void disable_msi_mode(struct pci_dev *dev, int pos, int type)
++{
++      u16 control;
++
++      pci_read_config_word(dev, msi_control_reg(pos), &control);
++      if (type == PCI_CAP_ID_MSI) {
++              /* Set enabled bits to single MSI & enable MSI_enable bit */
++              msi_disable(control);
++              pci_write_config_word(dev, msi_control_reg(pos), control);
++              dev->msi_enabled = 0;
++      } else {
++              msix_disable(control);
++              pci_write_config_word(dev, msi_control_reg(pos), control);
++              dev->msix_enabled = 0;
++      }
++      if (pci_find_capability(dev, PCI_CAP_ID_EXP)) {
++              /* PCI Express Endpoint device detected */
++              pci_intx(dev, 1);  /* enable intx */
++      }
++}
++
++static void enable_msi_mode(struct pci_dev *dev, int pos, int type)
++{
++      u16 control;
++
++      pci_read_config_word(dev, msi_control_reg(pos), &control);
++      if (type == PCI_CAP_ID_MSI) {
++              /* Set enabled bits to single MSI & enable MSI_enable bit */
++              msi_enable(control, 1);
++              pci_write_config_word(dev, msi_control_reg(pos), control);
++              dev->msi_enabled = 1;
++      } else {
++              msix_enable(control);
++              pci_write_config_word(dev, msi_control_reg(pos), control);
++              dev->msix_enabled = 1;
++      }
++      if (pci_find_capability(dev, PCI_CAP_ID_EXP)) {
++              /* PCI Express Endpoint device detected */
++              pci_intx(dev, 0);  /* disable intx */
++      }
++}
++
++#ifdef CONFIG_PM
++int pci_save_msi_state(struct pci_dev *dev)
++{
++      int pos;
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
++      if (pos <= 0 || dev->no_msi)
++              return 0;
++
++      if (!dev->msi_enabled)
++              return 0;
++
++      /* Restore dev->irq to its default pin-assertion vector */
++      msi_unmap_pirq(dev, dev->irq);
++      /* Disable MSI mode */
++      disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
++      /* Set the flags for use of restore */
++      dev->msi_enabled = 1;
++      return 0;
++}
++
++void pci_restore_msi_state(struct pci_dev *dev)
++{
++      int pos, pirq;
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
++      if (pos <= 0)
++              return;
++
++      if (!dev->msi_enabled)
++              return;
++
++      pirq = msi_map_pirq_to_vector(dev, dev->irq, 0, 1);
++      if (pirq < 0)
++              return;
++      enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
++}
++
++int pci_save_msix_state(struct pci_dev *dev)
++{
++      int pos;
++      unsigned long flags;
++      struct msi_dev_list *msi_dev_entry;
++      struct msi_pirq_entry *pirq_entry, *tmp;
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
++      if (pos <= 0 || dev->no_msi)
++              return 0;
++
++      /* save the capability */
++      if (!dev->msix_enabled)
++              return 0;
++
++      msi_dev_entry = get_msi_dev_pirq_list(dev);
++
++      spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
++        list_for_each_entry_safe(pirq_entry, tmp,
++                                 &msi_dev_entry->pirq_list_head, list)
++              msi_unmap_pirq(dev, pirq_entry->pirq);
++      spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
++
++      disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
++      /* Set the flags for use of restore */
++      dev->msix_enabled = 1;
++
++      return 0;
++}
++
++void pci_restore_msix_state(struct pci_dev *dev)
++{
++      int pos;
++      unsigned long flags;
++      struct msi_dev_list *msi_dev_entry;
++      struct msi_pirq_entry *pirq_entry, *tmp;
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
++      if (pos <= 0)
++              return;
++
++      if (!dev->msix_enabled)
++              return;
++
++      msi_dev_entry = get_msi_dev_pirq_list(dev);
++
++      spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
++      list_for_each_entry_safe(pirq_entry, tmp,
++                                                       &msi_dev_entry->pirq_list_head, list)
++              msi_map_pirq_to_vector(dev, pirq_entry->pirq, pirq_entry->entry_nr, 0);
++      spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
++
++      enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
++}
++#endif
++
++/**
++ * msi_capability_init - configure device's MSI capability structure
++ * @dev: pointer to the pci_dev data structure of MSI device function
++ *
++ * Setup the MSI capability structure of device function with a single
++ * MSI vector, regardless of device function is capable of handling
++ * multiple messages. A return of zero indicates the successful setup
++ * of an entry zero with the new MSI vector or non-zero for otherwise.
++ **/
++static int msi_capability_init(struct pci_dev *dev)
++{
++      int pos, pirq;
++      u16 control;
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
++      pci_read_config_word(dev, msi_control_reg(pos), &control);
++
++      pirq = msi_map_vector(dev, 0, 1);
++      if (pirq < 0)
++              return -EBUSY;
++
++      dev->irq = pirq;
++      /* Set MSI enabled bits  */
++      enable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
++      dev->msi_enabled = 1;
++
++      return 0;
++}
++
++/**
++ * msix_capability_init - configure device's MSI-X capability
++ * @dev: pointer to the pci_dev data structure of MSI-X device function
++ * @entries: pointer to an array of struct msix_entry entries
++ * @nvec: number of @entries
++ *
++ * Setup the MSI-X capability structure of device function with a
++ * single MSI-X vector. A return of zero indicates the successful setup of
++ * requested MSI-X entries with allocated vectors or non-zero for otherwise.
++ **/
++static int msix_capability_init(struct pci_dev *dev,
++                              struct msix_entry *entries, int nvec)
++{
++      int pirq, i, j, mapped, pos;
++      struct msi_dev_list *msi_dev_entry = get_msi_dev_pirq_list(dev);
++      struct msi_pirq_entry *pirq_entry;
++
++      if (!msi_dev_entry)
++              return -ENOMEM;
++
++      /* MSI-X Table Initialization */
++      for (i = 0; i < nvec; i++) {
++              mapped = 0;
++              list_for_each_entry(pirq_entry, &msi_dev_entry->pirq_list_head, list) {
++                      if (pirq_entry->entry_nr == entries[i].entry) {
++                              printk(KERN_WARNING "msix entry %d for dev %02x:%02x:%01x are \
++                                     not freed before acquire again.\n", entries[i].entry,
++                                         dev->bus->number, PCI_SLOT(dev->devfn),
++                                         PCI_FUNC(dev->devfn));
++                              (entries + i)->vector = pirq_entry->pirq;
++                              mapped = 1;
++                              break;
++                      }
++              }
++              if (mapped)
++                      continue;
++              pirq = msi_map_vector(dev, entries[i].entry, 0);
++              if (pirq < 0)
++                      break;
++              attach_pirq_entry(pirq, entries[i].entry, msi_dev_entry);
++              (entries + i)->vector = pirq;
++      }
++
++      if (i != nvec) {
++              for (j = --i; j >= 0; j--) {
++                      msi_unmap_pirq(dev, entries[j].vector);
++                      detach_pirq_entry(entries[j].entry, msi_dev_entry);
++                      entries[j].vector = 0;
++              }
++              return -EBUSY;
++      }
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
++      enable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
++      dev->msix_enabled = 1;
++
++      return 0;
++}
++
++/**
++ * pci_enable_msi - configure device's MSI capability structure
++ * @dev: pointer to the pci_dev data structure of MSI device function
++ *
++ * Setup the MSI capability structure of device function with
++ * a single MSI vector upon its software driver call to request for
++ * MSI mode enabled on its hardware device function. A return of zero
++ * indicates the successful setup of an entry zero with the new MSI
++ * vector or non-zero for otherwise.
++ **/
++extern int pci_frontend_enable_msi(struct pci_dev *dev);
++int pci_enable_msi(struct pci_dev* dev)
++{
++      struct pci_bus *bus;
++      int pos, temp, status = -EINVAL;
++
++      if (!pci_msi_enable || !dev)
++              return status;
++
++      if (dev->no_msi)
++              return status;
++
++      for (bus = dev->bus; bus; bus = bus->parent)
++              if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
++                      return -EINVAL;
++
++      status = msi_init();
++      if (status < 0)
++              return status;
++
++#ifdef CONFIG_XEN_PCIDEV_FRONTEND
++      if (!is_initial_xendomain())
++      {
++              int ret;
++
++              temp = dev->irq;
++              ret = pci_frontend_enable_msi(dev);
++              if (ret)
++                      return ret;
++
++              dev->irq_old = temp;
++
++              return ret;
++      }
++#endif
++
++      temp = dev->irq;
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
++      if (!pos)
++              return -EINVAL;
++
++      /* Check whether driver already requested for MSI-X vectors */
++      if (dev->msix_enabled) {
++              printk(KERN_INFO "PCI: %s: Can't enable MSI.  "
++                         "Device already has MSI-X vectors assigned\n",
++                         pci_name(dev));
++              dev->irq = temp;
++              return -EINVAL;
++      }
++
++      status = msi_capability_init(dev);
++      if ( !status )
++              dev->irq_old = temp;
++    else
++              dev->irq = temp;
++
++      return status;
++}
++
++extern void pci_frontend_disable_msi(struct pci_dev* dev);
++void pci_disable_msi(struct pci_dev* dev)
++{
++      int pos;
++      int pirq;
++
++      if (!pci_msi_enable)
++              return;
++      if (!dev)
++              return;
++
++#ifdef CONFIG_XEN_PCIDEV_FRONTEND
++      if (!is_initial_xendomain()) {
++              pci_frontend_disable_msi(dev);
++              dev->irq = dev->irq_old;
++              return;
++      }
++#endif
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSI);
++      if (!pos)
++              return;
++
++      pirq = dev->irq;
++      /* Restore dev->irq to its default pin-assertion vector */
++      dev->irq = dev->irq_old;
++      msi_unmap_pirq(dev, pirq);
++
++      /* Disable MSI mode */
++      disable_msi_mode(dev, pos, PCI_CAP_ID_MSI);
++}
++
++/**
++ * pci_enable_msix - configure device's MSI-X capability structure
++ * @dev: pointer to the pci_dev data structure of MSI-X device function
++ * @entries: pointer to an array of MSI-X entries
++ * @nvec: number of MSI-X vectors requested for allocation by device driver
++ *
++ * Setup the MSI-X capability structure of device function with the number
++ * of requested vectors upon its software driver call to request for
++ * MSI-X mode enabled on its hardware device function. A return of zero
++ * indicates the successful configuration of MSI-X capability structure
++ * with new allocated MSI-X vectors. A return of < 0 indicates a failure.
++ * Or a return of > 0 indicates that driver request is exceeding the number
++ * of vectors available. Driver should use the returned value to re-send
++ * its request.
++ **/
++extern int pci_frontend_enable_msix(struct pci_dev *dev,
++              struct msix_entry *entries, int nvec);
++int pci_enable_msix(struct pci_dev* dev, struct msix_entry *entries, int nvec)
++{
++      struct pci_bus *bus;
++      int status, pos, nr_entries;
++      int i, j, temp;
++      u16 control;
++
++      if (!pci_msi_enable || !dev || !entries)
++              return -EINVAL;
++
++      if (dev->no_msi)
++              return -EINVAL;
++
++      for (bus = dev->bus; bus; bus = bus->parent)
++              if (bus->bus_flags & PCI_BUS_FLAGS_NO_MSI)
++                      return -EINVAL;
++
++#ifdef CONFIG_XEN_PCIDEV_FRONTEND
++      if (!is_initial_xendomain()) {
++              int ret;
++
++              ret = pci_frontend_enable_msix(dev, entries, nvec);
++              if (ret) {
++                      printk("get %x from pci_frontend_enable_msix\n", ret);
++                      return ret;
++              }
++
++        return 0;
++      }
++#endif
++
++      status = msi_init();
++      if (status < 0)
++              return status;
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
++      if (!pos)
++              return -EINVAL;
++
++      pci_read_config_word(dev, msi_control_reg(pos), &control);
++      nr_entries = multi_msix_capable(control);
++      if (nvec > nr_entries)
++              return -EINVAL;
++
++      /* Check for any invalid entries */
++      for (i = 0; i < nvec; i++) {
++              if (entries[i].entry >= nr_entries)
++                      return -EINVAL;         /* invalid entry */
++              for (j = i + 1; j < nvec; j++) {
++                      if (entries[i].entry == entries[j].entry)
++                              return -EINVAL; /* duplicate entry */
++              }
++      }
++
++      temp = dev->irq;
++      /* Check whether driver already requested for MSI vector */
++      if (dev->msi_enabled) {
++              printk(KERN_INFO "PCI: %s: Can't enable MSI-X.  "
++                     "Device already has an MSI vector assigned\n",
++                     pci_name(dev));
++              dev->irq = temp;
++              return -EINVAL;
++      }
++
++      status = msix_capability_init(dev, entries, nvec);
++
++      if ( !status )
++              dev->irq_old = temp;
++      else
++              dev->irq = temp;
++
++      return status;
++}
++
++extern void pci_frontend_disable_msix(struct pci_dev* dev);
++void pci_disable_msix(struct pci_dev* dev)
++{
++      int pos;
++      u16 control;
++
++
++      if (!pci_msi_enable)
++              return;
++      if (!dev)
++              return;
++
++#ifdef CONFIG_XEN_PCIDEV_FRONTEND
++      if (!is_initial_xendomain()) {
++              pci_frontend_disable_msix(dev);
++              dev->irq = dev->irq_old;
++              return;
++      }
++#endif
++
++      pos = pci_find_capability(dev, PCI_CAP_ID_MSIX);
++      if (!pos)
++              return;
++
++      pci_read_config_word(dev, msi_control_reg(pos), &control);
++      if (!(control & PCI_MSIX_FLAGS_ENABLE))
++              return;
++
++      msi_remove_pci_irq_vectors(dev);
++
++      /* Disable MSI mode */
++      disable_msi_mode(dev, pos, PCI_CAP_ID_MSIX);
++}
++
++/**
++ * msi_remove_pci_irq_vectors - reclaim MSI(X) vectors to unused state
++ * @dev: pointer to the pci_dev data structure of MSI(X) device function
++ *
++ * Being called during hotplug remove, from which the device function
++ * is hot-removed. All previous assigned MSI/MSI-X vectors, if
++ * allocated for this device function, are reclaimed to unused state,
++ * which may be used later on.
++ **/
++void msi_remove_pci_irq_vectors(struct pci_dev* dev)
++{
++      unsigned long flags;
++      struct msi_dev_list *msi_dev_entry;
++      struct msi_pirq_entry *pirq_entry, *tmp;
++
++      if (!pci_msi_enable || !dev)
++              return;
++
++      msi_dev_entry = get_msi_dev_pirq_list(dev);
++
++      spin_lock_irqsave(&msi_dev_entry->pirq_list_lock, flags);
++      if (!list_empty(&msi_dev_entry->pirq_list_head))
++      {
++              printk(KERN_WARNING "msix pirqs for dev %02x:%02x:%01x are not freed \
++                     before acquire again.\n", dev->bus->number, PCI_SLOT(dev->devfn),
++                         PCI_FUNC(dev->devfn));
++              list_for_each_entry_safe(pirq_entry, tmp,
++                                       &msi_dev_entry->pirq_list_head, list) {
++                      msi_unmap_pirq(dev, pirq_entry->pirq);
++                      list_del(&pirq_entry->list);
++                      kfree(pirq_entry);
++              }
++      }
++      spin_unlock_irqrestore(&msi_dev_entry->pirq_list_lock, flags);
++      dev->irq = dev->irq_old;
++}
++
++void pci_no_msi(void)
++{
++      pci_msi_enable = 0;
++}
++
++EXPORT_SYMBOL(pci_enable_msi);
++EXPORT_SYMBOL(pci_disable_msi);
++EXPORT_SYMBOL(pci_enable_msix);
++EXPORT_SYMBOL(pci_disable_msix);
++#ifdef CONFIG_XEN
++EXPORT_SYMBOL(register_msi_get_owner);
++EXPORT_SYMBOL(unregister_msi_get_owner);
++#endif
++
+--- linux-2.6.18.8/drivers/pci/msi.h   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/pci/msi.h      2008-05-19 00:33:33.654085984 +0300
+@@ -84,6 +84,11 @@
+ extern void (*interrupt[NR_IRQS])(void);
+ extern int pci_vector_resources(int last, int nr_released);
++#ifdef CONFIG_XEN
++extern int unregister_msi_get_owner(int (*func)(struct pci_dev *dev));
++extern int register_msi_get_owner(int (*func)(struct pci_dev *dev));
++#endif
++
+ /*
+  * MSI-X Address Register
+  */
+--- linux-2.6.18.8/drivers/pci/quirks.c        2008-05-19 00:42:34.057238961 +0300
++++ linux-2.6.18-xen.hg/drivers/pci/quirks.c   2008-05-19 00:33:33.770092671 +0300
+@@ -23,6 +23,40 @@
+ #include <linux/acpi.h>
+ #include "pci.h"
++/* A global flag which signals if we should page-align PCI mem windows. */
++int pci_mem_align = 0;
++
++static int __init set_pci_mem_align(char *str)
++{
++      pci_mem_align = 1;
++      return 1;
++}
++__setup("pci-mem-align", set_pci_mem_align);
++
++/* This quirk function enables us to force all memory resources which are 
++ * assigned to PCI devices, to be page-aligned.
++ */
++static void __devinit quirk_align_mem_resources(struct pci_dev *dev)
++{
++      int i;
++      struct resource *r;
++      resource_size_t old_start;
++
++      if (!pci_mem_align)
++              return;
++
++      for (i=0; i < DEVICE_COUNT_RESOURCE; i++) {
++              r = &dev->resource[i];
++              if ((r == NULL) || !(r->flags & IORESOURCE_MEM))
++                      continue;
++
++              old_start = r->start;
++              r->start = (r->start + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
++              r->end = r->end - (old_start - r->start);
++      }
++}
++DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_align_mem_resources);
++
+ /* The Mellanox Tavor device gives false positive parity errors
+  * Mark this device with a broken_parity_status, to allow
+  * PCI scanning code to "skip" this now blacklisted device.
+@@ -1494,10 +1528,11 @@
+ static void __devinit quirk_e100_interrupt(struct pci_dev *dev)
+ {
+-      u16 command;
++      u16 command, pmcsr;
+       u32 bar;
+       u8 __iomem *csr;
+       u8 cmd_hi;
++      int pm;
+       switch (dev->device) {
+       /* PCI IDs taken from drivers/net/e100.c */
+@@ -1532,6 +1567,17 @@
+       if (!(command & PCI_COMMAND_MEMORY) || !bar)
+               return;
++        /*
++         * Check that the device is in the D0 power state. If it's not,
++         * there is no point to look any further.
++         */
++        pm = pci_find_capability(dev, PCI_CAP_ID_PM);
++        if (pm) {
++                pci_read_config_word(dev, pm + PCI_PM_CTRL, &pmcsr);
++                if ((pmcsr & PCI_PM_CTRL_STATE_MASK) != PCI_D0)
++                        return;
++        }
++
+       csr = ioremap(bar, 8);
+       if (!csr) {
+               printk(KERN_WARNING "PCI: Can't map %s e100 registers\n",
+--- linux-2.6.18.8/drivers/pnp/manager.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/pnp/manager.c  2008-05-19 00:33:34.394128641 +0300
+@@ -168,7 +168,7 @@
+       return 0;
+ }
+-static int pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
++static void pnp_assign_dma(struct pnp_dev *dev, struct pnp_dma *rule, int idx)
+ {
+       resource_size_t *start, *end;
+       unsigned long *flags;
+@@ -179,18 +179,14 @@
+               1, 3, 5, 6, 7, 0, 2, 4
+       };
+-      if (!dev || !rule)
+-              return -EINVAL;
+-
+       if (idx >= PNP_MAX_DMA) {
+               pnp_err("More than 2 dmas is incompatible with pnp specifications.");
+-              /* pretend we were successful so at least the manager won't try again */
+-              return 1;
++              return;
+       }
+       /* check if this resource has been manually set, if so skip */
+       if (!(dev->res.dma_resource[idx].flags & IORESOURCE_AUTO))
+-              return 1;
++              return;
+       start = &dev->res.dma_resource[idx].start;
+       end = &dev->res.dma_resource[idx].end;
+@@ -200,19 +196,17 @@
+       *flags |= rule->flags | IORESOURCE_DMA;
+       *flags &=  ~IORESOURCE_UNSET;
+-      if (!rule->map) {
+-              *flags |= IORESOURCE_DISABLED;
+-              return 1; /* skip disabled resource requests */
+-      }
+-
+       for (i = 0; i < 8; i++) {
+               if(rule->map & (1<<xtab[i])) {
+                       *start = *end = xtab[i];
+                       if(pnp_check_dma(dev, idx))
+-                              return 1;
++                              return;
+               }
+       }
+-      return 0;
++#ifdef MAX_DMA_CHANNELS
++      *start = *end = MAX_DMA_CHANNELS;
++#endif
++      *flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
+ }
+ /**
+@@ -331,8 +325,7 @@
+                       irq = irq->next;
+               }
+               while (dma) {
+-                      if (!pnp_assign_dma(dev, dma, ndma))
+-                              goto fail;
++                      pnp_assign_dma(dev, dma, ndma);
+                       ndma++;
+                       dma = dma->next;
+               }
+@@ -367,8 +360,7 @@
+                       irq = irq->next;
+               }
+               while (dma) {
+-                      if (!pnp_assign_dma(dev, dma, ndma))
+-                              goto fail;
++                      pnp_assign_dma(dev, dma, ndma);
+                       ndma++;
+                       dma = dma->next;
+               }
+--- linux-2.6.18.8/drivers/scsi/ahci.c 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/scsi/ahci.c    2008-05-19 00:33:35.798209573 +0300
+@@ -317,6 +317,34 @@
+         board_ahci }, /* ICH8M */
+       { PCI_VENDOR_ID_INTEL, 0x282a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+         board_ahci }, /* ICH8M */
++      { PCI_VENDOR_ID_INTEL, 0x2922, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH9 */
++      { PCI_VENDOR_ID_INTEL, 0x2923, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH9 */
++      { PCI_VENDOR_ID_INTEL, 0x2924, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH9 */
++      { PCI_VENDOR_ID_INTEL, 0x2925, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH9 */
++      { PCI_VENDOR_ID_INTEL, 0x2927, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH9 */
++      { PCI_VENDOR_ID_INTEL, 0x2929, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH9M */
++      { PCI_VENDOR_ID_INTEL, 0x292a, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH9M */
++      { PCI_VENDOR_ID_INTEL, 0x292b, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH9M */
++      { PCI_VENDOR_ID_INTEL, 0x292f, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH9M */
++      { PCI_VENDOR_ID_INTEL, 0x294d, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH9 */
++      { PCI_VENDOR_ID_INTEL, 0x294e, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH9M */
++      { PCI_VENDOR_ID_INTEL, 0x3a02, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH10 */
++      { PCI_VENDOR_ID_INTEL, 0x3a05, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH10 */
++      { PCI_VENDOR_ID_INTEL, 0x3a25, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
++        board_ahci }, /* ICH10 */
+       /* JMicron */
+       { 0x197b, 0x2360, PCI_ANY_ID, PCI_ANY_ID, 0, 0,
+--- linux-2.6.18.8/drivers/scsi/ata_piix.c     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/scsi/ata_piix.c        2008-05-19 00:33:37.286295348 +0300
+@@ -125,6 +125,8 @@
+       ich6m_sata_ahci         = 6,
+       ich7m_sata_ahci         = 7,
+       ich8_sata_ahci          = 8,
++      ich9_sata_ahci          = 9,
++      ich8_2port_sata         = 10,
+       /* constants for mapping table */
+       P0                      = 0,  /* port 0 */
+@@ -192,12 +194,32 @@
+       { 0x8086, 0x27c4, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich7m_sata_ahci },
+       /* Enterprise Southbridge 2 (where's the datasheet?) */
+       { 0x8086, 0x2680, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich6_sata_ahci },
+-      /* SATA Controller 1 IDE (ICH8, no datasheet yet) */
++      /* SATA Controller 1 IDE (ICH8) */
+       { 0x8086, 0x2820, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
+-      /* SATA Controller 2 IDE (ICH8, ditto) */
+-      { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
++      /* SATA Controller 2 IDE (ICH8) */
++      { 0x8086, 0x2825, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+       /* Mobile SATA Controller IDE (ICH8M, ditto) */
+       { 0x8086, 0x2828, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
++      /* SATA Controller 1 IDE (ICH9) */
++      { 0x8086, 0x2920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
++      /* SATA Controller 1 IDE (ICH9) */
++      { 0x8086, 0x2921, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
++      /* SATA Controller 2 IDE (ICH9) */
++      { 0x8086, 0x2926, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
++      /* Mobile SATA Controller 1 IDE (ICH9M) */
++      { 0x8086, 0x2928, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
++      /* Mobile SATA Controller 2 IDE (ICH9M) */
++      { 0x8086, 0x292d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
++      /* Mobile SATA Controller 2 IDE (ICH9M) */
++      { 0x8086, 0x292e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich9_sata_ahci },
++      /* SATA Controller IDE (ICH10) */
++      { 0x8086, 0x3a00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
++      /* SATA Controller IDE (ICH10) */
++      { 0x8086, 0x3a06, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
++      /* SATA Controller IDE (ICH10) */
++      { 0x8086, 0x3a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata_ahci },
++      /* SATA Controller IDE (ICH10) */
++      { 0x8086, 0x3a26, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_2port_sata },
+       { }     /* terminate list */
+ };
+@@ -361,9 +383,34 @@
+       .present_shift = 8,
+       .map = {
+               /* PM   PS   SM   SS       MAP */
+-              {  P0,  NA,  P1,  NA }, /* 00b (hardwired) */
++              {  P0,  P2,  P1,  P3 }, /* 00b (hardwired when in AHCI) */
+               {  RV,  RV,  RV,  RV },
+-              {  RV,  RV,  RV,  RV }, /* 10b (never) */
++              {  IDE,  IDE,  NA,  NA }, /* 10b (IDE mode) */
++              {  RV,  RV,  RV,  RV },
++      },
++};
++
++static const struct piix_map_db ich9_map_db = {
++      .mask = 0x3,
++      .port_enable = 0x3,
++      .present_shift = 8,
++      .map = {
++              /* PM   PS   SM   SS       MAP */
++              {  P0,  P2,  P1,  P3 }, /* 00b (hardwired when in AHCI) */
++              {  RV,  RV,  RV,  RV },
++              {  IDE,  IDE,  NA,  NA }, /* 10b (IDE mode) */
++              {  RV,  RV,  RV,  RV },
++      },
++};
++
++static const struct piix_map_db ich8_2port_map_db = {
++      .mask = 0x3,
++      .port_enable = 0x3,
++      .map = {
++              /* PM   PS   SM   SS       MAP */
++              {  P0,  NA,  P1,  NA }, /* 00b */
++              {  RV,  RV,  RV,  RV }, /* 01b */
++              {  RV,  RV,  RV,  RV }, /* 10b */
+               {  RV,  RV,  RV,  RV },
+       },
+ };
+@@ -376,6 +423,8 @@
+       [ich6m_sata_ahci]       = &ich6m_map_db,
+       [ich7m_sata_ahci]       = &ich7m_map_db,
+       [ich8_sata_ahci]        = &ich8_map_db,
++      [ich9_sata_ahci]        = &ich9_map_db,
++      [ich8_2port_sata]       = &ich8_2port_map_db,
+ };
+ static struct ata_port_info piix_port_info[] = {
+@@ -487,6 +536,30 @@
+               .udma_mask      = 0x7f, /* udma0-6 */
+               .port_ops       = &piix_sata_ops,
+       },
++
++      /* ich9_sata_ahci */
++      {
++              .sht            = &piix_sht,
++              .host_flags     = ATA_FLAG_SATA |
++                                PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
++                                PIIX_FLAG_AHCI,
++              .pio_mask       = 0x1f, /* pio0-4 */
++              .mwdma_mask     = 0x07, /* mwdma0-2 */
++              .udma_mask      = 0x7f, /* udma0-6 */
++              .port_ops       = &piix_sata_ops,
++      },
++      
++      /* ich8_2port_sata: 11: */
++      {
++              .sht            = &piix_sht,
++              .host_flags     = ATA_FLAG_SATA |
++                                PIIX_FLAG_CHECKINTR | PIIX_FLAG_SCR |
++                                PIIX_FLAG_AHCI,
++              .pio_mask       = 0x1f, /* pio0-4 */
++              .mwdma_mask     = 0x07, /* mwdma0-2 */
++              .udma_mask      = ATA_UDMA6,
++              .port_ops       = &piix_pata_ops,
++      },
+ };
+ static struct pci_bits piix_enable_bits[] = {
+--- linux-2.6.18.8/drivers/serial/Kconfig      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/serial/Kconfig 2008-05-19 00:33:39.506423318 +0300
+@@ -11,6 +11,7 @@
+ config SERIAL_8250
+       tristate "8250/16550 and compatible serial support"
+       depends on (BROKEN || !SPARC)
++      depends on !XEN_DISABLE_SERIAL
+       select SERIAL_CORE
+       ---help---
+         This selects whether you want to include the driver for the standard
+--- linux-2.6.18.8/drivers/video/console/Kconfig       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/video/console/Kconfig  2008-05-19 00:33:44.130689864 +0300
+@@ -53,6 +53,7 @@
+ config VIDEO_SELECT
+       bool "Video mode selection support"
+       depends on  X86 && VGA_CONSOLE
++      depends on !XEN
+       ---help---
+         This enables support for text mode selection on kernel startup. If
+         you want to take advantage of some high-resolution text mode your
+--- linux-2.6.18.8/drivers/xen/Kconfig 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/Kconfig    2008-05-19 00:33:45.658777945 +0300
+@@ -0,0 +1,298 @@
++#
++# This Kconfig describe xen options
++#
++
++mainmenu "Xen Configuration"
++
++config XEN
++      bool
++
++if XEN
++config XEN_INTERFACE_VERSION
++      hex
++      default 0x00030207
++
++menu "XEN"
++
++config XEN_PRIVILEGED_GUEST
++      bool "Privileged Guest (domain 0)"
++      help
++        Support for privileged operation (domain 0)
++
++config XEN_UNPRIVILEGED_GUEST
++      def_bool !XEN_PRIVILEGED_GUEST
++
++config XEN_PRIVCMD
++      def_bool y
++      depends on PROC_FS
++
++config XEN_XENBUS_DEV
++      def_bool y
++      depends on PROC_FS
++
++config XEN_NETDEV_ACCEL_SFC_UTIL
++      depends on X86    
++      tristate
++
++config XEN_BACKEND
++        tristate "Backend driver support"
++        default XEN_PRIVILEGED_GUEST
++        help
++          Support for backend device drivers that provide I/O services
++          to other virtual machines.
++
++config XEN_BLKDEV_BACKEND
++      tristate "Block-device backend driver"
++        depends on XEN_BACKEND
++      default XEN_BACKEND
++      help
++        The block-device backend driver allows the kernel to export its
++        block devices to other guests via a high-performance shared-memory
++        interface.
++
++config XEN_BLKDEV_TAP
++      tristate "Block-device tap backend driver"
++      depends on XEN_BACKEND
++      default XEN_BACKEND
++      help
++        The block tap driver is an alternative to the block back driver 
++          and allows VM block requests to be redirected to userspace through
++          a device interface.  The tap allows user-space development of 
++          high-performance block backends, where disk images may be implemented
++          as files, in memory, or on other hosts across the network.  This 
++        driver can safely coexist with the existing blockback driver.
++
++config XEN_NETDEV_BACKEND
++      tristate "Network-device backend driver"
++        depends on XEN_BACKEND && NET
++      default XEN_BACKEND
++      help
++        The network-device backend driver allows the kernel to export its
++        network devices to other guests via a high-performance shared-memory
++        interface.
++
++config XEN_NETDEV_PIPELINED_TRANSMITTER
++      bool "Pipelined transmitter (DANGEROUS)"
++      depends on XEN_NETDEV_BACKEND
++      help
++        If the net backend is a dumb domain, such as a transparent Ethernet
++        bridge with no local IP interface, it is safe to say Y here to get
++        slightly lower network overhead.
++        If the backend has a local IP interface; or may be doing smart things
++        like reassembling packets to perform firewall filtering; or if you
++        are unsure; or if you experience network hangs when this option is
++        enabled; then you must say N here.
++
++config XEN_NETDEV_ACCEL_SFC_BACKEND
++      tristate "Network-device backend driver acceleration for Solarflare NICs"
++      depends on XEN_NETDEV_BACKEND && SFC && SFC_RESOURCE && X86
++      select XEN_NETDEV_ACCEL_SFC_UTIL
++      default m
++
++config XEN_NETDEV_LOOPBACK
++      tristate "Network-device loopback driver"
++      depends on XEN_NETDEV_BACKEND
++      help
++        A two-interface loopback device to emulate a local netfront-netback
++        connection. If unsure, it is probably safe to say N here.
++
++config XEN_PCIDEV_BACKEND
++      tristate "PCI-device backend driver"
++      depends on PCI && XEN_BACKEND
++      default XEN_BACKEND
++      help
++        The PCI device backend driver allows the kernel to export arbitrary
++        PCI devices to other guests. If you select this to be a module, you
++        will need to make sure no other driver has bound to the device(s)
++        you want to make visible to other guests.
++
++choice
++      prompt "PCI Backend Mode"
++      depends on XEN_PCIDEV_BACKEND
++      default XEN_PCIDEV_BACKEND_VPCI if !IA64
++      default XEN_PCIDEV_BACKEND_CONTROLLER if IA64
++
++config XEN_PCIDEV_BACKEND_VPCI
++      bool "Virtual PCI"
++      ---help---
++        This PCI Backend hides the true PCI topology and makes the frontend
++        think there is a single PCI bus with only the exported devices on it.
++        For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
++        second device at 02:1a.1 will be re-assigned to 00:01.1.
++
++config XEN_PCIDEV_BACKEND_PASS
++      bool "Passthrough"
++      ---help---
++        This PCI Backend provides a real view of the PCI topology to the
++        frontend (for example, a device at 06:01.b will still appear at
++        06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
++        PCI devices to its driver domains. This may be required for drivers
++        which depend on finding their hardward in certain bus/slot
++        locations.
++
++config XEN_PCIDEV_BACKEND_SLOT
++      bool "Slot"
++      ---help---
++        This PCI Backend hides the true PCI topology and makes the frontend
++        think there is a single PCI bus with only the exported devices on it.
++        Contrary to the virtual PCI backend, a function becomes a new slot.
++        For example, a device at 03:05.2 will be re-assigned to 00:00.0. A
++        second device at 02:1a.1 will be re-assigned to 00:01.0.
++
++config XEN_PCIDEV_BACKEND_CONTROLLER
++      bool "Controller"
++      depends on IA64
++      ---help---
++        This PCI backend virtualizes the PCI bus topology by providing a
++        virtual bus per PCI root device.  Devices which are physically under
++        the same root bus will appear on the same virtual bus.  For systems
++        with complex I/O addressing, this is the only backend which supports
++        extended I/O port spaces and MMIO translation offsets.  This backend
++        also supports slot virtualization.  For example, a device at
++        0000:01:02.1 will be re-assigned to 0000:00:00.0.  A second device
++        at 0000:02:05.0 (behind a P2P bridge on bus 0000:01) will be
++        re-assigned to 0000:00:01.0.  A third device at 0000:16:05.0 (under
++        a different PCI root bus) will be re-assigned to 0000:01:00.0.
++
++endchoice
++
++config XEN_PCIDEV_BE_DEBUG
++      bool "PCI Backend Debugging"
++      depends on XEN_PCIDEV_BACKEND
++
++config XEN_TPMDEV_BACKEND
++      tristate "TPM-device backend driver"
++        depends on XEN_BACKEND
++      help
++        The TPM-device backend driver
++
++config XEN_BLKDEV_FRONTEND
++      tristate "Block-device frontend driver"
++      default y
++      help
++        The block-device frontend driver allows the kernel to access block
++        devices mounted within another guest OS. Unless you are building a
++        dedicated device-driver domain, or your master control domain
++        (domain 0), then you almost certainly want to say Y here.
++
++config XEN_NETDEV_FRONTEND
++      tristate "Network-device frontend driver"
++      depends on NET
++      default y
++      help
++        The network-device frontend driver allows the kernel to access
++        network interfaces within another guest OS. Unless you are building a
++        dedicated device-driver domain, or your master control domain
++        (domain 0), then you almost certainly want to say Y here.
++
++config XEN_NETDEV_ACCEL_SFC_FRONTEND
++      tristate "Network-device frontend driver acceleration for Solarflare NICs"
++      depends on XEN_NETDEV_FRONTEND && X86
++      select XEN_NETDEV_ACCEL_SFC_UTIL
++      default m
++
++config XEN_GRANT_DEV
++      tristate "User-space granted page access driver"
++      default XEN_PRIVILEGED_GUEST
++      help
++        Device for accessing (in user-space) pages that have been granted
++        by other domains.
++
++config XEN_FRAMEBUFFER
++      tristate "Framebuffer-device frontend driver"
++      depends on FB
++      select FB_CFB_FILLRECT
++      select FB_CFB_COPYAREA
++      select FB_CFB_IMAGEBLIT
++      default y
++      help
++        The framebuffer-device frontend drivers allows the kernel to create a
++        virtual framebuffer.  This framebuffer can be viewed in another
++        domain.  Unless this domain has access to a real video card, you
++        probably want to say Y here.
++
++config XEN_KEYBOARD
++      tristate "Keyboard-device frontend driver"
++      depends on XEN_FRAMEBUFFER && INPUT
++      default y
++      help
++        The keyboard-device frontend driver allows the kernel to create a
++        virtual keyboard.  This keyboard can then be driven by another
++        domain.  If you've said Y to CONFIG_XEN_FRAMEBUFFER, you probably
++        want to say Y here.
++
++config XEN_SCRUB_PAGES
++      bool "Scrub memory before freeing it to Xen"
++      default y
++      help
++        Erase memory contents before freeing it back to Xen's global
++        pool. This ensures that any secrets contained within that
++        memory (e.g., private keys) cannot be found by other guests that
++        may be running on the machine. Most people will want to say Y here.
++        If security is not a concern then you may increase performance by
++        saying N.
++
++config XEN_DISABLE_SERIAL
++      bool "Disable serial port drivers"
++      default y
++      help
++        Disable serial port drivers, allowing the Xen console driver
++        to provide a serial console at ttyS0.
++
++config XEN_SYSFS
++      tristate "Export Xen attributes in sysfs"
++      depends on SYSFS
++      select SYS_HYPERVISOR
++      default y
++      help
++        Xen hypervisor attributes will show up under /sys/hypervisor/.
++
++choice
++      prompt "Xen version compatibility"
++      default XEN_COMPAT_030002_AND_LATER
++
++      config XEN_COMPAT_030002_AND_LATER
++              bool "3.0.2 and later"
++
++      config XEN_COMPAT_030004_AND_LATER
++              bool "3.0.4 and later"
++
++      config XEN_COMPAT_030100_AND_LATER
++              bool "3.1.0 and later"
++
++      config XEN_COMPAT_LATEST_ONLY
++              bool "no compatibility code"
++
++endchoice
++
++config XEN_COMPAT
++      hex
++      default 0xffffff if XEN_COMPAT_LATEST_ONLY
++      default 0x030100 if XEN_COMPAT_030100_AND_LATER
++      default 0x030004 if XEN_COMPAT_030004_AND_LATER
++      default 0x030002 if XEN_COMPAT_030002_AND_LATER
++      default 0
++
++endmenu
++
++config HAVE_IRQ_IGNORE_UNHANDLED
++      def_bool y
++
++config NO_IDLE_HZ
++      def_bool y
++
++config XEN_SMPBOOT
++      def_bool y
++      depends on SMP && !PPC_XEN
++
++config XEN_BALLOON
++      def_bool y
++      depends on !PPC_XEN
++
++config XEN_XENCOMM
++      bool
++
++config XEN_DEVMEM
++      def_bool y
++
++endif
+--- linux-2.6.18.8/drivers/xen/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/Makefile   2008-05-19 00:33:45.662778175 +0300
+@@ -0,0 +1,23 @@
++obj-y += core/
++obj-y += console/
++obj-y += evtchn/
++obj-y += xenbus/
++obj-y += char/
++
++obj-y += util.o
++obj-$(CONFIG_XEN_BALLOON)             += balloon/
++obj-$(CONFIG_XEN_BLKDEV_BACKEND)      += blkback/
++obj-$(CONFIG_XEN_BLKDEV_TAP)          += blktap/
++obj-$(CONFIG_XEN_NETDEV_BACKEND)      += netback/
++obj-$(CONFIG_XEN_TPMDEV_BACKEND)      += tpmback/
++obj-$(CONFIG_XEN_BLKDEV_FRONTEND)     += blkfront/
++obj-$(CONFIG_XEN_NETDEV_FRONTEND)     += netfront/
++obj-$(CONFIG_XEN_PCIDEV_BACKEND)      += pciback/
++obj-$(CONFIG_XEN_PCIDEV_FRONTEND)     += pcifront/
++obj-$(CONFIG_XEN_FRAMEBUFFER)         += fbfront/
++obj-$(CONFIG_XEN_KEYBOARD)            += fbfront/
++obj-$(CONFIG_XEN_PRIVCMD)     += privcmd/
++obj-$(CONFIG_XEN_GRANT_DEV)   += gntdev/
++obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL)               += sfc_netutil/
++obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND)   += sfc_netfront/
++obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND)    += sfc_netback/
+--- linux-2.6.18.8/drivers/xen/balloon/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/balloon/Makefile   2008-05-19 00:33:45.674778867 +0300
+@@ -0,0 +1,2 @@
++
++obj-y := balloon.o sysfs.o
+--- linux-2.6.18.8/drivers/xen/balloon/balloon.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/balloon/balloon.c  2008-05-19 00:33:45.674778867 +0300
+@@ -0,0 +1,724 @@
++/******************************************************************************
++ * balloon.c
++ *
++ * Xen balloon driver - enables returning/claiming memory to/from Xen.
++ *
++ * Copyright (c) 2003, B Dragovic
++ * Copyright (c) 2003-2004, M Williamson, K Fraser
++ * Copyright (c) 2005 Dan M. Smith, IBM Corporation
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/mman.h>
++#include <linux/smp_lock.h>
++#include <linux/pagemap.h>
++#include <linux/bootmem.h>
++#include <linux/highmem.h>
++#include <linux/vmalloc.h>
++#include <linux/mutex.h>
++#include <xen/xen_proc.h>
++#include <asm/hypervisor.h>
++#include <xen/balloon.h>
++#include <xen/interface/memory.h>
++#include <asm/maddr.h>
++#include <asm/page.h>
++#include <asm/pgalloc.h>
++#include <asm/pgtable.h>
++#include <asm/uaccess.h>
++#include <asm/tlb.h>
++#include <linux/highmem.h>
++#include <linux/list.h>
++#include <xen/xenbus.h>
++#include "common.h"
++
++#ifdef HAVE_XEN_PLATFORM_COMPAT_H
++#include <xen/platform-compat.h>
++#endif
++
++#ifdef CONFIG_PROC_FS
++static struct proc_dir_entry *balloon_pde;
++#endif
++
++static DEFINE_MUTEX(balloon_mutex);
++
++/*
++ * Protects atomic reservation decrease/increase against concurrent increases.
++ * Also protects non-atomic updates of current_pages and driver_pages, and
++ * balloon lists.
++ */
++DEFINE_SPINLOCK(balloon_lock);
++
++struct balloon_stats balloon_stats;
++
++/* We increase/decrease in batches which fit in a page */
++static unsigned long frame_list[PAGE_SIZE / sizeof(unsigned long)];
++
++/* VM /proc information for memory */
++extern unsigned long totalram_pages;
++
++#ifndef MODULE
++extern unsigned long totalhigh_pages;
++#define inc_totalhigh_pages() (totalhigh_pages++)
++#define dec_totalhigh_pages() (totalhigh_pages--)
++#else
++#define inc_totalhigh_pages() ((void)0)
++#define dec_totalhigh_pages() ((void)0)
++#endif
++
++/* List of ballooned pages, threaded through the mem_map array. */
++static LIST_HEAD(ballooned_pages);
++
++/* Main work function, always executed in process context. */
++static void balloon_process(void *unused);
++static DECLARE_WORK(balloon_worker, balloon_process, NULL);
++static struct timer_list balloon_timer;
++
++/* When ballooning out (allocating memory to return to Xen) we don't really 
++   want the kernel to try too hard since that can trigger the oom killer. */
++#define GFP_BALLOON \
++      (GFP_HIGHUSER|__GFP_NOWARN|__GFP_NORETRY|__GFP_NOMEMALLOC|__GFP_COLD)
++
++#define PAGE_TO_LIST(p) (&(p)->lru)
++#define LIST_TO_PAGE(l) list_entry((l), struct page, lru)
++#define UNLIST_PAGE(p)                                \
++      do {                                    \
++              list_del(PAGE_TO_LIST(p));      \
++              PAGE_TO_LIST(p)->next = NULL;   \
++              PAGE_TO_LIST(p)->prev = NULL;   \
++      } while(0)
++
++#define IPRINTK(fmt, args...) \
++      printk(KERN_INFO "xen_mem: " fmt, ##args)
++#define WPRINTK(fmt, args...) \
++      printk(KERN_WARNING "xen_mem: " fmt, ##args)
++
++/* balloon_append: add the given page to the balloon. */
++static void balloon_append(struct page *page)
++{
++      /* Lowmem is re-populated first, so highmem pages go at list tail. */
++      if (PageHighMem(page)) {
++              list_add_tail(PAGE_TO_LIST(page), &ballooned_pages);
++              bs.balloon_high++;
++              dec_totalhigh_pages();
++      } else {
++              list_add(PAGE_TO_LIST(page), &ballooned_pages);
++              bs.balloon_low++;
++      }
++}
++
++/* balloon_retrieve: rescue a page from the balloon, if it is not empty. */
++static struct page *balloon_retrieve(void)
++{
++      struct page *page;
++
++      if (list_empty(&ballooned_pages))
++              return NULL;
++
++      page = LIST_TO_PAGE(ballooned_pages.next);
++      UNLIST_PAGE(page);
++
++      if (PageHighMem(page)) {
++              bs.balloon_high--;
++              inc_totalhigh_pages();
++      }
++      else
++              bs.balloon_low--;
++
++      return page;
++}
++
++static struct page *balloon_first_page(void)
++{
++      if (list_empty(&ballooned_pages))
++              return NULL;
++      return LIST_TO_PAGE(ballooned_pages.next);
++}
++
++static struct page *balloon_next_page(struct page *page)
++{
++      struct list_head *next = PAGE_TO_LIST(page)->next;
++      if (next == &ballooned_pages)
++              return NULL;
++      return LIST_TO_PAGE(next);
++}
++
++static inline void balloon_free_page(struct page *page)
++{
++#ifndef MODULE
++      if (put_page_testzero(page))
++              free_cold_page(page);
++#else
++      /* free_cold_page() is not being exported. */
++      __free_page(page);
++#endif
++}
++
++static void balloon_alarm(unsigned long unused)
++{
++      schedule_work(&balloon_worker);
++}
++
++static unsigned long current_target(void)
++{
++      unsigned long target = min(bs.target_pages, bs.hard_limit);
++      if (target > (bs.current_pages + bs.balloon_low + bs.balloon_high))
++              target = bs.current_pages + bs.balloon_low + bs.balloon_high;
++      return target;
++}
++
++static unsigned long minimum_target(void)
++{
++#ifndef CONFIG_XEN
++#define max_pfn num_physpages
++#endif
++      unsigned long min_pages, curr_pages = current_target();
++
++#define MB2PAGES(mb) ((mb) << (20 - PAGE_SHIFT))
++      /* Simple continuous piecewiese linear function:
++       *  max MiB -> min MiB  gradient
++       *       0         0
++       *      16        16
++       *      32        24
++       *     128        72    (1/2)
++       *     512       168    (1/4)
++       *    2048       360    (1/8)
++       *    8192       552    (1/32)
++       *   32768      1320
++       *  131072      4392
++       */
++      if (max_pfn < MB2PAGES(128))
++              min_pages = MB2PAGES(8) + (max_pfn >> 1);
++      else if (max_pfn < MB2PAGES(512))
++              min_pages = MB2PAGES(40) + (max_pfn >> 2);
++      else if (max_pfn < MB2PAGES(2048))
++              min_pages = MB2PAGES(104) + (max_pfn >> 3);
++      else
++              min_pages = MB2PAGES(296) + (max_pfn >> 5);
++#undef MB2PAGES
++
++      /* Don't enforce growth */
++      return min(min_pages, curr_pages);
++#ifndef CONFIG_XEN
++#undef max_pfn
++#endif
++}
++
++static int increase_reservation(unsigned long nr_pages)
++{
++      unsigned long  pfn, i, flags;
++      struct page   *page;
++      long           rc;
++      struct xen_memory_reservation reservation = {
++              .address_bits = 0,
++              .extent_order = 0,
++              .domid        = DOMID_SELF
++      };
++
++      if (nr_pages > ARRAY_SIZE(frame_list))
++              nr_pages = ARRAY_SIZE(frame_list);
++
++      balloon_lock(flags);
++
++      page = balloon_first_page();
++      for (i = 0; i < nr_pages; i++) {
++              BUG_ON(page == NULL);
++              frame_list[i] = page_to_pfn(page);;
++              page = balloon_next_page(page);
++      }
++
++      set_xen_guest_handle(reservation.extent_start, frame_list);
++      reservation.nr_extents   = nr_pages;
++      rc = HYPERVISOR_memory_op(
++              XENMEM_populate_physmap, &reservation);
++      if (rc < nr_pages) {
++              if (rc > 0) {
++                      int ret;
++
++                      /* We hit the Xen hard limit: reprobe. */
++                      reservation.nr_extents = rc;
++                      ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
++                                      &reservation);
++                      BUG_ON(ret != rc);
++              }
++              if (rc >= 0)
++                      bs.hard_limit = (bs.current_pages + rc -
++                                       bs.driver_pages);
++              goto out;
++      }
++
++      for (i = 0; i < nr_pages; i++) {
++              page = balloon_retrieve();
++              BUG_ON(page == NULL);
++
++              pfn = page_to_pfn(page);
++              BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap) &&
++                     phys_to_machine_mapping_valid(pfn));
++
++              set_phys_to_machine(pfn, frame_list[i]);
++
++#ifdef CONFIG_XEN
++              /* Link back into the page tables if not highmem. */
++              if (pfn < max_low_pfn) {
++                      int ret;
++                      ret = HYPERVISOR_update_va_mapping(
++                              (unsigned long)__va(pfn << PAGE_SHIFT),
++                              pfn_pte_ma(frame_list[i], PAGE_KERNEL),
++                              0);
++                      BUG_ON(ret);
++              }
++#endif
++
++              /* Relinquish the page back to the allocator. */
++              ClearPageReserved(page);
++              init_page_count(page);
++              balloon_free_page(page);
++      }
++
++      bs.current_pages += nr_pages;
++      totalram_pages = bs.current_pages;
++
++ out:
++      balloon_unlock(flags);
++
++      return 0;
++}
++
++static int decrease_reservation(unsigned long nr_pages)
++{
++      unsigned long  pfn, i, flags;
++      struct page   *page;
++      void          *v;
++      int            need_sleep = 0;
++      int ret;
++      struct xen_memory_reservation reservation = {
++              .address_bits = 0,
++              .extent_order = 0,
++              .domid        = DOMID_SELF
++      };
++
++      if (nr_pages > ARRAY_SIZE(frame_list))
++              nr_pages = ARRAY_SIZE(frame_list);
++
++      for (i = 0; i < nr_pages; i++) {
++              if ((page = alloc_page(GFP_BALLOON)) == NULL) {
++                      nr_pages = i;
++                      need_sleep = 1;
++                      break;
++              }
++
++              pfn = page_to_pfn(page);
++              frame_list[i] = pfn_to_mfn(pfn);
++
++              if (!PageHighMem(page)) {
++                      v = phys_to_virt(pfn << PAGE_SHIFT);
++                      scrub_pages(v, 1);
++#ifdef CONFIG_XEN
++                      ret = HYPERVISOR_update_va_mapping(
++                              (unsigned long)v, __pte_ma(0), 0);
++                      BUG_ON(ret);
++#endif
++              }
++#ifdef CONFIG_XEN_SCRUB_PAGES
++              else {
++                      v = kmap(page);
++                      scrub_pages(v, 1);
++                      kunmap(page);
++              }
++#endif
++      }
++
++#ifdef CONFIG_XEN
++      /* Ensure that ballooned highmem pages don't have kmaps. */
++      kmap_flush_unused();
++      flush_tlb_all();
++#endif
++
++      balloon_lock(flags);
++
++      /* No more mappings: invalidate P2M and add to balloon. */
++      for (i = 0; i < nr_pages; i++) {
++              pfn = mfn_to_pfn(frame_list[i]);
++              set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
++              balloon_append(pfn_to_page(pfn));
++      }
++
++      set_xen_guest_handle(reservation.extent_start, frame_list);
++      reservation.nr_extents   = nr_pages;
++      ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
++      BUG_ON(ret != nr_pages);
++
++      bs.current_pages -= nr_pages;
++      totalram_pages = bs.current_pages;
++
++      balloon_unlock(flags);
++
++      return need_sleep;
++}
++
++/*
++ * We avoid multiple worker processes conflicting via the balloon mutex.
++ * We may of course race updates of the target counts (which are protected
++ * by the balloon lock), or with changes to the Xen hard limit, but we will
++ * recover from these in time.
++ */
++static void balloon_process(void *unused)
++{
++      int need_sleep = 0;
++      long credit;
++
++      mutex_lock(&balloon_mutex);
++
++      do {
++              credit = current_target() - bs.current_pages;
++              if (credit > 0)
++                      need_sleep = (increase_reservation(credit) != 0);
++              if (credit < 0)
++                      need_sleep = (decrease_reservation(-credit) != 0);
++
++#ifndef CONFIG_PREEMPT
++              if (need_resched())
++                      schedule();
++#endif
++      } while ((credit != 0) && !need_sleep);
++
++      /* Schedule more work if there is some still to be done. */
++      if (current_target() != bs.current_pages)
++              mod_timer(&balloon_timer, jiffies + HZ);
++
++      mutex_unlock(&balloon_mutex);
++}
++
++/* Resets the Xen limit, sets new target, and kicks off processing. */
++void balloon_set_new_target(unsigned long target)
++{
++      /* No need for lock. Not read-modify-write updates. */
++      bs.hard_limit   = ~0UL;
++      bs.target_pages = max(target, minimum_target());
++      schedule_work(&balloon_worker);
++}
++
++static struct xenbus_watch target_watch =
++{
++      .node = "memory/target"
++};
++
++/* React to a change in the target key */
++static void watch_target(struct xenbus_watch *watch,
++                       const char **vec, unsigned int len)
++{
++      unsigned long long new_target;
++      int err;
++
++      err = xenbus_scanf(XBT_NIL, "memory", "target", "%llu", &new_target);
++      if (err != 1) {
++              /* This is ok (for domain0 at least) - so just return */
++              return;
++      }
++
++      /* The given memory/target value is in KiB, so it needs converting to
++       * pages. PAGE_SHIFT converts bytes to pages, hence PAGE_SHIFT - 10.
++       */
++      balloon_set_new_target(new_target >> (PAGE_SHIFT - 10));
++}
++
++static int balloon_init_watcher(struct notifier_block *notifier,
++                              unsigned long event,
++                              void *data)
++{
++      int err;
++
++      err = register_xenbus_watch(&target_watch);
++      if (err)
++              printk(KERN_ERR "Failed to set balloon watcher\n");
++
++      return NOTIFY_DONE;
++}
++
++#ifdef CONFIG_PROC_FS
++static int balloon_write(struct file *file, const char __user *buffer,
++                       unsigned long count, void *data)
++{
++      char memstring[64], *endchar;
++      unsigned long long target_bytes;
++
++      if (!capable(CAP_SYS_ADMIN))
++              return -EPERM;
++
++      if (count <= 1)
++              return -EBADMSG; /* runt */
++      if (count > sizeof(memstring))
++              return -EFBIG;   /* too long */
++
++      if (copy_from_user(memstring, buffer, count))
++              return -EFAULT;
++      memstring[sizeof(memstring)-1] = '\0';
++
++      target_bytes = memparse(memstring, &endchar);
++      balloon_set_new_target(target_bytes >> PAGE_SHIFT);
++
++      return count;
++}
++
++static int balloon_read(char *page, char **start, off_t off,
++                      int count, int *eof, void *data)
++{
++      int len;
++
++      len = sprintf(
++              page,
++              "Current allocation: %8lu kB\n"
++              "Requested target:   %8lu kB\n"
++              "Low-mem balloon:    %8lu kB\n"
++              "High-mem balloon:   %8lu kB\n"
++              "Driver pages:       %8lu kB\n"
++              "Xen hard limit:     ",
++              PAGES2KB(bs.current_pages), PAGES2KB(bs.target_pages), 
++              PAGES2KB(bs.balloon_low), PAGES2KB(bs.balloon_high),
++              PAGES2KB(bs.driver_pages));
++
++      if (bs.hard_limit != ~0UL)
++              len += sprintf(page + len, "%8lu kB\n",
++                             PAGES2KB(bs.hard_limit));
++      else
++              len += sprintf(page + len, "     ??? kB\n");
++
++      *eof = 1;
++      return len;
++}
++#endif
++
++static struct notifier_block xenstore_notifier;
++
++static int __init balloon_init(void)
++{
++#if defined(CONFIG_X86) && defined(CONFIG_XEN) 
++      unsigned long pfn;
++      struct page *page;
++#endif
++
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      IPRINTK("Initialising balloon driver.\n");
++
++#ifdef CONFIG_XEN
++      bs.current_pages = min(xen_start_info->nr_pages, max_pfn);
++      totalram_pages   = bs.current_pages;
++#else 
++      bs.current_pages = totalram_pages; 
++#endif
++      bs.target_pages  = bs.current_pages;
++      bs.balloon_low   = 0;
++      bs.balloon_high  = 0;
++      bs.driver_pages  = 0UL;
++      bs.hard_limit    = ~0UL;
++
++      init_timer(&balloon_timer);
++      balloon_timer.data = 0;
++      balloon_timer.function = balloon_alarm;
++    
++#ifdef CONFIG_PROC_FS
++      if ((balloon_pde = create_xen_proc_entry("balloon", 0644)) == NULL) {
++              WPRINTK("Unable to create /proc/xen/balloon.\n");
++              return -1;
++      }
++
++      balloon_pde->read_proc  = balloon_read;
++      balloon_pde->write_proc = balloon_write;
++#endif
++      balloon_sysfs_init();
++
++#if defined(CONFIG_X86) && defined(CONFIG_XEN) 
++      /* Initialise the balloon with excess memory space. */
++      for (pfn = xen_start_info->nr_pages; pfn < max_pfn; pfn++) {
++              page = pfn_to_page(pfn);
++              if (!PageReserved(page))
++                      balloon_append(page);
++      }
++#endif
++
++      target_watch.callback = watch_target;
++      xenstore_notifier.notifier_call = balloon_init_watcher;
++
++      register_xenstore_notifier(&xenstore_notifier);
++    
++      return 0;
++}
++
++subsys_initcall(balloon_init);
++
++static void __exit balloon_exit(void)
++{
++    /* XXX - release balloon here */
++    return; 
++}
++
++module_exit(balloon_exit); 
++
++void balloon_update_driver_allowance(long delta)
++{
++      unsigned long flags;
++
++      balloon_lock(flags);
++      bs.driver_pages += delta;
++      balloon_unlock(flags);
++}
++
++#ifdef CONFIG_XEN
++static int dealloc_pte_fn(
++      pte_t *pte, struct page *pmd_page, unsigned long addr, void *data)
++{
++      unsigned long mfn = pte_mfn(*pte);
++      int ret;
++      struct xen_memory_reservation reservation = {
++              .nr_extents   = 1,
++              .extent_order = 0,
++              .domid        = DOMID_SELF
++      };
++      set_xen_guest_handle(reservation.extent_start, &mfn);
++      set_pte_at(&init_mm, addr, pte, __pte_ma(0));
++      set_phys_to_machine(__pa(addr) >> PAGE_SHIFT, INVALID_P2M_ENTRY);
++      ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation, &reservation);
++      BUG_ON(ret != 1);
++      return 0;
++}
++#endif
++
++struct page **alloc_empty_pages_and_pagevec(int nr_pages)
++{
++      unsigned long flags;
++      void *v;
++      struct page *page, **pagevec;
++      int i, ret;
++
++      pagevec = kmalloc(sizeof(page) * nr_pages, GFP_KERNEL);
++      if (pagevec == NULL)
++              return NULL;
++
++      for (i = 0; i < nr_pages; i++) {
++              page = pagevec[i] = alloc_page(GFP_KERNEL|__GFP_COLD);
++              if (page == NULL)
++                      goto err;
++
++              v = page_address(page);
++              scrub_pages(v, 1);
++
++              balloon_lock(flags);
++
++              if (xen_feature(XENFEAT_auto_translated_physmap)) {
++                      unsigned long gmfn = page_to_pfn(page);
++                      struct xen_memory_reservation reservation = {
++                              .nr_extents   = 1,
++                              .extent_order = 0,
++                              .domid        = DOMID_SELF
++                      };
++                      set_xen_guest_handle(reservation.extent_start, &gmfn);
++                      ret = HYPERVISOR_memory_op(XENMEM_decrease_reservation,
++                                                 &reservation);
++                      if (ret == 1)
++                              ret = 0; /* success */
++              } else {
++#ifdef CONFIG_XEN
++                      ret = apply_to_page_range(&init_mm, (unsigned long)v,
++                                                PAGE_SIZE, dealloc_pte_fn,
++                                                NULL);
++#else
++                      /* Cannot handle non-auto translate mode. */
++                      ret = 1;
++#endif
++              }
++
++              if (ret != 0) {
++                      balloon_unlock(flags);
++                      balloon_free_page(page);
++                      goto err;
++              }
++
++              totalram_pages = --bs.current_pages;
++
++              balloon_unlock(flags);
++      }
++
++ out:
++      schedule_work(&balloon_worker);
++#ifdef CONFIG_XEN
++      flush_tlb_all();
++#endif
++      return pagevec;
++
++ err:
++      balloon_lock(flags);
++      while (--i >= 0)
++              balloon_append(pagevec[i]);
++      balloon_unlock(flags);
++      kfree(pagevec);
++      pagevec = NULL;
++      goto out;
++}
++
++void free_empty_pages_and_pagevec(struct page **pagevec, int nr_pages)
++{
++      unsigned long flags;
++      int i;
++
++      if (pagevec == NULL)
++              return;
++
++      balloon_lock(flags);
++      for (i = 0; i < nr_pages; i++) {
++              BUG_ON(page_count(pagevec[i]) != 1);
++              balloon_append(pagevec[i]);
++      }
++      balloon_unlock(flags);
++
++      kfree(pagevec);
++
++      schedule_work(&balloon_worker);
++}
++
++void balloon_release_driver_page(struct page *page)
++{
++      unsigned long flags;
++
++      balloon_lock(flags);
++      balloon_append(page);
++      bs.driver_pages--;
++      balloon_unlock(flags);
++
++      schedule_work(&balloon_worker);
++}
++
++EXPORT_SYMBOL_GPL(balloon_update_driver_allowance);
++EXPORT_SYMBOL_GPL(alloc_empty_pages_and_pagevec);
++EXPORT_SYMBOL_GPL(free_empty_pages_and_pagevec);
++EXPORT_SYMBOL_GPL(balloon_release_driver_page);
++
++MODULE_LICENSE("Dual BSD/GPL");
+--- linux-2.6.18.8/drivers/xen/balloon/common.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/balloon/common.h   2008-05-19 00:33:45.674778867 +0300
+@@ -0,0 +1,58 @@
++/******************************************************************************
++ * balloon/common.h
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef __XEN_BALLOON_COMMON_H__
++#define __XEN_BALLOON_COMMON_H__
++
++#define PAGES2KB(_p) ((_p)<<(PAGE_SHIFT-10))
++
++struct balloon_stats {
++      /* We aim for 'current allocation' == 'target allocation'. */
++      unsigned long current_pages;
++      unsigned long target_pages;
++      /* We may hit the hard limit in Xen. If we do then we remember it. */
++      unsigned long hard_limit;
++      /*
++       * Drivers may alter the memory reservation independently, but they
++       * must inform the balloon driver so we avoid hitting the hard limit.
++       */
++      unsigned long driver_pages;
++      /* Number of pages in high- and low-memory balloons. */
++      unsigned long balloon_low;
++      unsigned long balloon_high;
++};
++
++extern struct balloon_stats balloon_stats;
++#define bs balloon_stats
++
++int balloon_sysfs_init(void);
++void balloon_sysfs_exit(void);
++
++void balloon_set_new_target(unsigned long target);
++
++#endif /* __XEN_BALLOON_COMMON_H__ */
+--- linux-2.6.18.8/drivers/xen/balloon/sysfs.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/balloon/sysfs.c    2008-05-19 00:33:45.678779098 +0300
+@@ -0,0 +1,170 @@
++/******************************************************************************
++ * balloon/sysfs.c
++ *
++ * Xen balloon driver - sysfs interfaces.
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/capability.h>
++#include <linux/errno.h>
++#include <linux/stat.h>
++#include <linux/string.h>
++#include <linux/sysdev.h>
++#include "common.h"
++
++#ifdef HAVE_XEN_PLATFORM_COMPAT_H
++#include <xen/platform-compat.h>
++#endif
++
++#define BALLOON_CLASS_NAME "xen_memory"
++
++#define BALLOON_SHOW(name, format, args...)                   \
++      static ssize_t show_##name(struct sys_device *dev,      \
++                                 char *buf)                   \
++      {                                                       \
++              return sprintf(buf, format, ##args);            \
++      }                                                       \
++      static SYSDEV_ATTR(name, S_IRUGO, show_##name, NULL)
++
++BALLOON_SHOW(current_kb, "%lu\n", PAGES2KB(bs.current_pages));
++BALLOON_SHOW(low_kb, "%lu\n", PAGES2KB(bs.balloon_low));
++BALLOON_SHOW(high_kb, "%lu\n", PAGES2KB(bs.balloon_high));
++BALLOON_SHOW(hard_limit_kb,
++           (bs.hard_limit!=~0UL) ? "%lu\n" : "???\n",
++           (bs.hard_limit!=~0UL) ? PAGES2KB(bs.hard_limit) : 0);
++BALLOON_SHOW(driver_kb, "%lu\n", PAGES2KB(bs.driver_pages));
++
++static ssize_t show_target_kb(struct sys_device *dev, char *buf)
++{
++      return sprintf(buf, "%lu\n", PAGES2KB(bs.target_pages));
++}
++
++static ssize_t store_target_kb(struct sys_device *dev,
++                             const char *buf,
++                             size_t count)
++{
++      char memstring[64], *endchar;
++      unsigned long long target_bytes;
++
++      if (!capable(CAP_SYS_ADMIN))
++              return -EPERM;
++      
++      if (count <= 1)
++              return -EBADMSG; /* runt */
++      if (count > sizeof(memstring))
++              return -EFBIG;   /* too long */
++      strcpy(memstring, buf);
++      
++      target_bytes = memparse(memstring, &endchar);
++      balloon_set_new_target(target_bytes >> PAGE_SHIFT);
++      
++      return count;
++}
++
++static SYSDEV_ATTR(target_kb, S_IRUGO | S_IWUSR,
++                 show_target_kb, store_target_kb);
++
++static struct sysdev_attribute *balloon_attrs[] = {
++      &attr_target_kb,
++};
++
++static struct attribute *balloon_info_attrs[] = {
++      &attr_current_kb.attr,
++      &attr_low_kb.attr,
++      &attr_high_kb.attr,
++      &attr_hard_limit_kb.attr,
++      &attr_driver_kb.attr,
++      NULL
++};
++
++static struct attribute_group balloon_info_group = {
++      .name = "info",
++      .attrs = balloon_info_attrs,
++};
++
++static struct sysdev_class balloon_sysdev_class = {
++      set_kset_name(BALLOON_CLASS_NAME),
++};
++
++static struct sys_device balloon_sysdev;
++
++static int register_balloon(struct sys_device *sysdev)
++{
++      int i, error;
++
++      error = sysdev_class_register(&balloon_sysdev_class);
++      if (error)
++              return error;
++
++      sysdev->id = 0;
++      sysdev->cls = &balloon_sysdev_class;
++
++      error = sysdev_register(sysdev);
++      if (error) {
++              sysdev_class_unregister(&balloon_sysdev_class);
++              return error;
++      }
++
++      for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++) {
++              error = sysdev_create_file(sysdev, balloon_attrs[i]);
++              if (error)
++                      goto fail;
++      }
++
++      error = sysfs_create_group(&sysdev->kobj, &balloon_info_group);
++      if (error)
++              goto fail;
++      
++      return 0;
++
++ fail:
++      while (--i >= 0)
++              sysdev_remove_file(sysdev, balloon_attrs[i]);
++      sysdev_unregister(sysdev);
++      sysdev_class_unregister(&balloon_sysdev_class);
++      return error;
++}
++
++static void unregister_balloon(struct sys_device *sysdev)
++{
++      int i;
++
++      sysfs_remove_group(&sysdev->kobj, &balloon_info_group);
++      for (i = 0; i < ARRAY_SIZE(balloon_attrs); i++)
++              sysdev_remove_file(sysdev, balloon_attrs[i]);
++      sysdev_unregister(sysdev);
++      sysdev_class_unregister(&balloon_sysdev_class);
++}
++
++int balloon_sysfs_init(void)
++{
++      return register_balloon(&balloon_sysdev);
++}
++
++void balloon_sysfs_exit(void)
++{
++      unregister_balloon(&balloon_sysdev);
++}
+--- linux-2.6.18.8/drivers/xen/blkback/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blkback/Makefile   2008-05-19 00:33:45.678779098 +0300
+@@ -0,0 +1,3 @@
++obj-$(CONFIG_XEN_BLKDEV_BACKEND) := blkbk.o
++
++blkbk-y       := blkback.o xenbus.o interface.o vbd.o
+--- linux-2.6.18.8/drivers/xen/blkback/blkback.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blkback/blkback.c  2008-05-19 00:33:45.678779098 +0300
+@@ -0,0 +1,646 @@
++/******************************************************************************
++ * arch/xen/drivers/blkif/backend/main.c
++ * 
++ * Back-end of the driver for virtual block devices. This portion of the
++ * driver exports a 'unified' block-device interface that can be accessed
++ * by any operating system that implements a compatible front end. A 
++ * reference front-end implementation can be found in:
++ *  arch/xen/drivers/blkif/frontend
++ * 
++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
++ * Copyright (c) 2005, Christopher Clark
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/spinlock.h>
++#include <linux/kthread.h>
++#include <linux/list.h>
++#include <linux/delay.h>
++#include <xen/balloon.h>
++#include <asm/hypervisor.h>
++#include "common.h"
++
++/*
++ * These are rather arbitrary. They are fairly large because adjacent requests
++ * pulled from a communication ring are quite likely to end up being part of
++ * the same scatter/gather request at the disc.
++ * 
++ * ** TRY INCREASING 'blkif_reqs' IF WRITE SPEEDS SEEM TOO LOW **
++ * 
++ * This will increase the chances of being able to write whole tracks.
++ * 64 should be enough to keep us competitive with Linux.
++ */
++static int blkif_reqs = 64;
++module_param_named(reqs, blkif_reqs, int, 0);
++MODULE_PARM_DESC(reqs, "Number of blkback requests to allocate");
++
++/* Run-time switchable: /sys/module/blkback/parameters/ */
++static unsigned int log_stats = 0;
++static unsigned int debug_lvl = 0;
++module_param(log_stats, int, 0644);
++module_param(debug_lvl, int, 0644);
++
++/*
++ * Each outstanding request that we've passed to the lower device layers has a 
++ * 'pending_req' allocated to it. Each buffer_head that completes decrements 
++ * the pendcnt towards zero. When it hits zero, the specified domain has a 
++ * response queued for it, with the saved 'id' passed back.
++ */
++typedef struct {
++      blkif_t       *blkif;
++      u64            id;
++      int            nr_pages;
++      atomic_t       pendcnt;
++      unsigned short operation;
++      int            status;
++      struct list_head free_list;
++} pending_req_t;
++
++static pending_req_t *pending_reqs;
++static struct list_head pending_free;
++static DEFINE_SPINLOCK(pending_free_lock);
++static DECLARE_WAIT_QUEUE_HEAD(pending_free_wq);
++
++#define BLKBACK_INVALID_HANDLE (~0)
++
++static struct page **pending_pages;
++static grant_handle_t *pending_grant_handles;
++
++static inline int vaddr_pagenr(pending_req_t *req, int seg)
++{
++      return (req - pending_reqs) * BLKIF_MAX_SEGMENTS_PER_REQUEST + seg;
++}
++
++static inline unsigned long vaddr(pending_req_t *req, int seg)
++{
++      unsigned long pfn = page_to_pfn(pending_pages[vaddr_pagenr(req, seg)]);
++      return (unsigned long)pfn_to_kaddr(pfn);
++}
++
++#define pending_handle(_req, _seg) \
++      (pending_grant_handles[vaddr_pagenr(_req, _seg)])
++
++
++static int do_block_io_op(blkif_t *blkif);
++static void dispatch_rw_block_io(blkif_t *blkif,
++                               blkif_request_t *req,
++                               pending_req_t *pending_req);
++static void make_response(blkif_t *blkif, u64 id,
++                        unsigned short op, int st);
++
++/******************************************************************
++ * misc small helpers
++ */
++static pending_req_t* alloc_req(void)
++{
++      pending_req_t *req = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&pending_free_lock, flags);
++      if (!list_empty(&pending_free)) {
++              req = list_entry(pending_free.next, pending_req_t, free_list);
++              list_del(&req->free_list);
++      }
++      spin_unlock_irqrestore(&pending_free_lock, flags);
++      return req;
++}
++
++static void free_req(pending_req_t *req)
++{
++      unsigned long flags;
++      int was_empty;
++
++      spin_lock_irqsave(&pending_free_lock, flags);
++      was_empty = list_empty(&pending_free);
++      list_add(&req->free_list, &pending_free);
++      spin_unlock_irqrestore(&pending_free_lock, flags);
++      if (was_empty)
++              wake_up(&pending_free_wq);
++}
++
++static void unplug_queue(blkif_t *blkif)
++{
++      if (blkif->plug == NULL)
++              return;
++      if (blkif->plug->unplug_fn)
++              blkif->plug->unplug_fn(blkif->plug);
++      blk_put_queue(blkif->plug);
++      blkif->plug = NULL;
++}
++
++static void plug_queue(blkif_t *blkif, struct bio *bio)
++{
++      request_queue_t *q = bdev_get_queue(bio->bi_bdev);
++
++      if (q == blkif->plug)
++              return;
++      unplug_queue(blkif);
++      blk_get_queue(q);
++      blkif->plug = q;
++}
++
++static void fast_flush_area(pending_req_t *req)
++{
++      struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
++      unsigned int i, invcount = 0;
++      grant_handle_t handle;
++      int ret;
++
++      for (i = 0; i < req->nr_pages; i++) {
++              handle = pending_handle(req, i);
++              if (handle == BLKBACK_INVALID_HANDLE)
++                      continue;
++              gnttab_set_unmap_op(&unmap[invcount], vaddr(req, i),
++                                  GNTMAP_host_map, handle);
++              pending_handle(req, i) = BLKBACK_INVALID_HANDLE;
++              invcount++;
++      }
++
++      ret = HYPERVISOR_grant_table_op(
++              GNTTABOP_unmap_grant_ref, unmap, invcount);
++      BUG_ON(ret);
++}
++
++/******************************************************************
++ * SCHEDULER FUNCTIONS
++ */
++
++static void print_stats(blkif_t *blkif)
++{
++      printk(KERN_DEBUG "%s: oo %3d  |  rd %4d  |  wr %4d  |  br %4d\n",
++             current->comm, blkif->st_oo_req,
++             blkif->st_rd_req, blkif->st_wr_req, blkif->st_br_req);
++      blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
++      blkif->st_rd_req = 0;
++      blkif->st_wr_req = 0;
++      blkif->st_oo_req = 0;
++}
++
++int blkif_schedule(void *arg)
++{
++      blkif_t *blkif = arg;
++
++      blkif_get(blkif);
++
++      if (debug_lvl)
++              printk(KERN_DEBUG "%s: started\n", current->comm);
++
++      while (!kthread_should_stop()) {
++              if (try_to_freeze())
++                      continue;
++
++              wait_event_interruptible(
++                      blkif->wq,
++                      blkif->waiting_reqs || kthread_should_stop());
++              wait_event_interruptible(
++                      pending_free_wq,
++                      !list_empty(&pending_free) || kthread_should_stop());
++
++              blkif->waiting_reqs = 0;
++              smp_mb(); /* clear flag *before* checking for work */
++
++              if (do_block_io_op(blkif))
++                      blkif->waiting_reqs = 1;
++              unplug_queue(blkif);
++
++              if (log_stats && time_after(jiffies, blkif->st_print))
++                      print_stats(blkif);
++      }
++
++      if (log_stats)
++              print_stats(blkif);
++      if (debug_lvl)
++              printk(KERN_DEBUG "%s: exiting\n", current->comm);
++
++      blkif->xenblkd = NULL;
++      blkif_put(blkif);
++
++      return 0;
++}
++
++/******************************************************************
++ * COMPLETION CALLBACK -- Called as bh->b_end_io()
++ */
++
++static void __end_block_io_op(pending_req_t *pending_req, int error)
++{
++      /* An error fails the entire request. */
++      if ((pending_req->operation == BLKIF_OP_WRITE_BARRIER) &&
++          (error == -EOPNOTSUPP)) {
++              DPRINTK("blkback: write barrier op failed, not supported\n");
++              blkback_barrier(XBT_NIL, pending_req->blkif->be, 0);
++              pending_req->status = BLKIF_RSP_EOPNOTSUPP;
++      } else if (error) {
++              DPRINTK("Buffer not up-to-date at end of operation, "
++                      "error=%d\n", error);
++              pending_req->status = BLKIF_RSP_ERROR;
++      }
++
++      if (atomic_dec_and_test(&pending_req->pendcnt)) {
++              fast_flush_area(pending_req);
++              make_response(pending_req->blkif, pending_req->id,
++                            pending_req->operation, pending_req->status);
++              blkif_put(pending_req->blkif);
++              free_req(pending_req);
++      }
++}
++
++static int end_block_io_op(struct bio *bio, unsigned int done, int error)
++{
++      if (bio->bi_size != 0)
++              return 1;
++      __end_block_io_op(bio->bi_private, error);
++      bio_put(bio);
++      return error;
++}
++
++
++/******************************************************************************
++ * NOTIFICATION FROM GUEST OS.
++ */
++
++static void blkif_notify_work(blkif_t *blkif)
++{
++      blkif->waiting_reqs = 1;
++      wake_up(&blkif->wq);
++}
++
++irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++      blkif_notify_work(dev_id);
++      return IRQ_HANDLED;
++}
++
++
++
++/******************************************************************
++ * DOWNWARD CALLS -- These interface with the block-device layer proper.
++ */
++
++static int do_block_io_op(blkif_t *blkif)
++{
++      blkif_back_rings_t *blk_rings = &blkif->blk_rings;
++      blkif_request_t req;
++      pending_req_t *pending_req;
++      RING_IDX rc, rp;
++      int more_to_do = 0;
++
++      rc = blk_rings->common.req_cons;
++      rp = blk_rings->common.sring->req_prod;
++      rmb(); /* Ensure we see queued requests up to 'rp'. */
++
++      while (rc != rp) {
++
++              if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc))
++                      break;
++
++              pending_req = alloc_req();
++              if (NULL == pending_req) {
++                      blkif->st_oo_req++;
++                      more_to_do = 1;
++                      break;
++              }
++
++              if (kthread_should_stop()) {
++                      more_to_do = 1;
++                      break;
++              }
++
++              switch (blkif->blk_protocol) {
++              case BLKIF_PROTOCOL_NATIVE:
++                      memcpy(&req, RING_GET_REQUEST(&blk_rings->native, rc), sizeof(req));
++                      break;
++              case BLKIF_PROTOCOL_X86_32:
++                      blkif_get_x86_32_req(&req, RING_GET_REQUEST(&blk_rings->x86_32, rc));
++                      break;
++              case BLKIF_PROTOCOL_X86_64:
++                      blkif_get_x86_64_req(&req, RING_GET_REQUEST(&blk_rings->x86_64, rc));
++                      break;
++              default:
++                      BUG();
++              }
++              blk_rings->common.req_cons = ++rc; /* before make_response() */
++
++              /* Apply all sanity checks to /private copy/ of request. */
++              barrier();
++
++              switch (req.operation) {
++              case BLKIF_OP_READ:
++                      blkif->st_rd_req++;
++                      dispatch_rw_block_io(blkif, &req, pending_req);
++                      break;
++              case BLKIF_OP_WRITE_BARRIER:
++                      blkif->st_br_req++;
++                      /* fall through */
++              case BLKIF_OP_WRITE:
++                      blkif->st_wr_req++;
++                      dispatch_rw_block_io(blkif, &req, pending_req);
++                      break;
++              default:
++                      /* A good sign something is wrong: sleep for a while to
++                       * avoid excessive CPU consumption by a bad guest. */
++                      msleep(1);
++                      DPRINTK("error: unknown block io operation [%d]\n",
++                              req.operation);
++                      make_response(blkif, req.id, req.operation,
++                                    BLKIF_RSP_ERROR);
++                      free_req(pending_req);
++                      break;
++              }
++
++              /* Yield point for this unbounded loop. */
++              cond_resched();
++      }
++
++      return more_to_do;
++}
++
++static void dispatch_rw_block_io(blkif_t *blkif,
++                               blkif_request_t *req,
++                               pending_req_t *pending_req)
++{
++      extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
++      struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST];
++      struct phys_req preq;
++      struct { 
++              unsigned long buf; unsigned int nsec;
++      } seg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
++      unsigned int nseg;
++      struct bio *bio = NULL, *biolist[BLKIF_MAX_SEGMENTS_PER_REQUEST];
++      int ret, i, nbio = 0;
++      int operation;
++
++      switch (req->operation) {
++      case BLKIF_OP_READ:
++              operation = READ;
++              break;
++      case BLKIF_OP_WRITE:
++              operation = WRITE;
++              break;
++      case BLKIF_OP_WRITE_BARRIER:
++              operation = WRITE_BARRIER;
++              break;
++      default:
++              operation = 0; /* make gcc happy */
++              BUG();
++      }
++
++      /* Check that number of segments is sane. */
++      nseg = req->nr_segments;
++      if (unlikely(nseg == 0 && operation != WRITE_BARRIER) || 
++          unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST)) {
++              DPRINTK("Bad number of segments in request (%d)\n", nseg);
++              goto fail_response;
++      }
++
++      preq.dev           = req->handle;
++      preq.sector_number = req->sector_number;
++      preq.nr_sects      = 0;
++
++      pending_req->blkif     = blkif;
++      pending_req->id        = req->id;
++      pending_req->operation = req->operation;
++      pending_req->status    = BLKIF_RSP_OKAY;
++      pending_req->nr_pages  = nseg;
++
++      for (i = 0; i < nseg; i++) {
++              uint32_t flags;
++
++              seg[i].nsec = req->seg[i].last_sect -
++                      req->seg[i].first_sect + 1;
++
++              if ((req->seg[i].last_sect >= (PAGE_SIZE >> 9)) ||
++                  (req->seg[i].last_sect < req->seg[i].first_sect))
++                      goto fail_response;
++              preq.nr_sects += seg[i].nsec;
++
++              flags = GNTMAP_host_map;
++              if (operation != READ)
++                      flags |= GNTMAP_readonly;
++              gnttab_set_map_op(&map[i], vaddr(pending_req, i), flags,
++                                req->seg[i].gref, blkif->domid);
++      }
++
++      ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, nseg);
++      BUG_ON(ret);
++
++      for (i = 0; i < nseg; i++) {
++              if (unlikely(map[i].status != 0)) {
++                      DPRINTK("invalid buffer -- could not remap it\n");
++                      map[i].handle = BLKBACK_INVALID_HANDLE;
++                      ret |= 1;
++              }
++
++              pending_handle(pending_req, i) = map[i].handle;
++
++              if (ret)
++                      continue;
++
++              set_phys_to_machine(__pa(vaddr(
++                      pending_req, i)) >> PAGE_SHIFT,
++                      FOREIGN_FRAME(map[i].dev_bus_addr >> PAGE_SHIFT));
++              seg[i].buf  = map[i].dev_bus_addr | 
++                      (req->seg[i].first_sect << 9);
++      }
++
++      if (ret)
++              goto fail_flush;
++
++      if (vbd_translate(&preq, blkif, operation) != 0) {
++              DPRINTK("access denied: %s of [%llu,%llu] on dev=%04x\n", 
++                      operation == READ ? "read" : "write",
++                      preq.sector_number,
++                      preq.sector_number + preq.nr_sects, preq.dev);
++              goto fail_flush;
++      }
++
++      for (i = 0; i < nseg; i++) {
++              if (((int)preq.sector_number|(int)seg[i].nsec) &
++                  ((bdev_hardsect_size(preq.bdev) >> 9) - 1)) {
++                      DPRINTK("Misaligned I/O request from domain %d",
++                              blkif->domid);
++                      goto fail_put_bio;
++              }
++
++              while ((bio == NULL) ||
++                     (bio_add_page(bio,
++                                   virt_to_page(vaddr(pending_req, i)),
++                                   seg[i].nsec << 9,
++                                   seg[i].buf & ~PAGE_MASK) == 0)) {
++                      bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, nseg-i);
++                      if (unlikely(bio == NULL))
++                              goto fail_put_bio;
++
++                      bio->bi_bdev    = preq.bdev;
++                      bio->bi_private = pending_req;
++                      bio->bi_end_io  = end_block_io_op;
++                      bio->bi_sector  = preq.sector_number;
++              }
++
++              preq.sector_number += seg[i].nsec;
++      }
++
++      if (!bio) {
++              BUG_ON(operation != WRITE_BARRIER);
++              bio = biolist[nbio++] = bio_alloc(GFP_KERNEL, 0);
++              if (unlikely(bio == NULL))
++                      goto fail_put_bio;
++
++              bio->bi_bdev    = preq.bdev;
++              bio->bi_private = pending_req;
++              bio->bi_end_io  = end_block_io_op;
++              bio->bi_sector  = -1;
++      }
++
++      plug_queue(blkif, bio);
++      atomic_set(&pending_req->pendcnt, nbio);
++      blkif_get(blkif);
++
++      for (i = 0; i < nbio; i++)
++              submit_bio(operation, biolist[i]);
++
++      if (operation == READ)
++              blkif->st_rd_sect += preq.nr_sects;
++      else if (operation == WRITE || operation == WRITE_BARRIER)
++              blkif->st_wr_sect += preq.nr_sects;
++
++      return;
++
++ fail_put_bio:
++      for (i = 0; i < (nbio-1); i++)
++              bio_put(biolist[i]);
++ fail_flush:
++      fast_flush_area(pending_req);
++ fail_response:
++      make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
++      free_req(pending_req);
++      msleep(1); /* back off a bit */
++} 
++
++
++
++/******************************************************************
++ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
++ */
++
++
++static void make_response(blkif_t *blkif, u64 id,
++                        unsigned short op, int st)
++{
++      blkif_response_t  resp;
++      unsigned long     flags;
++      blkif_back_rings_t *blk_rings = &blkif->blk_rings;
++      int more_to_do = 0;
++      int notify;
++
++      resp.id        = id;
++      resp.operation = op;
++      resp.status    = st;
++
++      spin_lock_irqsave(&blkif->blk_ring_lock, flags);
++      /* Place on the response ring for the relevant domain. */
++      switch (blkif->blk_protocol) {
++      case BLKIF_PROTOCOL_NATIVE:
++              memcpy(RING_GET_RESPONSE(&blk_rings->native, blk_rings->native.rsp_prod_pvt),
++                     &resp, sizeof(resp));
++              break;
++      case BLKIF_PROTOCOL_X86_32:
++              memcpy(RING_GET_RESPONSE(&blk_rings->x86_32, blk_rings->x86_32.rsp_prod_pvt),
++                     &resp, sizeof(resp));
++              break;
++      case BLKIF_PROTOCOL_X86_64:
++              memcpy(RING_GET_RESPONSE(&blk_rings->x86_64, blk_rings->x86_64.rsp_prod_pvt),
++                     &resp, sizeof(resp));
++              break;
++      default:
++              BUG();
++      }
++      blk_rings->common.rsp_prod_pvt++;
++      RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify);
++      if (blk_rings->common.rsp_prod_pvt == blk_rings->common.req_cons) {
++              /*
++               * Tail check for pending requests. Allows frontend to avoid
++               * notifications if requests are already in flight (lower
++               * overheads and promotes batching).
++               */
++              RING_FINAL_CHECK_FOR_REQUESTS(&blk_rings->common, more_to_do);
++
++      } else if (RING_HAS_UNCONSUMED_REQUESTS(&blk_rings->common)) {
++              more_to_do = 1;
++      }
++
++      spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
++
++      if (more_to_do)
++              blkif_notify_work(blkif);
++      if (notify)
++              notify_remote_via_irq(blkif->irq);
++}
++
++static int __init blkif_init(void)
++{
++      int i, mmap_pages;
++
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      mmap_pages = blkif_reqs * BLKIF_MAX_SEGMENTS_PER_REQUEST;
++
++      pending_reqs          = kmalloc(sizeof(pending_reqs[0]) *
++                                      blkif_reqs, GFP_KERNEL);
++      pending_grant_handles = kmalloc(sizeof(pending_grant_handles[0]) *
++                                      mmap_pages, GFP_KERNEL);
++      pending_pages         = alloc_empty_pages_and_pagevec(mmap_pages);
++
++      if (!pending_reqs || !pending_grant_handles || !pending_pages)
++              goto out_of_memory;
++
++      for (i = 0; i < mmap_pages; i++)
++              pending_grant_handles[i] = BLKBACK_INVALID_HANDLE;
++
++      blkif_interface_init();
++
++      memset(pending_reqs, 0, sizeof(pending_reqs));
++      INIT_LIST_HEAD(&pending_free);
++
++      for (i = 0; i < blkif_reqs; i++)
++              list_add_tail(&pending_reqs[i].free_list, &pending_free);
++
++      blkif_xenbus_init();
++
++      return 0;
++
++ out_of_memory:
++      kfree(pending_reqs);
++      kfree(pending_grant_handles);
++      free_empty_pages_and_pagevec(pending_pages, mmap_pages);
++      printk("%s: out of memory\n", __FUNCTION__);
++      return -ENOMEM;
++}
++
++module_init(blkif_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
+--- linux-2.6.18.8/drivers/xen/blkback/common.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blkback/common.h   2008-05-19 00:33:45.678779098 +0300
+@@ -0,0 +1,139 @@
++/* 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef __BLKIF__BACKEND__COMMON_H__
++#define __BLKIF__BACKEND__COMMON_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/blkdev.h>
++#include <linux/vmalloc.h>
++#include <linux/wait.h>
++#include <asm/io.h>
++#include <asm/setup.h>
++#include <asm/pgalloc.h>
++#include <xen/evtchn.h>
++#include <asm/hypervisor.h>
++#include <xen/blkif.h>
++#include <xen/gnttab.h>
++#include <xen/driver_util.h>
++#include <xen/xenbus.h>
++
++#define DPRINTK(_f, _a...)                    \
++      pr_debug("(file=%s, line=%d) " _f,      \
++               __FILE__ , __LINE__ , ## _a )
++
++struct vbd {
++      blkif_vdev_t   handle;      /* what the domain refers to this vbd as */
++      unsigned char  readonly;    /* Non-zero -> read-only */
++      unsigned char  type;        /* VDISK_xxx */
++      u32            pdevice;     /* phys device that this vbd maps to */
++      struct block_device *bdev;
++};
++
++struct backend_info;
++
++typedef struct blkif_st {
++      /* Unique identifier for this interface. */
++      domid_t           domid;
++      unsigned int      handle;
++      /* Physical parameters of the comms window. */
++      unsigned int      irq;
++      /* Comms information. */
++      enum blkif_protocol blk_protocol;
++      blkif_back_rings_t blk_rings;
++      struct vm_struct *blk_ring_area;
++      /* The VBD attached to this interface. */
++      struct vbd        vbd;
++      /* Back pointer to the backend_info. */
++      struct backend_info *be;
++      /* Private fields. */
++      spinlock_t       blk_ring_lock;
++      atomic_t         refcnt;
++
++      wait_queue_head_t   wq;
++      struct task_struct  *xenblkd;
++      unsigned int        waiting_reqs;
++      request_queue_t     *plug;
++
++      /* statistics */
++      unsigned long       st_print;
++      int                 st_rd_req;
++      int                 st_wr_req;
++      int                 st_oo_req;
++      int                 st_br_req;
++      int                 st_rd_sect;
++      int                 st_wr_sect;
++
++      wait_queue_head_t waiting_to_free;
++
++      grant_handle_t shmem_handle;
++      grant_ref_t    shmem_ref;
++} blkif_t;
++
++blkif_t *blkif_alloc(domid_t domid);
++void blkif_disconnect(blkif_t *blkif);
++void blkif_free(blkif_t *blkif);
++int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn);
++
++#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
++#define blkif_put(_b)                                 \
++      do {                                            \
++              if (atomic_dec_and_test(&(_b)->refcnt)) \
++                      wake_up(&(_b)->waiting_to_free);\
++      } while (0)
++
++/* Create a vbd. */
++int vbd_create(blkif_t *blkif, blkif_vdev_t vdevice, unsigned major,
++             unsigned minor, int readonly, int cdrom);
++void vbd_free(struct vbd *vbd);
++
++unsigned long long vbd_size(struct vbd *vbd);
++unsigned int vbd_info(struct vbd *vbd);
++unsigned long vbd_secsize(struct vbd *vbd);
++
++struct phys_req {
++      unsigned short       dev;
++      unsigned short       nr_sects;
++      struct block_device *bdev;
++      blkif_sector_t       sector_number;
++};
++
++int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation);
++
++void blkif_interface_init(void);
++
++void blkif_xenbus_init(void);
++
++irqreturn_t blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
++int blkif_schedule(void *arg);
++
++int blkback_barrier(struct xenbus_transaction xbt,
++                  struct backend_info *be, int state);
++
++#endif /* __BLKIF__BACKEND__COMMON_H__ */
+--- linux-2.6.18.8/drivers/xen/blkback/interface.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blkback/interface.c        2008-05-19 00:33:45.682779328 +0300
+@@ -0,0 +1,181 @@
++/******************************************************************************
++ * arch/xen/drivers/blkif/backend/interface.c
++ * 
++ * Block-device interface management.
++ * 
++ * Copyright (c) 2004, Keir Fraser
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include "common.h"
++#include <xen/evtchn.h>
++#include <linux/kthread.h>
++
++static kmem_cache_t *blkif_cachep;
++
++blkif_t *blkif_alloc(domid_t domid)
++{
++      blkif_t *blkif;
++
++      blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
++      if (!blkif)
++              return ERR_PTR(-ENOMEM);
++
++      memset(blkif, 0, sizeof(*blkif));
++      blkif->domid = domid;
++      spin_lock_init(&blkif->blk_ring_lock);
++      atomic_set(&blkif->refcnt, 1);
++      init_waitqueue_head(&blkif->wq);
++      blkif->st_print = jiffies;
++      init_waitqueue_head(&blkif->waiting_to_free);
++
++      return blkif;
++}
++
++static int map_frontend_page(blkif_t *blkif, unsigned long shared_page)
++{
++      struct gnttab_map_grant_ref op;
++
++      gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
++                        GNTMAP_host_map, shared_page, blkif->domid);
++
++      if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
++              BUG();
++
++      if (op.status) {
++              DPRINTK(" Grant table operation failure !\n");
++              return op.status;
++      }
++
++      blkif->shmem_ref = shared_page;
++      blkif->shmem_handle = op.handle;
++
++      return 0;
++}
++
++static void unmap_frontend_page(blkif_t *blkif)
++{
++      struct gnttab_unmap_grant_ref op;
++
++      gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
++                          GNTMAP_host_map, blkif->shmem_handle);
++
++      if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
++              BUG();
++}
++
++int blkif_map(blkif_t *blkif, unsigned long shared_page, unsigned int evtchn)
++{
++      int err;
++
++      /* Already connected through? */
++      if (blkif->irq)
++              return 0;
++
++      if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
++              return -ENOMEM;
++
++      err = map_frontend_page(blkif, shared_page);
++      if (err) {
++              free_vm_area(blkif->blk_ring_area);
++              return err;
++      }
++
++      switch (blkif->blk_protocol) {
++      case BLKIF_PROTOCOL_NATIVE:
++      {
++              blkif_sring_t *sring;
++              sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
++              BACK_RING_INIT(&blkif->blk_rings.native, sring, PAGE_SIZE);
++              break;
++      }
++      case BLKIF_PROTOCOL_X86_32:
++      {
++              blkif_x86_32_sring_t *sring_x86_32;
++              sring_x86_32 = (blkif_x86_32_sring_t *)blkif->blk_ring_area->addr;
++              BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32, PAGE_SIZE);
++              break;
++      }
++      case BLKIF_PROTOCOL_X86_64:
++      {
++              blkif_x86_64_sring_t *sring_x86_64;
++              sring_x86_64 = (blkif_x86_64_sring_t *)blkif->blk_ring_area->addr;
++              BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64, PAGE_SIZE);
++              break;
++      }
++      default:
++              BUG();
++      }
++
++      err = bind_interdomain_evtchn_to_irqhandler(
++              blkif->domid, evtchn, blkif_be_int, 0, "blkif-backend", blkif);
++      if (err < 0)
++      {
++              unmap_frontend_page(blkif);
++              free_vm_area(blkif->blk_ring_area);
++              blkif->blk_rings.common.sring = NULL;
++              return err;
++      }
++      blkif->irq = err;
++
++      return 0;
++}
++
++void blkif_disconnect(blkif_t *blkif)
++{
++      if (blkif->xenblkd) {
++              kthread_stop(blkif->xenblkd);
++              blkif->xenblkd = NULL;
++      }
++
++      atomic_dec(&blkif->refcnt);
++      wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
++      atomic_inc(&blkif->refcnt);
++
++      if (blkif->irq) {
++              unbind_from_irqhandler(blkif->irq, blkif);
++              blkif->irq = 0;
++      }
++
++      if (blkif->blk_rings.common.sring) {
++              unmap_frontend_page(blkif);
++              free_vm_area(blkif->blk_ring_area);
++              blkif->blk_rings.common.sring = NULL;
++      }
++}
++
++void blkif_free(blkif_t *blkif)
++{
++      if (!atomic_dec_and_test(&blkif->refcnt))
++              BUG();
++      kmem_cache_free(blkif_cachep, blkif);
++}
++
++void __init blkif_interface_init(void)
++{
++      blkif_cachep = kmem_cache_create("blkif_cache", sizeof(blkif_t), 
++                                       0, 0, NULL, NULL);
++}
+--- linux-2.6.18.8/drivers/xen/blkback/vbd.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blkback/vbd.c      2008-05-19 00:33:45.682779328 +0300
+@@ -0,0 +1,118 @@
++/******************************************************************************
++ * blkback/vbd.c
++ * 
++ * Routines for managing virtual block devices (VBDs).
++ * 
++ * Copyright (c) 2003-2005, Keir Fraser & Steve Hand
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include "common.h"
++
++#define vbd_sz(_v)   ((_v)->bdev->bd_part ?                           \
++      (_v)->bdev->bd_part->nr_sects : (_v)->bdev->bd_disk->capacity)
++
++unsigned long long vbd_size(struct vbd *vbd)
++{
++      return vbd_sz(vbd);
++}
++
++unsigned int vbd_info(struct vbd *vbd)
++{
++      return vbd->type | (vbd->readonly?VDISK_READONLY:0);
++}
++
++unsigned long vbd_secsize(struct vbd *vbd)
++{
++      return bdev_hardsect_size(vbd->bdev);
++}
++
++int vbd_create(blkif_t *blkif, blkif_vdev_t handle, unsigned major,
++             unsigned minor, int readonly, int cdrom)
++{
++      struct vbd *vbd;
++      struct block_device *bdev;
++
++      vbd = &blkif->vbd;
++      vbd->handle   = handle; 
++      vbd->readonly = readonly;
++      vbd->type     = 0;
++
++      vbd->pdevice  = MKDEV(major, minor);
++
++      bdev = open_by_devnum(vbd->pdevice,
++                            vbd->readonly ? FMODE_READ : FMODE_WRITE);
++
++      if (IS_ERR(bdev)) {
++              DPRINTK("vbd_creat: device %08x could not be opened.\n",
++                      vbd->pdevice);
++              return -ENOENT;
++      }
++
++      vbd->bdev = bdev;
++
++      if (vbd->bdev->bd_disk == NULL) {
++              DPRINTK("vbd_creat: device %08x doesn't exist.\n",
++                      vbd->pdevice);
++              vbd_free(vbd);
++              return -ENOENT;
++      }
++
++      if (vbd->bdev->bd_disk->flags & GENHD_FL_CD || cdrom)
++              vbd->type |= VDISK_CDROM;
++      if (vbd->bdev->bd_disk->flags & GENHD_FL_REMOVABLE)
++              vbd->type |= VDISK_REMOVABLE;
++
++      DPRINTK("Successful creation of handle=%04x (dom=%u)\n",
++              handle, blkif->domid);
++      return 0;
++}
++
++void vbd_free(struct vbd *vbd)
++{
++      if (vbd->bdev)
++              blkdev_put(vbd->bdev);
++      vbd->bdev = NULL;
++}
++
++int vbd_translate(struct phys_req *req, blkif_t *blkif, int operation)
++{
++      struct vbd *vbd = &blkif->vbd;
++      int rc = -EACCES;
++
++      if ((operation != READ) && vbd->readonly)
++              goto out;
++
++      if (unlikely((req->sector_number + req->nr_sects) > vbd_sz(vbd)))
++              goto out;
++
++      req->dev  = vbd->pdevice;
++      req->bdev = vbd->bdev;
++      rc = 0;
++
++ out:
++      return rc;
++}
+--- linux-2.6.18.8/drivers/xen/blkback/xenbus.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blkback/xenbus.c   2008-05-19 00:33:45.682779328 +0300
+@@ -0,0 +1,541 @@
++/*  Xenbus code for blkif backend
++    Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
++    Copyright (C) 2005 XenSource Ltd
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 2 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program; if not, write to the Free Software
++    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include <stdarg.h>
++#include <linux/module.h>
++#include <linux/kthread.h>
++#include "common.h"
++
++#undef DPRINTK
++#define DPRINTK(fmt, args...)                         \
++      pr_debug("blkback/xenbus (%s:%d) " fmt ".\n",   \
++               __FUNCTION__, __LINE__, ##args)
++
++struct backend_info
++{
++      struct xenbus_device *dev;
++      blkif_t *blkif;
++      struct xenbus_watch backend_watch;
++      unsigned major;
++      unsigned minor;
++      char *mode;
++};
++
++static void connect(struct backend_info *);
++static int connect_ring(struct backend_info *);
++static void backend_changed(struct xenbus_watch *, const char **,
++                          unsigned int);
++
++static int blkback_name(blkif_t *blkif, char *buf)
++{
++      char *devpath, *devname;
++      struct xenbus_device *dev = blkif->be->dev;
++
++      devpath = xenbus_read(XBT_NIL, dev->nodename, "dev", NULL);
++      if (IS_ERR(devpath)) 
++              return PTR_ERR(devpath);
++      
++      if ((devname = strstr(devpath, "/dev/")) != NULL)
++              devname += strlen("/dev/");
++      else
++              devname  = devpath;
++
++      snprintf(buf, TASK_COMM_LEN, "blkback.%d.%s", blkif->domid, devname);
++      kfree(devpath);
++      
++      return 0;
++}
++
++static void update_blkif_status(blkif_t *blkif)
++{ 
++      int err;
++      char name[TASK_COMM_LEN];
++
++      /* Not ready to connect? */
++      if (!blkif->irq || !blkif->vbd.bdev)
++              return;
++
++      /* Already connected? */
++      if (blkif->be->dev->state == XenbusStateConnected)
++              return;
++
++      /* Attempt to connect: exit if we fail to. */
++      connect(blkif->be);
++      if (blkif->be->dev->state != XenbusStateConnected)
++              return;
++
++      err = blkback_name(blkif, name);
++      if (err) {
++              xenbus_dev_error(blkif->be->dev, err, "get blkback dev name");
++              return;
++      }
++
++      blkif->xenblkd = kthread_run(blkif_schedule, blkif, name);
++      if (IS_ERR(blkif->xenblkd)) {
++              err = PTR_ERR(blkif->xenblkd);
++              blkif->xenblkd = NULL;
++              xenbus_dev_error(blkif->be->dev, err, "start xenblkd");
++      }
++}
++
++
++/****************************************************************
++ *  sysfs interface for VBD I/O requests
++ */
++
++#define VBD_SHOW(name, format, args...)                                       \
++      static ssize_t show_##name(struct device *_dev,                 \
++                                 struct device_attribute *attr,       \
++                                 char *buf)                           \
++      {                                                               \
++              struct xenbus_device *dev = to_xenbus_device(_dev);     \
++              struct backend_info *be = dev->dev.driver_data;         \
++                                                                      \
++              return sprintf(buf, format, ##args);                    \
++      }                                                               \
++      static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
++
++VBD_SHOW(oo_req,  "%d\n", be->blkif->st_oo_req);
++VBD_SHOW(rd_req,  "%d\n", be->blkif->st_rd_req);
++VBD_SHOW(wr_req,  "%d\n", be->blkif->st_wr_req);
++VBD_SHOW(br_req,  "%d\n", be->blkif->st_br_req);
++VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect);
++VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect);
++
++static struct attribute *vbdstat_attrs[] = {
++      &dev_attr_oo_req.attr,
++      &dev_attr_rd_req.attr,
++      &dev_attr_wr_req.attr,
++      &dev_attr_br_req.attr,
++      &dev_attr_rd_sect.attr,
++      &dev_attr_wr_sect.attr,
++      NULL
++};
++
++static struct attribute_group vbdstat_group = {
++      .name = "statistics",
++      .attrs = vbdstat_attrs,
++};
++
++VBD_SHOW(physical_device, "%x:%x\n", be->major, be->minor);
++VBD_SHOW(mode, "%s\n", be->mode);
++
++int xenvbd_sysfs_addif(struct xenbus_device *dev)
++{
++      int error;
++      
++      error = device_create_file(&dev->dev, &dev_attr_physical_device);
++      if (error)
++              goto fail1;
++
++      error = device_create_file(&dev->dev, &dev_attr_mode);
++      if (error)
++              goto fail2;
++
++      error = sysfs_create_group(&dev->dev.kobj, &vbdstat_group);
++      if (error)
++              goto fail3;
++
++      return 0;
++
++fail3:        sysfs_remove_group(&dev->dev.kobj, &vbdstat_group);
++fail2:        device_remove_file(&dev->dev, &dev_attr_mode);
++fail1:        device_remove_file(&dev->dev, &dev_attr_physical_device);
++      return error;
++}
++
++void xenvbd_sysfs_delif(struct xenbus_device *dev)
++{
++      sysfs_remove_group(&dev->dev.kobj, &vbdstat_group);
++      device_remove_file(&dev->dev, &dev_attr_mode);
++      device_remove_file(&dev->dev, &dev_attr_physical_device);
++}
++
++static int blkback_remove(struct xenbus_device *dev)
++{
++      struct backend_info *be = dev->dev.driver_data;
++
++      DPRINTK("");
++
++      if (be->major || be->minor)
++              xenvbd_sysfs_delif(dev);
++
++      if (be->backend_watch.node) {
++              unregister_xenbus_watch(&be->backend_watch);
++              kfree(be->backend_watch.node);
++              be->backend_watch.node = NULL;
++      }
++
++      if (be->blkif) {
++              blkif_disconnect(be->blkif);
++              vbd_free(&be->blkif->vbd);
++              blkif_free(be->blkif);
++              be->blkif = NULL;
++      }
++
++      kfree(be);
++      dev->dev.driver_data = NULL;
++      return 0;
++}
++
++int blkback_barrier(struct xenbus_transaction xbt,
++                  struct backend_info *be, int state)
++{
++      struct xenbus_device *dev = be->dev;
++      int err;
++
++      err = xenbus_printf(xbt, dev->nodename, "feature-barrier",
++                          "%d", state);
++      if (err)
++              xenbus_dev_fatal(dev, err, "writing feature-barrier");
++
++      return err;
++}
++
++/**
++ * Entry point to this code when a new device is created.  Allocate the basic
++ * structures, and watch the store waiting for the hotplug scripts to tell us
++ * the device's physical major and minor numbers.  Switch to InitWait.
++ */
++static int blkback_probe(struct xenbus_device *dev,
++                       const struct xenbus_device_id *id)
++{
++      int err;
++      struct backend_info *be = kzalloc(sizeof(struct backend_info),
++                                        GFP_KERNEL);
++      if (!be) {
++              xenbus_dev_fatal(dev, -ENOMEM,
++                               "allocating backend structure");
++              return -ENOMEM;
++      }
++      be->dev = dev;
++      dev->dev.driver_data = be;
++
++      be->blkif = blkif_alloc(dev->otherend_id);
++      if (IS_ERR(be->blkif)) {
++              err = PTR_ERR(be->blkif);
++              be->blkif = NULL;
++              xenbus_dev_fatal(dev, err, "creating block interface");
++              goto fail;
++      }
++
++      /* setup back pointer */
++      be->blkif->be = be;
++
++      err = xenbus_watch_path2(dev, dev->nodename, "physical-device",
++                               &be->backend_watch, backend_changed);
++      if (err)
++              goto fail;
++
++      err = xenbus_switch_state(dev, XenbusStateInitWait);
++      if (err)
++              goto fail;
++
++      return 0;
++
++fail:
++      DPRINTK("failed");
++      blkback_remove(dev);
++      return err;
++}
++
++
++/**
++ * Callback received when the hotplug scripts have placed the physical-device
++ * node.  Read it and the mode node, and create a vbd.  If the frontend is
++ * ready, connect.
++ */
++static void backend_changed(struct xenbus_watch *watch,
++                          const char **vec, unsigned int len)
++{
++      int err;
++      unsigned major;
++      unsigned minor;
++      struct backend_info *be
++              = container_of(watch, struct backend_info, backend_watch);
++      struct xenbus_device *dev = be->dev;
++      int cdrom = 0;
++      char *device_type;
++
++      DPRINTK("");
++
++      err = xenbus_scanf(XBT_NIL, dev->nodename, "physical-device", "%x:%x",
++                         &major, &minor);
++      if (XENBUS_EXIST_ERR(err)) {
++              /* Since this watch will fire once immediately after it is
++                 registered, we expect this.  Ignore it, and wait for the
++                 hotplug scripts. */
++              return;
++      }
++      if (err != 2) {
++              xenbus_dev_fatal(dev, err, "reading physical-device");
++              return;
++      }
++
++      if ((be->major || be->minor) &&
++          ((be->major != major) || (be->minor != minor))) {
++              printk(KERN_WARNING
++                     "blkback: changing physical device (from %x:%x to "
++                     "%x:%x) not supported.\n", be->major, be->minor,
++                     major, minor);
++              return;
++      }
++
++      be->mode = xenbus_read(XBT_NIL, dev->nodename, "mode", NULL);
++      if (IS_ERR(be->mode)) {
++              err = PTR_ERR(be->mode);
++              be->mode = NULL;
++              xenbus_dev_fatal(dev, err, "reading mode");
++              return;
++      }
++
++      device_type = xenbus_read(XBT_NIL, dev->otherend, "device-type", NULL);
++      if (!IS_ERR(device_type)) {
++              cdrom = strcmp(device_type, "cdrom") == 0;
++              kfree(device_type);
++      }
++
++      if (be->major == 0 && be->minor == 0) {
++              /* Front end dir is a number, which is used as the handle. */
++
++              char *p = strrchr(dev->otherend, '/') + 1;
++              long handle = simple_strtoul(p, NULL, 0);
++
++              be->major = major;
++              be->minor = minor;
++
++              err = vbd_create(be->blkif, handle, major, minor,
++                               (NULL == strchr(be->mode, 'w')), cdrom);
++              if (err) {
++                      be->major = be->minor = 0;
++                      xenbus_dev_fatal(dev, err, "creating vbd structure");
++                      return;
++              }
++
++              err = xenvbd_sysfs_addif(dev);
++              if (err) {
++                      vbd_free(&be->blkif->vbd);
++                      be->major = be->minor = 0;
++                      xenbus_dev_fatal(dev, err, "creating sysfs entries");
++                      return;
++              }
++
++              /* We're potentially connected now */
++              update_blkif_status(be->blkif);
++      }
++}
++
++
++/**
++ * Callback received when the frontend's state changes.
++ */
++static void frontend_changed(struct xenbus_device *dev,
++                           enum xenbus_state frontend_state)
++{
++      struct backend_info *be = dev->dev.driver_data;
++      int err;
++
++      DPRINTK("%s", xenbus_strstate(frontend_state));
++
++      switch (frontend_state) {
++      case XenbusStateInitialising:
++              if (dev->state == XenbusStateClosed) {
++                      printk(KERN_INFO "%s: %s: prepare for reconnect\n",
++                             __FUNCTION__, dev->nodename);
++                      xenbus_switch_state(dev, XenbusStateInitWait);
++              }
++              break;
++
++      case XenbusStateInitialised:
++      case XenbusStateConnected:
++              /* Ensure we connect even when two watches fire in 
++                 close successsion and we miss the intermediate value 
++                 of frontend_state. */
++              if (dev->state == XenbusStateConnected)
++                      break;
++
++              err = connect_ring(be);
++              if (err)
++                      break;
++              update_blkif_status(be->blkif);
++              break;
++
++      case XenbusStateClosing:
++              blkif_disconnect(be->blkif);
++              xenbus_switch_state(dev, XenbusStateClosing);
++              break;
++
++      case XenbusStateClosed:
++              xenbus_switch_state(dev, XenbusStateClosed);
++              if (xenbus_dev_is_online(dev))
++                      break;
++              /* fall through if not online */
++      case XenbusStateUnknown:
++              device_unregister(&dev->dev);
++              break;
++
++      default:
++              xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
++                               frontend_state);
++              break;
++      }
++}
++
++
++/* ** Connection ** */
++
++
++/**
++ * Write the physical details regarding the block device to the store, and
++ * switch to Connected state.
++ */
++static void connect(struct backend_info *be)
++{
++      struct xenbus_transaction xbt;
++      int err;
++      struct xenbus_device *dev = be->dev;
++
++      DPRINTK("%s", dev->otherend);
++
++      /* Supply the information about the device the frontend needs */
++again:
++      err = xenbus_transaction_start(&xbt);
++      if (err) {
++              xenbus_dev_fatal(dev, err, "starting transaction");
++              return;
++      }
++
++      err = blkback_barrier(xbt, be, 1);
++      if (err)
++              goto abort;
++
++      err = xenbus_printf(xbt, dev->nodename, "sectors", "%llu",
++                          vbd_size(&be->blkif->vbd));
++      if (err) {
++              xenbus_dev_fatal(dev, err, "writing %s/sectors",
++                               dev->nodename);
++              goto abort;
++      }
++
++      /* FIXME: use a typename instead */
++      err = xenbus_printf(xbt, dev->nodename, "info", "%u",
++                          vbd_info(&be->blkif->vbd));
++      if (err) {
++              xenbus_dev_fatal(dev, err, "writing %s/info",
++                               dev->nodename);
++              goto abort;
++      }
++      err = xenbus_printf(xbt, dev->nodename, "sector-size", "%lu",
++                          vbd_secsize(&be->blkif->vbd));
++      if (err) {
++              xenbus_dev_fatal(dev, err, "writing %s/sector-size",
++                               dev->nodename);
++              goto abort;
++      }
++
++      err = xenbus_transaction_end(xbt, 0);
++      if (err == -EAGAIN)
++              goto again;
++      if (err)
++              xenbus_dev_fatal(dev, err, "ending transaction");
++
++      err = xenbus_switch_state(dev, XenbusStateConnected);
++      if (err)
++              xenbus_dev_fatal(dev, err, "switching to Connected state",
++                               dev->nodename);
++
++      return;
++ abort:
++      xenbus_transaction_end(xbt, 1);
++}
++
++
++static int connect_ring(struct backend_info *be)
++{
++      struct xenbus_device *dev = be->dev;
++      unsigned long ring_ref;
++      unsigned int evtchn;
++      char protocol[64] = "";
++      int err;
++
++      DPRINTK("%s", dev->otherend);
++
++      err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", &ring_ref,
++                          "event-channel", "%u", &evtchn, NULL);
++      if (err) {
++              xenbus_dev_fatal(dev, err,
++                               "reading %s/ring-ref and event-channel",
++                               dev->otherend);
++              return err;
++      }
++
++      be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
++      err = xenbus_gather(XBT_NIL, dev->otherend, "protocol",
++                          "%63s", protocol, NULL);
++      if (err)
++              strcpy(protocol, "unspecified, assuming native");
++      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE))
++              be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
++      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
++              be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32;
++      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64))
++              be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64;
++      else {
++              xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol);
++              return -1;
++      }
++      printk(KERN_INFO
++             "blkback: ring-ref %ld, event-channel %d, protocol %d (%s)\n",
++             ring_ref, evtchn, be->blkif->blk_protocol, protocol);
++
++      /* Map the shared frame, irq etc. */
++      err = blkif_map(be->blkif, ring_ref, evtchn);
++      if (err) {
++              xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
++                               ring_ref, evtchn);
++              return err;
++      }
++
++      return 0;
++}
++
++
++/* ** Driver Registration ** */
++
++
++static const struct xenbus_device_id blkback_ids[] = {
++      { "vbd" },
++      { "" }
++};
++
++
++static struct xenbus_driver blkback = {
++      .name = "vbd",
++      .owner = THIS_MODULE,
++      .ids = blkback_ids,
++      .probe = blkback_probe,
++      .remove = blkback_remove,
++      .otherend_changed = frontend_changed
++};
++
++
++void blkif_xenbus_init(void)
++{
++      xenbus_register_backend(&blkback);
++}
+--- linux-2.6.18.8/drivers/xen/blkfront/Makefile       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blkfront/Makefile  2008-05-19 00:33:45.686779559 +0300
+@@ -0,0 +1,5 @@
++
++obj-$(CONFIG_XEN_BLKDEV_FRONTEND)     := xenblk.o
++
++xenblk-objs := blkfront.o vbd.o
++
+--- linux-2.6.18.8/drivers/xen/blkfront/blkfront.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blkfront/blkfront.c        2008-05-19 00:33:45.686779559 +0300
+@@ -0,0 +1,922 @@
++/******************************************************************************
++ * blkfront.c
++ * 
++ * XenLinux virtual block-device driver.
++ * 
++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
++ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
++ * Copyright (c) 2004, Christian Limpach
++ * Copyright (c) 2004, Andrew Warfield
++ * Copyright (c) 2005, Christopher Clark
++ * Copyright (c) 2005, XenSource Ltd
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/version.h>
++#include "block.h"
++#include <linux/cdrom.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <scsi/scsi.h>
++#include <xen/evtchn.h>
++#include <xen/xenbus.h>
++#include <xen/interface/grant_table.h>
++#include <xen/interface/io/protocols.h>
++#include <xen/gnttab.h>
++#include <asm/hypervisor.h>
++#include <asm/maddr.h>
++
++#ifdef HAVE_XEN_PLATFORM_COMPAT_H
++#include <xen/platform-compat.h>
++#endif
++
++#define BLKIF_STATE_DISCONNECTED 0
++#define BLKIF_STATE_CONNECTED    1
++#define BLKIF_STATE_SUSPENDED    2
++
++#define MAXIMUM_OUTSTANDING_BLOCK_REQS \
++    (BLKIF_MAX_SEGMENTS_PER_REQUEST * BLK_RING_SIZE)
++#define GRANT_INVALID_REF     0
++
++static void connect(struct blkfront_info *);
++static void blkfront_closing(struct xenbus_device *);
++static int blkfront_remove(struct xenbus_device *);
++static int talk_to_backend(struct xenbus_device *, struct blkfront_info *);
++static int setup_blkring(struct xenbus_device *, struct blkfront_info *);
++
++static void kick_pending_request_queues(struct blkfront_info *);
++
++static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs);
++static void blkif_restart_queue(void *arg);
++static void blkif_recover(struct blkfront_info *);
++static void blkif_completion(struct blk_shadow *);
++static void blkif_free(struct blkfront_info *, int);
++
++
++/**
++ * Entry point to this code when a new device is created.  Allocate the basic
++ * structures and the ring buffer for communication with the backend, and
++ * inform the backend of the appropriate details for those.  Switch to
++ * Initialised state.
++ */
++static int blkfront_probe(struct xenbus_device *dev,
++                        const struct xenbus_device_id *id)
++{
++      int err, vdevice, i;
++      struct blkfront_info *info;
++
++      /* FIXME: Use dynamic device id if this is not set. */
++      err = xenbus_scanf(XBT_NIL, dev->nodename,
++                         "virtual-device", "%i", &vdevice);
++      if (err != 1) {
++              xenbus_dev_fatal(dev, err, "reading virtual-device");
++              return err;
++      }
++
++      info = kzalloc(sizeof(*info), GFP_KERNEL);
++      if (!info) {
++              xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
++              return -ENOMEM;
++      }
++
++      info->xbdev = dev;
++      info->vdevice = vdevice;
++      info->connected = BLKIF_STATE_DISCONNECTED;
++      INIT_WORK(&info->work, blkif_restart_queue, (void *)info);
++
++      for (i = 0; i < BLK_RING_SIZE; i++)
++              info->shadow[i].req.id = i+1;
++      info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
++
++      /* Front end dir is a number, which is used as the id. */
++      info->handle = simple_strtoul(strrchr(dev->nodename,'/')+1, NULL, 0);
++      dev->dev.driver_data = info;
++
++      err = talk_to_backend(dev, info);
++      if (err) {
++              kfree(info);
++              dev->dev.driver_data = NULL;
++              return err;
++      }
++
++      return 0;
++}
++
++
++/**
++ * We are reconnecting to the backend, due to a suspend/resume, or a backend
++ * driver restart.  We tear down our blkif structure and recreate it, but
++ * leave the device-layer structures intact so that this is transparent to the
++ * rest of the kernel.
++ */
++static int blkfront_resume(struct xenbus_device *dev)
++{
++      struct blkfront_info *info = dev->dev.driver_data;
++      int err;
++
++      DPRINTK("blkfront_resume: %s\n", dev->nodename);
++
++      blkif_free(info, info->connected == BLKIF_STATE_CONNECTED);
++
++      err = talk_to_backend(dev, info);
++      if (info->connected == BLKIF_STATE_SUSPENDED && !err)
++              blkif_recover(info);
++
++      return err;
++}
++
++
++/* Common code used when first setting up, and when resuming. */
++static int talk_to_backend(struct xenbus_device *dev,
++                         struct blkfront_info *info)
++{
++      const char *message = NULL;
++      struct xenbus_transaction xbt;
++      int err;
++
++      /* Create shared ring, alloc event channel. */
++      err = setup_blkring(dev, info);
++      if (err)
++              goto out;
++
++again:
++      err = xenbus_transaction_start(&xbt);
++      if (err) {
++              xenbus_dev_fatal(dev, err, "starting transaction");
++              goto destroy_blkring;
++      }
++
++      err = xenbus_printf(xbt, dev->nodename,
++                          "ring-ref","%u", info->ring_ref);
++      if (err) {
++              message = "writing ring-ref";
++              goto abort_transaction;
++      }
++      err = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
++                          irq_to_evtchn_port(info->irq));
++      if (err) {
++              message = "writing event-channel";
++              goto abort_transaction;
++      }
++      err = xenbus_printf(xbt, dev->nodename, "protocol", "%s",
++                          XEN_IO_PROTO_ABI_NATIVE);
++      if (err) {
++              message = "writing protocol";
++              goto abort_transaction;
++      }
++
++      err = xenbus_transaction_end(xbt, 0);
++      if (err) {
++              if (err == -EAGAIN)
++                      goto again;
++              xenbus_dev_fatal(dev, err, "completing transaction");
++              goto destroy_blkring;
++      }
++
++      xenbus_switch_state(dev, XenbusStateInitialised);
++
++      return 0;
++
++ abort_transaction:
++      xenbus_transaction_end(xbt, 1);
++      if (message)
++              xenbus_dev_fatal(dev, err, "%s", message);
++ destroy_blkring:
++      blkif_free(info, 0);
++ out:
++      return err;
++}
++
++
++static int setup_blkring(struct xenbus_device *dev,
++                       struct blkfront_info *info)
++{
++      blkif_sring_t *sring;
++      int err;
++
++      info->ring_ref = GRANT_INVALID_REF;
++
++      sring = (blkif_sring_t *)__get_free_page(GFP_KERNEL|__GFP_HIGH);
++      if (!sring) {
++              xenbus_dev_fatal(dev, -ENOMEM, "allocating shared ring");
++              return -ENOMEM;
++      }
++      SHARED_RING_INIT(sring);
++      FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
++
++      err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
++      if (err < 0) {
++              free_page((unsigned long)sring);
++              info->ring.sring = NULL;
++              goto fail;
++      }
++      info->ring_ref = err;
++
++      err = bind_listening_port_to_irqhandler(
++              dev->otherend_id, blkif_int, SA_SAMPLE_RANDOM, "blkif", info);
++      if (err <= 0) {
++              xenbus_dev_fatal(dev, err,
++                               "bind_listening_port_to_irqhandler");
++              goto fail;
++      }
++      info->irq = err;
++
++      return 0;
++fail:
++      blkif_free(info, 0);
++      return err;
++}
++
++
++/**
++ * Callback received when the backend's state changes.
++ */
++static void backend_changed(struct xenbus_device *dev,
++                          enum xenbus_state backend_state)
++{
++      struct blkfront_info *info = dev->dev.driver_data;
++      struct block_device *bd;
++
++      DPRINTK("blkfront:backend_changed.\n");
++
++      switch (backend_state) {
++      case XenbusStateInitialising:
++      case XenbusStateInitWait:
++      case XenbusStateInitialised:
++      case XenbusStateReconfiguring:
++      case XenbusStateReconfigured:
++      case XenbusStateUnknown:
++      case XenbusStateClosed:
++              break;
++
++      case XenbusStateConnected:
++              connect(info);
++              break;
++
++      case XenbusStateClosing:
++              bd = bdget(info->dev);
++              if (bd == NULL)
++                      xenbus_dev_fatal(dev, -ENODEV, "bdget failed");
++
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
++              down(&bd->bd_sem);
++#else
++              mutex_lock(&bd->bd_mutex);
++#endif
++              if (info->users > 0)
++                      xenbus_dev_error(dev, -EBUSY,
++                                       "Device in use; refusing to close");
++              else
++                      blkfront_closing(dev);
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,17)
++              up(&bd->bd_sem);
++#else
++              mutex_unlock(&bd->bd_mutex);
++#endif
++              bdput(bd);
++              break;
++      }
++}
++
++
++/* ** Connection ** */
++
++
++/*
++ * Invoked when the backend is finally 'ready' (and has told produced
++ * the details about the physical device - #sectors, size, etc).
++ */
++static void connect(struct blkfront_info *info)
++{
++      unsigned long long sectors;
++      unsigned long sector_size;
++      unsigned int binfo;
++      int err;
++
++      if ((info->connected == BLKIF_STATE_CONNECTED) ||
++          (info->connected == BLKIF_STATE_SUSPENDED) )
++              return;
++
++      DPRINTK("blkfront.c:connect:%s.\n", info->xbdev->otherend);
++
++      err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
++                          "sectors", "%Lu", &sectors,
++                          "info", "%u", &binfo,
++                          "sector-size", "%lu", &sector_size,
++                          NULL);
++      if (err) {
++              xenbus_dev_fatal(info->xbdev, err,
++                               "reading backend fields at %s",
++                               info->xbdev->otherend);
++              return;
++      }
++
++      err = xenbus_gather(XBT_NIL, info->xbdev->otherend,
++                          "feature-barrier", "%lu", &info->feature_barrier,
++                          NULL);
++      if (err)
++              info->feature_barrier = 0;
++
++      err = xlvbd_add(sectors, info->vdevice, binfo, sector_size, info);
++      if (err) {
++              xenbus_dev_fatal(info->xbdev, err, "xlvbd_add at %s",
++                               info->xbdev->otherend);
++              return;
++      }
++
++      (void)xenbus_switch_state(info->xbdev, XenbusStateConnected);
++
++      /* Kick pending requests. */
++      spin_lock_irq(&blkif_io_lock);
++      info->connected = BLKIF_STATE_CONNECTED;
++      kick_pending_request_queues(info);
++      spin_unlock_irq(&blkif_io_lock);
++
++      add_disk(info->gd);
++
++      info->is_ready = 1;
++}
++
++/**
++ * Handle the change of state of the backend to Closing.  We must delete our
++ * device-layer structures now, to ensure that writes are flushed through to
++ * the backend.  Once is this done, we can switch to Closed in
++ * acknowledgement.
++ */
++static void blkfront_closing(struct xenbus_device *dev)
++{
++      struct blkfront_info *info = dev->dev.driver_data;
++      unsigned long flags;
++
++      DPRINTK("blkfront_closing: %s removed\n", dev->nodename);
++
++      if (info->rq == NULL)
++              goto out;
++
++      spin_lock_irqsave(&blkif_io_lock, flags);
++      /* No more blkif_request(). */
++      blk_stop_queue(info->rq);
++      /* No more gnttab callback work. */
++      gnttab_cancel_free_callback(&info->callback);
++      spin_unlock_irqrestore(&blkif_io_lock, flags);
++
++      /* Flush gnttab callback work. Must be done with no locks held. */
++      flush_scheduled_work();
++
++      xlvbd_del(info);
++
++ out:
++      xenbus_frontend_closed(dev);
++}
++
++
++static int blkfront_remove(struct xenbus_device *dev)
++{
++      struct blkfront_info *info = dev->dev.driver_data;
++
++      DPRINTK("blkfront_remove: %s removed\n", dev->nodename);
++
++      blkif_free(info, 0);
++
++      kfree(info);
++
++      return 0;
++}
++
++
++static inline int GET_ID_FROM_FREELIST(
++      struct blkfront_info *info)
++{
++      unsigned long free = info->shadow_free;
++      BUG_ON(free > BLK_RING_SIZE);
++      info->shadow_free = info->shadow[free].req.id;
++      info->shadow[free].req.id = 0x0fffffee; /* debug */
++      return free;
++}
++
++static inline void ADD_ID_TO_FREELIST(
++      struct blkfront_info *info, unsigned long id)
++{
++      info->shadow[id].req.id  = info->shadow_free;
++      info->shadow[id].request = 0;
++      info->shadow_free = id;
++}
++
++static inline void flush_requests(struct blkfront_info *info)
++{
++      int notify;
++
++      RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&info->ring, notify);
++
++      if (notify)
++              notify_remote_via_irq(info->irq);
++}
++
++static void kick_pending_request_queues(struct blkfront_info *info)
++{
++      if (!RING_FULL(&info->ring)) {
++              /* Re-enable calldowns. */
++              blk_start_queue(info->rq);
++              /* Kick things off immediately. */
++              do_blkif_request(info->rq);
++      }
++}
++
++static void blkif_restart_queue(void *arg)
++{
++      struct blkfront_info *info = (struct blkfront_info *)arg;
++      spin_lock_irq(&blkif_io_lock);
++      if (info->connected == BLKIF_STATE_CONNECTED)
++              kick_pending_request_queues(info);
++      spin_unlock_irq(&blkif_io_lock);
++}
++
++static void blkif_restart_queue_callback(void *arg)
++{
++      struct blkfront_info *info = (struct blkfront_info *)arg;
++      schedule_work(&info->work);
++}
++
++int blkif_open(struct inode *inode, struct file *filep)
++{
++      struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
++      info->users++;
++      return 0;
++}
++
++
++int blkif_release(struct inode *inode, struct file *filep)
++{
++      struct blkfront_info *info = inode->i_bdev->bd_disk->private_data;
++      info->users--;
++      if (info->users == 0) {
++              /* Check whether we have been instructed to close.  We will
++                 have ignored this request initially, as the device was
++                 still mounted. */
++              struct xenbus_device * dev = info->xbdev;
++              enum xenbus_state state = xenbus_read_driver_state(dev->otherend);
++
++              if (state == XenbusStateClosing && info->is_ready)
++                      blkfront_closing(dev);
++      }
++      return 0;
++}
++
++
++int blkif_ioctl(struct inode *inode, struct file *filep,
++              unsigned command, unsigned long argument)
++{
++      int i;
++
++      DPRINTK_IOCTL("command: 0x%x, argument: 0x%lx, dev: 0x%04x\n",
++                    command, (long)argument, inode->i_rdev);
++
++      switch (command) {
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16)
++      case HDIO_GETGEO: {
++              struct block_device *bd = inode->i_bdev;
++              struct hd_geometry geo;
++              int ret;
++
++                if (!argument)
++                        return -EINVAL;
++
++              geo.start = get_start_sect(bd);
++              ret = blkif_getgeo(bd, &geo);
++              if (ret)
++                      return ret;
++
++              if (copy_to_user((struct hd_geometry __user *)argument, &geo,
++                               sizeof(geo)))
++                        return -EFAULT;
++
++                return 0;
++      }
++#endif
++      case CDROMMULTISESSION:
++              DPRINTK("FIXME: support multisession CDs later\n");
++              for (i = 0; i < sizeof(struct cdrom_multisession); i++)
++                      if (put_user(0, (char __user *)(argument + i)))
++                              return -EFAULT;
++              return 0;
++
++      case CDROM_GET_CAPABILITY: {
++              struct blkfront_info *info =
++                      inode->i_bdev->bd_disk->private_data;
++              struct gendisk *gd = info->gd;
++              if (gd->flags & GENHD_FL_CD)
++                      return 0;
++              return -EINVAL;
++      }
++      default:
++              /*printk(KERN_ALERT "ioctl %08x not supported by Xen blkdev\n",
++                command);*/
++              return -EINVAL; /* same return as native Linux */
++      }
++
++      return 0;
++}
++
++
++int blkif_getgeo(struct block_device *bd, struct hd_geometry *hg)
++{
++      /* We don't have real geometry info, but let's at least return
++         values consistent with the size of the device */
++      sector_t nsect = get_capacity(bd->bd_disk);
++      sector_t cylinders = nsect;
++
++      hg->heads = 0xff;
++      hg->sectors = 0x3f;
++      sector_div(cylinders, hg->heads * hg->sectors);
++      hg->cylinders = cylinders;
++      if ((sector_t)(hg->cylinders + 1) * hg->heads * hg->sectors < nsect)
++              hg->cylinders = 0xffff;
++      return 0;
++}
++
++
++/*
++ * blkif_queue_request
++ *
++ * request block io
++ *
++ * id: for guest use only.
++ * operation: BLKIF_OP_{READ,WRITE,PROBE}
++ * buffer: buffer to read/write into. this should be a
++ *   virtual address in the guest os.
++ */
++static int blkif_queue_request(struct request *req)
++{
++      struct blkfront_info *info = req->rq_disk->private_data;
++      unsigned long buffer_mfn;
++      blkif_request_t *ring_req;
++      struct bio *bio;
++      struct bio_vec *bvec;
++      int idx;
++      unsigned long id;
++      unsigned int fsect, lsect;
++      int ref;
++      grant_ref_t gref_head;
++
++      if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
++              return 1;
++
++      if (gnttab_alloc_grant_references(
++              BLKIF_MAX_SEGMENTS_PER_REQUEST, &gref_head) < 0) {
++              gnttab_request_free_callback(
++                      &info->callback,
++                      blkif_restart_queue_callback,
++                      info,
++                      BLKIF_MAX_SEGMENTS_PER_REQUEST);
++              return 1;
++      }
++
++      /* Fill out a communications ring structure. */
++      ring_req = RING_GET_REQUEST(&info->ring, info->ring.req_prod_pvt);
++      id = GET_ID_FROM_FREELIST(info);
++      info->shadow[id].request = (unsigned long)req;
++
++      ring_req->id = id;
++      ring_req->sector_number = (blkif_sector_t)req->sector;
++      ring_req->handle = info->handle;
++
++      ring_req->operation = rq_data_dir(req) ?
++              BLKIF_OP_WRITE : BLKIF_OP_READ;
++      if (blk_barrier_rq(req))
++              ring_req->operation = BLKIF_OP_WRITE_BARRIER;
++
++      ring_req->nr_segments = 0;
++      rq_for_each_bio (bio, req) {
++              bio_for_each_segment (bvec, bio, idx) {
++                      BUG_ON(ring_req->nr_segments
++                             == BLKIF_MAX_SEGMENTS_PER_REQUEST);
++                      buffer_mfn = page_to_phys(bvec->bv_page) >> PAGE_SHIFT;
++                      fsect = bvec->bv_offset >> 9;
++                      lsect = fsect + (bvec->bv_len >> 9) - 1;
++                      /* install a grant reference. */
++                      ref = gnttab_claim_grant_reference(&gref_head);
++                      BUG_ON(ref == -ENOSPC);
++
++                      gnttab_grant_foreign_access_ref(
++                              ref,
++                              info->xbdev->otherend_id,
++                              buffer_mfn,
++                              rq_data_dir(req) ? GTF_readonly : 0 );
++
++                      info->shadow[id].frame[ring_req->nr_segments] =
++                              mfn_to_pfn(buffer_mfn);
++
++                      ring_req->seg[ring_req->nr_segments] =
++                              (struct blkif_request_segment) {
++                                      .gref       = ref,
++                                      .first_sect = fsect,
++                                      .last_sect  = lsect };
++
++                      ring_req->nr_segments++;
++              }
++      }
++
++      info->ring.req_prod_pvt++;
++
++      /* Keep a private copy so we can reissue requests when recovering. */
++      info->shadow[id].req = *ring_req;
++
++      gnttab_free_grant_references(gref_head);
++
++      return 0;
++}
++
++/*
++ * do_blkif_request
++ *  read a block; request is in a request queue
++ */
++void do_blkif_request(request_queue_t *rq)
++{
++      struct blkfront_info *info = NULL;
++      struct request *req;
++      int queued;
++
++      DPRINTK("Entered do_blkif_request\n");
++
++      queued = 0;
++
++      while ((req = elv_next_request(rq)) != NULL) {
++              info = req->rq_disk->private_data;
++              if (!blk_fs_request(req)) {
++                      end_request(req, 0);
++                      continue;
++              }
++
++              if (RING_FULL(&info->ring))
++                      goto wait;
++
++              DPRINTK("do_blk_req %p: cmd %p, sec %llx, "
++                      "(%u/%li) buffer:%p [%s]\n",
++                      req, req->cmd, (long long)req->sector,
++                      req->current_nr_sectors,
++                      req->nr_sectors, req->buffer,
++                      rq_data_dir(req) ? "write" : "read");
++
++
++              blkdev_dequeue_request(req);
++              if (blkif_queue_request(req)) {
++                      blk_requeue_request(rq, req);
++              wait:
++                      /* Avoid pointless unplugs. */
++                      blk_stop_queue(rq);
++                      break;
++              }
++
++              queued++;
++      }
++
++      if (queued != 0)
++              flush_requests(info);
++}
++
++
++static irqreturn_t blkif_int(int irq, void *dev_id, struct pt_regs *ptregs)
++{
++      struct request *req;
++      blkif_response_t *bret;
++      RING_IDX i, rp;
++      unsigned long flags;
++      struct blkfront_info *info = (struct blkfront_info *)dev_id;
++      int uptodate;
++
++      spin_lock_irqsave(&blkif_io_lock, flags);
++
++      if (unlikely(info->connected != BLKIF_STATE_CONNECTED)) {
++              spin_unlock_irqrestore(&blkif_io_lock, flags);
++              return IRQ_HANDLED;
++      }
++
++ again:
++      rp = info->ring.sring->rsp_prod;
++      rmb(); /* Ensure we see queued responses up to 'rp'. */
++
++      for (i = info->ring.rsp_cons; i != rp; i++) {
++              unsigned long id;
++              int ret;
++
++              bret = RING_GET_RESPONSE(&info->ring, i);
++              id   = bret->id;
++              req  = (struct request *)info->shadow[id].request;
++
++              blkif_completion(&info->shadow[id]);
++
++              ADD_ID_TO_FREELIST(info, id);
++
++              uptodate = (bret->status == BLKIF_RSP_OKAY);
++              switch (bret->operation) {
++              case BLKIF_OP_WRITE_BARRIER:
++                      if (unlikely(bret->status == BLKIF_RSP_EOPNOTSUPP)) {
++                              printk("blkfront: %s: write barrier op failed\n",
++                                     info->gd->disk_name);
++                              uptodate = -EOPNOTSUPP;
++                              info->feature_barrier = 0;
++                              xlvbd_barrier(info);
++                      }
++                      /* fall through */
++              case BLKIF_OP_READ:
++              case BLKIF_OP_WRITE:
++                      if (unlikely(bret->status != BLKIF_RSP_OKAY))
++                              DPRINTK("Bad return from blkdev data "
++                                      "request: %x\n", bret->status);
++
++                      ret = end_that_request_first(req, uptodate,
++                              req->hard_nr_sectors);
++                      BUG_ON(ret);
++                      end_that_request_last(req, uptodate);
++                      break;
++              default:
++                      BUG();
++              }
++      }
++
++      info->ring.rsp_cons = i;
++
++      if (i != info->ring.req_prod_pvt) {
++              int more_to_do;
++              RING_FINAL_CHECK_FOR_RESPONSES(&info->ring, more_to_do);
++              if (more_to_do)
++                      goto again;
++      } else
++              info->ring.sring->rsp_event = i + 1;
++
++      kick_pending_request_queues(info);
++
++      spin_unlock_irqrestore(&blkif_io_lock, flags);
++
++      return IRQ_HANDLED;
++}
++
++static void blkif_free(struct blkfront_info *info, int suspend)
++{
++      /* Prevent new requests being issued until we fix things up. */
++      spin_lock_irq(&blkif_io_lock);
++      info->connected = suspend ?
++              BLKIF_STATE_SUSPENDED : BLKIF_STATE_DISCONNECTED;
++      /* No more blkif_request(). */
++      if (info->rq)
++              blk_stop_queue(info->rq);
++      /* No more gnttab callback work. */
++      gnttab_cancel_free_callback(&info->callback);
++      spin_unlock_irq(&blkif_io_lock);
++
++      /* Flush gnttab callback work. Must be done with no locks held. */
++      flush_scheduled_work();
++
++      /* Free resources associated with old device channel. */
++      if (info->ring_ref != GRANT_INVALID_REF) {
++              gnttab_end_foreign_access(info->ring_ref, 
++                                        (unsigned long)info->ring.sring);
++              info->ring_ref = GRANT_INVALID_REF;
++              info->ring.sring = NULL;
++      }
++      if (info->irq)
++              unbind_from_irqhandler(info->irq, info);
++      info->irq = 0;
++}
++
++static void blkif_completion(struct blk_shadow *s)
++{
++      int i;
++      for (i = 0; i < s->req.nr_segments; i++)
++              gnttab_end_foreign_access(s->req.seg[i].gref, 0UL);
++}
++
++static void blkif_recover(struct blkfront_info *info)
++{
++      int i;
++      blkif_request_t *req;
++      struct blk_shadow *copy;
++      int j;
++
++      /* Stage 1: Make a safe copy of the shadow state. */
++      copy = kmalloc(sizeof(info->shadow), GFP_KERNEL | __GFP_NOFAIL | __GFP_HIGH);
++      memcpy(copy, info->shadow, sizeof(info->shadow));
++
++      /* Stage 2: Set up free list. */
++      memset(&info->shadow, 0, sizeof(info->shadow));
++      for (i = 0; i < BLK_RING_SIZE; i++)
++              info->shadow[i].req.id = i+1;
++      info->shadow_free = info->ring.req_prod_pvt;
++      info->shadow[BLK_RING_SIZE-1].req.id = 0x0fffffff;
++
++      /* Stage 3: Find pending requests and requeue them. */
++      for (i = 0; i < BLK_RING_SIZE; i++) {
++              /* Not in use? */
++              if (copy[i].request == 0)
++                      continue;
++
++              /* Grab a request slot and copy shadow state into it. */
++              req = RING_GET_REQUEST(
++                      &info->ring, info->ring.req_prod_pvt);
++              *req = copy[i].req;
++
++              /* We get a new request id, and must reset the shadow state. */
++              req->id = GET_ID_FROM_FREELIST(info);
++              memcpy(&info->shadow[req->id], &copy[i], sizeof(copy[i]));
++
++              /* Rewrite any grant references invalidated by susp/resume. */
++              for (j = 0; j < req->nr_segments; j++)
++                      gnttab_grant_foreign_access_ref(
++                              req->seg[j].gref,
++                              info->xbdev->otherend_id,
++                              pfn_to_mfn(info->shadow[req->id].frame[j]),
++                              rq_data_dir((struct request *)
++                                          info->shadow[req->id].request) ?
++                              GTF_readonly : 0);
++              info->shadow[req->id].req = *req;
++
++              info->ring.req_prod_pvt++;
++      }
++
++      kfree(copy);
++
++      (void)xenbus_switch_state(info->xbdev, XenbusStateConnected);
++
++      spin_lock_irq(&blkif_io_lock);
++
++      /* Now safe for us to use the shared ring */
++      info->connected = BLKIF_STATE_CONNECTED;
++
++      /* Send off requeued requests */
++      flush_requests(info);
++
++      /* Kick any other new requests queued since we resumed */
++      kick_pending_request_queues(info);
++
++      spin_unlock_irq(&blkif_io_lock);
++}
++
++int blkfront_is_ready(struct xenbus_device *dev)
++{
++      struct blkfront_info *info = dev->dev.driver_data;
++
++      return info->is_ready;
++}
++
++
++/* ** Driver Registration ** */
++
++
++static const struct xenbus_device_id blkfront_ids[] = {
++      { "vbd" },
++      { "" }
++};
++MODULE_ALIAS("xen:vbd");
++
++static struct xenbus_driver blkfront = {
++      .name = "vbd",
++      .owner = THIS_MODULE,
++      .ids = blkfront_ids,
++      .probe = blkfront_probe,
++      .remove = blkfront_remove,
++      .resume = blkfront_resume,
++      .otherend_changed = backend_changed,
++      .is_ready = blkfront_is_ready,
++};
++
++
++static int __init xlblk_init(void)
++{
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      return xenbus_register_frontend(&blkfront);
++}
++module_init(xlblk_init);
++
++
++static void __exit xlblk_exit(void)
++{
++      return xenbus_unregister_driver(&blkfront);
++}
++module_exit(xlblk_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
+--- linux-2.6.18.8/drivers/xen/blkfront/block.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blkfront/block.h   2008-05-19 00:33:45.686779559 +0300
+@@ -0,0 +1,143 @@
++/******************************************************************************
++ * block.h
++ * 
++ * Shared definitions between all levels of XenLinux Virtual block devices.
++ * 
++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
++ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
++ * Copyright (c) 2004-2005, Christian Limpach
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef __XEN_DRIVERS_BLOCK_H__
++#define __XEN_DRIVERS_BLOCK_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/hdreg.h>
++#include <linux/blkdev.h>
++#include <linux/major.h>
++#include <asm/hypervisor.h>
++#include <xen/xenbus.h>
++#include <xen/gnttab.h>
++#include <xen/interface/xen.h>
++#include <xen/interface/io/blkif.h>
++#include <xen/interface/io/ring.h>
++#include <asm/io.h>
++#include <asm/atomic.h>
++#include <asm/uaccess.h>
++
++#define DPRINTK(_f, _a...) pr_debug(_f, ## _a)
++
++#if 0
++#define DPRINTK_IOCTL(_f, _a...) printk(KERN_ALERT _f, ## _a)
++#else
++#define DPRINTK_IOCTL(_f, _a...) ((void)0)
++#endif
++
++struct xlbd_type_info
++{
++      int partn_shift;
++      int disks_per_major;
++      char *devname;
++      char *diskname;
++};
++
++struct xlbd_major_info
++{
++      int major;
++      int index;
++      int usage;
++      struct xlbd_type_info *type;
++};
++
++struct blk_shadow {
++      blkif_request_t req;
++      unsigned long request;
++      unsigned long frame[BLKIF_MAX_SEGMENTS_PER_REQUEST];
++};
++
++#define BLK_RING_SIZE __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE)
++
++/*
++ * We have one of these per vbd, whether ide, scsi or 'other'.  They
++ * hang in private_data off the gendisk structure. We may end up
++ * putting all kinds of interesting stuff here :-)
++ */
++struct blkfront_info
++{
++      struct xenbus_device *xbdev;
++      dev_t dev;
++      struct gendisk *gd;
++      int vdevice;
++      blkif_vdev_t handle;
++      int connected;
++      int ring_ref;
++      blkif_front_ring_t ring;
++      unsigned int irq;
++      struct xlbd_major_info *mi;
++      request_queue_t *rq;
++      struct work_struct work;
++      struct gnttab_free_callback callback;
++      struct blk_shadow shadow[BLK_RING_SIZE];
++      unsigned long shadow_free;
++      int feature_barrier;
++      int is_ready;
++
++      /**
++       * The number of people holding this device open.  We won't allow a
++       * hot-unplug unless this is 0.
++       */
++      int users;
++};
++
++extern spinlock_t blkif_io_lock;
++
++extern int blkif_open(struct inode *inode, struct file *filep);
++extern int blkif_release(struct inode *inode, struct file *filep);
++extern int blkif_ioctl(struct inode *inode, struct file *filep,
++                     unsigned command, unsigned long argument);
++extern int blkif_getgeo(struct block_device *, struct hd_geometry *);
++extern int blkif_check(dev_t dev);
++extern int blkif_revalidate(dev_t dev);
++extern void do_blkif_request (request_queue_t *rq);
++
++/* Virtual block-device subsystem. */
++/* Note that xlvbd_add doesn't call add_disk for you: you're expected
++   to call add_disk on info->gd once the disk is properly connected
++   up. */
++int xlvbd_add(blkif_sector_t capacity, int device,
++            u16 vdisk_info, u16 sector_size, struct blkfront_info *info);
++void xlvbd_del(struct blkfront_info *info);
++int xlvbd_barrier(struct blkfront_info *info);
++
++#endif /* __XEN_DRIVERS_BLOCK_H__ */
+--- linux-2.6.18.8/drivers/xen/blkfront/vbd.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blkfront/vbd.c     2008-05-19 00:33:45.686779559 +0300
+@@ -0,0 +1,375 @@
++/******************************************************************************
++ * vbd.c
++ * 
++ * XenLinux virtual block-device driver (xvd).
++ * 
++ * Copyright (c) 2003-2004, Keir Fraser & Steve Hand
++ * Modifications by Mark A. Williamson are (c) Intel Research Cambridge
++ * Copyright (c) 2004-2005, Christian Limpach
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include "block.h"
++#include <linux/blkdev.h>
++#include <linux/list.h>
++
++#ifdef HAVE_XEN_PLATFORM_COMPAT_H
++#include <xen/platform-compat.h>
++#endif
++
++#define BLKIF_MAJOR(dev) ((dev)>>8)
++#define BLKIF_MINOR(dev) ((dev) & 0xff)
++
++/*
++ * For convenience we distinguish between ide, scsi and 'other' (i.e.,
++ * potentially combinations of the two) in the naming scheme and in a few other
++ * places.
++ */
++
++#define NUM_IDE_MAJORS 10
++#define NUM_SCSI_MAJORS 17
++#define NUM_VBD_MAJORS 1
++
++static struct xlbd_type_info xlbd_ide_type = {
++      .partn_shift = 6,
++      .disks_per_major = 2,
++      .devname = "ide",
++      .diskname = "hd",
++};
++
++static struct xlbd_type_info xlbd_scsi_type = {
++      .partn_shift = 4,
++      .disks_per_major = 16,
++      .devname = "sd",
++      .diskname = "sd",
++};
++
++static struct xlbd_type_info xlbd_vbd_type = {
++      .partn_shift = 4,
++      .disks_per_major = 16,
++      .devname = "xvd",
++      .diskname = "xvd",
++};
++
++static struct xlbd_major_info *major_info[NUM_IDE_MAJORS + NUM_SCSI_MAJORS +
++                                       NUM_VBD_MAJORS];
++
++#define XLBD_MAJOR_IDE_START  0
++#define XLBD_MAJOR_SCSI_START (NUM_IDE_MAJORS)
++#define XLBD_MAJOR_VBD_START  (NUM_IDE_MAJORS + NUM_SCSI_MAJORS)
++
++#define XLBD_MAJOR_IDE_RANGE  XLBD_MAJOR_IDE_START ... XLBD_MAJOR_SCSI_START - 1
++#define XLBD_MAJOR_SCSI_RANGE XLBD_MAJOR_SCSI_START ... XLBD_MAJOR_VBD_START - 1
++#define XLBD_MAJOR_VBD_RANGE  XLBD_MAJOR_VBD_START ... XLBD_MAJOR_VBD_START + NUM_VBD_MAJORS - 1
++
++/* Information about our VBDs. */
++#define MAX_VBDS 64
++static LIST_HEAD(vbds_list);
++
++static struct block_device_operations xlvbd_block_fops =
++{
++      .owner = THIS_MODULE,
++      .open = blkif_open,
++      .release = blkif_release,
++      .ioctl  = blkif_ioctl,
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
++      .getgeo = blkif_getgeo
++#endif
++};
++
++DEFINE_SPINLOCK(blkif_io_lock);
++
++static struct xlbd_major_info *
++xlbd_alloc_major_info(int major, int minor, int index)
++{
++      struct xlbd_major_info *ptr;
++
++      ptr = kzalloc(sizeof(struct xlbd_major_info), GFP_KERNEL);
++      if (ptr == NULL)
++              return NULL;
++
++      ptr->major = major;
++
++      switch (index) {
++      case XLBD_MAJOR_IDE_RANGE:
++              ptr->type = &xlbd_ide_type;
++              ptr->index = index - XLBD_MAJOR_IDE_START;
++              break;
++      case XLBD_MAJOR_SCSI_RANGE:
++              ptr->type = &xlbd_scsi_type;
++              ptr->index = index - XLBD_MAJOR_SCSI_START;
++              break;
++      case XLBD_MAJOR_VBD_RANGE:
++              ptr->type = &xlbd_vbd_type;
++              ptr->index = index - XLBD_MAJOR_VBD_START;
++              break;
++      }
++
++      if (register_blkdev(ptr->major, ptr->type->devname)) {
++              kfree(ptr);
++              return NULL;
++      }
++
++      printk("xen-vbd: registered block device major %i\n", ptr->major);
++      major_info[index] = ptr;
++      return ptr;
++}
++
++static struct xlbd_major_info *
++xlbd_get_major_info(int vdevice)
++{
++      struct xlbd_major_info *mi;
++      int major, minor, index;
++
++      major = BLKIF_MAJOR(vdevice);
++      minor = BLKIF_MINOR(vdevice);
++
++      switch (major) {
++      case IDE0_MAJOR: index = 0; break;
++      case IDE1_MAJOR: index = 1; break;
++      case IDE2_MAJOR: index = 2; break;
++      case IDE3_MAJOR: index = 3; break;
++      case IDE4_MAJOR: index = 4; break;
++      case IDE5_MAJOR: index = 5; break;
++      case IDE6_MAJOR: index = 6; break;
++      case IDE7_MAJOR: index = 7; break;
++      case IDE8_MAJOR: index = 8; break;
++      case IDE9_MAJOR: index = 9; break;
++      case SCSI_DISK0_MAJOR: index = 10; break;
++      case SCSI_DISK1_MAJOR ... SCSI_DISK7_MAJOR:
++              index = 11 + major - SCSI_DISK1_MAJOR;
++              break;
++        case SCSI_DISK8_MAJOR ... SCSI_DISK15_MAJOR:
++                index = 18 + major - SCSI_DISK8_MAJOR;
++                break;
++        case SCSI_CDROM_MAJOR: index = 26; break;
++        default: index = 27; break;
++      }
++
++      mi = ((major_info[index] != NULL) ? major_info[index] :
++            xlbd_alloc_major_info(major, minor, index));
++      if (mi)
++              mi->usage++;
++      return mi;
++}
++
++static void
++xlbd_put_major_info(struct xlbd_major_info *mi)
++{
++      mi->usage--;
++      /* XXX: release major if 0 */
++}
++
++static int
++xlvbd_init_blk_queue(struct gendisk *gd, u16 sector_size)
++{
++      request_queue_t *rq;
++
++      rq = blk_init_queue(do_blkif_request, &blkif_io_lock);
++      if (rq == NULL)
++              return -1;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,10)
++      elevator_init(rq, "noop");
++#else
++      elevator_init(rq, &elevator_noop);
++#endif
++
++      /* Hard sector size and max sectors impersonate the equiv. hardware. */
++      blk_queue_hardsect_size(rq, sector_size);
++      blk_queue_max_sectors(rq, 512);
++
++      /* Each segment in a request is up to an aligned page in size. */
++      blk_queue_segment_boundary(rq, PAGE_SIZE - 1);
++      blk_queue_max_segment_size(rq, PAGE_SIZE);
++
++      /* Ensure a merged request will fit in a single I/O ring slot. */
++      blk_queue_max_phys_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
++      blk_queue_max_hw_segments(rq, BLKIF_MAX_SEGMENTS_PER_REQUEST);
++
++      /* Make sure buffer addresses are sector-aligned. */
++      blk_queue_dma_alignment(rq, 511);
++
++      /* Make sure we don't use bounce buffers. */
++      blk_queue_bounce_limit(rq, BLK_BOUNCE_ANY);
++
++      gd->queue = rq;
++
++      return 0;
++}
++
++static int
++xlvbd_alloc_gendisk(int minor, blkif_sector_t capacity, int vdevice,
++                  u16 vdisk_info, u16 sector_size,
++                  struct blkfront_info *info)
++{
++      struct gendisk *gd;
++      struct xlbd_major_info *mi;
++      int nr_minors = 1;
++      int err = -ENODEV;
++      unsigned int offset;
++
++      BUG_ON(info->gd != NULL);
++      BUG_ON(info->mi != NULL);
++      BUG_ON(info->rq != NULL);
++
++      mi = xlbd_get_major_info(vdevice);
++      if (mi == NULL)
++              goto out;
++      info->mi = mi;
++
++      if ((minor & ((1 << mi->type->partn_shift) - 1)) == 0)
++              nr_minors = 1 << mi->type->partn_shift;
++
++      gd = alloc_disk(nr_minors);
++      if (gd == NULL)
++              goto out;
++
++      offset =  mi->index * mi->type->disks_per_major +
++                      (minor >> mi->type->partn_shift);
++      if (nr_minors > 1) {
++              if (offset < 26) {
++                      sprintf(gd->disk_name, "%s%c",
++                               mi->type->diskname, 'a' + offset );
++              }
++              else {
++                      sprintf(gd->disk_name, "%s%c%c",
++                              mi->type->diskname,
++                              'a' + ((offset/26)-1), 'a' + (offset%26) );
++              }
++      }
++      else {
++              if (offset < 26) {
++                      sprintf(gd->disk_name, "%s%c%d",
++                              mi->type->diskname,
++                              'a' + offset,
++                              minor & ((1 << mi->type->partn_shift) - 1));
++              }
++              else {
++                      sprintf(gd->disk_name, "%s%c%c%d",
++                              mi->type->diskname,
++                              'a' + ((offset/26)-1), 'a' + (offset%26),
++                              minor & ((1 << mi->type->partn_shift) - 1));
++              }
++      }
++
++      gd->major = mi->major;
++      gd->first_minor = minor;
++      gd->fops = &xlvbd_block_fops;
++      gd->private_data = info;
++      gd->driverfs_dev = &(info->xbdev->dev);
++      set_capacity(gd, capacity);
++
++      if (xlvbd_init_blk_queue(gd, sector_size)) {
++              del_gendisk(gd);
++              goto out;
++      }
++
++      info->rq = gd->queue;
++      info->gd = gd;
++
++      if (info->feature_barrier)
++              xlvbd_barrier(info);
++
++      if (vdisk_info & VDISK_READONLY)
++              set_disk_ro(gd, 1);
++
++      if (vdisk_info & VDISK_REMOVABLE)
++              gd->flags |= GENHD_FL_REMOVABLE;
++
++      if (vdisk_info & VDISK_CDROM)
++              gd->flags |= GENHD_FL_CD;
++
++      return 0;
++
++ out:
++      if (mi)
++              xlbd_put_major_info(mi);
++      info->mi = NULL;
++      return err;
++}
++
++int
++xlvbd_add(blkif_sector_t capacity, int vdevice, u16 vdisk_info,
++        u16 sector_size, struct blkfront_info *info)
++{
++      struct block_device *bd;
++      int err = 0;
++
++      info->dev = MKDEV(BLKIF_MAJOR(vdevice), BLKIF_MINOR(vdevice));
++
++      bd = bdget(info->dev);
++      if (bd == NULL)
++              return -ENODEV;
++
++      err = xlvbd_alloc_gendisk(BLKIF_MINOR(vdevice), capacity, vdevice,
++                                vdisk_info, sector_size, info);
++
++      bdput(bd);
++      return err;
++}
++
++void
++xlvbd_del(struct blkfront_info *info)
++{
++      if (info->mi == NULL)
++              return;
++
++      BUG_ON(info->gd == NULL);
++      del_gendisk(info->gd);
++      put_disk(info->gd);
++      info->gd = NULL;
++
++      xlbd_put_major_info(info->mi);
++      info->mi = NULL;
++
++      BUG_ON(info->rq == NULL);
++      blk_cleanup_queue(info->rq);
++      info->rq = NULL;
++}
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,16)
++int
++xlvbd_barrier(struct blkfront_info *info)
++{
++      int err;
++
++      err = blk_queue_ordered(info->rq,
++              info->feature_barrier ? QUEUE_ORDERED_DRAIN : QUEUE_ORDERED_NONE, NULL);
++      if (err)
++              return err;
++      printk(KERN_INFO "blkfront: %s: barriers %s\n",
++             info->gd->disk_name, info->feature_barrier ? "enabled" : "disabled");
++      return 0;
++}
++#else
++int
++xlvbd_barrier(struct blkfront_info *info)
++{
++      printk(KERN_INFO "blkfront: %s: barriers disabled\n", info->gd->disk_name);
++      return -ENOSYS;
++}
++#endif
+--- linux-2.6.18.8/drivers/xen/blktap/Makefile 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blktap/Makefile    2008-05-19 00:33:45.698780251 +0300
+@@ -0,0 +1,5 @@
++LINUXINCLUDE += -I../xen/include/public/io
++
++obj-$(CONFIG_XEN_BLKDEV_TAP) := xenblktap.o
++
++xenblktap-y := xenbus.o interface.o blktap.o 
+--- linux-2.6.18.8/drivers/xen/blktap/blktap.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blktap/blktap.c    2008-05-19 00:33:45.698780251 +0300
+@@ -0,0 +1,1648 @@
++/******************************************************************************
++ * drivers/xen/blktap/blktap.c
++ * 
++ * Back-end driver for user level virtual block devices. This portion of the
++ * driver exports a 'unified' block-device interface that can be accessed
++ * by any operating system that implements a compatible front end. Requests
++ * are remapped to a user-space memory region.
++ *
++ * Based on the blkback driver code.
++ * 
++ * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
++ *
++ * Clean ups and fix ups:
++ *    Copyright (c) 2006, Steven Rostedt - Red Hat, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/spinlock.h>
++#include <linux/kthread.h>
++#include <linux/list.h>
++#include <asm/hypervisor.h>
++#include "common.h"
++#include <xen/balloon.h>
++#include <xen/driver_util.h>
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/errno.h>
++#include <linux/major.h>
++#include <linux/gfp.h>
++#include <linux/poll.h>
++#include <linux/delay.h>
++#include <asm/tlbflush.h>
++
++#define MAX_TAP_DEV 256     /*the maximum number of tapdisk ring devices    */
++#define MAX_DEV_NAME 100    /*the max tapdisk ring device name e.g. blktap0 */
++
++/*
++ * The maximum number of requests that can be outstanding at any time
++ * is determined by 
++ *
++ *   [mmap_alloc * MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST] 
++ *
++ * where mmap_alloc < MAX_DYNAMIC_MEM.
++ *
++ * TODO:
++ * mmap_alloc is initialised to 2 and should be adjustable on the fly via
++ * sysfs.
++ */
++#define BLK_RING_SIZE         __RING_SIZE((blkif_sring_t *)0, PAGE_SIZE)
++#define MAX_DYNAMIC_MEM               BLK_RING_SIZE
++#define MAX_PENDING_REQS      BLK_RING_SIZE
++#define MMAP_PAGES (MAX_PENDING_REQS * BLKIF_MAX_SEGMENTS_PER_REQUEST)
++#define MMAP_VADDR(_start, _req,_seg)                                   \
++        (_start +                                                       \
++         ((_req) * BLKIF_MAX_SEGMENTS_PER_REQUEST * PAGE_SIZE) +        \
++         ((_seg) * PAGE_SIZE))
++static int blkif_reqs = MAX_PENDING_REQS;
++static int mmap_pages = MMAP_PAGES;
++
++#define RING_PAGES 1 /* BLKTAP - immediately before the mmap area, we
++                    * have a bunch of pages reserved for shared
++                    * memory rings.
++                    */
++
++/*Data struct handed back to userspace for tapdisk device to VBD mapping*/
++typedef struct domid_translate {
++      unsigned short domid;
++      unsigned short busid;
++} domid_translate_t ;
++
++/*Data struct associated with each of the tapdisk devices*/
++typedef struct tap_blkif {
++      struct vm_area_struct *vma;   /*Shared memory area                   */
++      unsigned long rings_vstart;   /*Kernel memory mapping                */
++      unsigned long user_vstart;    /*User memory mapping                  */
++      unsigned long dev_inuse;      /*One process opens device at a time.  */
++      unsigned long dev_pending;    /*In process of being opened           */
++      unsigned long ring_ok;        /*make this ring->state                */
++      blkif_front_ring_t ufe_ring;  /*Rings up to user space.              */
++      wait_queue_head_t wait;       /*for poll                             */
++      unsigned long mode;           /*current switching mode               */
++      int minor;                    /*Minor number for tapdisk device      */
++      pid_t pid;                    /*tapdisk process id                   */
++      enum { RUNNING, CLEANSHUTDOWN } status; /*Detect a clean userspace 
++                                                shutdown                   */
++      unsigned long *idx_map;       /*Record the user ring id to kern 
++                                      [req id, idx] tuple                  */
++      blkif_t *blkif;               /*Associate blkif with tapdev          */
++      struct domid_translate trans; /*Translation from domid to bus.       */
++} tap_blkif_t;
++
++static struct tap_blkif *tapfds[MAX_TAP_DEV];
++static int blktap_next_minor;
++
++module_param(blkif_reqs, int, 0);
++/* Run-time switchable: /sys/module/blktap/parameters/ */
++static unsigned int log_stats = 0;
++static unsigned int debug_lvl = 0;
++module_param(log_stats, int, 0644);
++module_param(debug_lvl, int, 0644);
++
++/*
++ * Each outstanding request that we've passed to the lower device layers has a 
++ * 'pending_req' allocated to it. Each buffer_head that completes decrements 
++ * the pendcnt towards zero. When it hits zero, the specified domain has a 
++ * response queued for it, with the saved 'id' passed back.
++ */
++typedef struct {
++      blkif_t       *blkif;
++      u64            id;
++      unsigned short mem_idx;
++      int            nr_pages;
++      atomic_t       pendcnt;
++      unsigned short operation;
++      int            status;
++      struct list_head free_list;
++      int            inuse;
++} pending_req_t;
++
++static pending_req_t *pending_reqs[MAX_PENDING_REQS];
++static struct list_head pending_free;
++static DEFINE_SPINLOCK(pending_free_lock);
++static DECLARE_WAIT_QUEUE_HEAD (pending_free_wq);
++static int alloc_pending_reqs;
++
++typedef unsigned int PEND_RING_IDX;
++
++static inline int MASK_PEND_IDX(int i) { 
++      return (i & (MAX_PENDING_REQS-1));
++}
++
++static inline unsigned int RTN_PEND_IDX(pending_req_t *req, int idx) {
++      return (req - pending_reqs[idx]);
++}
++
++#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
++
++#define BLKBACK_INVALID_HANDLE (~0)
++
++static struct page **foreign_pages[MAX_DYNAMIC_MEM];
++static inline unsigned long idx_to_kaddr(
++      unsigned int mmap_idx, unsigned int req_idx, unsigned int sg_idx)
++{
++      unsigned int arr_idx = req_idx*BLKIF_MAX_SEGMENTS_PER_REQUEST + sg_idx;
++      unsigned long pfn = page_to_pfn(foreign_pages[mmap_idx][arr_idx]);
++      return (unsigned long)pfn_to_kaddr(pfn);
++}
++
++static unsigned short mmap_alloc = 0;
++static unsigned short mmap_lock = 0;
++static unsigned short mmap_inuse = 0;
++
++/******************************************************************
++ * GRANT HANDLES
++ */
++
++/* When using grant tables to map a frame for device access then the
++ * handle returned must be used to unmap the frame. This is needed to
++ * drop the ref count on the frame.
++ */
++struct grant_handle_pair
++{
++        grant_handle_t kernel;
++        grant_handle_t user;
++};
++#define INVALID_GRANT_HANDLE  0xFFFF
++
++static struct grant_handle_pair 
++    pending_grant_handles[MAX_DYNAMIC_MEM][MMAP_PAGES];
++#define pending_handle(_id, _idx, _i) \
++    (pending_grant_handles[_id][((_idx) * BLKIF_MAX_SEGMENTS_PER_REQUEST) \
++    + (_i)])
++
++
++static int blktap_read_ufe_ring(tap_blkif_t *info); /*local prototypes*/
++
++#define BLKTAP_MINOR 0  /*/dev/xen/blktap has a dynamic major */
++#define BLKTAP_DEV_DIR  "/dev/xen"
++
++static int blktap_major;
++
++/* blktap IOCTLs: */
++#define BLKTAP_IOCTL_KICK_FE         1
++#define BLKTAP_IOCTL_KICK_BE         2 /* currently unused */
++#define BLKTAP_IOCTL_SETMODE         3
++#define BLKTAP_IOCTL_SENDPID       4
++#define BLKTAP_IOCTL_NEWINTF       5
++#define BLKTAP_IOCTL_MINOR         6
++#define BLKTAP_IOCTL_MAJOR         7
++#define BLKTAP_QUERY_ALLOC_REQS      8
++#define BLKTAP_IOCTL_FREEINTF        9
++#define BLKTAP_IOCTL_PRINT_IDXS      100  
++
++/* blktap switching modes: (Set with BLKTAP_IOCTL_SETMODE)             */
++#define BLKTAP_MODE_PASSTHROUGH      0x00000000  /* default            */
++#define BLKTAP_MODE_INTERCEPT_FE     0x00000001
++#define BLKTAP_MODE_INTERCEPT_BE     0x00000002  /* unimp.             */
++
++#define BLKTAP_MODE_INTERPOSE \
++           (BLKTAP_MODE_INTERCEPT_FE | BLKTAP_MODE_INTERCEPT_BE)
++
++
++static inline int BLKTAP_MODE_VALID(unsigned long arg)
++{
++      return ((arg == BLKTAP_MODE_PASSTHROUGH ) ||
++              (arg == BLKTAP_MODE_INTERCEPT_FE) ||
++                (arg == BLKTAP_MODE_INTERPOSE   ));
++}
++
++/* Requests passing through the tap to userspace are re-assigned an ID.
++ * We must record a mapping between the BE [IDX,ID] tuple and the userspace
++ * ring ID. 
++ */
++
++static inline unsigned long MAKE_ID(domid_t fe_dom, PEND_RING_IDX idx)
++{
++        return ((fe_dom << 16) | MASK_PEND_IDX(idx));
++}
++
++extern inline PEND_RING_IDX ID_TO_IDX(unsigned long id)
++{
++        return (PEND_RING_IDX)(id & 0x0000ffff);
++}
++
++extern inline int ID_TO_MIDX(unsigned long id)
++{
++        return (int)(id >> 16);
++}
++
++#define INVALID_REQ 0xdead0000
++
++/*TODO: Convert to a free list*/
++static inline int GET_NEXT_REQ(unsigned long *idx_map)
++{
++      int i;
++      for (i = 0; i < MAX_PENDING_REQS; i++)
++              if (idx_map[i] == INVALID_REQ)
++                      return i;
++
++      return INVALID_REQ;
++}
++
++static inline int OFFSET_TO_USR_IDX(int offset)
++{
++      return offset / BLKIF_MAX_SEGMENTS_PER_REQUEST;
++}
++
++static inline int OFFSET_TO_SEG(int offset)
++{
++      return offset % BLKIF_MAX_SEGMENTS_PER_REQUEST;
++}
++
++
++#define BLKTAP_INVALID_HANDLE(_g) \
++    (((_g->kernel) == INVALID_GRANT_HANDLE) &&  \
++     ((_g->user) == INVALID_GRANT_HANDLE))
++
++#define BLKTAP_INVALIDATE_HANDLE(_g) do {       \
++    (_g)->kernel = INVALID_GRANT_HANDLE; (_g)->user = INVALID_GRANT_HANDLE; \
++    } while(0)
++
++
++/******************************************************************
++ * BLKTAP VM OPS
++ */
++
++static struct page *blktap_nopage(struct vm_area_struct *vma,
++                                unsigned long address,
++                                int *type)
++{
++      /*
++       * if the page has not been mapped in by the driver then return
++       * NOPAGE_SIGBUS to the domain.
++       */
++
++      return NOPAGE_SIGBUS;
++}
++
++static pte_t blktap_clear_pte(struct vm_area_struct *vma,
++                            unsigned long uvaddr,
++                            pte_t *ptep, int is_fullmm)
++{
++      pte_t copy;
++      tap_blkif_t *info;
++      int offset, seg, usr_idx, pending_idx, mmap_idx;
++      unsigned long uvstart = vma->vm_start + (RING_PAGES << PAGE_SHIFT);
++      unsigned long kvaddr;
++      struct page **map;
++      struct page *pg;
++      struct grant_handle_pair *khandle;
++      struct gnttab_unmap_grant_ref unmap[2];
++      int count = 0;
++
++      /*
++       * If the address is before the start of the grant mapped region or
++       * if vm_file is NULL (meaning mmap failed and we have nothing to do)
++       */
++      if (uvaddr < uvstart || vma->vm_file == NULL)
++              return ptep_get_and_clear_full(vma->vm_mm, uvaddr, 
++                                             ptep, is_fullmm);
++
++      info = vma->vm_file->private_data;
++      map = vma->vm_private_data;
++
++      /* TODO Should these be changed to if statements? */
++      BUG_ON(!info);
++      BUG_ON(!info->idx_map);
++      BUG_ON(!map);
++
++      offset = (int) ((uvaddr - uvstart) >> PAGE_SHIFT);
++      usr_idx = OFFSET_TO_USR_IDX(offset);
++      seg = OFFSET_TO_SEG(offset);
++
++      pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx]));
++      mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]);
++
++      kvaddr = idx_to_kaddr(mmap_idx, pending_idx, seg);
++      pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
++      ClearPageReserved(pg);
++      map[offset + RING_PAGES] = NULL;
++
++      khandle = &pending_handle(mmap_idx, pending_idx, seg);
++
++      if (khandle->kernel != INVALID_GRANT_HANDLE) {
++              gnttab_set_unmap_op(&unmap[count], kvaddr, 
++                                  GNTMAP_host_map, khandle->kernel);
++              count++;
++
++              set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT, 
++                                  INVALID_P2M_ENTRY);
++      }
++
++      if (khandle->user != INVALID_GRANT_HANDLE) {
++              BUG_ON(xen_feature(XENFEAT_auto_translated_physmap));
++
++              copy = *ptep;
++              gnttab_set_unmap_op(&unmap[count], virt_to_machine(ptep), 
++                                  GNTMAP_host_map 
++                                  | GNTMAP_application_map 
++                                  | GNTMAP_contains_pte,
++                                  khandle->user);
++              count++;
++      } else {
++              BUG_ON(!xen_feature(XENFEAT_auto_translated_physmap));
++
++              /* USING SHADOW PAGE TABLES. */
++              copy = ptep_get_and_clear_full(vma->vm_mm, uvaddr, ptep,
++                                             is_fullmm);
++      }
++
++      if (count) {
++              BLKTAP_INVALIDATE_HANDLE(khandle);
++              if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref,
++                                            unmap, count))
++                      BUG();
++      }
++
++      return copy;
++}
++
++struct vm_operations_struct blktap_vm_ops = {
++      nopage:   blktap_nopage,
++      zap_pte:  blktap_clear_pte,
++};
++
++/******************************************************************
++ * BLKTAP FILE OPS
++ */
++ 
++/*Function Declarations*/
++static tap_blkif_t *get_next_free_dev(void);
++static int blktap_open(struct inode *inode, struct file *filp);
++static int blktap_release(struct inode *inode, struct file *filp);
++static int blktap_mmap(struct file *filp, struct vm_area_struct *vma);
++static int blktap_ioctl(struct inode *inode, struct file *filp,
++                        unsigned int cmd, unsigned long arg);
++static unsigned int blktap_poll(struct file *file, poll_table *wait);
++
++static const struct file_operations blktap_fops = {
++      .owner   = THIS_MODULE,
++      .poll    = blktap_poll,
++      .ioctl   = blktap_ioctl,
++      .open    = blktap_open,
++      .release = blktap_release,
++      .mmap    = blktap_mmap,
++};
++
++
++static tap_blkif_t *get_next_free_dev(void)
++{
++      struct class *class;
++      tap_blkif_t *info;
++      int minor;
++
++      /*
++       * This is called only from the ioctl, which
++       * means we should always have interrupts enabled.
++       */
++      BUG_ON(irqs_disabled());
++
++      spin_lock_irq(&pending_free_lock);
++
++      /* tapfds[0] is always NULL */
++
++      for (minor = 1; minor < blktap_next_minor; minor++) {
++              info = tapfds[minor];
++              /* we could have failed a previous attempt. */
++              if (!info ||
++                  ((info->dev_inuse == 0) &&
++                   (info->dev_pending == 0)) ) {
++                      info->dev_pending = 1;
++                      goto found;
++              }
++      }
++      info = NULL;
++      minor = -1;
++
++      /*
++       * We didn't find free device. If we can still allocate
++       * more, then we grab the next device minor that is
++       * available.  This is done while we are still under
++       * the protection of the pending_free_lock.
++       */
++      if (blktap_next_minor < MAX_TAP_DEV)
++              minor = blktap_next_minor++;
++found:
++      spin_unlock_irq(&pending_free_lock);
++
++      if (!info && minor > 0) {
++              info = kzalloc(sizeof(*info), GFP_KERNEL);
++              if (unlikely(!info)) {
++                      /*
++                       * If we failed here, try to put back
++                       * the next minor number. But if one
++                       * was just taken, then we just lose this
++                       * minor.  We can try to allocate this
++                       * minor again later.
++                       */
++                      spin_lock_irq(&pending_free_lock);
++                      if (blktap_next_minor == minor+1)
++                              blktap_next_minor--;
++                      spin_unlock_irq(&pending_free_lock);
++                      goto out;
++              }
++
++              info->minor = minor;
++              /*
++               * Make sure that we have a minor before others can
++               * see us.
++               */
++              wmb();
++              tapfds[minor] = info;
++
++              if ((class = get_xen_class()) != NULL)
++                      class_device_create(class, NULL,
++                                          MKDEV(blktap_major, minor), NULL,
++                                          "blktap%d", minor);
++      }
++
++out:
++      return info;
++}
++
++int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif) 
++{
++      tap_blkif_t *info;
++      int i;
++
++      for (i = 1; i < blktap_next_minor; i++) {
++              info = tapfds[i];
++              if ( info &&
++                   (info->trans.domid == domid) &&
++                   (info->trans.busid == xenbus_id) ) {
++                      info->blkif = blkif;
++                      info->status = RUNNING;
++                      return i;
++              }
++      }
++      return -1;
++}
++
++void signal_tapdisk(int idx) 
++{
++      tap_blkif_t *info;
++      struct task_struct *ptask;
++
++      info = tapfds[idx];
++      if ((idx < 0) || (idx > MAX_TAP_DEV) || !info)
++              return;
++
++      if (info->pid > 0) {
++              ptask = find_task_by_pid(info->pid);
++              if (ptask)
++                      info->status = CLEANSHUTDOWN;
++      }
++      info->blkif = NULL;
++
++      return;
++}
++
++static int blktap_open(struct inode *inode, struct file *filp)
++{
++      blkif_sring_t *sring;
++      int idx = iminor(inode) - BLKTAP_MINOR;
++      tap_blkif_t *info;
++      int i;
++      
++      /* ctrl device, treat differently */
++      if (!idx)
++              return 0;
++
++      info = tapfds[idx];
++
++      if ((idx < 0) || (idx > MAX_TAP_DEV) || !info) {
++              WPRINTK("Unable to open device /dev/xen/blktap%d\n",
++                      idx);
++              return -ENODEV;
++      }
++
++      DPRINTK("Opening device /dev/xen/blktap%d\n",idx);
++      
++      /*Only one process can access device at a time*/
++      if (test_and_set_bit(0, &info->dev_inuse))
++              return -EBUSY;
++
++      info->dev_pending = 0;
++          
++      /* Allocate the fe ring. */
++      sring = (blkif_sring_t *)get_zeroed_page(GFP_KERNEL);
++      if (sring == NULL)
++              goto fail_nomem;
++
++      SetPageReserved(virt_to_page(sring));
++    
++      SHARED_RING_INIT(sring);
++      FRONT_RING_INIT(&info->ufe_ring, sring, PAGE_SIZE);
++      
++      filp->private_data = info;
++      info->vma = NULL;
++
++      info->idx_map = kmalloc(sizeof(unsigned long) * MAX_PENDING_REQS, 
++                              GFP_KERNEL);
++      
++      if (info->idx_map == NULL)
++              goto fail_nomem;
++
++      if (idx > 0) {
++              init_waitqueue_head(&info->wait);
++              for (i = 0; i < MAX_PENDING_REQS; i++) 
++                      info->idx_map[i] = INVALID_REQ;
++      }
++
++      DPRINTK("Tap open: device /dev/xen/blktap%d\n",idx);
++      return 0;
++
++ fail_nomem:
++      return -ENOMEM;
++}
++
++static int blktap_release(struct inode *inode, struct file *filp)
++{
++      tap_blkif_t *info = filp->private_data;
++      
++      /* check for control device */
++      if (!info)
++              return 0;
++
++      info->dev_inuse = 0;
++      DPRINTK("Freeing device [/dev/xen/blktap%d]\n",info->minor);
++
++      /* Free the ring page. */
++      ClearPageReserved(virt_to_page(info->ufe_ring.sring));
++      free_page((unsigned long) info->ufe_ring.sring);
++
++      /* Clear any active mappings and free foreign map table */
++      if (info->vma) {
++              zap_page_range(
++                      info->vma, info->vma->vm_start, 
++                      info->vma->vm_end - info->vma->vm_start, NULL);
++
++              kfree(info->vma->vm_private_data);
++
++              info->vma = NULL;
++      }
++
++      if (info->idx_map) {
++              kfree(info->idx_map);
++              info->idx_map = NULL;
++      }
++
++      if ( (info->status != CLEANSHUTDOWN) && (info->blkif != NULL) ) {
++              if (info->blkif->xenblkd != NULL) {
++                      kthread_stop(info->blkif->xenblkd);
++                      info->blkif->xenblkd = NULL;
++              }
++              info->status = CLEANSHUTDOWN;
++      }
++
++      return 0;
++}
++
++
++/* Note on mmap:
++ * We need to map pages to user space in a way that will allow the block
++ * subsystem set up direct IO to them.  This couldn't be done before, because
++ * there isn't really a sane way to translate a user virtual address down to a 
++ * physical address when the page belongs to another domain.
++ *
++ * My first approach was to map the page in to kernel memory, add an entry
++ * for it in the physical frame list (using alloc_lomem_region as in blkback)
++ * and then attempt to map that page up to user space.  This is disallowed
++ * by xen though, which realizes that we don't really own the machine frame
++ * underlying the physical page.
++ *
++ * The new approach is to provide explicit support for this in xen linux.
++ * The VMA now has a flag, VM_FOREIGN, to indicate that it contains pages
++ * mapped from other vms.  vma->vm_private_data is set up as a mapping 
++ * from pages to actual page structs.  There is a new clause in get_user_pages
++ * that does the right thing for this sort of mapping.
++ */
++static int blktap_mmap(struct file *filp, struct vm_area_struct *vma)
++{
++      int size;
++      struct page **map;
++      int i;
++      tap_blkif_t *info = filp->private_data;
++      int ret;
++
++      if (info == NULL) {
++              WPRINTK("blktap: mmap, retrieving idx failed\n");
++              return -ENOMEM;
++      }
++      
++      vma->vm_flags |= VM_RESERVED;
++      vma->vm_ops = &blktap_vm_ops;
++
++      size = vma->vm_end - vma->vm_start;
++      if (size != ((mmap_pages + RING_PAGES) << PAGE_SHIFT)) {
++              WPRINTK("you _must_ map exactly %d pages!\n",
++                     mmap_pages + RING_PAGES);
++              return -EAGAIN;
++      }
++
++      size >>= PAGE_SHIFT;
++      info->rings_vstart = vma->vm_start;
++      info->user_vstart  = info->rings_vstart + (RING_PAGES << PAGE_SHIFT);
++    
++      /* Map the ring pages to the start of the region and reserve it. */
++      if (xen_feature(XENFEAT_auto_translated_physmap))
++              ret = vm_insert_page(vma, vma->vm_start,
++                                   virt_to_page(info->ufe_ring.sring));
++      else
++              ret = remap_pfn_range(vma, vma->vm_start,
++                                    __pa(info->ufe_ring.sring) >> PAGE_SHIFT,
++                                    PAGE_SIZE, vma->vm_page_prot);
++      if (ret) {
++              WPRINTK("Mapping user ring failed!\n");
++              goto fail;
++      }
++
++      /* Mark this VM as containing foreign pages, and set up mappings. */
++      map = kzalloc(((vma->vm_end - vma->vm_start) >> PAGE_SHIFT)
++                    * sizeof(struct page *),
++                    GFP_KERNEL);
++      if (map == NULL) {
++              WPRINTK("Couldn't alloc VM_FOREIGN map.\n");
++              goto fail;
++      }
++
++      for (i = 0; i < ((vma->vm_end - vma->vm_start) >> PAGE_SHIFT); i++)
++              map[i] = NULL;
++    
++      vma->vm_private_data = map;
++      vma->vm_flags |= VM_FOREIGN;
++      vma->vm_flags |= VM_DONTCOPY;
++
++#ifdef CONFIG_X86
++      vma->vm_mm->context.has_foreign_mappings = 1;
++#endif
++
++      info->vma = vma;
++      info->ring_ok = 1;
++      return 0;
++ fail:
++      /* Clear any active mappings. */
++      zap_page_range(vma, vma->vm_start, 
++                     vma->vm_end - vma->vm_start, NULL);
++
++      return -ENOMEM;
++}
++
++
++static int blktap_ioctl(struct inode *inode, struct file *filp,
++                        unsigned int cmd, unsigned long arg)
++{
++      tap_blkif_t *info = filp->private_data;
++
++      switch(cmd) {
++      case BLKTAP_IOCTL_KICK_FE: 
++      {
++              /* There are fe messages to process. */
++              return blktap_read_ufe_ring(info);
++      }
++      case BLKTAP_IOCTL_SETMODE:
++      {
++              if (info) {
++                      if (BLKTAP_MODE_VALID(arg)) {
++                              info->mode = arg;
++                              /* XXX: may need to flush rings here. */
++                              DPRINTK("blktap: set mode to %lx\n", 
++                                     arg);
++                              return 0;
++                      }
++              }
++              return 0;
++      }
++      case BLKTAP_IOCTL_PRINT_IDXS:
++        {
++              if (info) {
++                      printk("User Rings: \n-----------\n");
++                      printk("UF: rsp_cons: %2d, req_prod_prv: %2d "
++                              "| req_prod: %2d, rsp_prod: %2d\n",
++                              info->ufe_ring.rsp_cons,
++                              info->ufe_ring.req_prod_pvt,
++                              info->ufe_ring.sring->req_prod,
++                              info->ufe_ring.sring->rsp_prod);
++              }
++              return 0;
++        }
++      case BLKTAP_IOCTL_SENDPID:
++      {
++              if (info) {
++                      info->pid = (pid_t)arg;
++                      DPRINTK("blktap: pid received %d\n", 
++                             info->pid);
++              }
++              return 0;
++      }
++      case BLKTAP_IOCTL_NEWINTF:
++      {               
++              uint64_t val = (uint64_t)arg;
++              domid_translate_t *tr = (domid_translate_t *)&val;
++
++              DPRINTK("NEWINTF Req for domid %d and bus id %d\n", 
++                     tr->domid, tr->busid);
++              info = get_next_free_dev();
++              if (!info) {
++                      WPRINTK("Error initialising /dev/xen/blktap - "
++                              "No more devices\n");
++                      return -1;
++              }
++              info->trans.domid = tr->domid;
++              info->trans.busid = tr->busid;
++              return info->minor;
++      }
++      case BLKTAP_IOCTL_FREEINTF:
++      {
++              unsigned long dev = arg;
++              unsigned long flags;
++
++              info = tapfds[dev];
++
++              if ((dev > MAX_TAP_DEV) || !info)
++                      return 0; /* should this be an error? */
++
++              spin_lock_irqsave(&pending_free_lock, flags);
++              if (info->dev_pending)
++                      info->dev_pending = 0;
++              spin_unlock_irqrestore(&pending_free_lock, flags);
++
++              return 0;
++      }
++      case BLKTAP_IOCTL_MINOR:
++      {
++              unsigned long dev = arg;
++
++              info = tapfds[dev];
++
++              if ((dev > MAX_TAP_DEV) || !info)
++                      return -EINVAL;
++
++              return info->minor;
++      }
++      case BLKTAP_IOCTL_MAJOR:
++              return blktap_major;
++
++      case BLKTAP_QUERY_ALLOC_REQS:
++      {
++              WPRINTK("BLKTAP_QUERY_ALLOC_REQS ioctl: %d/%d\n",
++                     alloc_pending_reqs, blkif_reqs);
++              return (alloc_pending_reqs/blkif_reqs) * 100;
++      }
++      }
++      return -ENOIOCTLCMD;
++}
++
++static unsigned int blktap_poll(struct file *filp, poll_table *wait)
++{
++      tap_blkif_t *info = filp->private_data;
++      
++      /* do not work on the control device */
++      if (!info)
++              return 0;
++
++      poll_wait(filp, &info->wait, wait);
++      if (info->ufe_ring.req_prod_pvt != info->ufe_ring.sring->req_prod) {
++              RING_PUSH_REQUESTS(&info->ufe_ring);
++              return POLLIN | POLLRDNORM;
++      }
++      return 0;
++}
++
++void blktap_kick_user(int idx)
++{
++      tap_blkif_t *info;
++
++      info = tapfds[idx];
++
++      if ((idx < 0) || (idx > MAX_TAP_DEV) || !info)
++              return;
++
++      wake_up_interruptible(&info->wait);
++
++      return;
++}
++
++static int do_block_io_op(blkif_t *blkif);
++static void dispatch_rw_block_io(blkif_t *blkif,
++                               blkif_request_t *req,
++                               pending_req_t *pending_req);
++static void make_response(blkif_t *blkif, u64 id,
++                          unsigned short op, int st);
++
++/******************************************************************
++ * misc small helpers
++ */
++static int req_increase(void)
++{
++      int i, j;
++
++      if (mmap_alloc >= MAX_PENDING_REQS || mmap_lock) 
++              return -EINVAL;
++
++      pending_reqs[mmap_alloc]  = kzalloc(sizeof(pending_req_t)
++                                          * blkif_reqs, GFP_KERNEL);
++      foreign_pages[mmap_alloc] = alloc_empty_pages_and_pagevec(mmap_pages);
++
++      if (!pending_reqs[mmap_alloc] || !foreign_pages[mmap_alloc])
++              goto out_of_memory;
++
++      DPRINTK("%s: reqs=%d, pages=%d\n",
++              __FUNCTION__, blkif_reqs, mmap_pages);
++
++      for (i = 0; i < MAX_PENDING_REQS; i++) {
++              list_add_tail(&pending_reqs[mmap_alloc][i].free_list, 
++                            &pending_free);
++              pending_reqs[mmap_alloc][i].mem_idx = mmap_alloc;
++              for (j = 0; j < BLKIF_MAX_SEGMENTS_PER_REQUEST; j++)
++                      BLKTAP_INVALIDATE_HANDLE(&pending_handle(mmap_alloc, 
++                                                               i, j));
++      }
++
++      mmap_alloc++;
++      DPRINTK("# MMAPs increased to %d\n",mmap_alloc);
++      return 0;
++
++ out_of_memory:
++      free_empty_pages_and_pagevec(foreign_pages[mmap_alloc], mmap_pages);
++      kfree(pending_reqs[mmap_alloc]);
++      WPRINTK("%s: out of memory\n", __FUNCTION__);
++      return -ENOMEM;
++}
++
++static void mmap_req_del(int mmap)
++{
++      BUG_ON(!spin_is_locked(&pending_free_lock));
++
++      kfree(pending_reqs[mmap]);
++      pending_reqs[mmap] = NULL;
++
++      free_empty_pages_and_pagevec(foreign_pages[mmap_alloc], mmap_pages);
++      foreign_pages[mmap] = NULL;
++
++      mmap_lock = 0;
++      DPRINTK("# MMAPs decreased to %d\n",mmap_alloc);
++      mmap_alloc--;
++}
++
++static pending_req_t* alloc_req(void)
++{
++      pending_req_t *req = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&pending_free_lock, flags);
++
++      if (!list_empty(&pending_free)) {
++              req = list_entry(pending_free.next, pending_req_t, free_list);
++              list_del(&req->free_list);
++      }
++
++      if (req) {
++              req->inuse = 1;
++              alloc_pending_reqs++;
++      }
++      spin_unlock_irqrestore(&pending_free_lock, flags);
++
++      return req;
++}
++
++static void free_req(pending_req_t *req)
++{
++      unsigned long flags;
++      int was_empty;
++
++      spin_lock_irqsave(&pending_free_lock, flags);
++
++      alloc_pending_reqs--;
++      req->inuse = 0;
++      if (mmap_lock && (req->mem_idx == mmap_alloc-1)) {
++              mmap_inuse--;
++              if (mmap_inuse == 0) mmap_req_del(mmap_alloc-1);
++              spin_unlock_irqrestore(&pending_free_lock, flags);
++              return;
++      }
++      was_empty = list_empty(&pending_free);
++      list_add(&req->free_list, &pending_free);
++
++      spin_unlock_irqrestore(&pending_free_lock, flags);
++
++      if (was_empty)
++              wake_up(&pending_free_wq);
++}
++
++static void fast_flush_area(pending_req_t *req, int k_idx, int u_idx,
++                          int tapidx)
++{
++      struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
++      unsigned int i, invcount = 0;
++      struct grant_handle_pair *khandle;
++      uint64_t ptep;
++      int ret, mmap_idx;
++      unsigned long kvaddr, uvaddr;
++      tap_blkif_t *info;
++      
++
++      info = tapfds[tapidx];
++
++      if ((tapidx < 0) || (tapidx > MAX_TAP_DEV) || !info) {
++              WPRINTK("fast_flush: Couldn't get info!\n");
++              return;
++      }
++
++      if (info->vma != NULL &&
++          xen_feature(XENFEAT_auto_translated_physmap)) {
++              down_write(&info->vma->vm_mm->mmap_sem);
++              zap_page_range(info->vma, 
++                             MMAP_VADDR(info->user_vstart, u_idx, 0), 
++                             req->nr_pages << PAGE_SHIFT, NULL);
++              up_write(&info->vma->vm_mm->mmap_sem);
++              return;
++      }
++
++      mmap_idx = req->mem_idx;
++
++      for (i = 0; i < req->nr_pages; i++) {
++              kvaddr = idx_to_kaddr(mmap_idx, k_idx, i);
++              uvaddr = MMAP_VADDR(info->user_vstart, u_idx, i);
++
++              khandle = &pending_handle(mmap_idx, k_idx, i);
++
++              if (khandle->kernel != INVALID_GRANT_HANDLE) {
++                      gnttab_set_unmap_op(&unmap[invcount],
++                                          idx_to_kaddr(mmap_idx, k_idx, i),
++                                          GNTMAP_host_map, khandle->kernel);
++                      invcount++;
++
++                      set_phys_to_machine(
++                              __pa(idx_to_kaddr(mmap_idx, k_idx, i))
++                              >> PAGE_SHIFT, INVALID_P2M_ENTRY);
++              }
++
++              if (khandle->user != INVALID_GRANT_HANDLE) {
++                      BUG_ON(xen_feature(XENFEAT_auto_translated_physmap));
++                      if (create_lookup_pte_addr(
++                              info->vma->vm_mm,
++                              MMAP_VADDR(info->user_vstart, u_idx, i),
++                              &ptep) !=0) {
++                              WPRINTK("Couldn't get a pte addr!\n");
++                              return;
++                      }
++
++                      gnttab_set_unmap_op(&unmap[invcount], ptep,
++                                          GNTMAP_host_map
++                                          | GNTMAP_application_map
++                                          | GNTMAP_contains_pte,
++                                          khandle->user);
++                      invcount++;
++              }
++
++              BLKTAP_INVALIDATE_HANDLE(khandle);
++      }
++      ret = HYPERVISOR_grant_table_op(
++              GNTTABOP_unmap_grant_ref, unmap, invcount);
++      BUG_ON(ret);
++      
++      if (info->vma != NULL && !xen_feature(XENFEAT_auto_translated_physmap))
++              zap_page_range(info->vma, 
++                             MMAP_VADDR(info->user_vstart, u_idx, 0), 
++                             req->nr_pages << PAGE_SHIFT, NULL);
++}
++
++/******************************************************************
++ * SCHEDULER FUNCTIONS
++ */
++
++static void print_stats(blkif_t *blkif)
++{
++      printk(KERN_DEBUG "%s: oo %3d  |  rd %4d  |  wr %4d\n",
++             current->comm, blkif->st_oo_req,
++             blkif->st_rd_req, blkif->st_wr_req);
++      blkif->st_print = jiffies + msecs_to_jiffies(10 * 1000);
++      blkif->st_rd_req = 0;
++      blkif->st_wr_req = 0;
++      blkif->st_oo_req = 0;
++}
++
++int tap_blkif_schedule(void *arg)
++{
++      blkif_t *blkif = arg;
++
++      blkif_get(blkif);
++
++      if (debug_lvl)
++              printk(KERN_DEBUG "%s: started\n", current->comm);
++
++      while (!kthread_should_stop()) {
++              if (try_to_freeze())
++                      continue;
++
++              wait_event_interruptible(
++                      blkif->wq,
++                      blkif->waiting_reqs || kthread_should_stop());
++              wait_event_interruptible(
++                      pending_free_wq,
++                      !list_empty(&pending_free) || kthread_should_stop());
++
++              blkif->waiting_reqs = 0;
++              smp_mb(); /* clear flag *before* checking for work */
++
++              if (do_block_io_op(blkif))
++                      blkif->waiting_reqs = 1;
++
++              if (log_stats && time_after(jiffies, blkif->st_print))
++                      print_stats(blkif);
++      }
++
++      if (log_stats)
++              print_stats(blkif);
++      if (debug_lvl)
++              printk(KERN_DEBUG "%s: exiting\n", current->comm);
++
++      blkif->xenblkd = NULL;
++      blkif_put(blkif);
++
++      return 0;
++}
++
++/******************************************************************
++ * COMPLETION CALLBACK -- Called by user level ioctl()
++ */
++
++static int blktap_read_ufe_ring(tap_blkif_t *info)
++{
++      /* This is called to read responses from the UFE ring. */
++      RING_IDX i, j, rp;
++      blkif_response_t *resp;
++      blkif_t *blkif=NULL;
++      int pending_idx, usr_idx, mmap_idx;
++      pending_req_t *pending_req;
++      
++      if (!info)
++              return 0;
++
++      /* We currently only forward packets in INTERCEPT_FE mode. */
++      if (!(info->mode & BLKTAP_MODE_INTERCEPT_FE))
++              return 0;
++
++      /* for each outstanding message on the UFEring  */
++      rp = info->ufe_ring.sring->rsp_prod;
++      rmb();
++        
++      for (i = info->ufe_ring.rsp_cons; i != rp; i++) {
++              blkif_response_t res;
++              resp = RING_GET_RESPONSE(&info->ufe_ring, i);
++              memcpy(&res, resp, sizeof(res));
++              mb(); /* rsp_cons read by RING_FULL() in do_block_io_op(). */
++              ++info->ufe_ring.rsp_cons;
++
++              /*retrieve [usr_idx] to [mmap_idx,pending_idx] mapping*/
++              usr_idx = (int)res.id;
++              pending_idx = MASK_PEND_IDX(ID_TO_IDX(info->idx_map[usr_idx]));
++              mmap_idx = ID_TO_MIDX(info->idx_map[usr_idx]);
++
++              if ( (mmap_idx >= mmap_alloc) || 
++                 (ID_TO_IDX(info->idx_map[usr_idx]) >= MAX_PENDING_REQS) )
++                      WPRINTK("Incorrect req map"
++                             "[%d], internal map [%d,%d (%d)]\n", 
++                             usr_idx, mmap_idx, 
++                             ID_TO_IDX(info->idx_map[usr_idx]),
++                             MASK_PEND_IDX(
++                                     ID_TO_IDX(info->idx_map[usr_idx])));
++
++              pending_req = &pending_reqs[mmap_idx][pending_idx];
++              blkif = pending_req->blkif;
++
++              for (j = 0; j < pending_req->nr_pages; j++) {
++
++                      unsigned long kvaddr, uvaddr;
++                      struct page **map = info->vma->vm_private_data;
++                      struct page *pg;
++                      int offset;
++
++                      uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, j);
++                      kvaddr = idx_to_kaddr(mmap_idx, pending_idx, j);
++
++                      pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
++                      ClearPageReserved(pg);
++                      offset = (uvaddr - info->vma->vm_start) 
++                              >> PAGE_SHIFT;
++                      map[offset] = NULL;
++              }
++              fast_flush_area(pending_req, pending_idx, usr_idx, info->minor);
++              info->idx_map[usr_idx] = INVALID_REQ;
++              make_response(blkif, pending_req->id, res.operation,
++                            res.status);
++              blkif_put(pending_req->blkif);
++              free_req(pending_req);
++      }
++              
++      return 0;
++}
++
++
++/******************************************************************************
++ * NOTIFICATION FROM GUEST OS.
++ */
++
++static void blkif_notify_work(blkif_t *blkif)
++{
++      blkif->waiting_reqs = 1;
++      wake_up(&blkif->wq);
++}
++
++irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++      blkif_notify_work(dev_id);
++      return IRQ_HANDLED;
++}
++
++
++
++/******************************************************************
++ * DOWNWARD CALLS -- These interface with the block-device layer proper.
++ */
++static int print_dbug = 1;
++static int do_block_io_op(blkif_t *blkif)
++{
++      blkif_back_rings_t *blk_rings = &blkif->blk_rings;
++      blkif_request_t req;
++      pending_req_t *pending_req;
++      RING_IDX rc, rp;
++      int more_to_do = 0;
++      tap_blkif_t *info;
++
++      rc = blk_rings->common.req_cons;
++      rp = blk_rings->common.sring->req_prod;
++      rmb(); /* Ensure we see queued requests up to 'rp'. */
++
++      /*Check blkif has corresponding UE ring*/
++      if (blkif->dev_num < 0) {
++              /*oops*/
++              if (print_dbug) {
++                      WPRINTK("Corresponding UE " 
++                             "ring does not exist!\n");
++                      print_dbug = 0; /*We only print this message once*/
++              }
++              return 0;
++      }
++
++      info = tapfds[blkif->dev_num];
++
++      if (blkif->dev_num > MAX_TAP_DEV || !info || !info->dev_inuse) {
++              if (print_dbug) {
++                      WPRINTK("Can't get UE info!\n");
++                      print_dbug = 0;
++              }
++              return 0;
++      }
++
++      while (rc != rp) {
++              
++              if (RING_FULL(&info->ufe_ring)) {
++                      WPRINTK("RING_FULL! More to do\n");
++                      more_to_do = 1;
++                      break;
++              }
++
++              if (RING_REQUEST_CONS_OVERFLOW(&blk_rings->common, rc)) {
++                      WPRINTK("RING_REQUEST_CONS_OVERFLOW!"
++                             " More to do\n");
++                      more_to_do = 1;
++                      break;          
++              }
++
++              pending_req = alloc_req();
++              if (NULL == pending_req) {
++                      blkif->st_oo_req++;
++                      more_to_do = 1;
++                      break;
++              }
++
++              if (kthread_should_stop()) {
++                      more_to_do = 1;
++                      break;
++              }
++
++              switch (blkif->blk_protocol) {
++              case BLKIF_PROTOCOL_NATIVE:
++                      memcpy(&req, RING_GET_REQUEST(&blk_rings->native, rc),
++                             sizeof(req));
++                      break;
++              case BLKIF_PROTOCOL_X86_32:
++                      blkif_get_x86_32_req(&req, RING_GET_REQUEST(&blk_rings->x86_32, rc));
++                      break;
++              case BLKIF_PROTOCOL_X86_64:
++                      blkif_get_x86_64_req(&req, RING_GET_REQUEST(&blk_rings->x86_64, rc));
++                      break;
++              default:
++                      BUG();
++              }
++              blk_rings->common.req_cons = ++rc; /* before make_response() */
++
++              /* Apply all sanity checks to /private copy/ of request. */
++              barrier();
++
++              switch (req.operation) {
++              case BLKIF_OP_READ:
++                      blkif->st_rd_req++;
++                      dispatch_rw_block_io(blkif, &req, pending_req);
++                      break;
++
++              case BLKIF_OP_WRITE:
++                      blkif->st_wr_req++;
++                      dispatch_rw_block_io(blkif, &req, pending_req);
++                      break;
++
++              default:
++                      /* A good sign something is wrong: sleep for a while to
++                       * avoid excessive CPU consumption by a bad guest. */
++                      msleep(1);
++                      WPRINTK("unknown operation [%d]\n",
++                              req.operation);
++                      make_response(blkif, req.id, req.operation,
++                                    BLKIF_RSP_ERROR);
++                      free_req(pending_req);
++                      break;
++              }
++
++              /* Yield point for this unbounded loop. */
++              cond_resched();
++      }
++              
++      blktap_kick_user(blkif->dev_num);
++
++      return more_to_do;
++}
++
++static void dispatch_rw_block_io(blkif_t *blkif,
++                               blkif_request_t *req,
++                               pending_req_t *pending_req)
++{
++      extern void ll_rw_block(int rw, int nr, struct buffer_head * bhs[]);
++      int op, operation = (req->operation == BLKIF_OP_WRITE) ? WRITE : READ;
++      struct gnttab_map_grant_ref map[BLKIF_MAX_SEGMENTS_PER_REQUEST*2];
++      unsigned int nseg;
++      int ret, i, nr_sects = 0;
++      tap_blkif_t *info;
++      blkif_request_t *target;
++      int pending_idx = RTN_PEND_IDX(pending_req,pending_req->mem_idx);
++      int usr_idx;
++      uint16_t mmap_idx = pending_req->mem_idx;
++
++      if (blkif->dev_num < 0 || blkif->dev_num > MAX_TAP_DEV)
++              goto fail_response;
++
++      info = tapfds[blkif->dev_num];
++      if (info == NULL)
++              goto fail_response;
++
++      /* Check we have space on user ring - should never fail. */
++      usr_idx = GET_NEXT_REQ(info->idx_map);
++      if (usr_idx == INVALID_REQ) {
++              BUG();
++              goto fail_response;
++      }
++
++      /* Check that number of segments is sane. */
++      nseg = req->nr_segments;
++      if ( unlikely(nseg == 0) || 
++          unlikely(nseg > BLKIF_MAX_SEGMENTS_PER_REQUEST) ) {
++              WPRINTK("Bad number of segments in request (%d)\n", nseg);
++              goto fail_response;
++      }
++      
++      /* Make sure userspace is ready. */
++      if (!info->ring_ok) {
++              WPRINTK("blktap: ring not ready for requests!\n");
++              goto fail_response;
++      }
++
++      if (RING_FULL(&info->ufe_ring)) {
++              WPRINTK("blktap: fe_ring is full, can't add "
++                      "IO Request will be dropped. %d %d\n",
++                      RING_SIZE(&info->ufe_ring),
++                      RING_SIZE(&blkif->blk_rings.common));
++              goto fail_response;
++      }
++
++      pending_req->blkif     = blkif;
++      pending_req->id        = req->id;
++      pending_req->operation = operation;
++      pending_req->status    = BLKIF_RSP_OKAY;
++      pending_req->nr_pages  = nseg;
++      op = 0;
++      for (i = 0; i < nseg; i++) {
++              unsigned long uvaddr;
++              unsigned long kvaddr;
++              uint64_t ptep;
++              uint32_t flags;
++
++              uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i);
++              kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i);
++
++              flags = GNTMAP_host_map;
++              if (operation == WRITE)
++                      flags |= GNTMAP_readonly;
++              gnttab_set_map_op(&map[op], kvaddr, flags,
++                                req->seg[i].gref, blkif->domid);
++              op++;
++
++              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++                      /* Now map it to user. */
++                      ret = create_lookup_pte_addr(info->vma->vm_mm, 
++                                                   uvaddr, &ptep);
++                      if (ret) {
++                              WPRINTK("Couldn't get a pte addr!\n");
++                              goto fail_flush;
++                      }
++
++                      flags = GNTMAP_host_map | GNTMAP_application_map
++                              | GNTMAP_contains_pte;
++                      if (operation == WRITE)
++                              flags |= GNTMAP_readonly;
++                      gnttab_set_map_op(&map[op], ptep, flags,
++                                        req->seg[i].gref, blkif->domid);
++                      op++;
++              }
++
++              nr_sects += (req->seg[i].last_sect - 
++                           req->seg[i].first_sect + 1);
++      }
++
++      ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map, op);
++      BUG_ON(ret);
++
++      if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++              for (i = 0; i < (nseg*2); i+=2) {
++                      unsigned long uvaddr;
++                      unsigned long kvaddr;
++                      unsigned long offset;
++                      struct page *pg;
++
++                      uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i/2);
++                      kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i/2);
++
++                      if (unlikely(map[i].status != 0)) {
++                              WPRINTK("invalid kernel buffer -- "
++                                      "could not remap it\n");
++                              ret |= 1;
++                              map[i].handle = INVALID_GRANT_HANDLE;
++                      }
++
++                      if (unlikely(map[i+1].status != 0)) {
++                              WPRINTK("invalid user buffer -- "
++                                      "could not remap it\n");
++                              ret |= 1;
++                              map[i+1].handle = INVALID_GRANT_HANDLE;
++                      }
++
++                      pending_handle(mmap_idx, pending_idx, i/2).kernel 
++                              = map[i].handle;
++                      pending_handle(mmap_idx, pending_idx, i/2).user   
++                              = map[i+1].handle;
++
++                      if (ret)
++                              continue;
++
++                      set_phys_to_machine(__pa(kvaddr) >> PAGE_SHIFT,
++                                          FOREIGN_FRAME(map[i].dev_bus_addr
++                                                        >> PAGE_SHIFT));
++                      offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT;
++                      pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
++                      ((struct page **)info->vma->vm_private_data)[offset] =
++                              pg;
++              }
++      } else {
++              for (i = 0; i < nseg; i++) {
++                      unsigned long uvaddr;
++                      unsigned long kvaddr;
++                      unsigned long offset;
++                      struct page *pg;
++
++                      uvaddr = MMAP_VADDR(info->user_vstart, usr_idx, i);
++                      kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i);
++
++                      if (unlikely(map[i].status != 0)) {
++                              WPRINTK("invalid kernel buffer -- "
++                                      "could not remap it\n");
++                              ret |= 1;
++                              map[i].handle = INVALID_GRANT_HANDLE;
++                      }
++
++                      pending_handle(mmap_idx, pending_idx, i).kernel 
++                              = map[i].handle;
++
++                      if (ret)
++                              continue;
++
++                      offset = (uvaddr - info->vma->vm_start) >> PAGE_SHIFT;
++                      pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
++                      ((struct page **)info->vma->vm_private_data)[offset] =
++                              pg;
++              }
++      }
++
++      if (ret)
++              goto fail_flush;
++
++      if (xen_feature(XENFEAT_auto_translated_physmap))
++              down_write(&info->vma->vm_mm->mmap_sem);
++      /* Mark mapped pages as reserved: */
++      for (i = 0; i < req->nr_segments; i++) {
++              unsigned long kvaddr;
++              struct page *pg;
++
++              kvaddr = idx_to_kaddr(mmap_idx, pending_idx, i);
++              pg = pfn_to_page(__pa(kvaddr) >> PAGE_SHIFT);
++              SetPageReserved(pg);
++              if (xen_feature(XENFEAT_auto_translated_physmap)) {
++                      ret = vm_insert_page(info->vma,
++                                           MMAP_VADDR(info->user_vstart,
++                                                      usr_idx, i), pg);
++                      if (ret) {
++                              up_write(&info->vma->vm_mm->mmap_sem);
++                              goto fail_flush;
++                      }
++              }
++      }
++      if (xen_feature(XENFEAT_auto_translated_physmap))
++              up_write(&info->vma->vm_mm->mmap_sem);
++      
++      /*record [mmap_idx,pending_idx] to [usr_idx] mapping*/
++      info->idx_map[usr_idx] = MAKE_ID(mmap_idx, pending_idx);
++
++      blkif_get(blkif);
++      /* Finally, write the request message to the user ring. */
++      target = RING_GET_REQUEST(&info->ufe_ring,
++                                info->ufe_ring.req_prod_pvt);
++      memcpy(target, req, sizeof(*req));
++      target->id = usr_idx;
++      wmb(); /* blktap_poll() reads req_prod_pvt asynchronously */
++      info->ufe_ring.req_prod_pvt++;
++
++      if (operation == READ)
++              blkif->st_rd_sect += nr_sects;
++      else if (operation == WRITE)
++              blkif->st_wr_sect += nr_sects;
++
++      return;
++
++ fail_flush:
++      WPRINTK("Reached Fail_flush\n");
++      fast_flush_area(pending_req, pending_idx, usr_idx, blkif->dev_num);
++ fail_response:
++      make_response(blkif, req->id, req->operation, BLKIF_RSP_ERROR);
++      free_req(pending_req);
++      msleep(1); /* back off a bit */
++}
++
++
++
++/******************************************************************
++ * MISCELLANEOUS SETUP / TEARDOWN / DEBUGGING
++ */
++
++
++static void make_response(blkif_t *blkif, u64 id,
++                          unsigned short op, int st)
++{
++      blkif_response_t  resp;
++      unsigned long     flags;
++      blkif_back_rings_t *blk_rings = &blkif->blk_rings;
++      int more_to_do = 0;
++      int notify;
++
++      resp.id        = id;
++      resp.operation = op;
++      resp.status    = st;
++
++      spin_lock_irqsave(&blkif->blk_ring_lock, flags);
++      /* Place on the response ring for the relevant domain. */
++      switch (blkif->blk_protocol) {
++      case BLKIF_PROTOCOL_NATIVE:
++              memcpy(RING_GET_RESPONSE(&blk_rings->native,
++                                       blk_rings->native.rsp_prod_pvt),
++                     &resp, sizeof(resp));
++              break;
++      case BLKIF_PROTOCOL_X86_32:
++              memcpy(RING_GET_RESPONSE(&blk_rings->x86_32,
++                                       blk_rings->x86_32.rsp_prod_pvt),
++                     &resp, sizeof(resp));
++              break;
++      case BLKIF_PROTOCOL_X86_64:
++              memcpy(RING_GET_RESPONSE(&blk_rings->x86_64,
++                                       blk_rings->x86_64.rsp_prod_pvt),
++                     &resp, sizeof(resp));
++              break;
++      default:
++              BUG();
++      }
++      blk_rings->common.rsp_prod_pvt++;
++      RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&blk_rings->common, notify);
++
++      if (blk_rings->common.rsp_prod_pvt == blk_rings->common.req_cons) {
++              /*
++               * Tail check for pending requests. Allows frontend to avoid
++               * notifications if requests are already in flight (lower
++               * overheads and promotes batching).
++               */
++              RING_FINAL_CHECK_FOR_REQUESTS(&blk_rings->common, more_to_do);
++      } else if (RING_HAS_UNCONSUMED_REQUESTS(&blk_rings->common)) {
++              more_to_do = 1;
++      }
++
++      spin_unlock_irqrestore(&blkif->blk_ring_lock, flags);
++      if (more_to_do)
++              blkif_notify_work(blkif);
++      if (notify)
++              notify_remote_via_irq(blkif->irq);
++}
++
++static int __init blkif_init(void)
++{
++      int i, ret;
++      struct class *class;
++
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      INIT_LIST_HEAD(&pending_free);
++        for(i = 0; i < 2; i++) {
++              ret = req_increase();
++              if (ret)
++                      break;
++      }
++      if (i == 0)
++              return ret;
++
++      tap_blkif_interface_init();
++
++      alloc_pending_reqs = 0;
++
++      tap_blkif_xenbus_init();
++
++      /* Dynamically allocate a major for this device */
++      ret = register_chrdev(0, "blktap", &blktap_fops);
++
++      if (ret < 0) {
++              WPRINTK("Couldn't register /dev/xen/blktap\n");
++              return -ENOMEM;
++      }       
++      
++      blktap_major = ret;
++
++      /* tapfds[0] is always NULL */
++      blktap_next_minor++;
++
++      DPRINTK("Created misc_dev [/dev/xen/blktap%d]\n",i);
++
++      /* Make sure the xen class exists */
++      if ((class = get_xen_class()) != NULL) {
++              /*
++               * This will allow udev to create the blktap ctrl device.
++               * We only want to create blktap0 first.  We don't want
++               * to flood the sysfs system with needless blktap devices.
++               * We only create the device when a request of a new device is
++               * made.
++               */
++              class_device_create(class, NULL,
++                                  MKDEV(blktap_major, 0), NULL,
++                                  "blktap0");
++      } else {
++              /* this is bad, but not fatal */
++              WPRINTK("blktap: sysfs xen_class not created\n");
++      }
++
++      DPRINTK("Blktap device successfully created\n");
++
++      return 0;
++}
++
++module_init(blkif_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
+--- linux-2.6.18.8/drivers/xen/blktap/common.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blktap/common.h    2008-05-19 00:33:45.714781173 +0300
+@@ -0,0 +1,121 @@
++/* 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef __BLKIF__BACKEND__COMMON_H__
++#define __BLKIF__BACKEND__COMMON_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/blkdev.h>
++#include <linux/vmalloc.h>
++#include <asm/io.h>
++#include <asm/setup.h>
++#include <asm/pgalloc.h>
++#include <xen/evtchn.h>
++#include <asm/hypervisor.h>
++#include <xen/blkif.h>
++#include <xen/gnttab.h>
++#include <xen/driver_util.h>
++
++#define DPRINTK(_f, _a...) pr_debug("(file=%s, line=%d) " _f, \
++                                    __FILE__ , __LINE__ , ## _a )
++
++#define WPRINTK(fmt, args...) printk(KERN_WARNING "blk_tap: " fmt, ##args)
++
++struct backend_info;
++
++typedef struct blkif_st {
++      /* Unique identifier for this interface. */
++      domid_t           domid;
++      unsigned int      handle;
++      /* Physical parameters of the comms window. */
++      unsigned int      irq;
++      /* Comms information. */
++      enum blkif_protocol blk_protocol;
++      blkif_back_rings_t blk_rings;
++      struct vm_struct *blk_ring_area;
++      /* Back pointer to the backend_info. */
++      struct backend_info *be;
++      /* Private fields. */
++      spinlock_t       blk_ring_lock;
++      atomic_t         refcnt;
++
++      wait_queue_head_t   wq;
++      struct task_struct  *xenblkd;
++      unsigned int        waiting_reqs;
++      request_queue_t     *plug;
++
++      /* statistics */
++      unsigned long       st_print;
++      int                 st_rd_req;
++      int                 st_wr_req;
++      int                 st_oo_req;
++      int                 st_rd_sect;
++      int                 st_wr_sect;
++
++      wait_queue_head_t waiting_to_free;
++
++      grant_handle_t shmem_handle;
++      grant_ref_t    shmem_ref;
++      
++      int             dev_num;
++      uint64_t        sectors;
++} blkif_t;
++
++blkif_t *tap_alloc_blkif(domid_t domid);
++void tap_blkif_free(blkif_t *blkif);
++int tap_blkif_map(blkif_t *blkif, unsigned long shared_page, 
++                unsigned int evtchn);
++void tap_blkif_unmap(blkif_t *blkif);
++
++#define blkif_get(_b) (atomic_inc(&(_b)->refcnt))
++#define blkif_put(_b)                                 \
++      do {                                            \
++              if (atomic_dec_and_test(&(_b)->refcnt)) \
++                      wake_up(&(_b)->waiting_to_free);\
++      } while (0)
++
++
++struct phys_req {
++      unsigned short       dev;
++      unsigned short       nr_sects;
++      struct block_device *bdev;
++      blkif_sector_t       sector_number;
++};
++
++void tap_blkif_interface_init(void);
++
++void tap_blkif_xenbus_init(void);
++
++irqreturn_t tap_blkif_be_int(int irq, void *dev_id, struct pt_regs *regs);
++int tap_blkif_schedule(void *arg);
++
++int dom_to_devid(domid_t domid, int xenbus_id, blkif_t *blkif);
++void signal_tapdisk(int idx);
++
++#endif /* __BLKIF__BACKEND__COMMON_H__ */
+--- linux-2.6.18.8/drivers/xen/blktap/interface.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blktap/interface.c 2008-05-19 00:33:45.714781173 +0300
+@@ -0,0 +1,174 @@
++/******************************************************************************
++ * drivers/xen/blktap/interface.c
++ * 
++ * Block-device interface management.
++ * 
++ * Copyright (c) 2004, Keir Fraser
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++
++ */
++
++#include "common.h"
++#include <xen/evtchn.h>
++
++static kmem_cache_t *blkif_cachep;
++
++blkif_t *tap_alloc_blkif(domid_t domid)
++{
++      blkif_t *blkif;
++
++      blkif = kmem_cache_alloc(blkif_cachep, GFP_KERNEL);
++      if (!blkif)
++              return ERR_PTR(-ENOMEM);
++
++      memset(blkif, 0, sizeof(*blkif));
++      blkif->domid = domid;
++      spin_lock_init(&blkif->blk_ring_lock);
++      atomic_set(&blkif->refcnt, 1);
++      init_waitqueue_head(&blkif->wq);
++      blkif->st_print = jiffies;
++      init_waitqueue_head(&blkif->waiting_to_free);
++
++      return blkif;
++}
++
++static int map_frontend_page(blkif_t *blkif, unsigned long shared_page)
++{
++      struct gnttab_map_grant_ref op;
++
++      gnttab_set_map_op(&op, (unsigned long)blkif->blk_ring_area->addr,
++                        GNTMAP_host_map, shared_page, blkif->domid);
++
++      if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
++              BUG();
++
++      if (op.status) {
++              DPRINTK(" Grant table operation failure !\n");
++              return op.status;
++      }
++
++      blkif->shmem_ref = shared_page;
++      blkif->shmem_handle = op.handle;
++
++      return 0;
++}
++
++static void unmap_frontend_page(blkif_t *blkif)
++{
++      struct gnttab_unmap_grant_ref op;
++
++      gnttab_set_unmap_op(&op, (unsigned long)blkif->blk_ring_area->addr,
++                          GNTMAP_host_map, blkif->shmem_handle);
++
++      if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
++              BUG();
++}
++
++int tap_blkif_map(blkif_t *blkif, unsigned long shared_page, 
++                unsigned int evtchn)
++{
++      int err;
++
++      /* Already connected through? */
++      if (blkif->irq)
++              return 0;
++
++      if ( (blkif->blk_ring_area = alloc_vm_area(PAGE_SIZE)) == NULL )
++              return -ENOMEM;
++
++      err = map_frontend_page(blkif, shared_page);
++      if (err) {
++              free_vm_area(blkif->blk_ring_area);
++              return err;
++      }
++
++      switch (blkif->blk_protocol) {
++      case BLKIF_PROTOCOL_NATIVE:
++      {
++              blkif_sring_t *sring;
++              sring = (blkif_sring_t *)blkif->blk_ring_area->addr;
++              BACK_RING_INIT(&blkif->blk_rings.native, sring, PAGE_SIZE);
++              break;
++      }
++      case BLKIF_PROTOCOL_X86_32:
++      {
++              blkif_x86_32_sring_t *sring_x86_32;
++              sring_x86_32 = (blkif_x86_32_sring_t *)blkif->blk_ring_area->addr;
++              BACK_RING_INIT(&blkif->blk_rings.x86_32, sring_x86_32, PAGE_SIZE);
++              break;
++      }
++      case BLKIF_PROTOCOL_X86_64:
++      {
++              blkif_x86_64_sring_t *sring_x86_64;
++              sring_x86_64 = (blkif_x86_64_sring_t *)blkif->blk_ring_area->addr;
++              BACK_RING_INIT(&blkif->blk_rings.x86_64, sring_x86_64, PAGE_SIZE);
++              break;
++      }
++      default:
++              BUG();
++      }
++
++      err = bind_interdomain_evtchn_to_irqhandler(
++              blkif->domid, evtchn, tap_blkif_be_int,
++              0, "blkif-backend", blkif);
++      if (err < 0) {
++              unmap_frontend_page(blkif);
++              free_vm_area(blkif->blk_ring_area);
++              blkif->blk_rings.common.sring = NULL;
++              return err;
++      }
++      blkif->irq = err;
++
++      return 0;
++}
++
++void tap_blkif_unmap(blkif_t *blkif)
++{
++      if (blkif->irq) {
++              unbind_from_irqhandler(blkif->irq, blkif);
++              blkif->irq = 0;
++      }
++      if (blkif->blk_rings.common.sring) {
++              unmap_frontend_page(blkif);
++              free_vm_area(blkif->blk_ring_area);
++              blkif->blk_rings.common.sring = NULL;
++      }
++}
++
++void tap_blkif_free(blkif_t *blkif)
++{
++      atomic_dec(&blkif->refcnt);
++      wait_event(blkif->waiting_to_free, atomic_read(&blkif->refcnt) == 0);
++
++      tap_blkif_unmap(blkif);
++      kmem_cache_free(blkif_cachep, blkif);
++}
++
++void __init tap_blkif_interface_init(void)
++{
++      blkif_cachep = kmem_cache_create("blktapif_cache", sizeof(blkif_t), 
++                                       0, 0, NULL, NULL);
++}
+--- linux-2.6.18.8/drivers/xen/blktap/xenbus.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/blktap/xenbus.c    2008-05-19 00:33:45.714781173 +0300
+@@ -0,0 +1,477 @@
++/* drivers/xen/blktap/xenbus.c
++ *
++ * Xenbus code for blktap
++ *
++ * Copyright (c) 2004-2005, Andrew Warfield and Julian Chesterfield
++ *
++ * Based on the blkback xenbus code:
++ *
++ * Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
++ * Copyright (C) 2005 XenSource Ltd
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <stdarg.h>
++#include <linux/module.h>
++#include <linux/kthread.h>
++#include <xen/xenbus.h>
++#include "common.h"
++
++
++struct backend_info
++{
++      struct xenbus_device *dev;
++      blkif_t *blkif;
++      struct xenbus_watch backend_watch;
++      int xenbus_id;
++      int group_added;
++};
++
++
++static void connect(struct backend_info *);
++static int connect_ring(struct backend_info *);
++static int blktap_remove(struct xenbus_device *dev);
++static int blktap_probe(struct xenbus_device *dev,
++                       const struct xenbus_device_id *id);
++static void tap_backend_changed(struct xenbus_watch *, const char **,
++                          unsigned int);
++static void tap_frontend_changed(struct xenbus_device *dev,
++                           enum xenbus_state frontend_state);
++
++static int strsep_len(const char *str, char c, unsigned int len)
++{
++        unsigned int i;
++
++        for (i = 0; str[i]; i++)
++                if (str[i] == c) {
++                        if (len == 0)
++                                return i;
++                        len--;
++                }
++        return (len == 0) ? i : -ERANGE;
++}
++
++static long get_id(const char *str)
++{
++        int len,end;
++        const char *ptr;
++        char *tptr, num[10];
++      
++        len = strsep_len(str, '/', 2);
++        end = strlen(str);
++        if ( (len < 0) || (end < 0) ) return -1;
++      
++        ptr = str + len + 1;
++        strncpy(num,ptr,end - len);
++        tptr = num + (end - (len + 1));
++        *tptr = '\0';
++      DPRINTK("Get_id called for %s (%s)\n",str,num);
++      
++        return simple_strtol(num, NULL, 10);
++}                             
++
++static int blktap_name(blkif_t *blkif, char *buf)
++{
++      char *devpath, *devname;
++      struct xenbus_device *dev = blkif->be->dev;
++
++      devpath = xenbus_read(XBT_NIL, dev->nodename, "dev", NULL);
++      if (IS_ERR(devpath)) 
++              return PTR_ERR(devpath);
++      
++      if ((devname = strstr(devpath, "/dev/")) != NULL)
++              devname += strlen("/dev/");
++      else
++              devname  = devpath;
++
++      snprintf(buf, TASK_COMM_LEN, "blktap.%d.%s", blkif->domid, devname);
++      kfree(devpath);
++      
++      return 0;
++}
++
++/****************************************************************
++ *  sysfs interface for I/O requests of blktap device
++ */
++
++#define VBD_SHOW(name, format, args...)                                       \
++      static ssize_t show_##name(struct device *_dev,                 \
++                                 struct device_attribute *attr,       \
++                                 char *buf)                           \
++      {                                                               \
++              struct xenbus_device *dev = to_xenbus_device(_dev);     \
++              struct backend_info *be = dev->dev.driver_data;         \
++                                                                      \
++              return sprintf(buf, format, ##args);                    \
++      }                                                               \
++      static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL)
++
++VBD_SHOW(oo_req,  "%d\n", be->blkif->st_oo_req);
++VBD_SHOW(rd_req,  "%d\n", be->blkif->st_rd_req);
++VBD_SHOW(wr_req,  "%d\n", be->blkif->st_wr_req);
++VBD_SHOW(rd_sect, "%d\n", be->blkif->st_rd_sect);
++VBD_SHOW(wr_sect, "%d\n", be->blkif->st_wr_sect);
++
++static struct attribute *tapstat_attrs[] = {
++      &dev_attr_oo_req.attr,
++      &dev_attr_rd_req.attr,
++      &dev_attr_wr_req.attr,
++      &dev_attr_rd_sect.attr,
++      &dev_attr_wr_sect.attr,
++      NULL
++};
++
++static struct attribute_group tapstat_group = {
++      .name = "statistics",
++      .attrs = tapstat_attrs,
++};
++
++int xentap_sysfs_addif(struct xenbus_device *dev)
++{
++      int err;
++      struct backend_info *be = dev->dev.driver_data;
++      err = sysfs_create_group(&dev->dev.kobj, &tapstat_group);
++      if (!err)
++              be->group_added = 1;
++      return err;
++}
++
++void xentap_sysfs_delif(struct xenbus_device *dev)
++{
++      struct backend_info *be = dev->dev.driver_data;
++      sysfs_remove_group(&dev->dev.kobj, &tapstat_group);
++      be->group_added = 0;
++}
++
++static int blktap_remove(struct xenbus_device *dev)
++{
++      struct backend_info *be = dev->dev.driver_data;
++
++      if (be->group_added)
++              xentap_sysfs_delif(be->dev);
++      if (be->backend_watch.node) {
++              unregister_xenbus_watch(&be->backend_watch);
++              kfree(be->backend_watch.node);
++              be->backend_watch.node = NULL;
++      }
++      if (be->blkif) {
++              if (be->blkif->xenblkd)
++                      kthread_stop(be->blkif->xenblkd);
++              signal_tapdisk(be->blkif->dev_num);
++              tap_blkif_free(be->blkif);
++              be->blkif = NULL;
++      }
++      kfree(be);
++      dev->dev.driver_data = NULL;
++      return 0;
++}
++
++static void tap_update_blkif_status(blkif_t *blkif)
++{ 
++      int err;
++      char name[TASK_COMM_LEN];
++
++      /* Not ready to connect? */
++      if(!blkif->irq || !blkif->sectors) {
++              return;
++      } 
++
++      /* Already connected? */
++      if (blkif->be->dev->state == XenbusStateConnected)
++              return;
++
++      /* Attempt to connect: exit if we fail to. */
++      connect(blkif->be);
++      if (blkif->be->dev->state != XenbusStateConnected)
++              return;
++
++      err = blktap_name(blkif, name);
++      if (err) {
++              xenbus_dev_error(blkif->be->dev, err, "get blktap dev name");
++              return;
++      }
++
++      if (!blkif->be->group_added) {
++              err = xentap_sysfs_addif(blkif->be->dev);
++              if (err) {
++                      xenbus_dev_fatal(blkif->be->dev, err, 
++                                       "creating sysfs entries");
++                      return;
++              }
++      }
++
++      blkif->xenblkd = kthread_run(tap_blkif_schedule, blkif, name);
++      if (IS_ERR(blkif->xenblkd)) {
++              err = PTR_ERR(blkif->xenblkd);
++              blkif->xenblkd = NULL;
++              xenbus_dev_fatal(blkif->be->dev, err, "start xenblkd");
++              WPRINTK("Error starting thread\n");
++      }
++}
++
++/**
++ * Entry point to this code when a new device is created.  Allocate
++ * the basic structures, and watch the store waiting for the
++ * user-space program to tell us the physical device info.  Switch to
++ * InitWait.
++ */
++static int blktap_probe(struct xenbus_device *dev,
++                       const struct xenbus_device_id *id)
++{
++      int err;
++      struct backend_info *be = kzalloc(sizeof(struct backend_info),
++                                        GFP_KERNEL);
++      if (!be) {
++              xenbus_dev_fatal(dev, -ENOMEM,
++                               "allocating backend structure");
++              return -ENOMEM;
++      }
++
++      be->dev = dev;
++      dev->dev.driver_data = be;
++      be->xenbus_id = get_id(dev->nodename);
++
++      be->blkif = tap_alloc_blkif(dev->otherend_id);
++      if (IS_ERR(be->blkif)) {
++              err = PTR_ERR(be->blkif);
++              be->blkif = NULL;
++              xenbus_dev_fatal(dev, err, "creating block interface");
++              goto fail;
++      }
++
++      /* setup back pointer */
++      be->blkif->be = be;
++      be->blkif->sectors = 0;
++
++      /* set a watch on disk info, waiting for userspace to update details*/
++      err = xenbus_watch_path2(dev, dev->nodename, "info",
++                               &be->backend_watch, tap_backend_changed);
++      if (err)
++              goto fail;
++      
++      err = xenbus_switch_state(dev, XenbusStateInitWait);
++      if (err)
++              goto fail;
++      return 0;
++
++fail:
++      DPRINTK("blktap probe failed\n");
++      blktap_remove(dev);
++      return err;
++}
++
++
++/**
++ * Callback received when the user space code has placed the device
++ * information in xenstore. 
++ */
++static void tap_backend_changed(struct xenbus_watch *watch,
++                          const char **vec, unsigned int len)
++{
++      int err;
++      unsigned long info;
++      struct backend_info *be
++              = container_of(watch, struct backend_info, backend_watch);
++      struct xenbus_device *dev = be->dev;
++      
++      /** 
++       * Check to see whether userspace code has opened the image 
++       * and written sector
++       * and disk info to xenstore
++       */
++      err = xenbus_gather(XBT_NIL, dev->nodename, "info", "%lu", &info, 
++                          NULL);
++      if (XENBUS_EXIST_ERR(err))
++              return;
++      if (err) {
++              xenbus_dev_error(dev, err, "getting info");
++              return;
++      }
++
++      DPRINTK("Userspace update on disk info, %lu\n",info);
++
++      err = xenbus_gather(XBT_NIL, dev->nodename, "sectors", "%llu", 
++                          &be->blkif->sectors, NULL);
++
++      /* Associate tap dev with domid*/
++      be->blkif->dev_num = dom_to_devid(be->blkif->domid, be->xenbus_id, 
++                                        be->blkif);
++      DPRINTK("Thread started for domid [%d], connecting disk\n", 
++              be->blkif->dev_num);
++
++      tap_update_blkif_status(be->blkif);
++}
++
++/**
++ * Callback received when the frontend's state changes.
++ */
++static void tap_frontend_changed(struct xenbus_device *dev,
++                           enum xenbus_state frontend_state)
++{
++      struct backend_info *be = dev->dev.driver_data;
++      int err;
++
++      DPRINTK("\n");
++
++      switch (frontend_state) {
++      case XenbusStateInitialising:
++              if (dev->state == XenbusStateClosed) {
++                      printk(KERN_INFO "%s: %s: prepare for reconnect\n",
++                             __FUNCTION__, dev->nodename);
++                      xenbus_switch_state(dev, XenbusStateInitWait);
++              }
++              break;
++
++      case XenbusStateInitialised:
++      case XenbusStateConnected:
++              /* Ensure we connect even when two watches fire in 
++                 close successsion and we miss the intermediate value 
++                 of frontend_state. */
++              if (dev->state == XenbusStateConnected)
++                      break;
++
++              err = connect_ring(be);
++              if (err)
++                      break;
++              tap_update_blkif_status(be->blkif);
++              break;
++
++      case XenbusStateClosing:
++              if (be->blkif->xenblkd) {
++                      kthread_stop(be->blkif->xenblkd);
++                      be->blkif->xenblkd = NULL;
++              }
++              xenbus_switch_state(dev, XenbusStateClosing);
++              break;
++
++      case XenbusStateClosed:
++              xenbus_switch_state(dev, XenbusStateClosed);
++              if (xenbus_dev_is_online(dev))
++                      break;
++              /* fall through if not online */
++      case XenbusStateUnknown:
++              device_unregister(&dev->dev);
++              break;
++
++      default:
++              xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
++                               frontend_state);
++              break;
++      }
++}
++
++
++/**
++ * Switch to Connected state.
++ */
++static void connect(struct backend_info *be)
++{
++      int err;
++
++      struct xenbus_device *dev = be->dev;
++
++      err = xenbus_switch_state(dev, XenbusStateConnected);
++      if (err)
++              xenbus_dev_fatal(dev, err, "switching to Connected state",
++                               dev->nodename);
++
++      return;
++}
++
++
++static int connect_ring(struct backend_info *be)
++{
++      struct xenbus_device *dev = be->dev;
++      unsigned long ring_ref;
++      unsigned int evtchn;
++      char protocol[64];
++      int err;
++
++      DPRINTK("%s\n", dev->otherend);
++
++      err = xenbus_gather(XBT_NIL, dev->otherend, "ring-ref", "%lu", 
++                          &ring_ref, "event-channel", "%u", &evtchn, NULL);
++      if (err) {
++              xenbus_dev_fatal(dev, err,
++                               "reading %s/ring-ref and event-channel",
++                               dev->otherend);
++              return err;
++      }
++
++      be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
++      err = xenbus_gather(XBT_NIL, dev->otherend, "protocol",
++                          "%63s", protocol, NULL);
++      if (err)
++              strcpy(protocol, "unspecified, assuming native");
++      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE))
++              be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
++      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
++              be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_32;
++      else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_64))
++              be->blkif->blk_protocol = BLKIF_PROTOCOL_X86_64;
++      else {
++              xenbus_dev_fatal(dev, err, "unknown fe protocol %s", protocol);
++              return -1;
++      }
++      printk(KERN_INFO
++             "blktap: ring-ref %ld, event-channel %d, protocol %d (%s)\n",
++             ring_ref, evtchn, be->blkif->blk_protocol, protocol);
++
++      /* Map the shared frame, irq etc. */
++      err = tap_blkif_map(be->blkif, ring_ref, evtchn);
++      if (err) {
++              xenbus_dev_fatal(dev, err, "mapping ring-ref %lu port %u",
++                               ring_ref, evtchn);
++              return err;
++      } 
++
++      return 0;
++}
++
++
++/* ** Driver Registration ** */
++
++
++static const struct xenbus_device_id blktap_ids[] = {
++      { "tap" },
++      { "" }
++};
++
++
++static struct xenbus_driver blktap = {
++      .name = "tap",
++      .owner = THIS_MODULE,
++      .ids = blktap_ids,
++      .probe = blktap_probe,
++      .remove = blktap_remove,
++      .otherend_changed = tap_frontend_changed
++};
++
++
++void tap_blkif_xenbus_init(void)
++{
++      xenbus_register_backend(&blktap);
++}
+--- linux-2.6.18.8/drivers/xen/char/Makefile   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/char/Makefile      2008-05-19 00:33:45.718781403 +0300
+@@ -0,0 +1 @@
++obj-$(CONFIG_XEN_DEVMEM)      := mem.o
+--- linux-2.6.18.8/drivers/xen/char/mem.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/char/mem.c 2008-05-19 00:33:45.718781403 +0300
+@@ -0,0 +1,190 @@
++/*
++ *  Originally from linux/drivers/char/mem.c
++ *
++ *  Copyright (C) 1991, 1992  Linus Torvalds
++ *
++ *  Added devfs support. 
++ *    Jan-11-1998, C. Scott Ananian <cananian@alumni.princeton.edu>
++ *  Shared /dev/zero mmaping support, Feb 2000, Kanoj Sarcar <kanoj@sgi.com>
++ */
++
++#include <linux/mm.h>
++#include <linux/miscdevice.h>
++#include <linux/slab.h>
++#include <linux/vmalloc.h>
++#include <linux/mman.h>
++#include <linux/random.h>
++#include <linux/init.h>
++#include <linux/raw.h>
++#include <linux/tty.h>
++#include <linux/capability.h>
++#include <linux/smp_lock.h>
++#include <linux/ptrace.h>
++#include <linux/device.h>
++#include <asm/pgalloc.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <asm/hypervisor.h>
++
++static inline int uncached_access(struct file *file)
++{
++      if (file->f_flags & O_SYNC)
++              return 1;
++      /* Xen sets correct MTRR type on non-RAM for us. */
++      return 0;
++}
++
++/*
++ * This funcion reads the *physical* memory. The f_pos points directly to the 
++ * memory location. 
++ */
++static ssize_t read_mem(struct file * file, char __user * buf,
++                      size_t count, loff_t *ppos)
++{
++      unsigned long p = *ppos, ignored;
++      ssize_t read = 0, sz;
++      void __iomem *v;
++
++      while (count > 0) {
++              /*
++               * Handle first page in case it's not aligned
++               */
++              if (-p & (PAGE_SIZE - 1))
++                      sz = -p & (PAGE_SIZE - 1);
++              else
++                      sz = PAGE_SIZE;
++
++              sz = min_t(unsigned long, sz, count);
++
++              v = ioremap(p, sz);
++              if (IS_ERR(v) || v == NULL) {
++                      /*
++                       * Some programs (e.g., dmidecode) groove off into
++                       * weird RAM areas where no tables can possibly exist
++                       * (because Xen will have stomped on them!). These
++                       * programs get rather upset if we let them know that
++                       * Xen failed their access, so we fake out a read of
++                       * all zeroes.
++                       */
++                      if (clear_user(buf, count))
++                              return -EFAULT;
++                      read += count;
++                      break;
++              }
++
++              ignored = copy_to_user(buf, v, sz);
++              iounmap(v);
++              if (ignored)
++                      return -EFAULT;
++              buf += sz;
++              p += sz;
++              count -= sz;
++              read += sz;
++      }
++
++      *ppos += read;
++      return read;
++}
++
++static ssize_t write_mem(struct file * file, const char __user * buf, 
++                       size_t count, loff_t *ppos)
++{
++      unsigned long p = *ppos, ignored;
++      ssize_t written = 0, sz;
++      void __iomem *v;
++
++      while (count > 0) {
++              /*
++               * Handle first page in case it's not aligned
++               */
++              if (-p & (PAGE_SIZE - 1))
++                      sz = -p & (PAGE_SIZE - 1);
++              else
++                      sz = PAGE_SIZE;
++
++              sz = min_t(unsigned long, sz, count);
++
++              v = ioremap(p, sz);
++              if (v == NULL)
++                      break;
++              if (IS_ERR(v)) {
++                      if (written == 0)
++                              return PTR_ERR(v);
++                      break;
++              }
++
++              ignored = copy_from_user(v, buf, sz);
++              iounmap(v);
++              if (ignored) {
++                      written += sz - ignored;
++                      if (written)
++                              break;
++                      return -EFAULT;
++              }
++              buf += sz;
++              p += sz;
++              count -= sz;
++              written += sz;
++      }
++
++      *ppos += written;
++      return written;
++}
++
++#ifndef ARCH_HAS_DEV_MEM_MMAP_MEM
++static int xen_mmap_mem(struct file * file, struct vm_area_struct * vma)
++{
++      size_t size = vma->vm_end - vma->vm_start;
++
++      if (uncached_access(file))
++              vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++
++      /* We want to return the real error code, not EAGAIN. */
++      return direct_remap_pfn_range(vma, vma->vm_start, vma->vm_pgoff,
++                                    size, vma->vm_page_prot, DOMID_IO);
++}
++#endif
++
++/*
++ * The memory devices use the full 32/64 bits of the offset, and so we cannot
++ * check against negative addresses: they are ok. The return value is weird,
++ * though, in that case (0).
++ *
++ * also note that seeking relative to the "end of file" isn't supported:
++ * it has no meaning, so it returns -EINVAL.
++ */
++static loff_t memory_lseek(struct file * file, loff_t offset, int orig)
++{
++      loff_t ret;
++
++      mutex_lock(&file->f_dentry->d_inode->i_mutex);
++      switch (orig) {
++              case 0:
++                      file->f_pos = offset;
++                      ret = file->f_pos;
++                      force_successful_syscall_return();
++                      break;
++              case 1:
++                      file->f_pos += offset;
++                      ret = file->f_pos;
++                      force_successful_syscall_return();
++                      break;
++              default:
++                      ret = -EINVAL;
++      }
++      mutex_unlock(&file->f_dentry->d_inode->i_mutex);
++      return ret;
++}
++
++static int open_mem(struct inode * inode, struct file * filp)
++{
++      return capable(CAP_SYS_RAWIO) ? 0 : -EPERM;
++}
++
++const struct file_operations mem_fops = {
++      .llseek         = memory_lseek,
++      .read           = read_mem,
++      .write          = write_mem,
++      .mmap           = xen_mmap_mem,
++      .open           = open_mem,
++};
+--- linux-2.6.18.8/drivers/xen/console/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/console/Makefile   2008-05-19 00:33:45.762783940 +0300
+@@ -0,0 +1,2 @@
++
++obj-y := console.o xencons_ring.o
+--- linux-2.6.18.8/drivers/xen/console/console.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/console/console.c  2008-05-19 00:33:45.762783940 +0300
+@@ -0,0 +1,731 @@
++/******************************************************************************
++ * console.c
++ * 
++ * Virtual console driver.
++ * 
++ * Copyright (c) 2002-2004, K A Fraser.
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial.h>
++#include <linux/major.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++#include <linux/init.h>
++#include <linux/console.h>
++#include <linux/bootmem.h>
++#include <linux/sysrq.h>
++#include <linux/screen_info.h>
++#include <linux/vt.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/uaccess.h>
++#include <xen/interface/xen.h>
++#include <xen/interface/event_channel.h>
++#include <asm/hypervisor.h>
++#include <xen/evtchn.h>
++#include <xen/xenbus.h>
++#include <xen/xencons.h>
++
++/*
++ * Modes:
++ *  'xencons=off'  [XC_OFF]:     Console is disabled.
++ *  'xencons=tty'  [XC_TTY]:     Console attached to '/dev/tty[0-9]+'.
++ *  'xencons=ttyS' [XC_SERIAL]:  Console attached to '/dev/ttyS[0-9]+'.
++ *  'xencons=xvc'  [XC_XVC]:     Console attached to '/dev/xvc0'.
++ *  default:                     XC_XVC
++ * 
++ * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
++ * warnings from standard distro startup scripts.
++ */
++static enum {
++      XC_OFF, XC_TTY, XC_SERIAL, XC_XVC
++} xc_mode = XC_XVC;
++static int xc_num = -1;
++
++/* /dev/xvc0 device number allocated by lanana.org. */
++#define XEN_XVC_MAJOR 204
++#define XEN_XVC_MINOR 191
++
++#ifdef CONFIG_MAGIC_SYSRQ
++static unsigned long sysrq_requested;
++extern int sysrq_enabled;
++#endif
++
++static int __init xencons_setup(char *str)
++{
++      char *q;
++      int n;
++      extern int console_use_vt;
++
++      console_use_vt = 1;
++      if (!strncmp(str, "ttyS", 4)) {
++              xc_mode = XC_SERIAL;
++              str += 4;
++      } else if (!strncmp(str, "tty", 3)) {
++              xc_mode = XC_TTY;
++              str += 3;
++              console_use_vt = 0;
++      } else if (!strncmp(str, "xvc", 3)) {
++              xc_mode = XC_XVC;
++              str += 3;
++      } else if (!strncmp(str, "off", 3)) {
++              xc_mode = XC_OFF;
++              str += 3;
++      }
++
++      n = simple_strtol(str, &q, 10);
++      if (q != str)
++              xc_num = n;
++
++      return 1;
++}
++__setup("xencons=", xencons_setup);
++
++/* The kernel and user-land drivers share a common transmit buffer. */
++static unsigned int wbuf_size = 4096;
++#define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
++static char *wbuf;
++static unsigned int wc, wp; /* write_cons, write_prod */
++
++static int __init xencons_bufsz_setup(char *str)
++{
++      unsigned int goal;
++      goal = simple_strtoul(str, NULL, 0);
++      if (goal) {
++              goal = roundup_pow_of_two(goal);
++              if (wbuf_size < goal)
++                      wbuf_size = goal;
++      }
++      return 1;
++}
++__setup("xencons_bufsz=", xencons_bufsz_setup);
++
++/* This lock protects accesses to the common transmit buffer. */
++static DEFINE_SPINLOCK(xencons_lock);
++
++/* Common transmit-kick routine. */
++static void __xencons_tx_flush(void);
++
++static struct tty_driver *xencons_driver;
++
++/******************** Kernel console driver ********************************/
++
++static void kcons_write(struct console *c, const char *s, unsigned int count)
++{
++      int           i = 0;
++      unsigned long flags;
++
++      spin_lock_irqsave(&xencons_lock, flags);
++
++      while (i < count) {
++              for (; i < count; i++) {
++                      if ((wp - wc) >= (wbuf_size - 1))
++                              break;
++                      if ((wbuf[WBUF_MASK(wp++)] = s[i]) == '\n')
++                              wbuf[WBUF_MASK(wp++)] = '\r';
++              }
++
++              __xencons_tx_flush();
++      }
++
++      spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static void kcons_write_dom0(struct console *c, const char *s, unsigned int count)
++{
++
++      while (count > 0) {
++              int rc;
++              rc = HYPERVISOR_console_io( CONSOLEIO_write, count, (char *)s);
++              if (rc <= 0)
++                      break;
++              count -= rc;
++              s += rc;
++      }
++}
++
++static struct tty_driver *kcons_device(struct console *c, int *index)
++{
++      *index = 0;
++      return xencons_driver;
++}
++
++static struct console kcons_info = {
++      .device = kcons_device,
++      .flags  = CON_PRINTBUFFER | CON_ENABLED,
++      .index  = -1,
++};
++
++static int __init xen_console_init(void)
++{
++      if (!is_running_on_xen())
++              goto out;
++
++      if (is_initial_xendomain()) {
++              kcons_info.write = kcons_write_dom0;
++      } else {
++              if (!xen_start_info->console.domU.evtchn)
++                      goto out;
++              kcons_info.write = kcons_write;
++      }
++
++      switch (xc_mode) {
++      case XC_XVC:
++              strcpy(kcons_info.name, "xvc");
++              if (xc_num == -1)
++                      xc_num = 0;
++              break;
++
++      case XC_SERIAL:
++              strcpy(kcons_info.name, "ttyS");
++              if (xc_num == -1)
++                      xc_num = 0;
++              break;
++
++      case XC_TTY:
++              strcpy(kcons_info.name, "tty");
++              if (xc_num == -1)
++                      xc_num = 1;
++              break;
++
++      default:
++              goto out;
++      }
++
++      wbuf = alloc_bootmem(wbuf_size);
++
++      register_console(&kcons_info);
++
++ out:
++      return 0;
++}
++console_initcall(xen_console_init);
++
++/*** Useful function for console debugging -- goes straight to Xen. ***/
++asmlinkage int xprintk(const char *fmt, ...)
++{
++      va_list args;
++      int printk_len;
++      static char printk_buf[1024];
++
++      /* Emit the output into the temporary buffer */
++      va_start(args, fmt);
++      printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
++      va_end(args);
++
++      /* Send the processed output directly to Xen. */
++      kcons_write_dom0(NULL, printk_buf, printk_len);
++
++      return 0;
++}
++
++/*** Forcibly flush console data before dying. ***/
++void xencons_force_flush(void)
++{
++      int sz;
++
++      /* Emergency console is synchronous, so there's nothing to flush. */
++      if (!is_running_on_xen() ||
++          is_initial_xendomain() ||
++          !xen_start_info->console.domU.evtchn)
++              return;
++
++      /* Spin until console data is flushed through to the daemon. */
++      while (wc != wp) {
++              int sent = 0;
++              if ((sz = wp - wc) == 0)
++                      continue;
++              sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
++              if (sent > 0)
++                      wc += sent;
++      }
++}
++
++
++void __init dom0_init_screen_info(const struct dom0_vga_console_info *info, size_t size)
++{
++      /* This is drawn from a dump from vgacon:startup in
++       * standard Linux. */
++      screen_info.orig_video_mode = 3;
++      screen_info.orig_video_isVGA = 1;
++      screen_info.orig_video_lines = 25;
++      screen_info.orig_video_cols = 80;
++      screen_info.orig_video_ega_bx = 3;
++      screen_info.orig_video_points = 16;
++      screen_info.orig_y = screen_info.orig_video_lines - 1;
++
++      switch (info->video_type) {
++      case XEN_VGATYPE_TEXT_MODE_3:
++              if (size < offsetof(struct dom0_vga_console_info, u.text_mode_3)
++                         + sizeof(info->u.text_mode_3))
++                      break;
++              screen_info.orig_video_lines = info->u.text_mode_3.rows;
++              screen_info.orig_video_cols = info->u.text_mode_3.columns;
++              screen_info.orig_x = info->u.text_mode_3.cursor_x;
++              screen_info.orig_y = info->u.text_mode_3.cursor_y;
++              screen_info.orig_video_points =
++                      info->u.text_mode_3.font_height;
++              break;
++
++      case XEN_VGATYPE_VESA_LFB:
++              if (size < offsetof(struct dom0_vga_console_info,
++                                  u.vesa_lfb.gbl_caps))
++                      break;
++              screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
++              screen_info.lfb_width = info->u.vesa_lfb.width;
++              screen_info.lfb_height = info->u.vesa_lfb.height;
++              screen_info.lfb_depth = info->u.vesa_lfb.bits_per_pixel;
++              screen_info.lfb_base = info->u.vesa_lfb.lfb_base;
++              screen_info.lfb_size = info->u.vesa_lfb.lfb_size;
++              screen_info.lfb_linelength = info->u.vesa_lfb.bytes_per_line;
++              screen_info.red_size = info->u.vesa_lfb.red_size;
++              screen_info.red_pos = info->u.vesa_lfb.red_pos;
++              screen_info.green_size = info->u.vesa_lfb.green_size;
++              screen_info.green_pos = info->u.vesa_lfb.green_pos;
++              screen_info.blue_size = info->u.vesa_lfb.blue_size;
++              screen_info.blue_pos = info->u.vesa_lfb.blue_pos;
++              screen_info.rsvd_size = info->u.vesa_lfb.rsvd_size;
++              screen_info.rsvd_pos = info->u.vesa_lfb.rsvd_pos;
++              if (size >= offsetof(struct dom0_vga_console_info,
++                                   u.vesa_lfb.gbl_caps)
++                          + sizeof(info->u.vesa_lfb.gbl_caps))
++                      screen_info.capabilities = info->u.vesa_lfb.gbl_caps;
++              if (size >= offsetof(struct dom0_vga_console_info,
++                                   u.vesa_lfb.mode_attrs)
++                          + sizeof(info->u.vesa_lfb.mode_attrs))
++                      screen_info.vesa_attributes = info->u.vesa_lfb.mode_attrs;
++              break;
++      }
++}
++
++
++/******************** User-space console driver (/dev/console) ************/
++
++#define DRV(_d)         (_d)
++#define DUMMY_TTY(_tty) ((xc_mode == XC_TTY) &&               \
++                       ((_tty)->index != (xc_num - 1)))
++
++static struct termios *xencons_termios[MAX_NR_CONSOLES];
++static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
++static struct tty_struct *xencons_tty;
++static int xencons_priv_irq;
++static char x_char;
++
++void xencons_rx(char *buf, unsigned len, struct pt_regs *regs)
++{
++      int           i;
++      unsigned long flags;
++
++      spin_lock_irqsave(&xencons_lock, flags);
++      if (xencons_tty == NULL)
++              goto out;
++
++      for (i = 0; i < len; i++) {
++#ifdef CONFIG_MAGIC_SYSRQ
++              if (sysrq_enabled) {
++                      if (buf[i] == '\x0f') { /* ^O */
++                              if (!sysrq_requested) {
++                                      sysrq_requested = jiffies;
++                                      continue; /* don't print sysrq key */
++                              }
++                              sysrq_requested = 0;
++                      } else if (sysrq_requested) {
++                              unsigned long sysrq_timeout =
++                                      sysrq_requested + HZ*2;
++                              sysrq_requested = 0;
++                              if (time_before(jiffies, sysrq_timeout)) {
++                                      spin_unlock_irqrestore(
++                                              &xencons_lock, flags);
++                                      handle_sysrq(
++                                              buf[i], regs, xencons_tty);
++                                      spin_lock_irqsave(
++                                              &xencons_lock, flags);
++                                      continue;
++                              }
++                      }
++              }
++#endif
++              tty_insert_flip_char(xencons_tty, buf[i], 0);
++      }
++      tty_flip_buffer_push(xencons_tty);
++
++ out:
++      spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static void __xencons_tx_flush(void)
++{
++      int sent, sz, work_done = 0;
++
++      if (x_char) {
++              if (is_initial_xendomain())
++                      kcons_write_dom0(NULL, &x_char, 1);
++              else
++                      while (x_char)
++                              if (xencons_ring_send(&x_char, 1) == 1)
++                                      break;
++              x_char = 0;
++              work_done = 1;
++      }
++
++      while (wc != wp) {
++              sz = wp - wc;
++              if (sz > (wbuf_size - WBUF_MASK(wc)))
++                      sz = wbuf_size - WBUF_MASK(wc);
++              if (is_initial_xendomain()) {
++                      kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
++                      wc += sz;
++              } else {
++                      sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
++                      if (sent == 0)
++                              break;
++                      wc += sent;
++              }
++              work_done = 1;
++      }
++
++      if (work_done && (xencons_tty != NULL)) {
++              wake_up_interruptible(&xencons_tty->write_wait);
++              if ((xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
++                  (xencons_tty->ldisc.write_wakeup != NULL))
++                      (xencons_tty->ldisc.write_wakeup)(xencons_tty);
++      }
++}
++
++void xencons_tx(void)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&xencons_lock, flags);
++      __xencons_tx_flush();
++      spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++/* Privileged receive callback and transmit kicker. */
++static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
++                                        struct pt_regs *regs)
++{
++      static char rbuf[16];
++      int         l;
++
++      while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0)
++              xencons_rx(rbuf, l, regs);
++
++      xencons_tx();
++
++      return IRQ_HANDLED;
++}
++
++static int xencons_write_room(struct tty_struct *tty)
++{
++      return wbuf_size - (wp - wc);
++}
++
++static int xencons_chars_in_buffer(struct tty_struct *tty)
++{
++      return wp - wc;
++}
++
++static void xencons_send_xchar(struct tty_struct *tty, char ch)
++{
++      unsigned long flags;
++
++      if (DUMMY_TTY(tty))
++              return;
++
++      spin_lock_irqsave(&xencons_lock, flags);
++      x_char = ch;
++      __xencons_tx_flush();
++      spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static void xencons_throttle(struct tty_struct *tty)
++{
++      if (DUMMY_TTY(tty))
++              return;
++
++      if (I_IXOFF(tty))
++              xencons_send_xchar(tty, STOP_CHAR(tty));
++}
++
++static void xencons_unthrottle(struct tty_struct *tty)
++{
++      if (DUMMY_TTY(tty))
++              return;
++
++      if (I_IXOFF(tty)) {
++              if (x_char != 0)
++                      x_char = 0;
++              else
++                      xencons_send_xchar(tty, START_CHAR(tty));
++      }
++}
++
++static void xencons_flush_buffer(struct tty_struct *tty)
++{
++      unsigned long flags;
++
++      if (DUMMY_TTY(tty))
++              return;
++
++      spin_lock_irqsave(&xencons_lock, flags);
++      wc = wp = 0;
++      spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static inline int __xencons_put_char(int ch)
++{
++      char _ch = (char)ch;
++      if ((wp - wc) == wbuf_size)
++              return 0;
++      wbuf[WBUF_MASK(wp++)] = _ch;
++      return 1;
++}
++
++static int xencons_write(
++      struct tty_struct *tty,
++      const unsigned char *buf,
++      int count)
++{
++      int i;
++      unsigned long flags;
++
++      if (DUMMY_TTY(tty))
++              return count;
++
++      spin_lock_irqsave(&xencons_lock, flags);
++
++      for (i = 0; i < count; i++)
++              if (!__xencons_put_char(buf[i]))
++                      break;
++
++      if (i != 0)
++              __xencons_tx_flush();
++
++      spin_unlock_irqrestore(&xencons_lock, flags);
++
++      return i;
++}
++
++static void xencons_put_char(struct tty_struct *tty, u_char ch)
++{
++      unsigned long flags;
++
++      if (DUMMY_TTY(tty))
++              return;
++
++      spin_lock_irqsave(&xencons_lock, flags);
++      (void)__xencons_put_char(ch);
++      spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static void xencons_flush_chars(struct tty_struct *tty)
++{
++      unsigned long flags;
++
++      if (DUMMY_TTY(tty))
++              return;
++
++      spin_lock_irqsave(&xencons_lock, flags);
++      __xencons_tx_flush();
++      spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
++{
++      unsigned long orig_jiffies = jiffies;
++
++      if (DUMMY_TTY(tty))
++              return;
++
++      while (DRV(tty->driver)->chars_in_buffer(tty)) {
++              set_current_state(TASK_INTERRUPTIBLE);
++              schedule_timeout(1);
++              if (signal_pending(current))
++                      break;
++              if (timeout && time_after(jiffies, orig_jiffies + timeout))
++                      break;
++      }
++
++      set_current_state(TASK_RUNNING);
++}
++
++static int xencons_open(struct tty_struct *tty, struct file *filp)
++{
++      unsigned long flags;
++
++      if (DUMMY_TTY(tty))
++              return 0;
++
++      spin_lock_irqsave(&xencons_lock, flags);
++      tty->driver_data = NULL;
++      if (xencons_tty == NULL)
++              xencons_tty = tty;
++      __xencons_tx_flush();
++      spin_unlock_irqrestore(&xencons_lock, flags);
++
++      return 0;
++}
++
++static void xencons_close(struct tty_struct *tty, struct file *filp)
++{
++      unsigned long flags;
++
++      if (DUMMY_TTY(tty))
++              return;
++
++      mutex_lock(&tty_mutex);
++
++      if (tty->count != 1) {
++              mutex_unlock(&tty_mutex);
++              return;
++      }
++
++      /* Prevent other threads from re-opening this tty. */
++      set_bit(TTY_CLOSING, &tty->flags);
++      mutex_unlock(&tty_mutex);
++
++      tty->closing = 1;
++      tty_wait_until_sent(tty, 0);
++      if (DRV(tty->driver)->flush_buffer != NULL)
++              DRV(tty->driver)->flush_buffer(tty);
++      if (tty->ldisc.flush_buffer != NULL)
++              tty->ldisc.flush_buffer(tty);
++      tty->closing = 0;
++      spin_lock_irqsave(&xencons_lock, flags);
++      xencons_tty = NULL;
++      spin_unlock_irqrestore(&xencons_lock, flags);
++}
++
++static struct tty_operations xencons_ops = {
++      .open = xencons_open,
++      .close = xencons_close,
++      .write = xencons_write,
++      .write_room = xencons_write_room,
++      .put_char = xencons_put_char,
++      .flush_chars = xencons_flush_chars,
++      .chars_in_buffer = xencons_chars_in_buffer,
++      .send_xchar = xencons_send_xchar,
++      .flush_buffer = xencons_flush_buffer,
++      .throttle = xencons_throttle,
++      .unthrottle = xencons_unthrottle,
++      .wait_until_sent = xencons_wait_until_sent,
++};
++
++static int __init xencons_init(void)
++{
++      int rc;
++
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      if (xc_mode == XC_OFF)
++              return 0;
++
++      if (!is_initial_xendomain()) {
++              rc = xencons_ring_init();
++              if (rc)
++                      return rc;
++      }
++
++      xencons_driver = alloc_tty_driver((xc_mode == XC_TTY) ?
++                                        MAX_NR_CONSOLES : 1);
++      if (xencons_driver == NULL)
++              return -ENOMEM;
++
++      DRV(xencons_driver)->name            = "xencons";
++      DRV(xencons_driver)->major           = TTY_MAJOR;
++      DRV(xencons_driver)->type            = TTY_DRIVER_TYPE_SERIAL;
++      DRV(xencons_driver)->subtype         = SERIAL_TYPE_NORMAL;
++      DRV(xencons_driver)->init_termios    = tty_std_termios;
++      DRV(xencons_driver)->flags           =
++              TTY_DRIVER_REAL_RAW |
++              TTY_DRIVER_RESET_TERMIOS;
++      DRV(xencons_driver)->termios         = xencons_termios;
++      DRV(xencons_driver)->termios_locked  = xencons_termios_locked;
++
++      switch (xc_mode) {
++      case XC_XVC:
++              DRV(xencons_driver)->name        = "xvc";
++              DRV(xencons_driver)->major       = XEN_XVC_MAJOR;
++              DRV(xencons_driver)->minor_start = XEN_XVC_MINOR;
++              DRV(xencons_driver)->name_base   = xc_num;
++              break;
++      case XC_SERIAL:
++              DRV(xencons_driver)->name        = "ttyS";
++              DRV(xencons_driver)->minor_start = 64 + xc_num;
++              DRV(xencons_driver)->name_base   = xc_num;
++              break;
++      default:
++              DRV(xencons_driver)->name        = "tty";
++              DRV(xencons_driver)->minor_start = 1;
++              DRV(xencons_driver)->name_base   = 1;
++              break;
++      }
++
++      tty_set_operations(xencons_driver, &xencons_ops);
++
++      if ((rc = tty_register_driver(DRV(xencons_driver))) != 0) {
++              printk("WARNING: Failed to register Xen virtual "
++                     "console driver as '%s%d'\n",
++                     DRV(xencons_driver)->name,
++                     DRV(xencons_driver)->name_base);
++              put_tty_driver(xencons_driver);
++              xencons_driver = NULL;
++              return rc;
++      }
++
++      if (is_initial_xendomain()) {
++              xencons_priv_irq = bind_virq_to_irqhandler(
++                      VIRQ_CONSOLE,
++                      0,
++                      xencons_priv_interrupt,
++                      0,
++                      "console",
++                      NULL);
++              BUG_ON(xencons_priv_irq < 0);
++      }
++
++      printk("Xen virtual console successfully installed as %s%d\n",
++             DRV(xencons_driver)->name, xc_num);
++
++      return 0;
++}
++
++module_init(xencons_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
+--- linux-2.6.18.8/drivers/xen/console/xencons_ring.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/console/xencons_ring.c     2008-05-19 00:33:45.766784170 +0300
+@@ -0,0 +1,143 @@
++/* 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/errno.h>
++#include <linux/signal.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/tty.h>
++#include <linux/tty_flip.h>
++#include <linux/serial.h>
++#include <linux/major.h>
++#include <linux/ptrace.h>
++#include <linux/ioport.h>
++#include <linux/mm.h>
++#include <linux/slab.h>
++
++#include <asm/hypervisor.h>
++#include <xen/evtchn.h>
++#include <xen/xencons.h>
++#include <linux/wait.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/err.h>
++#include <xen/interface/io/console.h>
++
++static int xencons_irq;
++
++static inline struct xencons_interface *xencons_interface(void)
++{
++      return mfn_to_virt(xen_start_info->console.domU.mfn);
++}
++
++static inline void notify_daemon(void)
++{
++      /* Use evtchn: this is called early, before irq is set up. */
++      notify_remote_via_evtchn(xen_start_info->console.domU.evtchn);
++}
++
++int xencons_ring_send(const char *data, unsigned len)
++{
++      int sent = 0;
++      struct xencons_interface *intf = xencons_interface();
++      XENCONS_RING_IDX cons, prod;
++
++      cons = intf->out_cons;
++      prod = intf->out_prod;
++      mb();
++      BUG_ON((prod - cons) > sizeof(intf->out));
++
++      while ((sent < len) && ((prod - cons) < sizeof(intf->out)))
++              intf->out[MASK_XENCONS_IDX(prod++, intf->out)] = data[sent++];
++
++      wmb();
++      intf->out_prod = prod;
++
++      notify_daemon();
++
++      return sent;
++}
++
++static irqreturn_t handle_input(int irq, void *unused, struct pt_regs *regs)
++{
++      struct xencons_interface *intf = xencons_interface();
++      XENCONS_RING_IDX cons, prod;
++
++      cons = intf->in_cons;
++      prod = intf->in_prod;
++      mb();
++      BUG_ON((prod - cons) > sizeof(intf->in));
++
++      while (cons != prod) {
++              xencons_rx(intf->in+MASK_XENCONS_IDX(cons,intf->in), 1, regs);
++              cons++;
++      }
++
++      mb();
++      intf->in_cons = cons;
++
++      notify_daemon();
++
++      xencons_tx();
++
++      return IRQ_HANDLED;
++}
++
++int xencons_ring_init(void)
++{
++      int irq;
++
++      if (xencons_irq)
++              unbind_from_irqhandler(xencons_irq, NULL);
++      xencons_irq = 0;
++
++      if (!is_running_on_xen() ||
++          is_initial_xendomain() ||
++          !xen_start_info->console.domU.evtchn)
++              return -ENODEV;
++
++      irq = bind_caller_port_to_irqhandler(
++              xen_start_info->console.domU.evtchn,
++              handle_input, 0, "xencons", NULL);
++      if (irq < 0) {
++              printk(KERN_ERR "XEN console request irq failed %i\n", irq);
++              return irq;
++      }
++
++      xencons_irq = irq;
++
++      /* In case we have in-flight data after save/restore... */
++      notify_daemon();
++
++      return 0;
++}
++
++void xencons_resume(void)
++{
++      (void)xencons_ring_init();
++}
+--- linux-2.6.18.8/drivers/xen/core/Makefile   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/Makefile      2008-05-19 00:33:45.766784170 +0300
+@@ -0,0 +1,13 @@
++#
++# Makefile for the linux kernel.
++#
++
++obj-y := evtchn.o gnttab.o features.o reboot.o machine_reboot.o firmware.o
++
++obj-$(CONFIG_PROC_FS)         += xen_proc.o
++obj-$(CONFIG_SYS_HYPERVISOR)  += hypervisor_sysfs.o
++obj-$(CONFIG_HOTPLUG_CPU)     += cpu_hotplug.o
++obj-$(CONFIG_XEN_SYSFS)               += xen_sysfs.o
++obj-$(CONFIG_XEN_SMPBOOT)     += smpboot.o
++obj-$(CONFIG_KEXEC)           += machine_kexec.o
++obj-$(CONFIG_XEN_XENCOMM)     += xencomm.o
+--- linux-2.6.18.8/drivers/xen/core/cpu_hotplug.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/cpu_hotplug.c 2008-05-19 00:33:45.766784170 +0300
+@@ -0,0 +1,173 @@
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/notifier.h>
++#include <linux/cpu.h>
++#include <xen/cpu_hotplug.h>
++#include <xen/xenbus.h>
++
++/*
++ * Set of CPUs that remote admin software will allow us to bring online.
++ * Notified to us via xenbus.
++ */
++static cpumask_t xenbus_allowed_cpumask;
++
++/* Set of CPUs that local admin will allow us to bring online. */
++static cpumask_t local_allowed_cpumask = CPU_MASK_ALL;
++
++static int local_cpu_hotplug_request(void)
++{
++      /*
++       * We assume a CPU hotplug request comes from local admin if it is made
++       * via a userspace process (i.e., one with a real mm_struct).
++       */
++      return (current->mm != NULL);
++}
++
++static void vcpu_hotplug(unsigned int cpu)
++{
++      int err;
++      char dir[32], state[32];
++
++      if ((cpu >= NR_CPUS) || !cpu_possible(cpu))
++              return;
++
++      sprintf(dir, "cpu/%u", cpu);
++      err = xenbus_scanf(XBT_NIL, dir, "availability", "%s", state);
++      if (err != 1) {
++              printk(KERN_ERR "XENBUS: Unable to read cpu state\n");
++              return;
++      }
++
++      if (strcmp(state, "online") == 0) {
++              cpu_set(cpu, xenbus_allowed_cpumask);
++              (void)cpu_up(cpu);
++      } else if (strcmp(state, "offline") == 0) {
++              cpu_clear(cpu, xenbus_allowed_cpumask);
++              (void)cpu_down(cpu);
++      } else {
++              printk(KERN_ERR "XENBUS: unknown state(%s) on CPU%d\n",
++                     state, cpu);
++      }
++}
++
++static void handle_vcpu_hotplug_event(
++      struct xenbus_watch *watch, const char **vec, unsigned int len)
++{
++      unsigned int cpu;
++      char *cpustr;
++      const char *node = vec[XS_WATCH_PATH];
++
++      if ((cpustr = strstr(node, "cpu/")) != NULL) {
++              sscanf(cpustr, "cpu/%u", &cpu);
++              vcpu_hotplug(cpu);
++      }
++}
++
++static int smpboot_cpu_notify(struct notifier_block *notifier,
++                            unsigned long action, void *hcpu)
++{
++      unsigned int cpu = (long)hcpu;
++
++      /*
++       * We do this in a callback notifier rather than __cpu_disable()
++       * because local_cpu_hotplug_request() does not work in the latter
++       * as it's always executed from within a stopmachine kthread.
++       */
++      if ((action == CPU_DOWN_PREPARE) && local_cpu_hotplug_request())
++              cpu_clear(cpu, local_allowed_cpumask);
++
++      return NOTIFY_OK;
++}
++
++static int setup_cpu_watcher(struct notifier_block *notifier,
++                            unsigned long event, void *data)
++{
++      unsigned int i;
++
++      static struct xenbus_watch cpu_watch = {
++              .node = "cpu",
++              .callback = handle_vcpu_hotplug_event,
++              .flags = XBWF_new_thread };
++      (void)register_xenbus_watch(&cpu_watch);
++
++      if (!is_initial_xendomain()) {
++              for_each_possible_cpu(i)
++                      vcpu_hotplug(i);
++              printk(KERN_INFO "Brought up %ld CPUs\n",
++                     (long)num_online_cpus());
++      }
++
++      return NOTIFY_DONE;
++}
++
++static int __init setup_vcpu_hotplug_event(void)
++{
++      static struct notifier_block hotplug_cpu = {
++              .notifier_call = smpboot_cpu_notify };
++      static struct notifier_block xsn_cpu = {
++              .notifier_call = setup_cpu_watcher };
++
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      register_cpu_notifier(&hotplug_cpu);
++      register_xenstore_notifier(&xsn_cpu);
++
++      return 0;
++}
++
++arch_initcall(setup_vcpu_hotplug_event);
++
++int smp_suspend(void)
++{
++      unsigned int cpu;
++      int err;
++
++      for_each_online_cpu(cpu) {
++              if (cpu == 0)
++                      continue;
++              err = cpu_down(cpu);
++              if (err) {
++                      printk(KERN_CRIT "Failed to take all CPUs "
++                             "down: %d.\n", err);
++                      for_each_possible_cpu(cpu)
++                              vcpu_hotplug(cpu);
++                      return err;
++              }
++      }
++
++      return 0;
++}
++
++void smp_resume(void)
++{
++      unsigned int cpu;
++
++      for_each_possible_cpu(cpu)
++              vcpu_hotplug(cpu);
++}
++
++int cpu_up_check(unsigned int cpu)
++{
++      int rc = 0;
++
++      if (local_cpu_hotplug_request()) {
++              cpu_set(cpu, local_allowed_cpumask);
++              if (!cpu_isset(cpu, xenbus_allowed_cpumask)) {
++                      printk("%s: attempt to bring up CPU %u disallowed by "
++                             "remote admin.\n", __FUNCTION__, cpu);
++                      rc = -EBUSY;
++              }
++      } else if (!cpu_isset(cpu, local_allowed_cpumask) ||
++                 !cpu_isset(cpu, xenbus_allowed_cpumask)) {
++              rc = -EBUSY;
++      }
++
++      return rc;
++}
++
++void init_xenbus_allowed_cpumask(void)
++{
++      xenbus_allowed_cpumask = cpu_present_map;
++}
+--- linux-2.6.18.8/drivers/xen/core/evtchn.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/evtchn.c      2008-05-19 00:33:45.770784401 +0300
+@@ -0,0 +1,1061 @@
++/******************************************************************************
++ * evtchn.c
++ * 
++ * Communication via Xen event channels.
++ * 
++ * Copyright (c) 2002-2005, K A Fraser
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/module.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/sched.h>
++#include <linux/kernel_stat.h>
++#include <linux/version.h>
++#include <asm/atomic.h>
++#include <asm/system.h>
++#include <asm/ptrace.h>
++#include <asm/synch_bitops.h>
++#include <xen/evtchn.h>
++#include <xen/interface/event_channel.h>
++#include <xen/interface/physdev.h>
++#include <asm/hypervisor.h>
++#include <linux/mc146818rtc.h> /* RTC_IRQ */
++
++/*
++ * This lock protects updates to the following mapping and reference-count
++ * arrays. The lock does not need to be acquired to read the mapping tables.
++ */
++static DEFINE_SPINLOCK(irq_mapping_update_lock);
++
++/* IRQ <-> event-channel mappings. */
++static int evtchn_to_irq[NR_EVENT_CHANNELS] = {
++      [0 ...  NR_EVENT_CHANNELS-1] = -1 };
++
++/* Packed IRQ information: binding type, sub-type index, and event channel. */
++static u32 irq_info[NR_IRQS];
++
++/* Binding types. */
++enum {
++      IRQT_UNBOUND,
++      IRQT_PIRQ,
++      IRQT_VIRQ,
++      IRQT_IPI,
++      IRQT_LOCAL_PORT,
++      IRQT_CALLER_PORT
++};
++
++/* Constructor for packed IRQ information. */
++static inline u32 mk_irq_info(u32 type, u32 index, u32 evtchn)
++{
++      return ((type << 24) | (index << 16) | evtchn);
++}
++
++/* Convenient shorthand for packed representation of an unbound IRQ. */
++#define IRQ_UNBOUND   mk_irq_info(IRQT_UNBOUND, 0, 0)
++
++/*
++ * Accessors for packed IRQ information.
++ */
++
++static inline unsigned int evtchn_from_irq(int irq)
++{
++      return (u16)(irq_info[irq]);
++}
++
++static inline unsigned int index_from_irq(int irq)
++{
++      return (u8)(irq_info[irq] >> 16);
++}
++
++static inline unsigned int type_from_irq(int irq)
++{
++      return (u8)(irq_info[irq] >> 24);
++}
++
++/* IRQ <-> VIRQ mapping. */
++DEFINE_PER_CPU(int, virq_to_irq[NR_VIRQS]) = {[0 ... NR_VIRQS-1] = -1};
++
++/* IRQ <-> IPI mapping. */
++#ifndef NR_IPIS
++#define NR_IPIS 1
++#endif
++DEFINE_PER_CPU(int, ipi_to_irq[NR_IPIS]) = {[0 ... NR_IPIS-1] = -1};
++
++/* Reference counts for bindings to IRQs. */
++static int irq_bindcount[NR_IRQS];
++
++/* Bitmap indicating which PIRQs require Xen to be notified on unmask. */
++static DECLARE_BITMAP(pirq_needs_eoi, NR_PIRQS);
++
++#ifdef CONFIG_SMP
++
++static u8 cpu_evtchn[NR_EVENT_CHANNELS];
++static unsigned long cpu_evtchn_mask[NR_CPUS][NR_EVENT_CHANNELS/BITS_PER_LONG];
++
++static inline unsigned long active_evtchns(unsigned int cpu, shared_info_t *sh,
++                                         unsigned int idx)
++{
++      return (sh->evtchn_pending[idx] &
++              cpu_evtchn_mask[cpu][idx] &
++              ~sh->evtchn_mask[idx]);
++}
++
++static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
++{
++      shared_info_t *s = HYPERVISOR_shared_info;
++      int irq = evtchn_to_irq[chn];
++
++      BUG_ON(!test_bit(chn, s->evtchn_mask));
++
++      if (irq != -1)
++              set_native_irq_info(irq, cpumask_of_cpu(cpu));
++
++      clear_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu_evtchn[chn]]);
++      set_bit(chn, (unsigned long *)cpu_evtchn_mask[cpu]);
++      cpu_evtchn[chn] = cpu;
++}
++
++static void init_evtchn_cpu_bindings(void)
++{
++      int i;
++
++      /* By default all event channels notify CPU#0. */
++      for (i = 0; i < NR_IRQS; i++)
++              set_native_irq_info(i, cpumask_of_cpu(0));
++
++      memset(cpu_evtchn, 0, sizeof(cpu_evtchn));
++      memset(cpu_evtchn_mask[0], ~0, sizeof(cpu_evtchn_mask[0]));
++}
++
++static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
++{
++      return cpu_evtchn[evtchn];
++}
++
++#else
++
++static inline unsigned long active_evtchns(unsigned int cpu, shared_info_t *sh,
++                                         unsigned int idx)
++{
++      return (sh->evtchn_pending[idx] & ~sh->evtchn_mask[idx]);
++}
++
++static void bind_evtchn_to_cpu(unsigned int chn, unsigned int cpu)
++{
++}
++
++static void init_evtchn_cpu_bindings(void)
++{
++}
++
++static inline unsigned int cpu_from_evtchn(unsigned int evtchn)
++{
++      return 0;
++}
++
++#endif
++
++/* Upcall to generic IRQ layer. */
++#ifdef CONFIG_X86
++extern fastcall unsigned int do_IRQ(struct pt_regs *regs);
++void __init xen_init_IRQ(void);
++void __init init_IRQ(void)
++{
++      irq_ctx_init(0);
++      xen_init_IRQ();
++}
++#if defined (__i386__)
++static inline void exit_idle(void) {}
++#define IRQ_REG orig_eax
++#elif defined (__x86_64__)
++#include <asm/idle.h>
++#define IRQ_REG orig_rax
++#endif
++#define do_IRQ(irq, regs) do {                \
++      (regs)->IRQ_REG = ~(irq);       \
++      do_IRQ((regs));                 \
++} while (0)
++#endif
++
++/* Xen will never allocate port zero for any purpose. */
++#define VALID_EVTCHN(chn)     ((chn) != 0)
++
++/*
++ * Force a proper event-channel callback from Xen after clearing the
++ * callback mask. We do this in a very simple manner, by making a call
++ * down into Xen. The pending flag will be checked by Xen on return.
++ */
++void force_evtchn_callback(void)
++{
++      VOID(HYPERVISOR_xen_version(0, NULL));
++}
++/* Not a GPL symbol: used in ubiquitous macros, so too restrictive. */
++EXPORT_SYMBOL(force_evtchn_callback);
++
++static DEFINE_PER_CPU(unsigned int, upcall_count) = { 0 };
++static DEFINE_PER_CPU(unsigned int, last_processed_l1i) = { BITS_PER_LONG - 1 };
++static DEFINE_PER_CPU(unsigned int, last_processed_l2i) = { BITS_PER_LONG - 1 };
++
++/* NB. Interrupts are disabled on entry. */
++asmlinkage void evtchn_do_upcall(struct pt_regs *regs)
++{
++      unsigned long       l1, l2;
++      unsigned long       masked_l1, masked_l2;
++      unsigned int        l1i, l2i, port, count;
++      int                 irq;
++      unsigned int        cpu = smp_processor_id();
++      shared_info_t      *s = HYPERVISOR_shared_info;
++      vcpu_info_t        *vcpu_info = &s->vcpu_info[cpu];
++
++
++      do {
++              /* Avoid a callback storm when we reenable delivery. */
++              vcpu_info->evtchn_upcall_pending = 0;
++
++              /* Nested invocations bail immediately. */
++              if (unlikely(per_cpu(upcall_count, cpu)++))
++                      return;
++
++#ifndef CONFIG_X86 /* No need for a barrier -- XCHG is a barrier on x86. */
++              /* Clear master flag /before/ clearing selector flag. */
++              wmb();
++#endif
++              l1 = xchg(&vcpu_info->evtchn_pending_sel, 0);
++
++              l1i = per_cpu(last_processed_l1i, cpu);
++              l2i = per_cpu(last_processed_l2i, cpu);
++
++              while (l1 != 0) {
++
++                      l1i = (l1i + 1) % BITS_PER_LONG;
++                      masked_l1 = l1 & ((~0UL) << l1i);
++
++                      if (masked_l1 == 0) { /* if we masked out all events, wrap around to the beginning */
++                              l1i = BITS_PER_LONG - 1;
++                              l2i = BITS_PER_LONG - 1;
++                              continue;
++                      }
++                      l1i = __ffs(masked_l1);
++
++                      do {
++                              l2 = active_evtchns(cpu, s, l1i);
++
++                              l2i = (l2i + 1) % BITS_PER_LONG;
++                              masked_l2 = l2 & ((~0UL) << l2i);
++
++                              if (masked_l2 == 0) { /* if we masked out all events, move on */
++                                      l2i = BITS_PER_LONG - 1;
++                                      break;
++                              }
++
++                              l2i = __ffs(masked_l2);
++
++                              /* process port */
++                              port = (l1i * BITS_PER_LONG) + l2i;
++                              if ((irq = evtchn_to_irq[port]) != -1)
++                                      do_IRQ(irq, regs);
++                              else {
++                                      exit_idle();
++                                      evtchn_device_upcall(port);
++                              }
++
++                              /* if this is the final port processed, we'll pick up here+1 next time */
++                              per_cpu(last_processed_l1i, cpu) = l1i;
++                              per_cpu(last_processed_l2i, cpu) = l2i;
++
++                      } while (l2i != BITS_PER_LONG - 1);
++
++                      l2 = active_evtchns(cpu, s, l1i);
++                      if (l2 == 0) /* we handled all ports, so we can clear the selector bit */
++                              l1 &= ~(1UL << l1i);
++
++              }
++
++              /* If there were nested callbacks then we have more to do. */
++              count = per_cpu(upcall_count, cpu);
++              per_cpu(upcall_count, cpu) = 0;
++      } while (unlikely(count != 1));
++}
++
++static int find_unbound_irq(void)
++{
++      static int warned;
++      int dynirq, irq;
++
++      for (dynirq = 0; dynirq < NR_DYNIRQS; dynirq++) {
++              irq = dynirq_to_irq(dynirq);
++              if (irq_bindcount[irq] == 0)
++                      return irq;
++      }
++
++      if (!warned) {
++              warned = 1;
++              printk(KERN_WARNING "No available IRQ to bind to: "
++                     "increase NR_DYNIRQS.\n");
++      }
++
++      return -ENOSPC;
++}
++
++static int bind_caller_port_to_irq(unsigned int caller_port)
++{
++      int irq;
++
++      spin_lock(&irq_mapping_update_lock);
++
++      if ((irq = evtchn_to_irq[caller_port]) == -1) {
++              if ((irq = find_unbound_irq()) < 0)
++                      goto out;
++
++              evtchn_to_irq[caller_port] = irq;
++              irq_info[irq] = mk_irq_info(IRQT_CALLER_PORT, 0, caller_port);
++      }
++
++      irq_bindcount[irq]++;
++
++ out:
++      spin_unlock(&irq_mapping_update_lock);
++      return irq;
++}
++
++static int bind_local_port_to_irq(unsigned int local_port)
++{
++      int irq;
++
++      spin_lock(&irq_mapping_update_lock);
++
++      BUG_ON(evtchn_to_irq[local_port] != -1);
++
++      if ((irq = find_unbound_irq()) < 0) {
++              struct evtchn_close close = { .port = local_port };
++              if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
++                      BUG();
++              goto out;
++      }
++
++      evtchn_to_irq[local_port] = irq;
++      irq_info[irq] = mk_irq_info(IRQT_LOCAL_PORT, 0, local_port);
++      irq_bindcount[irq]++;
++
++ out:
++      spin_unlock(&irq_mapping_update_lock);
++      return irq;
++}
++
++static int bind_listening_port_to_irq(unsigned int remote_domain)
++{
++      struct evtchn_alloc_unbound alloc_unbound;
++      int err;
++
++      alloc_unbound.dom        = DOMID_SELF;
++      alloc_unbound.remote_dom = remote_domain;
++
++      err = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
++                                        &alloc_unbound);
++
++      return err ? : bind_local_port_to_irq(alloc_unbound.port);
++}
++
++static int bind_interdomain_evtchn_to_irq(unsigned int remote_domain,
++                                        unsigned int remote_port)
++{
++      struct evtchn_bind_interdomain bind_interdomain;
++      int err;
++
++      bind_interdomain.remote_dom  = remote_domain;
++      bind_interdomain.remote_port = remote_port;
++
++      err = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
++                                        &bind_interdomain);
++
++      return err ? : bind_local_port_to_irq(bind_interdomain.local_port);
++}
++
++static int bind_virq_to_irq(unsigned int virq, unsigned int cpu)
++{
++      struct evtchn_bind_virq bind_virq;
++      int evtchn, irq;
++
++      spin_lock(&irq_mapping_update_lock);
++
++      if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1) {
++              if ((irq = find_unbound_irq()) < 0)
++                      goto out;
++
++              bind_virq.virq = virq;
++              bind_virq.vcpu = cpu;
++              if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
++                                              &bind_virq) != 0)
++                      BUG();
++              evtchn = bind_virq.port;
++
++              evtchn_to_irq[evtchn] = irq;
++              irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
++
++              per_cpu(virq_to_irq, cpu)[virq] = irq;
++
++              bind_evtchn_to_cpu(evtchn, cpu);
++      }
++
++      irq_bindcount[irq]++;
++
++ out:
++      spin_unlock(&irq_mapping_update_lock);
++      return irq;
++}
++
++static int bind_ipi_to_irq(unsigned int ipi, unsigned int cpu)
++{
++      struct evtchn_bind_ipi bind_ipi;
++      int evtchn, irq;
++
++      spin_lock(&irq_mapping_update_lock);
++
++      if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1) {
++              if ((irq = find_unbound_irq()) < 0)
++                      goto out;
++
++              bind_ipi.vcpu = cpu;
++              if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
++                                              &bind_ipi) != 0)
++                      BUG();
++              evtchn = bind_ipi.port;
++
++              evtchn_to_irq[evtchn] = irq;
++              irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
++
++              per_cpu(ipi_to_irq, cpu)[ipi] = irq;
++
++              bind_evtchn_to_cpu(evtchn, cpu);
++      }
++
++      irq_bindcount[irq]++;
++
++ out:
++      spin_unlock(&irq_mapping_update_lock);
++      return irq;
++}
++
++static void unbind_from_irq(unsigned int irq)
++{
++      struct evtchn_close close;
++      unsigned int cpu;
++      int evtchn = evtchn_from_irq(irq);
++
++      spin_lock(&irq_mapping_update_lock);
++
++      if ((--irq_bindcount[irq] == 0) && VALID_EVTCHN(evtchn)) {
++              close.port = evtchn;
++              if ((type_from_irq(irq) != IRQT_CALLER_PORT) &&
++                  HYPERVISOR_event_channel_op(EVTCHNOP_close, &close))
++                      BUG();
++
++              switch (type_from_irq(irq)) {
++              case IRQT_VIRQ:
++                      per_cpu(virq_to_irq, cpu_from_evtchn(evtchn))
++                              [index_from_irq(irq)] = -1;
++                      break;
++              case IRQT_IPI:
++                      per_cpu(ipi_to_irq, cpu_from_evtchn(evtchn))
++                              [index_from_irq(irq)] = -1;
++                      break;
++              default:
++                      break;
++              }
++
++              /* Closed ports are implicitly re-bound to VCPU0. */
++              bind_evtchn_to_cpu(evtchn, 0);
++
++              evtchn_to_irq[evtchn] = -1;
++              irq_info[irq] = IRQ_UNBOUND;
++
++              /* Zap stats across IRQ changes of use. */
++              for_each_possible_cpu(cpu)
++                      kstat_cpu(cpu).irqs[irq] = 0;
++      }
++
++      spin_unlock(&irq_mapping_update_lock);
++}
++
++int bind_caller_port_to_irqhandler(
++      unsigned int caller_port,
++      irqreturn_t (*handler)(int, void *, struct pt_regs *),
++      unsigned long irqflags,
++      const char *devname,
++      void *dev_id)
++{
++      int irq, retval;
++
++      irq = bind_caller_port_to_irq(caller_port);
++      if (irq < 0)
++              return irq;
++
++      retval = request_irq(irq, handler, irqflags, devname, dev_id);
++      if (retval != 0) {
++              unbind_from_irq(irq);
++              return retval;
++      }
++
++      return irq;
++}
++EXPORT_SYMBOL_GPL(bind_caller_port_to_irqhandler);
++
++int bind_listening_port_to_irqhandler(
++      unsigned int remote_domain,
++      irqreturn_t (*handler)(int, void *, struct pt_regs *),
++      unsigned long irqflags,
++      const char *devname,
++      void *dev_id)
++{
++      int irq, retval;
++
++      irq = bind_listening_port_to_irq(remote_domain);
++      if (irq < 0)
++              return irq;
++
++      retval = request_irq(irq, handler, irqflags, devname, dev_id);
++      if (retval != 0) {
++              unbind_from_irq(irq);
++              return retval;
++      }
++
++      return irq;
++}
++EXPORT_SYMBOL_GPL(bind_listening_port_to_irqhandler);
++
++int bind_interdomain_evtchn_to_irqhandler(
++      unsigned int remote_domain,
++      unsigned int remote_port,
++      irqreturn_t (*handler)(int, void *, struct pt_regs *),
++      unsigned long irqflags,
++      const char *devname,
++      void *dev_id)
++{
++      int irq, retval;
++
++      irq = bind_interdomain_evtchn_to_irq(remote_domain, remote_port);
++      if (irq < 0)
++              return irq;
++
++      retval = request_irq(irq, handler, irqflags, devname, dev_id);
++      if (retval != 0) {
++              unbind_from_irq(irq);
++              return retval;
++      }
++
++      return irq;
++}
++EXPORT_SYMBOL_GPL(bind_interdomain_evtchn_to_irqhandler);
++
++int bind_virq_to_irqhandler(
++      unsigned int virq,
++      unsigned int cpu,
++      irqreturn_t (*handler)(int, void *, struct pt_regs *),
++      unsigned long irqflags,
++      const char *devname,
++      void *dev_id)
++{
++      int irq, retval;
++
++      irq = bind_virq_to_irq(virq, cpu);
++      if (irq < 0)
++              return irq;
++
++      retval = request_irq(irq, handler, irqflags, devname, dev_id);
++      if (retval != 0) {
++              unbind_from_irq(irq);
++              return retval;
++      }
++
++      return irq;
++}
++EXPORT_SYMBOL_GPL(bind_virq_to_irqhandler);
++
++int bind_ipi_to_irqhandler(
++      unsigned int ipi,
++      unsigned int cpu,
++      irqreturn_t (*handler)(int, void *, struct pt_regs *),
++      unsigned long irqflags,
++      const char *devname,
++      void *dev_id)
++{
++      int irq, retval;
++
++      irq = bind_ipi_to_irq(ipi, cpu);
++      if (irq < 0)
++              return irq;
++
++      retval = request_irq(irq, handler, irqflags, devname, dev_id);
++      if (retval != 0) {
++              unbind_from_irq(irq);
++              return retval;
++      }
++
++      return irq;
++}
++EXPORT_SYMBOL_GPL(bind_ipi_to_irqhandler);
++
++void unbind_from_irqhandler(unsigned int irq, void *dev_id)
++{
++      free_irq(irq, dev_id);
++      unbind_from_irq(irq);
++}
++EXPORT_SYMBOL_GPL(unbind_from_irqhandler);
++
++#ifdef CONFIG_SMP
++void rebind_evtchn_to_cpu(int port, unsigned int cpu)
++{
++      struct evtchn_bind_vcpu ebv = { .port = port, .vcpu = cpu };
++      int masked;
++
++      masked = test_and_set_evtchn_mask(port);
++      if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_vcpu, &ebv) == 0)
++              bind_evtchn_to_cpu(port, cpu);
++      if (!masked)
++              unmask_evtchn(port);
++}
++
++static void rebind_irq_to_cpu(unsigned int irq, unsigned int tcpu)
++{
++      int evtchn = evtchn_from_irq(irq);
++
++      if (VALID_EVTCHN(evtchn))
++              rebind_evtchn_to_cpu(evtchn, tcpu);
++}
++
++static void set_affinity_irq(unsigned int irq, cpumask_t dest)
++{
++      unsigned tcpu = first_cpu(dest);
++      rebind_irq_to_cpu(irq, tcpu);
++}
++#endif
++
++int resend_irq_on_evtchn(unsigned int irq)
++{
++      int masked, evtchn = evtchn_from_irq(irq);
++      shared_info_t *s = HYPERVISOR_shared_info;
++
++      if (!VALID_EVTCHN(evtchn))
++              return 1;
++
++      masked = test_and_set_evtchn_mask(evtchn);
++      synch_set_bit(evtchn, s->evtchn_pending);
++      if (!masked)
++              unmask_evtchn(evtchn);
++
++      return 1;
++}
++
++/*
++ * Interface to generic handling in irq.c
++ */
++
++static unsigned int startup_dynirq(unsigned int irq)
++{
++      int evtchn = evtchn_from_irq(irq);
++
++      if (VALID_EVTCHN(evtchn))
++              unmask_evtchn(evtchn);
++      return 0;
++}
++
++static void shutdown_dynirq(unsigned int irq)
++{
++      int evtchn = evtchn_from_irq(irq);
++
++      if (VALID_EVTCHN(evtchn))
++              mask_evtchn(evtchn);
++}
++
++static void enable_dynirq(unsigned int irq)
++{
++      int evtchn = evtchn_from_irq(irq);
++
++      if (VALID_EVTCHN(evtchn))
++              unmask_evtchn(evtchn);
++}
++
++static void disable_dynirq(unsigned int irq)
++{
++      int evtchn = evtchn_from_irq(irq);
++
++      if (VALID_EVTCHN(evtchn))
++              mask_evtchn(evtchn);
++}
++
++static void ack_dynirq(unsigned int irq)
++{
++      int evtchn = evtchn_from_irq(irq);
++
++      move_native_irq(irq);
++
++      if (VALID_EVTCHN(evtchn)) {
++              mask_evtchn(evtchn);
++              clear_evtchn(evtchn);
++      }
++}
++
++static void end_dynirq(unsigned int irq)
++{
++      int evtchn = evtchn_from_irq(irq);
++
++      if (VALID_EVTCHN(evtchn) && !(irq_desc[irq].status & IRQ_DISABLED))
++              unmask_evtchn(evtchn);
++}
++
++static struct hw_interrupt_type dynirq_type = {
++      .typename = "Dynamic-irq",
++      .startup  = startup_dynirq,
++      .shutdown = shutdown_dynirq,
++      .enable   = enable_dynirq,
++      .disable  = disable_dynirq,
++      .ack      = ack_dynirq,
++      .end      = end_dynirq,
++#ifdef CONFIG_SMP
++      .set_affinity = set_affinity_irq,
++#endif
++      .retrigger = resend_irq_on_evtchn,
++};
++
++static inline void pirq_unmask_notify(int pirq)
++{
++      struct physdev_eoi eoi = { .irq = pirq };
++      if (unlikely(test_bit(pirq, pirq_needs_eoi)))
++              VOID(HYPERVISOR_physdev_op(PHYSDEVOP_eoi, &eoi));
++}
++
++static inline void pirq_query_unmask(int pirq)
++{
++      struct physdev_irq_status_query irq_status;
++      irq_status.irq = pirq;
++      if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status))
++              irq_status.flags = 0;
++      clear_bit(pirq, pirq_needs_eoi);
++      if (irq_status.flags & XENIRQSTAT_needs_eoi)
++              set_bit(pirq, pirq_needs_eoi);
++}
++
++/*
++ * On startup, if there is no action associated with the IRQ then we are
++ * probing. In this case we should not share with others as it will confuse us.
++ */
++#define probing_irq(_irq) (irq_desc[(_irq)].action == NULL)
++
++static unsigned int startup_pirq(unsigned int irq)
++{
++      struct evtchn_bind_pirq bind_pirq;
++      int evtchn = evtchn_from_irq(irq);
++
++      if (VALID_EVTCHN(evtchn))
++              goto out;
++
++      bind_pirq.pirq  = irq;
++      /* NB. We are happy to share unless we are probing. */
++      bind_pirq.flags = probing_irq(irq) ? 0 : BIND_PIRQ__WILL_SHARE;
++      if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_pirq, &bind_pirq) != 0) {
++              if (!probing_irq(irq))
++                      printk(KERN_INFO "Failed to obtain physical IRQ %d\n",
++                             irq);
++              return 0;
++      }
++      evtchn = bind_pirq.port;
++
++      pirq_query_unmask(irq_to_pirq(irq));
++
++      evtchn_to_irq[evtchn] = irq;
++      bind_evtchn_to_cpu(evtchn, 0);
++      irq_info[irq] = mk_irq_info(IRQT_PIRQ, irq, evtchn);
++
++ out:
++      unmask_evtchn(evtchn);
++      pirq_unmask_notify(irq_to_pirq(irq));
++
++      return 0;
++}
++
++static void shutdown_pirq(unsigned int irq)
++{
++      struct evtchn_close close;
++      int evtchn = evtchn_from_irq(irq);
++
++      if (!VALID_EVTCHN(evtchn))
++              return;
++
++      mask_evtchn(evtchn);
++
++      close.port = evtchn;
++      if (HYPERVISOR_event_channel_op(EVTCHNOP_close, &close) != 0)
++              BUG();
++
++      bind_evtchn_to_cpu(evtchn, 0);
++      evtchn_to_irq[evtchn] = -1;
++      irq_info[irq] = IRQ_UNBOUND;
++}
++
++static void enable_pirq(unsigned int irq)
++{
++      startup_pirq(irq);
++}
++
++static void disable_pirq(unsigned int irq)
++{
++}
++
++static void ack_pirq(unsigned int irq)
++{
++      int evtchn = evtchn_from_irq(irq);
++
++      move_native_irq(irq);
++
++      if (VALID_EVTCHN(evtchn)) {
++              mask_evtchn(evtchn);
++              clear_evtchn(evtchn);
++      }
++}
++
++static void end_pirq(unsigned int irq)
++{
++      int evtchn = evtchn_from_irq(irq);
++
++      if ((irq_desc[irq].status & (IRQ_DISABLED|IRQ_PENDING)) ==
++          (IRQ_DISABLED|IRQ_PENDING)) {
++              shutdown_pirq(irq);
++      } else if (VALID_EVTCHN(evtchn)) {
++              unmask_evtchn(evtchn);
++              pirq_unmask_notify(irq_to_pirq(irq));
++      }
++}
++
++static struct hw_interrupt_type pirq_type = {
++      .typename = "Phys-irq",
++      .startup  = startup_pirq,
++      .shutdown = shutdown_pirq,
++      .enable   = enable_pirq,
++      .disable  = disable_pirq,
++      .ack      = ack_pirq,
++      .end      = end_pirq,
++#ifdef CONFIG_SMP
++      .set_affinity = set_affinity_irq,
++#endif
++      .retrigger = resend_irq_on_evtchn,
++};
++
++int irq_ignore_unhandled(unsigned int irq)
++{
++      struct physdev_irq_status_query irq_status = { .irq = irq };
++
++      if (!is_running_on_xen())
++              return 0;
++
++      if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status))
++              return 0;
++      return !!(irq_status.flags & XENIRQSTAT_shared);
++}
++
++void notify_remote_via_irq(int irq)
++{
++      int evtchn = evtchn_from_irq(irq);
++
++      if (VALID_EVTCHN(evtchn))
++              notify_remote_via_evtchn(evtchn);
++}
++EXPORT_SYMBOL_GPL(notify_remote_via_irq);
++
++int irq_to_evtchn_port(int irq)
++{
++      return evtchn_from_irq(irq);
++}
++EXPORT_SYMBOL_GPL(irq_to_evtchn_port);
++
++void mask_evtchn(int port)
++{
++      shared_info_t *s = HYPERVISOR_shared_info;
++      synch_set_bit(port, s->evtchn_mask);
++}
++EXPORT_SYMBOL_GPL(mask_evtchn);
++
++void unmask_evtchn(int port)
++{
++      shared_info_t *s = HYPERVISOR_shared_info;
++      unsigned int cpu = smp_processor_id();
++      vcpu_info_t *vcpu_info = &s->vcpu_info[cpu];
++
++      BUG_ON(!irqs_disabled());
++
++      /* Slow path (hypercall) if this is a non-local port. */
++      if (unlikely(cpu != cpu_from_evtchn(port))) {
++              struct evtchn_unmask unmask = { .port = port };
++              VOID(HYPERVISOR_event_channel_op(EVTCHNOP_unmask, &unmask));
++              return;
++      }
++
++      synch_clear_bit(port, s->evtchn_mask);
++
++      /* Did we miss an interrupt 'edge'? Re-fire if so. */
++      if (synch_test_bit(port, s->evtchn_pending) &&
++          !synch_test_and_set_bit(port / BITS_PER_LONG,
++                                  &vcpu_info->evtchn_pending_sel))
++              vcpu_info->evtchn_upcall_pending = 1;
++}
++EXPORT_SYMBOL_GPL(unmask_evtchn);
++
++void disable_all_local_evtchn(void)
++{
++      unsigned i, cpu = smp_processor_id();
++      shared_info_t *s = HYPERVISOR_shared_info;
++
++      for (i = 0; i < NR_EVENT_CHANNELS; ++i)
++              if (cpu_from_evtchn(i) == cpu)
++                      synch_set_bit(i, &s->evtchn_mask[0]);
++}
++
++static void restore_cpu_virqs(unsigned int cpu)
++{
++      struct evtchn_bind_virq bind_virq;
++      int virq, irq, evtchn;
++
++      for (virq = 0; virq < NR_VIRQS; virq++) {
++              if ((irq = per_cpu(virq_to_irq, cpu)[virq]) == -1)
++                      continue;
++
++              BUG_ON(irq_info[irq] != mk_irq_info(IRQT_VIRQ, virq, 0));
++
++              /* Get a new binding from Xen. */
++              bind_virq.virq = virq;
++              bind_virq.vcpu = cpu;
++              if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
++                                              &bind_virq) != 0)
++                      BUG();
++              evtchn = bind_virq.port;
++
++              /* Record the new mapping. */
++              evtchn_to_irq[evtchn] = irq;
++              irq_info[irq] = mk_irq_info(IRQT_VIRQ, virq, evtchn);
++              bind_evtchn_to_cpu(evtchn, cpu);
++
++              /* Ready for use. */
++              unmask_evtchn(evtchn);
++      }
++}
++
++static void restore_cpu_ipis(unsigned int cpu)
++{
++      struct evtchn_bind_ipi bind_ipi;
++      int ipi, irq, evtchn;
++
++      for (ipi = 0; ipi < NR_IPIS; ipi++) {
++              if ((irq = per_cpu(ipi_to_irq, cpu)[ipi]) == -1)
++                      continue;
++
++              BUG_ON(irq_info[irq] != mk_irq_info(IRQT_IPI, ipi, 0));
++
++              /* Get a new binding from Xen. */
++              bind_ipi.vcpu = cpu;
++              if (HYPERVISOR_event_channel_op(EVTCHNOP_bind_ipi,
++                                              &bind_ipi) != 0)
++                      BUG();
++              evtchn = bind_ipi.port;
++
++              /* Record the new mapping. */
++              evtchn_to_irq[evtchn] = irq;
++              irq_info[irq] = mk_irq_info(IRQT_IPI, ipi, evtchn);
++              bind_evtchn_to_cpu(evtchn, cpu);
++
++              /* Ready for use. */
++              unmask_evtchn(evtchn);
++
++      }
++}
++
++void irq_resume(void)
++{
++      unsigned int cpu, pirq, irq, evtchn;
++
++      init_evtchn_cpu_bindings();
++
++      /* New event-channel space is not 'live' yet. */
++      for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
++              mask_evtchn(evtchn);
++
++      /* Check that no PIRQs are still bound. */
++      for (pirq = 0; pirq < NR_PIRQS; pirq++)
++              BUG_ON(irq_info[pirq_to_irq(pirq)] != IRQ_UNBOUND);
++
++      /* No IRQ <-> event-channel mappings. */
++      for (irq = 0; irq < NR_IRQS; irq++)
++              irq_info[irq] &= ~0xFFFF; /* zap event-channel binding */
++      for (evtchn = 0; evtchn < NR_EVENT_CHANNELS; evtchn++)
++              evtchn_to_irq[evtchn] = -1;
++
++      for_each_possible_cpu(cpu) {
++              restore_cpu_virqs(cpu);
++              restore_cpu_ipis(cpu);
++      }
++
++}
++
++void __init xen_init_IRQ(void)
++{
++      unsigned int i;
++
++      init_evtchn_cpu_bindings();
++
++      /* No event channels are 'live' right now. */
++      for (i = 0; i < NR_EVENT_CHANNELS; i++)
++              mask_evtchn(i);
++
++      /* No IRQ -> event-channel mappings. */
++      for (i = 0; i < NR_IRQS; i++)
++              irq_info[i] = IRQ_UNBOUND;
++
++      /* Dynamic IRQ space is currently unbound. Zero the refcnts. */
++      for (i = 0; i < NR_DYNIRQS; i++) {
++              irq_bindcount[dynirq_to_irq(i)] = 0;
++
++              irq_desc[dynirq_to_irq(i)].status = IRQ_DISABLED;
++              irq_desc[dynirq_to_irq(i)].action = NULL;
++              irq_desc[dynirq_to_irq(i)].depth = 1;
++              irq_desc[dynirq_to_irq(i)].chip = &dynirq_type;
++      }
++
++      /* Phys IRQ space is statically bound (1:1 mapping). Nail refcnts. */
++      for (i = 0; i < NR_PIRQS; i++) {
++              irq_bindcount[pirq_to_irq(i)] = 1;
++
++#ifdef RTC_IRQ
++              /* If not domain 0, force our RTC driver to fail its probe. */
++              if ((i == RTC_IRQ) && !is_initial_xendomain())
++                      continue;
++#endif
++
++              irq_desc[pirq_to_irq(i)].status = IRQ_DISABLED;
++              irq_desc[pirq_to_irq(i)].action = NULL;
++              irq_desc[pirq_to_irq(i)].depth = 1;
++              irq_desc[pirq_to_irq(i)].chip = &pirq_type;
++      }
++}
+--- linux-2.6.18.8/drivers/xen/core/features.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/features.c    2008-05-19 00:33:45.770784401 +0300
+@@ -0,0 +1,34 @@
++/******************************************************************************
++ * features.c
++ *
++ * Xen feature flags.
++ *
++ * Copyright (c) 2006, Ian Campbell, XenSource Inc.
++ */
++#include <linux/types.h>
++#include <linux/cache.h>
++#include <linux/module.h>
++#include <asm/hypervisor.h>
++#include <xen/features.h>
++
++#ifdef HAVE_XEN_PLATFORM_COMPAT_H
++#include <xen/platform-compat.h>
++#endif
++
++u8 xen_features[XENFEAT_NR_SUBMAPS * 32] __read_mostly;
++/* Not a GPL symbol: used in ubiquitous macros, so too restrictive. */
++EXPORT_SYMBOL(xen_features);
++
++void setup_xen_features(void)
++{
++      xen_feature_info_t fi;
++      int i, j;
++
++      for (i = 0; i < XENFEAT_NR_SUBMAPS; i++) {
++              fi.submap_idx = i;
++              if (HYPERVISOR_xen_version(XENVER_get_features, &fi) < 0)
++                      break;
++              for (j=0; j<32; j++)
++                      xen_features[i*32+j] = !!(fi.submap & 1<<j);
++      }
++}
+--- linux-2.6.18.8/drivers/xen/core/firmware.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/firmware.c    2008-05-19 00:33:45.770784401 +0300
+@@ -0,0 +1,74 @@
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/edd.h>
++#include <video/edid.h>
++#include <xen/interface/platform.h>
++#include <asm/hypervisor.h>
++
++#if defined(CONFIG_EDD) || defined(CONFIG_EDD_MODULE)
++void __init copy_edd(void)
++{
++      int ret;
++      struct xen_platform_op op;
++
++      if (!is_initial_xendomain())
++              return;
++
++      op.cmd = XENPF_firmware_info;
++
++      op.u.firmware_info.type = XEN_FW_DISK_INFO;
++      for (op.u.firmware_info.index = 0;
++           edd.edd_info_nr < EDDMAXNR;
++           op.u.firmware_info.index++) {
++              struct edd_info *info = edd.edd_info + edd.edd_info_nr;
++
++              info->params.length = sizeof(info->params);
++              set_xen_guest_handle(op.u.firmware_info.u.disk_info.edd_params,
++                                   &info->params);
++              ret = HYPERVISOR_platform_op(&op);
++              if (ret)
++                      break;
++
++#define C(x) info->x = op.u.firmware_info.u.disk_info.x
++              C(device);
++              C(version);
++              C(interface_support);
++              C(legacy_max_cylinder);
++              C(legacy_max_head);
++              C(legacy_sectors_per_track);
++#undef C
++
++              edd.edd_info_nr++;
++      }
++
++      op.u.firmware_info.type = XEN_FW_DISK_MBR_SIGNATURE;
++      for (op.u.firmware_info.index = 0;
++           edd.mbr_signature_nr < EDD_MBR_SIG_MAX;
++           op.u.firmware_info.index++) {
++              ret = HYPERVISOR_platform_op(&op);
++              if (ret)
++                      break;
++              edd.mbr_signature[edd.mbr_signature_nr++] =
++                      op.u.firmware_info.u.disk_mbr_signature.mbr_signature;
++      }
++}
++#endif
++
++void __init copy_edid(void)
++{
++#if defined(CONFIG_FIRMWARE_EDID) && defined(CONFIG_X86)
++      struct xen_platform_op op;
++
++      if (!is_initial_xendomain())
++              return;
++
++      op.cmd = XENPF_firmware_info;
++      op.u.firmware_info.index = 0;
++      op.u.firmware_info.type = XEN_FW_VBEDDC_INFO;
++      set_xen_guest_handle(op.u.firmware_info.u.vbeddc_info.edid,
++                           edid_info.dummy);
++      if (HYPERVISOR_platform_op(&op) != 0)
++              memset(edid_info.dummy, 0x13, sizeof(edid_info.dummy));
++#endif
++}
+--- linux-2.6.18.8/drivers/xen/core/gnttab.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/gnttab.c      2008-05-19 00:33:45.818787168 +0300
+@@ -0,0 +1,769 @@
++/******************************************************************************
++ * gnttab.c
++ *
++ * Granting foreign access to our memory reservation.
++ *
++ * Copyright (c) 2005-2006, Christopher Clark
++ * Copyright (c) 2004-2005, K A Fraser
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/module.h>
++#include <linux/sched.h>
++#include <linux/mm.h>
++#include <linux/seqlock.h>
++#include <xen/interface/xen.h>
++#include <xen/gnttab.h>
++#include <asm/pgtable.h>
++#include <asm/uaccess.h>
++#include <asm/synch_bitops.h>
++#include <asm/io.h>
++#include <xen/interface/memory.h>
++#include <xen/driver_util.h>
++#include <asm/gnttab_dma.h>
++
++#ifdef HAVE_XEN_PLATFORM_COMPAT_H
++#include <xen/platform-compat.h>
++#endif
++
++/* External tools reserve first few grant table entries. */
++#define NR_RESERVED_ENTRIES 8
++#define GNTTAB_LIST_END 0xffffffff
++#define ENTRIES_PER_GRANT_FRAME (PAGE_SIZE / sizeof(grant_entry_t))
++
++static grant_ref_t **gnttab_list;
++static unsigned int nr_grant_frames;
++static unsigned int boot_max_nr_grant_frames;
++static int gnttab_free_count;
++static grant_ref_t gnttab_free_head;
++static DEFINE_SPINLOCK(gnttab_list_lock);
++
++static struct grant_entry *shared;
++
++static struct gnttab_free_callback *gnttab_free_callback_list;
++
++static int gnttab_expand(unsigned int req_entries);
++
++#define RPP (PAGE_SIZE / sizeof(grant_ref_t))
++#define gnttab_entry(entry) (gnttab_list[(entry) / RPP][(entry) % RPP])
++
++#define nr_freelist_frames(grant_frames)                              \
++      (((grant_frames) * ENTRIES_PER_GRANT_FRAME + RPP - 1) / RPP)
++
++static int get_free_entries(int count)
++{
++      unsigned long flags;
++      int ref, rc;
++      grant_ref_t head;
++
++      spin_lock_irqsave(&gnttab_list_lock, flags);
++
++      if ((gnttab_free_count < count) &&
++          ((rc = gnttab_expand(count - gnttab_free_count)) < 0)) {
++              spin_unlock_irqrestore(&gnttab_list_lock, flags);
++              return rc;
++      }
++
++      ref = head = gnttab_free_head;
++      gnttab_free_count -= count;
++      while (count-- > 1)
++              head = gnttab_entry(head);
++      gnttab_free_head = gnttab_entry(head);
++      gnttab_entry(head) = GNTTAB_LIST_END;
++
++      spin_unlock_irqrestore(&gnttab_list_lock, flags);
++
++      return ref;
++}
++
++#define get_free_entry() get_free_entries(1)
++
++static void do_free_callbacks(void)
++{
++      struct gnttab_free_callback *callback, *next;
++
++      callback = gnttab_free_callback_list;
++      gnttab_free_callback_list = NULL;
++
++      while (callback != NULL) {
++              next = callback->next;
++              if (gnttab_free_count >= callback->count) {
++                      callback->next = NULL;
++                      callback->fn(callback->arg);
++              } else {
++                      callback->next = gnttab_free_callback_list;
++                      gnttab_free_callback_list = callback;
++              }
++              callback = next;
++      }
++}
++
++static inline void check_free_callbacks(void)
++{
++      if (unlikely(gnttab_free_callback_list))
++              do_free_callbacks();
++}
++
++static void put_free_entry(grant_ref_t ref)
++{
++      unsigned long flags;
++      spin_lock_irqsave(&gnttab_list_lock, flags);
++      gnttab_entry(ref) = gnttab_free_head;
++      gnttab_free_head = ref;
++      gnttab_free_count++;
++      check_free_callbacks();
++      spin_unlock_irqrestore(&gnttab_list_lock, flags);
++}
++
++/*
++ * Public grant-issuing interface functions
++ */
++
++int gnttab_grant_foreign_access(domid_t domid, unsigned long frame,
++                              int flags)
++{
++      int ref;
++
++      if (unlikely((ref = get_free_entry()) < 0))
++              return -ENOSPC;
++
++      shared[ref].frame = frame;
++      shared[ref].domid = domid;
++      wmb();
++      BUG_ON(flags & (GTF_accept_transfer | GTF_reading | GTF_writing));
++      shared[ref].flags = GTF_permit_access | flags;
++
++      return ref;
++}
++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access);
++
++void gnttab_grant_foreign_access_ref(grant_ref_t ref, domid_t domid,
++                                   unsigned long frame, int flags)
++{
++      shared[ref].frame = frame;
++      shared[ref].domid = domid;
++      wmb();
++      BUG_ON(flags & (GTF_accept_transfer | GTF_reading | GTF_writing));
++      shared[ref].flags = GTF_permit_access | flags;
++}
++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_access_ref);
++
++
++int gnttab_query_foreign_access(grant_ref_t ref)
++{
++      u16 nflags;
++
++      nflags = shared[ref].flags;
++
++      return (nflags & (GTF_reading|GTF_writing));
++}
++EXPORT_SYMBOL_GPL(gnttab_query_foreign_access);
++
++int gnttab_end_foreign_access_ref(grant_ref_t ref)
++{
++      u16 flags, nflags;
++
++      nflags = shared[ref].flags;
++      do {
++              if ((flags = nflags) & (GTF_reading|GTF_writing)) {
++                      printk(KERN_DEBUG "WARNING: g.e. still in use!\n");
++                      return 0;
++              }
++      } while ((nflags = synch_cmpxchg_subword(&shared[ref].flags, flags, 0)) !=
++               flags);
++
++      return 1;
++}
++EXPORT_SYMBOL_GPL(gnttab_end_foreign_access_ref);
++
++void gnttab_end_foreign_access(grant_ref_t ref, unsigned long page)
++{
++      if (gnttab_end_foreign_access_ref(ref)) {
++              put_free_entry(ref);
++              if (page != 0)
++                      free_page(page);
++      } else {
++              /* XXX This needs to be fixed so that the ref and page are
++                 placed on a list to be freed up later. */
++              printk(KERN_DEBUG
++                     "WARNING: leaking g.e. and page still in use!\n");
++      }
++}
++EXPORT_SYMBOL_GPL(gnttab_end_foreign_access);
++
++int gnttab_grant_foreign_transfer(domid_t domid, unsigned long pfn)
++{
++      int ref;
++
++      if (unlikely((ref = get_free_entry()) < 0))
++              return -ENOSPC;
++      gnttab_grant_foreign_transfer_ref(ref, domid, pfn);
++
++      return ref;
++}
++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer);
++
++void gnttab_grant_foreign_transfer_ref(grant_ref_t ref, domid_t domid,
++                                     unsigned long pfn)
++{
++      shared[ref].frame = pfn;
++      shared[ref].domid = domid;
++      wmb();
++      shared[ref].flags = GTF_accept_transfer;
++}
++EXPORT_SYMBOL_GPL(gnttab_grant_foreign_transfer_ref);
++
++unsigned long gnttab_end_foreign_transfer_ref(grant_ref_t ref)
++{
++      unsigned long frame;
++      u16           flags;
++
++      /*
++       * If a transfer is not even yet started, try to reclaim the grant
++       * reference and return failure (== 0).
++       */
++      while (!((flags = shared[ref].flags) & GTF_transfer_committed)) {
++              if (synch_cmpxchg_subword(&shared[ref].flags, flags, 0) == flags)
++                      return 0;
++              cpu_relax();
++      }
++
++      /* If a transfer is in progress then wait until it is completed. */
++      while (!(flags & GTF_transfer_completed)) {
++              flags = shared[ref].flags;
++              cpu_relax();
++      }
++
++      /* Read the frame number /after/ reading completion status. */
++      rmb();
++      frame = shared[ref].frame;
++      BUG_ON(frame == 0);
++
++      return frame;
++}
++EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer_ref);
++
++unsigned long gnttab_end_foreign_transfer(grant_ref_t ref)
++{
++      unsigned long frame = gnttab_end_foreign_transfer_ref(ref);
++      put_free_entry(ref);
++      return frame;
++}
++EXPORT_SYMBOL_GPL(gnttab_end_foreign_transfer);
++
++void gnttab_free_grant_reference(grant_ref_t ref)
++{
++      put_free_entry(ref);
++}
++EXPORT_SYMBOL_GPL(gnttab_free_grant_reference);
++
++void gnttab_free_grant_references(grant_ref_t head)
++{
++      grant_ref_t ref;
++      unsigned long flags;
++      int count = 1;
++      if (head == GNTTAB_LIST_END)
++              return;
++      spin_lock_irqsave(&gnttab_list_lock, flags);
++      ref = head;
++      while (gnttab_entry(ref) != GNTTAB_LIST_END) {
++              ref = gnttab_entry(ref);
++              count++;
++      }
++      gnttab_entry(ref) = gnttab_free_head;
++      gnttab_free_head = head;
++      gnttab_free_count += count;
++      check_free_callbacks();
++      spin_unlock_irqrestore(&gnttab_list_lock, flags);
++}
++EXPORT_SYMBOL_GPL(gnttab_free_grant_references);
++
++int gnttab_alloc_grant_references(u16 count, grant_ref_t *head)
++{
++      int h = get_free_entries(count);
++
++      if (h < 0)
++              return -ENOSPC;
++
++      *head = h;
++
++      return 0;
++}
++EXPORT_SYMBOL_GPL(gnttab_alloc_grant_references);
++
++int gnttab_empty_grant_references(const grant_ref_t *private_head)
++{
++      return (*private_head == GNTTAB_LIST_END);
++}
++EXPORT_SYMBOL_GPL(gnttab_empty_grant_references);
++
++int gnttab_claim_grant_reference(grant_ref_t *private_head)
++{
++      grant_ref_t g = *private_head;
++      if (unlikely(g == GNTTAB_LIST_END))
++              return -ENOSPC;
++      *private_head = gnttab_entry(g);
++      return g;
++}
++EXPORT_SYMBOL_GPL(gnttab_claim_grant_reference);
++
++void gnttab_release_grant_reference(grant_ref_t *private_head,
++                                  grant_ref_t release)
++{
++      gnttab_entry(release) = *private_head;
++      *private_head = release;
++}
++EXPORT_SYMBOL_GPL(gnttab_release_grant_reference);
++
++void gnttab_request_free_callback(struct gnttab_free_callback *callback,
++                                void (*fn)(void *), void *arg, u16 count)
++{
++      unsigned long flags;
++      spin_lock_irqsave(&gnttab_list_lock, flags);
++      if (callback->next)
++              goto out;
++      callback->fn = fn;
++      callback->arg = arg;
++      callback->count = count;
++      callback->next = gnttab_free_callback_list;
++      gnttab_free_callback_list = callback;
++      check_free_callbacks();
++out:
++      spin_unlock_irqrestore(&gnttab_list_lock, flags);
++}
++EXPORT_SYMBOL_GPL(gnttab_request_free_callback);
++
++void gnttab_cancel_free_callback(struct gnttab_free_callback *callback)
++{
++      struct gnttab_free_callback **pcb;
++      unsigned long flags;
++
++      spin_lock_irqsave(&gnttab_list_lock, flags);
++      for (pcb = &gnttab_free_callback_list; *pcb; pcb = &(*pcb)->next) {
++              if (*pcb == callback) {
++                      *pcb = callback->next;
++                      break;
++              }
++      }
++      spin_unlock_irqrestore(&gnttab_list_lock, flags);
++}
++EXPORT_SYMBOL_GPL(gnttab_cancel_free_callback);
++
++static int grow_gnttab_list(unsigned int more_frames)
++{
++      unsigned int new_nr_grant_frames, extra_entries, i;
++      unsigned int nr_glist_frames, new_nr_glist_frames;
++
++      new_nr_grant_frames = nr_grant_frames + more_frames;
++      extra_entries       = more_frames * ENTRIES_PER_GRANT_FRAME;
++
++      nr_glist_frames = nr_freelist_frames(nr_grant_frames);
++      new_nr_glist_frames = nr_freelist_frames(new_nr_grant_frames);
++      for (i = nr_glist_frames; i < new_nr_glist_frames; i++) {
++              gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_ATOMIC);
++              if (!gnttab_list[i])
++                      goto grow_nomem;
++      }
++
++      for (i = ENTRIES_PER_GRANT_FRAME * nr_grant_frames;
++           i < ENTRIES_PER_GRANT_FRAME * new_nr_grant_frames - 1; i++)
++              gnttab_entry(i) = i + 1;
++
++      gnttab_entry(i) = gnttab_free_head;
++      gnttab_free_head = ENTRIES_PER_GRANT_FRAME * nr_grant_frames;
++      gnttab_free_count += extra_entries;
++
++      nr_grant_frames = new_nr_grant_frames;
++
++      check_free_callbacks();
++
++      return 0;
++      
++grow_nomem:
++      for ( ; i >= nr_glist_frames; i--)
++              free_page((unsigned long) gnttab_list[i]);
++      return -ENOMEM;
++}
++
++static unsigned int __max_nr_grant_frames(void)
++{
++      struct gnttab_query_size query;
++      int rc;
++
++      query.dom = DOMID_SELF;
++
++      rc = HYPERVISOR_grant_table_op(GNTTABOP_query_size, &query, 1);
++      if ((rc < 0) || (query.status != GNTST_okay))
++              return 4; /* Legacy max supported number of frames */
++
++      return query.max_nr_frames;
++}
++
++static inline unsigned int max_nr_grant_frames(void)
++{
++      unsigned int xen_max = __max_nr_grant_frames();
++
++      if (xen_max > boot_max_nr_grant_frames)
++              return boot_max_nr_grant_frames;
++      return xen_max;
++}
++
++#ifdef CONFIG_XEN
++
++static DEFINE_SEQLOCK(gnttab_dma_lock);
++
++#ifdef CONFIG_X86
++static int map_pte_fn(pte_t *pte, struct page *pmd_page,
++                    unsigned long addr, void *data)
++{
++      unsigned long **frames = (unsigned long **)data;
++
++      set_pte_at(&init_mm, addr, pte, pfn_pte_ma((*frames)[0], PAGE_KERNEL));
++      (*frames)++;
++      return 0;
++}
++
++static int unmap_pte_fn(pte_t *pte, struct page *pmd_page,
++                      unsigned long addr, void *data)
++{
++
++      set_pte_at(&init_mm, addr, pte, __pte(0));
++      return 0;
++}
++
++void *arch_gnttab_alloc_shared(unsigned long *frames)
++{
++      struct vm_struct *area;
++      area = alloc_vm_area(PAGE_SIZE * max_nr_grant_frames());
++      BUG_ON(area == NULL);
++      return area->addr;
++}
++#endif /* CONFIG_X86 */
++
++static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
++{
++      struct gnttab_setup_table setup;
++      unsigned long *frames;
++      unsigned int nr_gframes = end_idx + 1;
++      int rc;
++
++      frames = kmalloc(nr_gframes * sizeof(unsigned long), GFP_ATOMIC);
++      if (!frames)
++              return -ENOMEM;
++
++      setup.dom        = DOMID_SELF;
++      setup.nr_frames  = nr_gframes;
++      set_xen_guest_handle(setup.frame_list, frames);
++
++      rc = HYPERVISOR_grant_table_op(GNTTABOP_setup_table, &setup, 1);
++      if (rc == -ENOSYS) {
++              kfree(frames);
++              return -ENOSYS;
++      }
++
++      BUG_ON(rc || setup.status);
++
++      if (shared == NULL)
++              shared = arch_gnttab_alloc_shared(frames);
++
++#ifdef CONFIG_X86
++      rc = apply_to_page_range(&init_mm, (unsigned long)shared,
++                               PAGE_SIZE * nr_gframes,
++                               map_pte_fn, &frames);
++      BUG_ON(rc);
++      frames -= nr_gframes; /* adjust after map_pte_fn() */
++#endif /* CONFIG_X86 */
++
++      kfree(frames);
++
++      return 0;
++}
++
++static void gnttab_page_free(struct page *page)
++{
++      ClearPageForeign(page);
++      gnttab_reset_grant_page(page);
++      put_page(page);
++}
++
++/*
++ * Must not be called with IRQs off.  This should only be used on the
++ * slow path.
++ *
++ * Copy a foreign granted page to local memory.
++ */
++int gnttab_copy_grant_page(grant_ref_t ref, struct page **pagep)
++{
++      struct gnttab_unmap_and_replace unmap;
++      mmu_update_t mmu;
++      struct page *page;
++      struct page *new_page;
++      void *new_addr;
++      void *addr;
++      paddr_t pfn;
++      maddr_t mfn;
++      maddr_t new_mfn;
++      int err;
++
++      page = *pagep;
++      if (!get_page_unless_zero(page))
++              return -ENOENT;
++
++      err = -ENOMEM;
++      new_page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
++      if (!new_page)
++              goto out;
++
++      new_addr = page_address(new_page);
++      addr = page_address(page);
++      memcpy(new_addr, addr, PAGE_SIZE);
++
++      pfn = page_to_pfn(page);
++      mfn = pfn_to_mfn(pfn);
++      new_mfn = virt_to_mfn(new_addr);
++
++      write_seqlock(&gnttab_dma_lock);
++
++      /* Make seq visible before checking page_mapped. */
++      smp_mb();
++
++      /* Has the page been DMA-mapped? */
++      if (unlikely(page_mapped(page))) {
++              write_sequnlock(&gnttab_dma_lock);
++              put_page(new_page);
++              err = -EBUSY;
++              goto out;
++      }
++
++      if (!xen_feature(XENFEAT_auto_translated_physmap))
++              set_phys_to_machine(pfn, new_mfn);
++
++      gnttab_set_replace_op(&unmap, (unsigned long)addr,
++                            (unsigned long)new_addr, ref);
++
++      err = HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
++                                      &unmap, 1);
++      BUG_ON(err);
++      BUG_ON(unmap.status);
++
++      write_sequnlock(&gnttab_dma_lock);
++
++      if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++              set_phys_to_machine(page_to_pfn(new_page), INVALID_P2M_ENTRY);
++
++              mmu.ptr = (new_mfn << PAGE_SHIFT) | MMU_MACHPHYS_UPDATE;
++              mmu.val = pfn;
++              err = HYPERVISOR_mmu_update(&mmu, 1, NULL, DOMID_SELF);
++              BUG_ON(err);
++      }
++
++      new_page->mapping = page->mapping;
++      new_page->index = page->index;
++      set_bit(PG_foreign, &new_page->flags);
++      *pagep = new_page;
++
++      SetPageForeign(page, gnttab_page_free);
++      page->mapping = NULL;
++
++out:
++      put_page(page);
++      return err;
++}
++EXPORT_SYMBOL_GPL(gnttab_copy_grant_page);
++
++void gnttab_reset_grant_page(struct page *page)
++{
++      init_page_count(page);
++      reset_page_mapcount(page);
++}
++EXPORT_SYMBOL_GPL(gnttab_reset_grant_page);
++
++/*
++ * Keep track of foreign pages marked as PageForeign so that we don't
++ * return them to the remote domain prematurely.
++ *
++ * PageForeign pages are pinned down by increasing their mapcount.
++ *
++ * All other pages are simply returned as is.
++ */
++void __gnttab_dma_map_page(struct page *page)
++{
++      unsigned int seq;
++
++      if (!is_running_on_xen() || !PageForeign(page))
++              return;
++
++      do {
++              seq = read_seqbegin(&gnttab_dma_lock);
++
++              if (gnttab_dma_local_pfn(page))
++                      break;
++
++              atomic_set(&page->_mapcount, 0);
++
++              /* Make _mapcount visible before read_seqretry. */
++              smp_mb();
++      } while (unlikely(read_seqretry(&gnttab_dma_lock, seq)));
++}
++
++int gnttab_resume(void)
++{
++      if (max_nr_grant_frames() < nr_grant_frames)
++              return -ENOSYS;
++      return gnttab_map(0, nr_grant_frames - 1);
++}
++
++int gnttab_suspend(void)
++{
++#ifdef CONFIG_X86
++      apply_to_page_range(&init_mm, (unsigned long)shared,
++                          PAGE_SIZE * nr_grant_frames,
++                          unmap_pte_fn, NULL);
++#endif
++      return 0;
++}
++
++#else /* !CONFIG_XEN */
++
++#include <platform-pci.h>
++
++static unsigned long resume_frames;
++
++static int gnttab_map(unsigned int start_idx, unsigned int end_idx)
++{
++      struct xen_add_to_physmap xatp;
++      unsigned int i = end_idx;
++
++      /* Loop backwards, so that the first hypercall has the largest index,
++       * ensuring that the table will grow only once.
++       */
++      do {
++              xatp.domid = DOMID_SELF;
++              xatp.idx = i;
++              xatp.space = XENMAPSPACE_grant_table;
++              xatp.gpfn = (resume_frames >> PAGE_SHIFT) + i;
++              if (HYPERVISOR_memory_op(XENMEM_add_to_physmap, &xatp))
++                      BUG();
++      } while (i-- > start_idx);
++
++      return 0;
++}
++
++int gnttab_resume(void)
++{
++      unsigned int max_nr_gframes, nr_gframes;
++
++      nr_gframes = nr_grant_frames;
++      max_nr_gframes = max_nr_grant_frames();
++      if (max_nr_gframes < nr_gframes)
++              return -ENOSYS;
++
++      if (!resume_frames) {
++              resume_frames = alloc_xen_mmio(PAGE_SIZE * max_nr_gframes);
++              shared = ioremap(resume_frames, PAGE_SIZE * max_nr_gframes);
++              if (shared == NULL) {
++                      printk("error to ioremap gnttab share frames\n");
++                      return -1;
++              }
++      }
++
++      gnttab_map(0, nr_gframes - 1);
++
++      return 0;
++}
++
++#endif /* !CONFIG_XEN */
++
++static int gnttab_expand(unsigned int req_entries)
++{
++      int rc;
++      unsigned int cur, extra;
++
++      cur = nr_grant_frames;
++      extra = ((req_entries + (ENTRIES_PER_GRANT_FRAME-1)) /
++               ENTRIES_PER_GRANT_FRAME);
++      if (cur + extra > max_nr_grant_frames())
++              return -ENOSPC;
++
++      if ((rc = gnttab_map(cur, cur + extra - 1)) == 0)
++              rc = grow_gnttab_list(extra);
++
++      return rc;
++}
++
++int __devinit gnttab_init(void)
++{
++      int i;
++      unsigned int max_nr_glist_frames, nr_glist_frames;
++      unsigned int nr_init_grefs;
++
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      nr_grant_frames = 1;
++      boot_max_nr_grant_frames = __max_nr_grant_frames();
++
++      /* Determine the maximum number of frames required for the
++       * grant reference free list on the current hypervisor.
++       */
++      max_nr_glist_frames = nr_freelist_frames(boot_max_nr_grant_frames);
++
++      gnttab_list = kmalloc(max_nr_glist_frames * sizeof(grant_ref_t *),
++                            GFP_KERNEL);
++      if (gnttab_list == NULL)
++              return -ENOMEM;
++
++      nr_glist_frames = nr_freelist_frames(nr_grant_frames);
++      for (i = 0; i < nr_glist_frames; i++) {
++              gnttab_list[i] = (grant_ref_t *)__get_free_page(GFP_KERNEL);
++              if (gnttab_list[i] == NULL)
++                      goto ini_nomem;
++      }
++
++      if (gnttab_resume() < 0)
++              return -ENODEV;
++
++      nr_init_grefs = nr_grant_frames * ENTRIES_PER_GRANT_FRAME;
++
++      for (i = NR_RESERVED_ENTRIES; i < nr_init_grefs - 1; i++)
++              gnttab_entry(i) = i + 1;
++
++      gnttab_entry(nr_init_grefs - 1) = GNTTAB_LIST_END;
++      gnttab_free_count = nr_init_grefs - NR_RESERVED_ENTRIES;
++      gnttab_free_head  = NR_RESERVED_ENTRIES;
++
++      return 0;
++
++ ini_nomem:
++      for (i--; i >= 0; i--)
++              free_page((unsigned long)gnttab_list[i]);
++      kfree(gnttab_list);
++      return -ENOMEM;
++}
++
++#ifdef CONFIG_XEN
++core_initcall(gnttab_init);
++#endif
+--- linux-2.6.18.8/drivers/xen/core/hypervisor_sysfs.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/hypervisor_sysfs.c    2008-05-19 00:33:45.822787398 +0300
+@@ -0,0 +1,57 @@
++/*
++ *  copyright (c) 2006 IBM Corporation
++ *  Authored by: Mike D. Day <ncmike@us.ibm.com>
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/kobject.h>
++#include <xen/hypervisor_sysfs.h>
++#include <asm/hypervisor.h>
++
++static ssize_t hyp_sysfs_show(struct kobject *kobj,
++                            struct attribute *attr,
++                            char *buffer)
++{
++      struct hyp_sysfs_attr *hyp_attr;
++      hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
++      if (hyp_attr->show)
++              return hyp_attr->show(hyp_attr, buffer);
++      return 0;
++}
++
++static ssize_t hyp_sysfs_store(struct kobject *kobj,
++                             struct attribute *attr,
++                             const char *buffer,
++                             size_t len)
++{
++      struct hyp_sysfs_attr *hyp_attr;
++      hyp_attr = container_of(attr, struct hyp_sysfs_attr, attr);
++      if (hyp_attr->store)
++              return hyp_attr->store(hyp_attr, buffer, len);
++      return 0;
++}
++
++static struct sysfs_ops hyp_sysfs_ops = {
++      .show = hyp_sysfs_show,
++      .store = hyp_sysfs_store,
++};
++
++static struct kobj_type hyp_sysfs_kobj_type = {
++      .sysfs_ops = &hyp_sysfs_ops,
++};
++
++static int __init hypervisor_subsys_init(void)
++{
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      hypervisor_subsys.kset.kobj.ktype = &hyp_sysfs_kobj_type;
++      return 0;
++}
++
++device_initcall(hypervisor_subsys_init);
+--- linux-2.6.18.8/drivers/xen/core/machine_kexec.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/machine_kexec.c       2008-05-19 00:33:45.822787398 +0300
+@@ -0,0 +1,192 @@
++/*
++ * drivers/xen/core/machine_kexec.c 
++ * handle transition of Linux booting another kernel
++ */
++
++#include <linux/kexec.h>
++#include <xen/interface/kexec.h>
++#include <linux/mm.h>
++#include <linux/bootmem.h>
++
++extern void machine_kexec_setup_load_arg(xen_kexec_image_t *xki, 
++                                       struct kimage *image);
++extern int machine_kexec_setup_resources(struct resource *hypervisor,
++                                       struct resource *phys_cpus,
++                                       int nr_phys_cpus);
++extern void machine_kexec_register_resources(struct resource *res);
++
++static int __initdata xen_max_nr_phys_cpus;
++static struct resource xen_hypervisor_res;
++static struct resource *xen_phys_cpus;
++
++void __init xen_machine_kexec_setup_resources(void)
++{
++      xen_kexec_range_t range;
++      struct resource *res;
++      int k = 0;
++
++      if (!is_initial_xendomain())
++              return;
++
++      /* determine maximum number of physical cpus */
++
++      while (1) {
++              memset(&range, 0, sizeof(range));
++              range.range = KEXEC_RANGE_MA_CPU;
++              range.nr = k;
++
++              if(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
++                      break;
++
++              k++;
++      }
++
++      if (k == 0)
++              return;
++
++      xen_max_nr_phys_cpus = k;
++
++      /* allocate xen_phys_cpus */
++
++      xen_phys_cpus = alloc_bootmem_low(k * sizeof(struct resource));
++      BUG_ON(xen_phys_cpus == NULL);
++
++      /* fill in xen_phys_cpus with per-cpu crash note information */
++
++      for (k = 0; k < xen_max_nr_phys_cpus; k++) {
++              memset(&range, 0, sizeof(range));
++              range.range = KEXEC_RANGE_MA_CPU;
++              range.nr = k;
++
++              if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
++                      goto err;
++
++              res = xen_phys_cpus + k;
++
++              memset(res, 0, sizeof(*res));
++              res->name = "Crash note";
++              res->start = range.start;
++              res->end = range.start + range.size - 1;
++              res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
++      }
++
++      /* fill in xen_hypervisor_res with hypervisor machine address range */
++
++      memset(&range, 0, sizeof(range));
++      range.range = KEXEC_RANGE_MA_XEN;
++
++      if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
++              goto err;
++
++      xen_hypervisor_res.name = "Hypervisor code and data";
++      xen_hypervisor_res.start = range.start;
++      xen_hypervisor_res.end = range.start + range.size - 1;
++      xen_hypervisor_res.flags = IORESOURCE_BUSY | IORESOURCE_MEM;
++
++      /* fill in crashk_res if range is reserved by hypervisor */
++
++      memset(&range, 0, sizeof(range));
++      range.range = KEXEC_RANGE_MA_CRASH;
++
++      if (HYPERVISOR_kexec_op(KEXEC_CMD_kexec_get_range, &range))
++              goto err;
++
++      if (range.size) {
++              crashk_res.start = range.start;
++              crashk_res.end = range.start + range.size - 1;
++      }
++
++      if (machine_kexec_setup_resources(&xen_hypervisor_res, xen_phys_cpus,
++                                        xen_max_nr_phys_cpus))
++              goto err;
++
++      return;
++
++ err:
++      /*
++       * It isn't possible to free xen_phys_cpus this early in the
++       * boot. Failure at this stage is unexpected and the amount of
++       * memory is small therefore we tolerate the potential leak.
++         */
++      xen_max_nr_phys_cpus = 0;
++      return;
++}
++
++void __init xen_machine_kexec_register_resources(struct resource *res)
++{
++      request_resource(res, &xen_hypervisor_res);
++      machine_kexec_register_resources(res);
++}
++
++static void setup_load_arg(xen_kexec_image_t *xki, struct kimage *image)
++{
++      machine_kexec_setup_load_arg(xki, image);
++
++      xki->indirection_page = image->head;
++      xki->start_address = image->start;
++}
++
++/*
++ * Load the image into xen so xen can kdump itself
++ * This might have been done in prepare, but prepare
++ * is currently called too early. It might make sense
++ * to move prepare, but for now, just add an extra hook.
++ */
++int xen_machine_kexec_load(struct kimage *image)
++{
++      xen_kexec_load_t xkl;
++
++      memset(&xkl, 0, sizeof(xkl));
++      xkl.type = image->type;
++      setup_load_arg(&xkl.image, image);
++      return HYPERVISOR_kexec_op(KEXEC_CMD_kexec_load, &xkl);
++}
++
++/*
++ * Unload the image that was stored by machine_kexec_load()
++ * This might have been done in machine_kexec_cleanup() but it
++ * is called too late, and its possible xen could try and kdump
++ * using resources that have been freed.
++ */
++void xen_machine_kexec_unload(struct kimage *image)
++{
++      xen_kexec_load_t xkl;
++
++      memset(&xkl, 0, sizeof(xkl));
++      xkl.type = image->type;
++      WARN_ON(HYPERVISOR_kexec_op(KEXEC_CMD_kexec_unload, &xkl));
++}
++
++/*
++ * Do not allocate memory (or fail in any way) in machine_kexec().
++ * We are past the point of no return, committed to rebooting now.
++ *
++ * This has the hypervisor move to the prefered reboot CPU, 
++ * stop all CPUs and kexec. That is it combines machine_shutdown()
++ * and machine_kexec() in Linux kexec terms.
++ */
++NORET_TYPE void machine_kexec(struct kimage *image)
++{
++      xen_kexec_exec_t xke;
++
++      memset(&xke, 0, sizeof(xke));
++      xke.type = image->type;
++      VOID(HYPERVISOR_kexec_op(KEXEC_CMD_kexec, &xke));
++      panic("KEXEC_CMD_kexec hypercall should not return\n");
++}
++
++void machine_shutdown(void)
++{
++      /* do nothing */
++}
++
++
++/*
++ * Local variables:
++ *  c-file-style: "linux"
++ *  indent-tabs-mode: t
++ *  c-indent-level: 8
++ *  c-basic-offset: 8
++ *  tab-width: 8
++ * End:
++ */
+--- linux-2.6.18.8/drivers/xen/core/machine_reboot.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/machine_reboot.c      2008-05-19 00:33:45.822787398 +0300
+@@ -0,0 +1,252 @@
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/unistd.h>
++#include <linux/module.h>
++#include <linux/reboot.h>
++#include <linux/sysrq.h>
++#include <linux/stringify.h>
++#include <linux/stop_machine.h>
++#include <asm/irq.h>
++#include <asm/mmu_context.h>
++#include <xen/evtchn.h>
++#include <asm/hypervisor.h>
++#include <xen/xenbus.h>
++#include <linux/cpu.h>
++#include <xen/gnttab.h>
++#include <xen/xencons.h>
++#include <xen/cpu_hotplug.h>
++#include <xen/interface/vcpu.h>
++
++#if defined(__i386__) || defined(__x86_64__)
++
++/*
++ * Power off function, if any
++ */
++void (*pm_power_off)(void);
++EXPORT_SYMBOL(pm_power_off);
++
++void machine_emergency_restart(void)
++{
++      /* We really want to get pending console data out before we die. */
++      xencons_force_flush();
++      HYPERVISOR_shutdown(SHUTDOWN_reboot);
++}
++
++void machine_restart(char * __unused)
++{
++      machine_emergency_restart();
++}
++
++void machine_halt(void)
++{
++      machine_power_off();
++}
++
++void machine_power_off(void)
++{
++      /* We really want to get pending console data out before we die. */
++      xencons_force_flush();
++      if (pm_power_off)
++              pm_power_off();
++      HYPERVISOR_shutdown(SHUTDOWN_poweroff);
++}
++
++int reboot_thru_bios = 0;     /* for dmi_scan.c */
++EXPORT_SYMBOL(machine_restart);
++EXPORT_SYMBOL(machine_halt);
++EXPORT_SYMBOL(machine_power_off);
++
++static void pre_suspend(void)
++{
++      HYPERVISOR_shared_info = (shared_info_t *)empty_zero_page;
++      WARN_ON(HYPERVISOR_update_va_mapping(fix_to_virt(FIX_SHARED_INFO),
++                                           __pte_ma(0), 0));
++
++      xen_start_info->store_mfn = mfn_to_pfn(xen_start_info->store_mfn);
++      xen_start_info->console.domU.mfn =
++              mfn_to_pfn(xen_start_info->console.domU.mfn);
++}
++
++static void post_suspend(int suspend_cancelled)
++{
++      int i, j, k, fpp;
++      unsigned long shinfo_mfn;
++      extern unsigned long max_pfn;
++      extern unsigned long *pfn_to_mfn_frame_list_list;
++      extern unsigned long *pfn_to_mfn_frame_list[];
++
++      if (suspend_cancelled) {
++              xen_start_info->store_mfn =
++                      pfn_to_mfn(xen_start_info->store_mfn);
++              xen_start_info->console.domU.mfn =
++                      pfn_to_mfn(xen_start_info->console.domU.mfn);
++      } else {
++#ifdef CONFIG_SMP
++              cpu_initialized_map = cpu_online_map;
++#endif
++      }
++
++      shinfo_mfn = xen_start_info->shared_info >> PAGE_SHIFT;
++      if (HYPERVISOR_update_va_mapping(fix_to_virt(FIX_SHARED_INFO),
++                                       pfn_pte_ma(shinfo_mfn, PAGE_KERNEL),
++                                       0))
++              BUG();
++      HYPERVISOR_shared_info = (shared_info_t *)fix_to_virt(FIX_SHARED_INFO);
++
++      memset(empty_zero_page, 0, PAGE_SIZE);
++
++      fpp = PAGE_SIZE/sizeof(unsigned long);
++      for (i = 0, j = 0, k = -1; i < max_pfn; i += fpp, j++) {
++              if ((j % fpp) == 0) {
++                      k++;
++                      pfn_to_mfn_frame_list_list[k] =
++                              virt_to_mfn(pfn_to_mfn_frame_list[k]);
++                      j = 0;
++              }
++              pfn_to_mfn_frame_list[k][j] =
++                      virt_to_mfn(&phys_to_machine_mapping[i]);
++      }
++      HYPERVISOR_shared_info->arch.max_pfn = max_pfn;
++      HYPERVISOR_shared_info->arch.pfn_to_mfn_frame_list_list =
++              virt_to_mfn(pfn_to_mfn_frame_list_list);
++}
++
++#else /* !(defined(__i386__) || defined(__x86_64__)) */
++
++#ifndef HAVE_XEN_PRE_SUSPEND
++#define xen_pre_suspend()     ((void)0)
++#endif
++
++#ifndef HAVE_XEN_POST_SUSPEND
++#define xen_post_suspend(x)   ((void)0)
++#endif
++
++#define switch_idle_mm()      ((void)0)
++#define mm_pin_all()          ((void)0)
++#define pre_suspend()         xen_pre_suspend()
++#define post_suspend(x)               xen_post_suspend(x)
++
++#endif
++
++struct suspend {
++      int fast_suspend;
++      void (*resume_notifier)(void);
++};
++
++static int take_machine_down(void *_suspend)
++{
++      struct suspend *suspend = _suspend;
++      int suspend_cancelled, err;
++      extern void time_resume(void);
++
++      if (suspend->fast_suspend) {
++              BUG_ON(!irqs_disabled());
++      } else {
++              BUG_ON(irqs_disabled());
++
++              for (;;) {
++                      err = smp_suspend();
++                      if (err)
++                              return err;
++
++                      xenbus_suspend();
++                      preempt_disable();
++
++                      if (num_online_cpus() == 1)
++                              break;
++
++                      preempt_enable();
++                      xenbus_suspend_cancel();
++              }
++
++              local_irq_disable();
++      }
++
++      mm_pin_all();
++      gnttab_suspend();
++      pre_suspend();
++
++      /*
++       * This hypercall returns 1 if suspend was cancelled or the domain was
++       * merely checkpointed, and 0 if it is resuming in a new domain.
++       */
++      suspend_cancelled = HYPERVISOR_suspend(virt_to_mfn(xen_start_info));
++
++      suspend->resume_notifier();
++      post_suspend(suspend_cancelled);
++      gnttab_resume();
++      if (!suspend_cancelled) {
++              irq_resume();
++#ifdef __x86_64__
++              /*
++               * Older versions of Xen do not save/restore the user %cr3.
++               * We do it here just in case, but there's no need if we are
++               * in fast-suspend mode as that implies a new enough Xen.
++               */
++              if (!suspend->fast_suspend) {
++                      struct mmuext_op op;
++                      op.cmd = MMUEXT_NEW_USER_BASEPTR;
++                      op.arg1.mfn = pfn_to_mfn(__pa(__user_pgd(
++                              current->active_mm->pgd)) >> PAGE_SHIFT);
++                      if (HYPERVISOR_mmuext_op(&op, 1, NULL, DOMID_SELF))
++                              BUG();
++              }
++#endif
++      }
++      time_resume();
++
++      if (!suspend->fast_suspend)
++              local_irq_enable();
++
++      return suspend_cancelled;
++}
++
++int __xen_suspend(int fast_suspend, void (*resume_notifier)(void))
++{
++      int err, suspend_cancelled;
++      struct suspend suspend;
++
++      BUG_ON(smp_processor_id() != 0);
++      BUG_ON(in_interrupt());
++
++#if defined(__i386__) || defined(__x86_64__)
++      if (xen_feature(XENFEAT_auto_translated_physmap)) {
++              printk(KERN_WARNING "Cannot suspend in "
++                     "auto_translated_physmap mode.\n");
++              return -EOPNOTSUPP;
++      }
++#endif
++
++      /* If we are definitely UP then 'slow mode' is actually faster. */
++      if (num_possible_cpus() == 1)
++              fast_suspend = 0;
++
++      suspend.fast_suspend = fast_suspend;
++      suspend.resume_notifier = resume_notifier;
++
++      if (fast_suspend) {
++              xenbus_suspend();
++              err = stop_machine_run(take_machine_down, &suspend, 0);
++              if (err < 0)
++                      xenbus_suspend_cancel();
++      } else {
++              err = take_machine_down(&suspend);
++      }
++
++      if (err < 0)
++              return err;
++
++      suspend_cancelled = err;
++      if (!suspend_cancelled) {
++              xencons_resume();
++              xenbus_resume();
++      } else {
++              xenbus_suspend_cancel();
++      }
++
++      if (!fast_suspend)
++              smp_resume();
++
++      return 0;
++}
+--- linux-2.6.18.8/drivers/xen/core/reboot.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/reboot.c      2008-05-19 00:33:45.822787398 +0300
+@@ -0,0 +1,272 @@
++#define __KERNEL_SYSCALLS__
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/unistd.h>
++#include <linux/module.h>
++#include <linux/reboot.h>
++#include <linux/sysrq.h>
++#include <asm/hypervisor.h>
++#include <xen/xenbus.h>
++#include <linux/kmod.h>
++#include <linux/slab.h>
++#include <linux/workqueue.h>
++
++#ifdef HAVE_XEN_PLATFORM_COMPAT_H
++#include <xen/platform-compat.h>
++#endif
++
++MODULE_LICENSE("Dual BSD/GPL");
++
++#define SHUTDOWN_INVALID  -1
++#define SHUTDOWN_POWEROFF  0
++#define SHUTDOWN_SUSPEND   2
++#define SHUTDOWN_RESUMING  3
++#define SHUTDOWN_HALT      4
++
++/* Ignore multiple shutdown requests. */
++static int shutting_down = SHUTDOWN_INVALID;
++
++/* Can we leave APs online when we suspend? */
++static int fast_suspend;
++
++static void __shutdown_handler(void *unused);
++static DECLARE_WORK(shutdown_work, __shutdown_handler, NULL);
++
++int __xen_suspend(int fast_suspend, void (*resume_notifier)(void));
++
++static int shutdown_process(void *__unused)
++{
++      static char *envp[] = { "HOME=/", "TERM=linux",
++                              "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
++      static char *poweroff_argv[] = { "/sbin/poweroff", NULL };
++
++      extern asmlinkage long sys_reboot(int magic1, int magic2,
++                                        unsigned int cmd, void *arg);
++
++      if ((shutting_down == SHUTDOWN_POWEROFF) ||
++          (shutting_down == SHUTDOWN_HALT)) {
++              if (call_usermodehelper("/sbin/poweroff", poweroff_argv,
++                                      envp, 0) < 0) {
++#ifdef CONFIG_XEN
++                      sys_reboot(LINUX_REBOOT_MAGIC1,
++                                 LINUX_REBOOT_MAGIC2,
++                                 LINUX_REBOOT_CMD_POWER_OFF,
++                                 NULL);
++#endif /* CONFIG_XEN */
++              }
++      }
++
++      shutting_down = SHUTDOWN_INVALID; /* could try again */
++
++      return 0;
++}
++
++static void xen_resume_notifier(void)
++{
++      int old_state = xchg(&shutting_down, SHUTDOWN_RESUMING);
++      BUG_ON(old_state != SHUTDOWN_SUSPEND);
++}
++
++static int xen_suspend(void *__unused)
++{
++      int err, old_state;
++
++      daemonize("suspend");
++      err = set_cpus_allowed(current, cpumask_of_cpu(0));
++      if (err) {
++              printk(KERN_ERR "Xen suspend can't run on CPU0 (%d)\n", err);
++              goto fail;
++      }
++
++      do {
++              err = __xen_suspend(fast_suspend, xen_resume_notifier);
++              if (err) {
++                      printk(KERN_ERR "Xen suspend failed (%d)\n", err);
++                      goto fail;
++              }
++              old_state = cmpxchg(
++                      &shutting_down, SHUTDOWN_RESUMING, SHUTDOWN_INVALID);
++      } while (old_state == SHUTDOWN_SUSPEND);
++
++      switch (old_state) {
++      case SHUTDOWN_INVALID:
++      case SHUTDOWN_SUSPEND:
++              BUG();
++      case SHUTDOWN_RESUMING:
++              break;
++      default:
++              schedule_work(&shutdown_work);
++              break;
++      }
++
++      return 0;
++
++ fail:
++      old_state = xchg(&shutting_down, SHUTDOWN_INVALID);
++      BUG_ON(old_state != SHUTDOWN_SUSPEND);
++      return 0;
++}
++
++static void __shutdown_handler(void *unused)
++{
++      int err;
++
++      err = kernel_thread((shutting_down == SHUTDOWN_SUSPEND) ?
++                          xen_suspend : shutdown_process,
++                          NULL, CLONE_FS | CLONE_FILES);
++
++      if (err < 0) {
++              printk(KERN_WARNING "Error creating shutdown process (%d): "
++                     "retrying...\n", -err);
++              schedule_delayed_work(&shutdown_work, HZ/2);
++      }
++}
++
++static void shutdown_handler(struct xenbus_watch *watch,
++                           const char **vec, unsigned int len)
++{
++      extern void ctrl_alt_del(void);
++      char *str;
++      struct xenbus_transaction xbt;
++      int err, old_state, new_state = SHUTDOWN_INVALID;
++
++      if ((shutting_down != SHUTDOWN_INVALID) &&
++          (shutting_down != SHUTDOWN_RESUMING))
++              return;
++
++ again:
++      err = xenbus_transaction_start(&xbt);
++      if (err)
++              return;
++
++      str = (char *)xenbus_read(xbt, "control", "shutdown", NULL);
++      /* Ignore read errors and empty reads. */
++      if (XENBUS_IS_ERR_READ(str)) {
++              xenbus_transaction_end(xbt, 1);
++              return;
++      }
++
++      xenbus_write(xbt, "control", "shutdown", "");
++
++      err = xenbus_transaction_end(xbt, 0);
++      if (err == -EAGAIN) {
++              kfree(str);
++              goto again;
++      }
++
++      if (strcmp(str, "poweroff") == 0)
++              new_state = SHUTDOWN_POWEROFF;
++      else if (strcmp(str, "reboot") == 0)
++              ctrl_alt_del();
++      else if (strcmp(str, "suspend") == 0)
++              new_state = SHUTDOWN_SUSPEND;
++      else if (strcmp(str, "halt") == 0)
++              new_state = SHUTDOWN_HALT;
++      else
++              printk("Ignoring shutdown request: %s\n", str);
++
++      if (new_state != SHUTDOWN_INVALID) {
++              old_state = xchg(&shutting_down, new_state);
++              if (old_state == SHUTDOWN_INVALID)
++                      schedule_work(&shutdown_work);
++              else
++                      BUG_ON(old_state != SHUTDOWN_RESUMING);
++      }
++
++      kfree(str);
++}
++
++static void sysrq_handler(struct xenbus_watch *watch, const char **vec,
++                        unsigned int len)
++{
++      char sysrq_key = '\0';
++      struct xenbus_transaction xbt;
++      int err;
++
++ again:
++      err = xenbus_transaction_start(&xbt);
++      if (err)
++              return;
++      if (!xenbus_scanf(xbt, "control", "sysrq", "%c", &sysrq_key)) {
++              printk(KERN_ERR "Unable to read sysrq code in "
++                     "control/sysrq\n");
++              xenbus_transaction_end(xbt, 1);
++              return;
++      }
++
++      if (sysrq_key != '\0')
++              xenbus_printf(xbt, "control", "sysrq", "%c", '\0');
++
++      err = xenbus_transaction_end(xbt, 0);
++      if (err == -EAGAIN)
++              goto again;
++
++#ifdef CONFIG_MAGIC_SYSRQ
++      if (sysrq_key != '\0')
++              handle_sysrq(sysrq_key, NULL, NULL);
++#endif
++}
++
++static struct xenbus_watch shutdown_watch = {
++      .node = "control/shutdown",
++      .callback = shutdown_handler
++};
++
++static struct xenbus_watch sysrq_watch = {
++      .node = "control/sysrq",
++      .callback = sysrq_handler
++};
++
++static int setup_shutdown_watcher(void)
++{
++      int err;
++
++      xenbus_scanf(XBT_NIL, "control",
++                   "platform-feature-multiprocessor-suspend",
++                   "%d", &fast_suspend);
++
++      err = register_xenbus_watch(&shutdown_watch);
++      if (err) {
++              printk(KERN_ERR "Failed to set shutdown watcher\n");
++              return err;
++      }
++
++      err = register_xenbus_watch(&sysrq_watch);
++      if (err) {
++              printk(KERN_ERR "Failed to set sysrq watcher\n");
++              return err;
++      }
++
++      return 0;
++}
++
++#ifdef CONFIG_XEN
++
++static int shutdown_event(struct notifier_block *notifier,
++                        unsigned long event,
++                        void *data)
++{
++      setup_shutdown_watcher();
++      return NOTIFY_DONE;
++}
++
++static int __init setup_shutdown_event(void)
++{
++      static struct notifier_block xenstore_notifier = {
++              .notifier_call = shutdown_event
++      };
++      register_xenstore_notifier(&xenstore_notifier);
++
++      return 0;
++}
++
++subsys_initcall(setup_shutdown_event);
++
++#else /* !defined(CONFIG_XEN) */
++
++int xen_reboot_init(void)
++{
++      return setup_shutdown_watcher();
++}
++
++#endif /* !defined(CONFIG_XEN) */
+--- linux-2.6.18.8/drivers/xen/core/smpboot.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/smpboot.c     2008-05-19 00:33:45.826787629 +0300
+@@ -0,0 +1,464 @@
++/*
++ *    Xen SMP booting functions
++ *
++ *    See arch/i386/kernel/smpboot.c for copyright and credits for derived
++ *    portions of this file.
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/sched.h>
++#include <linux/kernel_stat.h>
++#include <linux/smp_lock.h>
++#include <linux/irq.h>
++#include <linux/bootmem.h>
++#include <linux/notifier.h>
++#include <linux/cpu.h>
++#include <linux/percpu.h>
++#include <asm/desc.h>
++#include <asm/arch_hooks.h>
++#include <asm/pgalloc.h>
++#include <xen/evtchn.h>
++#include <xen/interface/vcpu.h>
++#include <xen/cpu_hotplug.h>
++#include <xen/xenbus.h>
++
++extern irqreturn_t smp_reschedule_interrupt(int, void *, struct pt_regs *);
++extern irqreturn_t smp_call_function_interrupt(int, void *, struct pt_regs *);
++
++extern int local_setup_timer(unsigned int cpu);
++extern void local_teardown_timer(unsigned int cpu);
++
++extern void hypervisor_callback(void);
++extern void failsafe_callback(void);
++extern void system_call(void);
++extern void smp_trap_init(trap_info_t *);
++
++/* Number of siblings per CPU package */
++int smp_num_siblings = 1;
++
++cpumask_t cpu_online_map;
++EXPORT_SYMBOL(cpu_online_map);
++cpumask_t cpu_possible_map;
++EXPORT_SYMBOL(cpu_possible_map);
++cpumask_t cpu_initialized_map;
++
++struct cpuinfo_x86 cpu_data[NR_CPUS] __cacheline_aligned;
++EXPORT_SYMBOL(cpu_data);
++
++#ifdef CONFIG_HOTPLUG_CPU
++DEFINE_PER_CPU(int, cpu_state) = { 0 };
++#endif
++
++static DEFINE_PER_CPU(int, resched_irq);
++static DEFINE_PER_CPU(int, callfunc_irq);
++static char resched_name[NR_CPUS][15];
++static char callfunc_name[NR_CPUS][15];
++
++u8 cpu_2_logical_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = BAD_APICID };
++
++cpumask_t cpu_sibling_map[NR_CPUS] __cacheline_aligned;
++cpumask_t cpu_core_map[NR_CPUS] __cacheline_aligned;
++EXPORT_SYMBOL(cpu_core_map);
++
++#if defined(__i386__)
++u8 x86_cpu_to_apicid[NR_CPUS] = { [0 ... NR_CPUS-1] = 0xff };
++EXPORT_SYMBOL(x86_cpu_to_apicid);
++#elif !defined(CONFIG_X86_IO_APIC)
++unsigned int maxcpus = NR_CPUS;
++#endif
++
++void __init prefill_possible_map(void)
++{
++      int i, rc;
++
++      for_each_possible_cpu(i)
++          if (i != smp_processor_id())
++              return;
++
++      for (i = 0; i < NR_CPUS; i++) {
++              rc = HYPERVISOR_vcpu_op(VCPUOP_is_up, i, NULL);
++              if (rc >= 0)
++                      cpu_set(i, cpu_possible_map);
++      }
++}
++
++void __init smp_alloc_memory(void)
++{
++}
++
++static inline void
++set_cpu_sibling_map(unsigned int cpu)
++{
++      cpu_data[cpu].phys_proc_id = cpu;
++      cpu_data[cpu].cpu_core_id  = 0;
++
++      cpu_sibling_map[cpu] = cpumask_of_cpu(cpu);
++      cpu_core_map[cpu]    = cpumask_of_cpu(cpu);
++
++      cpu_data[cpu].booted_cores = 1;
++}
++
++static void
++remove_siblinginfo(unsigned int cpu)
++{
++      cpu_data[cpu].phys_proc_id = BAD_APICID;
++      cpu_data[cpu].cpu_core_id  = BAD_APICID;
++
++      cpus_clear(cpu_sibling_map[cpu]);
++      cpus_clear(cpu_core_map[cpu]);
++
++      cpu_data[cpu].booted_cores = 0;
++}
++
++static int __cpuinit xen_smp_intr_init(unsigned int cpu)
++{
++      int rc;
++
++      per_cpu(resched_irq, cpu) = per_cpu(callfunc_irq, cpu) = -1;
++
++      sprintf(resched_name[cpu], "resched%u", cpu);
++      rc = bind_ipi_to_irqhandler(RESCHEDULE_VECTOR,
++                                  cpu,
++                                  smp_reschedule_interrupt,
++                                  SA_INTERRUPT,
++                                  resched_name[cpu],
++                                  NULL);
++      if (rc < 0)
++              goto fail;
++      per_cpu(resched_irq, cpu) = rc;
++
++      sprintf(callfunc_name[cpu], "callfunc%u", cpu);
++      rc = bind_ipi_to_irqhandler(CALL_FUNCTION_VECTOR,
++                                  cpu,
++                                  smp_call_function_interrupt,
++                                  SA_INTERRUPT,
++                                  callfunc_name[cpu],
++                                  NULL);
++      if (rc < 0)
++              goto fail;
++      per_cpu(callfunc_irq, cpu) = rc;
++
++      if ((cpu != 0) && ((rc = local_setup_timer(cpu)) != 0))
++              goto fail;
++
++      return 0;
++
++ fail:
++      if (per_cpu(resched_irq, cpu) >= 0)
++              unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
++      if (per_cpu(callfunc_irq, cpu) >= 0)
++              unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
++      return rc;
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++static void xen_smp_intr_exit(unsigned int cpu)
++{
++      if (cpu != 0)
++              local_teardown_timer(cpu);
++
++      unbind_from_irqhandler(per_cpu(resched_irq, cpu), NULL);
++      unbind_from_irqhandler(per_cpu(callfunc_irq, cpu), NULL);
++}
++#endif
++
++void __cpuinit cpu_bringup(void)
++{
++      cpu_init();
++      identify_cpu(cpu_data + smp_processor_id());
++      touch_softlockup_watchdog();
++      preempt_disable();
++      local_irq_enable();
++}
++
++static void __cpuinit cpu_bringup_and_idle(void)
++{
++      cpu_bringup();
++      cpu_idle();
++}
++
++static void __cpuinit cpu_initialize_context(unsigned int cpu)
++{
++      /* vcpu_guest_context_t is too large to allocate on the stack.
++       * Hence we allocate statically and protect it with a lock */
++      static vcpu_guest_context_t ctxt;
++      static DEFINE_SPINLOCK(ctxt_lock);
++
++      struct task_struct *idle = idle_task(cpu);
++#ifdef __x86_64__
++      struct desc_ptr *gdt_descr = &cpu_gdt_descr[cpu];
++#else
++      struct Xgt_desc_struct *gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
++#endif
++
++      if (cpu_test_and_set(cpu, cpu_initialized_map))
++              return;
++
++      spin_lock(&ctxt_lock);
++
++      memset(&ctxt, 0, sizeof(ctxt));
++
++      ctxt.flags = VGCF_IN_KERNEL;
++      ctxt.user_regs.ds = __USER_DS;
++      ctxt.user_regs.es = __USER_DS;
++      ctxt.user_regs.fs = 0;
++      ctxt.user_regs.gs = 0;
++      ctxt.user_regs.ss = __KERNEL_DS;
++      ctxt.user_regs.eip = (unsigned long)cpu_bringup_and_idle;
++      ctxt.user_regs.eflags = X86_EFLAGS_IF | 0x1000; /* IOPL_RING1 */
++
++      memset(&ctxt.fpu_ctxt, 0, sizeof(ctxt.fpu_ctxt));
++
++      smp_trap_init(ctxt.trap_ctxt);
++
++      ctxt.ldt_ents = 0;
++
++      ctxt.gdt_frames[0] = virt_to_mfn(gdt_descr->address);
++      ctxt.gdt_ents      = gdt_descr->size / 8;
++
++#ifdef __i386__
++      ctxt.user_regs.cs = __KERNEL_CS;
++      ctxt.user_regs.esp = idle->thread.esp0 - sizeof(struct pt_regs);
++
++      ctxt.kernel_ss = __KERNEL_DS;
++      ctxt.kernel_sp = idle->thread.esp0;
++
++      ctxt.event_callback_cs     = __KERNEL_CS;
++      ctxt.event_callback_eip    = (unsigned long)hypervisor_callback;
++      ctxt.failsafe_callback_cs  = __KERNEL_CS;
++      ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
++
++      ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(swapper_pg_dir));
++#else /* __x86_64__ */
++      ctxt.user_regs.cs = __KERNEL_CS;
++      ctxt.user_regs.esp = idle->thread.rsp0 - sizeof(struct pt_regs);
++
++      ctxt.kernel_ss = __KERNEL_DS;
++      ctxt.kernel_sp = idle->thread.rsp0;
++
++      ctxt.event_callback_eip    = (unsigned long)hypervisor_callback;
++      ctxt.failsafe_callback_eip = (unsigned long)failsafe_callback;
++      ctxt.syscall_callback_eip  = (unsigned long)system_call;
++
++      ctxt.ctrlreg[3] = xen_pfn_to_cr3(virt_to_mfn(init_level4_pgt));
++
++      ctxt.gs_base_kernel = (unsigned long)(cpu_pda(cpu));
++#endif
++
++      if (HYPERVISOR_vcpu_op(VCPUOP_initialise, cpu, &ctxt))
++              BUG();
++
++      spin_unlock(&ctxt_lock);
++}
++
++void __init smp_prepare_cpus(unsigned int max_cpus)
++{
++      unsigned int cpu;
++      struct task_struct *idle;
++      int apicid, acpiid;
++      struct vcpu_get_physid cpu_id;
++#ifdef __x86_64__
++      struct desc_ptr *gdt_descr;
++#else
++      struct Xgt_desc_struct *gdt_descr;
++#endif
++
++      apicid = 0;
++      if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, 0, &cpu_id) == 0) {
++              apicid = xen_vcpu_physid_to_x86_apicid(cpu_id.phys_id);
++              acpiid = xen_vcpu_physid_to_x86_acpiid(cpu_id.phys_id);
++#ifdef CONFIG_ACPI
++              if (acpiid != 0xff)
++                      x86_acpiid_to_apicid[acpiid] = apicid;
++#endif
++      }
++      boot_cpu_data.apicid = apicid;
++      cpu_data[0] = boot_cpu_data;
++
++      cpu_2_logical_apicid[0] = apicid;
++      x86_cpu_to_apicid[0] = apicid;
++
++      current_thread_info()->cpu = 0;
++
++      for (cpu = 0; cpu < NR_CPUS; cpu++) {
++              cpus_clear(cpu_sibling_map[cpu]);
++              cpus_clear(cpu_core_map[cpu]);
++      }
++
++      set_cpu_sibling_map(0);
++
++      if (xen_smp_intr_init(0))
++              BUG();
++
++      cpu_initialized_map = cpumask_of_cpu(0);
++
++      /* Restrict the possible_map according to max_cpus. */
++      while ((num_possible_cpus() > 1) && (num_possible_cpus() > max_cpus)) {
++              for (cpu = NR_CPUS-1; !cpu_isset(cpu, cpu_possible_map); cpu--)
++                      continue;
++              cpu_clear(cpu, cpu_possible_map);
++      }
++
++      for_each_possible_cpu (cpu) {
++              if (cpu == 0)
++                      continue;
++
++#ifdef __x86_64__
++              gdt_descr = &cpu_gdt_descr[cpu];
++#else
++              gdt_descr = &per_cpu(cpu_gdt_descr, cpu);
++#endif
++              gdt_descr->address = get_zeroed_page(GFP_KERNEL);
++              if (unlikely(!gdt_descr->address)) {
++                      printk(KERN_CRIT "CPU%d failed to allocate GDT\n",
++                             cpu);
++                      continue;
++              }
++              gdt_descr->size = GDT_SIZE;
++              memcpy((void *)gdt_descr->address, cpu_gdt_table, GDT_SIZE);
++              make_page_readonly(
++                      (void *)gdt_descr->address,
++                      XENFEAT_writable_descriptor_tables);
++
++              apicid = cpu;
++              if (HYPERVISOR_vcpu_op(VCPUOP_get_physid, cpu, &cpu_id) == 0) {
++                      apicid = xen_vcpu_physid_to_x86_apicid(cpu_id.phys_id);
++                      acpiid = xen_vcpu_physid_to_x86_acpiid(cpu_id.phys_id);
++#ifdef CONFIG_ACPI
++                      if (acpiid != 0xff)
++                              x86_acpiid_to_apicid[acpiid] = apicid;
++#endif
++              }
++              cpu_data[cpu] = boot_cpu_data;
++              cpu_data[cpu].apicid = apicid;
++
++              cpu_2_logical_apicid[cpu] = apicid;
++              x86_cpu_to_apicid[cpu] = apicid;
++
++              idle = fork_idle(cpu);
++              if (IS_ERR(idle))
++                      panic("failed fork for CPU %d", cpu);
++
++#ifdef __x86_64__
++              cpu_pda(cpu)->pcurrent = idle;
++              cpu_pda(cpu)->cpunumber = cpu;
++              clear_ti_thread_flag(idle->thread_info, TIF_FORK);
++#endif
++
++              irq_ctx_init(cpu);
++
++#ifdef CONFIG_HOTPLUG_CPU
++              if (is_initial_xendomain())
++                      cpu_set(cpu, cpu_present_map);
++#else
++              cpu_set(cpu, cpu_present_map);
++#endif
++      }
++
++      init_xenbus_allowed_cpumask();
++
++#ifdef CONFIG_X86_IO_APIC
++      /*
++       * Here we can be sure that there is an IO-APIC in the system. Let's
++       * go and set it up:
++       */
++      if (!skip_ioapic_setup && nr_ioapics)
++              setup_IO_APIC();
++#endif
++}
++
++void __devinit smp_prepare_boot_cpu(void)
++{
++      prefill_possible_map();
++}
++
++#ifdef CONFIG_HOTPLUG_CPU
++
++/*
++ * Initialize cpu_present_map late to skip SMP boot code in init/main.c.
++ * But do it early enough to catch critical for_each_present_cpu() loops
++ * in i386-specific code.
++ */
++static int __init initialize_cpu_present_map(void)
++{
++      cpu_present_map = cpu_possible_map;
++      return 0;
++}
++core_initcall(initialize_cpu_present_map);
++
++int __cpu_disable(void)
++{
++      cpumask_t map = cpu_online_map;
++      unsigned int cpu = smp_processor_id();
++
++      if (cpu == 0)
++              return -EBUSY;
++
++      remove_siblinginfo(cpu);
++
++      cpu_clear(cpu, map);
++      fixup_irqs(map);
++      cpu_clear(cpu, cpu_online_map);
++
++      return 0;
++}
++
++void __cpu_die(unsigned int cpu)
++{
++      while (HYPERVISOR_vcpu_op(VCPUOP_is_up, cpu, NULL)) {
++              current->state = TASK_UNINTERRUPTIBLE;
++              schedule_timeout(HZ/10);
++      }
++
++      xen_smp_intr_exit(cpu);
++
++      if (num_online_cpus() == 1)
++              alternatives_smp_switch(0);
++}
++
++#endif /* CONFIG_HOTPLUG_CPU */
++
++int __cpuinit __cpu_up(unsigned int cpu)
++{
++      int rc;
++
++      rc = cpu_up_check(cpu);
++      if (rc)
++              return rc;
++
++      cpu_initialize_context(cpu);
++
++      if (num_online_cpus() == 1)
++              alternatives_smp_switch(1);
++
++      /* This must be done before setting cpu_online_map */
++      set_cpu_sibling_map(cpu);
++      wmb();
++
++      rc = xen_smp_intr_init(cpu);
++      if (rc) {
++              remove_siblinginfo(cpu);
++              return rc;
++      }
++
++      cpu_set(cpu, cpu_online_map);
++
++      rc = HYPERVISOR_vcpu_op(VCPUOP_up, cpu, NULL);
++      BUG_ON(rc);
++
++      return 0;
++}
++
++void __init smp_cpus_done(unsigned int max_cpus)
++{
++}
++
++#ifndef CONFIG_X86_LOCAL_APIC
++int setup_profiling_timer(unsigned int multiplier)
++{
++      return -EINVAL;
++}
++#endif
+--- linux-2.6.18.8/drivers/xen/core/xen_proc.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/xen_proc.c    2008-05-19 00:33:45.826787629 +0300
+@@ -0,0 +1,23 @@
++
++#include <linux/module.h>
++#include <linux/proc_fs.h>
++#include <xen/xen_proc.h>
++
++static struct proc_dir_entry *xen_base;
++
++struct proc_dir_entry *create_xen_proc_entry(const char *name, mode_t mode)
++{
++      if ( xen_base == NULL )
++              if ( (xen_base = proc_mkdir("xen", &proc_root)) == NULL )
++                      panic("Couldn't create /proc/xen");
++      return create_proc_entry(name, mode, xen_base);
++}
++
++EXPORT_SYMBOL_GPL(create_xen_proc_entry); 
++
++void remove_xen_proc_entry(const char *name)
++{
++      remove_proc_entry(name, xen_base);
++}
++
++EXPORT_SYMBOL_GPL(remove_xen_proc_entry); 
+--- linux-2.6.18.8/drivers/xen/core/xen_sysfs.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/xen_sysfs.c   2008-05-19 00:33:45.826787629 +0300
+@@ -0,0 +1,382 @@
++/*
++ *  copyright (c) 2006 IBM Corporation
++ *  Authored by: Mike D. Day <ncmike@us.ibm.com>
++ *
++ *  This program is free software; you can redistribute it and/or modify
++ *  it under the terms of the GNU General Public License version 2 as
++ *  published by the Free Software Foundation.
++ */
++
++#include <linux/err.h>
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <asm/hypervisor.h>
++#include <xen/features.h>
++#include <xen/hypervisor_sysfs.h>
++#include <xen/xenbus.h>
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Mike D. Day <ncmike@us.ibm.com>");
++
++static ssize_t type_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      return sprintf(buffer, "xen\n");
++}
++
++HYPERVISOR_ATTR_RO(type);
++
++static int __init xen_sysfs_type_init(void)
++{
++      return sysfs_create_file(&hypervisor_subsys.kset.kobj, &type_attr.attr);
++}
++
++static void xen_sysfs_type_destroy(void)
++{
++      sysfs_remove_file(&hypervisor_subsys.kset.kobj, &type_attr.attr);
++}
++
++/* xen version attributes */
++static ssize_t major_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      int version = HYPERVISOR_xen_version(XENVER_version, NULL);
++      if (version)
++              return sprintf(buffer, "%d\n", version >> 16);
++      return -ENODEV;
++}
++
++HYPERVISOR_ATTR_RO(major);
++
++static ssize_t minor_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      int version = HYPERVISOR_xen_version(XENVER_version, NULL);
++      if (version)
++              return sprintf(buffer, "%d\n", version & 0xff);
++      return -ENODEV;
++}
++
++HYPERVISOR_ATTR_RO(minor);
++
++static ssize_t extra_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      int ret = -ENOMEM;
++      char *extra;
++
++      extra = kmalloc(XEN_EXTRAVERSION_LEN, GFP_KERNEL);
++      if (extra) {
++              ret = HYPERVISOR_xen_version(XENVER_extraversion, extra);
++              if (!ret)
++                      ret = sprintf(buffer, "%s\n", extra);
++              kfree(extra);
++      }
++
++      return ret;
++}
++
++HYPERVISOR_ATTR_RO(extra);
++
++static struct attribute *version_attrs[] = {
++      &major_attr.attr,
++      &minor_attr.attr,
++      &extra_attr.attr,
++      NULL
++};
++
++static struct attribute_group version_group = {
++      .name = "version",
++      .attrs = version_attrs,
++};
++
++static int __init xen_sysfs_version_init(void)
++{
++      return sysfs_create_group(&hypervisor_subsys.kset.kobj,
++                                &version_group);
++}
++
++static void xen_sysfs_version_destroy(void)
++{
++      sysfs_remove_group(&hypervisor_subsys.kset.kobj, &version_group);
++}
++
++/* UUID */
++
++static ssize_t uuid_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      char *vm, *val;
++      int ret;
++      extern int xenstored_ready;
++
++      if (!xenstored_ready)
++              return -EBUSY;
++
++      vm = xenbus_read(XBT_NIL, "vm", "", NULL);
++      if (IS_ERR(vm))
++              return PTR_ERR(vm);
++      val = xenbus_read(XBT_NIL, vm, "uuid", NULL);
++      kfree(vm);
++      if (IS_ERR(val))
++              return PTR_ERR(val);
++      ret = sprintf(buffer, "%s\n", val);
++      kfree(val);
++      return ret;
++}
++
++HYPERVISOR_ATTR_RO(uuid);
++
++static int __init xen_sysfs_uuid_init(void)
++{
++      return sysfs_create_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr);
++}
++
++static void xen_sysfs_uuid_destroy(void)
++{
++      sysfs_remove_file(&hypervisor_subsys.kset.kobj, &uuid_attr.attr);
++}
++
++/* xen compilation attributes */
++
++static ssize_t compiler_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      int ret = -ENOMEM;
++      struct xen_compile_info *info;
++
++      info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
++      if (info) {
++              ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
++              if (!ret)
++                      ret = sprintf(buffer, "%s\n", info->compiler);
++              kfree(info);
++      }
++
++      return ret;
++}
++
++HYPERVISOR_ATTR_RO(compiler);
++
++static ssize_t compiled_by_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      int ret = -ENOMEM;
++      struct xen_compile_info *info;
++
++      info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
++      if (info) {
++              ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
++              if (!ret)
++                      ret = sprintf(buffer, "%s\n", info->compile_by);
++              kfree(info);
++      }
++
++      return ret;
++}
++
++HYPERVISOR_ATTR_RO(compiled_by);
++
++static ssize_t compile_date_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      int ret = -ENOMEM;
++      struct xen_compile_info *info;
++
++      info = kmalloc(sizeof(struct xen_compile_info), GFP_KERNEL);
++      if (info) {
++              ret = HYPERVISOR_xen_version(XENVER_compile_info, info);
++              if (!ret)
++                      ret = sprintf(buffer, "%s\n", info->compile_date);
++              kfree(info);
++      }
++
++      return ret;
++}
++
++HYPERVISOR_ATTR_RO(compile_date);
++
++static struct attribute *xen_compile_attrs[] = {
++      &compiler_attr.attr,
++      &compiled_by_attr.attr,
++      &compile_date_attr.attr,
++      NULL
++};
++
++static struct attribute_group xen_compilation_group = {
++      .name = "compilation",
++      .attrs = xen_compile_attrs,
++};
++
++int __init static xen_compilation_init(void)
++{
++      return sysfs_create_group(&hypervisor_subsys.kset.kobj,
++                                &xen_compilation_group);
++}
++
++static void xen_compilation_destroy(void)
++{
++      sysfs_remove_group(&hypervisor_subsys.kset.kobj,
++                         &xen_compilation_group);
++}
++
++/* xen properties info */
++
++static ssize_t capabilities_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      int ret = -ENOMEM;
++      char *caps;
++
++      caps = kmalloc(XEN_CAPABILITIES_INFO_LEN, GFP_KERNEL);
++      if (caps) {
++              ret = HYPERVISOR_xen_version(XENVER_capabilities, caps);
++              if (!ret)
++                      ret = sprintf(buffer, "%s\n", caps);
++              kfree(caps);
++      }
++
++      return ret;
++}
++
++HYPERVISOR_ATTR_RO(capabilities);
++
++static ssize_t changeset_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      int ret = -ENOMEM;
++      char *cset;
++
++      cset = kmalloc(XEN_CHANGESET_INFO_LEN, GFP_KERNEL);
++      if (cset) {
++              ret = HYPERVISOR_xen_version(XENVER_changeset, cset);
++              if (!ret)
++                      ret = sprintf(buffer, "%s\n", cset);
++              kfree(cset);
++      }
++
++      return ret;
++}
++
++HYPERVISOR_ATTR_RO(changeset);
++
++static ssize_t virtual_start_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      int ret = -ENOMEM;
++      struct xen_platform_parameters *parms;
++
++      parms = kmalloc(sizeof(struct xen_platform_parameters), GFP_KERNEL);
++      if (parms) {
++              ret = HYPERVISOR_xen_version(XENVER_platform_parameters,
++                                           parms);
++              if (!ret)
++                      ret = sprintf(buffer, "%lx\n", parms->virt_start);
++              kfree(parms);
++      }
++
++      return ret;
++}
++
++HYPERVISOR_ATTR_RO(virtual_start);
++
++static ssize_t pagesize_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      int ret;
++
++      ret = HYPERVISOR_xen_version(XENVER_pagesize, NULL);
++      if (ret > 0)
++              ret = sprintf(buffer, "%x\n", ret);
++
++      return ret;
++}
++
++HYPERVISOR_ATTR_RO(pagesize);
++
++/* eventually there will be several more features to export */
++static ssize_t xen_feature_show(int index, char *buffer)
++{
++      int ret = -ENOMEM;
++      struct xen_feature_info *info;
++
++      info = kmalloc(sizeof(struct xen_feature_info), GFP_KERNEL);
++      if (info) {
++              info->submap_idx = index;
++              ret = HYPERVISOR_xen_version(XENVER_get_features, info);
++              if (!ret)
++                      ret = sprintf(buffer, "%d\n", info->submap);
++              kfree(info);
++      }
++
++      return ret;
++}
++
++static ssize_t writable_pt_show(struct hyp_sysfs_attr *attr, char *buffer)
++{
++      return xen_feature_show(XENFEAT_writable_page_tables, buffer);
++}
++
++HYPERVISOR_ATTR_RO(writable_pt);
++
++static struct attribute *xen_properties_attrs[] = {
++      &capabilities_attr.attr,
++      &changeset_attr.attr,
++      &virtual_start_attr.attr,
++      &pagesize_attr.attr,
++      &writable_pt_attr.attr,
++      NULL
++};
++
++static struct attribute_group xen_properties_group = {
++      .name = "properties",
++      .attrs = xen_properties_attrs,
++};
++
++static int __init xen_properties_init(void)
++{
++      return sysfs_create_group(&hypervisor_subsys.kset.kobj,
++                                &xen_properties_group);
++}
++
++static void xen_properties_destroy(void)
++{
++      sysfs_remove_group(&hypervisor_subsys.kset.kobj,
++                         &xen_properties_group);
++}
++
++static int __init hyper_sysfs_init(void)
++{
++      int ret;
++
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      ret = xen_sysfs_type_init();
++      if (ret)
++              goto out;
++      ret = xen_sysfs_version_init();
++      if (ret)
++              goto version_out;
++      ret = xen_compilation_init();
++      if (ret)
++              goto comp_out;
++      ret = xen_sysfs_uuid_init();
++      if (ret)
++              goto uuid_out;
++      ret = xen_properties_init();
++      if (!ret)
++              goto out;
++
++      xen_sysfs_uuid_destroy();
++uuid_out:
++      xen_compilation_destroy();
++comp_out:
++      xen_sysfs_version_destroy();
++version_out:
++      xen_sysfs_type_destroy();
++out:
++      return ret;
++}
++
++static void __exit hyper_sysfs_exit(void)
++{
++      xen_properties_destroy();
++      xen_compilation_destroy();
++      xen_sysfs_uuid_destroy();
++      xen_sysfs_version_destroy();
++      xen_sysfs_type_destroy();
++
++}
++
++module_init(hyper_sysfs_init);
++module_exit(hyper_sysfs_exit);
+--- linux-2.6.18.8/drivers/xen/core/xencomm.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/core/xencomm.c     2008-05-19 00:33:45.826787629 +0300
+@@ -0,0 +1,229 @@
++/*
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ * 
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ * 
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
++ *
++ * Copyright (C) IBM Corp. 2006
++ *
++ * Authors: Hollis Blanchard <hollisb@us.ibm.com>
++ */
++
++#include <linux/gfp.h>
++#include <linux/mm.h>
++#include <asm/page.h>
++#include <xen/xencomm.h>
++#include <xen/interface/xen.h>
++#ifdef __ia64__
++#include <asm/xen/xencomm.h>  /* for is_kern_addr() */
++#endif
++
++#ifdef HAVE_XEN_PLATFORM_COMPAT_H
++#include <xen/platform-compat.h>
++#endif
++
++static int xencomm_init(struct xencomm_desc *desc,
++                      void *buffer, unsigned long bytes)
++{
++      unsigned long recorded = 0;
++      int i = 0;
++
++      while ((recorded < bytes) && (i < desc->nr_addrs)) {
++              unsigned long vaddr = (unsigned long)buffer + recorded;
++              unsigned long paddr;
++              int offset;
++              int chunksz;
++
++              offset = vaddr % PAGE_SIZE; /* handle partial pages */
++              chunksz = min(PAGE_SIZE - offset, bytes - recorded);
++
++              paddr = xencomm_vtop(vaddr);
++              if (paddr == ~0UL) {
++                      printk("%s: couldn't translate vaddr %lx\n",
++                             __func__, vaddr);
++                      return -EINVAL;
++              }
++
++              desc->address[i++] = paddr;
++              recorded += chunksz;
++      }
++
++      if (recorded < bytes) {
++              printk("%s: could only translate %ld of %ld bytes\n",
++                     __func__, recorded, bytes);
++              return -ENOSPC;
++      }
++
++      /* mark remaining addresses invalid (just for safety) */
++      while (i < desc->nr_addrs)
++              desc->address[i++] = XENCOMM_INVALID;
++
++      desc->magic = XENCOMM_MAGIC;
++
++      return 0;
++}
++
++static struct xencomm_desc *xencomm_alloc(gfp_t gfp_mask,
++                                        void *buffer, unsigned long bytes)
++{
++      struct xencomm_desc *desc;
++      unsigned long buffer_ulong = (unsigned long)buffer;
++      unsigned long start = buffer_ulong & PAGE_MASK;
++      unsigned long end = (buffer_ulong + bytes) | ~PAGE_MASK;
++      unsigned long nr_addrs = (end - start + 1) >> PAGE_SHIFT;
++      unsigned long size = sizeof(*desc) +
++              sizeof(desc->address[0]) * nr_addrs;
++
++      /*
++       * slab allocator returns at least sizeof(void*) aligned pointer.
++       * When sizeof(*desc) > sizeof(void*), struct xencomm_desc might
++       * cross page boundary.
++       */
++      if (sizeof(*desc) > sizeof(void*)) {
++              unsigned long order = get_order(size);
++              desc = (struct xencomm_desc *)__get_free_pages(gfp_mask,
++                                                             order);
++              if (desc == NULL)
++                      return NULL;
++
++              desc->nr_addrs =
++                      ((PAGE_SIZE << order) - sizeof(struct xencomm_desc)) /
++                      sizeof(*desc->address);
++      } else {
++              desc = kmalloc(size, gfp_mask);
++              if (desc == NULL)
++                      return NULL;
++
++              desc->nr_addrs = nr_addrs;
++      }
++      return desc;
++}
++
++void xencomm_free(struct xencomm_handle *desc)
++{
++      if (desc && !((ulong)desc & XENCOMM_INLINE_FLAG)) {
++              struct xencomm_desc *desc__ = (struct xencomm_desc*)desc;
++              if (sizeof(*desc__) > sizeof(void*)) {
++                      unsigned long size = sizeof(*desc__) +
++                              sizeof(desc__->address[0]) * desc__->nr_addrs;
++                      unsigned long order = get_order(size);
++                      free_pages((unsigned long)__va(desc), order);
++              } else
++                      kfree(__va(desc));
++      }
++}
++
++static int xencomm_create(void *buffer, unsigned long bytes, struct xencomm_desc **ret, gfp_t gfp_mask)
++{
++      struct xencomm_desc *desc;
++      int rc;
++
++      pr_debug("%s: %p[%ld]\n", __func__, buffer, bytes);
++
++      if (bytes == 0) {
++              /* don't create a descriptor; Xen recognizes NULL. */
++              BUG_ON(buffer != NULL);
++              *ret = NULL;
++              return 0;
++      }
++
++      BUG_ON(buffer == NULL); /* 'bytes' is non-zero */
++
++      desc = xencomm_alloc(gfp_mask, buffer, bytes);
++      if (!desc) {
++              printk("%s failure\n", "xencomm_alloc");
++              return -ENOMEM;
++      }
++
++      rc = xencomm_init(desc, buffer, bytes);
++      if (rc) {
++              printk("%s failure: %d\n", "xencomm_init", rc);
++              xencomm_free((struct xencomm_handle *)__pa(desc));
++              return rc;
++      }
++
++      *ret = desc;
++      return 0;
++}
++
++/* check if memory address is within VMALLOC region  */
++static int is_phys_contiguous(unsigned long addr)
++{
++      if (!is_kernel_addr(addr))
++              return 0;
++
++      return (addr < VMALLOC_START) || (addr >= VMALLOC_END);
++}
++
++static struct xencomm_handle *xencomm_create_inline(void *ptr)
++{
++      unsigned long paddr;
++
++      BUG_ON(!is_phys_contiguous((unsigned long)ptr));
++
++      paddr = (unsigned long)xencomm_pa(ptr);
++      BUG_ON(paddr & XENCOMM_INLINE_FLAG);
++      return (struct xencomm_handle *)(paddr | XENCOMM_INLINE_FLAG);
++}
++
++/* "mini" routine, for stack-based communications: */
++static int xencomm_create_mini(void *buffer,
++      unsigned long bytes, struct xencomm_mini *xc_desc,
++      struct xencomm_desc **ret)
++{
++      int rc = 0;
++      struct xencomm_desc *desc;
++      BUG_ON(((unsigned long)xc_desc) % sizeof(*xc_desc) != 0);
++
++      desc = (void *)xc_desc; 
++
++      desc->nr_addrs = XENCOMM_MINI_ADDRS;
++
++      if (!(rc = xencomm_init(desc, buffer, bytes)))
++              *ret = desc;
++
++      return rc;
++}
++
++struct xencomm_handle *xencomm_map(void *ptr, unsigned long bytes)
++{
++      int rc;
++      struct xencomm_desc *desc;
++
++      if (is_phys_contiguous((unsigned long)ptr))
++              return xencomm_create_inline(ptr);
++
++      rc = xencomm_create(ptr, bytes, &desc, GFP_KERNEL);
++
++      if (rc || desc == NULL)
++              return NULL;
++
++      return xencomm_pa(desc);
++}
++
++struct xencomm_handle *__xencomm_map_no_alloc(void *ptr, unsigned long bytes, 
++                      struct xencomm_mini *xc_desc)
++{
++      int rc;
++      struct xencomm_desc *desc = NULL;
++
++      if (is_phys_contiguous((unsigned long)ptr))
++              return xencomm_create_inline(ptr);
++
++      rc = xencomm_create_mini(ptr, bytes, xc_desc,
++                              &desc);
++
++      if (rc)
++              return NULL;
++ 
++      return xencomm_pa(desc);
++}
+--- linux-2.6.18.8/drivers/xen/evtchn/Makefile 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/evtchn/Makefile    2008-05-19 00:33:45.830787860 +0300
+@@ -0,0 +1,2 @@
++
++obj-y := evtchn.o
+--- linux-2.6.18.8/drivers/xen/evtchn/evtchn.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/evtchn/evtchn.c    2008-05-19 00:33:45.830787860 +0300
+@@ -0,0 +1,558 @@
++/******************************************************************************
++ * evtchn.c
++ * 
++ * Driver for receiving and demuxing event-channel signals.
++ * 
++ * Copyright (c) 2004-2005, K A Fraser
++ * Multi-process extensions Copyright (c) 2004, Steven Smith
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/errno.h>
++#include <linux/miscdevice.h>
++#include <linux/major.h>
++#include <linux/proc_fs.h>
++#include <linux/stat.h>
++#include <linux/poll.h>
++#include <linux/irq.h>
++#include <linux/init.h>
++#include <linux/gfp.h>
++#include <linux/mutex.h>
++#include <linux/cpu.h>
++#include <xen/evtchn.h>
++#include <xen/public/evtchn.h>
++
++struct per_user_data {
++      /* Notification ring, accessed via /dev/xen/evtchn. */
++#define EVTCHN_RING_SIZE     (PAGE_SIZE / sizeof(evtchn_port_t))
++#define EVTCHN_RING_MASK(_i) ((_i)&(EVTCHN_RING_SIZE-1))
++      evtchn_port_t *ring;
++      unsigned int ring_cons, ring_prod, ring_overflow;
++      struct mutex ring_cons_mutex; /* protect against concurrent readers */
++
++      /* Processes wait on this queue when ring is empty. */
++      wait_queue_head_t evtchn_wait;
++      struct fasync_struct *evtchn_async_queue;
++
++      int bind_cpu;
++      int nr_event_wrong_delivery;
++};
++
++/* Who's bound to each port? */
++static struct per_user_data *port_user[NR_EVENT_CHANNELS];
++static spinlock_t port_user_lock;
++
++void evtchn_device_upcall(int port)
++{
++      struct per_user_data *u;
++
++      spin_lock(&port_user_lock);
++
++      mask_evtchn(port);
++      clear_evtchn(port);
++
++      if ((u = port_user[port]) != NULL) {
++              if ((u->ring_prod - u->ring_cons) < EVTCHN_RING_SIZE) {
++                      u->ring[EVTCHN_RING_MASK(u->ring_prod)] = port;
++                      if (u->ring_cons == u->ring_prod++) {
++                              wake_up_interruptible(&u->evtchn_wait);
++                              kill_fasync(&u->evtchn_async_queue,
++                                          SIGIO, POLL_IN);
++                      }
++              } else {
++                      u->ring_overflow = 1;
++              }
++      }
++
++      spin_unlock(&port_user_lock);
++}
++
++static void evtchn_check_wrong_delivery(struct per_user_data *u)
++{
++      evtchn_port_t port;
++      unsigned int current_cpu = smp_processor_id();
++
++      /* Delivered to correct CPU? All is good. */
++      if (u->bind_cpu == current_cpu) {
++              u->nr_event_wrong_delivery = 0;
++              return;
++      }
++
++      /* Tolerate up to 100 consecutive misdeliveries. */
++      if (++u->nr_event_wrong_delivery < 100)
++              return;
++
++      spin_lock_irq(&port_user_lock);
++
++      for (port = 0; port < NR_EVENT_CHANNELS; port++)
++              if (port_user[port] == u)
++                      rebind_evtchn_to_cpu(port, current_cpu);
++
++      u->bind_cpu = current_cpu;
++      u->nr_event_wrong_delivery = 0;
++
++      spin_unlock_irq(&port_user_lock);
++}
++
++static ssize_t evtchn_read(struct file *file, char __user *buf,
++                         size_t count, loff_t *ppos)
++{
++      int rc;
++      unsigned int c, p, bytes1 = 0, bytes2 = 0;
++      struct per_user_data *u = file->private_data;
++
++      /* Whole number of ports. */
++      count &= ~(sizeof(evtchn_port_t)-1);
++
++      if (count == 0)
++              return 0;
++
++      if (count > PAGE_SIZE)
++              count = PAGE_SIZE;
++
++      for (;;) {
++              mutex_lock(&u->ring_cons_mutex);
++
++              rc = -EFBIG;
++              if (u->ring_overflow)
++                      goto unlock_out;
++
++              if ((c = u->ring_cons) != (p = u->ring_prod))
++                      break;
++
++              mutex_unlock(&u->ring_cons_mutex);
++
++              if (file->f_flags & O_NONBLOCK)
++                      return -EAGAIN;
++
++              rc = wait_event_interruptible(
++                      u->evtchn_wait, u->ring_cons != u->ring_prod);
++              if (rc)
++                      return rc;
++      }
++
++      /* Byte lengths of two chunks. Chunk split (if any) is at ring wrap. */
++      if (((c ^ p) & EVTCHN_RING_SIZE) != 0) {
++              bytes1 = (EVTCHN_RING_SIZE - EVTCHN_RING_MASK(c)) *
++                      sizeof(evtchn_port_t);
++              bytes2 = EVTCHN_RING_MASK(p) * sizeof(evtchn_port_t);
++      } else {
++              bytes1 = (p - c) * sizeof(evtchn_port_t);
++              bytes2 = 0;
++      }
++
++      /* Truncate chunks according to caller's maximum byte count. */
++      if (bytes1 > count) {
++              bytes1 = count;
++              bytes2 = 0;
++      } else if ((bytes1 + bytes2) > count) {
++              bytes2 = count - bytes1;
++      }
++
++      rc = -EFAULT;
++      if (copy_to_user(buf, &u->ring[EVTCHN_RING_MASK(c)], bytes1) ||
++          ((bytes2 != 0) &&
++           copy_to_user(&buf[bytes1], &u->ring[0], bytes2)))
++              goto unlock_out;
++      
++      evtchn_check_wrong_delivery(u);
++
++      u->ring_cons += (bytes1 + bytes2) / sizeof(evtchn_port_t);
++      rc = bytes1 + bytes2;
++
++ unlock_out:
++      mutex_unlock(&u->ring_cons_mutex);
++      return rc;
++}
++
++static ssize_t evtchn_write(struct file *file, const char __user *buf,
++                          size_t count, loff_t *ppos)
++{
++      int rc, i;
++      evtchn_port_t *kbuf = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
++      struct per_user_data *u = file->private_data;
++
++      if (kbuf == NULL)
++              return -ENOMEM;
++
++      /* Whole number of ports. */
++      count &= ~(sizeof(evtchn_port_t)-1);
++
++      rc = 0;
++      if (count == 0)
++              goto out;
++
++      if (count > PAGE_SIZE)
++              count = PAGE_SIZE;
++
++      rc = -EFAULT;
++      if (copy_from_user(kbuf, buf, count) != 0)
++              goto out;
++
++      spin_lock_irq(&port_user_lock);
++      for (i = 0; i < (count/sizeof(evtchn_port_t)); i++)
++              if ((kbuf[i] < NR_EVENT_CHANNELS) && (port_user[kbuf[i]] == u))
++                      unmask_evtchn(kbuf[i]);
++      spin_unlock_irq(&port_user_lock);
++
++      rc = count;
++
++ out:
++      free_page((unsigned long)kbuf);
++      return rc;
++}
++
++static unsigned int next_bind_cpu(cpumask_t map)
++{
++      static unsigned int bind_cpu;
++      bind_cpu = next_cpu(bind_cpu, map);
++      if (bind_cpu >= NR_CPUS)
++              bind_cpu = first_cpu(map);
++      return bind_cpu;
++}
++
++static void evtchn_bind_to_user(struct per_user_data *u, int port)
++{
++      spin_lock_irq(&port_user_lock);
++
++      BUG_ON(port_user[port] != NULL);
++      port_user[port] = u;
++
++      if (u->bind_cpu == -1)
++              u->bind_cpu = next_bind_cpu(cpu_online_map);
++
++      rebind_evtchn_to_cpu(port, u->bind_cpu);
++
++      unmask_evtchn(port);
++
++      spin_unlock_irq(&port_user_lock);
++}
++
++static long evtchn_ioctl(struct file *file,
++                       unsigned int cmd, unsigned long arg)
++{
++      int rc;
++      struct per_user_data *u = file->private_data;
++      void __user *uarg = (void __user *) arg;
++
++      switch (cmd) {
++      case IOCTL_EVTCHN_BIND_VIRQ: {
++              struct ioctl_evtchn_bind_virq bind;
++              struct evtchn_bind_virq bind_virq;
++
++              rc = -EFAULT;
++              if (copy_from_user(&bind, uarg, sizeof(bind)))
++                      break;
++
++              bind_virq.virq = bind.virq;
++              bind_virq.vcpu = 0;
++              rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_virq,
++                                               &bind_virq);
++              if (rc != 0)
++                      break;
++
++              rc = bind_virq.port;
++              evtchn_bind_to_user(u, rc);
++              break;
++      }
++
++      case IOCTL_EVTCHN_BIND_INTERDOMAIN: {
++              struct ioctl_evtchn_bind_interdomain bind;
++              struct evtchn_bind_interdomain bind_interdomain;
++
++              rc = -EFAULT;
++              if (copy_from_user(&bind, uarg, sizeof(bind)))
++                      break;
++
++              bind_interdomain.remote_dom  = bind.remote_domain;
++              bind_interdomain.remote_port = bind.remote_port;
++              rc = HYPERVISOR_event_channel_op(EVTCHNOP_bind_interdomain,
++                                               &bind_interdomain);
++              if (rc != 0)
++                      break;
++
++              rc = bind_interdomain.local_port;
++              evtchn_bind_to_user(u, rc);
++              break;
++      }
++
++      case IOCTL_EVTCHN_BIND_UNBOUND_PORT: {
++              struct ioctl_evtchn_bind_unbound_port bind;
++              struct evtchn_alloc_unbound alloc_unbound;
++
++              rc = -EFAULT;
++              if (copy_from_user(&bind, uarg, sizeof(bind)))
++                      break;
++
++              alloc_unbound.dom        = DOMID_SELF;
++              alloc_unbound.remote_dom = bind.remote_domain;
++              rc = HYPERVISOR_event_channel_op(EVTCHNOP_alloc_unbound,
++                                               &alloc_unbound);
++              if (rc != 0)
++                      break;
++
++              rc = alloc_unbound.port;
++              evtchn_bind_to_user(u, rc);
++              break;
++      }
++
++      case IOCTL_EVTCHN_UNBIND: {
++              struct ioctl_evtchn_unbind unbind;
++              struct evtchn_close close;
++              int ret;
++
++              rc = -EFAULT;
++              if (copy_from_user(&unbind, uarg, sizeof(unbind)))
++                      break;
++
++              rc = -EINVAL;
++              if (unbind.port >= NR_EVENT_CHANNELS)
++                      break;
++
++              spin_lock_irq(&port_user_lock);
++    
++              rc = -ENOTCONN;
++              if (port_user[unbind.port] != u) {
++                      spin_unlock_irq(&port_user_lock);
++                      break;
++              }
++
++              port_user[unbind.port] = NULL;
++              mask_evtchn(unbind.port);
++              rebind_evtchn_to_cpu(unbind.port, 0);
++
++              spin_unlock_irq(&port_user_lock);
++
++              close.port = unbind.port;
++              ret = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
++              BUG_ON(ret);
++
++              rc = 0;
++              break;
++      }
++
++      case IOCTL_EVTCHN_NOTIFY: {
++              struct ioctl_evtchn_notify notify;
++
++              rc = -EFAULT;
++              if (copy_from_user(&notify, uarg, sizeof(notify)))
++                      break;
++
++              if (notify.port >= NR_EVENT_CHANNELS) {
++                      rc = -EINVAL;
++              } else if (port_user[notify.port] != u) {
++                      rc = -ENOTCONN;
++              } else {
++                      notify_remote_via_evtchn(notify.port);
++                      rc = 0;
++              }
++              break;
++      }
++
++      case IOCTL_EVTCHN_RESET: {
++              /* Initialise the ring to empty. Clear errors. */
++              mutex_lock(&u->ring_cons_mutex);
++              spin_lock_irq(&port_user_lock);
++              u->ring_cons = u->ring_prod = u->ring_overflow = 0;
++              spin_unlock_irq(&port_user_lock);
++              mutex_unlock(&u->ring_cons_mutex);
++              rc = 0;
++              break;
++      }
++
++      default:
++              rc = -ENOSYS;
++              break;
++      }
++
++      return rc;
++}
++
++static unsigned int evtchn_poll(struct file *file, poll_table *wait)
++{
++      unsigned int mask = POLLOUT | POLLWRNORM;
++      struct per_user_data *u = file->private_data;
++
++      poll_wait(file, &u->evtchn_wait, wait);
++      if (u->ring_cons != u->ring_prod)
++              mask |= POLLIN | POLLRDNORM;
++      if (u->ring_overflow)
++              mask = POLLERR;
++      return mask;
++}
++
++static int evtchn_fasync(int fd, struct file *filp, int on)
++{
++      struct per_user_data *u = filp->private_data;
++      return fasync_helper(fd, filp, on, &u->evtchn_async_queue);
++}
++
++static int evtchn_open(struct inode *inode, struct file *filp)
++{
++      struct per_user_data *u;
++
++      if ((u = kmalloc(sizeof(*u), GFP_KERNEL)) == NULL)
++              return -ENOMEM;
++
++      memset(u, 0, sizeof(*u));
++      init_waitqueue_head(&u->evtchn_wait);
++
++      u->ring = (evtchn_port_t *)__get_free_page(GFP_KERNEL);
++      if (u->ring == NULL) {
++              kfree(u);
++              return -ENOMEM;
++      }
++
++      mutex_init(&u->ring_cons_mutex);
++
++      filp->private_data = u;
++
++      u->bind_cpu = -1;
++
++      return 0;
++}
++
++static int evtchn_release(struct inode *inode, struct file *filp)
++{
++      int i;
++      struct per_user_data *u = filp->private_data;
++      struct evtchn_close close;
++
++      spin_lock_irq(&port_user_lock);
++
++      free_page((unsigned long)u->ring);
++
++      for (i = 0; i < NR_EVENT_CHANNELS; i++) {
++              int ret;
++              if (port_user[i] != u)
++                      continue;
++
++              port_user[i] = NULL;
++              mask_evtchn(i);
++              rebind_evtchn_to_cpu(i, 0);
++
++              close.port = i;
++              ret = HYPERVISOR_event_channel_op(EVTCHNOP_close, &close);
++              BUG_ON(ret);
++      }
++
++      spin_unlock_irq(&port_user_lock);
++
++      kfree(u);
++
++      return 0;
++}
++
++static const struct file_operations evtchn_fops = {
++      .owner   = THIS_MODULE,
++      .read    = evtchn_read,
++      .write   = evtchn_write,
++      .unlocked_ioctl = evtchn_ioctl,
++      .poll    = evtchn_poll,
++      .fasync  = evtchn_fasync,
++      .open    = evtchn_open,
++      .release = evtchn_release,
++};
++
++static struct miscdevice evtchn_miscdev = {
++      .minor        = MISC_DYNAMIC_MINOR,
++      .name         = "evtchn",
++      .fops         = &evtchn_fops,
++};
++
++static int __cpuinit evtchn_cpu_notify(struct notifier_block *nfb,
++                      unsigned long action, void *hcpu)
++{
++      int hotcpu = (unsigned long)hcpu;
++      cpumask_t map = cpu_online_map;
++      int port, newcpu;
++      struct per_user_data *u;
++
++      switch (action) {
++      case CPU_DOWN_PREPARE:
++              cpu_clear(hotcpu, map);
++              spin_lock_irq(&port_user_lock);
++              for (port = 0; port < NR_EVENT_CHANNELS; port++) {
++                      if ((u = port_user[port]) != NULL && 
++                          u->bind_cpu == hotcpu &&
++                          (newcpu = next_bind_cpu(map)) < NR_CPUS) {
++                              rebind_evtchn_to_cpu(port, newcpu);
++                              u->bind_cpu = newcpu;
++                      }
++              }
++              spin_unlock_irq(&port_user_lock);
++              break;
++      default:
++              return NOTIFY_DONE;
++      }
++      return NOTIFY_OK;
++}
++
++static struct notifier_block __cpuinitdata evtchn_cpu_nfb = {
++      .notifier_call = evtchn_cpu_notify
++};
++
++static int __init evtchn_init(void)
++{
++      int err;
++
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      spin_lock_init(&port_user_lock);
++      memset(port_user, 0, sizeof(port_user));
++
++      /* Create '/dev/misc/evtchn'. */
++      err = misc_register(&evtchn_miscdev);
++      if (err != 0) {
++              printk(KERN_ALERT "Could not register /dev/misc/evtchn\n");
++              return err;
++      }
++
++      register_cpu_notifier(&evtchn_cpu_nfb);
++
++      printk("Event-channel device installed.\n");
++
++      return 0;
++}
++
++static void __exit evtchn_cleanup(void)
++{
++      misc_deregister(&evtchn_miscdev);
++      unregister_cpu_notifier(&evtchn_cpu_nfb);
++}
++
++module_init(evtchn_init);
++module_exit(evtchn_cleanup);
++
++MODULE_LICENSE("Dual BSD/GPL");
+--- linux-2.6.18.8/drivers/xen/fbfront/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/fbfront/Makefile   2008-05-19 00:33:45.830787860 +0300
+@@ -0,0 +1,2 @@
++obj-$(CONFIG_XEN_FRAMEBUFFER) := xenfb.o
++obj-$(CONFIG_XEN_KEYBOARD)    += xenkbd.o
+--- linux-2.6.18.8/drivers/xen/fbfront/xenfb.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/fbfront/xenfb.c    2008-05-19 00:33:45.834788090 +0300
+@@ -0,0 +1,887 @@
++/*
++ * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device
++ *
++ * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com>
++ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
++ *
++ *  Based on linux/drivers/video/q40fb.c
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License. See the file COPYING in the main directory of this archive for
++ *  more details.
++ */
++
++/*
++ * TODO:
++ *
++ * Switch to grant tables when they become capable of dealing with the
++ * frame buffer.
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/fb.h>
++#include <linux/module.h>
++#include <linux/vmalloc.h>
++#include <linux/mm.h>
++#include <linux/mutex.h>
++#include <asm/hypervisor.h>
++#include <xen/evtchn.h>
++#include <xen/interface/io/fbif.h>
++#include <xen/interface/io/protocols.h>
++#include <xen/xenbus.h>
++#include <linux/kthread.h>
++
++struct xenfb_mapping
++{
++      struct list_head        link;
++      struct vm_area_struct   *vma;
++      atomic_t                map_refs;
++      int                     faults;
++      struct xenfb_info       *info;
++};
++
++struct xenfb_info
++{
++      struct task_struct      *kthread;
++      wait_queue_head_t       wq;
++
++      unsigned char           *fb;
++      struct fb_info          *fb_info;
++      struct timer_list       refresh;
++      int                     dirty;
++      int                     x1, y1, x2, y2; /* dirty rectangle,
++                                                 protected by dirty_lock */
++      spinlock_t              dirty_lock;
++      struct mutex            mm_lock;
++      int                     nr_pages;
++      struct page             **pages;
++      struct list_head        mappings; /* protected by mm_lock */
++
++      int                     irq;
++      struct xenfb_page       *page;
++      unsigned long           *mfns;
++      int                     update_wanted; /* XENFB_TYPE_UPDATE wanted */
++      int                     feature_resize; /* Backend has resize feature */
++      struct xenfb_resize     resize;
++      int                     resize_dpy;
++      spinlock_t              resize_lock;
++
++      struct xenbus_device    *xbdev;
++};
++
++/*
++ * There are three locks:
++ *    spinlock resize_lock protecting resize_dpy and resize
++ *    spinlock dirty_lock protecting the dirty rectangle
++ *    mutex mm_lock protecting mappings.
++ *
++ * How the dirty and mapping locks work together
++ *
++ * The problem is that dirty rectangle and mappings aren't
++ * independent: the dirty rectangle must cover all faulted pages in
++ * mappings.  We need to prove that our locking maintains this
++ * invariant.
++ *
++ * There are several kinds of critical regions:
++ *
++ * 1. Holding only dirty_lock: xenfb_refresh().  May run in
++ *    interrupts.  Extends the dirty rectangle.  Trivially preserves
++ *    invariant.
++ *
++ * 2. Holding only mm_lock: xenfb_mmap() and xenfb_vm_close().  Touch
++ *    only mappings.  The former creates unfaulted pages.  Preserves
++ *    invariant.  The latter removes pages.  Preserves invariant.
++ *
++ * 3. Holding both locks: xenfb_vm_nopage().  Extends the dirty
++ *    rectangle and updates mappings consistently.  Preserves
++ *    invariant.
++ *
++ * 4. The ugliest one: xenfb_update_screen().  Clear the dirty
++ *    rectangle and update mappings consistently.
++ *
++ *    We can't simply hold both locks, because zap_page_range() cannot
++ *    be called with a spinlock held.
++ *
++ *    Therefore, we first clear the dirty rectangle with both locks
++ *    held.  Then we unlock dirty_lock and update the mappings.
++ *    Critical regions that hold only dirty_lock may interfere with
++ *    that.  This can only be region 1: xenfb_refresh().  But that
++ *    just extends the dirty rectangle, which can't harm the
++ *    invariant.
++ *
++ * But FIXME: the invariant is too weak.  It misses that the fault
++ * record in mappings must be consistent with the mapping of pages in
++ * the associated address space!  do_no_page() updates the PTE after
++ * xenfb_vm_nopage() returns, i.e. outside the critical region.  This
++ * allows the following race:
++ *
++ * X writes to some address in the Xen frame buffer
++ * Fault - call do_no_page()
++ *     call xenfb_vm_nopage()
++ *         grab mm_lock
++ *         map->faults++;
++ *         release mm_lock
++ *     return back to do_no_page()
++ * (preempted, or SMP)
++ * Xen worker thread runs.
++ *      grab mm_lock
++ *      look at mappings
++ *          find this mapping, zaps its pages (but page not in pte yet)
++ *          clear map->faults
++ *      releases mm_lock
++ * (back to X process)
++ *     put page in X's pte
++ *
++ * Oh well, we wont be updating the writes to this page anytime soon.
++ */
++#define MB_ (1024*1024)
++#define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8)
++
++enum {KPARAM_MEM, KPARAM_WIDTH, KPARAM_HEIGHT, KPARAM_CNT};
++static int video[KPARAM_CNT] = {2, XENFB_WIDTH, XENFB_HEIGHT};
++module_param_array(video, int, NULL, 0);
++MODULE_PARM_DESC(video,
++              "Size of video memory in MB and width,height in pixels, default = (2,800,600)");
++
++static int xenfb_fps = 20;
++
++static int xenfb_remove(struct xenbus_device *);
++static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *);
++static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *);
++static void xenfb_disconnect_backend(struct xenfb_info *);
++
++static void xenfb_send_event(struct xenfb_info *info,
++              union xenfb_out_event *event)
++{
++      __u32 prod;
++
++      prod = info->page->out_prod;
++      /* caller ensures !xenfb_queue_full() */
++      mb();                   /* ensure ring space available */
++      XENFB_OUT_RING_REF(info->page, prod) = *event;
++      wmb();                  /* ensure ring contents visible */
++      info->page->out_prod = prod + 1;
++
++      notify_remote_via_irq(info->irq);
++}
++
++static void xenfb_do_update(struct xenfb_info *info,
++                          int x, int y, int w, int h)
++{
++      union xenfb_out_event event;
++
++      memset(&event, 0, sizeof(event));
++      event.type = XENFB_TYPE_UPDATE;
++      event.update.x = x;
++      event.update.y = y;
++      event.update.width = w;
++      event.update.height = h;
++
++      /* caller ensures !xenfb_queue_full() */
++      xenfb_send_event(info, &event);
++}
++
++static void xenfb_do_resize(struct xenfb_info *info)
++{
++      union xenfb_out_event event;
++
++      memset(&event, 0, sizeof(event));
++      event.resize = info->resize;
++
++      /* caller ensures !xenfb_queue_full() */
++      xenfb_send_event(info, &event);
++}
++
++static int xenfb_queue_full(struct xenfb_info *info)
++{
++      __u32 cons, prod;
++
++      prod = info->page->out_prod;
++      cons = info->page->out_cons;
++      return prod - cons == XENFB_OUT_RING_LEN;
++}
++
++static void xenfb_update_screen(struct xenfb_info *info)
++{
++      unsigned long flags;
++      int y1, y2, x1, x2;
++      struct xenfb_mapping *map;
++
++      if (!info->update_wanted)
++              return;
++      if (xenfb_queue_full(info))
++              return;
++
++      mutex_lock(&info->mm_lock);
++
++      spin_lock_irqsave(&info->dirty_lock, flags);
++      y1 = info->y1;
++      y2 = info->y2;
++      x1 = info->x1;
++      x2 = info->x2;
++      info->x1 = info->y1 = INT_MAX;
++      info->x2 = info->y2 = 0;
++      spin_unlock_irqrestore(&info->dirty_lock, flags);
++
++      list_for_each_entry(map, &info->mappings, link) {
++              if (!map->faults)
++                      continue;
++              zap_page_range(map->vma, map->vma->vm_start,
++                             map->vma->vm_end - map->vma->vm_start, NULL);
++              map->faults = 0;
++      }
++
++      mutex_unlock(&info->mm_lock);
++
++      if (x2 < x1 || y2 < y1) {
++              printk("xenfb_update_screen bogus rect %d %d %d %d\n",
++                     x1, x2, y1, y2);
++              WARN_ON(1);
++      }
++      xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1);
++}
++
++static void xenfb_handle_resize_dpy(struct xenfb_info *info)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&info->resize_lock, flags);
++      if (info->resize_dpy) {
++              if (!xenfb_queue_full(info)) {
++                      info->resize_dpy = 0;
++                      xenfb_do_resize(info);
++              }
++      }
++      spin_unlock_irqrestore(&info->resize_lock, flags);
++}
++
++static int xenfb_thread(void *data)
++{
++      struct xenfb_info *info = data;
++
++      while (!kthread_should_stop()) {
++              xenfb_handle_resize_dpy(info);
++              if (info->dirty) {
++                      info->dirty = 0;
++                      xenfb_update_screen(info);
++              }
++              wait_event_interruptible(info->wq,
++                      kthread_should_stop() || info->dirty);
++              try_to_freeze();
++      }
++      return 0;
++}
++
++static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
++                         unsigned blue, unsigned transp,
++                         struct fb_info *info)
++{
++      u32 v;
++
++      if (regno > info->cmap.len)
++              return 1;
++
++      red   >>= (16 - info->var.red.length);
++      green >>= (16 - info->var.green.length);
++      blue  >>= (16 - info->var.blue.length);
++
++      v = (red << info->var.red.offset) |
++          (green << info->var.green.offset) |
++          (blue << info->var.blue.offset);
++
++      /* FIXME is this sane?  check against xxxfb_setcolreg()!  */
++      switch (info->var.bits_per_pixel) {
++      case 16:
++      case 24:
++      case 32:
++              ((u32 *)info->pseudo_palette)[regno] = v;
++              break;
++      }
++      
++      return 0;
++}
++
++static void xenfb_timer(unsigned long data)
++{
++      struct xenfb_info *info = (struct xenfb_info *)data;
++      wake_up(&info->wq);
++}
++
++static void __xenfb_refresh(struct xenfb_info *info,
++                          int x1, int y1, int w, int h)
++{
++      int y2, x2;
++
++      y2 = y1 + h;
++      x2 = x1 + w;
++
++      if (info->y1 > y1)
++              info->y1 = y1;
++      if (info->y2 < y2)
++              info->y2 = y2;
++      if (info->x1 > x1)
++              info->x1 = x1;
++      if (info->x2 < x2)
++              info->x2 = x2;
++      info->dirty = 1;
++
++      if (timer_pending(&info->refresh))
++              return;
++
++      mod_timer(&info->refresh, jiffies + HZ/xenfb_fps);
++}
++
++static void xenfb_refresh(struct xenfb_info *info,
++                        int x1, int y1, int w, int h)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&info->dirty_lock, flags);
++      __xenfb_refresh(info, x1, y1, w, h);
++      spin_unlock_irqrestore(&info->dirty_lock, flags);
++}
++
++static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
++{
++      struct xenfb_info *info = p->par;
++
++      cfb_fillrect(p, rect);
++      xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);
++}
++
++static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image)
++{
++      struct xenfb_info *info = p->par;
++
++      cfb_imageblit(p, image);
++      xenfb_refresh(info, image->dx, image->dy, image->width, image->height);
++}
++
++static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
++{
++      struct xenfb_info *info = p->par;
++
++      cfb_copyarea(p, area);
++      xenfb_refresh(info, area->dx, area->dy, area->width, area->height);
++}
++
++static void xenfb_vm_open(struct vm_area_struct *vma)
++{
++      struct xenfb_mapping *map = vma->vm_private_data;
++      atomic_inc(&map->map_refs);
++}
++
++static void xenfb_vm_close(struct vm_area_struct *vma)
++{
++      struct xenfb_mapping *map = vma->vm_private_data;
++      struct xenfb_info *info = map->info;
++
++      mutex_lock(&info->mm_lock);
++      if (atomic_dec_and_test(&map->map_refs)) {
++              list_del(&map->link);
++              kfree(map);
++      }
++      mutex_unlock(&info->mm_lock);
++}
++
++static struct page *xenfb_vm_nopage(struct vm_area_struct *vma,
++                                  unsigned long vaddr, int *type)
++{
++      struct xenfb_mapping *map = vma->vm_private_data;
++      struct xenfb_info *info = map->info;
++      int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT;
++      unsigned long flags;
++      struct page *page;
++      int y1, y2;
++
++      if (pgnr >= info->nr_pages)
++              return NOPAGE_SIGBUS;
++
++      mutex_lock(&info->mm_lock);
++      spin_lock_irqsave(&info->dirty_lock, flags);
++      page = info->pages[pgnr];
++      get_page(page);
++      map->faults++;
++
++      y1 = pgnr * PAGE_SIZE / info->fb_info->fix.line_length;
++      y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fb_info->fix.line_length;
++      if (y2 > info->fb_info->var.yres)
++              y2 = info->fb_info->var.yres;
++      __xenfb_refresh(info, 0, y1, info->fb_info->var.xres, y2 - y1);
++      spin_unlock_irqrestore(&info->dirty_lock, flags);
++      mutex_unlock(&info->mm_lock);
++
++      if (type)
++              *type = VM_FAULT_MINOR;
++
++      return page;
++}
++
++static struct vm_operations_struct xenfb_vm_ops = {
++      .open   = xenfb_vm_open,
++      .close  = xenfb_vm_close,
++      .nopage = xenfb_vm_nopage,
++};
++
++static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma)
++{
++      struct xenfb_info *info = fb_info->par;
++      struct xenfb_mapping *map;
++      int map_pages;
++
++      if (!(vma->vm_flags & VM_WRITE))
++              return -EINVAL;
++      if (!(vma->vm_flags & VM_SHARED))
++              return -EINVAL;
++      if (vma->vm_pgoff != 0)
++              return -EINVAL;
++
++      map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT;
++      if (map_pages > info->nr_pages)
++              return -EINVAL;
++
++      map = kzalloc(sizeof(*map), GFP_KERNEL);
++      if (map == NULL)
++              return -ENOMEM;
++
++      map->vma = vma;
++      map->faults = 0;
++      map->info = info;
++      atomic_set(&map->map_refs, 1);
++
++      mutex_lock(&info->mm_lock);
++      list_add(&map->link, &info->mappings);
++      mutex_unlock(&info->mm_lock);
++
++      vma->vm_ops = &xenfb_vm_ops;
++      vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED);
++      vma->vm_private_data = map;
++
++      return 0;
++}
++
++static int
++xenfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
++{
++      struct xenfb_info *xenfb_info;
++      int required_mem_len;
++
++      xenfb_info = info->par;
++
++      if (!xenfb_info->feature_resize) {
++              if (var->xres == video[KPARAM_WIDTH] &&
++                      var->yres == video[KPARAM_HEIGHT] &&
++                      var->bits_per_pixel == xenfb_info->page->depth) {
++                      return 0;
++              }
++              return -EINVAL;
++      }
++
++      /* Can't resize past initial width and height */
++      if (var->xres > video[KPARAM_WIDTH] || var->yres > video[KPARAM_HEIGHT])
++              return -EINVAL;
++
++      required_mem_len = var->xres * var->yres * (xenfb_info->page->depth / 8);
++      if (var->bits_per_pixel == xenfb_info->page->depth &&
++              var->xres <= info->fix.line_length / (XENFB_DEPTH / 8) &&
++              required_mem_len <= info->fix.smem_len) {
++              var->xres_virtual = var->xres;
++              var->yres_virtual = var->yres;
++              return 0;
++      }
++      return -EINVAL;
++}
++
++static int xenfb_set_par(struct fb_info *info)
++{
++      struct xenfb_info *xenfb_info;
++      unsigned long flags;
++
++      xenfb_info = info->par;
++
++      spin_lock_irqsave(&xenfb_info->resize_lock, flags);
++      xenfb_info->resize.type = XENFB_TYPE_RESIZE;
++      xenfb_info->resize.width = info->var.xres;
++      xenfb_info->resize.height = info->var.yres;
++      xenfb_info->resize.stride = info->fix.line_length;
++      xenfb_info->resize.depth = info->var.bits_per_pixel;
++      xenfb_info->resize.offset = 0;
++      xenfb_info->resize_dpy = 1;
++      spin_unlock_irqrestore(&xenfb_info->resize_lock, flags);
++      return 0;
++}
++
++static struct fb_ops xenfb_fb_ops = {
++      .owner          = THIS_MODULE,
++      .fb_setcolreg   = xenfb_setcolreg,
++      .fb_fillrect    = xenfb_fillrect,
++      .fb_copyarea    = xenfb_copyarea,
++      .fb_imageblit   = xenfb_imageblit,
++      .fb_mmap        = xenfb_mmap,
++      .fb_check_var   = xenfb_check_var,
++      .fb_set_par     = xenfb_set_par,
++};
++
++static irqreturn_t xenfb_event_handler(int rq, void *dev_id,
++                                     struct pt_regs *regs)
++{
++      /*
++       * No in events recognized, simply ignore them all.
++       * If you need to recognize some, see xenbkd's input_handler()
++       * for how to do that.
++       */
++      struct xenfb_info *info = dev_id;
++      struct xenfb_page *page = info->page;
++
++      if (page->in_cons != page->in_prod) {
++              info->page->in_cons = info->page->in_prod;
++              notify_remote_via_irq(info->irq);
++      }
++      return IRQ_HANDLED;
++}
++
++static unsigned long vmalloc_to_mfn(void *address)
++{
++      return pfn_to_mfn(vmalloc_to_pfn(address));
++}
++
++static int __devinit xenfb_probe(struct xenbus_device *dev,
++                               const struct xenbus_device_id *id)
++{
++      struct xenfb_info *info;
++      struct fb_info *fb_info;
++      int fb_size;
++      int val;
++      int ret;
++
++      info = kzalloc(sizeof(*info), GFP_KERNEL);
++      if (info == NULL) {
++              xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
++              return -ENOMEM;
++      }
++
++      /* Limit kernel param videoram amount to what is in xenstore */
++      if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) {
++              if (val < video[KPARAM_MEM])
++                      video[KPARAM_MEM] = val;
++      }
++
++      /* If requested res does not fit in available memory, use default */
++      fb_size = video[KPARAM_MEM] * MB_;
++      if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH/8 > fb_size) {
++              video[KPARAM_WIDTH] = XENFB_WIDTH;
++              video[KPARAM_HEIGHT] = XENFB_HEIGHT;
++              fb_size = XENFB_DEFAULT_FB_LEN;
++      }
++
++      dev->dev.driver_data = info;
++      info->xbdev = dev;
++      info->irq = -1;
++      info->x1 = info->y1 = INT_MAX;
++      spin_lock_init(&info->dirty_lock);
++      spin_lock_init(&info->resize_lock);
++      mutex_init(&info->mm_lock);
++      init_waitqueue_head(&info->wq);
++      init_timer(&info->refresh);
++      info->refresh.function = xenfb_timer;
++      info->refresh.data = (unsigned long)info;
++      INIT_LIST_HEAD(&info->mappings);
++
++      info->fb = vmalloc(fb_size);
++      if (info->fb == NULL)
++              goto error_nomem;
++      memset(info->fb, 0, fb_size);
++
++      info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
++
++      info->pages = kmalloc(sizeof(struct page *) * info->nr_pages,
++                            GFP_KERNEL);
++      if (info->pages == NULL)
++              goto error_nomem;
++
++      info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
++      if (!info->mfns)
++              goto error_nomem;
++
++      /* set up shared page */
++      info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
++      if (!info->page)
++              goto error_nomem;
++
++      fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
++                              /* see fishy hackery below */
++      if (fb_info == NULL)
++              goto error_nomem;
++
++      /* FIXME fishy hackery */
++      fb_info->pseudo_palette = fb_info->par;
++      fb_info->par = info;
++      /* /FIXME */
++      fb_info->screen_base = info->fb;
++
++      fb_info->fbops = &xenfb_fb_ops;
++      fb_info->var.xres_virtual = fb_info->var.xres = video[KPARAM_WIDTH];
++      fb_info->var.yres_virtual = fb_info->var.yres = video[KPARAM_HEIGHT];
++      fb_info->var.bits_per_pixel = XENFB_DEPTH;
++
++      fb_info->var.red = (struct fb_bitfield){16, 8, 0};
++      fb_info->var.green = (struct fb_bitfield){8, 8, 0};
++      fb_info->var.blue = (struct fb_bitfield){0, 8, 0};
++
++      fb_info->var.activate = FB_ACTIVATE_NOW;
++      fb_info->var.height = -1;
++      fb_info->var.width = -1;
++      fb_info->var.vmode = FB_VMODE_NONINTERLACED;
++
++      fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
++      fb_info->fix.line_length = fb_info->var.xres * (XENFB_DEPTH / 8);
++      fb_info->fix.smem_start = 0;
++      fb_info->fix.smem_len = fb_size;
++      strcpy(fb_info->fix.id, "xen");
++      fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
++      fb_info->fix.accel = FB_ACCEL_NONE;
++
++      fb_info->flags = FBINFO_FLAG_DEFAULT;
++
++      ret = fb_alloc_cmap(&fb_info->cmap, 256, 0);
++      if (ret < 0) {
++              framebuffer_release(fb_info);
++              xenbus_dev_fatal(dev, ret, "fb_alloc_cmap");
++              goto error;
++      }
++
++      xenfb_init_shared_page(info, fb_info);
++
++      ret = register_framebuffer(fb_info);
++      if (ret) {
++              fb_dealloc_cmap(&info->fb_info->cmap);
++              framebuffer_release(fb_info);
++              xenbus_dev_fatal(dev, ret, "register_framebuffer");
++              goto error;
++      }
++      info->fb_info = fb_info;
++
++      /* FIXME should this be delayed until backend XenbusStateConnected? */
++      info->kthread = kthread_run(xenfb_thread, info, "xenfb thread");
++      if (IS_ERR(info->kthread)) {
++              ret = PTR_ERR(info->kthread);
++              info->kthread = NULL;
++              xenbus_dev_fatal(dev, ret, "register_framebuffer");
++              goto error;
++      }
++
++      ret = xenfb_connect_backend(dev, info);
++      if (ret < 0)
++              goto error;
++
++      return 0;
++
++ error_nomem:
++      ret = -ENOMEM;
++      xenbus_dev_fatal(dev, ret, "allocating device memory");
++ error:
++      xenfb_remove(dev);
++      return ret;
++}
++
++static int xenfb_resume(struct xenbus_device *dev)
++{
++      struct xenfb_info *info = dev->dev.driver_data;
++
++      xenfb_disconnect_backend(info);
++      xenfb_init_shared_page(info, info->fb_info);
++      return xenfb_connect_backend(dev, info);
++}
++
++static int xenfb_remove(struct xenbus_device *dev)
++{
++      struct xenfb_info *info = dev->dev.driver_data;
++
++      del_timer(&info->refresh);
++      if (info->kthread)
++              kthread_stop(info->kthread);
++      xenfb_disconnect_backend(info);
++      if (info->fb_info) {
++              unregister_framebuffer(info->fb_info);
++              fb_dealloc_cmap(&info->fb_info->cmap);
++              framebuffer_release(info->fb_info);
++      }
++      free_page((unsigned long)info->page);
++      vfree(info->mfns);
++      kfree(info->pages);
++      vfree(info->fb);
++      kfree(info);
++
++      return 0;
++}
++
++static void xenfb_init_shared_page(struct xenfb_info *info,
++                                   struct fb_info * fb_info)
++{
++      int i;
++      int epd = PAGE_SIZE / sizeof(info->mfns[0]);
++
++      for (i = 0; i < info->nr_pages; i++)
++              info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE);
++
++      for (i = 0; i < info->nr_pages; i++)
++              info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
++
++      for (i = 0; i * epd < info->nr_pages; i++)
++              info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]);
++
++      info->page->width = fb_info->var.xres;
++      info->page->height = fb_info->var.yres;
++      info->page->depth = fb_info->var.bits_per_pixel;
++      info->page->line_length = fb_info->fix.line_length;
++      info->page->mem_length = fb_info->fix.smem_len;
++      info->page->in_cons = info->page->in_prod = 0;
++      info->page->out_cons = info->page->out_prod = 0;
++}
++
++static int xenfb_connect_backend(struct xenbus_device *dev,
++                               struct xenfb_info *info)
++{
++      int ret;
++      struct xenbus_transaction xbt;
++
++      ret = bind_listening_port_to_irqhandler(
++              dev->otherend_id, xenfb_event_handler, 0, "xenfb", info);
++      if (ret < 0) {
++              xenbus_dev_fatal(dev, ret,
++                               "bind_listening_port_to_irqhandler");
++              return ret;
++      }
++      info->irq = ret;
++
++ again:
++      ret = xenbus_transaction_start(&xbt);
++      if (ret) {
++              xenbus_dev_fatal(dev, ret, "starting transaction");
++              return ret;
++      }
++      ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
++                          virt_to_mfn(info->page));
++      if (ret)
++              goto error_xenbus;
++      ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
++                          irq_to_evtchn_port(info->irq));
++      if (ret)
++              goto error_xenbus;
++      ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s",
++                          XEN_IO_PROTO_ABI_NATIVE);
++      if (ret)
++              goto error_xenbus;
++      ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1");
++      if (ret)
++              goto error_xenbus;
++      ret = xenbus_transaction_end(xbt, 0);
++      if (ret) {
++              if (ret == -EAGAIN)
++                      goto again;
++              xenbus_dev_fatal(dev, ret, "completing transaction");
++              return ret;
++      }
++
++      xenbus_switch_state(dev, XenbusStateInitialised);
++      return 0;
++
++ error_xenbus:
++      xenbus_transaction_end(xbt, 1);
++      xenbus_dev_fatal(dev, ret, "writing xenstore");
++      return ret;
++}
++
++static void xenfb_disconnect_backend(struct xenfb_info *info)
++{
++      if (info->irq >= 0)
++              unbind_from_irqhandler(info->irq, info);
++      info->irq = -1;
++}
++
++static void xenfb_backend_changed(struct xenbus_device *dev,
++                                enum xenbus_state backend_state)
++{
++      struct xenfb_info *info = dev->dev.driver_data;
++      int val;
++
++      switch (backend_state) {
++      case XenbusStateInitialising:
++      case XenbusStateInitialised:
++      case XenbusStateReconfiguring:
++      case XenbusStateReconfigured:
++      case XenbusStateUnknown:
++      case XenbusStateClosed:
++              break;
++
++      case XenbusStateInitWait:
++      InitWait:
++              xenbus_switch_state(dev, XenbusStateConnected);
++              break;
++
++      case XenbusStateConnected:
++              /*
++               * Work around xenbus race condition: If backend goes
++               * through InitWait to Connected fast enough, we can
++               * get Connected twice here.
++               */
++              if (dev->state != XenbusStateConnected)
++                      goto InitWait; /* no InitWait seen yet, fudge it */
++
++              if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
++                               "request-update", "%d", &val) < 0)
++                      val = 0;
++              if (val)
++                      info->update_wanted = 1;
++
++              if (xenbus_scanf(XBT_NIL, dev->otherend,
++                                      "feature-resize", "%d", &val) < 0)
++                      val = 0;
++              info->feature_resize = val;
++              break;
++
++      case XenbusStateClosing:
++              // FIXME is this safe in any dev->state?
++              xenbus_frontend_closed(dev);
++              break;
++      }
++}
++
++static const struct xenbus_device_id xenfb_ids[] = {
++      { "vfb" },
++      { "" }
++};
++MODULE_ALIAS("xen:vfb");
++
++static struct xenbus_driver xenfb_driver = {
++      .name = "vfb",
++      .owner = THIS_MODULE,
++      .ids = xenfb_ids,
++      .probe = xenfb_probe,
++      .remove = xenfb_remove,
++      .resume = xenfb_resume,
++      .otherend_changed = xenfb_backend_changed,
++};
++
++static int __init xenfb_init(void)
++{
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      /* Nothing to do if running in dom0. */
++      if (is_initial_xendomain())
++              return -ENODEV;
++
++      return xenbus_register_frontend(&xenfb_driver);
++}
++
++static void __exit xenfb_cleanup(void)
++{
++      return xenbus_unregister_driver(&xenfb_driver);
++}
++
++module_init(xenfb_init);
++module_exit(xenfb_cleanup);
++
++MODULE_LICENSE("GPL");
+--- linux-2.6.18.8/drivers/xen/fbfront/xenkbd.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/fbfront/xenkbd.c   2008-05-19 00:33:45.834788090 +0300
+@@ -0,0 +1,354 @@
++/*
++ * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device
++ *
++ * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
++ * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
++ *
++ *  Based on linux/drivers/input/mouse/sermouse.c
++ *
++ *  This file is subject to the terms and conditions of the GNU General Public
++ *  License. See the file COPYING in the main directory of this archive for
++ *  more details.
++ */
++
++/*
++ * TODO:
++ *
++ * Switch to grant tables together with xenfb.c.
++ */
++
++#include <linux/kernel.h>
++#include <linux/errno.h>
++#include <linux/module.h>
++#include <linux/input.h>
++#include <asm/hypervisor.h>
++#include <xen/evtchn.h>
++#include <xen/interface/io/fbif.h>
++#include <xen/interface/io/kbdif.h>
++#include <xen/xenbus.h>
++
++struct xenkbd_info
++{
++      struct input_dev *kbd;
++      struct input_dev *ptr;
++      struct xenkbd_page *page;
++      int irq;
++      struct xenbus_device *xbdev;
++      char phys[32];
++};
++
++static int xenkbd_remove(struct xenbus_device *);
++static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
++static void xenkbd_disconnect_backend(struct xenkbd_info *);
++
++/*
++ * Note: if you need to send out events, see xenfb_do_update() for how
++ * to do that.
++ */
++
++static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs)
++{
++      struct xenkbd_info *info = dev_id;
++      struct xenkbd_page *page = info->page;
++      __u32 cons, prod;
++
++      prod = page->in_prod;
++      if (prod == page->in_cons)
++              return IRQ_HANDLED;
++      rmb();                  /* ensure we see ring contents up to prod */
++      for (cons = page->in_cons; cons != prod; cons++) {
++              union xenkbd_in_event *event;
++              struct input_dev *dev;
++              event = &XENKBD_IN_RING_REF(page, cons);
++
++              dev = info->ptr;
++              switch (event->type) {
++              case XENKBD_TYPE_MOTION:
++                      if (event->motion.rel_z)
++                              input_report_rel(dev, REL_WHEEL,
++                                               -event->motion.rel_z);
++                      input_report_rel(dev, REL_X, event->motion.rel_x);
++                      input_report_rel(dev, REL_Y, event->motion.rel_y);
++                      break;
++              case XENKBD_TYPE_KEY:
++                      dev = NULL;
++                      if (test_bit(event->key.keycode, info->kbd->keybit))
++                              dev = info->kbd;
++                      if (test_bit(event->key.keycode, info->ptr->keybit))
++                              dev = info->ptr;
++                      if (dev)
++                              input_report_key(dev, event->key.keycode,
++                                               event->key.pressed);
++                      else
++                              printk("xenkbd: unhandled keycode 0x%x\n",
++                                     event->key.keycode);
++                      break;
++              case XENKBD_TYPE_POS:
++                      if (event->pos.rel_z)
++                              input_report_rel(dev, REL_WHEEL,
++                                               -event->pos.rel_z);
++                      input_report_abs(dev, ABS_X, event->pos.abs_x);
++                      input_report_abs(dev, ABS_Y, event->pos.abs_y);
++                      break;
++              }
++              if (dev)
++                      input_sync(dev);
++      }
++      mb();                   /* ensure we got ring contents */
++      page->in_cons = cons;
++      notify_remote_via_irq(info->irq);
++
++      return IRQ_HANDLED;
++}
++
++int __devinit xenkbd_probe(struct xenbus_device *dev,
++                         const struct xenbus_device_id *id)
++{
++      int ret, i;
++      struct xenkbd_info *info;
++      struct input_dev *kbd, *ptr;
++
++      info = kzalloc(sizeof(*info), GFP_KERNEL);
++      if (!info) {
++              xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
++              return -ENOMEM;
++      }
++      dev->dev.driver_data = info;
++      info->xbdev = dev;
++      snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename);
++
++      info->page = (void *)__get_free_page(GFP_KERNEL);
++      if (!info->page)
++              goto error_nomem;
++      info->page->in_cons = info->page->in_prod = 0;
++      info->page->out_cons = info->page->out_prod = 0;
++
++      /* keyboard */
++      kbd = input_allocate_device();
++      if (!kbd)
++              goto error_nomem;
++      kbd->name = "Xen Virtual Keyboard";
++      kbd->phys = info->phys;
++      kbd->id.bustype = BUS_PCI;
++      kbd->id.vendor = 0x5853;
++      kbd->id.product = 0xffff;
++      kbd->evbit[0] = BIT(EV_KEY);
++      for (i = KEY_ESC; i < KEY_UNKNOWN; i++)
++              set_bit(i, kbd->keybit);
++      for (i = KEY_OK; i < KEY_MAX; i++)
++              set_bit(i, kbd->keybit);
++
++      ret = input_register_device(kbd);
++      if (ret) {
++              input_free_device(kbd);
++              xenbus_dev_fatal(dev, ret, "input_register_device(kbd)");
++              goto error;
++      }
++      info->kbd = kbd;
++
++      /* pointing device */
++      ptr = input_allocate_device();
++      if (!ptr)
++              goto error_nomem;
++      ptr->name = "Xen Virtual Pointer";
++      ptr->phys = info->phys;
++      ptr->id.bustype = BUS_PCI;
++      ptr->id.vendor = 0x5853;
++      ptr->id.product = 0xfffe;
++      ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
++      for (i = BTN_LEFT; i <= BTN_TASK; i++)
++              set_bit(i, ptr->keybit);
++      ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y) | BIT(REL_WHEEL);
++      input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0);
++      input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
++
++      ret = input_register_device(ptr);
++      if (ret) {
++              input_free_device(ptr);
++              xenbus_dev_fatal(dev, ret, "input_register_device(ptr)");
++              goto error;
++      }
++      info->ptr = ptr;
++
++      ret = xenkbd_connect_backend(dev, info);
++      if (ret < 0)
++              goto error;
++
++      return 0;
++
++ error_nomem:
++      ret = -ENOMEM;
++      xenbus_dev_fatal(dev, ret, "allocating device memory");
++ error:
++      xenkbd_remove(dev);
++      return ret;
++}
++
++static int xenkbd_resume(struct xenbus_device *dev)
++{
++      struct xenkbd_info *info = dev->dev.driver_data;
++
++      xenkbd_disconnect_backend(info);
++      info->page->in_cons = info->page->in_prod = 0;
++      info->page->out_cons = info->page->out_prod = 0;
++      return xenkbd_connect_backend(dev, info);
++}
++
++static int xenkbd_remove(struct xenbus_device *dev)
++{
++      struct xenkbd_info *info = dev->dev.driver_data;
++
++      xenkbd_disconnect_backend(info);
++      input_unregister_device(info->kbd);
++      input_unregister_device(info->ptr);
++      free_page((unsigned long)info->page);
++      kfree(info);
++      return 0;
++}
++
++static int xenkbd_connect_backend(struct xenbus_device *dev,
++                                struct xenkbd_info *info)
++{
++      int ret;
++      struct xenbus_transaction xbt;
++
++      ret = bind_listening_port_to_irqhandler(
++              dev->otherend_id, input_handler, 0, "xenkbd", info);
++      if (ret < 0) {
++              xenbus_dev_fatal(dev, ret,
++                               "bind_listening_port_to_irqhandler");
++              return ret;
++      }
++      info->irq = ret;
++
++ again:
++      ret = xenbus_transaction_start(&xbt);
++      if (ret) {
++              xenbus_dev_fatal(dev, ret, "starting transaction");
++              return ret;
++      }
++      ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
++                          virt_to_mfn(info->page));
++      if (ret)
++              goto error_xenbus;
++      ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
++                          irq_to_evtchn_port(info->irq));
++      if (ret)
++              goto error_xenbus;
++      ret = xenbus_transaction_end(xbt, 0);
++      if (ret) {
++              if (ret == -EAGAIN)
++                      goto again;
++              xenbus_dev_fatal(dev, ret, "completing transaction");
 +              return ret;
 +      }
-+      ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
-+                          virt_to_mfn(info->page));
-+      if (ret)
-+              goto error_xenbus;
-+      ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
-+                          irq_to_evtchn_port(info->irq));
-+      if (ret)
-+              goto error_xenbus;
-+      ret = xenbus_transaction_end(xbt, 0);
-+      if (ret) {
-+              if (ret == -EAGAIN)
-+                      goto again;
-+              xenbus_dev_fatal(dev, ret, "completing transaction");
-+              return ret;
++
++      xenbus_switch_state(dev, XenbusStateInitialised);
++      return 0;
++
++ error_xenbus:
++      xenbus_transaction_end(xbt, 1);
++      xenbus_dev_fatal(dev, ret, "writing xenstore");
++      return ret;
++}
++
++static void xenkbd_disconnect_backend(struct xenkbd_info *info)
++{
++      if (info->irq >= 0)
++              unbind_from_irqhandler(info->irq, info);
++      info->irq = -1;
++}
++
++static void xenkbd_backend_changed(struct xenbus_device *dev,
++                                 enum xenbus_state backend_state)
++{
++      struct xenkbd_info *info = dev->dev.driver_data;
++      int ret, val;
++
++      switch (backend_state) {
++      case XenbusStateInitialising:
++      case XenbusStateInitialised:
++      case XenbusStateReconfiguring:
++      case XenbusStateReconfigured:
++      case XenbusStateUnknown:
++      case XenbusStateClosed:
++              break;
++
++      case XenbusStateInitWait:
++      InitWait:
++              ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
++                                 "feature-abs-pointer", "%d", &val);
++              if (ret < 0)
++                      val = 0;
++              if (val) {
++                      ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
++                                          "request-abs-pointer", "1");
++                      if (ret)
++                              ; /* FIXME */
++              }
++              xenbus_switch_state(dev, XenbusStateConnected);
++              break;
++
++      case XenbusStateConnected:
++              /*
++               * Work around xenbus race condition: If backend goes
++               * through InitWait to Connected fast enough, we can
++               * get Connected twice here.
++               */
++              if (dev->state != XenbusStateConnected)
++                      goto InitWait; /* no InitWait seen yet, fudge it */
++
++              /* Set input abs params to match backend screen res */
++              if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
++                                 "width", "%d", &val) > 0 )
++                      input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0);
++
++              if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
++                                 "height", "%d", &val) > 0 )
++                      input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0);
++
++              break;
++
++      case XenbusStateClosing:
++              xenbus_frontend_closed(dev);
++              break;
++      }
++}
++
++static const struct xenbus_device_id xenkbd_ids[] = {
++      { "vkbd" },
++      { "" }
++};
++MODULE_ALIAS("xen:vkbd");
++
++static struct xenbus_driver xenkbd_driver = {
++      .name = "vkbd",
++      .owner = THIS_MODULE,
++      .ids = xenkbd_ids,
++      .probe = xenkbd_probe,
++      .remove = xenkbd_remove,
++      .resume = xenkbd_resume,
++      .otherend_changed = xenkbd_backend_changed,
++};
++
++static int __init xenkbd_init(void)
++{
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      /* Nothing to do if running in dom0. */
++      if (is_initial_xendomain())
++              return -ENODEV;
++
++      return xenbus_register_frontend(&xenkbd_driver);
++}
++
++static void __exit xenkbd_cleanup(void)
++{
++      return xenbus_unregister_driver(&xenkbd_driver);
++}
++
++module_init(xenkbd_init);
++module_exit(xenkbd_cleanup);
++
++MODULE_LICENSE("GPL");
+--- linux-2.6.18.8/drivers/xen/gntdev/Makefile 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/gntdev/Makefile    2008-05-19 00:33:45.834788090 +0300
+@@ -0,0 +1 @@
++obj-$(CONFIG_XEN_GRANT_DEV) := gntdev.o
+--- linux-2.6.18.8/drivers/xen/gntdev/gntdev.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/gntdev/gntdev.c    2008-05-19 00:33:45.838788321 +0300
+@@ -0,0 +1,1077 @@
++/******************************************************************************
++ * gntdev.c
++ * 
++ * Device for accessing (in user-space) pages that have been granted by other
++ * domains.
++ *
++ * Copyright (c) 2006-2007, D G Murray.
++ * 
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ * 
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ */
++
++#include <asm/atomic.h>
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/device.h>
++#include <linux/mm.h>
++#include <linux/mman.h>
++#include <asm/uaccess.h>
++#include <asm/io.h>
++#include <xen/gnttab.h>
++#include <asm/hypervisor.h>
++#include <xen/balloon.h>
++#include <xen/evtchn.h>
++#include <xen/driver_util.h>
++
++#include <linux/types.h>
++#include <xen/public/gntdev.h>
++
++
++#define DRIVER_AUTHOR "Derek G. Murray <Derek.Murray@cl.cam.ac.uk>"
++#define DRIVER_DESC   "User-space granted page access driver"
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR(DRIVER_AUTHOR);
++MODULE_DESCRIPTION(DRIVER_DESC);
++
++#define MAX_GRANTS_LIMIT   1024
++#define DEFAULT_MAX_GRANTS 128
++
++/* A slot can be in one of three states:
++ *
++ * 0. GNTDEV_SLOT_INVALID:
++ *    This slot is not associated with a grant reference, and is therefore free
++ *    to be overwritten by a new grant reference.
++ *
++ * 1. GNTDEV_SLOT_NOT_YET_MAPPED:
++ *    This slot is associated with a grant reference (via the 
++ *    IOCTL_GNTDEV_MAP_GRANT_REF ioctl), but it has not yet been mmap()-ed.
++ *
++ * 2. GNTDEV_SLOT_MAPPED:
++ *    This slot is associated with a grant reference, and has been mmap()-ed.
++ */
++typedef enum gntdev_slot_state {
++      GNTDEV_SLOT_INVALID = 0,
++      GNTDEV_SLOT_NOT_YET_MAPPED,
++      GNTDEV_SLOT_MAPPED
++} gntdev_slot_state_t;
++
++#define GNTDEV_INVALID_HANDLE    -1
++#define GNTDEV_FREE_LIST_INVALID -1
++/* Each opened instance of gntdev is associated with a list of grants,
++ * represented by an array of elements of the following type,
++ * gntdev_grant_info_t.
++ */
++typedef struct gntdev_grant_info {
++      gntdev_slot_state_t state;
++      union {
++              uint32_t free_list_index;
++              struct {
++                      domid_t domid;
++                      grant_ref_t ref;
++                      grant_handle_t kernel_handle;
++                      grant_handle_t user_handle;
++                      uint64_t dev_bus_addr;
++              } valid;
++      } u;
++} gntdev_grant_info_t;
++
++/* Private data structure, which is stored in the file pointer for files
++ * associated with this device.
++ */
++typedef struct gntdev_file_private_data {
++  
++      /* Array of grant information. */
++      gntdev_grant_info_t *grants;
++      uint32_t grants_size;
++
++      /* Read/write semaphore used to protect the grants array. */
++      struct rw_semaphore grants_sem;
++
++      /* An array of indices of free slots in the grants array.
++       * N.B. An entry in this list may temporarily have the value
++       * GNTDEV_FREE_LIST_INVALID if the corresponding slot has been removed
++       * from the list by the contiguous allocator, but the list has not yet
++       * been compressed. However, this is not visible across invocations of
++       * the device.
++       */
++      int32_t *free_list;
++      
++      /* The number of free slots in the grants array. */
++      uint32_t free_list_size;
++
++      /* Read/write semaphore used to protect the free list. */
++      struct rw_semaphore free_list_sem;
++      
++      /* Index of the next slot after the most recent contiguous allocation, 
++       * for use in a next-fit allocator.
++       */
++      uint32_t next_fit_index;
++
++      /* Used to map grants into the kernel, before mapping them into user
++       * space.
++       */
++      struct page **foreign_pages;
++
++} gntdev_file_private_data_t;
++
++/* Module lifecycle operations. */
++static int __init gntdev_init(void);
++static void __exit gntdev_exit(void);
++
++module_init(gntdev_init);
++module_exit(gntdev_exit);
++
++/* File operations. */
++static int gntdev_open(struct inode *inode, struct file *flip);
++static int gntdev_release(struct inode *inode, struct file *flip);
++static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma);
++static long gntdev_ioctl(struct file *flip,
++                       unsigned int cmd, unsigned long arg);
++
++static const struct file_operations gntdev_fops = {
++      .owner = THIS_MODULE,
++      .open = gntdev_open,
++      .release = gntdev_release,
++      .mmap = gntdev_mmap,
++      .unlocked_ioctl = gntdev_ioctl
++};
++
++/* VM operations. */
++static void gntdev_vma_close(struct vm_area_struct *vma);
++static pte_t gntdev_clear_pte(struct vm_area_struct *vma, unsigned long addr,
++                            pte_t *ptep, int is_fullmm);
++
++static struct vm_operations_struct gntdev_vmops = {
++      .close = gntdev_vma_close,
++      .zap_pte = gntdev_clear_pte
++};
++
++/* Global variables. */
++
++/* The driver major number, for use when unregistering the driver. */
++static int gntdev_major;
++
++#define GNTDEV_NAME "gntdev"
++
++/* Memory mapping functions
++ * ------------------------
++ *
++ * Every granted page is mapped into both kernel and user space, and the two
++ * following functions return the respective virtual addresses of these pages.
++ *
++ * When shadow paging is disabled, the granted page is mapped directly into
++ * user space; when it is enabled, it is mapped into the kernel and remapped
++ * into user space using vm_insert_page() (see gntdev_mmap(), below).
++ */
++
++/* Returns the virtual address (in user space) of the @page_index'th page
++ * in the given VM area.
++ */
++static inline unsigned long get_user_vaddr (struct vm_area_struct *vma,
++                                          int page_index)
++{
++      return (unsigned long) vma->vm_start + (page_index << PAGE_SHIFT);
++}
++
++/* Returns the virtual address (in kernel space) of the @slot_index'th page
++ * mapped by the gntdev instance that owns the given private data struct.
++ */
++static inline unsigned long get_kernel_vaddr (gntdev_file_private_data_t *priv,
++                                            int slot_index)
++{
++      unsigned long pfn;
++      void *kaddr;
++      pfn = page_to_pfn(priv->foreign_pages[slot_index]);
++      kaddr = pfn_to_kaddr(pfn);
++      return (unsigned long) kaddr;
++}
++
++/* Helper functions. */
++
++/* Adds information about a grant reference to the list of grants in the file's
++ * private data structure. Returns non-zero on failure. On success, sets the
++ * value of *offset to the offset that should be mmap()-ed in order to map the
++ * grant reference.
++ */
++static int add_grant_reference(struct file *flip,
++                             struct ioctl_gntdev_grant_ref *op,
++                             uint64_t *offset)
++{
++      gntdev_file_private_data_t *private_data 
++              = (gntdev_file_private_data_t *) flip->private_data;
++
++      uint32_t slot_index;
++
++      if (unlikely(private_data->free_list_size == 0)) {
++              return -ENOMEM;
++      }
++
++      slot_index = private_data->free_list[--private_data->free_list_size];
++      private_data->free_list[private_data->free_list_size]
++              = GNTDEV_FREE_LIST_INVALID;
++
++      /* Copy the grant information into file's private data. */
++      private_data->grants[slot_index].state = GNTDEV_SLOT_NOT_YET_MAPPED;
++      private_data->grants[slot_index].u.valid.domid = op->domid;
++      private_data->grants[slot_index].u.valid.ref = op->ref;
++
++      /* The offset is calculated as the index of the chosen entry in the
++       * file's private data's array of grant information. This is then
++       * shifted to give an offset into the virtual "file address space".
++       */
++      *offset = slot_index << PAGE_SHIFT;
++
++      return 0;
++}
++
++/* Adds the @count grant references to the contiguous range in the slot array
++ * beginning at @first_slot. It is assumed that @first_slot was returned by a
++ * previous invocation of find_contiguous_free_range(), during the same
++ * invocation of the driver.
++ */
++static int add_grant_references(struct file *flip,
++                              int count,
++                              struct ioctl_gntdev_grant_ref *ops,
++                              uint32_t first_slot)
++{
++      gntdev_file_private_data_t *private_data 
++              = (gntdev_file_private_data_t *) flip->private_data;
++      int i;
++      
++      for (i = 0; i < count; ++i) {
++
++              /* First, mark the slot's entry in the free list as invalid. */
++              int free_list_index = 
++                      private_data->grants[first_slot+i].u.free_list_index;
++              private_data->free_list[free_list_index] = 
++                      GNTDEV_FREE_LIST_INVALID;
++
++              /* Now, update the slot. */
++              private_data->grants[first_slot+i].state = 
++                      GNTDEV_SLOT_NOT_YET_MAPPED;
++              private_data->grants[first_slot+i].u.valid.domid =
++                      ops[i].domid;
++              private_data->grants[first_slot+i].u.valid.ref = ops[i].ref;
++      }
++
++      return 0;       
++}
++
++/* Scans through the free list for @flip, removing entries that are marked as
++ * GNTDEV_SLOT_INVALID. This will reduce the recorded size of the free list to
++ * the number of valid entries.
++ */
++static void compress_free_list(struct file *flip) 
++{
++      gntdev_file_private_data_t *private_data 
++              = (gntdev_file_private_data_t *) flip->private_data;
++      int i, j = 0, old_size, slot_index;
++      
++      old_size = private_data->free_list_size;
++      for (i = 0; i < old_size; ++i) {
++              if (private_data->free_list[i] != GNTDEV_FREE_LIST_INVALID) {
++                      if (i > j) {
++                              slot_index = private_data->free_list[i];
++                              private_data->free_list[j] = slot_index;
++                              private_data->grants[slot_index].u
++                                      .free_list_index = j;
++                              private_data->free_list[i] 
++                                      = GNTDEV_FREE_LIST_INVALID;
++                      }
++                      ++j;
++              } else {
++                      --private_data->free_list_size;
++              }
++      }
++}
++
++/* Searches the grant array in the private data of @flip for a range of
++ * @num_slots contiguous slots in the GNTDEV_SLOT_INVALID state.
++ *
++ * Returns the index of the first slot if a range is found, otherwise -ENOMEM.
++ */
++static int find_contiguous_free_range(struct file *flip,
++                                    uint32_t num_slots) 
++{
++      gntdev_file_private_data_t *private_data 
++              = (gntdev_file_private_data_t *) flip->private_data;
++      
++      int i;
++      int start_index = private_data->next_fit_index;
++      int range_start = 0, range_length;
++
++      if (private_data->free_list_size < num_slots) {
++              return -ENOMEM;
++      }
++
++      /* First search from the start_index to the end of the array. */
++      range_length = 0;
++      for (i = start_index; i < private_data->grants_size; ++i) {
++              if (private_data->grants[i].state == GNTDEV_SLOT_INVALID) {
++                      if (range_length == 0) {
++                              range_start = i;
++                      }
++                      ++range_length;
++                      if (range_length == num_slots) {
++                              return range_start;
++                      }
++              }
++      }
++      
++      /* Now search from the start of the array to the start_index. */
++      range_length = 0;
++      for (i = 0; i < start_index; ++i) {
++              if (private_data->grants[i].state == GNTDEV_SLOT_INVALID) {
++                      if (range_length == 0) {
++                              range_start = i;
++                      }
++                      ++range_length;
++                      if (range_length == num_slots) {
++                              return range_start;
++                      }
++              }
++      }
++      
++      return -ENOMEM;
++}
++
++static int init_private_data(gntdev_file_private_data_t *priv,
++                           uint32_t max_grants)
++{
++      int i;
++
++      /* Allocate space for the kernel-mapping of granted pages. */
++      priv->foreign_pages = 
++              alloc_empty_pages_and_pagevec(max_grants);
++      if (!priv->foreign_pages)
++              goto nomem_out;
++
++      /* Allocate the grant list and free-list. */
++      priv->grants = kmalloc(max_grants * sizeof(gntdev_grant_info_t),
++                             GFP_KERNEL);
++      if (!priv->grants)
++              goto nomem_out2;
++      priv->free_list = kmalloc(max_grants * sizeof(int32_t), GFP_KERNEL);
++      if (!priv->free_list)
++              goto nomem_out3;
++
++      /* Initialise the free-list, which contains all slots at first. */
++      for (i = 0; i < max_grants; ++i) {
++              priv->free_list[max_grants - i - 1] = i;
++              priv->grants[i].state = GNTDEV_SLOT_INVALID;
++              priv->grants[i].u.free_list_index = max_grants - i - 1;
++      }
++      priv->grants_size = max_grants;
++      priv->free_list_size = max_grants;
++      priv->next_fit_index = 0;
++
++      up_write(&priv->grants_sem);
++      up_write(&priv->free_list_sem);
++
++      return 0;
++
++nomem_out3:
++      kfree(priv->grants);
++nomem_out2:
++      free_empty_pages_and_pagevec(priv->foreign_pages, max_grants);
++nomem_out:
++      return -ENOMEM;
++
++}
++
++/* Interface functions. */
++
++/* Initialises the driver. Called when the module is loaded. */
++static int __init gntdev_init(void)
++{
++      struct class *class;
++      struct class_device *device;
++
++      if (!is_running_on_xen()) {
++              printk(KERN_ERR "You must be running Xen to use gntdev\n");
++              return -ENODEV;
++      }
++
++      gntdev_major = register_chrdev(0, GNTDEV_NAME, &gntdev_fops);
++      if (gntdev_major < 0)
++      {
++              printk(KERN_ERR "Could not register gntdev device\n");
++              return -ENOMEM;
++      }
++
++      /* Note that if the sysfs code fails, we will still initialise the
++       * device, and output the major number so that the device can be
++       * created manually using mknod.
++       */
++      if ((class = get_xen_class()) == NULL) {
++              printk(KERN_ERR "Error setting up xen_class\n");
++              printk(KERN_ERR "gntdev created with major number = %d\n", 
++                     gntdev_major);
++              return 0;
++      }
++
++      device = class_device_create(class, NULL, MKDEV(gntdev_major, 0),
++                                   NULL, GNTDEV_NAME);
++      if (IS_ERR(device)) {
++              printk(KERN_ERR "Error creating gntdev device in xen_class\n");
++              printk(KERN_ERR "gntdev created with major number = %d\n",
++                     gntdev_major);
++              return 0;
++      }
++
++      return 0;
++}
++
++/* Cleans up and unregisters the driver. Called when the driver is unloaded.
++ */
++static void __exit gntdev_exit(void)
++{
++      struct class *class;
++      if ((class = get_xen_class()) != NULL)
++              class_device_destroy(class, MKDEV(gntdev_major, 0));
++      unregister_chrdev(gntdev_major, GNTDEV_NAME);
++}
++
++/* Called when the device is opened. */
++static int gntdev_open(struct inode *inode, struct file *flip)
++{
++      gntdev_file_private_data_t *private_data;
++
++      try_module_get(THIS_MODULE);
++
++      /* Allocate space for the per-instance private data. */
++      private_data = kmalloc(sizeof(*private_data), GFP_KERNEL);
++      if (!private_data)
++              goto nomem_out;
++
++      /* These will be lazily initialised by init_private_data. */
++      private_data->grants = NULL;
++      private_data->free_list = NULL;
++      private_data->foreign_pages = NULL;
++
++      init_rwsem(&private_data->grants_sem);
++      init_rwsem(&private_data->free_list_sem);
++
++      flip->private_data = private_data;
++
++      return 0;
++
++nomem_out:
++      return -ENOMEM;
++}
++
++/* Called when the device is closed.
++ */
++static int gntdev_release(struct inode *inode, struct file *flip)
++{
++      if (flip->private_data) {
++              gntdev_file_private_data_t *private_data = 
++                      (gntdev_file_private_data_t *) flip->private_data;
++              if (private_data->foreign_pages)
++                      free_empty_pages_and_pagevec
++                              (private_data->foreign_pages,
++                               private_data->grants_size);
++              if (private_data->grants) 
++                      kfree(private_data->grants);
++              if (private_data->free_list)
++                      kfree(private_data->free_list);
++              kfree(private_data);
++      }
++      module_put(THIS_MODULE);
++      return 0;
++}
++
++/* Called when an attempt is made to mmap() the device. The private data from
++ * @flip contains the list of grant references that can be mapped. The vm_pgoff
++ * field of @vma contains the index into that list that refers to the grant
++ * reference that will be mapped. Only mappings that are a multiple of
++ * PAGE_SIZE are handled.
++ */
++static int gntdev_mmap (struct file *flip, struct vm_area_struct *vma) 
++{
++      struct gnttab_map_grant_ref op;
++      unsigned long slot_index = vma->vm_pgoff;
++      unsigned long kernel_vaddr, user_vaddr;
++      uint32_t size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
++      uint64_t ptep;
++      int ret;
++      int flags;
++      int i;
++      struct page *page;
++      gntdev_file_private_data_t *private_data = flip->private_data;
++
++      if (unlikely(!private_data)) {
++              printk(KERN_ERR "File's private data is NULL.\n");
++              return -EINVAL;
++      }
++
++      /* Test to make sure that the grants array has been initialised. */
++      down_read(&private_data->grants_sem);
++      if (unlikely(!private_data->grants)) {
++              up_read(&private_data->grants_sem);
++              printk(KERN_ERR "Attempted to mmap before ioctl.\n");
++              return -EINVAL;
++      }
++      up_read(&private_data->grants_sem);
++
++      if (unlikely((size <= 0) || 
++                   (size + slot_index) > private_data->grants_size)) {
++              printk(KERN_ERR "Invalid number of pages or offset"
++                     "(num_pages = %d, first_slot = %ld).\n",
++                     size, slot_index);
++              return -ENXIO;
++      }
++
++      if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) {
++              printk(KERN_ERR "Writable mappings must be shared.\n");
++              return -EINVAL;
++      }
++
++      /* Slots must be in the NOT_YET_MAPPED state. */
++      down_write(&private_data->grants_sem);
++      for (i = 0; i < size; ++i) {
++              if (private_data->grants[slot_index + i].state != 
++                  GNTDEV_SLOT_NOT_YET_MAPPED) {
++                      printk(KERN_ERR "Slot (index = %ld) is in the wrong "
++                             "state (%d).\n", slot_index + i, 
++                             private_data->grants[slot_index + i].state);
++                      up_write(&private_data->grants_sem);
++                      return -EINVAL;
++              }
++      }
++
++      /* Install the hook for unmapping. */
++      vma->vm_ops = &gntdev_vmops;
++    
++      /* The VM area contains pages from another VM. */
++      vma->vm_flags |= VM_FOREIGN;
++      vma->vm_private_data = kzalloc(size * sizeof(struct page *),
++                                     GFP_KERNEL);
++      if (vma->vm_private_data == NULL) {
++              printk(KERN_ERR "Couldn't allocate mapping structure for VM "
++                     "area.\n");
++              return -ENOMEM;
++      }
++
++      /* This flag prevents Bad PTE errors when the memory is unmapped. */
++      vma->vm_flags |= VM_RESERVED;
++
++      /* This flag prevents this VM area being copied on a fork(). A better
++       * behaviour might be to explicitly carry out the appropriate mappings
++       * on fork(), but I don't know if there's a hook for this.
++       */
++      vma->vm_flags |= VM_DONTCOPY;
++
++#ifdef CONFIG_X86
++      /* This flag ensures that the page tables are not unpinned before the
++       * VM area is unmapped. Therefore Xen still recognises the PTE as
++       * belonging to an L1 pagetable, and the grant unmap operation will
++       * succeed, even if the process does not exit cleanly.
++       */
++      vma->vm_mm->context.has_foreign_mappings = 1;
++#endif
++
++      for (i = 0; i < size; ++i) {
++
++              flags = GNTMAP_host_map;
++              if (!(vma->vm_flags & VM_WRITE))
++                      flags |= GNTMAP_readonly;
++
++              kernel_vaddr = get_kernel_vaddr(private_data, slot_index + i);
++              user_vaddr = get_user_vaddr(vma, i);
++              page = pfn_to_page(__pa(kernel_vaddr) >> PAGE_SHIFT);
++
++              gnttab_set_map_op(&op, kernel_vaddr, flags,   
++                                private_data->grants[slot_index+i]
++                                .u.valid.ref, 
++                                private_data->grants[slot_index+i]
++                                .u.valid.domid);
++
++              /* Carry out the mapping of the grant reference. */
++              ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, 
++                                              &op, 1);
++              BUG_ON(ret);
++              if (op.status) {
++                      printk(KERN_ERR "Error mapping the grant reference "
++                             "into the kernel (%d). domid = %d; ref = %d\n",
++                             op.status,
++                             private_data->grants[slot_index+i]
++                             .u.valid.domid,
++                             private_data->grants[slot_index+i]
++                             .u.valid.ref);
++                      goto undo_map_out;
++              }
++
++              /* Store a reference to the page that will be mapped into user
++               * space.
++               */
++              ((struct page **) vma->vm_private_data)[i] = page;
++
++              /* Mark mapped page as reserved. */
++              SetPageReserved(page);
++
++              /* Record the grant handle, for use in the unmap operation. */
++              private_data->grants[slot_index+i].u.valid.kernel_handle = 
++                      op.handle;
++              private_data->grants[slot_index+i].u.valid.dev_bus_addr = 
++                      op.dev_bus_addr;
++              
++              private_data->grants[slot_index+i].state = GNTDEV_SLOT_MAPPED;
++              private_data->grants[slot_index+i].u.valid.user_handle =
++                      GNTDEV_INVALID_HANDLE;
++
++              /* Now perform the mapping to user space. */
++              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++
++                      /* NOT USING SHADOW PAGE TABLES. */
++                      /* In this case, we map the grant(s) straight into user
++                       * space.
++                       */
++
++                      /* Get the machine address of the PTE for the user 
++                       *  page.
++                       */
++                      if ((ret = create_lookup_pte_addr(vma->vm_mm, 
++                                                        vma->vm_start 
++                                                        + (i << PAGE_SHIFT), 
++                                                        &ptep)))
++                      {
++                              printk(KERN_ERR "Error obtaining PTE pointer "
++                                     "(%d).\n", ret);
++                              goto undo_map_out;
++                      }
++                      
++                      /* Configure the map operation. */
++              
++                      /* The reference is to be used by host CPUs. */
++                      flags = GNTMAP_host_map;
++                      
++                      /* Specifies a user space mapping. */
++                      flags |= GNTMAP_application_map;
++                      
++                      /* The map request contains the machine address of the
++                       * PTE to update.
++                       */
++                      flags |= GNTMAP_contains_pte;
++                      
++                      if (!(vma->vm_flags & VM_WRITE))
++                              flags |= GNTMAP_readonly;
++
++                      gnttab_set_map_op(&op, ptep, flags, 
++                                        private_data->grants[slot_index+i]
++                                        .u.valid.ref, 
++                                        private_data->grants[slot_index+i]
++                                        .u.valid.domid);
++
++                      /* Carry out the mapping of the grant reference. */
++                      ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
++                                                      &op, 1);
++                      BUG_ON(ret);
++                      if (op.status) {
++                              printk(KERN_ERR "Error mapping the grant "
++                                     "reference into user space (%d). domid "
++                                     "= %d; ref = %d\n", op.status,
++                                     private_data->grants[slot_index+i].u
++                                     .valid.domid,
++                                     private_data->grants[slot_index+i].u
++                                     .valid.ref);
++                              goto undo_map_out;
++                      }
++                      
++                      /* Record the grant handle, for use in the unmap 
++                       * operation. 
++                       */
++                      private_data->grants[slot_index+i].u.
++                              valid.user_handle = op.handle;
++
++                      /* Update p2m structure with the new mapping. */
++                      set_phys_to_machine(__pa(kernel_vaddr) >> PAGE_SHIFT,
++                                          FOREIGN_FRAME(private_data->
++                                                        grants[slot_index+i]
++                                                        .u.valid.dev_bus_addr
++                                                        >> PAGE_SHIFT));
++              } else {
++                      /* USING SHADOW PAGE TABLES. */
++                      /* In this case, we simply insert the page into the VM
++                       * area. */
++                      ret = vm_insert_page(vma, user_vaddr, page);
++              }
++
++      }
++
++      up_write(&private_data->grants_sem);
++      return 0;
++
++undo_map_out:
++      /* If we have a mapping failure, the unmapping will be taken care of
++       * by do_mmap_pgoff(), which will eventually call gntdev_clear_pte().
++       * All we need to do here is free the vma_private_data.
++       */
++      kfree(vma->vm_private_data);
++
++      /* THIS IS VERY UNPLEASANT: do_mmap_pgoff() will set the vma->vm_file
++       * to NULL on failure. However, we need this in gntdev_clear_pte() to
++       * unmap the grants. Therefore, we smuggle a reference to the file's
++       * private data in the VM area's private data pointer.
++       */
++      vma->vm_private_data = private_data;
++      
++      up_write(&private_data->grants_sem);
++
++      return -ENOMEM;
++}
++
++static pte_t gntdev_clear_pte(struct vm_area_struct *vma, unsigned long addr,
++                            pte_t *ptep, int is_fullmm)
++{
++      int slot_index, ret;
++      pte_t copy;
++      struct gnttab_unmap_grant_ref op;
++      gntdev_file_private_data_t *private_data;
++
++      /* THIS IS VERY UNPLEASANT: do_mmap_pgoff() will set the vma->vm_file
++       * to NULL on failure. However, we need this in gntdev_clear_pte() to
++       * unmap the grants. Therefore, we smuggle a reference to the file's
++       * private data in the VM area's private data pointer.
++       */
++      if (vma->vm_file) {
++              private_data = (gntdev_file_private_data_t *)
++                      vma->vm_file->private_data;
++      } else if (vma->vm_private_data) {
++              private_data = (gntdev_file_private_data_t *)
++                      vma->vm_private_data;
++      } else {
++              private_data = NULL; /* gcc warning */
++              BUG();
++      }
++
++      /* Copy the existing value of the PTE for returning. */
++      copy = *ptep;
++
++      /* Calculate the grant relating to this PTE. */
++      slot_index = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT);
++
++      /* Only unmap grants if the slot has been mapped. This could be being
++       * called from a failing mmap().
++       */
++      if (private_data->grants[slot_index].state == GNTDEV_SLOT_MAPPED) {
++
++              /* First, we clear the user space mapping, if it has been made.
++               */
++              if (private_data->grants[slot_index].u.valid.user_handle !=
++                  GNTDEV_INVALID_HANDLE && 
++                  !xen_feature(XENFEAT_auto_translated_physmap)) {
++                      /* NOT USING SHADOW PAGE TABLES. */
++                      gnttab_set_unmap_op(&op, virt_to_machine(ptep), 
++                                          GNTMAP_contains_pte,
++                                          private_data->grants[slot_index]
++                                          .u.valid.user_handle);
++                      ret = HYPERVISOR_grant_table_op(
++                              GNTTABOP_unmap_grant_ref, &op, 1);
++                      BUG_ON(ret);
++                      if (op.status)
++                              printk("User unmap grant status = %d\n", 
++                                     op.status);
++              } else {
++                      /* USING SHADOW PAGE TABLES. */
++                      pte_clear_full(vma->vm_mm, addr, ptep, is_fullmm);
++              }
++
++              /* Finally, we unmap the grant from kernel space. */
++              gnttab_set_unmap_op(&op, 
++                                  get_kernel_vaddr(private_data, slot_index),
++                                  GNTMAP_host_map, 
++                                  private_data->grants[slot_index].u.valid
++                                  .kernel_handle);
++              ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, 
++                                              &op, 1);
++              BUG_ON(ret);
++              if (op.status)
++                      printk("Kernel unmap grant status = %d\n", op.status);
++
++
++              /* Return slot to the not-yet-mapped state, so that it may be
++               * mapped again, or removed by a subsequent ioctl.
++               */
++              private_data->grants[slot_index].state = 
++                      GNTDEV_SLOT_NOT_YET_MAPPED;
++
++              /* Invalidate the physical to machine mapping for this page. */
++              set_phys_to_machine(__pa(get_kernel_vaddr(private_data, 
++                                                        slot_index)) 
++                                  >> PAGE_SHIFT, INVALID_P2M_ENTRY);
++
++      } else {
++              pte_clear_full(vma->vm_mm, addr, ptep, is_fullmm);
++      }
++
++      return copy;
++}
++
++/* "Destructor" for a VM area.
++ */
++static void gntdev_vma_close(struct vm_area_struct *vma) {
++      if (vma->vm_private_data) {
++              kfree(vma->vm_private_data);
++      }
++}
++
++/* Called when an ioctl is made on the device.
++ */
++static long gntdev_ioctl(struct file *flip,
++                       unsigned int cmd, unsigned long arg)
++{
++      int rc = 0;
++      gntdev_file_private_data_t *private_data = 
++              (gntdev_file_private_data_t *) flip->private_data;
++
++      /* On the first invocation, we will lazily initialise the grant array
++       * and free-list.
++       */
++      if (unlikely(!private_data->grants) 
++          && likely(cmd != IOCTL_GNTDEV_SET_MAX_GRANTS)) {
++              down_write(&private_data->grants_sem);
++              
++              if (unlikely(private_data->grants)) {
++                      up_write(&private_data->grants_sem);
++                      goto private_data_initialised;
++              }
++              
++              /* Just use the default. Setting to a non-default is handled
++               * in the ioctl switch.
++               */
++              rc = init_private_data(private_data, DEFAULT_MAX_GRANTS);
++              
++              up_write(&private_data->grants_sem);
++
++              if (rc) {
++                      printk (KERN_ERR "Initialising gntdev private data "
++                              "failed.\n");
++                      return rc;
++              }
++      }
++          
++private_data_initialised:
++      switch (cmd) {
++      case IOCTL_GNTDEV_MAP_GRANT_REF:
++      {
++              struct ioctl_gntdev_map_grant_ref op;
++              down_write(&private_data->grants_sem);
++              down_write(&private_data->free_list_sem);
++
++              if ((rc = copy_from_user(&op, (void __user *) arg, 
++                                       sizeof(op)))) {
++                      rc = -EFAULT;
++                      goto map_out;
++              }
++              if (unlikely(op.count <= 0)) {
++                      rc = -EINVAL;
++                      goto map_out;
++              }
++
++              if (op.count == 1) {
++                      if ((rc = add_grant_reference(flip, &op.refs[0],
++                                                    &op.index)) < 0) {
++                              printk(KERN_ERR "Adding grant reference "
++                                     "failed (%d).\n", rc);
++                              goto map_out;
++                      }
++              } else {
++                      struct ioctl_gntdev_grant_ref *refs, *u;
++                      refs = kmalloc(op.count * sizeof(*refs), GFP_KERNEL);
++                      if (!refs) {
++                              rc = -ENOMEM;
++                              goto map_out;
++                      }
++                      u = ((struct ioctl_gntdev_map_grant_ref *)arg)->refs;
++                      if ((rc = copy_from_user(refs,
++                                               (void __user *)u,
++                                               sizeof(*refs) * op.count))) {
++                              printk(KERN_ERR "Copying refs from user failed"
++                                     " (%d).\n", rc);
++                              rc = -EINVAL;
++                              goto map_out;
++                      }
++                      if ((rc = find_contiguous_free_range(flip, op.count))
++                          < 0) {
++                              printk(KERN_ERR "Finding contiguous range "
++                                     "failed (%d).\n", rc);
++                              kfree(refs);
++                              goto map_out;
++                      }
++                      op.index = rc << PAGE_SHIFT;
++                      if ((rc = add_grant_references(flip, op.count,
++                                                     refs, rc))) {
++                              printk(KERN_ERR "Adding grant references "
++                                     "failed (%d).\n", rc);
++                              kfree(refs);
++                              goto map_out;
++                      }
++                      compress_free_list(flip);
++                      kfree(refs);
++              }
++              if ((rc = copy_to_user((void __user *) arg, 
++                                     &op, 
++                                     sizeof(op)))) {
++                      printk(KERN_ERR "Copying result back to user failed "
++                             "(%d)\n", rc);
++                      rc = -EFAULT;
++                      goto map_out;
++              }
++      map_out:
++              up_write(&private_data->grants_sem);
++              up_write(&private_data->free_list_sem);
++              return rc;
++      }
++      case IOCTL_GNTDEV_UNMAP_GRANT_REF:
++      {
++              struct ioctl_gntdev_unmap_grant_ref op;
++              int i, start_index;
++
++              down_write(&private_data->grants_sem);
++              down_write(&private_data->free_list_sem);
++
++              if ((rc = copy_from_user(&op, 
++                                       (void __user *) arg, 
++                                       sizeof(op)))) {
++                      rc = -EFAULT;
++                      goto unmap_out;
++              }
++
++              start_index = op.index >> PAGE_SHIFT;
++
++              /* First, check that all pages are in the NOT_YET_MAPPED
++               * state.
++               */
++              for (i = 0; i < op.count; ++i) {
++                      if (unlikely
++                          (private_data->grants[start_index + i].state
++                           != GNTDEV_SLOT_NOT_YET_MAPPED)) {
++                              if (private_data->grants[start_index + i].state
++                                  == GNTDEV_SLOT_INVALID) {
++                                      printk(KERN_ERR
++                                             "Tried to remove an invalid "
++                                             "grant at offset 0x%x.",
++                                             (start_index + i) 
++                                             << PAGE_SHIFT);
++                                      rc = -EINVAL;
++                              } else {
++                                      printk(KERN_ERR
++                                             "Tried to remove a grant which "
++                                             "is currently mmap()-ed at "
++                                             "offset 0x%x.",
++                                             (start_index + i) 
++                                             << PAGE_SHIFT);
++                                      rc = -EBUSY;
++                              }
++                              goto unmap_out;
++                      }
++              }
++
++              /* Unmap pages and add them to the free list.
++               */
++              for (i = 0; i < op.count; ++i) {
++                      private_data->grants[start_index+i].state = 
++                              GNTDEV_SLOT_INVALID;
++                      private_data->grants[start_index+i].u.free_list_index =
++                              private_data->free_list_size;
++                      private_data->free_list[private_data->free_list_size] =
++                              start_index + i;
++                      ++private_data->free_list_size;
++              }
++
++      unmap_out:
++              up_write(&private_data->grants_sem);
++              up_write(&private_data->free_list_sem);
++              return rc;
++      }
++      case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR:
++      {
++              struct ioctl_gntdev_get_offset_for_vaddr op;
++              struct vm_area_struct *vma;
++              unsigned long vaddr;
++
++              if ((rc = copy_from_user(&op, 
++                                       (void __user *) arg, 
++                                       sizeof(op)))) {
++                      rc = -EFAULT;
++                      goto get_offset_out;
++              }
++              vaddr = (unsigned long)op.vaddr;
++
++              down_read(&current->mm->mmap_sem);              
++              vma = find_vma(current->mm, vaddr);
++              if (vma == NULL) {
++                      rc = -EFAULT;
++                      goto get_offset_unlock_out;
++              }
++              if ((!vma->vm_ops) || (vma->vm_ops != &gntdev_vmops)) {
++                      printk(KERN_ERR "The vaddr specified does not belong "
++                             "to a gntdev instance: %#lx\n", vaddr);
++                      rc = -EFAULT;
++                      goto get_offset_unlock_out;
++              }
++              if (vma->vm_start != vaddr) {
++                      printk(KERN_ERR "The vaddr specified in an "
++                             "IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR must be at "
++                             "the start of the VM area. vma->vm_start = "
++                             "%#lx; vaddr = %#lx\n",
++                             vma->vm_start, vaddr);
++                      rc = -EFAULT;
++                      goto get_offset_unlock_out;
++              }
++              op.offset = vma->vm_pgoff << PAGE_SHIFT;
++              op.count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
++              up_read(&current->mm->mmap_sem);
++              if ((rc = copy_to_user((void __user *) arg, 
++                                     &op, 
++                                     sizeof(op)))) {
++                      rc = -EFAULT;
++                      goto get_offset_out;
++              }
++              goto get_offset_out;
++      get_offset_unlock_out:
++              up_read(&current->mm->mmap_sem);
++      get_offset_out:
++              return rc;
++      }
++      case IOCTL_GNTDEV_SET_MAX_GRANTS:
++      {
++              struct ioctl_gntdev_set_max_grants op;
++              if ((rc = copy_from_user(&op, 
++                                       (void __user *) arg, 
++                                       sizeof(op)))) {
++                      rc = -EFAULT;
++                      goto set_max_out;
++              }
++              down_write(&private_data->grants_sem);
++              if (private_data->grants) {
++                      rc = -EBUSY;
++                      goto set_max_unlock_out;
++              }
++              if (op.count > MAX_GRANTS_LIMIT) {
++                      rc = -EINVAL;
++                      goto set_max_unlock_out;
++              }                                                
++              rc = init_private_data(private_data, op.count);
++      set_max_unlock_out:
++              up_write(&private_data->grants_sem);
++      set_max_out:
++              return rc;
++      }
++      default:
++              return -ENOIOCTLCMD;
++      }
++
++      return 0;
++}
+--- linux-2.6.18.8/drivers/xen/netback/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/netback/Makefile   2008-05-19 00:33:45.838788321 +0300
+@@ -0,0 +1,5 @@
++obj-$(CONFIG_XEN_NETDEV_BACKEND) := netbk.o
++obj-$(CONFIG_XEN_NETDEV_LOOPBACK) += netloop.o
++
++netbk-y   := netback.o xenbus.o interface.o accel.o
++netloop-y := loopback.o
+--- linux-2.6.18.8/drivers/xen/netback/accel.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/netback/accel.c    2008-05-19 00:33:45.838788321 +0300
+@@ -0,0 +1,269 @@
++/******************************************************************************
++ * drivers/xen/netback/accel.c
++ *
++ * Interface between backend virtual network device and accelerated plugin. 
++ * 
++ * Copyright (C) 2007 Solarflare Communications, Inc
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/list.h>
++#include <asm/atomic.h>
++#include <xen/xenbus.h>
++#include <linux/mutex.h>
++
++#include "common.h"
++
++#if 0
++#undef DPRINTK
++#define DPRINTK(fmt, args...)                                         \
++      printk("netback/accel (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
++#endif
++
++/* 
++ * A list of available netback accelerator plugin modules (each list
++ * entry is of type struct netback_accelerator) 
++ */ 
++static struct list_head accelerators_list;
++/* Lock used to protect access to accelerators_list */
++DEFINE_MUTEX(accelerators_mutex);
++
++/* 
++ * Compare a backend to an accelerator, and decide if they are
++ * compatible (i.e. if the accelerator should be used by the
++ * backend) 
++ */
++static int match_accelerator(struct xenbus_device *xendev,
++                           struct backend_info *be, 
++                           struct netback_accelerator *accelerator)
++{
++      int rc = 0;
++      char *eth_name = xenbus_read(XBT_NIL, xendev->nodename, "accel", NULL);
++      
++      if (IS_ERR(eth_name)) {
++              /* Probably means not present */
++              DPRINTK("%s: no match due to xenbus_read accel error %d\n", 
++                      __FUNCTION__, PTR_ERR(eth_name));
++              return 0;
++      } else {
++              if (!strcmp(eth_name, accelerator->eth_name))
++                      rc = 1;
++              kfree(eth_name);
++              return rc;
++      }
++}
++
++
++static void do_probe(struct backend_info *be, 
++                   struct netback_accelerator *accelerator,
++                   struct xenbus_device *xendev) 
++{
++      be->accelerator = accelerator;
++      atomic_inc(&be->accelerator->use_count);
++      if (be->accelerator->hooks->probe(xendev) != 0) {
++              atomic_dec(&be->accelerator->use_count);
++              module_put(be->accelerator->hooks->owner);
++              be->accelerator = NULL;
++      }
++}
++
++
++/*
++ * Notify suitable backends that a new accelerator is available and
++ * connected.  This will also notify the accelerator plugin module
++ * that it is being used for a device through the probe hook.
++ */
++static int netback_accelerator_probe_backend(struct device *dev, void *arg)
++{
++      struct netback_accelerator *accelerator = 
++              (struct netback_accelerator *)arg;
++      struct xenbus_device *xendev = to_xenbus_device(dev);
++
++      if (!strcmp("vif", xendev->devicetype)) {
++              struct backend_info *be = xendev->dev.driver_data;
++
++              if (match_accelerator(xendev, be, accelerator) &&
++                  try_module_get(accelerator->hooks->owner)) {
++                      do_probe(be, accelerator, xendev);
++              }
++      }
++      return 0;
++}
++
++
++/*
++ * Notify suitable backends that an accelerator is unavailable.
++ */
++static int netback_accelerator_remove_backend(struct device *dev, void *arg)
++{
++      struct xenbus_device *xendev = to_xenbus_device(dev);
++      struct netback_accelerator *accelerator = 
++              (struct netback_accelerator *)arg;
++      
++      if (!strcmp("vif", xendev->devicetype)) {
++              struct backend_info *be = xendev->dev.driver_data;
++
++              if (be->accelerator == accelerator) {
++                      be->accelerator->hooks->remove(xendev);
++                      atomic_dec(&be->accelerator->use_count);
++                      module_put(be->accelerator->hooks->owner);
++                      be->accelerator = NULL;
++              }
++      }
++      return 0;
++}
++
++
++
++/*
++ * Entry point for an netback accelerator plugin module.  Called to
++ * advertise its presence, and connect to any suitable backends.
++ */
++int netback_connect_accelerator(unsigned version, int id, const char *eth_name, 
++                              struct netback_accel_hooks *hooks)
++{
++      struct netback_accelerator *new_accelerator;
++      unsigned eth_name_len;
++
++      if (version != NETBACK_ACCEL_VERSION) {
++              if (version > NETBACK_ACCEL_VERSION) {
++                      /* Caller has higher version number, leave it
++                         up to them to decide whether to continue.
++                         They can recall with a lower number if
++                         they're happy to be compatible with us */
++                      return NETBACK_ACCEL_VERSION;
++              } else {
++                      /* We have a more recent version than caller.
++                         Currently reject, but may in future be able
++                         to be backwardly compatible */
++                      return -EPROTO;
++              }
++      }
++
++      new_accelerator = 
++              kmalloc(sizeof(struct netback_accelerator), GFP_KERNEL);
++      if (!new_accelerator) {
++              DPRINTK("%s: failed to allocate memory for accelerator\n",
++                      __FUNCTION__);
++              return -ENOMEM;
++      }
++
++      new_accelerator->id = id;
++      
++      eth_name_len = strlen(eth_name)+1;
++      new_accelerator->eth_name = kmalloc(eth_name_len, GFP_KERNEL);
++      if (!new_accelerator->eth_name) {
++              DPRINTK("%s: failed to allocate memory for eth_name string\n",
++                      __FUNCTION__);
++              kfree(new_accelerator);
++              return -ENOMEM;
++      }
++      strlcpy(new_accelerator->eth_name, eth_name, eth_name_len);
++      
++      new_accelerator->hooks = hooks;
++
++      atomic_set(&new_accelerator->use_count, 0);
++      
++      mutex_lock(&accelerators_mutex);
++      list_add(&new_accelerator->link, &accelerators_list);
++      
++      /* tell existing backends about new plugin */
++      xenbus_for_each_backend(new_accelerator, 
++                              netback_accelerator_probe_backend);
++
++      mutex_unlock(&accelerators_mutex);
++
++      return 0;
++
++}
++EXPORT_SYMBOL_GPL(netback_connect_accelerator);
++
++
++/* 
++ * Disconnect an accelerator plugin module that has previously been
++ * connected.
++ */
++void netback_disconnect_accelerator(int id, const char *eth_name)
++{
++      struct netback_accelerator *accelerator, *next;
++
++      mutex_lock(&accelerators_mutex);
++      list_for_each_entry_safe(accelerator, next, &accelerators_list, link) {
++              if (!strcmp(eth_name, accelerator->eth_name)) {
++                      xenbus_for_each_backend
++                              (accelerator, netback_accelerator_remove_backend);
++                      BUG_ON(atomic_read(&accelerator->use_count) != 0);
++                      list_del(&accelerator->link);                           
++                      kfree(accelerator->eth_name);
++                      kfree(accelerator);
++                      break;
++              }
++      }
++      mutex_unlock(&accelerators_mutex);
++}
++EXPORT_SYMBOL_GPL(netback_disconnect_accelerator);
++
++
++void netback_probe_accelerators(struct backend_info *be,
++                              struct xenbus_device *dev)
++{
++      struct netback_accelerator *accelerator;
++
++      /* 
++       * Check list of accelerators to see if any is suitable, and
++       * use it if it is.
++       */
++      mutex_lock(&accelerators_mutex);
++      list_for_each_entry(accelerator, &accelerators_list, link) { 
++              if (match_accelerator(dev, be, accelerator) &&
++                  try_module_get(accelerator->hooks->owner)) {
++                      do_probe(be, accelerator, dev);
++                      break;
++              }
++      }
++      mutex_unlock(&accelerators_mutex);
++}
++
++
++void netback_remove_accelerators(struct backend_info *be,
++                               struct xenbus_device *dev)
++{
++      mutex_lock(&accelerators_mutex);
++      /* Notify the accelerator (if any) of this device's removal */
++      if (be->accelerator != NULL) {
++              be->accelerator->hooks->remove(dev);
++              atomic_dec(&be->accelerator->use_count);
++              module_put(be->accelerator->hooks->owner);
++              be->accelerator = NULL;
++      }
++      mutex_unlock(&accelerators_mutex);
++}
++
++
++void netif_accel_init(void)
++{
++      INIT_LIST_HEAD(&accelerators_list);
++}
+--- linux-2.6.18.8/drivers/xen/netback/common.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/netback/common.h   2008-05-19 00:33:45.838788321 +0300
+@@ -0,0 +1,217 @@
++/******************************************************************************
++ * arch/xen/drivers/netif/backend/common.h
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef __NETIF__BACKEND__COMMON_H__
++#define __NETIF__BACKEND__COMMON_H__
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/slab.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/wait.h>
++#include <xen/evtchn.h>
++#include <xen/interface/io/netif.h>
++#include <asm/io.h>
++#include <asm/pgalloc.h>
++#include <xen/interface/grant_table.h>
++#include <xen/gnttab.h>
++#include <xen/driver_util.h>
++#include <xen/xenbus.h>
++
++#define DPRINTK(_f, _a...)                    \
++      pr_debug("(file=%s, line=%d) " _f,      \
++               __FILE__ , __LINE__ , ## _a )
++#define IPRINTK(fmt, args...)                         \
++      printk(KERN_INFO "xen_net: " fmt, ##args)
++#define WPRINTK(fmt, args...)                         \
++      printk(KERN_WARNING "xen_net: " fmt, ##args)
++
++typedef struct netif_st {
++      /* Unique identifier for this interface. */
++      domid_t          domid;
++      unsigned int     handle;
++
++      u8               fe_dev_addr[6];
++
++      /* Physical parameters of the comms window. */
++      grant_handle_t   tx_shmem_handle;
++      grant_ref_t      tx_shmem_ref;
++      grant_handle_t   rx_shmem_handle;
++      grant_ref_t      rx_shmem_ref;
++      unsigned int     irq;
++
++      /* The shared rings and indexes. */
++      netif_tx_back_ring_t tx;
++      netif_rx_back_ring_t rx;
++      struct vm_struct *tx_comms_area;
++      struct vm_struct *rx_comms_area;
++
++      /* Set of features that can be turned on in dev->features. */
++      int features;
++
++      /* Internal feature information. */
++      u8 can_queue:1; /* can queue packets for receiver? */
++      u8 copying_receiver:1;  /* copy packets to receiver?       */
++
++      /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */
++      RING_IDX rx_req_cons_peek;
++
++      /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
++      unsigned long   credit_bytes;
++      unsigned long   credit_usec;
++      unsigned long   remaining_credit;
++      struct timer_list credit_timeout;
++
++      /* Enforce draining of the transmit queue. */
++      struct timer_list tx_queue_timeout;
++
++      /* Miscellaneous private stuff. */
++      struct list_head list;  /* scheduling list */
++      atomic_t         refcnt;
++      struct net_device *dev;
++      struct net_device_stats stats;
++
++      unsigned int carrier;
++
++      wait_queue_head_t waiting_to_free;
++} netif_t;
++
++/*
++ * Implement our own carrier flag: the network stack's version causes delays
++ * when the carrier is re-enabled (in particular, dev_activate() may not
++ * immediately be called, which can cause packet loss; also the etherbridge
++ * can be rather lazy in activating its port).
++ */
++#define netback_carrier_on(netif)     ((netif)->carrier = 1)
++#define netback_carrier_off(netif)    ((netif)->carrier = 0)
++#define netback_carrier_ok(netif)     ((netif)->carrier)
++
++enum {
++      NETBK_DONT_COPY_SKB,
++      NETBK_DELAYED_COPY_SKB,
++      NETBK_ALWAYS_COPY_SKB,
++};
++
++extern int netbk_copy_skb_mode;
++
++/* Function pointers into netback accelerator plugin modules */
++struct netback_accel_hooks {
++      struct module *owner;
++      int  (*probe)(struct xenbus_device *dev);
++      int (*remove)(struct xenbus_device *dev);
++};
++
++/* Structure to track the state of a netback accelerator plugin */
++struct netback_accelerator {
++      struct list_head link;
++      int id;
++      char *eth_name;
++      atomic_t use_count;
++      struct netback_accel_hooks *hooks;
++};
++
++struct backend_info {
++      struct xenbus_device *dev;
++      netif_t *netif;
++      enum xenbus_state frontend_state;
++
++      /* State relating to the netback accelerator */
++      void *netback_accel_priv;
++      /* The accelerator that this backend is currently using */
++      struct netback_accelerator *accelerator;
++};
++
++#define NETBACK_ACCEL_VERSION 0x00010001
++
++/* 
++ * Connect an accelerator plugin module to netback.  Returns zero on
++ * success, < 0 on error, > 0 (with highest version number supported)
++ * if version mismatch.
++ */
++extern int netback_connect_accelerator(unsigned version,
++                                     int id, const char *eth_name, 
++                                     struct netback_accel_hooks *hooks);
++/* Disconnect a previously connected accelerator plugin module */
++extern void netback_disconnect_accelerator(int id, const char *eth_name);
++
++
++extern
++void netback_probe_accelerators(struct backend_info *be,
++                              struct xenbus_device *dev);
++extern
++void netback_remove_accelerators(struct backend_info *be,
++                               struct xenbus_device *dev);
++extern
++void netif_accel_init(void);
++
++
++#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE)
++#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE)
++
++void netif_disconnect(netif_t *netif);
++
++netif_t *netif_alloc(domid_t domid, unsigned int handle);
++int netif_map(netif_t *netif, unsigned long tx_ring_ref,
++            unsigned long rx_ring_ref, unsigned int evtchn);
++
++#define netif_get(_b) (atomic_inc(&(_b)->refcnt))
++#define netif_put(_b)                                         \
++      do {                                                    \
++              if ( atomic_dec_and_test(&(_b)->refcnt) )       \
++                      wake_up(&(_b)->waiting_to_free);        \
++      } while (0)
++
++void netif_xenbus_init(void);
++
++#define netif_schedulable(netif)                              \
++      (netif_running((netif)->dev) && netback_carrier_ok(netif))
++
++void netif_schedule_work(netif_t *netif);
++void netif_deschedule_work(netif_t *netif);
++
++int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
++struct net_device_stats *netif_be_get_stats(struct net_device *dev);
++irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs);
++
++static inline int netbk_can_queue(struct net_device *dev)
++{
++      netif_t *netif = netdev_priv(dev);
++      return netif->can_queue;
++}
++
++static inline int netbk_can_sg(struct net_device *dev)
++{
++      netif_t *netif = netdev_priv(dev);
++      return netif->features & NETIF_F_SG;
++}
++
++#endif /* __NETIF__BACKEND__COMMON_H__ */
+--- linux-2.6.18.8/drivers/xen/netback/interface.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/netback/interface.c        2008-05-19 00:33:45.842788551 +0300
+@@ -0,0 +1,336 @@
++/******************************************************************************
++ * arch/xen/drivers/netif/backend/interface.c
++ * 
++ * Network-device interface management.
++ * 
++ * Copyright (c) 2004-2005, Keir Fraser
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include "common.h"
++#include <linux/ethtool.h>
++#include <linux/rtnetlink.h>
++
++/*
++ * Module parameter 'queue_length':
++ * 
++ * Enables queuing in the network stack when a client has run out of receive
++ * descriptors. Although this feature can improve receive bandwidth by avoiding
++ * packet loss, it can also result in packets sitting in the 'tx_queue' for
++ * unbounded time. This is bad if those packets hold onto foreign resources.
++ * For example, consider a packet that holds onto resources belonging to the
++ * guest for which it is queued (e.g., packet received on vif1.0, destined for
++ * vif1.1 which is not activated in the guest): in this situation the guest
++ * will never be destroyed, unless vif1.1 is taken down. To avoid this, we
++ * run a timer (tx_queue_timeout) to drain the queue when the interface is
++ * blocked.
++ */
++static unsigned long netbk_queue_length = 32;
++module_param_named(queue_length, netbk_queue_length, ulong, 0);
++
++static void __netif_up(netif_t *netif)
++{
++      enable_irq(netif->irq);
++      netif_schedule_work(netif);
++}
++
++static void __netif_down(netif_t *netif)
++{
++      disable_irq(netif->irq);
++      netif_deschedule_work(netif);
++}
++
++static int net_open(struct net_device *dev)
++{
++      netif_t *netif = netdev_priv(dev);
++      if (netback_carrier_ok(netif)) {
++              __netif_up(netif);
++              netif_start_queue(dev);
++      }
++      return 0;
++}
++
++static int net_close(struct net_device *dev)
++{
++      netif_t *netif = netdev_priv(dev);
++      if (netback_carrier_ok(netif))
++              __netif_down(netif);
++      netif_stop_queue(dev);
++      return 0;
++}
++
++static int netbk_change_mtu(struct net_device *dev, int mtu)
++{
++      int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
++
++      if (mtu > max)
++              return -EINVAL;
++      dev->mtu = mtu;
++      return 0;
++}
++
++static int netbk_set_sg(struct net_device *dev, u32 data)
++{
++      if (data) {
++              netif_t *netif = netdev_priv(dev);
++
++              if (!(netif->features & NETIF_F_SG))
++                      return -ENOSYS;
++      }
++
++      return ethtool_op_set_sg(dev, data);
++}
++
++static int netbk_set_tso(struct net_device *dev, u32 data)
++{
++      if (data) {
++              netif_t *netif = netdev_priv(dev);
++
++              if (!(netif->features & NETIF_F_TSO))
++                      return -ENOSYS;
++      }
++
++      return ethtool_op_set_tso(dev, data);
++}
++
++static struct ethtool_ops network_ethtool_ops =
++{
++      .get_tx_csum = ethtool_op_get_tx_csum,
++      .set_tx_csum = ethtool_op_set_tx_csum,
++      .get_sg = ethtool_op_get_sg,
++      .set_sg = netbk_set_sg,
++      .get_tso = ethtool_op_get_tso,
++      .set_tso = netbk_set_tso,
++      .get_link = ethtool_op_get_link,
++};
++
++netif_t *netif_alloc(domid_t domid, unsigned int handle)
++{
++      int err = 0;
++      struct net_device *dev;
++      netif_t *netif;
++      char name[IFNAMSIZ] = {};
++
++      snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
++      dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
++      if (dev == NULL) {
++              DPRINTK("Could not create netif: out of memory\n");
++              return ERR_PTR(-ENOMEM);
++      }
++
++      netif = netdev_priv(dev);
++      memset(netif, 0, sizeof(*netif));
++      netif->domid  = domid;
++      netif->handle = handle;
++      atomic_set(&netif->refcnt, 1);
++      init_waitqueue_head(&netif->waiting_to_free);
++      netif->dev = dev;
++
++      netback_carrier_off(netif);
++
++      netif->credit_bytes = netif->remaining_credit = ~0UL;
++      netif->credit_usec  = 0UL;
++      init_timer(&netif->credit_timeout);
++      /* Initialize 'expires' now: it's used to track the credit window. */
++      netif->credit_timeout.expires = jiffies;
++
++      init_timer(&netif->tx_queue_timeout);
++
++      dev->hard_start_xmit = netif_be_start_xmit;
++      dev->get_stats       = netif_be_get_stats;
++      dev->open            = net_open;
++      dev->stop            = net_close;
++      dev->change_mtu      = netbk_change_mtu;
++      dev->features        = NETIF_F_IP_CSUM;
++
++      SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
++
++      dev->tx_queue_len = netbk_queue_length;
++
++      /*
++       * Initialise a dummy MAC address. We choose the numerically
++       * largest non-broadcast address to prevent the address getting
++       * stolen by an Ethernet bridge for STP purposes.
++       * (FE:FF:FF:FF:FF:FF)
++       */ 
++      memset(dev->dev_addr, 0xFF, ETH_ALEN);
++      dev->dev_addr[0] &= ~0x01;
++
++      rtnl_lock();
++      err = register_netdevice(dev);
++      rtnl_unlock();
++      if (err) {
++              DPRINTK("Could not register new net device %s: err=%d\n",
++                      dev->name, err);
++              free_netdev(dev);
++              return ERR_PTR(err);
++      }
++
++      DPRINTK("Successfully created netif\n");
++      return netif;
++}
++
++static int map_frontend_pages(
++      netif_t *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
++{
++      struct gnttab_map_grant_ref op;
++
++      gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
++                        GNTMAP_host_map, tx_ring_ref, netif->domid);
++    
++      if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
++              BUG();
++
++      if (op.status) { 
++              DPRINTK(" Gnttab failure mapping tx_ring_ref!\n");
++              return op.status;
++      }
++
++      netif->tx_shmem_ref    = tx_ring_ref;
++      netif->tx_shmem_handle = op.handle;
++
++      gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
++                        GNTMAP_host_map, rx_ring_ref, netif->domid);
++
++      if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
++              BUG();
++
++      if (op.status) {
++              DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
++              return op.status;
++      }
++
++      netif->rx_shmem_ref    = rx_ring_ref;
++      netif->rx_shmem_handle = op.handle;
++
++      return 0;
++}
++
++static void unmap_frontend_pages(netif_t *netif)
++{
++      struct gnttab_unmap_grant_ref op;
++
++      gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
++                          GNTMAP_host_map, netif->tx_shmem_handle);
++
++      if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
++              BUG();
++
++      gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
++                          GNTMAP_host_map, netif->rx_shmem_handle);
++
++      if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
++              BUG();
++}
++
++int netif_map(netif_t *netif, unsigned long tx_ring_ref,
++            unsigned long rx_ring_ref, unsigned int evtchn)
++{
++      int err = -ENOMEM;
++      netif_tx_sring_t *txs;
++      netif_rx_sring_t *rxs;
++
++      /* Already connected through? */
++      if (netif->irq)
++              return 0;
++
++      netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
++      if (netif->tx_comms_area == NULL)
++              return -ENOMEM;
++      netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
++      if (netif->rx_comms_area == NULL)
++              goto err_rx;
++
++      err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
++      if (err)
++              goto err_map;
++
++      err = bind_interdomain_evtchn_to_irqhandler(
++              netif->domid, evtchn, netif_be_int, 0,
++              netif->dev->name, netif);
++      if (err < 0)
++              goto err_hypervisor;
++      netif->irq = err;
++      disable_irq(netif->irq);
++
++      txs = (netif_tx_sring_t *)netif->tx_comms_area->addr;
++      BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
++
++      rxs = (netif_rx_sring_t *)
++              ((char *)netif->rx_comms_area->addr);
++      BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
++
++      netif->rx_req_cons_peek = 0;
++
++      netif_get(netif);
++
++      rtnl_lock();
++      netback_carrier_on(netif);
++      if (netif_running(netif->dev))
++              __netif_up(netif);
++      rtnl_unlock();
++
++      return 0;
++err_hypervisor:
++      unmap_frontend_pages(netif);
++err_map:
++      free_vm_area(netif->rx_comms_area);
++err_rx:
++      free_vm_area(netif->tx_comms_area);
++      return err;
++}
++
++void netif_disconnect(netif_t *netif)
++{
++      if (netback_carrier_ok(netif)) {
++              rtnl_lock();
++              netback_carrier_off(netif);
++              netif_carrier_off(netif->dev); /* discard queued packets */
++              if (netif_running(netif->dev))
++                      __netif_down(netif);
++              rtnl_unlock();
++              netif_put(netif);
++      }
++
++      atomic_dec(&netif->refcnt);
++      wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
++
++      del_timer_sync(&netif->credit_timeout);
++      del_timer_sync(&netif->tx_queue_timeout);
++
++      if (netif->irq)
++              unbind_from_irqhandler(netif->irq, netif);
++      
++      unregister_netdev(netif->dev);
++
++      if (netif->tx.sring) {
++              unmap_frontend_pages(netif);
++              free_vm_area(netif->tx_comms_area);
++              free_vm_area(netif->rx_comms_area);
++      }
++
++      free_netdev(netif->dev);
++}
+--- linux-2.6.18.8/drivers/xen/netback/loopback.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/netback/loopback.c 2008-05-19 00:33:45.842788551 +0300
+@@ -0,0 +1,324 @@
++/******************************************************************************
++ * netback/loopback.c
++ * 
++ * A two-interface loopback device to emulate a local netfront-netback
++ * connection. This ensures that local packet delivery looks identical
++ * to inter-domain delivery. Most importantly, packets delivered locally
++ * originating from other domains will get *copied* when they traverse this
++ * driver. This prevents unbounded delays in socket-buffer queues from
++ * causing the netback driver to "seize up".
++ * 
++ * This driver creates a symmetric pair of loopback interfaces with names
++ * vif0.0 and veth0. The intention is that 'vif0.0' is bound to an Ethernet
++ * bridge, just like a proper netback interface, while a local IP interface
++ * is configured on 'veth0'.
++ * 
++ * As with a real netback interface, vif0.0 is configured with a suitable
++ * dummy MAC address. No default is provided for veth0: a reasonable strategy
++ * is to transfer eth0's MAC address to veth0, and give eth0 a dummy address
++ * (to avoid confusing the Etherbridge).
++ * 
++ * Copyright (c) 2005 K A Fraser
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/module.h>
++#include <linux/netdevice.h>
++#include <linux/inetdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/ethtool.h>
++#include <net/dst.h>
++#include <net/xfrm.h>         /* secpath_reset() */
++#include <asm/hypervisor.h>   /* is_initial_xendomain() */
++
++static int nloopbacks = -1;
++module_param(nloopbacks, int, 0);
++MODULE_PARM_DESC(nloopbacks, "Number of netback-loopback devices to create");
++
++struct net_private {
++      struct net_device *loopback_dev;
++      struct net_device_stats stats;
++};
++
++static int loopback_open(struct net_device *dev)
++{
++      struct net_private *np = netdev_priv(dev);
++      memset(&np->stats, 0, sizeof(np->stats));
++      netif_start_queue(dev);
++      return 0;
++}
++
++static int loopback_close(struct net_device *dev)
++{
++      netif_stop_queue(dev);
++      return 0;
++}
++
++#ifdef CONFIG_X86
++static int is_foreign(unsigned long pfn)
++{
++      /* NB. Play it safe for auto-translation mode. */
++      return (xen_feature(XENFEAT_auto_translated_physmap) ||
++              (phys_to_machine_mapping[pfn] & FOREIGN_FRAME_BIT));
++}
++#else
++/* How to detect a foreign mapping? Play it safe. */
++#define is_foreign(pfn)       (1)
++#endif
++
++static int skb_remove_foreign_references(struct sk_buff *skb)
++{
++      struct page *page;
++      unsigned long pfn;
++      int i, off;
++      char *vaddr;
++
++      BUG_ON(skb_shinfo(skb)->frag_list);
++
++      if (skb_cloned(skb) &&
++          unlikely(pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
++              return 0;
++
++      for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
++              pfn = page_to_pfn(skb_shinfo(skb)->frags[i].page);
++              if (!is_foreign(pfn))
++                      continue;
++              
++              page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
++              if (unlikely(!page))
++                      return 0;
++
++              vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
++              off = skb_shinfo(skb)->frags[i].page_offset;
++              memcpy(page_address(page) + off,
++                     vaddr + off,
++                     skb_shinfo(skb)->frags[i].size);
++              kunmap_skb_frag(vaddr);
++
++              put_page(skb_shinfo(skb)->frags[i].page);
++              skb_shinfo(skb)->frags[i].page = page;
++      }
++
++      return 1;
++}
++
++static int loopback_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      struct net_private *np = netdev_priv(dev);
++
++      if (!skb_remove_foreign_references(skb)) {
++              np->stats.tx_dropped++;
++              dev_kfree_skb(skb);
++              return 0;
++      }
++
++      dst_release(skb->dst);
++      skb->dst = NULL;
++
++      skb_orphan(skb);
++
++      np->stats.tx_bytes += skb->len;
++      np->stats.tx_packets++;
++
++      /* Switch to loopback context. */
++      dev = np->loopback_dev;
++      np  = netdev_priv(dev);
++
++      np->stats.rx_bytes += skb->len;
++      np->stats.rx_packets++;
++
++      if (skb->ip_summed == CHECKSUM_HW) {
++              /* Defer checksum calculation. */
++              skb->proto_csum_blank = 1;
++              /* Must be a local packet: assert its integrity. */
++              skb->proto_data_valid = 1;
++      }
++
++      skb->ip_summed = skb->proto_data_valid ?
++              CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
++
++      skb->pkt_type = PACKET_HOST; /* overridden by eth_type_trans() */
++      skb->protocol = eth_type_trans(skb, dev);
++      skb->dev      = dev;
++      dev->last_rx  = jiffies;
++
++      /* Flush netfilter context: rx'ed skbuffs not expected to have any. */
++      nf_reset(skb);
++      secpath_reset(skb);
++
++      netif_rx(skb);
++
++      return 0;
++}
++
++static struct net_device_stats *loopback_get_stats(struct net_device *dev)
++{
++      struct net_private *np = netdev_priv(dev);
++      return &np->stats;
++}
++
++static struct ethtool_ops network_ethtool_ops =
++{
++      .get_tx_csum = ethtool_op_get_tx_csum,
++      .set_tx_csum = ethtool_op_set_tx_csum,
++      .get_sg = ethtool_op_get_sg,
++      .set_sg = ethtool_op_set_sg,
++      .get_tso = ethtool_op_get_tso,
++      .set_tso = ethtool_op_set_tso,
++      .get_link = ethtool_op_get_link,
++};
++
++/*
++ * Nothing to do here. Virtual interface is point-to-point and the
++ * physical interface is probably promiscuous anyway.
++ */
++static void loopback_set_multicast_list(struct net_device *dev)
++{
++}
++
++static void loopback_construct(struct net_device *dev, struct net_device *lo)
++{
++      struct net_private *np = netdev_priv(dev);
++
++      np->loopback_dev     = lo;
++
++      dev->open            = loopback_open;
++      dev->stop            = loopback_close;
++      dev->hard_start_xmit = loopback_start_xmit;
++      dev->get_stats       = loopback_get_stats;
++      dev->set_multicast_list = loopback_set_multicast_list;
++      dev->change_mtu      = NULL; /* allow arbitrary mtu */
++
++      dev->tx_queue_len    = 0;
++
++      dev->features        = (NETIF_F_HIGHDMA |
++                              NETIF_F_LLTX |
++                              NETIF_F_TSO |
++                              NETIF_F_SG |
++                              NETIF_F_IP_CSUM);
++
++      SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
++
++      /*
++       * We do not set a jumbo MTU on the interface. Otherwise the network
++       * stack will try to send large packets that will get dropped by the
++       * Ethernet bridge (unless the physical Ethernet interface is
++       * configured to transfer jumbo packets). If a larger MTU is desired
++       * then the system administrator can specify it using the 'ifconfig'
++       * command.
++       */
++      /*dev->mtu             = 16*1024;*/
++}
++
++static int __init make_loopback(int i)
++{
++      struct net_device *dev1, *dev2;
++      char dev_name[IFNAMSIZ];
++      int err = -ENOMEM;
++
++      sprintf(dev_name, "vif0.%d", i);
++      dev1 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup);
++      if (!dev1)
++              return err;
++
++      sprintf(dev_name, "veth%d", i);
++      dev2 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup);
++      if (!dev2)
++              goto fail_netdev2;
++
++      loopback_construct(dev1, dev2);
++      loopback_construct(dev2, dev1);
++
++      /*
++       * Initialise a dummy MAC address for the 'dummy backend' interface. We
++       * choose the numerically largest non-broadcast address to prevent the
++       * address getting stolen by an Ethernet bridge for STP purposes.
++       */
++      memset(dev1->dev_addr, 0xFF, ETH_ALEN);
++      dev1->dev_addr[0] &= ~0x01;
++
++      if ((err = register_netdev(dev1)) != 0)
++              goto fail;
++
++      if ((err = register_netdev(dev2)) != 0) {
++              unregister_netdev(dev1);
++              goto fail;
++      }
++
++      return 0;
++
++ fail:
++      free_netdev(dev2);
++ fail_netdev2:
++      free_netdev(dev1);
++      return err;
++}
++
++static void __exit clean_loopback(int i)
++{
++      struct net_device *dev1, *dev2;
++      char dev_name[IFNAMSIZ];
++
++      sprintf(dev_name, "vif0.%d", i);
++      dev1 = dev_get_by_name(dev_name);
++      sprintf(dev_name, "veth%d", i);
++      dev2 = dev_get_by_name(dev_name);
++      if (dev1 && dev2) {
++              unregister_netdev(dev2);
++              unregister_netdev(dev1);
++              free_netdev(dev2);
++              free_netdev(dev1);
++      }
++}
++
++static int __init loopback_init(void)
++{
++      int i, err = 0;
++
++      if (nloopbacks == -1)
++              nloopbacks = is_initial_xendomain() ? 4 : 0;
++
++      for (i = 0; i < nloopbacks; i++)
++              if ((err = make_loopback(i)) != 0)
++                      break;
++
++      return err;
++}
++
++module_init(loopback_init);
++
++static void __exit loopback_exit(void)
++{
++      int i;
++
++      for (i = nloopbacks; i-- > 0; )
++              clean_loopback(i);
++}
++
++module_exit(loopback_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
+--- linux-2.6.18.8/drivers/xen/netback/netback.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/netback/netback.c  2008-05-19 00:33:45.842788551 +0300
+@@ -0,0 +1,1614 @@
++/******************************************************************************
++ * drivers/xen/netback/netback.c
++ * 
++ * Back-end of the driver for virtual network devices. This portion of the
++ * driver exports a 'unified' network-device interface that can be accessed
++ * by any operating system that implements a compatible front end. A 
++ * reference front-end implementation can be found in:
++ *  drivers/xen/netfront/netfront.c
++ * 
++ * Copyright (c) 2002-2005, K A Fraser
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include "common.h"
++#include <xen/balloon.h>
++#include <xen/interface/memory.h>
++
++/*define NETBE_DEBUG_INTERRUPT*/
++
++/* extra field used in struct page */
++#define netif_page_index(pg) (*(long *)&(pg)->mapping)
++
++struct netbk_rx_meta {
++      skb_frag_t frag;
++      int id;
++      u8 copy:1;
++};
++
++struct netbk_tx_pending_inuse {
++      struct list_head list;
++      unsigned long alloc_time;
++};
++
++static void netif_idx_release(u16 pending_idx);
++static void netif_page_release(struct page *page);
++static void make_tx_response(netif_t *netif, 
++                           netif_tx_request_t *txp,
++                           s8       st);
++static netif_rx_response_t *make_rx_response(netif_t *netif, 
++                                           u16      id, 
++                                           s8       st,
++                                           u16      offset,
++                                           u16      size,
++                                           u16      flags);
++
++static void net_tx_action(unsigned long unused);
++static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0);
++
++static void net_rx_action(unsigned long unused);
++static DECLARE_TASKLET(net_rx_tasklet, net_rx_action, 0);
++
++static struct timer_list net_timer;
++static struct timer_list netbk_tx_pending_timer;
++
++#define MAX_PENDING_REQS 256
++
++static struct sk_buff_head rx_queue;
++
++static struct page **mmap_pages;
++static inline unsigned long idx_to_pfn(unsigned int idx)
++{
++      return page_to_pfn(mmap_pages[idx]);
++}
++
++static inline unsigned long idx_to_kaddr(unsigned int idx)
++{
++      return (unsigned long)pfn_to_kaddr(idx_to_pfn(idx));
++}
++
++#define PKT_PROT_LEN 64
++
++static struct pending_tx_info {
++      netif_tx_request_t req;
++      netif_t *netif;
++} pending_tx_info[MAX_PENDING_REQS];
++static u16 pending_ring[MAX_PENDING_REQS];
++typedef unsigned int PEND_RING_IDX;
++#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
++static PEND_RING_IDX pending_prod, pending_cons;
++#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
++
++/* Freed TX SKBs get batched on this ring before return to pending_ring. */
++static u16 dealloc_ring[MAX_PENDING_REQS];
++static PEND_RING_IDX dealloc_prod, dealloc_cons;
++
++/* Doubly-linked list of in-use pending entries. */
++static struct netbk_tx_pending_inuse pending_inuse[MAX_PENDING_REQS];
++static LIST_HEAD(pending_inuse_head);
++
++static struct sk_buff_head tx_queue;
++
++static grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
++static gnttab_unmap_grant_ref_t tx_unmap_ops[MAX_PENDING_REQS];
++static gnttab_map_grant_ref_t tx_map_ops[MAX_PENDING_REQS];
++
++static struct list_head net_schedule_list;
++static spinlock_t net_schedule_list_lock;
++
++#define MAX_MFN_ALLOC 64
++static unsigned long mfn_list[MAX_MFN_ALLOC];
++static unsigned int alloc_index = 0;
++
++/* Setting this allows the safe use of this driver without netloop. */
++static int MODPARM_copy_skb = 1;
++module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
++MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without netloop");
++
++int netbk_copy_skb_mode;
++
++static inline unsigned long alloc_mfn(void)
++{
++      BUG_ON(alloc_index == 0);
++      return mfn_list[--alloc_index];
++}
++
++static int check_mfn(int nr)
++{
++      struct xen_memory_reservation reservation = {
++              .extent_order = 0,
++              .domid        = DOMID_SELF
++      };
++      int rc;
++
++      if (likely(alloc_index >= nr))
++              return 0;
++
++      set_xen_guest_handle(reservation.extent_start, mfn_list + alloc_index);
++      reservation.nr_extents = MAX_MFN_ALLOC - alloc_index;
++      rc = HYPERVISOR_memory_op(XENMEM_increase_reservation, &reservation);
++      if (likely(rc > 0))
++              alloc_index += rc;
++
++      return alloc_index >= nr ? 0 : -ENOMEM;
++}
++
++static inline void maybe_schedule_tx_action(void)
++{
++      smp_mb();
++      if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
++          !list_empty(&net_schedule_list))
++              tasklet_schedule(&net_tx_tasklet);
++}
++
++static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
++{
++      struct skb_shared_info *ninfo;
++      struct sk_buff *nskb;
++      unsigned long offset;
++      int ret;
++      int len;
++      int headlen;
++
++      BUG_ON(skb_shinfo(skb)->frag_list != NULL);
++
++      nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
++      if (unlikely(!nskb))
++              goto err;
++
++      skb_reserve(nskb, 16 + NET_IP_ALIGN);
++      headlen = nskb->end - nskb->data;
++      if (headlen > skb_headlen(skb))
++              headlen = skb_headlen(skb);
++      ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
++      BUG_ON(ret);
++
++      ninfo = skb_shinfo(nskb);
++      ninfo->gso_size = skb_shinfo(skb)->gso_size;
++      ninfo->gso_type = skb_shinfo(skb)->gso_type;
++
++      offset = headlen;
++      len = skb->len - headlen;
++
++      nskb->len = skb->len;
++      nskb->data_len = len;
++      nskb->truesize += len;
++
++      while (len) {
++              struct page *page;
++              int copy;
++              int zero;
++
++              if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
++                      dump_stack();
++                      goto err_free;
++              }
++
++              copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
++              zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
++
++              page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
++              if (unlikely(!page))
++                      goto err_free;
++
++              ret = skb_copy_bits(skb, offset, page_address(page), copy);
++              BUG_ON(ret);
++
++              ninfo->frags[ninfo->nr_frags].page = page;
++              ninfo->frags[ninfo->nr_frags].page_offset = 0;
++              ninfo->frags[ninfo->nr_frags].size = copy;
++              ninfo->nr_frags++;
++
++              offset += copy;
++              len -= copy;
++      }
++
++      offset = nskb->data - skb->data;
++
++      nskb->h.raw = skb->h.raw + offset;
++      nskb->nh.raw = skb->nh.raw + offset;
++      nskb->mac.raw = skb->mac.raw + offset;
++
++      return nskb;
++
++ err_free:
++      kfree_skb(nskb);
++ err:
++      return NULL;
++}
++
++static inline int netbk_max_required_rx_slots(netif_t *netif)
++{
++      if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
++              return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
++      return 1; /* all in one */
++}
++
++static inline int netbk_queue_full(netif_t *netif)
++{
++      RING_IDX peek   = netif->rx_req_cons_peek;
++      RING_IDX needed = netbk_max_required_rx_slots(netif);
++
++      return ((netif->rx.sring->req_prod - peek) < needed) ||
++             ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
++}
++
++static void tx_queue_callback(unsigned long data)
++{
++      netif_t *netif = (netif_t *)data;
++      if (netif_schedulable(netif))
++              netif_wake_queue(netif->dev);
++}
++
++int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      netif_t *netif = netdev_priv(dev);
++
++      BUG_ON(skb->dev != dev);
++
++      /* Drop the packet if the target domain has no receive buffers. */
++      if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
++              goto drop;
++
++      /*
++       * Copy the packet here if it's destined for a flipping interface
++       * but isn't flippable (e.g. extra references to data).
++       * XXX For now we also copy skbuffs whose head crosses a page
++       * boundary, because netbk_gop_skb can't handle them.
++       */
++      if (!netif->copying_receiver ||
++          ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE)) {
++              struct sk_buff *nskb = netbk_copy_skb(skb);
++              if ( unlikely(nskb == NULL) )
++                      goto drop;
++              /* Copy only the header fields we use in this driver. */
++              nskb->dev = skb->dev;
++              nskb->ip_summed = skb->ip_summed;
++              nskb->proto_data_valid = skb->proto_data_valid;
++              dev_kfree_skb(skb);
++              skb = nskb;
++      }
++
++      netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
++                                 !!skb_shinfo(skb)->gso_size;
++      netif_get(netif);
++
++      if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
++              netif->rx.sring->req_event = netif->rx_req_cons_peek +
++                      netbk_max_required_rx_slots(netif);
++              mb(); /* request notification /then/ check & stop the queue */
++              if (netbk_queue_full(netif)) {
++                      netif_stop_queue(dev);
++                      /*
++                       * Schedule 500ms timeout to restart the queue, thus
++                       * ensuring that an inactive queue will be drained.
++                       * Packets will be immediately be dropped until more
++                       * receive buffers become available (see
++                       * netbk_queue_full() check above).
++                       */
++                      netif->tx_queue_timeout.data = (unsigned long)netif;
++                      netif->tx_queue_timeout.function = tx_queue_callback;
++                      __mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
++              }
++      }
++
++      skb_queue_tail(&rx_queue, skb);
++      tasklet_schedule(&net_rx_tasklet);
++
++      return 0;
++
++ drop:
++      netif->stats.tx_dropped++;
++      dev_kfree_skb(skb);
++      return 0;
++}
++
++#if 0
++static void xen_network_done_notify(void)
++{
++      static struct net_device *eth0_dev = NULL;
++      if (unlikely(eth0_dev == NULL))
++              eth0_dev = __dev_get_by_name("eth0");
++      netif_rx_schedule(eth0_dev);
++}
++/* 
++ * Add following to poll() function in NAPI driver (Tigon3 is example):
++ *  if ( xen_network_done() )
++ *      tg3_enable_ints(tp);
++ */
++int xen_network_done(void)
++{
++      return skb_queue_empty(&rx_queue);
++}
++#endif
++
++struct netrx_pending_operations {
++      unsigned trans_prod, trans_cons;
++      unsigned mmu_prod, mmu_mcl;
++      unsigned mcl_prod, mcl_cons;
++      unsigned copy_prod, copy_cons;
++      unsigned meta_prod, meta_cons;
++      mmu_update_t *mmu;
++      gnttab_transfer_t *trans;
++      gnttab_copy_t *copy;
++      multicall_entry_t *mcl;
++      struct netbk_rx_meta *meta;
++};
++
++/* Set up the grant operations for this fragment.  If it's a flipping
++   interface, we also set up the unmap request from here. */
++static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta *meta,
++                        int i, struct netrx_pending_operations *npo,
++                        struct page *page, unsigned long size,
++                        unsigned long offset)
++{
++      mmu_update_t *mmu;
++      gnttab_transfer_t *gop;
++      gnttab_copy_t *copy_gop;
++      multicall_entry_t *mcl;
++      netif_rx_request_t *req;
++      unsigned long old_mfn, new_mfn;
++
++      old_mfn = virt_to_mfn(page_address(page));
++
++      req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i);
++      if (netif->copying_receiver) {
++              /* The fragment needs to be copied rather than
++                 flipped. */
++              meta->copy = 1;
++              copy_gop = npo->copy + npo->copy_prod++;
++              copy_gop->flags = GNTCOPY_dest_gref;
++              if (PageForeign(page)) {
++                      struct pending_tx_info *src_pend =
++                              &pending_tx_info[netif_page_index(page)];
++                      copy_gop->source.domid = src_pend->netif->domid;
++                      copy_gop->source.u.ref = src_pend->req.gref;
++                      copy_gop->flags |= GNTCOPY_source_gref;
++              } else {
++                      copy_gop->source.domid = DOMID_SELF;
++                      copy_gop->source.u.gmfn = old_mfn;
++              }
++              copy_gop->source.offset = offset;
++              copy_gop->dest.domid = netif->domid;
++              copy_gop->dest.offset = 0;
++              copy_gop->dest.u.ref = req->gref;
++              copy_gop->len = size;
++      } else {
++              meta->copy = 0;
++              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++                      new_mfn = alloc_mfn();
++
++                      /*
++                       * Set the new P2M table entry before
++                       * reassigning the old data page. Heed the
++                       * comment in pgtable-2level.h:pte_page(). :-)
++                       */
++                      set_phys_to_machine(page_to_pfn(page), new_mfn);
++
++                      mcl = npo->mcl + npo->mcl_prod++;
++                      MULTI_update_va_mapping(mcl,
++                                           (unsigned long)page_address(page),
++                                           pfn_pte_ma(new_mfn, PAGE_KERNEL),
++                                           0);
++
++                      mmu = npo->mmu + npo->mmu_prod++;
++                      mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) |
++                              MMU_MACHPHYS_UPDATE;
++                      mmu->val = page_to_pfn(page);
++              }
++
++              gop = npo->trans + npo->trans_prod++;
++              gop->mfn = old_mfn;
++              gop->domid = netif->domid;
++              gop->ref = req->gref;
++      }
++      return req->id;
++}
++
++static void netbk_gop_skb(struct sk_buff *skb,
++                        struct netrx_pending_operations *npo)
++{
++      netif_t *netif = netdev_priv(skb->dev);
++      int nr_frags = skb_shinfo(skb)->nr_frags;
++      int i;
++      int extra;
++      struct netbk_rx_meta *head_meta, *meta;
++
++      head_meta = npo->meta + npo->meta_prod++;
++      head_meta->frag.page_offset = skb_shinfo(skb)->gso_type;
++      head_meta->frag.size = skb_shinfo(skb)->gso_size;
++      extra = !!head_meta->frag.size + 1;
++
++      for (i = 0; i < nr_frags; i++) {
++              meta = npo->meta + npo->meta_prod++;
++              meta->frag = skb_shinfo(skb)->frags[i];
++              meta->id = netbk_gop_frag(netif, meta, i + extra, npo,
++                                        meta->frag.page,
++                                        meta->frag.size,
++                                        meta->frag.page_offset);
++      }
++
++      /*
++       * This must occur at the end to ensure that we don't trash skb_shinfo
++       * until we're done. We know that the head doesn't cross a page
++       * boundary because such packets get copied in netif_be_start_xmit.
++       */
++      head_meta->id = netbk_gop_frag(netif, head_meta, 0, npo,
++                                     virt_to_page(skb->data),
++                                     skb_headlen(skb),
++                                     offset_in_page(skb->data));
++
++      netif->rx.req_cons += nr_frags + extra;
++}
++
++static inline void netbk_free_pages(int nr_frags, struct netbk_rx_meta *meta)
++{
++      int i;
++
++      for (i = 0; i < nr_frags; i++)
++              put_page(meta[i].frag.page);
++}
++
++/* This is a twin to netbk_gop_skb.  Assume that netbk_gop_skb was
++   used to set up the operations on the top of
++   netrx_pending_operations, which have since been done.  Check that
++   they didn't give any errors and advance over them. */
++static int netbk_check_gop(int nr_frags, domid_t domid,
++                         struct netrx_pending_operations *npo)
++{
++      multicall_entry_t *mcl;
++      gnttab_transfer_t *gop;
++      gnttab_copy_t     *copy_op;
++      int status = NETIF_RSP_OKAY;
++      int i;
++
++      for (i = 0; i <= nr_frags; i++) {
++              if (npo->meta[npo->meta_cons + i].copy) {
++                      copy_op = npo->copy + npo->copy_cons++;
++                      if (copy_op->status != GNTST_okay) {
++                              DPRINTK("Bad status %d from copy to DOM%d.\n",
++                                      copy_op->status, domid);
++                              status = NETIF_RSP_ERROR;
++                      }
++              } else {
++                      if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++                              mcl = npo->mcl + npo->mcl_cons++;
++                              /* The update_va_mapping() must not fail. */
++                              BUG_ON(mcl->result != 0);
++                      }
++
++                      gop = npo->trans + npo->trans_cons++;
++                      /* Check the reassignment error code. */
++                      if (gop->status != 0) {
++                              DPRINTK("Bad status %d from grant transfer to DOM%u\n",
++                                      gop->status, domid);
++                              /*
++                               * Page no longer belongs to us unless
++                               * GNTST_bad_page, but that should be
++                               * a fatal error anyway.
++                               */
++                              BUG_ON(gop->status == GNTST_bad_page);
++                              status = NETIF_RSP_ERROR;
++                      }
++              }
++      }
++
++      return status;
++}
++
++static void netbk_add_frag_responses(netif_t *netif, int status,
++                                   struct netbk_rx_meta *meta, int nr_frags)
++{
++      int i;
++      unsigned long offset;
++
++      for (i = 0; i < nr_frags; i++) {
++              int id = meta[i].id;
++              int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data;
++
++              if (meta[i].copy)
++                      offset = 0;
++              else
++                      offset = meta[i].frag.page_offset;
++              make_rx_response(netif, id, status, offset,
++                               meta[i].frag.size, flags);
++      }
++}
++
++static void net_rx_action(unsigned long unused)
++{
++      netif_t *netif = NULL;
++      s8 status;
++      u16 id, irq, flags;
++      netif_rx_response_t *resp;
++      multicall_entry_t *mcl;
++      struct sk_buff_head rxq;
++      struct sk_buff *skb;
++      int notify_nr = 0;
++      int ret;
++      int nr_frags;
++      int count;
++      unsigned long offset;
++
++      /*
++       * Putting hundreds of bytes on the stack is considered rude.
++       * Static works because a tasklet can only be on one CPU at any time.
++       */
++      static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+3];
++      static mmu_update_t rx_mmu[NET_RX_RING_SIZE];
++      static gnttab_transfer_t grant_trans_op[NET_RX_RING_SIZE];
++      static gnttab_copy_t grant_copy_op[NET_RX_RING_SIZE];
++      static unsigned char rx_notify[NR_IRQS];
++      static u16 notify_list[NET_RX_RING_SIZE];
++      static struct netbk_rx_meta meta[NET_RX_RING_SIZE];
++
++      struct netrx_pending_operations npo = {
++              mmu: rx_mmu,
++              trans: grant_trans_op,
++              copy: grant_copy_op,
++              mcl: rx_mcl,
++              meta: meta};
++
++      skb_queue_head_init(&rxq);
++
++      count = 0;
++
++      while ((skb = skb_dequeue(&rx_queue)) != NULL) {
++              nr_frags = skb_shinfo(skb)->nr_frags;
++              *(int *)skb->cb = nr_frags;
++
++              if (!xen_feature(XENFEAT_auto_translated_physmap) &&
++                  !((netif_t *)netdev_priv(skb->dev))->copying_receiver &&
++                  check_mfn(nr_frags + 1)) {
++                      /* Memory squeeze? Back off for an arbitrary while. */
++                      if ( net_ratelimit() )
++                              WPRINTK("Memory squeeze in netback "
++                                      "driver.\n");
++                      mod_timer(&net_timer, jiffies + HZ);
++                      skb_queue_head(&rx_queue, skb);
++                      break;
++              }
++
++              netbk_gop_skb(skb, &npo);
++
++              count += nr_frags + 1;
++
++              __skb_queue_tail(&rxq, skb);
++
++              /* Filled the batch queue? */
++              if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
++                      break;
++      }
++
++      BUG_ON(npo.meta_prod > ARRAY_SIZE(meta));
++
++      npo.mmu_mcl = npo.mcl_prod;
++      if (npo.mcl_prod) {
++              BUG_ON(xen_feature(XENFEAT_auto_translated_physmap));
++              BUG_ON(npo.mmu_prod > ARRAY_SIZE(rx_mmu));
++              mcl = npo.mcl + npo.mcl_prod++;
++
++              BUG_ON(mcl[-1].op != __HYPERVISOR_update_va_mapping);
++              mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL;
++
++              mcl->op = __HYPERVISOR_mmu_update;
++              mcl->args[0] = (unsigned long)rx_mmu;
++              mcl->args[1] = npo.mmu_prod;
++              mcl->args[2] = 0;
++              mcl->args[3] = DOMID_SELF;
++      }
++
++      if (npo.trans_prod) {
++              BUG_ON(npo.trans_prod > ARRAY_SIZE(grant_trans_op));
++              mcl = npo.mcl + npo.mcl_prod++;
++              mcl->op = __HYPERVISOR_grant_table_op;
++              mcl->args[0] = GNTTABOP_transfer;
++              mcl->args[1] = (unsigned long)grant_trans_op;
++              mcl->args[2] = npo.trans_prod;
++      }
++
++      if (npo.copy_prod) {
++              BUG_ON(npo.copy_prod > ARRAY_SIZE(grant_copy_op));
++              mcl = npo.mcl + npo.mcl_prod++;
++              mcl->op = __HYPERVISOR_grant_table_op;
++              mcl->args[0] = GNTTABOP_copy;
++              mcl->args[1] = (unsigned long)grant_copy_op;
++              mcl->args[2] = npo.copy_prod;
++      }
++
++      /* Nothing to do? */
++      if (!npo.mcl_prod)
++              return;
++
++      BUG_ON(npo.mcl_prod > ARRAY_SIZE(rx_mcl));
++
++      ret = HYPERVISOR_multicall(npo.mcl, npo.mcl_prod);
++      BUG_ON(ret != 0);
++      /* The mmu_machphys_update() must not fail. */
++      BUG_ON(npo.mmu_mcl && npo.mcl[npo.mmu_mcl].result != 0);
++
++      while ((skb = __skb_dequeue(&rxq)) != NULL) {
++              nr_frags = *(int *)skb->cb;
++
++              netif = netdev_priv(skb->dev);
++              /* We can't rely on skb_release_data to release the
++                 pages used by fragments for us, since it tries to
++                 touch the pages in the fraglist.  If we're in
++                 flipping mode, that doesn't work.  In copying mode,
++                 we still have access to all of the pages, and so
++                 it's safe to let release_data deal with it. */
++              /* (Freeing the fragments is safe since we copy
++                 non-linear skbs destined for flipping interfaces) */
++              if (!netif->copying_receiver) {
++                      atomic_set(&(skb_shinfo(skb)->dataref), 1);
++                      skb_shinfo(skb)->frag_list = NULL;
++                      skb_shinfo(skb)->nr_frags = 0;
++                      netbk_free_pages(nr_frags, meta + npo.meta_cons + 1);
++              }
++
++              netif->stats.tx_bytes += skb->len;
++              netif->stats.tx_packets++;
++
++              status = netbk_check_gop(nr_frags, netif->domid, &npo);
++
++              id = meta[npo.meta_cons].id;
++              flags = nr_frags ? NETRXF_more_data : 0;
++
++              if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
++                      flags |= NETRXF_csum_blank | NETRXF_data_validated;
++              else if (skb->proto_data_valid) /* remote but checksummed? */
++                      flags |= NETRXF_data_validated;
++
++              if (meta[npo.meta_cons].copy)
++                      offset = 0;
++              else
++                      offset = offset_in_page(skb->data);
++              resp = make_rx_response(netif, id, status, offset,
++                                      skb_headlen(skb), flags);
++
++              if (meta[npo.meta_cons].frag.size) {
++                      struct netif_extra_info *gso =
++                              (struct netif_extra_info *)
++                              RING_GET_RESPONSE(&netif->rx,
++                                                netif->rx.rsp_prod_pvt++);
++
++                      resp->flags |= NETRXF_extra_info;
++
++                      gso->u.gso.size = meta[npo.meta_cons].frag.size;
++                      gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
++                      gso->u.gso.pad = 0;
++                      gso->u.gso.features = 0;
++
++                      gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
++                      gso->flags = 0;
++              }
++
++              netbk_add_frag_responses(netif, status,
++                                       meta + npo.meta_cons + 1,
++                                       nr_frags);
++
++              RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
++              irq = netif->irq;
++              if (ret && !rx_notify[irq]) {
++                      rx_notify[irq] = 1;
++                      notify_list[notify_nr++] = irq;
++              }
++
++              if (netif_queue_stopped(netif->dev) &&
++                  netif_schedulable(netif) &&
++                  !netbk_queue_full(netif))
++                      netif_wake_queue(netif->dev);
++
++              netif_put(netif);
++              dev_kfree_skb(skb);
++              npo.meta_cons += nr_frags + 1;
++      }
++
++      while (notify_nr != 0) {
++              irq = notify_list[--notify_nr];
++              rx_notify[irq] = 0;
++              notify_remote_via_irq(irq);
++      }
++
++      /* More work to do? */
++      if (!skb_queue_empty(&rx_queue) && !timer_pending(&net_timer))
++              tasklet_schedule(&net_rx_tasklet);
++#if 0
++      else
++              xen_network_done_notify();
++#endif
++}
++
++static void net_alarm(unsigned long unused)
++{
++      tasklet_schedule(&net_rx_tasklet);
++}
++
++static void netbk_tx_pending_timeout(unsigned long unused)
++{
++      tasklet_schedule(&net_tx_tasklet);
++}
++
++struct net_device_stats *netif_be_get_stats(struct net_device *dev)
++{
++      netif_t *netif = netdev_priv(dev);
++      return &netif->stats;
++}
++
++static int __on_net_schedule_list(netif_t *netif)
++{
++      return netif->list.next != NULL;
++}
++
++static void remove_from_net_schedule_list(netif_t *netif)
++{
++      spin_lock_irq(&net_schedule_list_lock);
++      if (likely(__on_net_schedule_list(netif))) {
++              list_del(&netif->list);
++              netif->list.next = NULL;
++              netif_put(netif);
++      }
++      spin_unlock_irq(&net_schedule_list_lock);
++}
++
++static void add_to_net_schedule_list_tail(netif_t *netif)
++{
++      if (__on_net_schedule_list(netif))
++              return;
++
++      spin_lock_irq(&net_schedule_list_lock);
++      if (!__on_net_schedule_list(netif) &&
++          likely(netif_schedulable(netif))) {
++              list_add_tail(&netif->list, &net_schedule_list);
++              netif_get(netif);
++      }
++      spin_unlock_irq(&net_schedule_list_lock);
++}
++
++/*
++ * Note on CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER:
++ * If this driver is pipelining transmit requests then we can be very
++ * aggressive in avoiding new-packet notifications -- frontend only needs to
++ * send a notification if there are no outstanding unreceived responses.
++ * If we may be buffer transmit buffers for any reason then we must be rather
++ * more conservative and treat this as the final check for pending work.
++ */
++void netif_schedule_work(netif_t *netif)
++{
++      int more_to_do;
++
++#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
++      more_to_do = RING_HAS_UNCONSUMED_REQUESTS(&netif->tx);
++#else
++      RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
++#endif
++
++      if (more_to_do) {
++              add_to_net_schedule_list_tail(netif);
++              maybe_schedule_tx_action();
++      }
++}
++
++void netif_deschedule_work(netif_t *netif)
++{
++      remove_from_net_schedule_list(netif);
++}
++
++
++static void tx_add_credit(netif_t *netif)
++{
++      unsigned long max_burst, max_credit;
++
++      /*
++       * Allow a burst big enough to transmit a jumbo packet of up to 128kB.
++       * Otherwise the interface can seize up due to insufficient credit.
++       */
++      max_burst = RING_GET_REQUEST(&netif->tx, netif->tx.req_cons)->size;
++      max_burst = min(max_burst, 131072UL);
++      max_burst = max(max_burst, netif->credit_bytes);
++
++      /* Take care that adding a new chunk of credit doesn't wrap to zero. */
++      max_credit = netif->remaining_credit + netif->credit_bytes;
++      if (max_credit < netif->remaining_credit)
++              max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
++
++      netif->remaining_credit = min(max_credit, max_burst);
++}
++
++static void tx_credit_callback(unsigned long data)
++{
++      netif_t *netif = (netif_t *)data;
++      tx_add_credit(netif);
++      netif_schedule_work(netif);
++}
++
++static inline int copy_pending_req(PEND_RING_IDX pending_idx)
++{
++      return gnttab_copy_grant_page(grant_tx_handle[pending_idx],
++                                    &mmap_pages[pending_idx]);
++}
++
++inline static void net_tx_action_dealloc(void)
++{
++      struct netbk_tx_pending_inuse *inuse, *n;
++      gnttab_unmap_grant_ref_t *gop;
++      u16 pending_idx;
++      PEND_RING_IDX dc, dp;
++      netif_t *netif;
++      int ret;
++      LIST_HEAD(list);
++
++      dc = dealloc_cons;
++      gop = tx_unmap_ops;
++
++      /*
++       * Free up any grants we have finished using
++       */
++      do {
++              dp = dealloc_prod;
++
++              /* Ensure we see all indices enqueued by netif_idx_release(). */
++              smp_rmb();
++
++              while (dc != dp) {
++                      unsigned long pfn;
++
++                      pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
++                      list_move_tail(&pending_inuse[pending_idx].list, &list);
++
++                      pfn = idx_to_pfn(pending_idx);
++                      /* Already unmapped? */
++                      if (!phys_to_machine_mapping_valid(pfn))
++                              continue;
++
++                      gnttab_set_unmap_op(gop, idx_to_kaddr(pending_idx),
++                                          GNTMAP_host_map,
++                                          grant_tx_handle[pending_idx]);
++                      gop++;
++              }
++
++              if (netbk_copy_skb_mode != NETBK_DELAYED_COPY_SKB ||
++                  list_empty(&pending_inuse_head))
++                      break;
++
++              /* Copy any entries that have been pending for too long. */
++              list_for_each_entry_safe(inuse, n, &pending_inuse_head, list) {
++                      if (time_after(inuse->alloc_time + HZ / 2, jiffies))
++                              break;
++
++                      switch (copy_pending_req(inuse - pending_inuse)) {
++                      case 0:
++                              list_move_tail(&inuse->list, &list);
++                              continue;
++                      case -EBUSY:
++                              list_del_init(&inuse->list);
++                              continue;
++                      case -ENOENT:
++                              continue;
++                      }
++
++                      break;
++              }
++      } while (dp != dealloc_prod);
++
++      dealloc_cons = dc;
++
++      ret = HYPERVISOR_grant_table_op(
++              GNTTABOP_unmap_grant_ref, tx_unmap_ops, gop - tx_unmap_ops);
++      BUG_ON(ret);
++
++      list_for_each_entry_safe(inuse, n, &list, list) {
++              pending_idx = inuse - pending_inuse;
++
++              netif = pending_tx_info[pending_idx].netif;
++
++              make_tx_response(netif, &pending_tx_info[pending_idx].req, 
++                               NETIF_RSP_OKAY);
++
++              /* Ready for next use. */
++              gnttab_reset_grant_page(mmap_pages[pending_idx]);
++
++              pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
++
++              netif_put(netif);
++
++              list_del_init(&inuse->list);
++      }
++}
++
++static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end)
++{
++      RING_IDX cons = netif->tx.req_cons;
++
++      do {
++              make_tx_response(netif, txp, NETIF_RSP_ERROR);
++              if (cons >= end)
++                      break;
++              txp = RING_GET_REQUEST(&netif->tx, cons++);
++      } while (1);
++      netif->tx.req_cons = cons;
++      netif_schedule_work(netif);
++      netif_put(netif);
++}
++
++static int netbk_count_requests(netif_t *netif, netif_tx_request_t *first,
++                              netif_tx_request_t *txp, int work_to_do)
++{
++      RING_IDX cons = netif->tx.req_cons;
++      int frags = 0;
++
++      if (!(first->flags & NETTXF_more_data))
++              return 0;
++
++      do {
++              if (frags >= work_to_do) {
++                      DPRINTK("Need more frags\n");
++                      return -frags;
++              }
++
++              if (unlikely(frags >= MAX_SKB_FRAGS)) {
++                      DPRINTK("Too many frags\n");
++                      return -frags;
++              }
++
++              memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
++                     sizeof(*txp));
++              if (txp->size > first->size) {
++                      DPRINTK("Frags galore\n");
++                      return -frags;
++              }
++
++              first->size -= txp->size;
++              frags++;
++
++              if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
++                      DPRINTK("txp->offset: %x, size: %u\n",
++                              txp->offset, txp->size);
++                      return -frags;
++              }
++      } while ((txp++)->flags & NETTXF_more_data);
++
++      return frags;
++}
++
++static gnttab_map_grant_ref_t *netbk_get_requests(netif_t *netif,
++                                                struct sk_buff *skb,
++                                                netif_tx_request_t *txp,
++                                                gnttab_map_grant_ref_t *mop)
++{
++      struct skb_shared_info *shinfo = skb_shinfo(skb);
++      skb_frag_t *frags = shinfo->frags;
++      unsigned long pending_idx = *((u16 *)skb->data);
++      int i, start;
++
++      /* Skip first skb fragment if it is on same page as header fragment. */
++      start = ((unsigned long)shinfo->frags[0].page == pending_idx);
++
++      for (i = start; i < shinfo->nr_frags; i++, txp++) {
++              pending_idx = pending_ring[MASK_PEND_IDX(pending_cons++)];
++
++              gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
++                                GNTMAP_host_map | GNTMAP_readonly,
++                                txp->gref, netif->domid);
++
++              memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
++              netif_get(netif);
++              pending_tx_info[pending_idx].netif = netif;
++              frags[i].page = (void *)pending_idx;
++      }
++
++      return mop;
++}
++
++static int netbk_tx_check_mop(struct sk_buff *skb,
++                             gnttab_map_grant_ref_t **mopp)
++{
++      gnttab_map_grant_ref_t *mop = *mopp;
++      int pending_idx = *((u16 *)skb->data);
++      netif_t *netif = pending_tx_info[pending_idx].netif;
++      netif_tx_request_t *txp;
++      struct skb_shared_info *shinfo = skb_shinfo(skb);
++      int nr_frags = shinfo->nr_frags;
++      int i, err, start;
++
++      /* Check status of header. */
++      err = mop->status;
++      if (unlikely(err)) {
++              txp = &pending_tx_info[pending_idx].req;
++              make_tx_response(netif, txp, NETIF_RSP_ERROR);
++              pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
++              netif_put(netif);
++      } else {
++              set_phys_to_machine(
++                      __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT,
++                      FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
++              grant_tx_handle[pending_idx] = mop->handle;
++      }
++
++      /* Skip first skb fragment if it is on same page as header fragment. */
++      start = ((unsigned long)shinfo->frags[0].page == pending_idx);
++
++      for (i = start; i < nr_frags; i++) {
++              int j, newerr;
++
++              pending_idx = (unsigned long)shinfo->frags[i].page;
++
++              /* Check error status: if okay then remember grant handle. */
++              newerr = (++mop)->status;
++              if (likely(!newerr)) {
++                      set_phys_to_machine(
++                              __pa(idx_to_kaddr(pending_idx))>>PAGE_SHIFT,
++                              FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
++                      grant_tx_handle[pending_idx] = mop->handle;
++                      /* Had a previous error? Invalidate this fragment. */
++                      if (unlikely(err))
++                              netif_idx_release(pending_idx);
++                      continue;
++              }
++
++              /* Error on this fragment: respond to client with an error. */
++              txp = &pending_tx_info[pending_idx].req;
++              make_tx_response(netif, txp, NETIF_RSP_ERROR);
++              pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
++              netif_put(netif);
++
++              /* Not the first error? Preceding frags already invalidated. */
++              if (err)
++                      continue;
++
++              /* First error: invalidate header and preceding fragments. */
++              pending_idx = *((u16 *)skb->data);
++              netif_idx_release(pending_idx);
++              for (j = start; j < i; j++) {
++                      pending_idx = (unsigned long)shinfo->frags[i].page;
++                      netif_idx_release(pending_idx);
++              }
++
++              /* Remember the error: invalidate all subsequent fragments. */
++              err = newerr;
++      }
++
++      *mopp = mop + 1;
++      return err;
++}
++
++static void netbk_fill_frags(struct sk_buff *skb)
++{
++      struct skb_shared_info *shinfo = skb_shinfo(skb);
++      int nr_frags = shinfo->nr_frags;
++      int i;
++
++      for (i = 0; i < nr_frags; i++) {
++              skb_frag_t *frag = shinfo->frags + i;
++              netif_tx_request_t *txp;
++              unsigned long pending_idx;
++
++              pending_idx = (unsigned long)frag->page;
++
++              pending_inuse[pending_idx].alloc_time = jiffies;
++              list_add_tail(&pending_inuse[pending_idx].list,
++                            &pending_inuse_head);
++
++              txp = &pending_tx_info[pending_idx].req;
++              frag->page = virt_to_page(idx_to_kaddr(pending_idx));
++              frag->size = txp->size;
++              frag->page_offset = txp->offset;
++
++              skb->len += txp->size;
++              skb->data_len += txp->size;
++              skb->truesize += txp->size;
++      }
++}
++
++int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras,
++                   int work_to_do)
++{
++      struct netif_extra_info extra;
++      RING_IDX cons = netif->tx.req_cons;
++
++      do {
++              if (unlikely(work_to_do-- <= 0)) {
++                      DPRINTK("Missing extra info\n");
++                      return -EBADR;
++              }
++
++              memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons),
++                     sizeof(extra));
++              if (unlikely(!extra.type ||
++                           extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
++                      netif->tx.req_cons = ++cons;
++                      DPRINTK("Invalid extra type: %d\n", extra.type);
++                      return -EINVAL;
++              }
++
++              memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
++              netif->tx.req_cons = ++cons;
++      } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
++
++      return work_to_do;
++}
++
++static int netbk_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso)
++{
++      if (!gso->u.gso.size) {
++              DPRINTK("GSO size must not be zero.\n");
++              return -EINVAL;
++      }
++
++      /* Currently only TCPv4 S.O. is supported. */
++      if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
++              DPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
++              return -EINVAL;
++      }
++
++      skb_shinfo(skb)->gso_size = gso->u.gso.size;
++      skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
++
++      /* Header must be checked, and gso_segs computed. */
++      skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
++      skb_shinfo(skb)->gso_segs = 0;
++
++      return 0;
++}
++
++/* Called after netfront has transmitted */
++static void net_tx_action(unsigned long unused)
++{
++      struct list_head *ent;
++      struct sk_buff *skb;
++      netif_t *netif;
++      netif_tx_request_t txreq;
++      netif_tx_request_t txfrags[MAX_SKB_FRAGS];
++      struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
++      u16 pending_idx;
++      RING_IDX i;
++      gnttab_map_grant_ref_t *mop;
++      unsigned int data_len;
++      int ret, work_to_do;
++
++      if (dealloc_cons != dealloc_prod)
++              net_tx_action_dealloc();
++
++      mop = tx_map_ops;
++      while (((NR_PENDING_REQS + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
++              !list_empty(&net_schedule_list)) {
++              /* Get a netif from the list with work to do. */
++              ent = net_schedule_list.next;
++              netif = list_entry(ent, netif_t, list);
++              netif_get(netif);
++              remove_from_net_schedule_list(netif);
++
++              RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
++              if (!work_to_do) {
++                      netif_put(netif);
++                      continue;
++              }
++
++              i = netif->tx.req_cons;
++              rmb(); /* Ensure that we see the request before we copy it. */
++              memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq));
++
++              /* Credit-based scheduling. */
++              if (txreq.size > netif->remaining_credit) {
++                      unsigned long now = jiffies;
++                      unsigned long next_credit = 
++                              netif->credit_timeout.expires +
++                              msecs_to_jiffies(netif->credit_usec / 1000);
++
++                      /* Timer could already be pending in rare cases. */
++                      if (timer_pending(&netif->credit_timeout)) {
++                              netif_put(netif);
++                              continue;
++                      }
++
++                      /* Passed the point where we can replenish credit? */
++                      if (time_after_eq(now, next_credit)) {
++                              netif->credit_timeout.expires = now;
++                              tx_add_credit(netif);
++                      }
++
++                      /* Still too big to send right now? Set a callback. */
++                      if (txreq.size > netif->remaining_credit) {
++                              netif->credit_timeout.data     =
++                                      (unsigned long)netif;
++                              netif->credit_timeout.function =
++                                      tx_credit_callback;
++                              __mod_timer(&netif->credit_timeout,
++                                          next_credit);
++                              netif_put(netif);
++                              continue;
++                      }
++              }
++              netif->remaining_credit -= txreq.size;
++
++              work_to_do--;
++              netif->tx.req_cons = ++i;
++
++              memset(extras, 0, sizeof(extras));
++              if (txreq.flags & NETTXF_extra_info) {
++                      work_to_do = netbk_get_extras(netif, extras,
++                                                    work_to_do);
++                      i = netif->tx.req_cons;
++                      if (unlikely(work_to_do < 0)) {
++                              netbk_tx_err(netif, &txreq, i);
++                              continue;
++                      }
++              }
++
++              ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
++              if (unlikely(ret < 0)) {
++                      netbk_tx_err(netif, &txreq, i - ret);
++                      continue;
++              }
++              i += ret;
++
++              if (unlikely(txreq.size < ETH_HLEN)) {
++                      DPRINTK("Bad packet size: %d\n", txreq.size);
++                      netbk_tx_err(netif, &txreq, i);
++                      continue;
++              }
++
++              /* No crossing a page as the payload mustn't fragment. */
++              if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
++                      DPRINTK("txreq.offset: %x, size: %u, end: %lu\n", 
++                              txreq.offset, txreq.size, 
++                              (txreq.offset &~PAGE_MASK) + txreq.size);
++                      netbk_tx_err(netif, &txreq, i);
++                      continue;
++              }
++
++              pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
++
++              data_len = (txreq.size > PKT_PROT_LEN &&
++                          ret < MAX_SKB_FRAGS) ?
++                      PKT_PROT_LEN : txreq.size;
++
++              skb = alloc_skb(data_len + 16 + NET_IP_ALIGN,
++                              GFP_ATOMIC | __GFP_NOWARN);
++              if (unlikely(skb == NULL)) {
++                      DPRINTK("Can't allocate a skb in start_xmit.\n");
++                      netbk_tx_err(netif, &txreq, i);
++                      break;
++              }
++
++              /* Packets passed to netif_rx() must have some headroom. */
++              skb_reserve(skb, 16 + NET_IP_ALIGN);
++
++              if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
++                      struct netif_extra_info *gso;
++                      gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
++
++                      if (netbk_set_skb_gso(skb, gso)) {
++                              kfree_skb(skb);
++                              netbk_tx_err(netif, &txreq, i);
++                              continue;
++                      }
++              }
++
++              gnttab_set_map_op(mop, idx_to_kaddr(pending_idx),
++                                GNTMAP_host_map | GNTMAP_readonly,
++                                txreq.gref, netif->domid);
++              mop++;
++
++              memcpy(&pending_tx_info[pending_idx].req,
++                     &txreq, sizeof(txreq));
++              pending_tx_info[pending_idx].netif = netif;
++              *((u16 *)skb->data) = pending_idx;
++
++              __skb_put(skb, data_len);
++
++              skb_shinfo(skb)->nr_frags = ret;
++              if (data_len < txreq.size) {
++                      skb_shinfo(skb)->nr_frags++;
++                      skb_shinfo(skb)->frags[0].page =
++                              (void *)(unsigned long)pending_idx;
++              } else {
++                      /* Discriminate from any valid pending_idx value. */
++                      skb_shinfo(skb)->frags[0].page = (void *)~0UL;
++              }
++
++              __skb_queue_tail(&tx_queue, skb);
++
++              pending_cons++;
++
++              mop = netbk_get_requests(netif, skb, txfrags, mop);
++
++              netif->tx.req_cons = i;
++              netif_schedule_work(netif);
++
++              if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops))
++                      break;
++      }
++
++      if (mop == tx_map_ops)
++              return;
++
++      ret = HYPERVISOR_grant_table_op(
++              GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops);
++      BUG_ON(ret);
++
++      mop = tx_map_ops;
++      while ((skb = __skb_dequeue(&tx_queue)) != NULL) {
++              netif_tx_request_t *txp;
++
++              pending_idx = *((u16 *)skb->data);
++              netif       = pending_tx_info[pending_idx].netif;
++              txp         = &pending_tx_info[pending_idx].req;
++
++              /* Check the remap error code. */
++              if (unlikely(netbk_tx_check_mop(skb, &mop))) {
++                      DPRINTK("netback grant failed.\n");
++                      skb_shinfo(skb)->nr_frags = 0;
++                      kfree_skb(skb);
++                      continue;
++              }
++
++              data_len = skb->len;
++              memcpy(skb->data,
++                     (void *)(idx_to_kaddr(pending_idx)|txp->offset),
++                     data_len);
++              if (data_len < txp->size) {
++                      /* Append the packet payload as a fragment. */
++                      txp->offset += data_len;
++                      txp->size -= data_len;
++              } else {
++                      /* Schedule a response immediately. */
++                      netif_idx_release(pending_idx);
++              }
++
++              /*
++               * Old frontends do not assert data_validated but we
++               * can infer it from csum_blank so test both flags.
++               */
++              if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank)) {
++                      skb->ip_summed = CHECKSUM_UNNECESSARY;
++                      skb->proto_data_valid = 1;
++              } else {
++                      skb->ip_summed = CHECKSUM_NONE;
++                      skb->proto_data_valid = 0;
++              }
++              skb->proto_csum_blank = !!(txp->flags & NETTXF_csum_blank);
++
++              netbk_fill_frags(skb);
++
++              skb->dev      = netif->dev;
++              skb->protocol = eth_type_trans(skb, skb->dev);
++
++              netif->stats.rx_bytes += skb->len;
++              netif->stats.rx_packets++;
++
++              if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
++                  unlikely(skb_linearize(skb))) {
++                      DPRINTK("Can't linearize skb in net_tx_action.\n");
++                      kfree_skb(skb);
++                      continue;
++              }
++
++              netif_rx(skb);
++              netif->dev->last_rx = jiffies;
++      }
++
++      if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
++          !list_empty(&pending_inuse_head)) {
++              struct netbk_tx_pending_inuse *oldest;
++
++              oldest = list_entry(pending_inuse_head.next,
++                                  struct netbk_tx_pending_inuse, list);
++              mod_timer(&netbk_tx_pending_timer, oldest->alloc_time + HZ);
++      }
++}
++
++static void netif_idx_release(u16 pending_idx)
++{
++      static DEFINE_SPINLOCK(_lock);
++      unsigned long flags;
++
++      spin_lock_irqsave(&_lock, flags);
++      dealloc_ring[MASK_PEND_IDX(dealloc_prod)] = pending_idx;
++      /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
++      smp_wmb();
++      dealloc_prod++;
++      spin_unlock_irqrestore(&_lock, flags);
++
++      tasklet_schedule(&net_tx_tasklet);
++}
++
++static void netif_page_release(struct page *page)
++{
++      netif_idx_release(netif_page_index(page));
++}
++
++irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
++{
++      netif_t *netif = dev_id;
++
++      add_to_net_schedule_list_tail(netif);
++      maybe_schedule_tx_action();
++
++      if (netif_schedulable(netif) && !netbk_queue_full(netif))
++              netif_wake_queue(netif->dev);
++
++      return IRQ_HANDLED;
++}
++
++static void make_tx_response(netif_t *netif, 
++                           netif_tx_request_t *txp,
++                           s8       st)
++{
++      RING_IDX i = netif->tx.rsp_prod_pvt;
++      netif_tx_response_t *resp;
++      int notify;
++
++      resp = RING_GET_RESPONSE(&netif->tx, i);
++      resp->id     = txp->id;
++      resp->status = st;
++
++      if (txp->flags & NETTXF_extra_info)
++              RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
++
++      netif->tx.rsp_prod_pvt = ++i;
++      RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
++      if (notify)
++              notify_remote_via_irq(netif->irq);
++
++#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
++      if (i == netif->tx.req_cons) {
++              int more_to_do;
++              RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
++              if (more_to_do)
++                      add_to_net_schedule_list_tail(netif);
++      }
++#endif
++}
++
++static netif_rx_response_t *make_rx_response(netif_t *netif, 
++                                           u16      id, 
++                                           s8       st,
++                                           u16      offset,
++                                           u16      size,
++                                           u16      flags)
++{
++      RING_IDX i = netif->rx.rsp_prod_pvt;
++      netif_rx_response_t *resp;
++
++      resp = RING_GET_RESPONSE(&netif->rx, i);
++      resp->offset     = offset;
++      resp->flags      = flags;
++      resp->id         = id;
++      resp->status     = (s16)size;
++      if (st < 0)
++              resp->status = (s16)st;
++
++      netif->rx.rsp_prod_pvt = ++i;
++
++      return resp;
++}
++
++#ifdef NETBE_DEBUG_INTERRUPT
++static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
++{
++      struct list_head *ent;
++      netif_t *netif;
++      int i = 0;
++
++      printk(KERN_ALERT "netif_schedule_list:\n");
++      spin_lock_irq(&net_schedule_list_lock);
++
++      list_for_each (ent, &net_schedule_list) {
++              netif = list_entry(ent, netif_t, list);
++              printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
++                     "rx_resp_prod=%08x\n",
++                     i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
++              printk(KERN_ALERT "   tx_req_cons=%08x tx_resp_prod=%08x)\n",
++                     netif->tx.req_cons, netif->tx.rsp_prod_pvt);
++              printk(KERN_ALERT "   shared(rx_req_prod=%08x "
++                     "rx_resp_prod=%08x\n",
++                     netif->rx.sring->req_prod, netif->rx.sring->rsp_prod);
++              printk(KERN_ALERT "   rx_event=%08x tx_req_prod=%08x\n",
++                     netif->rx.sring->rsp_event, netif->tx.sring->req_prod);
++              printk(KERN_ALERT "   tx_resp_prod=%08x, tx_event=%08x)\n",
++                     netif->tx.sring->rsp_prod, netif->tx.sring->rsp_event);
++              i++;
++      }
++
++      spin_unlock_irq(&net_schedule_list_lock);
++      printk(KERN_ALERT " ** End of netif_schedule_list **\n");
++
++      return IRQ_HANDLED;
++}
++#endif
++
++static int __init netback_init(void)
++{
++      int i;
++      struct page *page;
++
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      /* We can increase reservation by this much in net_rx_action(). */
++      balloon_update_driver_allowance(NET_RX_RING_SIZE);
++
++      skb_queue_head_init(&rx_queue);
++      skb_queue_head_init(&tx_queue);
++
++      init_timer(&net_timer);
++      net_timer.data = 0;
++      net_timer.function = net_alarm;
++
++      init_timer(&netbk_tx_pending_timer);
++      netbk_tx_pending_timer.data = 0;
++      netbk_tx_pending_timer.function = netbk_tx_pending_timeout;
++
++      mmap_pages = alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
++      if (mmap_pages == NULL) {
++              printk("%s: out of memory\n", __FUNCTION__);
++              return -ENOMEM;
++      }
++
++      for (i = 0; i < MAX_PENDING_REQS; i++) {
++              page = mmap_pages[i];
++              SetPageForeign(page, netif_page_release);
++              netif_page_index(page) = i;
++              INIT_LIST_HEAD(&pending_inuse[i].list);
++      }
++
++      pending_cons = 0;
++      pending_prod = MAX_PENDING_REQS;
++      for (i = 0; i < MAX_PENDING_REQS; i++)
++              pending_ring[i] = i;
++
++      spin_lock_init(&net_schedule_list_lock);
++      INIT_LIST_HEAD(&net_schedule_list);
++
++      netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
++      if (MODPARM_copy_skb) {
++              if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
++                                            NULL, 0))
++                      netbk_copy_skb_mode = NETBK_ALWAYS_COPY_SKB;
++              else
++                      netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
++      }
++
++      netif_accel_init();
++
++      netif_xenbus_init();
++
++#ifdef NETBE_DEBUG_INTERRUPT
++      (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
++                                    0,
++                                    netif_be_dbg,
++                                    SA_SHIRQ, 
++                                    "net-be-dbg",
++                                    &netif_be_dbg);
++#endif
++
++      return 0;
++}
++
++module_init(netback_init);
++
++MODULE_LICENSE("Dual BSD/GPL");
+--- linux-2.6.18.8/drivers/xen/netback/xenbus.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/netback/xenbus.c   2008-05-19 00:33:45.846788782 +0300
+@@ -0,0 +1,452 @@
++/*  Xenbus code for netif backend
++    Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
++    Copyright (C) 2005 XenSource Ltd
++
++    This program is free software; you can redistribute it and/or modify
++    it under the terms of the GNU General Public License as published by
++    the Free Software Foundation; either version 2 of the License, or
++    (at your option) any later version.
++
++    This program is distributed in the hope that it will be useful,
++    but WITHOUT ANY WARRANTY; without even the implied warranty of
++    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++    GNU General Public License for more details.
++
++    You should have received a copy of the GNU General Public License
++    along with this program; if not, write to the Free Software
++    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++*/
++
++#include <stdarg.h>
++#include <linux/module.h>
++#include <xen/xenbus.h>
++#include "common.h"
++
++#if 0
++#undef DPRINTK
++#define DPRINTK(fmt, args...) \
++    printk("netback/xenbus (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
++#endif
++
++
++static int connect_rings(struct backend_info *);
++static void connect(struct backend_info *);
++static void backend_create_netif(struct backend_info *be);
++
++static int netback_remove(struct xenbus_device *dev)
++{
++      struct backend_info *be = dev->dev.driver_data;
++
++      netback_remove_accelerators(be, dev);
++
++      if (be->netif) {
++              netif_disconnect(be->netif);
++              be->netif = NULL;
++      }
++      kfree(be);
++      dev->dev.driver_data = NULL;
++      return 0;
++}
++
++
++/**
++ * Entry point to this code when a new device is created.  Allocate the basic
++ * structures and switch to InitWait.
++ */
++static int netback_probe(struct xenbus_device *dev,
++                       const struct xenbus_device_id *id)
++{
++      const char *message;
++      struct xenbus_transaction xbt;
++      int err;
++      int sg;
++      struct backend_info *be = kzalloc(sizeof(struct backend_info),
++                                        GFP_KERNEL);
++      if (!be) {
++              xenbus_dev_fatal(dev, -ENOMEM,
++                               "allocating backend structure");
++              return -ENOMEM;
++      }
++
++      be->dev = dev;
++      dev->dev.driver_data = be;
++
++      sg = 1;
++      if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
++              sg = 0;
++
++      do {
++              err = xenbus_transaction_start(&xbt);
++              if (err) {
++                      xenbus_dev_fatal(dev, err, "starting transaction");
++                      goto fail;
++              }
++
++              err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", sg);
++              if (err) {
++                      message = "writing feature-sg";
++                      goto abort_transaction;
++              }
++
++              err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
++                                  "%d", sg);
++              if (err) {
++                      message = "writing feature-gso-tcpv4";
++                      goto abort_transaction;
++              }
++
++              /* We support rx-copy path. */
++              err = xenbus_printf(xbt, dev->nodename,
++                                  "feature-rx-copy", "%d", 1);
++              if (err) {
++                      message = "writing feature-rx-copy";
++                      goto abort_transaction;
++              }
++
++              /*
++               * We don't support rx-flip path (except old guests who don't
++               * grok this feature flag).
++               */
++              err = xenbus_printf(xbt, dev->nodename,
++                                  "feature-rx-flip", "%d", 0);
++              if (err) {
++                      message = "writing feature-rx-flip";
++                      goto abort_transaction;
++              }
++
++              err = xenbus_transaction_end(xbt, 0);
++      } while (err == -EAGAIN);
++
++      if (err) {
++              xenbus_dev_fatal(dev, err, "completing transaction");
++              goto fail;
++      }
++
++      netback_probe_accelerators(be, dev);
++
++      err = xenbus_switch_state(dev, XenbusStateInitWait);
++      if (err)
++              goto fail;
++
++      /* This kicks hotplug scripts, so do it immediately. */
++      backend_create_netif(be);
++
++      return 0;
++
++abort_transaction:
++      xenbus_transaction_end(xbt, 1);
++      xenbus_dev_fatal(dev, err, "%s", message);
++fail:
++      DPRINTK("failed");
++      netback_remove(dev);
++      return err;
++}
++
++
++/**
++ * Handle the creation of the hotplug script environment.  We add the script
++ * and vif variables to the environment, for the benefit of the vif-* hotplug
++ * scripts.
++ */
++static int netback_uevent(struct xenbus_device *xdev, char **envp,
++                        int num_envp, char *buffer, int buffer_size)
++{
++      struct backend_info *be = xdev->dev.driver_data;
++      netif_t *netif = be->netif;
++      int i = 0, length = 0;
++      char *val;
++
++      DPRINTK("netback_uevent");
++
++      val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
++      if (IS_ERR(val)) {
++              int err = PTR_ERR(val);
++              xenbus_dev_fatal(xdev, err, "reading script");
++              return err;
++      }
++      else {
++              add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
++                             &length, "script=%s", val);
++              kfree(val);
++      }
++
++      add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++                     "vif=%s", netif->dev->name);
++
++      envp[i] = NULL;
++
++      return 0;
++}
++
++
++static void backend_create_netif(struct backend_info *be)
++{
++      int err;
++      long handle;
++      struct xenbus_device *dev = be->dev;
++
++      if (be->netif != NULL)
++              return;
++
++      err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle);
++      if (err != 1) {
++              xenbus_dev_fatal(dev, err, "reading handle");
++              return;
++      }
++
++      be->netif = netif_alloc(dev->otherend_id, handle);
++      if (IS_ERR(be->netif)) {
++              err = PTR_ERR(be->netif);
++              be->netif = NULL;
++              xenbus_dev_fatal(dev, err, "creating interface");
++              return;
++      }
++
++      kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
++}
++
++
++/**
++ * Callback received when the frontend's state changes.
++ */
++static void frontend_changed(struct xenbus_device *dev,
++                           enum xenbus_state frontend_state)
++{
++      struct backend_info *be = dev->dev.driver_data;
++
++      DPRINTK("%s", xenbus_strstate(frontend_state));
++
++      be->frontend_state = frontend_state;
++
++      switch (frontend_state) {
++      case XenbusStateInitialising:
++              if (dev->state == XenbusStateClosed) {
++                      printk(KERN_INFO "%s: %s: prepare for reconnect\n",
++                             __FUNCTION__, dev->nodename);
++                      xenbus_switch_state(dev, XenbusStateInitWait);
++              }
++              break;
++
++      case XenbusStateInitialised:
++              break;
++
++      case XenbusStateConnected:
++              backend_create_netif(be);
++              if (be->netif)
++                      connect(be);
++              break;
++
++      case XenbusStateClosing:
++              if (be->netif) {
++                      netif_disconnect(be->netif);
++                      be->netif = NULL;
++              }
++              xenbus_switch_state(dev, XenbusStateClosing);
++              break;
++
++      case XenbusStateClosed:
++              xenbus_switch_state(dev, XenbusStateClosed);
++              if (xenbus_dev_is_online(dev))
++                      break;
++              /* fall through if not online */
++      case XenbusStateUnknown:
++              if (be->netif != NULL)
++                      kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
++              device_unregister(&dev->dev);
++              break;
++
++      default:
++              xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
++                               frontend_state);
++              break;
++      }
++}
++
++
++static void xen_net_read_rate(struct xenbus_device *dev,
++                            unsigned long *bytes, unsigned long *usec)
++{
++      char *s, *e;
++      unsigned long b, u;
++      char *ratestr;
++
++      /* Default to unlimited bandwidth. */
++      *bytes = ~0UL;
++      *usec = 0;
++
++      ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
++      if (IS_ERR(ratestr))
++              return;
++
++      s = ratestr;
++      b = simple_strtoul(s, &e, 10);
++      if ((s == e) || (*e != ','))
++              goto fail;
++
++      s = e + 1;
++      u = simple_strtoul(s, &e, 10);
++      if ((s == e) || (*e != '\0'))
++              goto fail;
++
++      *bytes = b;
++      *usec = u;
++
++      kfree(ratestr);
++      return;
++
++ fail:
++      WPRINTK("Failed to parse network rate limit. Traffic unlimited.\n");
++      kfree(ratestr);
++}
++
++static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
++{
++      char *s, *e, *macstr;
++      int i;
++
++      macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
++      if (IS_ERR(macstr))
++              return PTR_ERR(macstr);
++
++      for (i = 0; i < ETH_ALEN; i++) {
++              mac[i] = simple_strtoul(s, &e, 16);
++              if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
++                      kfree(macstr);
++                      return -ENOENT;
++              }
++              s = e+1;
++      }
++
++      kfree(macstr);
++      return 0;
++}
++
++static void connect(struct backend_info *be)
++{
++      int err;
++      struct xenbus_device *dev = be->dev;
++
++      err = connect_rings(be);
++      if (err)
++              return;
++
++      err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
++      if (err) {
++              xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
++              return;
++      }
++
++      xen_net_read_rate(dev, &be->netif->credit_bytes,
++                        &be->netif->credit_usec);
++      be->netif->remaining_credit = be->netif->credit_bytes;
++
++      xenbus_switch_state(dev, XenbusStateConnected);
++
++      netif_wake_queue(be->netif->dev);
++}
++
++
++static int connect_rings(struct backend_info *be)
++{
++      struct xenbus_device *dev = be->dev;
++      unsigned long tx_ring_ref, rx_ring_ref;
++      unsigned int evtchn, rx_copy;
++      int err;
++      int val;
++
++      DPRINTK("");
++
++      err = xenbus_gather(XBT_NIL, dev->otherend,
++                          "tx-ring-ref", "%lu", &tx_ring_ref,
++                          "rx-ring-ref", "%lu", &rx_ring_ref,
++                          "event-channel", "%u", &evtchn, NULL);
++      if (err) {
++              xenbus_dev_fatal(dev, err,
++                               "reading %s/ring-ref and event-channel",
++                               dev->otherend);
++              return err;
++      }
++
++      err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u",
++                         &rx_copy);
++      if (err == -ENOENT) {
++              err = 0;
++              rx_copy = 0;
++      }
++      if (err < 0) {
++              xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
++                               dev->otherend);
++              return err;
++      }
++      be->netif->copying_receiver = !!rx_copy;
++
++      if (be->netif->dev->tx_queue_len != 0) {
++              if (xenbus_scanf(XBT_NIL, dev->otherend,
++                               "feature-rx-notify", "%d", &val) < 0)
++                      val = 0;
++              if (val)
++                      be->netif->can_queue = 1;
++              else
++                      /* Must be non-zero for pfifo_fast to work. */
++                      be->netif->dev->tx_queue_len = 1;
++      }
++
++      if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d", &val) < 0)
++              val = 0;
++      if (val) {
++              be->netif->features |= NETIF_F_SG;
++              be->netif->dev->features |= NETIF_F_SG;
++      }
++
++      if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4", "%d",
++                       &val) < 0)
++              val = 0;
++      if (val) {
++              be->netif->features |= NETIF_F_TSO;
++              be->netif->dev->features |= NETIF_F_TSO;
++      }
++
++      if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
++                       "%d", &val) < 0)
++              val = 0;
++      if (val) {
++              be->netif->features &= ~NETIF_F_IP_CSUM;
++              be->netif->dev->features &= ~NETIF_F_IP_CSUM;
++      }
++
++      /* Map the shared frame, irq etc. */
++      err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn);
++      if (err) {
++              xenbus_dev_fatal(dev, err,
++                               "mapping shared-frames %lu/%lu port %u",
++                               tx_ring_ref, rx_ring_ref, evtchn);
++              return err;
++      }
++      return 0;
++}
++
++
++/* ** Driver Registration ** */
++
++
++static const struct xenbus_device_id netback_ids[] = {
++      { "vif" },
++      { "" }
++};
++
++
++static struct xenbus_driver netback = {
++      .name = "vif",
++      .owner = THIS_MODULE,
++      .ids = netback_ids,
++      .probe = netback_probe,
++      .remove = netback_remove,
++      .uevent = netback_uevent,
++      .otherend_changed = frontend_changed,
++};
++
++
++void netif_xenbus_init(void)
++{
++      xenbus_register_backend(&netback);
++}
+--- linux-2.6.18.8/drivers/xen/netfront/Makefile       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/netfront/Makefile  2008-05-19 00:33:45.846788782 +0300
+@@ -0,0 +1,4 @@
++
++obj-$(CONFIG_XEN_NETDEV_FRONTEND)     := xennet.o
++
++xennet-objs := netfront.o accel.o
+--- linux-2.6.18.8/drivers/xen/netfront/accel.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/netfront/accel.c   2008-05-19 00:33:45.850789013 +0300
+@@ -0,0 +1,823 @@
++/******************************************************************************
++ * Virtual network driver for conversing with remote driver backends.
++ *
++ * Copyright (C) 2007 Solarflare Communications, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/netdevice.h>
++#include <linux/skbuff.h>
++#include <linux/list.h>
++#include <linux/mutex.h>
++#include <asm/hypervisor.h>
++#include <xen/xenbus.h>
++
++#include "netfront.h"
++
++#define DPRINTK(fmt, args...)                         \
++      pr_debug("netfront/accel (%s:%d) " fmt,         \
++             __FUNCTION__, __LINE__, ##args)
++#define IPRINTK(fmt, args...)                         \
++      printk(KERN_INFO "netfront/accel: " fmt, ##args)
++#define WPRINTK(fmt, args...)                         \
++      printk(KERN_WARNING "netfront/accel: " fmt, ##args)
++
++static int netfront_remove_accelerator(struct netfront_info *np,
++                                     struct xenbus_device *dev);
++static int netfront_load_accelerator(struct netfront_info *np, 
++                                   struct xenbus_device *dev, 
++                                   const char *frontend);
++
++/*
++ * List of all netfront accelerator plugin modules available.  Each
++ * list entry is of type struct netfront_accelerator.
++ */ 
++static struct list_head accelerators_list;
++
++/* Lock to protect access to accelerators_list */
++static spinlock_t accelerators_lock;
++
++/* Workqueue to process acceleration configuration changes */
++struct workqueue_struct *accel_watch_workqueue;
++
++/* Mutex to prevent concurrent loads and suspends, etc. */
++DEFINE_MUTEX(accelerator_mutex);
++
++void netif_init_accel(void)
++{
++      INIT_LIST_HEAD(&accelerators_list);
++      spin_lock_init(&accelerators_lock);
++
++      accel_watch_workqueue = create_workqueue("net_accel");
++}
++
++void netif_exit_accel(void)
++{
++      struct netfront_accelerator *accelerator, *tmp;
++      unsigned long flags;
++
++      flush_workqueue(accel_watch_workqueue);
++      destroy_workqueue(accel_watch_workqueue);
++
++      spin_lock_irqsave(&accelerators_lock, flags);
++
++      list_for_each_entry_safe(accelerator, tmp, &accelerators_list, link) {
++              BUG_ON(!list_empty(&accelerator->vif_states));
++
++              list_del(&accelerator->link);
++              kfree(accelerator->frontend);
++              kfree(accelerator);
++      }
++
++      spin_unlock_irqrestore(&accelerators_lock, flags);
++}
++
++
++/* 
++ * Watch the configured accelerator and change plugin if it's modified 
++ */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++static void accel_watch_work(struct work_struct *context)
++#else
++static void accel_watch_work(void *context)
++#endif
++{
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++      struct netfront_accel_vif_state *vif_state = 
++              container_of(context, struct netfront_accel_vif_state, 
++                           accel_work);
++#else
++        struct netfront_accel_vif_state *vif_state = 
++              (struct netfront_accel_vif_state *)context;
++#endif
++      struct netfront_info *np = vif_state->np;
++      char *accel_frontend;
++      int accel_len, rc = -1;
++
++      mutex_lock(&accelerator_mutex);
++
++      accel_frontend = xenbus_read(XBT_NIL, np->xbdev->otherend, 
++                                   "accel-frontend", &accel_len);
++      if (IS_ERR(accel_frontend)) {
++              accel_frontend = NULL;
++              netfront_remove_accelerator(np, np->xbdev);
++      } else {
++              /* If this is the first time, request the accelerator,
++                 otherwise only request one if it has changed */
++              if (vif_state->accel_frontend == NULL) {
++                      rc = netfront_load_accelerator(np, np->xbdev, 
++                                                     accel_frontend);
++              } else {
++                      if (strncmp(vif_state->accel_frontend, accel_frontend,
++                                  accel_len)) {
++                              netfront_remove_accelerator(np, np->xbdev);
++                              rc = netfront_load_accelerator(np, np->xbdev, 
++                                                             accel_frontend);
++                      }
++              }
++      }
++
++      /* Get rid of previous state and replace with the new name */
++      if (vif_state->accel_frontend != NULL)
++              kfree(vif_state->accel_frontend);
++      vif_state->accel_frontend = accel_frontend;
++
++      mutex_unlock(&accelerator_mutex);
++
++      if (rc == 0) {
++              DPRINTK("requesting module %s\n", accel_frontend);
++              request_module("%s", accel_frontend);
++              /*
++               * Module should now call netfront_accelerator_loaded() once
++               * it's up and running, and we can continue from there 
++               */
++      }
++}
++
++
++static void accel_watch_changed(struct xenbus_watch *watch,
++                              const char **vec, unsigned int len)
++{
++      struct netfront_accel_vif_state *vif_state = 
++              container_of(watch, struct netfront_accel_vif_state,
++                           accel_watch);
++      queue_work(accel_watch_workqueue, &vif_state->accel_work);
++}
++
++
++void netfront_accelerator_add_watch(struct netfront_info *np)
++{
++      int err;
++      
++      /* Check we're not trying to overwrite an existing watch */
++      BUG_ON(np->accel_vif_state.accel_watch.node != NULL);
++
++      /* Get a watch on the accelerator plugin */
++      err = xenbus_watch_path2(np->xbdev, np->xbdev->otherend, 
++                               "accel-frontend", 
++                               &np->accel_vif_state.accel_watch,
++                               accel_watch_changed);
++      if (err) {
++              DPRINTK("%s: Failed to register accel watch: %d\n",
++                        __FUNCTION__, err);
++              np->accel_vif_state.accel_watch.node = NULL;
++        }
++}
++
++
++static
++void netfront_accelerator_remove_watch(struct netfront_info *np)
++{
++      struct netfront_accel_vif_state *vif_state = &np->accel_vif_state;
++
++      /* Get rid of watch on accelerator plugin */
++      if (vif_state->accel_watch.node != NULL) {
++              unregister_xenbus_watch(&vif_state->accel_watch);
++              kfree(vif_state->accel_watch.node);
++              vif_state->accel_watch.node = NULL;
++
++              flush_workqueue(accel_watch_workqueue);
++
++              /* Clean up any state left from watch */
++              if (vif_state->accel_frontend != NULL) {
++                      kfree(vif_state->accel_frontend);
++                      vif_state->accel_frontend = NULL;
++              }
++      }       
++}
++
++
++/* 
++ * Initialise the accel_vif_state field in the netfront state
++ */ 
++void init_accelerator_vif(struct netfront_info *np,
++                        struct xenbus_device *dev)
++{
++      np->accelerator = NULL;
++
++      /* It's assumed that these things don't change */
++      np->accel_vif_state.np = np;
++      np->accel_vif_state.dev = dev;
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++      INIT_WORK(&np->accel_vif_state.accel_work, accel_watch_work);
++#else
++      INIT_WORK(&np->accel_vif_state.accel_work, accel_watch_work, 
++                &np->accel_vif_state);
++#endif
++}
++
++
++/*
++ * Compare a frontend description string against an accelerator to see
++ * if they match.  Would ultimately be nice to replace the string with
++ * a unique numeric identifier for each accelerator.
++ */
++static int match_accelerator(const char *frontend, 
++                           struct netfront_accelerator *accelerator)
++{
++      return strcmp(frontend, accelerator->frontend) == 0;
++}
++
++
++/* 
++ * Add a frontend vif to the list of vifs that is using a netfront
++ * accelerator plugin module.
++ */
++static void add_accelerator_vif(struct netfront_accelerator *accelerator,
++                              struct netfront_info *np)
++{
++      unsigned long flags;
++
++      /* Need lock to write list */
++      spin_lock_irqsave(&accelerator->vif_states_lock, flags);
++
++      if (np->accelerator == NULL) {
++              np->accelerator = accelerator;
++              
++              list_add(&np->accel_vif_state.link, &accelerator->vif_states);
++      } else {
++              /* 
++               * May get here legitimately if suspend_cancel is
++               * called, but in that case configuration should not
++               * have changed
++               */
++              BUG_ON(np->accelerator != accelerator);
++      }
++
++      spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
++}
++
++
++/*
++ * Initialise the state to track an accelerator plugin module.
++ */ 
++static int init_accelerator(const char *frontend, 
++                          struct netfront_accelerator **result,
++                          struct netfront_accel_hooks *hooks)
++{
++      struct netfront_accelerator *accelerator = 
++              kmalloc(sizeof(struct netfront_accelerator), GFP_KERNEL);
++      unsigned long flags;
++      int frontend_len;
++
++      if (!accelerator) {
++              DPRINTK("no memory for accelerator\n");
++              return -ENOMEM;
++      }
++
++      frontend_len = strlen(frontend) + 1;
++      accelerator->frontend = kmalloc(frontend_len, GFP_KERNEL);
++      if (!accelerator->frontend) {
++              DPRINTK("no memory for accelerator\n");
++              kfree(accelerator);
++              return -ENOMEM;
++      }
++      strlcpy(accelerator->frontend, frontend, frontend_len);
++      
++      INIT_LIST_HEAD(&accelerator->vif_states);
++      spin_lock_init(&accelerator->vif_states_lock);
++
++      accelerator->hooks = hooks;
++
++      spin_lock_irqsave(&accelerators_lock, flags);
++      list_add(&accelerator->link, &accelerators_list);
++      spin_unlock_irqrestore(&accelerators_lock, flags);
++
++      *result = accelerator;
++
++      return 0;
++}                                     
++
++
++/* 
++ * Modify the hooks stored in the per-vif state to match that in the
++ * netfront accelerator's state.
++ */
++static void 
++accelerator_set_vif_state_hooks(struct netfront_accel_vif_state *vif_state)
++{
++      /* This function must be called with the vif_states_lock held */
++
++      DPRINTK("%p\n",vif_state);
++
++      /* Make sure there are no data path operations going on */
++      netif_poll_disable(vif_state->np->netdev);
++      netif_tx_lock_bh(vif_state->np->netdev);
++
++      vif_state->hooks = vif_state->np->accelerator->hooks;
++
++      netif_tx_unlock_bh(vif_state->np->netdev);
++      netif_poll_enable(vif_state->np->netdev);
++}
++
++
++static void accelerator_probe_new_vif(struct netfront_info *np,
++                                    struct xenbus_device *dev, 
++                                    struct netfront_accelerator *accelerator)
++{
++      struct netfront_accel_hooks *hooks;
++      unsigned long flags;
++
++      DPRINTK("\n");
++
++      /* Include this frontend device on the accelerator's list */
++      add_accelerator_vif(accelerator, np);
++      
++      hooks = accelerator->hooks;
++      
++      if (hooks) {
++              if (hooks->new_device(np->netdev, dev) == 0) {
++                      spin_lock_irqsave
++                              (&accelerator->vif_states_lock, flags);
++
++                      accelerator_set_vif_state_hooks(&np->accel_vif_state);
++
++                      spin_unlock_irqrestore
++                              (&accelerator->vif_states_lock, flags);
++              }
++      }
++
++      return;
++}
++
++
++/*  
++ * Request that a particular netfront accelerator plugin is loaded.
++ * Usually called as a result of the vif configuration specifying
++ * which one to use. Must be called with accelerator_mutex held 
++ */
++static int netfront_load_accelerator(struct netfront_info *np, 
++                                   struct xenbus_device *dev, 
++                                   const char *frontend)
++{
++      struct netfront_accelerator *accelerator;
++      int rc = 0;
++
++      DPRINTK(" %s\n", frontend);
++
++      /* 
++       * Look at list of loaded accelerators to see if the requested
++       * one is already there 
++       */
++      list_for_each_entry(accelerator, &accelerators_list, link) {
++              if (match_accelerator(frontend, accelerator)) {
++                      accelerator_probe_new_vif(np, dev, accelerator);
++                      return 0;
++              }
++      }
++
++      /* Couldn't find it, so create a new one and load the module */
++      if ((rc = init_accelerator(frontend, &accelerator, NULL)) < 0) {
++              return rc;
++      }
++
++      /* Include this frontend device on the accelerator's list */
++      add_accelerator_vif(accelerator, np);
++
++      return rc;
++}
++
++
++/*
++ * Go through all the netfront vifs and see if they have requested
++ * this accelerator.  Notify the accelerator plugin of the relevant
++ * device if so.  Called when an accelerator plugin module is first
++ * loaded and connects to netfront.
++ */
++static void 
++accelerator_probe_vifs(struct netfront_accelerator *accelerator,
++                     struct netfront_accel_hooks *hooks)
++{
++      struct netfront_accel_vif_state *vif_state, *tmp;
++      unsigned long flags;
++
++      DPRINTK("%p\n", accelerator);
++
++      /* 
++       * Store the hooks for future calls to probe a new device, and
++       * to wire into the vif_state once the accelerator plugin is
++       * ready to accelerate each vif
++       */
++      BUG_ON(hooks == NULL);
++      accelerator->hooks = hooks;
++
++      /* 
++       *  currently hold accelerator_mutex, so don't need
++       *  vif_states_lock to read the list
++       */
++      list_for_each_entry_safe(vif_state, tmp, &accelerator->vif_states,
++                               link) {
++              struct netfront_info *np = vif_state->np;
++              
++              if (hooks->new_device(np->netdev, vif_state->dev) == 0) {
++                      spin_lock_irqsave
++                              (&accelerator->vif_states_lock, flags);
++
++                      accelerator_set_vif_state_hooks(vif_state);
++
++                      spin_unlock_irqrestore
++                              (&accelerator->vif_states_lock, flags);
++              }
++      }
++}
++
++
++/* 
++ * Called by the netfront accelerator plugin module when it has loaded 
++ */
++int netfront_accelerator_loaded(int version, const char *frontend, 
++                              struct netfront_accel_hooks *hooks)
++{
++      struct netfront_accelerator *accelerator;
++
++      if (is_initial_xendomain())
++              return -EINVAL;
++
++      if (version != NETFRONT_ACCEL_VERSION) {
++              if (version > NETFRONT_ACCEL_VERSION) {
++                      /* Caller has higher version number, leave it
++                         up to them to decide whether to continue.
++                         They can re-call with a lower number if
++                         they're happy to be compatible with us */
++                      return NETFRONT_ACCEL_VERSION;
++              } else {
++                      /* We have a more recent version than caller.
++                         Currently reject, but may in future be able
++                         to be backwardly compatible */
++                      return -EPROTO;
++              }
++      }
++
++      mutex_lock(&accelerator_mutex);
++
++      /* 
++       * Look through list of accelerators to see if it has already
++       * been requested
++       */
++      list_for_each_entry(accelerator, &accelerators_list, link) {
++              if (match_accelerator(frontend, accelerator)) {
++                      accelerator_probe_vifs(accelerator, hooks);
++                      goto out;
++              }
++      }
++
++      /*
++       * If it wasn't in the list, add it now so that when it is
++       * requested the caller will find it
++       */
++      DPRINTK("Couldn't find matching accelerator (%s)\n",
++              frontend);
++
++      init_accelerator(frontend, &accelerator, hooks);
++
++ out:
++      mutex_unlock(&accelerator_mutex);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(netfront_accelerator_loaded);
++
++
++/* 
++ * Remove the hooks from a single vif state.
++ */
++static void 
++accelerator_remove_single_hook(struct netfront_accelerator *accelerator,
++                             struct netfront_accel_vif_state *vif_state)
++{
++      /* Make sure there are no data path operations going on */
++      netif_poll_disable(vif_state->np->netdev);
++      netif_tx_lock_bh(vif_state->np->netdev);
++
++      /* 
++       * Remove the hooks, but leave the vif_state on the
++       * accelerator's list as that signifies this vif is
++       * interested in using that accelerator if it becomes
++       * available again
++       */
++      vif_state->hooks = NULL;
++      
++      netif_tx_unlock_bh(vif_state->np->netdev);
++      netif_poll_enable(vif_state->np->netdev);                      
++}
++
++
++/* 
++ * Safely remove the accelerator function hooks from a netfront state.
++ */
++static void accelerator_remove_hooks(struct netfront_accelerator *accelerator)
++{
++      struct netfront_accel_hooks *hooks;
++      struct netfront_accel_vif_state *vif_state, *tmp;
++      unsigned long flags;
++
++      /* Mutex is held so don't need vif_states_lock to iterate list */
++      list_for_each_entry_safe(vif_state, tmp,
++                               &accelerator->vif_states,
++                               link) {
++              spin_lock_irqsave(&accelerator->vif_states_lock, flags);
++
++              if(vif_state->hooks) {
++                      hooks = vif_state->hooks;
++                      
++                      /* Last chance to get statistics from the accelerator */
++                      hooks->get_stats(vif_state->np->netdev,
++                                       &vif_state->np->stats);
++
++                      spin_unlock_irqrestore(&accelerator->vif_states_lock,
++                                             flags);
++
++                      accelerator_remove_single_hook(accelerator, vif_state);
++
++                      accelerator->hooks->remove(vif_state->dev);
++              } else {
++                      spin_unlock_irqrestore(&accelerator->vif_states_lock,
++                                             flags);
++              }
++      }
++      
++      accelerator->hooks = NULL;
++}
++
++
++/* 
++ * Called by a netfront accelerator when it is unloaded.  This safely
++ * removes the hooks into the plugin and blocks until all devices have
++ * finished using it, so on return it is safe to unload.
++ */
++void netfront_accelerator_stop(const char *frontend)
++{
++      struct netfront_accelerator *accelerator;
++      unsigned long flags;
++
++      mutex_lock(&accelerator_mutex);
++      spin_lock_irqsave(&accelerators_lock, flags);
++
++      list_for_each_entry(accelerator, &accelerators_list, link) {
++              if (match_accelerator(frontend, accelerator)) {
++                      spin_unlock_irqrestore(&accelerators_lock, flags);
++
++                      accelerator_remove_hooks(accelerator);
++
++                      goto out;
++              }
++      }
++      spin_unlock_irqrestore(&accelerators_lock, flags);
++ out:
++      mutex_unlock(&accelerator_mutex);
++}
++EXPORT_SYMBOL_GPL(netfront_accelerator_stop);
++
++
++/* Helper for call_remove and do_suspend */
++static int do_remove(struct netfront_info *np, struct xenbus_device *dev,
++                   unsigned long *lock_flags)
++{
++      struct netfront_accelerator *accelerator = np->accelerator;
++      struct netfront_accel_hooks *hooks;
++      int rc = 0;
++ 
++      if (np->accel_vif_state.hooks) {
++              hooks = np->accel_vif_state.hooks;
++
++              /* Last chance to get statistics from the accelerator */
++              hooks->get_stats(np->netdev, &np->stats);
++
++              spin_unlock_irqrestore(&accelerator->vif_states_lock, 
++                                     *lock_flags);
++
++              /* 
++               * Try and do the opposite of accelerator_probe_new_vif
++               * to ensure there's no state pointing back at the 
++               * netdev 
++               */
++              accelerator_remove_single_hook(accelerator, 
++                                             &np->accel_vif_state);
++
++              rc = accelerator->hooks->remove(dev);
++
++              spin_lock_irqsave(&accelerator->vif_states_lock, *lock_flags);
++      }
++ 
++      return rc;
++}
++
++
++static int netfront_remove_accelerator(struct netfront_info *np,
++                                     struct xenbus_device *dev)
++{
++      struct netfront_accelerator *accelerator;
++      struct netfront_accel_vif_state *tmp_vif_state;
++      unsigned long flags;
++      int rc = 0; 
++
++      /* Check that we've got a device that was accelerated */
++      if (np->accelerator == NULL)
++              return rc;
++
++      accelerator = np->accelerator;
++
++      spin_lock_irqsave(&accelerator->vif_states_lock, flags); 
++
++      list_for_each_entry(tmp_vif_state, &accelerator->vif_states,
++                          link) {
++              if (tmp_vif_state == &np->accel_vif_state) {
++                      list_del(&np->accel_vif_state.link);
++                      break;
++              }
++      }
++
++      rc = do_remove(np, dev, &flags);
++
++      np->accelerator = NULL;
++
++      spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); 
++
++      return rc;
++}
++
++
++int netfront_accelerator_call_remove(struct netfront_info *np,
++                                   struct xenbus_device *dev)
++{
++      int rc;
++      netfront_accelerator_remove_watch(np);
++      mutex_lock(&accelerator_mutex);
++      rc = netfront_remove_accelerator(np, dev);
++      mutex_unlock(&accelerator_mutex);
++      return rc;
++}
++
++  
++int netfront_accelerator_suspend(struct netfront_info *np,
++                               struct xenbus_device *dev)
++{
++      unsigned long flags;
++      int rc = 0;
++      
++      netfront_accelerator_remove_watch(np);
++
++      mutex_lock(&accelerator_mutex);
++
++      /* Check that we've got a device that was accelerated */
++      if (np->accelerator == NULL)
++              goto out;
++
++      /* 
++       * Call the remove accelerator hook, but leave the vif_state
++       * on the accelerator's list in case there is a suspend_cancel.
++       */
++      spin_lock_irqsave(&np->accelerator->vif_states_lock, flags); 
++      
++      rc = do_remove(np, dev, &flags);
++
++      spin_unlock_irqrestore(&np->accelerator->vif_states_lock, flags); 
++ out:
++      mutex_unlock(&accelerator_mutex);
++      return rc;
++}
++  
++  
++int netfront_accelerator_suspend_cancel(struct netfront_info *np,
++                                      struct xenbus_device *dev)
++{
++      /* 
++       * Setting the watch will cause it to fire and probe the
++       * accelerator, so no need to call accelerator_probe_new_vif()
++       * directly here
++       */
++      netfront_accelerator_add_watch(np);
++      return 0;
++}
++ 
++ 
++void netfront_accelerator_resume(struct netfront_info *np,
++                               struct xenbus_device *dev)
++{
++      struct netfront_accel_vif_state *accel_vif_state = NULL;
++      spinlock_t *vif_states_lock;
++      unsigned long flags;
++ 
++      mutex_lock(&accelerator_mutex);
++
++      /* Check that we've got a device that was accelerated */
++      if(np->accelerator == NULL)
++              goto out;
++
++      /* Find the vif_state from the accelerator's list */
++      list_for_each_entry(accel_vif_state, &np->accelerator->vif_states, 
++                          link) {
++              if (accel_vif_state->dev == dev) {
++                      BUG_ON(accel_vif_state != &np->accel_vif_state);
++ 
++                      vif_states_lock = &np->accelerator->vif_states_lock;
++                      spin_lock_irqsave(vif_states_lock, flags); 
++ 
++                      /* 
++                       * Remove it from the accelerator's list so
++                       * state is consistent for probing new vifs
++                       * when they get connected
++                       */
++                      list_del(&accel_vif_state->link);
++                      np->accelerator = NULL;
++ 
++                      spin_unlock_irqrestore(vif_states_lock, flags); 
++                      
++                      break;
++              }
++      }
++
++ out:
++      mutex_unlock(&accelerator_mutex);
++      return;
++}
++
++
++int netfront_check_accelerator_queue_ready(struct net_device *dev,
++                                         struct netfront_info *np)
++{
++      struct netfront_accelerator *accelerator;
++      struct netfront_accel_hooks *hooks;
++      int rc = 1;
++      unsigned long flags;
++
++      accelerator = np->accelerator;
++
++      /* Call the check_ready accelerator hook. */ 
++      if (np->accel_vif_state.hooks && accelerator) {
++              spin_lock_irqsave(&accelerator->vif_states_lock, flags); 
++              hooks = np->accel_vif_state.hooks;
++              if (hooks && np->accelerator == accelerator)
++                      rc = np->accel_vif_state.hooks->check_ready(dev);
++              spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
++      }
++
++      return rc;
++}
++
++
++void netfront_accelerator_call_stop_napi_irq(struct netfront_info *np,
++                                           struct net_device *dev)
++{
++      struct netfront_accelerator *accelerator;
++      struct netfront_accel_hooks *hooks;
++      unsigned long flags;
++
++      accelerator = np->accelerator;
++
++      /* Call the stop_napi_interrupts accelerator hook. */
++      if (np->accel_vif_state.hooks && accelerator != NULL) {
++              spin_lock_irqsave(&accelerator->vif_states_lock, flags); 
++              hooks = np->accel_vif_state.hooks;
++              if (hooks && np->accelerator == accelerator)
++                      np->accel_vif_state.hooks->stop_napi_irq(dev);
++              spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
++      }
++}
++
++
++int netfront_accelerator_call_get_stats(struct netfront_info *np,
++                                      struct net_device *dev)
++{
++      struct netfront_accelerator *accelerator;
++      struct netfront_accel_hooks *hooks;
++      unsigned long flags;
++      int rc = 0;
++
++      accelerator = np->accelerator;
++
++      /* Call the get_stats accelerator hook. */
++      if (np->accel_vif_state.hooks && accelerator != NULL) {
++              spin_lock_irqsave(&accelerator->vif_states_lock, flags); 
++              hooks = np->accel_vif_state.hooks;
++              if (hooks && np->accelerator == accelerator)
++                      rc = np->accel_vif_state.hooks->get_stats(dev,
++                                                                &np->stats);
++              spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
++      }
++      return rc;
++}
++
+--- linux-2.6.18.8/drivers/xen/netfront/netfront.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/netfront/netfront.c        2008-05-19 00:33:45.878790627 +0300
+@@ -0,0 +1,2241 @@
++/******************************************************************************
++ * Virtual network driver for conversing with remote driver backends.
++ *
++ * Copyright (c) 2002-2005, K A Fraser
++ * Copyright (c) 2005, XenSource Ltd
++ * Copyright (C) 2007 Solarflare Communications, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/netdevice.h>
++#include <linux/inetdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/skbuff.h>
++#include <linux/init.h>
++#include <linux/bitops.h>
++#include <linux/ethtool.h>
++#include <linux/in.h>
++#include <linux/if_ether.h>
++#include <linux/io.h>
++#include <linux/moduleparam.h>
++#include <net/sock.h>
++#include <net/pkt_sched.h>
++#include <net/arp.h>
++#include <net/route.h>
++#include <asm/uaccess.h>
++#include <xen/evtchn.h>
++#include <xen/xenbus.h>
++#include <xen/interface/io/netif.h>
++#include <xen/interface/memory.h>
++#include <xen/balloon.h>
++#include <asm/page.h>
++#include <asm/maddr.h>
++#include <asm/uaccess.h>
++#include <xen/interface/grant_table.h>
++#include <xen/gnttab.h>
++
++struct netfront_cb {
++      struct page *page;
++      unsigned offset;
++};
++
++#define NETFRONT_SKB_CB(skb)  ((struct netfront_cb *)((skb)->cb))
++
++#include "netfront.h"
++
++/*
++ * Mutually-exclusive module options to select receive data path:
++ *  rx_copy : Packets are copied by network backend into local memory
++ *  rx_flip : Page containing packet data is transferred to our ownership
++ * For fully-virtualised guests there is no option - copying must be used.
++ * For paravirtualised guests, flipping is the default.
++ */
++#ifdef CONFIG_XEN
++static int MODPARM_rx_copy = 0;
++module_param_named(rx_copy, MODPARM_rx_copy, bool, 0);
++MODULE_PARM_DESC(rx_copy, "Copy packets from network card (rather than flip)");
++static int MODPARM_rx_flip = 0;
++module_param_named(rx_flip, MODPARM_rx_flip, bool, 0);
++MODULE_PARM_DESC(rx_flip, "Flip packets from network card (rather than copy)");
++#else
++static const int MODPARM_rx_copy = 1;
++static const int MODPARM_rx_flip = 0;
++#endif
++
++#define RX_COPY_THRESHOLD 256
++
++/* If we don't have GSO, fake things up so that we never try to use it. */
++#if defined(NETIF_F_GSO)
++#define HAVE_GSO                      1
++#define HAVE_TSO                      1 /* TSO is a subset of GSO */
++#define HAVE_CSUM_OFFLOAD             1
++static inline void dev_disable_gso_features(struct net_device *dev)
++{
++      /* Turn off all GSO bits except ROBUST. */
++      dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
++      dev->features |= NETIF_F_GSO_ROBUST;
++}
++#elif defined(NETIF_F_TSO)
++#define HAVE_GSO                     0
++#define HAVE_TSO                       1
++
++/* Some older kernels cannot cope with incorrect checksums,
++ * particularly in netfilter. I'm not sure there is 100% correlation
++ * with the presence of NETIF_F_TSO but it appears to be a good first
++ * approximiation.
++ */
++#define HAVE_CSUM_OFFLOAD              0
++
++#define gso_size tso_size
++#define gso_segs tso_segs
++static inline void dev_disable_gso_features(struct net_device *dev)
++{
++       /* Turn off all TSO bits. */
++       dev->features &= ~NETIF_F_TSO;
++}
++static inline int skb_is_gso(const struct sk_buff *skb)
++{
++        return skb_shinfo(skb)->tso_size;
++}
++static inline int skb_gso_ok(struct sk_buff *skb, int features)
++{
++        return (features & NETIF_F_TSO);
++}
++
++static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
++{
++        return skb_is_gso(skb) &&
++               (!skb_gso_ok(skb, dev->features) ||
++                unlikely(skb->ip_summed != CHECKSUM_HW));
++}
++#else
++#define HAVE_GSO                      0
++#define HAVE_TSO                      0
++#define HAVE_CSUM_OFFLOAD             0
++#define netif_needs_gso(dev, skb)     0
++#define dev_disable_gso_features(dev) ((void)0)
++#define ethtool_op_set_tso(dev, data) (-ENOSYS)
++#endif
++
++#define GRANT_INVALID_REF     0
++
++struct netfront_rx_info {
++      struct netif_rx_response rx;
++      struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
++};
++
++/*
++ * Implement our own carrier flag: the network stack's version causes delays
++ * when the carrier is re-enabled (in particular, dev_activate() may not
++ * immediately be called, which can cause packet loss).
++ */
++#define netfront_carrier_on(netif)    ((netif)->carrier = 1)
++#define netfront_carrier_off(netif)   ((netif)->carrier = 0)
++#define netfront_carrier_ok(netif)    ((netif)->carrier)
++
++/*
++ * Access macros for acquiring freeing slots in tx_skbs[].
++ */
++
++static inline void add_id_to_freelist(struct sk_buff **list, unsigned short id)
++{
++      list[id] = list[0];
++      list[0]  = (void *)(unsigned long)id;
++}
++
++static inline unsigned short get_id_from_freelist(struct sk_buff **list)
++{
++      unsigned int id = (unsigned int)(unsigned long)list[0];
++      list[0] = list[id];
++      return id;
++}
++
++static inline int xennet_rxidx(RING_IDX idx)
++{
++      return idx & (NET_RX_RING_SIZE - 1);
++}
++
++static inline struct sk_buff *xennet_get_rx_skb(struct netfront_info *np,
++                                              RING_IDX ri)
++{
++      int i = xennet_rxidx(ri);
++      struct sk_buff *skb = np->rx_skbs[i];
++      np->rx_skbs[i] = NULL;
++      return skb;
++}
++
++static inline grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
++                                          RING_IDX ri)
++{
++      int i = xennet_rxidx(ri);
++      grant_ref_t ref = np->grant_rx_ref[i];
++      np->grant_rx_ref[i] = GRANT_INVALID_REF;
++      return ref;
++}
++
++#define DPRINTK(fmt, args...)                         \
++      pr_debug("netfront (%s:%d) " fmt,               \
++               __FUNCTION__, __LINE__, ##args)
++#define IPRINTK(fmt, args...)                         \
++      printk(KERN_INFO "netfront: " fmt, ##args)
++#define WPRINTK(fmt, args...)                         \
++      printk(KERN_WARNING "netfront: " fmt, ##args)
++
++static int setup_device(struct xenbus_device *, struct netfront_info *);
++static struct net_device *create_netdev(struct xenbus_device *);
++
++static void end_access(int, void *);
++static void netif_disconnect_backend(struct netfront_info *);
++
++static int network_connect(struct net_device *);
++static void network_tx_buf_gc(struct net_device *);
++static void network_alloc_rx_buffers(struct net_device *);
++static void send_fake_arp(struct net_device *);
++
++static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs);
++
++#ifdef CONFIG_SYSFS
++static int xennet_sysfs_addif(struct net_device *netdev);
++static void xennet_sysfs_delif(struct net_device *netdev);
++#else /* !CONFIG_SYSFS */
++#define xennet_sysfs_addif(dev) (0)
++#define xennet_sysfs_delif(dev) do { } while(0)
++#endif
++
++static inline int xennet_can_sg(struct net_device *dev)
++{
++      return dev->features & NETIF_F_SG;
++}
++
++/**
++ * Entry point to this code when a new device is created.  Allocate the basic
++ * structures and the ring buffers for communication with the backend, and
++ * inform the backend of the appropriate details for those.
++ */
++static int __devinit netfront_probe(struct xenbus_device *dev,
++                                  const struct xenbus_device_id *id)
++{
++      int err;
++      struct net_device *netdev;
++      struct netfront_info *info;
++
++      netdev = create_netdev(dev);
++      if (IS_ERR(netdev)) {
++              err = PTR_ERR(netdev);
++              xenbus_dev_fatal(dev, err, "creating netdev");
++              return err;
++      }
++
++      info = netdev_priv(netdev);
++      dev->dev.driver_data = info;
++
++      err = register_netdev(info->netdev);
++      if (err) {
++              printk(KERN_WARNING "%s: register_netdev err=%d\n",
++                     __FUNCTION__, err);
++              goto fail;
++      }
++
++      err = xennet_sysfs_addif(info->netdev);
++      if (err) {
++              unregister_netdev(info->netdev);
++              printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
++                     __FUNCTION__, err);
++              goto fail;
++      }
++
++      return 0;
++
++ fail:
++      free_netdev(netdev);
++      dev->dev.driver_data = NULL;
++      return err;
++}
++
++static int __devexit netfront_remove(struct xenbus_device *dev)
++{
++      struct netfront_info *info = dev->dev.driver_data;
++
++      DPRINTK("%s\n", dev->nodename);
++
++      netfront_accelerator_call_remove(info, dev);
++
++      netif_disconnect_backend(info);
++
++      del_timer_sync(&info->rx_refill_timer);
++
++      xennet_sysfs_delif(info->netdev);
++
++      unregister_netdev(info->netdev);
++
++      free_netdev(info->netdev);
++
++      return 0;
++}
++
++
++static int netfront_suspend(struct xenbus_device *dev)
++{
++      struct netfront_info *info = dev->dev.driver_data;
++      return netfront_accelerator_suspend(info, dev);
++}
++
++
++static int netfront_suspend_cancel(struct xenbus_device *dev)
++{
++      struct netfront_info *info = dev->dev.driver_data;
++      return netfront_accelerator_suspend_cancel(info, dev);
++}
++
++
++/**
++ * We are reconnecting to the backend, due to a suspend/resume, or a backend
++ * driver restart.  We tear down our netif structure and recreate it, but
++ * leave the device-layer structures intact so that this is transparent to the
++ * rest of the kernel.
++ */
++static int netfront_resume(struct xenbus_device *dev)
++{
++      struct netfront_info *info = dev->dev.driver_data;
++
++      DPRINTK("%s\n", dev->nodename);
++
++      netfront_accelerator_resume(info, dev);
++
++      netif_disconnect_backend(info);
++      return 0;
++}
++
++static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
++{
++      char *s, *e, *macstr;
++      int i;
++
++      macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
++      if (IS_ERR(macstr))
++              return PTR_ERR(macstr);
++
++      for (i = 0; i < ETH_ALEN; i++) {
++              mac[i] = simple_strtoul(s, &e, 16);
++              if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
++                      kfree(macstr);
++                      return -ENOENT;
++              }
++              s = e+1;
++      }
++
++      kfree(macstr);
++      return 0;
++}
++
++/* Common code used when first setting up, and when resuming. */
++static int talk_to_backend(struct xenbus_device *dev,
++                         struct netfront_info *info)
++{
++      const char *message;
++      struct xenbus_transaction xbt;
++      int err;
++
++      /* Read mac only in the first setup. */
++      if (!is_valid_ether_addr(info->mac)) {
++              err = xen_net_read_mac(dev, info->mac);
++              if (err) {
++                      xenbus_dev_fatal(dev, err, "parsing %s/mac",
++                                       dev->nodename);
++                      goto out;
++              }
++      }
++
++      /* Create shared ring, alloc event channel. */
++      err = setup_device(dev, info);
++      if (err)
++              goto out;
++
++      /* This will load an accelerator if one is configured when the
++       * watch fires */
++      netfront_accelerator_add_watch(info);
++
++again:
++      err = xenbus_transaction_start(&xbt);
++      if (err) {
++              xenbus_dev_fatal(dev, err, "starting transaction");
++              goto destroy_ring;
++      }
++
++      err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref","%u",
++                          info->tx_ring_ref);
++      if (err) {
++              message = "writing tx ring-ref";
++              goto abort_transaction;
++      }
++      err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref","%u",
++                          info->rx_ring_ref);
++      if (err) {
++              message = "writing rx ring-ref";
++              goto abort_transaction;
++      }
++      err = xenbus_printf(xbt, dev->nodename,
++                          "event-channel", "%u",
++                          irq_to_evtchn_port(info->irq));
++      if (err) {
++              message = "writing event-channel";
++              goto abort_transaction;
++      }
++
++      err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",
++                          info->copying_receiver);
++      if (err) {
++              message = "writing request-rx-copy";
++              goto abort_transaction;
++      }
++
++      err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);
++      if (err) {
++              message = "writing feature-rx-notify";
++              goto abort_transaction;
++      }
++
++      err = xenbus_printf(xbt, dev->nodename, "feature-no-csum-offload",
++                          "%d", !HAVE_CSUM_OFFLOAD);
++      if (err) {
++              message = "writing feature-no-csum-offload";
++              goto abort_transaction;
++      }
++
++      err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
++      if (err) {
++              message = "writing feature-sg";
++              goto abort_transaction;
++      }
++
++      err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d",
++                          HAVE_TSO);
++      if (err) {
++              message = "writing feature-gso-tcpv4";
++              goto abort_transaction;
++      }
++
++      err = xenbus_transaction_end(xbt, 0);
++      if (err) {
++              if (err == -EAGAIN)
++                      goto again;
++              xenbus_dev_fatal(dev, err, "completing transaction");
++              goto destroy_ring;
++      }
++
++      return 0;
++
++ abort_transaction:
++      xenbus_transaction_end(xbt, 1);
++      xenbus_dev_fatal(dev, err, "%s", message);
++ destroy_ring:
++      netfront_accelerator_call_remove(info, dev);
++      netif_disconnect_backend(info);
++ out:
++      return err;
++}
++
++static int setup_device(struct xenbus_device *dev, struct netfront_info *info)
++{
++      struct netif_tx_sring *txs;
++      struct netif_rx_sring *rxs;
++      int err;
++      struct net_device *netdev = info->netdev;
++
++      info->tx_ring_ref = GRANT_INVALID_REF;
++      info->rx_ring_ref = GRANT_INVALID_REF;
++      info->rx.sring = NULL;
++      info->tx.sring = NULL;
++      info->irq = 0;
++
++      txs = (struct netif_tx_sring *)get_zeroed_page(GFP_KERNEL|__GFP_HIGH);
++      if (!txs) {
++              err = -ENOMEM;
++              xenbus_dev_fatal(dev, err, "allocating tx ring page");
++              goto fail;
++      }
++      SHARED_RING_INIT(txs);
++      FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
++
++      err = xenbus_grant_ring(dev, virt_to_mfn(txs));
++      if (err < 0) {
++              free_page((unsigned long)txs);
++              goto fail;
++      }
++      info->tx_ring_ref = err;
++
++      rxs = (struct netif_rx_sring *)get_zeroed_page(GFP_KERNEL|__GFP_HIGH);
++      if (!rxs) {
++              err = -ENOMEM;
++              xenbus_dev_fatal(dev, err, "allocating rx ring page");
++              goto fail;
++      }
++      SHARED_RING_INIT(rxs);
++      FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
++
++      err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
++      if (err < 0) {
++              free_page((unsigned long)rxs);
++              goto fail;
++      }
++      info->rx_ring_ref = err;
++
++      memcpy(netdev->dev_addr, info->mac, ETH_ALEN);
++
++      err = bind_listening_port_to_irqhandler(
++              dev->otherend_id, netif_int, SA_SAMPLE_RANDOM, netdev->name,
++              netdev);
++      if (err < 0)
++              goto fail;
++      info->irq = err;
++
++      return 0;
++
++ fail:
++      return err;
++}
++
++/**
++ * Callback received when the backend's state changes.
++ */
++static void backend_changed(struct xenbus_device *dev,
++                          enum xenbus_state backend_state)
++{
++      struct netfront_info *np = dev->dev.driver_data;
++      struct net_device *netdev = np->netdev;
++
++      DPRINTK("%s\n", xenbus_strstate(backend_state));
++
++      switch (backend_state) {
++      case XenbusStateInitialising:
++      case XenbusStateInitialised:
++      case XenbusStateConnected:
++      case XenbusStateReconfiguring:
++      case XenbusStateReconfigured:
++      case XenbusStateUnknown:
++      case XenbusStateClosed:
++              break;
++
++      case XenbusStateInitWait:
++              if (dev->state != XenbusStateInitialising)
++                      break;
++              if (network_connect(netdev) != 0)
++                      break;
++              xenbus_switch_state(dev, XenbusStateConnected);
++              send_fake_arp(netdev);
++              break;
++
++      case XenbusStateClosing:
++              xenbus_frontend_closed(dev);
++              break;
++      }
++}
++
++/** Send a packet on a net device to encourage switches to learn the
++ * MAC. We send a fake ARP request.
++ *
++ * @param dev device
++ * @return 0 on success, error code otherwise
++ */
++static void send_fake_arp(struct net_device *dev)
++{
++#ifdef CONFIG_INET
++      struct sk_buff *skb;
++      u32             src_ip, dst_ip;
++
++      dst_ip = INADDR_BROADCAST;
++      src_ip = inet_select_addr(dev, dst_ip, RT_SCOPE_LINK);
++
++      /* No IP? Then nothing to do. */
++      if (src_ip == 0)
++              return;
++
++      skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
++                       dst_ip, dev, src_ip,
++                       /*dst_hw*/ NULL, /*src_hw*/ NULL,
++                       /*target_hw*/ dev->dev_addr);
++      if (skb == NULL)
++              return;
++
++      dev_queue_xmit(skb);
++#endif
++}
++
++static inline int netfront_tx_slot_available(struct netfront_info *np)
++{
++      return ((np->tx.req_prod_pvt - np->tx.rsp_cons) <
++              (TX_MAX_TARGET - MAX_SKB_FRAGS - 2));
++}
++
++
++static inline void network_maybe_wake_tx(struct net_device *dev)
++{
++      struct netfront_info *np = netdev_priv(dev);
++
++      if (unlikely(netif_queue_stopped(dev)) &&
++          netfront_tx_slot_available(np) &&
++          likely(netif_running(dev)) &&
++          netfront_check_accelerator_queue_ready(dev, np))
++              netif_wake_queue(dev);
++}
++
++
++int netfront_check_queue_ready(struct net_device *dev)
++{
++      struct netfront_info *np = netdev_priv(dev);
++
++      return unlikely(netif_queue_stopped(dev)) &&
++              netfront_tx_slot_available(np) &&
++              likely(netif_running(dev));
++}
++EXPORT_SYMBOL(netfront_check_queue_ready);
++
++
++static int network_open(struct net_device *dev)
++{
++      struct netfront_info *np = netdev_priv(dev);
++
++      memset(&np->stats, 0, sizeof(np->stats));
++
++      spin_lock_bh(&np->rx_lock);
++      if (netfront_carrier_ok(np)) {
++              network_alloc_rx_buffers(dev);
++              np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
++              if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)){
++                      netfront_accelerator_call_stop_napi_irq(np, dev);
++
++                      netif_rx_schedule(dev);
++              }
++      }
++      spin_unlock_bh(&np->rx_lock);
++
++      network_maybe_wake_tx(dev);
++
++      return 0;
++}
++
++static void network_tx_buf_gc(struct net_device *dev)
++{
++      RING_IDX cons, prod;
++      unsigned short id;
++      struct netfront_info *np = netdev_priv(dev);
++      struct sk_buff *skb;
++
++      BUG_ON(!netfront_carrier_ok(np));
++
++      do {
++              prod = np->tx.sring->rsp_prod;
++              rmb(); /* Ensure we see responses up to 'rp'. */
++
++              for (cons = np->tx.rsp_cons; cons != prod; cons++) {
++                      struct netif_tx_response *txrsp;
++
++                      txrsp = RING_GET_RESPONSE(&np->tx, cons);
++                      if (txrsp->status == NETIF_RSP_NULL)
++                              continue;
++
++                      id  = txrsp->id;
++                      skb = np->tx_skbs[id];
++                      if (unlikely(gnttab_query_foreign_access(
++                              np->grant_tx_ref[id]) != 0)) {
++                              printk(KERN_ALERT "network_tx_buf_gc: warning "
++                                     "-- grant still in use by backend "
++                                     "domain.\n");
++                              BUG();
++                      }
++                      gnttab_end_foreign_access_ref(np->grant_tx_ref[id]);
++                      gnttab_release_grant_reference(
++                              &np->gref_tx_head, np->grant_tx_ref[id]);
++                      np->grant_tx_ref[id] = GRANT_INVALID_REF;
++                      add_id_to_freelist(np->tx_skbs, id);
++                      dev_kfree_skb_irq(skb);
++              }
++
++              np->tx.rsp_cons = prod;
++
++              /*
++               * Set a new event, then check for race with update of tx_cons.
++               * Note that it is essential to schedule a callback, no matter
++               * how few buffers are pending. Even if there is space in the
++               * transmit ring, higher layers may be blocked because too much
++               * data is outstanding: in such cases notification from Xen is
++               * likely to be the only kick that we'll get.
++               */
++              np->tx.sring->rsp_event =
++                      prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
++              mb();
++      } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
++
++      network_maybe_wake_tx(dev);
++}
++
++static void rx_refill_timeout(unsigned long data)
++{
++      struct net_device *dev = (struct net_device *)data;
++      struct netfront_info *np = netdev_priv(dev);
++
++      netfront_accelerator_call_stop_napi_irq(np, dev);
++
++      netif_rx_schedule(dev);
++}
++
++static void network_alloc_rx_buffers(struct net_device *dev)
++{
++      unsigned short id;
++      struct netfront_info *np = netdev_priv(dev);
++      struct sk_buff *skb;
++      struct page *page;
++      int i, batch_target, notify;
++      RING_IDX req_prod = np->rx.req_prod_pvt;
++      struct xen_memory_reservation reservation;
++      grant_ref_t ref;
++      unsigned long pfn;
++      void *vaddr;
++      int nr_flips;
++      netif_rx_request_t *req;
++
++      if (unlikely(!netfront_carrier_ok(np)))
++              return;
++
++      /*
++       * Allocate skbuffs greedily, even though we batch updates to the
++       * receive ring. This creates a less bursty demand on the memory
++       * allocator, so should reduce the chance of failed allocation requests
++       * both for ourself and for other kernel subsystems.
++       */
++      batch_target = np->rx_target - (req_prod - np->rx.rsp_cons);
++      for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) {
++              /*
++               * Allocate an skb and a page. Do not use __dev_alloc_skb as
++               * that will allocate page-sized buffers which is not
++               * necessary here.
++               * 16 bytes added as necessary headroom for netif_receive_skb.
++               */
++              skb = alloc_skb(RX_COPY_THRESHOLD + 16 + NET_IP_ALIGN,
++                              GFP_ATOMIC | __GFP_NOWARN);
++              if (unlikely(!skb))
++                      goto no_skb;
++
++              page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
++              if (!page) {
++                      kfree_skb(skb);
++no_skb:
++                      /* Any skbuffs queued for refill? Force them out. */
++                      if (i != 0)
++                              goto refill;
++                      /* Could not allocate any skbuffs. Try again later. */
++                      mod_timer(&np->rx_refill_timer,
++                                jiffies + (HZ/10));
++                      break;
++              }
++
++              skb_reserve(skb, 16 + NET_IP_ALIGN); /* mimic dev_alloc_skb() */
++              skb_shinfo(skb)->frags[0].page = page;
++              skb_shinfo(skb)->nr_frags = 1;
++              __skb_queue_tail(&np->rx_batch, skb);
++      }
++
++      /* Is the batch large enough to be worthwhile? */
++      if (i < (np->rx_target/2)) {
++              if (req_prod > np->rx.sring->req_prod)
++                      goto push;
++              return;
++      }
++
++      /* Adjust our fill target if we risked running out of buffers. */
++      if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) &&
++          ((np->rx_target *= 2) > np->rx_max_target))
++              np->rx_target = np->rx_max_target;
++
++ refill:
++      for (nr_flips = i = 0; ; i++) {
++              if ((skb = __skb_dequeue(&np->rx_batch)) == NULL)
++                      break;
++
++              skb->dev = dev;
++
++              id = xennet_rxidx(req_prod + i);
++
++              BUG_ON(np->rx_skbs[id]);
++              np->rx_skbs[id] = skb;
++
++              ref = gnttab_claim_grant_reference(&np->gref_rx_head);
++              BUG_ON((signed short)ref < 0);
++              np->grant_rx_ref[id] = ref;
++
++              pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
++              vaddr = page_address(skb_shinfo(skb)->frags[0].page);
++
++              req = RING_GET_REQUEST(&np->rx, req_prod + i);
++              if (!np->copying_receiver) {
++                      gnttab_grant_foreign_transfer_ref(ref,
++                                                        np->xbdev->otherend_id,
++                                                        pfn);
++                      np->rx_pfn_array[nr_flips] = pfn_to_mfn(pfn);
++                      if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++                              /* Remove this page before passing
++                               * back to Xen. */
++                              set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
++                              MULTI_update_va_mapping(np->rx_mcl+i,
++                                                      (unsigned long)vaddr,
++                                                      __pte(0), 0);
++                      }
++                      nr_flips++;
++              } else {
++                      gnttab_grant_foreign_access_ref(ref,
++                                                      np->xbdev->otherend_id,
++                                                      pfn_to_mfn(pfn),
++                                                      0);
++              }
++
++              req->id = id;
++              req->gref = ref;
++      }
++
++      if ( nr_flips != 0 ) {
++              /* Tell the ballon driver what is going on. */
++              balloon_update_driver_allowance(i);
++
++              set_xen_guest_handle(reservation.extent_start,
++                                   np->rx_pfn_array);
++              reservation.nr_extents   = nr_flips;
++              reservation.extent_order = 0;
++              reservation.address_bits = 0;
++              reservation.domid        = DOMID_SELF;
++
++              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++                      /* After all PTEs have been zapped, flush the TLB. */
++                      np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] =
++                              UVMF_TLB_FLUSH|UVMF_ALL;
++
++                      /* Give away a batch of pages. */
++                      np->rx_mcl[i].op = __HYPERVISOR_memory_op;
++                      np->rx_mcl[i].args[0] = XENMEM_decrease_reservation;
++                      np->rx_mcl[i].args[1] = (unsigned long)&reservation;
++
++                      /* Zap PTEs and give away pages in one big
++                       * multicall. */
++                      if (unlikely(HYPERVISOR_multicall(np->rx_mcl, i+1)))
++                              BUG();
++
++                      /* Check return status of HYPERVISOR_memory_op(). */
++                      if (unlikely(np->rx_mcl[i].result != i))
++                              panic("Unable to reduce memory reservation\n");
++                      while (i--)
++                              BUG_ON(np->rx_mcl[i].result);
++              } else {
++                      if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
++                                               &reservation) != i)
++                              panic("Unable to reduce memory reservation\n");
++              }
++      } else {
++              wmb();
++      }
++
++      /* Above is a suitable barrier to ensure backend will see requests. */
++      np->rx.req_prod_pvt = req_prod + i;
++ push:
++      RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
++      if (notify)
++              notify_remote_via_irq(np->irq);
++}
++
++static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
++                            struct netif_tx_request *tx)
++{
++      struct netfront_info *np = netdev_priv(dev);
++      char *data = skb->data;
++      unsigned long mfn;
++      RING_IDX prod = np->tx.req_prod_pvt;
++      int frags = skb_shinfo(skb)->nr_frags;
++      unsigned int offset = offset_in_page(data);
++      unsigned int len = skb_headlen(skb);
++      unsigned int id;
++      grant_ref_t ref;
++      int i;
++
++      while (len > PAGE_SIZE - offset) {
++              tx->size = PAGE_SIZE - offset;
++              tx->flags |= NETTXF_more_data;
++              len -= tx->size;
++              data += tx->size;
++              offset = 0;
++
++              id = get_id_from_freelist(np->tx_skbs);
++              np->tx_skbs[id] = skb_get(skb);
++              tx = RING_GET_REQUEST(&np->tx, prod++);
++              tx->id = id;
++              ref = gnttab_claim_grant_reference(&np->gref_tx_head);
++              BUG_ON((signed short)ref < 0);
++
++              mfn = virt_to_mfn(data);
++              gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
++                                              mfn, GTF_readonly);
++
++              tx->gref = np->grant_tx_ref[id] = ref;
++              tx->offset = offset;
++              tx->size = len;
++              tx->flags = 0;
++      }
++
++      for (i = 0; i < frags; i++) {
++              skb_frag_t *frag = skb_shinfo(skb)->frags + i;
++
++              tx->flags |= NETTXF_more_data;
++
++              id = get_id_from_freelist(np->tx_skbs);
++              np->tx_skbs[id] = skb_get(skb);
++              tx = RING_GET_REQUEST(&np->tx, prod++);
++              tx->id = id;
++              ref = gnttab_claim_grant_reference(&np->gref_tx_head);
++              BUG_ON((signed short)ref < 0);
++
++              mfn = pfn_to_mfn(page_to_pfn(frag->page));
++              gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
++                                              mfn, GTF_readonly);
++
++              tx->gref = np->grant_tx_ref[id] = ref;
++              tx->offset = frag->page_offset;
++              tx->size = frag->size;
++              tx->flags = 0;
++      }
++
++      np->tx.req_prod_pvt = prod;
++}
++
++static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
++{
++      unsigned short id;
++      struct netfront_info *np = netdev_priv(dev);
++      struct netif_tx_request *tx;
++      struct netif_extra_info *extra;
++      char *data = skb->data;
++      RING_IDX i;
++      grant_ref_t ref;
++      unsigned long mfn;
++      int notify;
++      int frags = skb_shinfo(skb)->nr_frags;
++      unsigned int offset = offset_in_page(data);
++      unsigned int len = skb_headlen(skb);
++
++      /* Check the fast path, if hooks are available */
++      if (np->accel_vif_state.hooks && 
++          np->accel_vif_state.hooks->start_xmit(skb, dev)) { 
++              /* Fast path has sent this packet */ 
++              return 0; 
++      } 
++
++      frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
++      if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
++              printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
++                     frags);
++              dump_stack();
++              goto drop;
++      }
++
++      spin_lock_irq(&np->tx_lock);
++
++      if (unlikely(!netfront_carrier_ok(np) ||
++                   (frags > 1 && !xennet_can_sg(dev)) ||
++                   netif_needs_gso(dev, skb))) {
++              spin_unlock_irq(&np->tx_lock);
++              goto drop;
++      }
++
++      i = np->tx.req_prod_pvt;
++
++      id = get_id_from_freelist(np->tx_skbs);
++      np->tx_skbs[id] = skb;
++
++      tx = RING_GET_REQUEST(&np->tx, i);
++
++      tx->id   = id;
++      ref = gnttab_claim_grant_reference(&np->gref_tx_head);
++      BUG_ON((signed short)ref < 0);
++      mfn = virt_to_mfn(data);
++      gnttab_grant_foreign_access_ref(
++              ref, np->xbdev->otherend_id, mfn, GTF_readonly);
++      tx->gref = np->grant_tx_ref[id] = ref;
++      tx->offset = offset;
++      tx->size = len;
++
++      tx->flags = 0;
++      extra = NULL;
++
++      if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
++              tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
++#ifdef CONFIG_XEN
++      if (skb->proto_data_valid) /* remote but checksummed? */
++              tx->flags |= NETTXF_data_validated;
++#endif
++
++#if HAVE_TSO
++      if (skb_shinfo(skb)->gso_size) {
++              struct netif_extra_info *gso = (struct netif_extra_info *)
++                      RING_GET_REQUEST(&np->tx, ++i);
++
++              if (extra)
++                      extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
++              else
++                      tx->flags |= NETTXF_extra_info;
++
++              gso->u.gso.size = skb_shinfo(skb)->gso_size;
++              gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
++              gso->u.gso.pad = 0;
++              gso->u.gso.features = 0;
++
++              gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
++              gso->flags = 0;
++              extra = gso;
++      }
++#endif
++
++      np->tx.req_prod_pvt = i + 1;
++
++      xennet_make_frags(skb, dev, tx);
++      tx->size = skb->len;
++
++      RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify);
++      if (notify)
++              notify_remote_via_irq(np->irq);
++
++      np->stats.tx_bytes += skb->len;
++      np->stats.tx_packets++;
++      dev->trans_start = jiffies;
++
++      /* Note: It is not safe to access skb after network_tx_buf_gc()! */
++      network_tx_buf_gc(dev);
++
++      if (!netfront_tx_slot_available(np))
++              netif_stop_queue(dev);
++
++      spin_unlock_irq(&np->tx_lock);
++
++      return 0;
++
++ drop:
++      np->stats.tx_dropped++;
++      dev_kfree_skb(skb);
++      return 0;
++}
++
++static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs)
++{
++      struct net_device *dev = dev_id;
++      struct netfront_info *np = netdev_priv(dev);
++      unsigned long flags;
++
++      spin_lock_irqsave(&np->tx_lock, flags);
++
++      if (likely(netfront_carrier_ok(np))) {
++              network_tx_buf_gc(dev);
++              /* Under tx_lock: protects access to rx shared-ring indexes. */
++              if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) {
++                      netfront_accelerator_call_stop_napi_irq(np, dev);
++
++                      netif_rx_schedule(dev);
++                      dev->last_rx = jiffies;
++              }
++      }
++
++      spin_unlock_irqrestore(&np->tx_lock, flags);
++
++      return IRQ_HANDLED;
++}
++
++static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb,
++                              grant_ref_t ref)
++{
++      int new = xennet_rxidx(np->rx.req_prod_pvt);
++
++      BUG_ON(np->rx_skbs[new]);
++      np->rx_skbs[new] = skb;
++      np->grant_rx_ref[new] = ref;
++      RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new;
++      RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref;
++      np->rx.req_prod_pvt++;
++}
++
++int xennet_get_extras(struct netfront_info *np,
++                    struct netif_extra_info *extras, RING_IDX rp)
++
++{
++      struct netif_extra_info *extra;
++      RING_IDX cons = np->rx.rsp_cons;
++      int err = 0;
++
++      do {
++              struct sk_buff *skb;
++              grant_ref_t ref;
++
++              if (unlikely(cons + 1 == rp)) {
++                      if (net_ratelimit())
++                              WPRINTK("Missing extra info\n");
++                      err = -EBADR;
++                      break;
++              }
++
++              extra = (struct netif_extra_info *)
++                      RING_GET_RESPONSE(&np->rx, ++cons);
++
++              if (unlikely(!extra->type ||
++                           extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
++                      if (net_ratelimit())
++                              WPRINTK("Invalid extra type: %d\n",
++                                      extra->type);
++                      err = -EINVAL;
++              } else {
++                      memcpy(&extras[extra->type - 1], extra,
++                             sizeof(*extra));
++              }
++
++              skb = xennet_get_rx_skb(np, cons);
++              ref = xennet_get_rx_ref(np, cons);
++              xennet_move_rx_slot(np, skb, ref);
++      } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
++
++      np->rx.rsp_cons = cons;
++      return err;
++}
++
++static int xennet_get_responses(struct netfront_info *np,
++                              struct netfront_rx_info *rinfo, RING_IDX rp,
++                              struct sk_buff_head *list,
++                              int *pages_flipped_p)
++{
++      int pages_flipped = *pages_flipped_p;
++      struct mmu_update *mmu;
++      struct multicall_entry *mcl;
++      struct netif_rx_response *rx = &rinfo->rx;
++      struct netif_extra_info *extras = rinfo->extras;
++      RING_IDX cons = np->rx.rsp_cons;
++      struct sk_buff *skb = xennet_get_rx_skb(np, cons);
++      grant_ref_t ref = xennet_get_rx_ref(np, cons);
++      int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
++      int frags = 1;
++      int err = 0;
++      unsigned long ret;
++
++      if (rx->flags & NETRXF_extra_info) {
++              err = xennet_get_extras(np, extras, rp);
++              cons = np->rx.rsp_cons;
++      }
++
++      for (;;) {
++              unsigned long mfn;
++
++              if (unlikely(rx->status < 0 ||
++                           rx->offset + rx->status > PAGE_SIZE)) {
++                      if (net_ratelimit())
++                              WPRINTK("rx->offset: %x, size: %u\n",
++                                      rx->offset, rx->status);
++                      xennet_move_rx_slot(np, skb, ref);
++                      err = -EINVAL;
++                      goto next;
++              }
++
++              /*
++               * This definitely indicates a bug, either in this driver or in
++               * the backend driver. In future this should flag the bad
++               * situation to the system controller to reboot the backed.
++               */
++              if (ref == GRANT_INVALID_REF) {
++                      if (net_ratelimit())
++                              WPRINTK("Bad rx response id %d.\n", rx->id);
++                      err = -EINVAL;
++                      goto next;
++              }
++
++              if (!np->copying_receiver) {
++                      /* Memory pressure, insufficient buffer
++                       * headroom, ... */
++                      if (!(mfn = gnttab_end_foreign_transfer_ref(ref))) {
++                              if (net_ratelimit())
++                                      WPRINTK("Unfulfilled rx req "
++                                              "(id=%d, st=%d).\n",
++                                              rx->id, rx->status);
++                              xennet_move_rx_slot(np, skb, ref);
++                              err = -ENOMEM;
++                              goto next;
++                      }
++
++                      if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++                              /* Remap the page. */
++                              struct page *page =
++                                      skb_shinfo(skb)->frags[0].page;
++                              unsigned long pfn = page_to_pfn(page);
++                              void *vaddr = page_address(page);
++
++                              mcl = np->rx_mcl + pages_flipped;
++                              mmu = np->rx_mmu + pages_flipped;
++
++                              MULTI_update_va_mapping(mcl,
++                                                      (unsigned long)vaddr,
++                                                      pfn_pte_ma(mfn,
++                                                                 PAGE_KERNEL),
++                                                      0);
++                              mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT)
++                                      | MMU_MACHPHYS_UPDATE;
++                              mmu->val = pfn;
++
++                              set_phys_to_machine(pfn, mfn);
++                      }
++                      pages_flipped++;
++              } else {
++                      ret = gnttab_end_foreign_access_ref(ref);
++                      BUG_ON(!ret);
++              }
++
++              gnttab_release_grant_reference(&np->gref_rx_head, ref);
++
++              __skb_queue_tail(list, skb);
++
++next:
++              if (!(rx->flags & NETRXF_more_data))
++                      break;
++
++              if (cons + frags == rp) {
++                      if (net_ratelimit())
++                              WPRINTK("Need more frags\n");
++                      err = -ENOENT;
++                      break;
++              }
++
++              rx = RING_GET_RESPONSE(&np->rx, cons + frags);
++              skb = xennet_get_rx_skb(np, cons + frags);
++              ref = xennet_get_rx_ref(np, cons + frags);
++              frags++;
++      }
++
++      if (unlikely(frags > max)) {
++              if (net_ratelimit())
++                      WPRINTK("Too many frags\n");
++              err = -E2BIG;
++      }
++
++      if (unlikely(err))
++              np->rx.rsp_cons = cons + frags;
++
++      *pages_flipped_p = pages_flipped;
++
++      return err;
++}
++
++static RING_IDX xennet_fill_frags(struct netfront_info *np,
++                                struct sk_buff *skb,
++                                struct sk_buff_head *list)
++{
++      struct skb_shared_info *shinfo = skb_shinfo(skb);
++      int nr_frags = shinfo->nr_frags;
++      RING_IDX cons = np->rx.rsp_cons;
++      skb_frag_t *frag = shinfo->frags + nr_frags;
++      struct sk_buff *nskb;
++
++      while ((nskb = __skb_dequeue(list))) {
++              struct netif_rx_response *rx =
++                      RING_GET_RESPONSE(&np->rx, ++cons);
++
++              frag->page = skb_shinfo(nskb)->frags[0].page;
++              frag->page_offset = rx->offset;
++              frag->size = rx->status;
++
++              skb->data_len += rx->status;
++
++              skb_shinfo(nskb)->nr_frags = 0;
++              kfree_skb(nskb);
++
++              frag++;
++              nr_frags++;
++      }
++
++      shinfo->nr_frags = nr_frags;
++      return cons;
++}
++
++static int xennet_set_skb_gso(struct sk_buff *skb,
++                            struct netif_extra_info *gso)
++{
++      if (!gso->u.gso.size) {
++              if (net_ratelimit())
++                      WPRINTK("GSO size must not be zero.\n");
++              return -EINVAL;
++      }
++
++      /* Currently only TCPv4 S.O. is supported. */
++      if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
++              if (net_ratelimit())
++                      WPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
++              return -EINVAL;
++      }
++
++#if HAVE_TSO
++      skb_shinfo(skb)->gso_size = gso->u.gso.size;
++#if HAVE_GSO
++      skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
++
++      /* Header must be checked, and gso_segs computed. */
++      skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
++#endif
++      skb_shinfo(skb)->gso_segs = 0;
++
++      return 0;
++#else
++      if (net_ratelimit())
++              WPRINTK("GSO unsupported by this kernel.\n");
++      return -EINVAL;
++#endif
++}
++
++static int netif_poll(struct net_device *dev, int *pbudget)
++{
++      struct netfront_info *np = netdev_priv(dev);
++      struct sk_buff *skb;
++      struct netfront_rx_info rinfo;
++      struct netif_rx_response *rx = &rinfo.rx;
++      struct netif_extra_info *extras = rinfo.extras;
++      RING_IDX i, rp;
++      struct multicall_entry *mcl;
++      int work_done, budget, more_to_do = 1, accel_more_to_do = 1;
++      struct sk_buff_head rxq;
++      struct sk_buff_head errq;
++      struct sk_buff_head tmpq;
++      unsigned long flags;
++      unsigned int len;
++      int pages_flipped = 0;
++      int err;
++
++      spin_lock(&np->rx_lock); /* no need for spin_lock_bh() in ->poll() */
++
++      if (unlikely(!netfront_carrier_ok(np))) {
++              spin_unlock(&np->rx_lock);
++              return 0;
++      }
++
++      skb_queue_head_init(&rxq);
++      skb_queue_head_init(&errq);
++      skb_queue_head_init(&tmpq);
++
++      if ((budget = *pbudget) > dev->quota)
++              budget = dev->quota;
++      rp = np->rx.sring->rsp_prod;
++      rmb(); /* Ensure we see queued responses up to 'rp'. */
++
++      i = np->rx.rsp_cons;
++      work_done = 0;
++      while ((i != rp) && (work_done < budget)) {
++              memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
++              memset(extras, 0, sizeof(rinfo.extras));
++
++              err = xennet_get_responses(np, &rinfo, rp, &tmpq,
++                                         &pages_flipped);
++
++              if (unlikely(err)) {
++err:  
++                      while ((skb = __skb_dequeue(&tmpq)))
++                              __skb_queue_tail(&errq, skb);
++                      np->stats.rx_errors++;
++                      i = np->rx.rsp_cons;
++                      continue;
++              }
++
++              skb = __skb_dequeue(&tmpq);
++
++              if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
++                      struct netif_extra_info *gso;
++                      gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
++
++                      if (unlikely(xennet_set_skb_gso(skb, gso))) {
++                              __skb_queue_head(&tmpq, skb);
++                              np->rx.rsp_cons += skb_queue_len(&tmpq);
++                              goto err;
++                      }
++              }
++
++              NETFRONT_SKB_CB(skb)->page = skb_shinfo(skb)->frags[0].page;
++              NETFRONT_SKB_CB(skb)->offset = rx->offset;
++
++              len = rx->status;
++              if (len > RX_COPY_THRESHOLD)
++                      len = RX_COPY_THRESHOLD;
++              skb_put(skb, len);
++
++              if (rx->status > len) {
++                      skb_shinfo(skb)->frags[0].page_offset =
++                              rx->offset + len;
++                      skb_shinfo(skb)->frags[0].size = rx->status - len;
++                      skb->data_len = rx->status - len;
++              } else {
++                      skb_shinfo(skb)->frags[0].page = NULL;
++                      skb_shinfo(skb)->nr_frags = 0;
++              }
++
++              i = xennet_fill_frags(np, skb, &tmpq);
++
++              /*
++               * Truesize must approximates the size of true data plus
++               * any supervisor overheads. Adding hypervisor overheads
++               * has been shown to significantly reduce achievable
++               * bandwidth with the default receive buffer size. It is
++               * therefore not wise to account for it here.
++               *
++               * After alloc_skb(RX_COPY_THRESHOLD), truesize is set to
++               * RX_COPY_THRESHOLD + the supervisor overheads. Here, we
++               * add the size of the data pulled in xennet_fill_frags().
++               *
++               * We also adjust for any unused space in the main data
++               * area by subtracting (RX_COPY_THRESHOLD - len). This is
++               * especially important with drivers which split incoming
++               * packets into header and data, using only 66 bytes of
++               * the main data area (see the e1000 driver for example.)
++               * On such systems, without this last adjustement, our
++               * achievable receive throughout using the standard receive
++               * buffer size was cut by 25%(!!!).
++               */
++              skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
++              skb->len += skb->data_len;
++
++              /*
++               * Old backends do not assert data_validated but we
++               * can infer it from csum_blank so test both flags.
++               */
++              if (rx->flags & (NETRXF_data_validated|NETRXF_csum_blank))
++                      skb->ip_summed = CHECKSUM_UNNECESSARY;
++              else
++                      skb->ip_summed = CHECKSUM_NONE;
++#ifdef CONFIG_XEN
++              skb->proto_data_valid = (skb->ip_summed != CHECKSUM_NONE);
++              skb->proto_csum_blank = !!(rx->flags & NETRXF_csum_blank);
++#endif
++              np->stats.rx_packets++;
++              np->stats.rx_bytes += skb->len;
++
++              __skb_queue_tail(&rxq, skb);
++
++              np->rx.rsp_cons = ++i;
++              work_done++;
++      }
++
++      if (pages_flipped) {
++              /* Some pages are no longer absent... */
++              balloon_update_driver_allowance(-pages_flipped);
++
++              /* Do all the remapping work and M2P updates. */
++              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++                      mcl = np->rx_mcl + pages_flipped;
++                      mcl->op = __HYPERVISOR_mmu_update;
++                      mcl->args[0] = (unsigned long)np->rx_mmu;
++                      mcl->args[1] = pages_flipped;
++                      mcl->args[2] = 0;
++                      mcl->args[3] = DOMID_SELF;
++                      err = HYPERVISOR_multicall_check(np->rx_mcl,
++                                                       pages_flipped + 1,
++                                                       NULL);
++                      BUG_ON(err);
++              }
++      }
++
++      while ((skb = __skb_dequeue(&errq)))
++              kfree_skb(skb);
++
++      while ((skb = __skb_dequeue(&rxq)) != NULL) {
++              struct page *page = NETFRONT_SKB_CB(skb)->page;
++              void *vaddr = page_address(page);
++              unsigned offset = NETFRONT_SKB_CB(skb)->offset;
++
++              memcpy(skb->data, vaddr + offset, skb_headlen(skb));
++
++              if (page != skb_shinfo(skb)->frags[0].page)
++                      __free_page(page);
++
++              /* Ethernet work: Delayed to here as it peeks the header. */
++              skb->protocol = eth_type_trans(skb, dev);
++
++              /* Pass it up. */
++              netif_receive_skb(skb);
++              dev->last_rx = jiffies;
++      }
++
++      /* If we get a callback with very few responses, reduce fill target. */
++      /* NB. Note exponential increase, linear decrease. */
++      if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) >
++           ((3*np->rx_target) / 4)) &&
++          (--np->rx_target < np->rx_min_target))
++              np->rx_target = np->rx_min_target;
++
++      network_alloc_rx_buffers(dev);
++
++      if (work_done < budget) {
++              /* there's some spare capacity, try the accelerated path */
++              int accel_budget = budget - work_done;
++              int accel_budget_start = accel_budget;
++
++              if (np->accel_vif_state.hooks) { 
++                      accel_more_to_do =  
++                              np->accel_vif_state.hooks->netdev_poll 
++                              (dev, &accel_budget); 
++                      work_done += (accel_budget_start - accel_budget); 
++              } else
++                      accel_more_to_do = 0;
++      }
++
++      *pbudget   -= work_done;
++      dev->quota -= work_done;
++
++      if (work_done < budget) {
++              local_irq_save(flags);
++
++              RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
++
++              if (!more_to_do && !accel_more_to_do && 
++                  np->accel_vif_state.hooks) {
++                      /* 
++                       *  Slow path has nothing more to do, see if
++                       *  fast path is likewise
++                       */
++                      accel_more_to_do = 
++                              np->accel_vif_state.hooks->start_napi_irq(dev);
++              }
++
++              if (!more_to_do && !accel_more_to_do)
++                      __netif_rx_complete(dev);
++
++              local_irq_restore(flags);
++      }
++
++      spin_unlock(&np->rx_lock);
++      
++      return more_to_do | accel_more_to_do;
++}
++
++static void netif_release_tx_bufs(struct netfront_info *np)
++{
++      struct sk_buff *skb;
++      int i;
++
++      for (i = 1; i <= NET_TX_RING_SIZE; i++) {
++              if ((unsigned long)np->tx_skbs[i] < PAGE_OFFSET)
++                      continue;
++
++              skb = np->tx_skbs[i];
++              gnttab_end_foreign_access_ref(np->grant_tx_ref[i]);
++              gnttab_release_grant_reference(
++                      &np->gref_tx_head, np->grant_tx_ref[i]);
++              np->grant_tx_ref[i] = GRANT_INVALID_REF;
++              add_id_to_freelist(np->tx_skbs, i);
++              dev_kfree_skb_irq(skb);
++      }
++}
++
++static void netif_release_rx_bufs_flip(struct netfront_info *np)
++{
++      struct mmu_update      *mmu = np->rx_mmu;
++      struct multicall_entry *mcl = np->rx_mcl;
++      struct sk_buff_head free_list;
++      struct sk_buff *skb;
++      unsigned long mfn;
++      int xfer = 0, noxfer = 0, unused = 0;
++      int id, ref, rc;
++
++      skb_queue_head_init(&free_list);
++
++      spin_lock_bh(&np->rx_lock);
++
++      for (id = 0; id < NET_RX_RING_SIZE; id++) {
++              if ((ref = np->grant_rx_ref[id]) == GRANT_INVALID_REF) {
++                      unused++;
++                      continue;
++              }
++
++              skb = np->rx_skbs[id];
++              mfn = gnttab_end_foreign_transfer_ref(ref);
++              gnttab_release_grant_reference(&np->gref_rx_head, ref);
++              np->grant_rx_ref[id] = GRANT_INVALID_REF;
++              add_id_to_freelist(np->rx_skbs, id);
++
++              if (0 == mfn) {
++                      struct page *page = skb_shinfo(skb)->frags[0].page;
++                      balloon_release_driver_page(page);
++                      skb_shinfo(skb)->nr_frags = 0;
++                      dev_kfree_skb(skb);
++                      noxfer++;
++                      continue;
++              }
++
++              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++                      /* Remap the page. */
++                      struct page *page = skb_shinfo(skb)->frags[0].page;
++                      unsigned long pfn = page_to_pfn(page);
++                      void *vaddr = page_address(page);
++
++                      MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
++                                              pfn_pte_ma(mfn, PAGE_KERNEL),
++                                              0);
++                      mcl++;
++                      mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT)
++                              | MMU_MACHPHYS_UPDATE;
++                      mmu->val = pfn;
++                      mmu++;
++
++                      set_phys_to_machine(pfn, mfn);
++              }
++              __skb_queue_tail(&free_list, skb);
++              xfer++;
++      }
++
++      DPRINTK("%s: %d xfer, %d noxfer, %d unused\n",
++              __FUNCTION__, xfer, noxfer, unused);
++
++      if (xfer) {
++              /* Some pages are no longer absent... */
++              balloon_update_driver_allowance(-xfer);
++
++              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++                      /* Do all the remapping work and M2P updates. */
++                      mcl->op = __HYPERVISOR_mmu_update;
++                      mcl->args[0] = (unsigned long)np->rx_mmu;
++                      mcl->args[1] = mmu - np->rx_mmu;
++                      mcl->args[2] = 0;
++                      mcl->args[3] = DOMID_SELF;
++                      mcl++;
++                      rc = HYPERVISOR_multicall_check(
++                              np->rx_mcl, mcl - np->rx_mcl, NULL);
++                      BUG_ON(rc);
++              }
++      }
++
++      while ((skb = __skb_dequeue(&free_list)) != NULL)
++              dev_kfree_skb(skb);
++
++      spin_unlock_bh(&np->rx_lock);
++}
++
++static void netif_release_rx_bufs_copy(struct netfront_info *np)
++{
++      struct sk_buff *skb;
++      int i, ref;
++      int busy = 0, inuse = 0;
++
++      spin_lock_bh(&np->rx_lock);
++
++      for (i = 0; i < NET_RX_RING_SIZE; i++) {
++              ref = np->grant_rx_ref[i];
++
++              if (ref == GRANT_INVALID_REF)
++                      continue;
++
++              inuse++;
++
++              skb = np->rx_skbs[i];
++
++              if (!gnttab_end_foreign_access_ref(ref))
++              {
++                      busy++;
++                      continue;
++              }
++
++              gnttab_release_grant_reference(&np->gref_rx_head, ref);
++              np->grant_rx_ref[i] = GRANT_INVALID_REF;
++              add_id_to_freelist(np->rx_skbs, i);
++
++              skb_shinfo(skb)->nr_frags = 0;
++              dev_kfree_skb(skb);
++      }
++
++      if (busy)
++              DPRINTK("%s: Unable to release %d of %d inuse grant references out of %ld total.\n",
++                      __FUNCTION__, busy, inuse, NET_RX_RING_SIZE);
++
++      spin_unlock_bh(&np->rx_lock);
++}
++
++static int network_close(struct net_device *dev)
++{
++      struct netfront_info *np = netdev_priv(dev);
++      netif_stop_queue(np->netdev);
++      return 0;
++}
++
++
++static struct net_device_stats *network_get_stats(struct net_device *dev)
++{
++      struct netfront_info *np = netdev_priv(dev);
++
++      netfront_accelerator_call_get_stats(np, dev);
++      return &np->stats;
++}
++
++static int xennet_set_mac_address(struct net_device *dev, void *p)
++{
++      struct netfront_info *np = netdev_priv(dev);
++      struct sockaddr *addr = p;
++
++      if (netif_running(dev))
++              return -EBUSY;
++
++      if (!is_valid_ether_addr(addr->sa_data))
++              return -EADDRNOTAVAIL;
++
++      memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
++      memcpy(np->mac, addr->sa_data, ETH_ALEN);
++
++      return 0;
++}
++
++static int xennet_change_mtu(struct net_device *dev, int mtu)
++{
++      int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
++
++      if (mtu > max)
++              return -EINVAL;
++      dev->mtu = mtu;
++      return 0;
++}
++
++static int xennet_set_sg(struct net_device *dev, u32 data)
++{
++      if (data) {
++              struct netfront_info *np = netdev_priv(dev);
++              int val;
++
++              if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",
++                               "%d", &val) < 0)
++                      val = 0;
++              if (!val)
++                      return -ENOSYS;
++      } else if (dev->mtu > ETH_DATA_LEN)
++              dev->mtu = ETH_DATA_LEN;
++
++      return ethtool_op_set_sg(dev, data);
++}
++
++static int xennet_set_tso(struct net_device *dev, u32 data)
++{
++      if (data) {
++              struct netfront_info *np = netdev_priv(dev);
++              int val;
++
++              if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
++                               "feature-gso-tcpv4", "%d", &val) < 0)
++                      val = 0;
++              if (!val)
++                      return -ENOSYS;
++      }
++
++      return ethtool_op_set_tso(dev, data);
++}
++
++static void xennet_set_features(struct net_device *dev)
++{
++      dev_disable_gso_features(dev);
++      xennet_set_sg(dev, 0);
++
++      /* We need checksum offload to enable scatter/gather and TSO. */
++      if (!(dev->features & NETIF_F_IP_CSUM))
++              return;
++
++      if (xennet_set_sg(dev, 1))
++              return;
++
++      /* Before 2.6.9 TSO seems to be unreliable so do not enable it
++       * on older kernels.
++       */
++      if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9))
++              xennet_set_tso(dev, 1);
++}
++
++static int network_connect(struct net_device *dev)
++{
++      struct netfront_info *np = netdev_priv(dev);
++      int i, requeue_idx, err;
++      struct sk_buff *skb;
++      grant_ref_t ref;
++      netif_rx_request_t *req;
++      unsigned int feature_rx_copy, feature_rx_flip;
++
++      err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
++                         "feature-rx-copy", "%u", &feature_rx_copy);
++      if (err != 1)
++              feature_rx_copy = 0;
++      err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
++                         "feature-rx-flip", "%u", &feature_rx_flip);
++      if (err != 1)
++              feature_rx_flip = 1;
++
++      /*
++       * Copy packets on receive path if:
++       *  (a) This was requested by user, and the backend supports it; or
++       *  (b) Flipping was requested, but this is unsupported by the backend.
++       */
++      np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) ||
++                              (MODPARM_rx_flip && !feature_rx_flip));
++
++      err = talk_to_backend(np->xbdev, np);
++      if (err)
++              return err;
++
++      xennet_set_features(dev);
++
++      DPRINTK("device %s has %sing receive path.\n",
++              dev->name, np->copying_receiver ? "copy" : "flipp");
++
++      spin_lock_bh(&np->rx_lock);
++      spin_lock_irq(&np->tx_lock);
++
++      /*
++       * Recovery procedure:
++       *  NB. Freelist index entries are always going to be less than
++       *  PAGE_OFFSET, whereas pointers to skbs will always be equal or
++       *  greater than PAGE_OFFSET: we use this property to distinguish
++       *  them.
++       */
++
++      /* Step 1: Discard all pending TX packet fragments. */
++      netif_release_tx_bufs(np);
++
++      /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
++      for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
++              if (!np->rx_skbs[i])
++                      continue;
++
++              skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i);
++              ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
++              req = RING_GET_REQUEST(&np->rx, requeue_idx);
++
++              if (!np->copying_receiver) {
++                      gnttab_grant_foreign_transfer_ref(
++                              ref, np->xbdev->otherend_id,
++                              page_to_pfn(skb_shinfo(skb)->frags->page));
++              } else {
++                      gnttab_grant_foreign_access_ref(
++                              ref, np->xbdev->otherend_id,
++                              pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
++                                                     frags->page)),
++                              0);
++              }
++              req->gref = ref;
++              req->id   = requeue_idx;
++
++              requeue_idx++;
++      }
++
++      np->rx.req_prod_pvt = requeue_idx;
++
++      /*
++       * Step 3: All public and private state should now be sane.  Get
++       * ready to start sending and receiving packets and give the driver
++       * domain a kick because we've probably just requeued some
++       * packets.
++       */
++      netfront_carrier_on(np);
++      notify_remote_via_irq(np->irq);
++      network_tx_buf_gc(dev);
++      network_alloc_rx_buffers(dev);
++
++      spin_unlock_irq(&np->tx_lock);
++      spin_unlock_bh(&np->rx_lock);
++
++      return 0;
++}
++
++static void netif_uninit(struct net_device *dev)
++{
++      struct netfront_info *np = netdev_priv(dev);
++      netif_release_tx_bufs(np);
++      if (np->copying_receiver)
++              netif_release_rx_bufs_copy(np);
++      else
++              netif_release_rx_bufs_flip(np);
++      gnttab_free_grant_references(np->gref_tx_head);
++      gnttab_free_grant_references(np->gref_rx_head);
++}
++
++static struct ethtool_ops network_ethtool_ops =
++{
++      .get_tx_csum = ethtool_op_get_tx_csum,
++      .set_tx_csum = ethtool_op_set_tx_csum,
++      .get_sg = ethtool_op_get_sg,
++      .set_sg = xennet_set_sg,
++#if HAVE_TSO
++      .get_tso = ethtool_op_get_tso,
++      .set_tso = xennet_set_tso,
++#endif
++      .get_link = ethtool_op_get_link,
++};
++
++#ifdef CONFIG_SYSFS
++static ssize_t show_rxbuf_min(struct class_device *cd, char *buf)
++{
++      struct net_device *netdev = container_of(cd, struct net_device,
++                                               class_dev);
++      struct netfront_info *info = netdev_priv(netdev);
++
++      return sprintf(buf, "%u\n", info->rx_min_target);
++}
++
++static ssize_t store_rxbuf_min(struct class_device *cd,
++                             const char *buf, size_t len)
++{
++      struct net_device *netdev = container_of(cd, struct net_device,
++                                               class_dev);
++      struct netfront_info *np = netdev_priv(netdev);
++      char *endp;
++      unsigned long target;
++
++      if (!capable(CAP_NET_ADMIN))
++              return -EPERM;
++
++      target = simple_strtoul(buf, &endp, 0);
++      if (endp == buf)
++              return -EBADMSG;
++
++      if (target < RX_MIN_TARGET)
++              target = RX_MIN_TARGET;
++      if (target > RX_MAX_TARGET)
++              target = RX_MAX_TARGET;
++
++      spin_lock_bh(&np->rx_lock);
++      if (target > np->rx_max_target)
++              np->rx_max_target = target;
++      np->rx_min_target = target;
++      if (target > np->rx_target)
++              np->rx_target = target;
++
++      network_alloc_rx_buffers(netdev);
++
++      spin_unlock_bh(&np->rx_lock);
++      return len;
++}
++
++static ssize_t show_rxbuf_max(struct class_device *cd, char *buf)
++{
++      struct net_device *netdev = container_of(cd, struct net_device,
++                                               class_dev);
++      struct netfront_info *info = netdev_priv(netdev);
++
++      return sprintf(buf, "%u\n", info->rx_max_target);
++}
++
++static ssize_t store_rxbuf_max(struct class_device *cd,
++                             const char *buf, size_t len)
++{
++      struct net_device *netdev = container_of(cd, struct net_device,
++                                               class_dev);
++      struct netfront_info *np = netdev_priv(netdev);
++      char *endp;
++      unsigned long target;
++
++      if (!capable(CAP_NET_ADMIN))
++              return -EPERM;
++
++      target = simple_strtoul(buf, &endp, 0);
++      if (endp == buf)
++              return -EBADMSG;
++
++      if (target < RX_MIN_TARGET)
++              target = RX_MIN_TARGET;
++      if (target > RX_MAX_TARGET)
++              target = RX_MAX_TARGET;
++
++      spin_lock_bh(&np->rx_lock);
++      if (target < np->rx_min_target)
++              np->rx_min_target = target;
++      np->rx_max_target = target;
++      if (target < np->rx_target)
++              np->rx_target = target;
++
++      network_alloc_rx_buffers(netdev);
++
++      spin_unlock_bh(&np->rx_lock);
++      return len;
++}
++
++static ssize_t show_rxbuf_cur(struct class_device *cd, char *buf)
++{
++      struct net_device *netdev = container_of(cd, struct net_device,
++                                               class_dev);
++      struct netfront_info *info = netdev_priv(netdev);
++
++      return sprintf(buf, "%u\n", info->rx_target);
++}
++
++static const struct class_device_attribute xennet_attrs[] = {
++      __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min),
++      __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max),
++      __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL),
++};
++
++static int xennet_sysfs_addif(struct net_device *netdev)
++{
++      int i;
++      int error = 0;
++
++      for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
++              error = class_device_create_file(&netdev->class_dev, 
++                                               &xennet_attrs[i]);
++              if (error)
++                      goto fail;
++      }
++      return 0;
++
++ fail:
++      while (--i >= 0)
++              class_device_remove_file(&netdev->class_dev,
++                                       &xennet_attrs[i]);
++      return error;
++}
++
++static void xennet_sysfs_delif(struct net_device *netdev)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
++              class_device_remove_file(&netdev->class_dev,
++                                       &xennet_attrs[i]);
++      }
++}
++
++#endif /* CONFIG_SYSFS */
++
++
++/*
++ * Nothing to do here. Virtual interface is point-to-point and the
++ * physical interface is probably promiscuous anyway.
++ */
++static void network_set_multicast_list(struct net_device *dev)
++{
++}
++
++static struct net_device * __devinit create_netdev(struct xenbus_device *dev)
++{
++      int i, err = 0;
++      struct net_device *netdev = NULL;
++      struct netfront_info *np = NULL;
++
++      netdev = alloc_etherdev(sizeof(struct netfront_info));
++      if (!netdev) {
++              printk(KERN_WARNING "%s> alloc_etherdev failed.\n",
++                     __FUNCTION__);
++              return ERR_PTR(-ENOMEM);
++      }
++
++      np                   = netdev_priv(netdev);
++      np->xbdev            = dev;
++
++      spin_lock_init(&np->tx_lock);
++      spin_lock_init(&np->rx_lock);
++
++      init_accelerator_vif(np, dev);
++
++      skb_queue_head_init(&np->rx_batch);
++      np->rx_target     = RX_DFL_MIN_TARGET;
++      np->rx_min_target = RX_DFL_MIN_TARGET;
++      np->rx_max_target = RX_MAX_TARGET;
++
++      init_timer(&np->rx_refill_timer);
++      np->rx_refill_timer.data = (unsigned long)netdev;
++      np->rx_refill_timer.function = rx_refill_timeout;
++
++      /* Initialise {tx,rx}_skbs as a free chain containing every entry. */
++      for (i = 0; i <= NET_TX_RING_SIZE; i++) {
++              np->tx_skbs[i] = (void *)((unsigned long) i+1);
++              np->grant_tx_ref[i] = GRANT_INVALID_REF;
++      }
++
++      for (i = 0; i < NET_RX_RING_SIZE; i++) {
++              np->rx_skbs[i] = NULL;
++              np->grant_rx_ref[i] = GRANT_INVALID_REF;
++      }
++
++      /* A grant for every tx ring slot */
++      if (gnttab_alloc_grant_references(TX_MAX_TARGET,
++                                        &np->gref_tx_head) < 0) {
++              printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n");
++              err = -ENOMEM;
++              goto exit;
++      }
++      /* A grant for every rx ring slot */
++      if (gnttab_alloc_grant_references(RX_MAX_TARGET,
++                                        &np->gref_rx_head) < 0) {
++              printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n");
++              err = -ENOMEM;
++              goto exit_free_tx;
++      }
++
++      netdev->open            = network_open;
++      netdev->hard_start_xmit = network_start_xmit;
++      netdev->stop            = network_close;
++      netdev->get_stats       = network_get_stats;
++      netdev->poll            = netif_poll;
++      netdev->set_multicast_list = network_set_multicast_list;
++      netdev->uninit          = netif_uninit;
++      netdev->set_mac_address = xennet_set_mac_address;
++      netdev->change_mtu      = xennet_change_mtu;
++      netdev->weight          = 64;
++      netdev->features        = NETIF_F_IP_CSUM;
++
++      SET_ETHTOOL_OPS(netdev, &network_ethtool_ops);
++      SET_MODULE_OWNER(netdev);
++      SET_NETDEV_DEV(netdev, &dev->dev);
++
++      np->netdev = netdev;
++
++      netfront_carrier_off(np);
++
++      return netdev;
++
++ exit_free_tx:
++      gnttab_free_grant_references(np->gref_tx_head);
++ exit:
++      free_netdev(netdev);
++      return ERR_PTR(err);
++}
++
++#ifdef CONFIG_INET
++/*
++ * We use this notifier to send out a fake ARP reply to reset switches and
++ * router ARP caches when an IP interface is brought up on a VIF.
++ */
++static int
++inetdev_notify(struct notifier_block *this, unsigned long event, void *ptr)
++{
++      struct in_ifaddr  *ifa = (struct in_ifaddr *)ptr;
++      struct net_device *dev = ifa->ifa_dev->dev;
++
++      /* UP event and is it one of our devices? */
++      if (event == NETDEV_UP && dev->open == network_open)
++              send_fake_arp(dev);
++
++      return NOTIFY_DONE;
++}
++
++static struct notifier_block notifier_inetdev = {
++      .notifier_call  = inetdev_notify,
++      .next           = NULL,
++      .priority       = 0
++};
++#endif
++
++
++static void netif_disconnect_backend(struct netfront_info *info)
++{
++      /* Stop old i/f to prevent errors whilst we rebuild the state. */
++      spin_lock_bh(&info->rx_lock);
++      spin_lock_irq(&info->tx_lock);
++      netfront_carrier_off(info);
++      spin_unlock_irq(&info->tx_lock);
++      spin_unlock_bh(&info->rx_lock);
++
++      if (info->irq)
++              unbind_from_irqhandler(info->irq, info->netdev);
++      info->irq = 0;
++
++      end_access(info->tx_ring_ref, info->tx.sring);
++      end_access(info->rx_ring_ref, info->rx.sring);
++      info->tx_ring_ref = GRANT_INVALID_REF;
++      info->rx_ring_ref = GRANT_INVALID_REF;
++      info->tx.sring = NULL;
++      info->rx.sring = NULL;
++}
++
++
++static void end_access(int ref, void *page)
++{
++      if (ref != GRANT_INVALID_REF)
++              gnttab_end_foreign_access(ref, (unsigned long)page);
++}
++
++
++/* ** Driver registration ** */
++
++
++static const struct xenbus_device_id netfront_ids[] = {
++      { "vif" },
++      { "" }
++};
++MODULE_ALIAS("xen:vif");
++
++
++static struct xenbus_driver netfront_driver = {
++      .name = "vif",
++      .owner = THIS_MODULE,
++      .ids = netfront_ids,
++      .probe = netfront_probe,
++      .remove = __devexit_p(netfront_remove),
++      .suspend = netfront_suspend,
++      .suspend_cancel = netfront_suspend_cancel,
++      .resume = netfront_resume,
++      .otherend_changed = backend_changed,
++};
++
++
++static int __init netif_init(void)
++{
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++#ifdef CONFIG_XEN
++      if (MODPARM_rx_flip && MODPARM_rx_copy) {
++              WPRINTK("Cannot specify both rx_copy and rx_flip.\n");
++              return -EINVAL;
++      }
++
++      if (!MODPARM_rx_flip && !MODPARM_rx_copy)
++              MODPARM_rx_flip = 1; /* Default is to flip. */
++#endif
++
++      netif_init_accel();
++
++      IPRINTK("Initialising virtual ethernet driver.\n");
++
++#ifdef CONFIG_INET
++      (void)register_inetaddr_notifier(&notifier_inetdev);
++#endif
++
++      return xenbus_register_frontend(&netfront_driver);
++}
++module_init(netif_init);
++
++
++static void __exit netif_exit(void)
++{
++#ifdef CONFIG_INET
++      unregister_inetaddr_notifier(&notifier_inetdev);
++#endif
++
++      netif_exit_accel();
++
++      return xenbus_unregister_driver(&netfront_driver);
++}
++module_exit(netif_exit);
++
++MODULE_LICENSE("Dual BSD/GPL");
+--- linux-2.6.18.8/drivers/xen/netfront/netfront.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/netfront/netfront.h        2008-05-19 00:33:45.878790627 +0300
+@@ -0,0 +1,274 @@
++/******************************************************************************
++ * Virtual network driver for conversing with remote driver backends.
++ *
++ * Copyright (c) 2002-2005, K A Fraser
++ * Copyright (c) 2005, XenSource Ltd
++ * Copyright (C) 2007 Solarflare Communications, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ *
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#ifndef NETFRONT_H
++#define NETFRONT_H
++
++#include <xen/interface/io/netif.h>
++#include <linux/netdevice.h>
++#include <linux/skbuff.h>
++#include <linux/list.h>
++
++#define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
++#define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
++
++#include <xen/xenbus.h>
++
++#ifdef HAVE_XEN_PLATFORM_COMPAT_H
++#include <xen/platform-compat.h>
++#endif
++
++/* 
++ * Function pointer table for hooks into a network acceleration
++ * plugin.  These are called at appropriate points from the netfront
++ * driver 
++ */
++struct netfront_accel_hooks {
++      /* 
++       * new_device: Accelerator hook to ask the plugin to support a
++       * new network interface
++       */
++      int (*new_device)(struct net_device *net_dev, struct xenbus_device *dev);
++      /*
++       * remove: Opposite of new_device
++       */
++      int (*remove)(struct xenbus_device *dev);
++      /*
++       * The net_device is being polled, check the accelerated
++       * hardware for any pending packets
++       */
++      int (*netdev_poll)(struct net_device *dev, int *pbudget);
++      /*
++       * start_xmit: Used to give the accelerated plugin the option
++       * of sending a packet.  Returns non-zero if has done so, or
++       * zero to decline and force the packet onto normal send
++       * path
++       */
++      int (*start_xmit)(struct sk_buff *skb, struct net_device *dev);
++      /* 
++       * start/stop_napi_interrupts Used by netfront to indicate
++       * when napi interrupts should be enabled or disabled 
++       */
++      int (*start_napi_irq)(struct net_device *dev);
++      void (*stop_napi_irq)(struct net_device *dev);
++      /* 
++       * Called before re-enabling the TX queue to check the fast
++       * path has slots too
++       */
++      int (*check_ready)(struct net_device *dev);
++      /*
++       * Get the fastpath network statistics
++       */
++      int (*get_stats)(struct net_device *dev,
++                       struct net_device_stats *stats);
++};
++
++
++/* Version of API/protocol for communication between netfront and
++   acceleration plugin supported */
++#define NETFRONT_ACCEL_VERSION 0x00010003
++
++/* 
++ * Per-netfront device state for the accelerator.  This is used to
++ * allow efficient per-netfront device access to the accelerator
++ * hooks 
++ */
++struct netfront_accel_vif_state {
++      struct list_head link;
++
++      struct xenbus_device *dev;
++      struct netfront_info *np;
++      struct netfront_accel_hooks *hooks;
++
++      /* Watch on the accelerator configuration value */
++      struct xenbus_watch accel_watch;
++      /* Work item to process change in accelerator */
++      struct work_struct accel_work;
++      /* The string from xenbus last time accel_watch fired */
++      char *accel_frontend;
++}; 
++
++/* 
++ * Per-accelerator state stored in netfront.  These form a list that
++ * is used to track which devices are accelerated by which plugins,
++ * and what plugins are available/have been requested 
++ */
++struct netfront_accelerator {
++      /* Used to make a list */
++      struct list_head link;
++      /* ID of the accelerator */
++      int id;
++      /*
++       * String describing the accelerator.  Currently this is the
++       * name of the accelerator module.  This is provided by the
++       * backend accelerator through xenstore 
++       */
++      char *frontend;
++      /* The hooks into the accelerator plugin module */
++      struct netfront_accel_hooks *hooks;
++
++      /* 
++       * List of per-netfront device state (struct
++       * netfront_accel_vif_state) for each netfront device that is
++       * using this accelerator
++       */
++      struct list_head vif_states;
++      spinlock_t vif_states_lock;
++};
++
++struct netfront_info {
++      struct list_head list;
++      struct net_device *netdev;
++
++      struct net_device_stats stats;
++
++      struct netif_tx_front_ring tx;
++      struct netif_rx_front_ring rx;
++
++      spinlock_t   tx_lock;
++      spinlock_t   rx_lock;
++
++      unsigned int irq;
++      unsigned int copying_receiver;
++      unsigned int carrier;
++
++      /* Receive-ring batched refills. */
++#define RX_MIN_TARGET 8
++#define RX_DFL_MIN_TARGET 64
++#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
++      unsigned rx_min_target, rx_max_target, rx_target;
++      struct sk_buff_head rx_batch;
++
++      struct timer_list rx_refill_timer;
++
++      /*
++       * {tx,rx}_skbs store outstanding skbuffs. The first entry in tx_skbs
++       * is an index into a chain of free entries.
++       */
++      struct sk_buff *tx_skbs[NET_TX_RING_SIZE+1];
++      struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
++
++#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
++      grant_ref_t gref_tx_head;
++      grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1];
++      grant_ref_t gref_rx_head;
++      grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
++
++      struct xenbus_device *xbdev;
++      int tx_ring_ref;
++      int rx_ring_ref;
++      u8 mac[ETH_ALEN];
++
++      unsigned long rx_pfn_array[NET_RX_RING_SIZE];
++      struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
++      struct mmu_update rx_mmu[NET_RX_RING_SIZE];
++
++      /* Private pointer to state internal to accelerator module */
++      void *accel_priv;
++      /* The accelerator used by this netfront device */
++      struct netfront_accelerator *accelerator;
++      /* The accelerator state for this netfront device */
++      struct netfront_accel_vif_state accel_vif_state;
++};
++
++
++/* Exported Functions */
++
++/*
++ * Called by an accelerator plugin module when it has loaded.
++ *
++ * frontend: the string describing the accelerator, currently the module name 
++ * hooks: the hooks for netfront to use to call into the accelerator
++ * version: the version of API between frontend and plugin requested
++ * 
++ * return: 0 on success, <0 on error, >0 (with version supported) on
++ * version mismatch
++ */
++extern int netfront_accelerator_loaded(int version, const char *frontend, 
++                                     struct netfront_accel_hooks *hooks);
++
++/* 
++ * Called by an accelerator plugin module when it is about to unload.
++ *
++ * frontend: the string describing the accelerator.  Must match the
++ * one passed to netfront_accelerator_loaded()
++ */ 
++extern void netfront_accelerator_stop(const char *frontend);
++
++/* 
++ * Called by an accelerator before waking the net device's TX queue to
++ * ensure the slow path has available slots.  Returns true if OK to
++ * wake, false if still busy 
++ */
++extern int netfront_check_queue_ready(struct net_device *net_dev);
++
++
++/* Internal-to-netfront Functions */
++
++/* 
++ * Call into accelerator and check to see if it has tx space before we
++ * wake the net device's TX queue.  Returns true if OK to wake, false
++ * if still busy
++ */ 
++extern 
++int netfront_check_accelerator_queue_ready(struct net_device *dev,
++                                         struct netfront_info *np);
++extern
++int netfront_accelerator_call_remove(struct netfront_info *np,
++                                   struct xenbus_device *dev);
++extern
++int netfront_accelerator_suspend(struct netfront_info *np,
++                               struct xenbus_device *dev);
++extern
++int netfront_accelerator_suspend_cancel(struct netfront_info *np,
++                                      struct xenbus_device *dev);
++extern
++void netfront_accelerator_resume(struct netfront_info *np,
++                               struct xenbus_device *dev);
++extern
++void netfront_accelerator_call_stop_napi_irq(struct netfront_info *np,
++                                           struct net_device *dev);
++extern
++int netfront_accelerator_call_get_stats(struct netfront_info *np,
++                                      struct net_device *dev);
++extern
++void netfront_accelerator_add_watch(struct netfront_info *np);
++
++extern
++void netif_init_accel(void);
++extern
++void netif_exit_accel(void);
++
++extern
++void init_accelerator_vif(struct netfront_info *np,
++                        struct xenbus_device *dev);
++#endif /* NETFRONT_H */
+--- linux-2.6.18.8/drivers/xen/pciback/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/Makefile   2008-05-19 00:33:46.162806998 +0300
+@@ -0,0 +1,17 @@
++obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback.o
++
++pciback-y := pci_stub.o pciback_ops.o xenbus.o
++pciback-y += conf_space.o conf_space_header.o \
++           conf_space_capability.o \
++           conf_space_capability_vpd.o \
++           conf_space_capability_pm.o \
++             conf_space_quirks.o
++pciback-$(CONFIG_PCI_MSI) += conf_space_capability_msi.o
++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o
++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
++pciback-$(CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER) += controller.o
++
++ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
++EXTRA_CFLAGS += -DDEBUG
++endif
+--- linux-2.6.18.8/drivers/xen/pciback/conf_space.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space.c       2008-05-19 00:33:46.182808150 +0300
+@@ -0,0 +1,426 @@
++/*
++ * PCI Backend - Functions for creating a virtual configuration space for
++ *               exported PCI Devices.
++ *               It's dangerous to allow PCI Driver Domains to change their
++ *               device's resources (memory, i/o ports, interrupts). We need to
++ *               restrict changes to certain PCI Configuration registers:
++ *               BARs, INTERRUPT_PIN, most registers in the header...
++ *
++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_quirks.h"
++
++#define DEFINE_PCI_CONFIG(op,size,type)                       \
++int pciback_##op##_config_##size                              \
++(struct pci_dev *dev, int offset, type value, void *data)     \
++{                                                             \
++      return pci_##op##_config_##size (dev, offset, value);   \
++}
++
++DEFINE_PCI_CONFIG(read, byte, u8 *)
++DEFINE_PCI_CONFIG(read, word, u16 *)
++DEFINE_PCI_CONFIG(read, dword, u32 *)
++
++DEFINE_PCI_CONFIG(write, byte, u8)
++DEFINE_PCI_CONFIG(write, word, u16)
++DEFINE_PCI_CONFIG(write, dword, u32)
++
++static int conf_space_read(struct pci_dev *dev,
++                         struct config_field_entry *entry, int offset,
++                         u32 * value)
++{
++      int ret = 0;
++      struct config_field *field = entry->field;
++
++      *value = 0;
++
++      switch (field->size) {
++      case 1:
++              if (field->u.b.read)
++                      ret = field->u.b.read(dev, offset, (u8 *) value,
++                                            entry->data);
++              break;
++      case 2:
++              if (field->u.w.read)
++                      ret = field->u.w.read(dev, offset, (u16 *) value,
++                                            entry->data);
++              break;
++      case 4:
++              if (field->u.dw.read)
++                      ret = field->u.dw.read(dev, offset, value, entry->data);
++              break;
++      }
++      return ret;
++}
++
++static int conf_space_write(struct pci_dev *dev,
++                          struct config_field_entry *entry, int offset,
++                          u32 value)
++{
++      int ret = 0;
++      struct config_field *field = entry->field;
++
++      switch (field->size) {
++      case 1:
++              if (field->u.b.write)
++                      ret = field->u.b.write(dev, offset, (u8) value,
++                                             entry->data);
++              break;
++      case 2:
++              if (field->u.w.write)
++                      ret = field->u.w.write(dev, offset, (u16) value,
++                                             entry->data);
++              break;
++      case 4:
++              if (field->u.dw.write)
++                      ret = field->u.dw.write(dev, offset, value,
++                                              entry->data);
++              break;
++      }
++      return ret;
++}
++
++static inline u32 get_mask(int size)
++{
++      if (size == 1)
++              return 0xff;
++      else if (size == 2)
++              return 0xffff;
++      else
++              return 0xffffffff;
++}
++
++static inline int valid_request(int offset, int size)
++{
++      /* Validate request (no un-aligned requests) */
++      if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
++              return 1;
++      return 0;
++}
++
++static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
++                            int offset)
++{
++      if (offset >= 0) {
++              new_val_mask <<= (offset * 8);
++              new_val <<= (offset * 8);
++      } else {
++              new_val_mask >>= (offset * -8);
++              new_val >>= (offset * -8);
++      }
++      val = (val & ~new_val_mask) | (new_val & new_val_mask);
++
++      return val;
++}
++
++static int pcibios_err_to_errno(int err)
++{
++      switch (err) {
++      case PCIBIOS_SUCCESSFUL:
++              return XEN_PCI_ERR_success;
++      case PCIBIOS_DEVICE_NOT_FOUND:
++              return XEN_PCI_ERR_dev_not_found;
++      case PCIBIOS_BAD_REGISTER_NUMBER:
++              return XEN_PCI_ERR_invalid_offset;
++      case PCIBIOS_FUNC_NOT_SUPPORTED:
++              return XEN_PCI_ERR_not_implemented;
++      case PCIBIOS_SET_FAILED:
++              return XEN_PCI_ERR_access_denied;
++      }
++      return err;
++}
++
++int pciback_config_read(struct pci_dev *dev, int offset, int size,
++                      u32 * ret_val)
++{
++      int err = 0;
++      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++      struct config_field_entry *cfg_entry;
++      struct config_field *field;
++      int req_start, req_end, field_start, field_end;
++      /* if read fails for any reason, return 0 (as if device didn't respond) */
++      u32 value = 0, tmp_val;
++
++      if (unlikely(verbose_request))
++              printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
++                     pci_name(dev), size, offset);
++
++      if (!valid_request(offset, size)) {
++              err = XEN_PCI_ERR_invalid_offset;
++              goto out;
++      }
++
++      /* Get the real value first, then modify as appropriate */
++      switch (size) {
++      case 1:
++              err = pci_read_config_byte(dev, offset, (u8 *) & value);
++              break;
++      case 2:
++              err = pci_read_config_word(dev, offset, (u16 *) & value);
++              break;
++      case 4:
++              err = pci_read_config_dword(dev, offset, &value);
++              break;
++      }
++
++      list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++              field = cfg_entry->field;
++
++              req_start = offset;
++              req_end = offset + size;
++              field_start = OFFSET(cfg_entry);
++              field_end = OFFSET(cfg_entry) + field->size;
++
++              if ((req_start >= field_start && req_start < field_end)
++                  || (req_end > field_start && req_end <= field_end)) {
++                      err = conf_space_read(dev, cfg_entry, field_start,
++                                            &tmp_val);
++                      if (err)
++                              goto out;
++
++                      value = merge_value(value, tmp_val,
++                                          get_mask(field->size),
++                                          field_start - req_start);
++              }
++      }
++
++      out:
++      if (unlikely(verbose_request))
++              printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
++                     pci_name(dev), size, offset, value);
++
++      *ret_val = value;
++      return pcibios_err_to_errno(err);
++}
++
++int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
++{
++      int err = 0, handled = 0;
++      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++      struct config_field_entry *cfg_entry;
++      struct config_field *field;
++      u32 tmp_val;
++      int req_start, req_end, field_start, field_end;
++
++      if (unlikely(verbose_request))
++              printk(KERN_DEBUG
++                     "pciback: %s: write request %d bytes at 0x%x = %x\n",
++                     pci_name(dev), size, offset, value);
++
++      if (!valid_request(offset, size))
++              return XEN_PCI_ERR_invalid_offset;
++
++      list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++              field = cfg_entry->field;
++
++              req_start = offset;
++              req_end = offset + size;
++              field_start = OFFSET(cfg_entry);
++              field_end = OFFSET(cfg_entry) + field->size;
++
++              if ((req_start >= field_start && req_start < field_end)
++                  || (req_end > field_start && req_end <= field_end)) {
++                      tmp_val = 0;
++
++                      err = pciback_config_read(dev, field_start,
++                                                field->size, &tmp_val);
++                      if (err)
++                              break;
++
++                      tmp_val = merge_value(tmp_val, value, get_mask(size),
++                                            req_start - field_start);
++
++                      err = conf_space_write(dev, cfg_entry, field_start,
++                                             tmp_val);
++
++                      /* handled is set true here, but not every byte
++                       * may have been written! Properly detecting if
++                       * every byte is handled is unnecessary as the
++                       * flag is used to detect devices that need
++                       * special helpers to work correctly.
++                       */
++                      handled = 1;
++              }
++      }
++
++      if (!handled && !err) {
++              /* By default, anything not specificially handled above is
++               * read-only. The permissive flag changes this behavior so
++               * that anything not specifically handled above is writable.
++               * This means that some fields may still be read-only because
++               * they have entries in the config_field list that intercept
++               * the write and do nothing. */
++              if (dev_data->permissive) {
++                      switch (size) {
++                      case 1:
++                              err = pci_write_config_byte(dev, offset,
++                                                          (u8) value);
++                              break;
++                      case 2:
++                              err = pci_write_config_word(dev, offset,
++                                                          (u16) value);
++                              break;
++                      case 4:
++                              err = pci_write_config_dword(dev, offset,
++                                                           (u32) value);
++                              break;
++                      }
++              } else if (!dev_data->warned_on_write) {
++                      dev_data->warned_on_write = 1;
++                      dev_warn(&dev->dev, "Driver tried to write to a "
++                               "read-only configuration space field at offset "
++                               "0x%x, size %d. This may be harmless, but if "
++                               "you have problems with your device:\n"
++                               "1) see permissive attribute in sysfs\n"
++                               "2) report problems to the xen-devel "
++                               "mailing list along with details of your "
++                               "device obtained from lspci.\n", offset, size);
++              }
++      }
++
++      return pcibios_err_to_errno(err);
++}
++
++void pciback_config_free_dyn_fields(struct pci_dev *dev)
++{
++      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++      struct config_field_entry *cfg_entry, *t;
++      struct config_field *field;
++
++      dev_dbg(&dev->dev,
++              "free-ing dynamically allocated virtual configuration space fields\n");
++
++      list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
++              field = cfg_entry->field;
++
++              if (field->clean) {
++                      field->clean(field);
++
++                      if (cfg_entry->data)
++                              kfree(cfg_entry->data);
++
++                      list_del(&cfg_entry->list);
++                      kfree(cfg_entry);
++              }
++
++      }
++}
++
++void pciback_config_reset_dev(struct pci_dev *dev)
++{
++      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++      struct config_field_entry *cfg_entry;
++      struct config_field *field;
++
++      dev_dbg(&dev->dev, "resetting virtual configuration space\n");
++
++      list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++              field = cfg_entry->field;
++
++              if (field->reset)
++                      field->reset(dev, OFFSET(cfg_entry), cfg_entry->data);
++      }
++}
++
++void pciback_config_free_dev(struct pci_dev *dev)
++{
++      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++      struct config_field_entry *cfg_entry, *t;
++      struct config_field *field;
++
++      dev_dbg(&dev->dev, "free-ing virtual configuration space fields\n");
++
++      list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
++              list_del(&cfg_entry->list);
++
++              field = cfg_entry->field;
++
++              if (field->release)
++                      field->release(dev, OFFSET(cfg_entry), cfg_entry->data);
++
++              kfree(cfg_entry);
++      }
++}
++
++int pciback_config_add_field_offset(struct pci_dev *dev,
++                                  struct config_field *field,
++                                  unsigned int base_offset)
++{
++      int err = 0;
++      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++      struct config_field_entry *cfg_entry;
++      void *tmp;
++
++      cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
++      if (!cfg_entry) {
++              err = -ENOMEM;
++              goto out;
++      }
++
++      cfg_entry->data = NULL;
++      cfg_entry->field = field;
++      cfg_entry->base_offset = base_offset;
++
++      /* silently ignore duplicate fields */
++      err = pciback_field_is_dup(dev,OFFSET(cfg_entry));
++      if (err)
++              goto out;
++
++      if (field->init) {
++              tmp = field->init(dev, OFFSET(cfg_entry));
++
++              if (IS_ERR(tmp)) {
++                      err = PTR_ERR(tmp);
++                      goto out;
++              }
++
++              cfg_entry->data = tmp;
++      }
++
++      dev_dbg(&dev->dev, "added config field at offset 0x%02x\n",
++              OFFSET(cfg_entry));
++      list_add_tail(&cfg_entry->list, &dev_data->config_fields);
++
++      out:
++      if (err)
++              kfree(cfg_entry);
++
++      return err;
++}
++
++/* This sets up the device's virtual configuration space to keep track of 
++ * certain registers (like the base address registers (BARs) so that we can
++ * keep the client from manipulating them directly.
++ */
++int pciback_config_init_dev(struct pci_dev *dev)
++{
++      int err = 0;
++      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++
++      dev_dbg(&dev->dev, "initializing virtual configuration space\n");
++
++      INIT_LIST_HEAD(&dev_data->config_fields);
++
++      err = pciback_config_header_add_fields(dev);
++      if (err)
++              goto out;
++
++      err = pciback_config_capability_add_fields(dev);
++      if (err)
++              goto out;
++
++      err = pciback_config_quirks_init(dev);
++
++      out:
++      return err;
++}
++
++int pciback_config_init(void)
++{
++      return pciback_config_capability_init();
++}
+--- linux-2.6.18.8/drivers/xen/pciback/conf_space.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space.h       2008-05-19 00:33:46.182808150 +0300
+@@ -0,0 +1,126 @@
++/*
++ * PCI Backend - Common data structures for overriding the configuration space
++ *
++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++
++#ifndef __XEN_PCIBACK_CONF_SPACE_H__
++#define __XEN_PCIBACK_CONF_SPACE_H__
++
++#include <linux/list.h>
++#include <linux/err.h>
++
++/* conf_field_init can return an errno in a ptr with ERR_PTR() */
++typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
++typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
++typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
++
++typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
++                               void *data);
++typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
++                              void *data);
++typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
++                              void *data);
++typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
++                              void *data);
++typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
++                             void *data);
++typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
++                             void *data);
++
++/* These are the fields within the configuration space which we
++ * are interested in intercepting reads/writes to and changing their
++ * values.
++ */
++struct config_field {
++      unsigned int offset;
++      unsigned int size;
++      unsigned int mask;
++      conf_field_init init;
++      conf_field_reset reset;
++      conf_field_free release;
++      void (*clean) (struct config_field * field);
++      union {
++              struct {
++                      conf_dword_write write;
++                      conf_dword_read read;
++              } dw;
++              struct {
++                      conf_word_write write;
++                      conf_word_read read;
++              } w;
++              struct {
++                      conf_byte_write write;
++                      conf_byte_read read;
++              } b;
++      } u;
++      struct list_head list;
++};
++
++struct config_field_entry {
++      struct list_head list;
++      struct config_field *field;
++      unsigned int base_offset;
++      void *data;
++};
++
++#define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
++
++/* Add fields to a device - the add_fields macro expects to get a pointer to
++ * the first entry in an array (of which the ending is marked by size==0)
++ */
++int pciback_config_add_field_offset(struct pci_dev *dev,
++                                  struct config_field *field,
++                                  unsigned int offset);
++
++static inline int pciback_config_add_field(struct pci_dev *dev,
++                                         struct config_field *field)
++{
++      return pciback_config_add_field_offset(dev, field, 0);
++}
++
++static inline int pciback_config_add_fields(struct pci_dev *dev,
++                                          struct config_field *field)
++{
++      int i, err = 0;
++      for (i = 0; field[i].size != 0; i++) {
++              err = pciback_config_add_field(dev, &field[i]);
++              if (err)
++                      break;
++      }
++      return err;
++}
++
++static inline int pciback_config_add_fields_offset(struct pci_dev *dev,
++                                                 struct config_field *field,
++                                                 unsigned int offset)
++{
++      int i, err = 0;
++      for (i = 0; field[i].size != 0; i++) {
++              err = pciback_config_add_field_offset(dev, &field[i], offset);
++              if (err)
++                      break;
++      }
++      return err;
++}
++
++/* Read/Write the real configuration space */
++int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
++                           void *data);
++int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
++                           void *data);
++int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
++                            void *data);
++int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
++                            void *data);
++int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
++                            void *data);
++int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
++                             void *data);
++
++int pciback_config_capability_init(void);
++
++int pciback_config_header_add_fields(struct pci_dev *dev);
++int pciback_config_capability_add_fields(struct pci_dev *dev);
++
++#endif                                /* __XEN_PCIBACK_CONF_SPACE_H__ */
+--- linux-2.6.18.8/drivers/xen/pciback/conf_space_capability.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability.c    2008-05-19 00:33:46.186808381 +0300
+@@ -0,0 +1,71 @@
++/*
++ * PCI Backend - Handles the virtual fields found on the capability lists
++ *               in the configuration space.
++ *
++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_capability.h"
++
++static LIST_HEAD(capabilities);
++
++static struct config_field caplist_header[] = {
++      {
++       .offset    = PCI_CAP_LIST_ID,
++       .size      = 2, /* encompass PCI_CAP_LIST_ID & PCI_CAP_LIST_NEXT */
++       .u.w.read  = pciback_read_config_word,
++       .u.w.write = NULL,
++      },
++      {
++       .size = 0,
++      },
++};
++
++static inline void register_capability(struct pciback_config_capability *cap)
++{
++      list_add_tail(&cap->cap_list, &capabilities);
++}
++
++int pciback_config_capability_add_fields(struct pci_dev *dev)
++{
++      int err = 0;
++      struct pciback_config_capability *cap;
++      int cap_offset;
++
++      list_for_each_entry(cap, &capabilities, cap_list) {
++              cap_offset = pci_find_capability(dev, cap->capability);
++              if (cap_offset) {
++                      dev_dbg(&dev->dev, "Found capability 0x%x at 0x%x\n",
++                              cap->capability, cap_offset);
++
++                      err = pciback_config_add_fields_offset(dev,
++                                                             caplist_header,
++                                                             cap_offset);
++                      if (err)
++                              goto out;
++                      err = pciback_config_add_fields_offset(dev,
++                                                             cap->fields,
++                                                             cap_offset);
++                      if (err)
++                              goto out;
++              }
++      }
++
++      out:
++      return err;
++}
++
++extern struct pciback_config_capability pciback_config_capability_vpd;
++extern struct pciback_config_capability pciback_config_capability_pm;
++
++int pciback_config_capability_init(void)
++{
++      register_capability(&pciback_config_capability_vpd);
++      register_capability(&pciback_config_capability_pm);
++
++      return 0;
++}
+--- linux-2.6.18.8/drivers/xen/pciback/conf_space_capability.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability.h    2008-05-19 00:33:46.186808381 +0300
+@@ -0,0 +1,23 @@
++/*
++ * PCI Backend - Data structures for special overlays for structures on
++ *               the capability list.
++ *
++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++
++#ifndef __PCIBACK_CONFIG_CAPABILITY_H__
++#define __PCIBACK_CONFIG_CAPABILITY_H__
++
++#include <linux/pci.h>
++#include <linux/list.h>
++
++struct pciback_config_capability {
++      struct list_head cap_list;
++
++      int capability;
++
++      /* If the device has the capability found above, add these fields */
++      struct config_field *fields;
++};
++
++#endif
+--- linux-2.6.18.8/drivers/xen/pciback/conf_space_capability_msi.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability_msi.c        2008-05-19 00:33:46.186808381 +0300
+@@ -0,0 +1,57 @@
++/*
++ * PCI Backend -- Configuration overlay for MSI capability
++ */
++#include <linux/pci.h>
++#include "conf_space.h"
++#include "conf_space_capability.h"
++#include <xen/interface/io/pciif.h>
++#include "pciback.h"
++
++int pciback_enable_msi(struct pciback_device *pdev,
++              struct pci_dev *dev, struct xen_pci_op *op)
++{
++      int otherend = pdev->xdev->otherend_id;
++      int status;
++
++      status = pci_enable_msi(dev);
++
++      if (status) {
++              printk("error enable msi for guest %x status %x\n", otherend, status);
++              op->value = 0;
++              return XEN_PCI_ERR_op_failed;
++      }
++
++      op->value = dev->irq;
++      return 0;
++}
++
++int pciback_disable_msi(struct pciback_device *pdev,
++              struct pci_dev *dev, struct xen_pci_op *op)
++{
++      pci_disable_msi(dev);
++
++      op->value = dev->irq;
++      return 0;
++}
++
++int pciback_enable_msix(struct pciback_device *pdev,
++              struct pci_dev *dev, struct xen_pci_op *op)
++{
++      int result;
++
++      result = pci_enable_msix(dev, op->msix_entries, op->value);
++
++      op->value = result;
++      return result;
++}
++
++int pciback_disable_msix(struct pciback_device *pdev,
++              struct pci_dev *dev, struct xen_pci_op *op)
++{
++
++      pci_disable_msix(dev);
++
++      op->value = dev->irq;
++      return 0;
++}
++
+--- linux-2.6.18.8/drivers/xen/pciback/conf_space_capability_pm.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability_pm.c 2008-05-19 00:33:46.206809534 +0300
+@@ -0,0 +1,128 @@
++/*
++ * PCI Backend - Configuration space overlay for power management
++ *
++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++
++#include <linux/pci.h>
++#include "conf_space.h"
++#include "conf_space_capability.h"
++
++static int pm_caps_read(struct pci_dev *dev, int offset, u16 *value,
++                      void *data)
++{
++      int err;
++      u16 real_value;
++
++      err = pci_read_config_word(dev, offset, &real_value);
++      if (err)
++              goto out;
++
++      *value = real_value & ~PCI_PM_CAP_PME_MASK;
++
++      out:
++      return err;
++}
++
++/* PM_OK_BITS specifies the bits that the driver domain is allowed to change.
++ * Can't allow driver domain to enable PMEs - they're shared */
++#define PM_OK_BITS (PCI_PM_CTRL_PME_STATUS|PCI_PM_CTRL_DATA_SEL_MASK)
++
++static int pm_ctrl_write(struct pci_dev *dev, int offset, u16 new_value,
++                       void *data)
++{
++      int err;
++      u16 old_value;
++      pci_power_t new_state, old_state;
++
++      err = pci_read_config_word(dev, offset, &old_value);
++      if (err)
++              goto out;
++
++      old_state = (pci_power_t)(old_value & PCI_PM_CTRL_STATE_MASK);
++      new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
++
++      new_value &= PM_OK_BITS;
++      if ((old_value & PM_OK_BITS) != new_value) {
++              new_value = (old_value & ~PM_OK_BITS) | new_value;
++              err = pci_write_config_word(dev, offset, new_value);
++              if (err)
++                      goto out;
++      }
++
++      /* Let pci core handle the power management change */
++      dev_dbg(&dev->dev, "set power state to %x\n", new_state);
++      err = pci_set_power_state(dev, new_state);
++      if (err) {
++              err = PCIBIOS_SET_FAILED;
++              goto out;
++      }
++
++      /*
++       * Device may lose PCI config info on D3->D0 transition. This
++       * is a problem for some guests which will not reset BARs. Even
++       * those that have a go will be foiled by our BAR-write handler
++       * which will discard the write! Since Linux won't re-init
++       * the config space automatically in all cases, we do it here.
++       * Future: Should we re-initialise all first 64 bytes of config space?
++       */
++      if (new_state == PCI_D0 &&
++          (old_state == PCI_D3hot || old_state == PCI_D3cold) &&
++          !(old_value & PCI_PM_CTRL_NO_SOFT_RESET))
++              pci_restore_bars(dev);
++
++ out:
++      return err;
++}
++
++/* Ensure PMEs are disabled */
++static void *pm_ctrl_init(struct pci_dev *dev, int offset)
++{
++      int err;
++      u16 value;
++
++      err = pci_read_config_word(dev, offset, &value);
++      if (err)
++              goto out;
++
++      if (value & PCI_PM_CTRL_PME_ENABLE) {
++              value &= ~PCI_PM_CTRL_PME_ENABLE;
++              err = pci_write_config_word(dev, offset, value);
++      }
++
++      out:
++      return ERR_PTR(err);
++}
++
++static struct config_field caplist_pm[] = {
++      {
++              .offset     = PCI_PM_PMC,
++              .size       = 2,
++              .u.w.read   = pm_caps_read,
++      },
++      {
++              .offset     = PCI_PM_CTRL,
++              .size       = 2,
++              .init       = pm_ctrl_init,
++              .u.w.read   = pciback_read_config_word,
++              .u.w.write  = pm_ctrl_write,
++      },
++      {
++              .offset     = PCI_PM_PPB_EXTENSIONS,
++              .size       = 1,
++              .u.b.read   = pciback_read_config_byte,
++      },
++      {
++              .offset     = PCI_PM_DATA_REGISTER,
++              .size       = 1,
++              .u.b.read   = pciback_read_config_byte,
++      },
++      {
++              .size = 0,
++      },
++};
++
++struct pciback_config_capability pciback_config_capability_pm = {
++      .capability = PCI_CAP_ID_PM,
++      .fields = caplist_pm,
++};
+--- linux-2.6.18.8/drivers/xen/pciback/conf_space_capability_vpd.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability_vpd.c        2008-05-19 00:33:46.226810687 +0300
+@@ -0,0 +1,42 @@
++/*
++ * PCI Backend - Configuration space overlay for Vital Product Data
++ *
++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++
++#include <linux/pci.h>
++#include "conf_space.h"
++#include "conf_space_capability.h"
++
++static int vpd_address_write(struct pci_dev *dev, int offset, u16 value,
++                           void *data)
++{
++      /* Disallow writes to the vital product data */
++      if (value & PCI_VPD_ADDR_F)
++              return PCIBIOS_SET_FAILED;
++      else
++              return pci_write_config_word(dev, offset, value);
++}
++
++static struct config_field caplist_vpd[] = {
++      {
++       .offset    = PCI_VPD_ADDR,
++       .size      = 2,
++       .u.w.read  = pciback_read_config_word,
++       .u.w.write = vpd_address_write,
++       },
++      {
++       .offset     = PCI_VPD_DATA,
++       .size       = 4,
++       .u.dw.read  = pciback_read_config_dword,
++       .u.dw.write = NULL,
++       },
++      {
++       .size = 0,
++       },
++};
++ 
++struct pciback_config_capability pciback_config_capability_vpd = {
++      .capability = PCI_CAP_ID_VPD,
++      .fields = caplist_vpd,
++};
+--- linux-2.6.18.8/drivers/xen/pciback/conf_space_header.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_header.c        2008-05-19 00:33:46.226810687 +0300
+@@ -0,0 +1,323 @@
++/*
++ * PCI Backend - Handles the virtual fields in the configuration space headers.
++ *
++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++
++struct pci_bar_info {
++      u32 val;
++      u32 len_val;
++      int which;
++};
++
++#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
++#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
++
++static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
++{
++      int err;
++
++      if (!dev->is_enabled && is_enable_cmd(value)) {
++              if (unlikely(verbose_request))
++                      printk(KERN_DEBUG "pciback: %s: enable\n",
++                             pci_name(dev));
++              err = pci_enable_device(dev);
++              if (err)
++                      return err;
++      } else if (dev->is_enabled && !is_enable_cmd(value)) {
++              if (unlikely(verbose_request))
++                      printk(KERN_DEBUG "pciback: %s: disable\n",
++                             pci_name(dev));
++              pci_disable_device(dev);
++      }
++
++      if (!dev->is_busmaster && is_master_cmd(value)) {
++              if (unlikely(verbose_request))
++                      printk(KERN_DEBUG "pciback: %s: set bus master\n",
++                             pci_name(dev));
++              pci_set_master(dev);
++      }
++
++      if (value & PCI_COMMAND_INVALIDATE) {
++              if (unlikely(verbose_request))
++                      printk(KERN_DEBUG
++                             "pciback: %s: enable memory-write-invalidate\n",
++                             pci_name(dev));
++              err = pci_set_mwi(dev);
++              if (err) {
++                      printk(KERN_WARNING
++                             "pciback: %s: cannot enable memory-write-invalidate (%d)\n",
++                             pci_name(dev), err);
++                      value &= ~PCI_COMMAND_INVALIDATE;
++              }
++      }
++
++      return pci_write_config_word(dev, offset, value);
++}
++
++static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
++{
++      struct pci_bar_info *bar = data;
++
++      if (unlikely(!bar)) {
++              printk(KERN_WARNING "pciback: driver data not found for %s\n",
++                     pci_name(dev));
++              return XEN_PCI_ERR_op_failed;
++      }
++
++      /* A write to obtain the length must happen as a 32-bit write.
++       * This does not (yet) support writing individual bytes
++       */
++      if (value == ~PCI_ROM_ADDRESS_ENABLE)
++              bar->which = 1;
++      else {
++              u32 tmpval;
++              pci_read_config_dword(dev, offset, &tmpval);
++              if (tmpval != bar->val && value == bar->val) {
++                      /* Allow restoration of bar value. */
++                      pci_write_config_dword(dev, offset, bar->val);
++              }
++              bar->which = 0;
++      }
++
++      /* Do we need to support enabling/disabling the rom address here? */
++
++      return 0;
++}
++
++/* For the BARs, only allow writes which write ~0 or
++ * the correct resource information
++ * (Needed for when the driver probes the resource usage)
++ */
++static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
++{
++      struct pci_bar_info *bar = data;
++
++      if (unlikely(!bar)) {
++              printk(KERN_WARNING "pciback: driver data not found for %s\n",
++                     pci_name(dev));
++              return XEN_PCI_ERR_op_failed;
++      }
++
++      /* A write to obtain the length must happen as a 32-bit write.
++       * This does not (yet) support writing individual bytes
++       */
++      if (value == ~0)
++              bar->which = 1;
++      else {
++              u32 tmpval;
++              pci_read_config_dword(dev, offset, &tmpval);
++              if (tmpval != bar->val && value == bar->val) {
++                      /* Allow restoration of bar value. */
++                      pci_write_config_dword(dev, offset, bar->val);
++              }
++              bar->which = 0;
++      }
++
++      return 0;
++}
++
++static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
++{
++      struct pci_bar_info *bar = data;
++
++      if (unlikely(!bar)) {
++              printk(KERN_WARNING "pciback: driver data not found for %s\n",
++                     pci_name(dev));
++              return XEN_PCI_ERR_op_failed;
++      }
++
++      *value = bar->which ? bar->len_val : bar->val;
++
++      return 0;
++}
++
++static inline void read_dev_bar(struct pci_dev *dev,
++                              struct pci_bar_info *bar_info, int offset,
++                              u32 len_mask)
++{
++      pci_read_config_dword(dev, offset, &bar_info->val);
++      pci_write_config_dword(dev, offset, len_mask);
++      pci_read_config_dword(dev, offset, &bar_info->len_val);
++      pci_write_config_dword(dev, offset, bar_info->val);
++}
++
++static void *bar_init(struct pci_dev *dev, int offset)
++{
++      struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
++
++      if (!bar)
++              return ERR_PTR(-ENOMEM);
++
++      read_dev_bar(dev, bar, offset, ~0);
++      bar->which = 0;
++
++      return bar;
++}
++
++static void *rom_init(struct pci_dev *dev, int offset)
++{
++      struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
++
++      if (!bar)
++              return ERR_PTR(-ENOMEM);
++
++      read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
++      bar->which = 0;
++
++      return bar;
++}
++
++static void bar_reset(struct pci_dev *dev, int offset, void *data)
++{
++      struct pci_bar_info *bar = data;
++
++      bar->which = 0;
++}
++
++static void bar_release(struct pci_dev *dev, int offset, void *data)
++{
++      kfree(data);
++}
++
++static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
++                        void *data)
++{
++      *value = (u8) dev->irq;
++
++      return 0;
++}
++
++static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
++{
++      u8 cur_value;
++      int err;
++
++      err = pci_read_config_byte(dev, offset, &cur_value);
++      if (err)
++              goto out;
++
++      if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
++          || value == PCI_BIST_START)
++              err = pci_write_config_byte(dev, offset, value);
++
++      out:
++      return err;
++}
++
++static struct config_field header_common[] = {
++      {
++       .offset    = PCI_COMMAND,
++       .size      = 2,
++       .u.w.read  = pciback_read_config_word,
++       .u.w.write = command_write,
++      },
++      {
++       .offset    = PCI_INTERRUPT_LINE,
++       .size      = 1,
++       .u.b.read  = interrupt_read,
++      },
++      {
++       .offset    = PCI_INTERRUPT_PIN,
++       .size      = 1,
++       .u.b.read  = pciback_read_config_byte,
++      },
++      {
++       /* Any side effects of letting driver domain control cache line? */
++       .offset    = PCI_CACHE_LINE_SIZE,
++       .size      = 1,
++       .u.b.read  = pciback_read_config_byte,
++       .u.b.write = pciback_write_config_byte,
++      },
++      {
++       .offset    = PCI_LATENCY_TIMER,
++       .size      = 1,
++       .u.b.read  = pciback_read_config_byte,
++      },
++      {
++       .offset    = PCI_BIST,
++       .size      = 1,
++       .u.b.read  = pciback_read_config_byte,
++       .u.b.write = bist_write,
++      },
++      {
++       .size = 0,
++      },
++};
++
++#define CFG_FIELD_BAR(reg_offset)                     \
++      {                                               \
++       .offset     = reg_offset,                      \
++       .size       = 4,                               \
++       .init       = bar_init,                        \
++       .reset      = bar_reset,                       \
++       .release    = bar_release,                     \
++       .u.dw.read  = bar_read,                        \
++       .u.dw.write = bar_write,                       \
++       }
++
++#define CFG_FIELD_ROM(reg_offset)                     \
++      {                                               \
++       .offset     = reg_offset,                      \
++       .size       = 4,                               \
++       .init       = rom_init,                        \
++       .reset      = bar_reset,                       \
++       .release    = bar_release,                     \
++       .u.dw.read  = bar_read,                        \
++       .u.dw.write = rom_write,                       \
++       }
++
++static struct config_field header_0[] = {
++      CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
++      CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
++      CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
++      CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
++      CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
++      CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
++      CFG_FIELD_ROM(PCI_ROM_ADDRESS),
++      {
++       .size = 0,
++      },
++};
++
++static struct config_field header_1[] = {
++      CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
++      CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
++      CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
++      {
++       .size = 0,
++      },
++};
++
++int pciback_config_header_add_fields(struct pci_dev *dev)
++{
++      int err;
++
++      err = pciback_config_add_fields(dev, header_common);
++      if (err)
++              goto out;
++
++      switch (dev->hdr_type) {
++      case PCI_HEADER_TYPE_NORMAL:
++              err = pciback_config_add_fields(dev, header_0);
++              break;
++
++      case PCI_HEADER_TYPE_BRIDGE:
++              err = pciback_config_add_fields(dev, header_1);
++              break;
++
++      default:
++              err = -EINVAL;
++              printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
++                     pci_name(dev), dev->hdr_type);
++              break;
++      }
++
++      out:
++      return err;
++}
+--- linux-2.6.18.8/drivers/xen/pciback/conf_space_quirks.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_quirks.c        2008-05-19 00:33:46.258812531 +0300
+@@ -0,0 +1,126 @@
++/*
++ * PCI Backend - Handle special overlays for broken devices.
++ *
++ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ * Author: Chris Bookholt <hap10@epoch.ncsc.mil>
++ */
++
++#include <linux/kernel.h>
++#include <linux/pci.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_quirks.h"
++
++LIST_HEAD(pciback_quirks);
++
++struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev)
++{
++      struct pciback_config_quirk *tmp_quirk;
++
++      list_for_each_entry(tmp_quirk, &pciback_quirks, quirks_list)
++          if (pci_match_id(&tmp_quirk->devid, dev))
++              goto out;
++      tmp_quirk = NULL;
++      printk(KERN_DEBUG
++             "quirk didn't match any device pciback knows about\n");
++      out:
++      return tmp_quirk;
++}
++
++static inline void register_quirk(struct pciback_config_quirk *quirk)
++{
++      list_add_tail(&quirk->quirks_list, &pciback_quirks);
++}
++
++int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg)
++{
++      int ret = 0;
++      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++      struct config_field_entry *cfg_entry;
++
++      list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++              if ( OFFSET(cfg_entry) == reg) {
++                      ret = 1;
++                      break;
++              }
++      }
++      return ret;
++}
++
++int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
++                                  *field)
++{
++      int err = 0;
++
++      switch (field->size) {
++      case 1:
++              field->u.b.read = pciback_read_config_byte;
++              field->u.b.write = pciback_write_config_byte;
++              break;
++      case 2:
++              field->u.w.read = pciback_read_config_word;
++              field->u.w.write = pciback_write_config_word;
++              break;
++      case 4:
++              field->u.dw.read = pciback_read_config_dword;
++              field->u.dw.write = pciback_write_config_dword;
++              break;
++      default:
++              err = -EINVAL;
++              goto out;
++      }
++
++      pciback_config_add_field(dev, field);
++
++      out:
++      return err;
++}
++
++int pciback_config_quirks_init(struct pci_dev *dev)
++{
++      struct pciback_config_quirk *quirk;
++      int ret = 0;
++
++      quirk = kzalloc(sizeof(*quirk), GFP_ATOMIC);
++      if (!quirk) {
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      quirk->devid.vendor = dev->vendor;
++      quirk->devid.device = dev->device;
++      quirk->devid.subvendor = dev->subsystem_vendor;
++      quirk->devid.subdevice = dev->subsystem_device;
++      quirk->devid.class = 0;
++      quirk->devid.class_mask = 0;
++      quirk->devid.driver_data = 0UL;
++
++      quirk->pdev = dev;
++
++      register_quirk(quirk);
++      out:
++      return ret;
++}
++
++void pciback_config_field_free(struct config_field *field)
++{
++      kfree(field);
++}
++
++int pciback_config_quirk_release(struct pci_dev *dev)
++{
++      struct pciback_config_quirk *quirk;
++      int ret = 0;
++
++      quirk = pciback_find_quirk(dev);
++      if (!quirk) {
++              ret = -ENXIO;
++              goto out;
++      }
++
++      list_del(&quirk->quirks_list);
++      kfree(quirk);
++
++      out:
++      return ret;
++}
+--- linux-2.6.18.8/drivers/xen/pciback/conf_space_quirks.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_quirks.h        2008-05-19 00:33:46.262812762 +0300
+@@ -0,0 +1,35 @@
++/*
++ * PCI Backend - Data structures for special overlays for broken devices.
++ *
++ * Ryan Wilson <hap9@epoch.ncsc.mil>
++ * Chris Bookholt <hap10@epoch.ncsc.mil>
++ */
++
++#ifndef __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
++#define __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
++
++#include <linux/pci.h>
++#include <linux/list.h>
++
++struct pciback_config_quirk {
++      struct list_head quirks_list;
++      struct pci_device_id devid;
++      struct pci_dev *pdev;
++};
++
++struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev);
++
++int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
++                                  *field);
++
++int pciback_config_quirks_remove_field(struct pci_dev *dev, int reg);
++
++int pciback_config_quirks_init(struct pci_dev *dev);
++
++void pciback_config_field_free(struct config_field *field);
++
++int pciback_config_quirk_release(struct pci_dev *dev);
++
++int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg);
++
++#endif
+--- linux-2.6.18.8/drivers/xen/pciback/controller.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/controller.c       2008-05-19 00:33:46.262812762 +0300
+@@ -0,0 +1,408 @@
++/*
++ * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
++ *      Alex Williamson <alex.williamson@hp.com>
++ *
++ * PCI "Controller" Backend - virtualize PCI bus topology based on PCI
++ * controllers.  Devices under the same PCI controller are exposed on the
++ * same virtual domain:bus.  Within a bus, device slots are virtualized
++ * to compact the bus.
++ *
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
++ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ */
++
++#include <linux/acpi.h>
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pciback.h"
++
++#define PCI_MAX_BUSSES        255
++#define PCI_MAX_SLOTS 32
++
++struct controller_dev_entry {
++      struct list_head list;
++      struct pci_dev *dev;
++      unsigned int devfn;
++};
++
++struct controller_list_entry {
++      struct list_head list;
++      struct pci_controller *controller;
++      unsigned int domain;
++      unsigned int bus;
++      unsigned int next_devfn;
++      struct list_head dev_list;
++};
++
++struct controller_dev_data {
++      struct list_head list;
++      unsigned int next_domain;
++      unsigned int next_bus;
++      spinlock_t lock;
++};
++
++struct walk_info {
++      struct pciback_device *pdev;
++      int resource_count;
++      int root_num;
++};
++
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++                                  unsigned int domain, unsigned int bus,
++                                  unsigned int devfn)
++{
++      struct controller_dev_data *dev_data = pdev->pci_dev_data;
++      struct controller_dev_entry *dev_entry;
++      struct controller_list_entry *cntrl_entry;
++      struct pci_dev *dev = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&dev_data->lock, flags);
++
++      list_for_each_entry(cntrl_entry, &dev_data->list, list) {
++              if (cntrl_entry->domain != domain ||
++                  cntrl_entry->bus != bus)
++                      continue;
++
++              list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
++                      if (devfn == dev_entry->devfn) {
++                              dev = dev_entry->dev;
++                              goto found;
++                      }
++              }
++      }
++found:
++      spin_unlock_irqrestore(&dev_data->lock, flags);
++
++      return dev;
++}
++
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
++                      int devid, publish_pci_dev_cb publish_cb)
++{
++      struct controller_dev_data *dev_data = pdev->pci_dev_data;
++      struct controller_dev_entry *dev_entry;
++      struct controller_list_entry *cntrl_entry;
++      struct pci_controller *dev_controller = PCI_CONTROLLER(dev);
++      unsigned long flags;
++      int ret = 0, found = 0;
++
++      spin_lock_irqsave(&dev_data->lock, flags);
++
++      /* Look to see if we already have a domain:bus for this controller */
++      list_for_each_entry(cntrl_entry, &dev_data->list, list) {
++              if (cntrl_entry->controller == dev_controller) {
++                      found = 1;
++                      break;
++              }
++      }
++
++      if (!found) {
++              cntrl_entry = kmalloc(sizeof(*cntrl_entry), GFP_ATOMIC);
++              if (!cntrl_entry) {
++                      ret =  -ENOMEM;
++                      goto out;
++              }
++
++              cntrl_entry->controller = dev_controller;
++              cntrl_entry->next_devfn = PCI_DEVFN(0, 0);
++
++              cntrl_entry->domain = dev_data->next_domain;
++              cntrl_entry->bus = dev_data->next_bus++;
++              if (dev_data->next_bus > PCI_MAX_BUSSES) {
++                      dev_data->next_domain++;
++                      dev_data->next_bus = 0;
++              }
++
++              INIT_LIST_HEAD(&cntrl_entry->dev_list);
++
++              list_add_tail(&cntrl_entry->list, &dev_data->list);
++      }
++
++      if (PCI_SLOT(cntrl_entry->next_devfn) > PCI_MAX_SLOTS) {
++              /*
++               * While it seems unlikely, this can actually happen if
++               * a controller has P2P bridges under it.
++               */
++              xenbus_dev_fatal(pdev->xdev, -ENOSPC, "Virtual bus %04x:%02x "
++                               "is full, no room to export %04x:%02x:%02x.%x",
++                               cntrl_entry->domain, cntrl_entry->bus,
++                               pci_domain_nr(dev->bus), dev->bus->number,
++                               PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
++              ret = -ENOSPC;
++              goto out;
++      }
++
++      dev_entry = kmalloc(sizeof(*dev_entry), GFP_ATOMIC);
++      if (!dev_entry) {
++              if (list_empty(&cntrl_entry->dev_list)) {
++                      list_del(&cntrl_entry->list);
++                      kfree(cntrl_entry);
++              }
++              ret = -ENOMEM;
++              goto out;
++      }
++
++      dev_entry->dev = dev;
++      dev_entry->devfn = cntrl_entry->next_devfn;
++
++      list_add_tail(&dev_entry->list, &cntrl_entry->dev_list);
++
++      cntrl_entry->next_devfn += PCI_DEVFN(1, 0);
++
++out:
++      spin_unlock_irqrestore(&dev_data->lock, flags);
++
++      /* TODO: Publish virtual domain:bus:slot.func here. */
++
++      return ret;
++}
++
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++      struct controller_dev_data *dev_data = pdev->pci_dev_data;
++      struct controller_list_entry *cntrl_entry;
++      struct controller_dev_entry *dev_entry = NULL;
++      struct pci_dev *found_dev = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&dev_data->lock, flags);
++
++      list_for_each_entry(cntrl_entry, &dev_data->list, list) {
++              if (cntrl_entry->controller != PCI_CONTROLLER(dev))
++                      continue;
++
++              list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
++                      if (dev_entry->dev == dev) {
++                              found_dev = dev_entry->dev;
++                              break;
++                      }
++              }
++      }
++
++      if (!found_dev) {
++              spin_unlock_irqrestore(&dev_data->lock, flags);
++              return;
++      }
++
++      list_del(&dev_entry->list);
++      kfree(dev_entry);
++
++      if (list_empty(&cntrl_entry->dev_list)) {
++              list_del(&cntrl_entry->list);
++              kfree(cntrl_entry);
++      }
++
++      spin_unlock_irqrestore(&dev_data->lock, flags);
++      pcistub_put_pci_dev(found_dev);
++}
++
++int pciback_init_devices(struct pciback_device *pdev)
++{
++      struct controller_dev_data *dev_data;
++
++      dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
++      if (!dev_data)
++              return -ENOMEM;
++
++      spin_lock_init(&dev_data->lock);
++
++      INIT_LIST_HEAD(&dev_data->list);
++
++      /* Starting domain:bus numbers */
++      dev_data->next_domain = 0;
++      dev_data->next_bus = 0;
++
++      pdev->pci_dev_data = dev_data;
++
++      return 0;
++}
++
++static acpi_status write_xenbus_resource(struct acpi_resource *res, void *data)
++{
++      struct walk_info *info = data;
++      struct acpi_resource_address64 addr;
++      acpi_status status;
++      int i, len, err;
++      char str[32], tmp[3];
++      unsigned char *ptr, *buf;
++
++      status = acpi_resource_to_address64(res, &addr);
++
++      /* Do we care about this range?  Let's check. */
++      if (!ACPI_SUCCESS(status) ||
++          !(addr.resource_type == ACPI_MEMORY_RANGE ||
++            addr.resource_type == ACPI_IO_RANGE) ||
++          !addr.address_length || addr.producer_consumer != ACPI_PRODUCER)
++              return AE_OK;
++
++      /*
++       * Furthermore, we really only care to tell the guest about
++       * address ranges that require address translation of some sort.
++       */
++      if (!(addr.resource_type == ACPI_MEMORY_RANGE &&
++            addr.info.mem.translation) &&
++          !(addr.resource_type == ACPI_IO_RANGE &&
++            addr.info.io.translation))
++              return AE_OK;
++         
++      /* Store the resource in xenbus for the guest */
++      len = snprintf(str, sizeof(str), "root-%d-resource-%d",
++                     info->root_num, info->resource_count);
++      if (unlikely(len >= (sizeof(str) - 1)))
++              return AE_OK;
++
++      buf = kzalloc((sizeof(*res) * 2) + 1, GFP_KERNEL);
++      if (!buf)
++              return AE_OK;
++
++      /* Clean out resource_source */
++      res->data.address64.resource_source.index = 0xFF;
++      res->data.address64.resource_source.string_length = 0;
++      res->data.address64.resource_source.string_ptr = NULL;
++
++      ptr = (unsigned char *)res;
++
++      /* Turn the acpi_resource into an ASCII byte stream */
++      for (i = 0; i < sizeof(*res); i++) {
++              snprintf(tmp, sizeof(tmp), "%02x", ptr[i]);
++              strncat(buf, tmp, 2);
++      }
++
++      err = xenbus_printf(XBT_NIL, info->pdev->xdev->nodename,
++                          str, "%s", buf);
++
++      if (!err)
++              info->resource_count++;
++
++      kfree(buf);
++
++      return AE_OK;
++}
++
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++                            publish_pci_root_cb publish_root_cb)
++{
++      struct controller_dev_data *dev_data = pdev->pci_dev_data;
++      struct controller_list_entry *cntrl_entry;
++      int i, root_num, len, err = 0;
++      unsigned int domain, bus;
++      char str[64];
++      struct walk_info info;
++
++      spin_lock(&dev_data->lock);
++
++      list_for_each_entry(cntrl_entry, &dev_data->list, list) {
++              /* First publish all the domain:bus info */
++              err = publish_root_cb(pdev, cntrl_entry->domain,
++                                    cntrl_entry->bus);
++              if (err)
++                      goto out;
++
++              /*
++               * Now figure out which root-%d this belongs to
++               * so we can associate resources with it.
++               */
++              err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++                                 "root_num", "%d", &root_num);
++
++              if (err != 1)
++                      goto out;
++
++              for (i = 0; i < root_num; i++) {
++                      len = snprintf(str, sizeof(str), "root-%d", i);
++                      if (unlikely(len >= (sizeof(str) - 1))) {
++                              err = -ENOMEM;
++                              goto out;
++                      }
++
++                      err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++                                         str, "%x:%x", &domain, &bus);
++                      if (err != 2)
++                              goto out;
++
++                      /* Is this the one we just published? */
++                      if (domain == cntrl_entry->domain &&
++                          bus == cntrl_entry->bus)
++                              break;
++              }
++
++              if (i == root_num)
++                      goto out;
++
++              info.pdev = pdev;
++              info.resource_count = 0;
++              info.root_num = i;
++
++              /* Let ACPI do the heavy lifting on decoding resources */
++              acpi_walk_resources(cntrl_entry->controller->acpi_handle,
++                                  METHOD_NAME__CRS, write_xenbus_resource,
++                                  &info);
++
++              /* No resouces.  OK.  On to the next one */
++              if (!info.resource_count)
++                      continue;
++
++              /* Store the number of resources we wrote for this root-%d */
++              len = snprintf(str, sizeof(str), "root-%d-resources", i);
++              if (unlikely(len >= (sizeof(str) - 1))) {
++                      err = -ENOMEM;
++                      goto out;
++              }
++
++              err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
++                                  "%d", info.resource_count);
++              if (err)
++                      goto out;
++      }
++
++      /* Finally, write some magic to synchronize with the guest. */
++      len = snprintf(str, sizeof(str), "root-resource-magic");
++      if (unlikely(len >= (sizeof(str) - 1))) {
++              err = -ENOMEM;
++              goto out;
++      }
++
++      err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
++                          "%lx", (sizeof(struct acpi_resource) * 2) + 1);
++
++out:
++      spin_unlock(&dev_data->lock);
++
++      return err;
++}
++
++void pciback_release_devices(struct pciback_device *pdev)
++{
++      struct controller_dev_data *dev_data = pdev->pci_dev_data;
++      struct controller_list_entry *cntrl_entry, *c;
++      struct controller_dev_entry *dev_entry, *d;
++
++      list_for_each_entry_safe(cntrl_entry, c, &dev_data->list, list) {
++              list_for_each_entry_safe(dev_entry, d,
++                                       &cntrl_entry->dev_list, list) {
++                      list_del(&dev_entry->list);
++                      pcistub_put_pci_dev(dev_entry->dev);
++                      kfree(dev_entry);
++              }
++              list_del(&cntrl_entry->list);
++              kfree(cntrl_entry);
++      }
++
++      kfree(dev_data);
++      pdev->pci_dev_data = NULL;
++}
+--- linux-2.6.18.8/drivers/xen/pciback/passthrough.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/passthrough.c      2008-05-19 00:33:46.262812762 +0300
+@@ -0,0 +1,166 @@
++/*
++ * PCI Backend - Provides restricted access to the real PCI bus topology
++ *               to the frontend
++ *
++ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++
++#include <linux/list.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pciback.h"
++
++struct passthrough_dev_data {
++      /* Access to dev_list must be protected by lock */
++      struct list_head dev_list;
++      spinlock_t lock;
++};
++
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++                                  unsigned int domain, unsigned int bus,
++                                  unsigned int devfn)
++{
++      struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++      struct pci_dev_entry *dev_entry;
++      struct pci_dev *dev = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&dev_data->lock, flags);
++
++      list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
++              if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
++                  && bus == (unsigned int)dev_entry->dev->bus->number
++                  && devfn == dev_entry->dev->devfn) {
++                      dev = dev_entry->dev;
++                      break;
++              }
++      }
++
++      spin_unlock_irqrestore(&dev_data->lock, flags);
++
++      return dev;
++}
++
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
++                      int devid, publish_pci_dev_cb publish_cb)
++{
++      struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++      struct pci_dev_entry *dev_entry;
++      unsigned long flags;
++      unsigned int domain, bus, devfn;
++      int err;
++
++      dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
++      if (!dev_entry)
++              return -ENOMEM;
++      dev_entry->dev = dev;
++
++      spin_lock_irqsave(&dev_data->lock, flags);
++      list_add_tail(&dev_entry->list, &dev_data->dev_list);
++      spin_unlock_irqrestore(&dev_data->lock, flags);
++
++      /* Publish this device. */
++      domain = (unsigned int)pci_domain_nr(dev->bus);
++      bus = (unsigned int)dev->bus->number;
++      devfn = dev->devfn;
++      err = publish_cb(pdev, domain, bus, devfn, devid);
++
++      return err;
++}
++
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++      struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++      struct pci_dev_entry *dev_entry, *t;
++      struct pci_dev *found_dev = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&dev_data->lock, flags);
++
++      list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
++              if (dev_entry->dev == dev) {
++                      list_del(&dev_entry->list);
++                      found_dev = dev_entry->dev;
++                      kfree(dev_entry);
++              }
++      }
++
++      spin_unlock_irqrestore(&dev_data->lock, flags);
++
++      if (found_dev)
++              pcistub_put_pci_dev(found_dev);
++}
++
++int pciback_init_devices(struct pciback_device *pdev)
++{
++      struct passthrough_dev_data *dev_data;
++
++      dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
++      if (!dev_data)
++              return -ENOMEM;
++
++      spin_lock_init(&dev_data->lock);
++
++      INIT_LIST_HEAD(&dev_data->dev_list);
++
++      pdev->pci_dev_data = dev_data;
++
++      return 0;
++}
++
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++                            publish_pci_root_cb publish_root_cb)
++{
++      int err = 0;
++      struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++      struct pci_dev_entry *dev_entry, *e;
++      struct pci_dev *dev;
++      int found;
++      unsigned int domain, bus;
++
++      spin_lock(&dev_data->lock);
++
++      list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
++              /* Only publish this device as a root if none of its
++               * parent bridges are exported
++               */
++              found = 0;
++              dev = dev_entry->dev->bus->self;
++              for (; !found && dev != NULL; dev = dev->bus->self) {
++                      list_for_each_entry(e, &dev_data->dev_list, list) {
++                              if (dev == e->dev) {
++                                      found = 1;
++                                      break;
++                              }
++                      }
++              }
++
++              domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
++              bus = (unsigned int)dev_entry->dev->bus->number;
++
++              if (!found) {
++                      err = publish_root_cb(pdev, domain, bus);
++                      if (err)
++                              break;
++              }
++      }
++
++      spin_unlock(&dev_data->lock);
++
++      return err;
++}
++
++void pciback_release_devices(struct pciback_device *pdev)
++{
++      struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
++      struct pci_dev_entry *dev_entry, *t;
++
++      list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
++              list_del(&dev_entry->list);
++              pcistub_put_pci_dev(dev_entry->dev);
++              kfree(dev_entry);
++      }
++
++      kfree(dev_data);
++      pdev->pci_dev_data = NULL;
++}
+--- linux-2.6.18.8/drivers/xen/pciback/pci_stub.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/pci_stub.c 2008-05-19 00:33:46.266812993 +0300
+@@ -0,0 +1,953 @@
++/*
++ * PCI Stub Driver - Grabs devices in backend to be exported later
++ *
++ * Ryan Wilson <hap9@epoch.ncsc.mil>
++ * Chris Bookholt <hap10@epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/kref.h>
++#include <asm/atomic.h>
++#include "pciback.h"
++#include "conf_space.h"
++#include "conf_space_quirks.h"
++
++static char *pci_devs_to_hide = NULL;
++module_param_named(hide, pci_devs_to_hide, charp, 0444);
++
++struct pcistub_device_id {
++      struct list_head slot_list;
++      int domain;
++      unsigned char bus;
++      unsigned int devfn;
++};
++static LIST_HEAD(pcistub_device_ids);
++static DEFINE_SPINLOCK(device_ids_lock);
++
++struct pcistub_device {
++      struct kref kref;
++      struct list_head dev_list;
++      spinlock_t lock;
++
++      struct pci_dev *dev;
++      struct pciback_device *pdev;    /* non-NULL if struct pci_dev is in use */
++};
++
++/* Access to pcistub_devices & seized_devices lists and the initialize_devices
++ * flag must be locked with pcistub_devices_lock
++ */
++static DEFINE_SPINLOCK(pcistub_devices_lock);
++static LIST_HEAD(pcistub_devices);
++
++/* wait for device_initcall before initializing our devices
++ * (see pcistub_init_devices_late)
++ */
++static int initialize_devices = 0;
++static LIST_HEAD(seized_devices);
++
++static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
++{
++      struct pcistub_device *psdev;
++
++      dev_dbg(&dev->dev, "pcistub_device_alloc\n");
++
++      psdev = kzalloc(sizeof(*psdev), GFP_ATOMIC);
++      if (!psdev)
++              return NULL;
++
++      psdev->dev = pci_dev_get(dev);
++      if (!psdev->dev) {
++              kfree(psdev);
++              return NULL;
++      }
++
++      kref_init(&psdev->kref);
++      spin_lock_init(&psdev->lock);
++
++      return psdev;
++}
++
++/* Don't call this directly as it's called by pcistub_device_put */
++static void pcistub_device_release(struct kref *kref)
++{
++      struct pcistub_device *psdev;
++
++      psdev = container_of(kref, struct pcistub_device, kref);
++
++      dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
++
++      /* Clean-up the device */
++      pciback_reset_device(psdev->dev);
++      pciback_config_free_dyn_fields(psdev->dev);
++      pciback_config_free_dev(psdev->dev);
++      kfree(pci_get_drvdata(psdev->dev));
++      pci_set_drvdata(psdev->dev, NULL);
++
++      pci_dev_put(psdev->dev);
++
++      kfree(psdev);
++}
++
++static inline void pcistub_device_get(struct pcistub_device *psdev)
++{
++      kref_get(&psdev->kref);
++}
++
++static inline void pcistub_device_put(struct pcistub_device *psdev)
++{
++      kref_put(&psdev->kref, pcistub_device_release);
++}
++
++static struct pcistub_device *pcistub_device_find(int domain, int bus,
++                                                int slot, int func)
++{
++      struct pcistub_device *psdev = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++              if (psdev->dev != NULL
++                  && domain == pci_domain_nr(psdev->dev->bus)
++                  && bus == psdev->dev->bus->number
++                  && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
++                      pcistub_device_get(psdev);
++                      goto out;
++              }
++      }
++
++      /* didn't find it */
++      psdev = NULL;
++
++      out:
++      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++      return psdev;
++}
++
++static struct pci_dev *pcistub_device_get_pci_dev(struct pciback_device *pdev,
++                                                struct pcistub_device *psdev)
++{
++      struct pci_dev *pci_dev = NULL;
++      unsigned long flags;
++
++      pcistub_device_get(psdev);
++
++      spin_lock_irqsave(&psdev->lock, flags);
++      if (!psdev->pdev) {
++              psdev->pdev = pdev;
++              pci_dev = psdev->dev;
++      }
++      spin_unlock_irqrestore(&psdev->lock, flags);
++
++      if (!pci_dev)
++              pcistub_device_put(psdev);
++
++      return pci_dev;
++}
++
++struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
++                                          int domain, int bus,
++                                          int slot, int func)
++{
++      struct pcistub_device *psdev;
++      struct pci_dev *found_dev = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++              if (psdev->dev != NULL
++                  && domain == pci_domain_nr(psdev->dev->bus)
++                  && bus == psdev->dev->bus->number
++                  && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
++                      found_dev = pcistub_device_get_pci_dev(pdev, psdev);
++                      break;
++              }
++      }
++
++      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++      return found_dev;
++}
++
++struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
++                                  struct pci_dev *dev)
++{
++      struct pcistub_device *psdev;
++      struct pci_dev *found_dev = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++              if (psdev->dev == dev) {
++                      found_dev = pcistub_device_get_pci_dev(pdev, psdev);
++                      break;
++              }
++      }
++
++      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++      return found_dev;
++}
++
++void pcistub_put_pci_dev(struct pci_dev *dev)
++{
++      struct pcistub_device *psdev, *found_psdev = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++              if (psdev->dev == dev) {
++                      found_psdev = psdev;
++                      break;
++              }
++      }
++
++      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++      /* Cleanup our device
++       * (so it's ready for the next domain)
++       */
++      pciback_reset_device(found_psdev->dev);
++      pciback_config_free_dyn_fields(found_psdev->dev);
++      pciback_config_reset_dev(found_psdev->dev);
++
++      spin_lock_irqsave(&found_psdev->lock, flags);
++      found_psdev->pdev = NULL;
++      spin_unlock_irqrestore(&found_psdev->lock, flags);
++
++      pcistub_device_put(found_psdev);
++}
++
++static int __devinit pcistub_match_one(struct pci_dev *dev,
++                                     struct pcistub_device_id *pdev_id)
++{
++      /* Match the specified device by domain, bus, slot, func and also if
++       * any of the device's parent bridges match.
++       */
++      for (; dev != NULL; dev = dev->bus->self) {
++              if (pci_domain_nr(dev->bus) == pdev_id->domain
++                  && dev->bus->number == pdev_id->bus
++                  && dev->devfn == pdev_id->devfn)
++                      return 1;
++
++              /* Sometimes topmost bridge links to itself. */
++              if (dev == dev->bus->self)
++                      break;
++      }
++
++      return 0;
++}
++
++static int __devinit pcistub_match(struct pci_dev *dev)
++{
++      struct pcistub_device_id *pdev_id;
++      unsigned long flags;
++      int found = 0;
++
++      spin_lock_irqsave(&device_ids_lock, flags);
++      list_for_each_entry(pdev_id, &pcistub_device_ids, slot_list) {
++              if (pcistub_match_one(dev, pdev_id)) {
++                      found = 1;
++                      break;
++              }
++      }
++      spin_unlock_irqrestore(&device_ids_lock, flags);
++
++      return found;
++}
++
++static int __devinit pcistub_init_device(struct pci_dev *dev)
++{
++      struct pciback_dev_data *dev_data;
++      int err = 0;
++
++      dev_dbg(&dev->dev, "initializing...\n");
++
++      /* The PCI backend is not intended to be a module (or to work with
++       * removable PCI devices (yet). If it were, pciback_config_free()
++       * would need to be called somewhere to free the memory allocated
++       * here and then to call kfree(pci_get_drvdata(psdev->dev)).
++       */
++      dev_data = kzalloc(sizeof(*dev_data), GFP_ATOMIC);
++      if (!dev_data) {
++              err = -ENOMEM;
++              goto out;
++      }
++      pci_set_drvdata(dev, dev_data);
++
++      dev_dbg(&dev->dev, "initializing config\n");
++      err = pciback_config_init_dev(dev);
++      if (err)
++              goto out;
++
++      /* HACK: Force device (& ACPI) to determine what IRQ it's on - we
++       * must do this here because pcibios_enable_device may specify
++       * the pci device's true irq (and possibly its other resources)
++       * if they differ from what's in the configuration space.
++       * This makes the assumption that the device's resources won't
++       * change after this point (otherwise this code may break!)
++       */
++      dev_dbg(&dev->dev, "enabling device\n");
++      err = pci_enable_device(dev);
++      if (err)
++              goto config_release;
++
++      /* Now disable the device (this also ensures some private device
++       * data is setup before we export)
++       */
++      dev_dbg(&dev->dev, "reset device\n");
++      pciback_reset_device(dev);
++
++      return 0;
++
++      config_release:
++      pciback_config_free_dev(dev);
++
++      out:
++      pci_set_drvdata(dev, NULL);
++      kfree(dev_data);
++      return err;
++}
++
++/*
++ * Because some initialization still happens on
++ * devices during fs_initcall, we need to defer
++ * full initialization of our devices until
++ * device_initcall.
++ */
++static int __init pcistub_init_devices_late(void)
++{
++      struct pcistub_device *psdev;
++      unsigned long flags;
++      int err = 0;
++
++      pr_debug("pciback: pcistub_init_devices_late\n");
++
++      spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++      while (!list_empty(&seized_devices)) {
++              psdev = container_of(seized_devices.next,
++                                   struct pcistub_device, dev_list);
++              list_del(&psdev->dev_list);
++
++              spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++              err = pcistub_init_device(psdev->dev);
++              if (err) {
++                      dev_err(&psdev->dev->dev,
++                              "error %d initializing device\n", err);
++                      kfree(psdev);
++                      psdev = NULL;
++              }
++
++              spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++              if (psdev)
++                      list_add_tail(&psdev->dev_list, &pcistub_devices);
++      }
++
++      initialize_devices = 1;
++
++      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++      return 0;
++}
++
++static int __devinit pcistub_seize(struct pci_dev *dev)
++{
++      struct pcistub_device *psdev;
++      unsigned long flags;
++      int err = 0;
++
++      psdev = pcistub_device_alloc(dev);
++      if (!psdev)
++              return -ENOMEM;
++
++      spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++      if (initialize_devices) {
++              spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++              /* don't want irqs disabled when calling pcistub_init_device */
++              err = pcistub_init_device(psdev->dev);
++
++              spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++              if (!err)
++                      list_add(&psdev->dev_list, &pcistub_devices);
++      } else {
++              dev_dbg(&dev->dev, "deferring initialization\n");
++              list_add(&psdev->dev_list, &seized_devices);
++      }
++
++      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++      if (err)
++              pcistub_device_put(psdev);
++
++      return err;
++}
++
++static int __devinit pcistub_probe(struct pci_dev *dev,
++                                 const struct pci_device_id *id)
++{
++      int err = 0;
++
++      dev_dbg(&dev->dev, "probing...\n");
++
++      if (pcistub_match(dev)) {
++
++              if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
++                  && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
++                      dev_err(&dev->dev, "can't export pci devices that "
++                              "don't have a normal (0) or bridge (1) "
++                              "header type!\n");
++                      err = -ENODEV;
++                      goto out;
++              }
++
++              dev_info(&dev->dev, "seizing device\n");
++              err = pcistub_seize(dev);
++      } else
++              /* Didn't find the device */
++              err = -ENODEV;
++
++      out:
++      return err;
++}
++
++static void pcistub_remove(struct pci_dev *dev)
++{
++      struct pcistub_device *psdev, *found_psdev = NULL;
++      unsigned long flags;
++
++      dev_dbg(&dev->dev, "removing\n");
++
++      spin_lock_irqsave(&pcistub_devices_lock, flags);
++
++      pciback_config_quirk_release(dev);
++
++      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++              if (psdev->dev == dev) {
++                      found_psdev = psdev;
++                      break;
++              }
++      }
++
++      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++      if (found_psdev) {
++              dev_dbg(&dev->dev, "found device to remove - in use? %p\n",
++                      found_psdev->pdev);
++
++              if (found_psdev->pdev) {
++                      printk(KERN_WARNING "pciback: ****** removing device "
++                             "%s while still in-use! ******\n",
++                             pci_name(found_psdev->dev));
++                      printk(KERN_WARNING "pciback: ****** driver domain may "
++                             "still access this device's i/o resources!\n");
++                      printk(KERN_WARNING "pciback: ****** shutdown driver "
++                             "domain before binding device\n");
++                      printk(KERN_WARNING "pciback: ****** to other drivers "
++                             "or domains\n");
++
++                      pciback_release_pci_dev(found_psdev->pdev,
++                                              found_psdev->dev);
++              }
++
++              spin_lock_irqsave(&pcistub_devices_lock, flags);
++              list_del(&found_psdev->dev_list);
++              spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++
++              /* the final put for releasing from the list */
++              pcistub_device_put(found_psdev);
++      }
++}
++
++static struct pci_device_id pcistub_ids[] = {
++      {
++       .vendor = PCI_ANY_ID,
++       .device = PCI_ANY_ID,
++       .subvendor = PCI_ANY_ID,
++       .subdevice = PCI_ANY_ID,
++       },
++      {0,},
++};
++
++/*
++ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
++ * for a normal device. I don't want it to be loaded automatically.
++ */
++
++static struct pci_driver pciback_pci_driver = {
++      .name = "pciback",
++      .id_table = pcistub_ids,
++      .probe = pcistub_probe,
++      .remove = pcistub_remove,
++};
++
++static inline int str_to_slot(const char *buf, int *domain, int *bus,
++                            int *slot, int *func)
++{
++      int err;
++
++      err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func);
++      if (err == 4)
++              return 0;
++      else if (err < 0)
++              return -EINVAL;
++
++      /* try again without domain */
++      *domain = 0;
++      err = sscanf(buf, " %x:%x.%x", bus, slot, func);
++      if (err == 3)
++              return 0;
++
++      return -EINVAL;
++}
++
++static inline int str_to_quirk(const char *buf, int *domain, int *bus, int
++                             *slot, int *func, int *reg, int *size, int *mask)
++{
++      int err;
++
++      err =
++          sscanf(buf, " %04x:%02x:%02x.%1x-%08x:%1x:%08x", domain, bus, slot,
++                 func, reg, size, mask);
++      if (err == 7)
++              return 0;
++      return -EINVAL;
++}
++
++static int pcistub_device_id_add(int domain, int bus, int slot, int func)
++{
++      struct pcistub_device_id *pci_dev_id;
++      unsigned long flags;
++
++      pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
++      if (!pci_dev_id)
++              return -ENOMEM;
++
++      pci_dev_id->domain = domain;
++      pci_dev_id->bus = bus;
++      pci_dev_id->devfn = PCI_DEVFN(slot, func);
++
++      pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n",
++               domain, bus, slot, func);
++
++      spin_lock_irqsave(&device_ids_lock, flags);
++      list_add_tail(&pci_dev_id->slot_list, &pcistub_device_ids);
++      spin_unlock_irqrestore(&device_ids_lock, flags);
++
++      return 0;
++}
++
++static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
++{
++      struct pcistub_device_id *pci_dev_id, *t;
++      int devfn = PCI_DEVFN(slot, func);
++      int err = -ENOENT;
++      unsigned long flags;
++
++      spin_lock_irqsave(&device_ids_lock, flags);
++      list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, slot_list) {
++
++              if (pci_dev_id->domain == domain
++                  && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) {
++                      /* Don't break; here because it's possible the same
++                       * slot could be in the list more than once
++                       */
++                      list_del(&pci_dev_id->slot_list);
++                      kfree(pci_dev_id);
++
++                      err = 0;
++
++                      pr_debug("pciback: removed %04x:%02x:%02x.%01x from "
++                               "seize list\n", domain, bus, slot, func);
++              }
++      }
++      spin_unlock_irqrestore(&device_ids_lock, flags);
++
++      return err;
++}
++
++static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg,
++                         int size, int mask)
++{
++      int err = 0;
++      struct pcistub_device *psdev;
++      struct pci_dev *dev;
++      struct config_field *field;
++
++      psdev = pcistub_device_find(domain, bus, slot, func);
++      if (!psdev || !psdev->dev) {
++              err = -ENODEV;
++              goto out;
++      }
++      dev = psdev->dev;
++
++      field = kzalloc(sizeof(*field), GFP_ATOMIC);
++      if (!field) {
++              err = -ENOMEM;
++              goto out;
++      }
++
++      field->offset = reg;
++      field->size = size;
++      field->mask = mask;
++      field->init = NULL;
++      field->reset = NULL;
++      field->release = NULL;
++      field->clean = pciback_config_field_free;
++
++      err = pciback_config_quirks_add_field(dev, field);
++      if (err)
++              kfree(field);
++      out:
++      return err;
++}
++
++static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf,
++                              size_t count)
++{
++      int domain, bus, slot, func;
++      int err;
++
++      err = str_to_slot(buf, &domain, &bus, &slot, &func);
++      if (err)
++              goto out;
++
++      err = pcistub_device_id_add(domain, bus, slot, func);
++
++      out:
++      if (!err)
++              err = count;
++      return err;
++}
++
++DRIVER_ATTR(new_slot, S_IWUSR, NULL, pcistub_slot_add);
++
++static ssize_t pcistub_slot_remove(struct device_driver *drv, const char *buf,
++                                 size_t count)
++{
++      int domain, bus, slot, func;
++      int err;
++
++      err = str_to_slot(buf, &domain, &bus, &slot, &func);
++      if (err)
++              goto out;
++
++      err = pcistub_device_id_remove(domain, bus, slot, func);
++
++      out:
++      if (!err)
++              err = count;
++      return err;
++}
++
++DRIVER_ATTR(remove_slot, S_IWUSR, NULL, pcistub_slot_remove);
++
++static ssize_t pcistub_slot_show(struct device_driver *drv, char *buf)
++{
++      struct pcistub_device_id *pci_dev_id;
++      size_t count = 0;
++      unsigned long flags;
++
++      spin_lock_irqsave(&device_ids_lock, flags);
++      list_for_each_entry(pci_dev_id, &pcistub_device_ids, slot_list) {
++              if (count >= PAGE_SIZE)
++                      break;
++
++              count += scnprintf(buf + count, PAGE_SIZE - count,
++                                 "%04x:%02x:%02x.%01x\n",
++                                 pci_dev_id->domain, pci_dev_id->bus,
++                                 PCI_SLOT(pci_dev_id->devfn),
++                                 PCI_FUNC(pci_dev_id->devfn));
++      }
++      spin_unlock_irqrestore(&device_ids_lock, flags);
++
++      return count;
++}
++
++DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL);
++
++static ssize_t pcistub_quirk_add(struct device_driver *drv, const char *buf,
++                               size_t count)
++{
++      int domain, bus, slot, func, reg, size, mask;
++      int err;
++
++      err = str_to_quirk(buf, &domain, &bus, &slot, &func, &reg, &size,
++                         &mask);
++      if (err)
++              goto out;
++
++      err = pcistub_reg_add(domain, bus, slot, func, reg, size, mask);
++
++      out:
++      if (!err)
++              err = count;
++      return err;
++}
++
++static ssize_t pcistub_quirk_show(struct device_driver *drv, char *buf)
++{
++      int count = 0;
++      unsigned long flags;
++      extern struct list_head pciback_quirks;
++      struct pciback_config_quirk *quirk;
++      struct pciback_dev_data *dev_data;
++      struct config_field *field;
++      struct config_field_entry *cfg_entry;
++
++      spin_lock_irqsave(&device_ids_lock, flags);
++      list_for_each_entry(quirk, &pciback_quirks, quirks_list) {
++              if (count >= PAGE_SIZE)
++                      goto out;
++
++              count += scnprintf(buf + count, PAGE_SIZE - count,
++                                 "%02x:%02x.%01x\n\t%04x:%04x:%04x:%04x\n",
++                                 quirk->pdev->bus->number,
++                                 PCI_SLOT(quirk->pdev->devfn),
++                                 PCI_FUNC(quirk->pdev->devfn),
++                                 quirk->devid.vendor, quirk->devid.device,
++                                 quirk->devid.subvendor,
++                                 quirk->devid.subdevice);
++
++              dev_data = pci_get_drvdata(quirk->pdev);
++
++              list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
++                      field = cfg_entry->field;
++                      if (count >= PAGE_SIZE)
++                              goto out;
++
++                      count += scnprintf(buf + count, PAGE_SIZE - count,
++                                         "\t\t%08x:%01x:%08x\n",
++                                         cfg_entry->base_offset + field->offset, 
++                                         field->size, field->mask);
++              }
++      }
++
++      out:
++      spin_unlock_irqrestore(&device_ids_lock, flags);
++
++      return count;
++}
++
++DRIVER_ATTR(quirks, S_IRUSR | S_IWUSR, pcistub_quirk_show, pcistub_quirk_add);
++
++static ssize_t permissive_add(struct device_driver *drv, const char *buf,
++                            size_t count)
++{
++      int domain, bus, slot, func;
++      int err;
++      struct pcistub_device *psdev;
++      struct pciback_dev_data *dev_data;
++      err = str_to_slot(buf, &domain, &bus, &slot, &func);
++      if (err)
++              goto out;
++      psdev = pcistub_device_find(domain, bus, slot, func);
++      if (!psdev) {
++              err = -ENODEV;
++              goto out;
++      }
++      if (!psdev->dev) {
++              err = -ENODEV;
++              goto release;
++      }
++      dev_data = pci_get_drvdata(psdev->dev);
++      /* the driver data for a device should never be null at this point */
++      if (!dev_data) {
++              err = -ENXIO;
++              goto release;
++      }
++      if (!dev_data->permissive) {
++              dev_data->permissive = 1;
++              /* Let user know that what they're doing could be unsafe */
++              dev_warn(&psdev->dev->dev,
++                       "enabling permissive mode configuration space accesses!\n");
++              dev_warn(&psdev->dev->dev,
++                       "permissive mode is potentially unsafe!\n");
++      }
++      release:
++      pcistub_device_put(psdev);
++      out:
++      if (!err)
++              err = count;
++      return err;
++}
++
++static ssize_t permissive_show(struct device_driver *drv, char *buf)
++{
++      struct pcistub_device *psdev;
++      struct pciback_dev_data *dev_data;
++      size_t count = 0;
++      unsigned long flags;
++      spin_lock_irqsave(&pcistub_devices_lock, flags);
++      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
++              if (count >= PAGE_SIZE)
++                      break;
++              if (!psdev->dev)
++                      continue;
++              dev_data = pci_get_drvdata(psdev->dev);
++              if (!dev_data || !dev_data->permissive)
++                      continue;
++              count +=
++                  scnprintf(buf + count, PAGE_SIZE - count, "%s\n",
++                            pci_name(psdev->dev));
++      }
++      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++      return count;
++}
++
++DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add);
++
++#ifdef CONFIG_PCI_MSI
++
++int pciback_get_owner(struct pci_dev *dev)
++{
++      struct pcistub_device *psdev;
++
++      psdev = pcistub_device_find(pci_domain_nr(dev->bus), dev->bus->number,
++                      PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
++      /* XXX will other domain has pciback support ??? */
++      if (!psdev || !psdev->pdev) {
++              printk(KERN_WARNING "no ownder\n");
++              return -1;
++      }
++      return psdev->pdev->xdev->otherend_id;
++}
++#endif
++
++static void pcistub_exit(void)
++{
++      driver_remove_file(&pciback_pci_driver.driver, &driver_attr_new_slot);
++      driver_remove_file(&pciback_pci_driver.driver,
++                         &driver_attr_remove_slot);
++      driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots);
++      driver_remove_file(&pciback_pci_driver.driver, &driver_attr_quirks);
++      driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
++
++      pci_unregister_driver(&pciback_pci_driver);
++#ifdef CONFIG_PCI_MSI
++      unregister_msi_get_owner(pciback_get_owner);
++#endif
++}
++
++static int __init pcistub_init(void)
++{
++      int pos = 0;
++      int err = 0;
++      int domain, bus, slot, func;
++      int parsed;
++
++      if (pci_devs_to_hide && *pci_devs_to_hide) {
++              do {
++                      parsed = 0;
++
++                      err = sscanf(pci_devs_to_hide + pos,
++                                   " (%x:%x:%x.%x) %n",
++                                   &domain, &bus, &slot, &func, &parsed);
++                      if (err != 4) {
++                              domain = 0;
++                              err = sscanf(pci_devs_to_hide + pos,
++                                           " (%x:%x.%x) %n",
++                                           &bus, &slot, &func, &parsed);
++                              if (err != 3)
++                                      goto parse_error;
++                      }
++
++                      err = pcistub_device_id_add(domain, bus, slot, func);
++                      if (err)
++                              goto out;
++
++                      /* if parsed<=0, we've reached the end of the string */
++                      pos += parsed;
++              } while (parsed > 0 && pci_devs_to_hide[pos]);
++      }
++
++      /* If we're the first PCI Device Driver to register, we're the
++       * first one to get offered PCI devices as they become
++       * available (and thus we can be the first to grab them)
++       */
++      err = pci_register_driver(&pciback_pci_driver);
++      if (err < 0)
++              goto out;
++
++      err = driver_create_file(&pciback_pci_driver.driver,
++                               &driver_attr_new_slot);
++      if (!err)
++              err = driver_create_file(&pciback_pci_driver.driver,
++                                       &driver_attr_remove_slot);
++      if (!err)
++              err = driver_create_file(&pciback_pci_driver.driver,
++                                       &driver_attr_slots);
++      if (!err)
++              err = driver_create_file(&pciback_pci_driver.driver,
++                                       &driver_attr_quirks);
++      if (!err)
++              err = driver_create_file(&pciback_pci_driver.driver,
++                                       &driver_attr_permissive);
++
++#ifdef CONFIG_PCI_MSI
++      if (!err)
++              err = register_msi_get_owner(pciback_get_owner);
++#endif
++      if (err)
++              pcistub_exit();
++
++      out:
++      return err;
++
++      parse_error:
++      printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
++             pci_devs_to_hide + pos);
++      return -EINVAL;
++}
++
++#ifndef MODULE
++/*
++ * fs_initcall happens before device_initcall
++ * so pciback *should* get called first (b/c we 
++ * want to suck up any device before other drivers
++ * get a chance by being the first pci device
++ * driver to register)
++ */
++fs_initcall(pcistub_init);
++#endif
++
++static int __init pciback_init(void)
++{
++      int err;
++
++      err = pciback_config_init();
++      if (err)
++              return err;
++
++#ifdef MODULE
++      err = pcistub_init();
++      if (err < 0)
++              return err;
++#endif
++
++      pcistub_init_devices_late();
++      err = pciback_xenbus_register();
++      if (err)
++              pcistub_exit();
++
++      return err;
++}
++
++static void __exit pciback_cleanup(void)
++{
++      pciback_xenbus_unregister();
++      pcistub_exit();
++}
++
++module_init(pciback_init);
++module_exit(pciback_cleanup);
++
++MODULE_LICENSE("Dual BSD/GPL");
+--- linux-2.6.18.8/drivers/xen/pciback/pciback.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/pciback.h  2008-05-19 00:33:46.266812993 +0300
+@@ -0,0 +1,111 @@
++/*
++ * PCI Backend Common Data Structures & Function Declarations
++ *
++ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++#ifndef __XEN_PCIBACK_H__
++#define __XEN_PCIBACK_H__
++
++#include <linux/pci.h>
++#include <linux/interrupt.h>
++#include <xen/xenbus.h>
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <linux/workqueue.h>
++#include <asm/atomic.h>
++#include <xen/interface/io/pciif.h>
++
++struct pci_dev_entry {
++      struct list_head list;
++      struct pci_dev *dev;
++};
++
++#define _PDEVF_op_active      (0)
++#define PDEVF_op_active       (1<<(_PDEVF_op_active))
++
++struct pciback_device {
++      void *pci_dev_data;
++      spinlock_t dev_lock;
++
++      struct xenbus_device *xdev;
++
++      struct xenbus_watch be_watch;
++      u8 be_watching;
++
++      int evtchn_irq;
++
++      struct vm_struct *sh_area;
++      struct xen_pci_sharedinfo *sh_info;
++
++      unsigned long flags;
++
++      struct work_struct op_work;
++};
++
++struct pciback_dev_data {
++      struct list_head config_fields;
++      int permissive;
++      int warned_on_write;
++};
++
++/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
++struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
++                                          int domain, int bus,
++                                          int slot, int func);
++struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
++                                  struct pci_dev *dev);
++void pcistub_put_pci_dev(struct pci_dev *dev);
++
++/* Ensure a device is turned off or reset */
++void pciback_reset_device(struct pci_dev *pdev);
++
++/* Access a virtual configuration space for a PCI device */
++int pciback_config_init(void);
++int pciback_config_init_dev(struct pci_dev *dev);
++void pciback_config_free_dyn_fields(struct pci_dev *dev);
++void pciback_config_reset_dev(struct pci_dev *dev);
++void pciback_config_free_dev(struct pci_dev *dev);
++int pciback_config_read(struct pci_dev *dev, int offset, int size,
++                      u32 * ret_val);
++int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
++
++/* Handle requests for specific devices from the frontend */
++typedef int (*publish_pci_dev_cb) (struct pciback_device *pdev,
++                                 unsigned int domain, unsigned int bus,
++                                 unsigned int devfn, unsigned int devid);
++typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
++                                  unsigned int domain, unsigned int bus);
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
++                      int devid, publish_pci_dev_cb publish_cb);
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++                                  unsigned int domain, unsigned int bus,
++                                  unsigned int devfn);
++int pciback_init_devices(struct pciback_device *pdev);
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++                            publish_pci_root_cb cb);
++void pciback_release_devices(struct pciback_device *pdev);
++
++/* Handles events from front-end */
++irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
++void pciback_do_op(void *data);
++
++int pciback_xenbus_register(void);
++void pciback_xenbus_unregister(void);
++
++#ifdef CONFIG_PCI_MSI
++int pciback_enable_msi(struct pciback_device *pdev,
++                       struct pci_dev *dev, struct xen_pci_op *op);
++
++int pciback_disable_msi(struct pciback_device *pdev,
++                         struct pci_dev *dev, struct xen_pci_op *op);
++
++
++int pciback_enable_msix(struct pciback_device *pdev,
++                        struct pci_dev *dev, struct xen_pci_op *op);
++
++int pciback_disable_msix(struct pciback_device *pdev,
++                        struct pci_dev *dev, struct xen_pci_op *op);
++#endif
++extern int verbose_request;
++#endif
+--- linux-2.6.18.8/drivers/xen/pciback/pciback_ops.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/pciback_ops.c      2008-05-19 00:33:46.266812993 +0300
+@@ -0,0 +1,117 @@
++/*
++ * PCI Backend Operations - respond to PCI requests from Frontend
++ *
++ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <asm/bitops.h>
++#include <xen/evtchn.h>
++#include "pciback.h"
++
++int verbose_request = 0;
++module_param(verbose_request, int, 0644);
++
++/* Ensure a device is "turned off" and ready to be exported.
++ * (Also see pciback_config_reset to ensure virtual configuration space is
++ * ready to be re-exported)
++ */
++void pciback_reset_device(struct pci_dev *dev)
++{
++      u16 cmd;
++
++      /* Disable devices (but not bridges) */
++      if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
++              pci_disable_device(dev);
++
++              pci_write_config_word(dev, PCI_COMMAND, 0);
++
++              dev->is_enabled = 0;
++              dev->is_busmaster = 0;
++      } else {
++              pci_read_config_word(dev, PCI_COMMAND, &cmd);
++              if (cmd & (PCI_COMMAND_INVALIDATE)) {
++                      cmd &= ~(PCI_COMMAND_INVALIDATE);
++                      pci_write_config_word(dev, PCI_COMMAND, cmd);
++
++                      dev->is_busmaster = 0;
++              }
++      }
++}
++
++static inline void test_and_schedule_op(struct pciback_device *pdev)
++{
++      /* Check that frontend is requesting an operation and that we are not
++       * already processing a request */
++      if (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)
++          && !test_and_set_bit(_PDEVF_op_active, &pdev->flags))
++              schedule_work(&pdev->op_work);
++}
++
++/* Performing the configuration space reads/writes must not be done in atomic
++ * context because some of the pci_* functions can sleep (mostly due to ACPI
++ * use of semaphores). This function is intended to be called from a work
++ * queue in process context taking a struct pciback_device as a parameter */
++void pciback_do_op(void *data)
++{
++      struct pciback_device *pdev = data;
++      struct pci_dev *dev;
++      struct xen_pci_op *op = &pdev->sh_info->op;
++
++      dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
++
++      if (dev == NULL)
++              op->err = XEN_PCI_ERR_dev_not_found;
++      else
++      {
++              switch (op->cmd)
++              {
++                      case XEN_PCI_OP_conf_read:
++                              op->err = pciback_config_read(dev,
++                                        op->offset, op->size, &op->value);
++                              break;
++                      case XEN_PCI_OP_conf_write:
++                              op->err = pciback_config_write(dev,
++                                        op->offset, op->size, op->value);
++                              break;
++#ifdef CONFIG_PCI_MSI
++                      case XEN_PCI_OP_enable_msi:
++                              op->err = pciback_enable_msi(pdev, dev, op);
++                              break;
++                      case XEN_PCI_OP_disable_msi:
++                              op->err = pciback_disable_msi(pdev, dev, op);
++                              break;
++                      case XEN_PCI_OP_enable_msix:
++                              op->err = pciback_enable_msix(pdev, dev, op);
++                              break;
++                      case XEN_PCI_OP_disable_msix:
++                              op->err = pciback_disable_msix(pdev, dev, op);
++                              break;
++#endif
++                      default:
++                              op->err = XEN_PCI_ERR_not_implemented;
++                              break;
++              }
++      }
++      /* Tell the driver domain that we're done. */ 
++      wmb();
++      clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
++      notify_remote_via_irq(pdev->evtchn_irq);
++
++      /* Mark that we're done. */
++      smp_mb__before_clear_bit(); /* /after/ clearing PCIF_active */
++      clear_bit(_PDEVF_op_active, &pdev->flags);
++      smp_mb__after_clear_bit(); /* /before/ final check for work */
++
++      /* Check to see if the driver domain tried to start another request in
++       * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active. */
++      test_and_schedule_op(pdev);
++}
++
++irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
++{
++      struct pciback_device *pdev = dev_id;
++
++      test_and_schedule_op(pdev);
++
++      return IRQ_HANDLED;
++}
+--- linux-2.6.18.8/drivers/xen/pciback/slot.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/slot.c     2008-05-19 00:33:46.266812993 +0300
+@@ -0,0 +1,157 @@
++/*
++ * PCI Backend - Provides a Virtual PCI bus (with real devices)
++ *               to the frontend
++ *
++ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil> (vpci.c)
++ *   Author: Tristan Gingold <tristan.gingold@bull.net>, from vpci.c
++ */
++
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pciback.h"
++
++/* There are at most 32 slots in a pci bus.  */
++#define PCI_SLOT_MAX 32
++
++#define PCI_BUS_NBR 2
++
++struct slot_dev_data {
++      /* Access to dev_list must be protected by lock */
++      struct pci_dev *slots[PCI_BUS_NBR][PCI_SLOT_MAX];
++      spinlock_t lock;
++};
++
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++                                  unsigned int domain, unsigned int bus,
++                                  unsigned int devfn)
++{
++      struct pci_dev *dev = NULL;
++      struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++      unsigned long flags;
++
++      if (domain != 0 || PCI_FUNC(devfn) != 0)
++              return NULL;
++
++      if (PCI_SLOT(devfn) >= PCI_SLOT_MAX || bus >= PCI_BUS_NBR)
++              return NULL;
++
++      spin_lock_irqsave(&slot_dev->lock, flags);
++      dev = slot_dev->slots[bus][PCI_SLOT(devfn)];
++      spin_unlock_irqrestore(&slot_dev->lock, flags);
++
++      return dev;
++}
++
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
++                      int devid, publish_pci_dev_cb publish_cb)
++{
++      int err = 0, slot, bus;
++      struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++      unsigned long flags;
++
++      if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
++              err = -EFAULT;
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Can't export bridges on the virtual PCI bus");
++              goto out;
++      }
++
++      spin_lock_irqsave(&slot_dev->lock, flags);
++
++      /* Assign to a new slot on the virtual PCI bus */
++      for (bus = 0; bus < PCI_BUS_NBR; bus++)
++              for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++                      if (slot_dev->slots[bus][slot] == NULL) {
++                              printk(KERN_INFO
++                                     "pciback: slot: %s: assign to virtual slot %d, bus %d\n",
++                                     pci_name(dev), slot, bus);
++                              slot_dev->slots[bus][slot] = dev;
++                              goto unlock;
++                      }
++              }
++
++      err = -ENOMEM;
++      xenbus_dev_fatal(pdev->xdev, err,
++                       "No more space on root virtual PCI bus");
++
++      unlock:
++      spin_unlock_irqrestore(&slot_dev->lock, flags);
++
++      /* Publish this device. */
++      if(!err)
++              err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, 0), devid);
++
++      out:
++      return err;
++}
++
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++      int slot, bus;
++      struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++      struct pci_dev *found_dev = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&slot_dev->lock, flags);
++
++      for (bus = 0; bus < PCI_BUS_NBR; bus++)
++              for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++                      if (slot_dev->slots[bus][slot] == dev) {
++                              slot_dev->slots[bus][slot] = NULL;
++                              found_dev = dev;
++                              goto out;
++                      }
++              }
++
++      out:
++      spin_unlock_irqrestore(&slot_dev->lock, flags);
++
++      if (found_dev)
++              pcistub_put_pci_dev(found_dev);
++}
++
++int pciback_init_devices(struct pciback_device *pdev)
++{
++      int slot, bus;
++      struct slot_dev_data *slot_dev;
++
++      slot_dev = kmalloc(sizeof(*slot_dev), GFP_KERNEL);
++      if (!slot_dev)
++              return -ENOMEM;
++
++      spin_lock_init(&slot_dev->lock);
++
++      for (bus = 0; bus < PCI_BUS_NBR; bus++)
++              for (slot = 0; slot < PCI_SLOT_MAX; slot++)
++                      slot_dev->slots[bus][slot] = NULL;
++
++      pdev->pci_dev_data = slot_dev;
++
++      return 0;
++}
++
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++                            publish_pci_root_cb publish_cb)
++{
++      /* The Virtual PCI bus has only one root */
++      return publish_cb(pdev, 0, 0);
++}
++
++void pciback_release_devices(struct pciback_device *pdev)
++{
++      int slot, bus;
++      struct slot_dev_data *slot_dev = pdev->pci_dev_data;
++      struct pci_dev *dev;
++
++      for (bus = 0; bus < PCI_BUS_NBR; bus++)
++              for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++                      dev = slot_dev->slots[bus][slot];
++                      if (dev != NULL)
++                              pcistub_put_pci_dev(dev);
++              }
++
++      kfree(slot_dev);
++      pdev->pci_dev_data = NULL;
++}
+--- linux-2.6.18.8/drivers/xen/pciback/vpci.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/vpci.c     2008-05-19 00:33:46.266812993 +0300
+@@ -0,0 +1,212 @@
++/*
++ * PCI Backend - Provides a Virtual PCI bus (with real devices)
++ *               to the frontend
++ *
++ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++
++#include <linux/list.h>
++#include <linux/slab.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pciback.h"
++
++#define PCI_SLOT_MAX 32
++
++struct vpci_dev_data {
++      /* Access to dev_list must be protected by lock */
++      struct list_head dev_list[PCI_SLOT_MAX];
++      spinlock_t lock;
++};
++
++static inline struct list_head *list_first(struct list_head *head)
++{
++      return head->next;
++}
++
++struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
++                                  unsigned int domain, unsigned int bus,
++                                  unsigned int devfn)
++{
++      struct pci_dev_entry *entry;
++      struct pci_dev *dev = NULL;
++      struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++      unsigned long flags;
++
++      if (domain != 0 || bus != 0)
++              return NULL;
++
++      if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
++              spin_lock_irqsave(&vpci_dev->lock, flags);
++
++              list_for_each_entry(entry,
++                                  &vpci_dev->dev_list[PCI_SLOT(devfn)],
++                                  list) {
++                      if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) {
++                              dev = entry->dev;
++                              break;
++                      }
++              }
++
++              spin_unlock_irqrestore(&vpci_dev->lock, flags);
++      }
++      return dev;
++}
++
++static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
++{
++      if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
++          && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
++              return 1;
++
++      return 0;
++}
++
++int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev,
++                      int devid, publish_pci_dev_cb publish_cb)
++{
++      int err = 0, slot, func;
++      struct pci_dev_entry *t, *dev_entry;
++      struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++      unsigned long flags;
++
++      if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
++              err = -EFAULT;
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Can't export bridges on the virtual PCI bus");
++              goto out;
++      }
++
++      dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
++      if (!dev_entry) {
++              err = -ENOMEM;
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error adding entry to virtual PCI bus");
++              goto out;
++      }
++
++      dev_entry->dev = dev;
++
++      spin_lock_irqsave(&vpci_dev->lock, flags);
++
++      /* Keep multi-function devices together on the virtual PCI bus */
++      for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++              if (!list_empty(&vpci_dev->dev_list[slot])) {
++                      t = list_entry(list_first(&vpci_dev->dev_list[slot]),
++                                     struct pci_dev_entry, list);
++
++                      if (match_slot(dev, t->dev)) {
++                              pr_info("pciback: vpci: %s: "
++                                      "assign to virtual slot %d func %d\n",
++                                      pci_name(dev), slot,
++                                      PCI_FUNC(dev->devfn));
++                              list_add_tail(&dev_entry->list,
++                                            &vpci_dev->dev_list[slot]);
++                              func = PCI_FUNC(dev->devfn);
++                              goto unlock;
++                      }
++              }
++      }
++
++      /* Assign to a new slot on the virtual PCI bus */
++      for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++              if (list_empty(&vpci_dev->dev_list[slot])) {
++                      printk(KERN_INFO
++                             "pciback: vpci: %s: assign to virtual slot %d\n",
++                             pci_name(dev), slot);
++                      list_add_tail(&dev_entry->list,
++                                    &vpci_dev->dev_list[slot]);
++                      func = PCI_FUNC(dev->devfn);
++                      goto unlock;
++              }
++      }
++
++      err = -ENOMEM;
++      xenbus_dev_fatal(pdev->xdev, err,
++                       "No more space on root virtual PCI bus");
++
++      unlock:
++      spin_unlock_irqrestore(&vpci_dev->lock, flags);
++
++      /* Publish this device. */
++      if(!err)
++              err = publish_cb(pdev, 0, 0, PCI_DEVFN(slot, func), devid);
++
++      out:
++      return err;
++}
++
++void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++{
++      int slot;
++      struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++      struct pci_dev *found_dev = NULL;
++      unsigned long flags;
++
++      spin_lock_irqsave(&vpci_dev->lock, flags);
++
++      for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++              struct pci_dev_entry *e, *tmp;
++              list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
++                                       list) {
++                      if (e->dev == dev) {
++                              list_del(&e->list);
++                              found_dev = e->dev;
++                              kfree(e);
++                              goto out;
++                      }
++              }
++      }
++
++      out:
++      spin_unlock_irqrestore(&vpci_dev->lock, flags);
++
++      if (found_dev)
++              pcistub_put_pci_dev(found_dev);
++}
++
++int pciback_init_devices(struct pciback_device *pdev)
++{
++      int slot;
++      struct vpci_dev_data *vpci_dev;
++
++      vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
++      if (!vpci_dev)
++              return -ENOMEM;
++
++      spin_lock_init(&vpci_dev->lock);
++
++      for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++              INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
++      }
++
++      pdev->pci_dev_data = vpci_dev;
++
++      return 0;
++}
++
++int pciback_publish_pci_roots(struct pciback_device *pdev,
++                            publish_pci_root_cb publish_cb)
++{
++      /* The Virtual PCI bus has only one root */
++      return publish_cb(pdev, 0, 0);
++}
++
++void pciback_release_devices(struct pciback_device *pdev)
++{
++      int slot;
++      struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++
++      for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
++              struct pci_dev_entry *e, *tmp;
++              list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
++                                       list) {
++                      list_del(&e->list);
++                      pcistub_put_pci_dev(e->dev);
++                      kfree(e);
++              }
++      }
++
++      kfree(vpci_dev);
++      pdev->pci_dev_data = NULL;
++}
+--- linux-2.6.18.8/drivers/xen/pciback/xenbus.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pciback/xenbus.c   2008-05-19 00:33:46.270813223 +0300
+@@ -0,0 +1,685 @@
++/*
++ * PCI Backend Xenbus Setup - handles setup with frontend and xend
++ *
++ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/list.h>
++#include <linux/vmalloc.h>
++#include <xen/xenbus.h>
++#include <xen/evtchn.h>
++#include "pciback.h"
++
++#define INVALID_EVTCHN_IRQ  (-1)
++
++static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
++{
++      struct pciback_device *pdev;
++
++      pdev = kzalloc(sizeof(struct pciback_device), GFP_KERNEL);
++      if (pdev == NULL)
++              goto out;
++      dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
++
++      pdev->xdev = xdev;
++      xdev->dev.driver_data = pdev;
++
++      spin_lock_init(&pdev->dev_lock);
++
++      pdev->sh_area = NULL;
++      pdev->sh_info = NULL;
++      pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
++      pdev->be_watching = 0;
++
++      INIT_WORK(&pdev->op_work, pciback_do_op, pdev);
++
++      if (pciback_init_devices(pdev)) {
++              kfree(pdev);
++              pdev = NULL;
++      }
++      out:
++      return pdev;
++}
++
++static void free_pdev(struct pciback_device *pdev)
++{
++      if (pdev->be_watching)
++              unregister_xenbus_watch(&pdev->be_watch);
++
++      /* Ensure the guest can't trigger our handler before removing devices */
++      if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ)
++              unbind_from_irqhandler(pdev->evtchn_irq, pdev);
++
++      /* If the driver domain started an op, make sure we complete it or
++       * delete it before releasing the shared memory */
++      cancel_delayed_work(&pdev->op_work);
++      flush_scheduled_work();
++
++      if (pdev->sh_info)
++              xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_area);
++
++      pciback_release_devices(pdev);
++
++      pdev->xdev->dev.driver_data = NULL;
++      pdev->xdev = NULL;
++
++      kfree(pdev);
++}
++
++static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
++                           int remote_evtchn)
++{
++      int err = 0;
++      struct vm_struct *area;
++
++      dev_dbg(&pdev->xdev->dev,
++              "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
++              gnt_ref, remote_evtchn);
++
++      area = xenbus_map_ring_valloc(pdev->xdev, gnt_ref);
++      if (IS_ERR(area)) {
++              err = PTR_ERR(area);
++              goto out;
++      }
++      pdev->sh_area = area;
++      pdev->sh_info = area->addr;
++
++      err = bind_interdomain_evtchn_to_irqhandler(
++              pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event,
++              SA_SAMPLE_RANDOM, "pciback", pdev);
++      if (err < 0) {
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error binding event channel to IRQ");
++              goto out;
++      }
++      pdev->evtchn_irq = err;
++      err = 0;
++
++      dev_dbg(&pdev->xdev->dev, "Attached!\n");
++      out:
++      return err;
++}
++
++static int pciback_attach(struct pciback_device *pdev)
++{
++      int err = 0;
++      int gnt_ref, remote_evtchn;
++      char *magic = NULL;
++
++      spin_lock(&pdev->dev_lock);
++
++      /* Make sure we only do this setup once */
++      if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++          XenbusStateInitialised)
++              goto out;
++
++      /* Wait for frontend to state that it has published the configuration */
++      if (xenbus_read_driver_state(pdev->xdev->otherend) !=
++          XenbusStateInitialised)
++              goto out;
++
++      dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
++
++      err = xenbus_gather(XBT_NIL, pdev->xdev->otherend,
++                          "pci-op-ref", "%u", &gnt_ref,
++                          "event-channel", "%u", &remote_evtchn,
++                          "magic", NULL, &magic, NULL);
++      if (err) {
++              /* If configuration didn't get read correctly, wait longer */
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error reading configuration from frontend");
++              goto out;
++      }
++
++      if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
++              xenbus_dev_fatal(pdev->xdev, -EFAULT,
++                               "version mismatch (%s/%s) with pcifront - "
++                               "halting pciback",
++                               magic, XEN_PCI_MAGIC);
++              goto out;
++      }
++
++      err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
++      if (err)
++              goto out;
++
++      dev_dbg(&pdev->xdev->dev, "Connecting...\n");
++
++      err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
++      if (err)
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error switching to connected state!");
++
++      dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
++      out:
++      spin_unlock(&pdev->dev_lock);
++
++      if (magic)
++              kfree(magic);
++
++      return err;
++}
++
++static int pciback_publish_pci_dev(struct pciback_device *pdev,
++                                 unsigned int domain, unsigned int bus,
++                                 unsigned int devfn, unsigned int devid)
++{
++      int err;
++      int len;
++      char str[64];
++
++      len = snprintf(str, sizeof(str), "vdev-%d", devid);
++      if (unlikely(len >= (sizeof(str) - 1))) {
++              err = -ENOMEM;
++              goto out;
++      }
++
++      err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
++                          "%04x:%02x:%02x.%02x", domain, bus,
++                          PCI_SLOT(devfn), PCI_FUNC(devfn));
++
++      out:
++      return err;
++}
++
++static int pciback_export_device(struct pciback_device *pdev,
++                               int domain, int bus, int slot, int func,
++                               int devid)
++{
++      struct pci_dev *dev;
++      int err = 0;
++
++      dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
++              domain, bus, slot, func);
++
++      dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);
++      if (!dev) {
++              err = -EINVAL;
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Couldn't locate PCI device "
++                               "(%04x:%02x:%02x.%01x)! "
++                               "perhaps already in-use?",
++                               domain, bus, slot, func);
++              goto out;
++      }
++
++      err = pciback_add_pci_dev(pdev, dev, devid, pciback_publish_pci_dev);
++      if (err)
++              goto out;
++
++      /* TODO: It'd be nice to export a bridge and have all of its children
++       * get exported with it. This may be best done in xend (which will
++       * have to calculate resource usage anyway) but we probably want to
++       * put something in here to ensure that if a bridge gets given to a
++       * driver domain, that all devices under that bridge are not given
++       * to other driver domains (as he who controls the bridge can disable
++       * it and stop the other devices from working).
++       */
++      out:
++      return err;
++}
++
++static int pciback_remove_device(struct pciback_device *pdev,
++                               int domain, int bus, int slot, int func)
++{
++      int err = 0;
++      struct pci_dev *dev;
++
++      dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n",
++              domain, bus, slot, func);
++
++      dev = pciback_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func));
++      if (!dev) {
++              err = -EINVAL;
++              dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device "
++                      "(%04x:%02x:%02x.%01x)! not owned by this domain\n",
++                      domain, bus, slot, func);
++              goto out;
++      }
++
++      pciback_release_pci_dev(pdev, dev);
++      
++      out:
++      return err;
++}
++
++static int pciback_publish_pci_root(struct pciback_device *pdev,
++                                  unsigned int domain, unsigned int bus)
++{
++      unsigned int d, b;
++      int i, root_num, len, err;
++      char str[64];
++
++      dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
++
++      err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++                         "root_num", "%d", &root_num);
++      if (err == 0 || err == -ENOENT)
++              root_num = 0;
++      else if (err < 0)
++              goto out;
++
++      /* Verify that we haven't already published this pci root */
++      for (i = 0; i < root_num; i++) {
++              len = snprintf(str, sizeof(str), "root-%d", i);
++              if (unlikely(len >= (sizeof(str) - 1))) {
++                      err = -ENOMEM;
++                      goto out;
++              }
++
++              err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++                                 str, "%x:%x", &d, &b);
++              if (err < 0)
++                      goto out;
++              if (err != 2) {
++                      err = -EINVAL;
++                      goto out;
++              }
++
++              if (d == domain && b == bus) {
++                      err = 0;
++                      goto out;
++              }
++      }
++
++      len = snprintf(str, sizeof(str), "root-%d", root_num);
++      if (unlikely(len >= (sizeof(str) - 1))) {
++              err = -ENOMEM;
++              goto out;
++      }
++
++      dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
++              root_num, domain, bus);
++
++      err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
++                          "%04x:%02x", domain, bus);
++      if (err)
++              goto out;
++
++      err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
++                          "root_num", "%d", (root_num + 1));
++
++      out:
++      return err;
++}
++
++static int pciback_reconfigure(struct pciback_device *pdev)
++{
++      int err = 0;
++      int num_devs;
++      int domain, bus, slot, func;
++      int substate;
++      int i, len;
++      char state_str[64];
++      char dev_str[64];
++
++      spin_lock(&pdev->dev_lock);
++
++      dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n");
++
++      /* Make sure we only reconfigure once */
++      if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++          XenbusStateReconfiguring)
++              goto out;
++
++      err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
++                         &num_devs);
++      if (err != 1) {
++              if (err >= 0)
++                      err = -EINVAL;
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error reading number of devices");
++              goto out;
++      }
++
++      for (i = 0; i < num_devs; i++) {
++              len = snprintf(state_str, sizeof(state_str), "state-%d", i);
++              if (unlikely(len >= (sizeof(state_str) - 1))) {
++                      err = -ENOMEM;
++                      xenbus_dev_fatal(pdev->xdev, err,
++                                       "String overflow while reading "
++                                       "configuration");
++                      goto out;
++              }
++              err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, state_str,
++                                 "%d", &substate);
++              if (err != 1) 
++                      substate = XenbusStateUnknown;
++
++              switch (substate) {
++              case XenbusStateInitialising:
++                      dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i);
++
++                      len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
++                      if (unlikely(len >= (sizeof(dev_str) - 1))) {
++                              err = -ENOMEM;
++                              xenbus_dev_fatal(pdev->xdev, err,
++                                               "String overflow while "
++                                               "reading configuration");
++                              goto out;
++                      }
++                      err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++                                         dev_str, "%x:%x:%x.%x",
++                                         &domain, &bus, &slot, &func);
++                      if (err < 0) {
++                              xenbus_dev_fatal(pdev->xdev, err,
++                                               "Error reading device "
++                                               "configuration");
++                              goto out;
++                      }
++                      if (err != 4) {
++                              err = -EINVAL;
++                              xenbus_dev_fatal(pdev->xdev, err,
++                                               "Error parsing pci device "
++                                               "configuration");
++                              goto out;
++                      }
++      
++                      err = pciback_export_device(pdev, domain, bus, slot,
++                                                  func, i);
++                      if (err)
++                              goto out;
++
++                      /* Publish pci roots. */
++                      err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
++                      if (err) {
++                              xenbus_dev_fatal(pdev->xdev, err,
++                                               "Error while publish PCI root"
++                                               "buses for frontend");
++                              goto out;
++                      }
++
++                      err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
++                                          state_str, "%d",
++                                          XenbusStateInitialised);
++                      if (err) {
++                              xenbus_dev_fatal(pdev->xdev, err,
++                                               "Error switching substate of "
++                                               "dev-%d\n", i);
++                              goto out;
++                      }       
++                      break;
++
++              case XenbusStateClosing:
++                      dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i);
++
++                      len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i);
++                      if (unlikely(len >= (sizeof(dev_str) - 1))) {
++                              err = -ENOMEM;
++                              xenbus_dev_fatal(pdev->xdev, err,
++                                               "String overflow while "
++                                               "reading configuration");
++                              goto out;
++                      }
++                      err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
++                                         dev_str, "%x:%x:%x.%x",
++                                         &domain, &bus, &slot, &func);
++                      if (err < 0) {
++                              xenbus_dev_fatal(pdev->xdev, err,
++                                               "Error reading device "
++                                               "configuration");
++                              goto out;
++                      }
++                      if (err != 4) {
++                              err = -EINVAL;
++                              xenbus_dev_fatal(pdev->xdev, err,
++                                               "Error parsing pci device "
++                                               "configuration");
++                              goto out;
++                      }
++
++                      err = pciback_remove_device(pdev, domain, bus, slot,
++                                                  func);
++                      if(err)
++                              goto out;
++
++                      /* TODO: If at some point we implement support for pci
++                       * root hot-remove on pcifront side, we'll need to
++                       * remove unnecessary xenstore nodes of pci roots here.
++                       */
++
++                      break;
++
++              default:
++                      break;
++              }
++      }
++
++      err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured);
++      if (err) {
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error switching to reconfigured state!");
++              goto out;
++      }
++      
++      out:
++      spin_unlock(&pdev->dev_lock);
++
++      return 0;
++}
++
++static void pciback_frontend_changed(struct xenbus_device *xdev,
++                                   enum xenbus_state fe_state)
++{
++      struct pciback_device *pdev = xdev->dev.driver_data;
++
++      dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
++
++      switch (fe_state) {
++      case XenbusStateInitialised:
++              pciback_attach(pdev);
++              break;
++
++      case XenbusStateClosing:
++              xenbus_switch_state(xdev, XenbusStateClosed);
++              break;
++
++      case XenbusStateUnknown:
++      case XenbusStateClosed:
++              dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
++              device_unregister(&xdev->dev);
++              break;
++
++      case XenbusStateReconfiguring:
++              pciback_reconfigure(pdev);
++              break;
++
++      case XenbusStateConnected:
++              /* pcifront switched its state from reconfiguring to connected.
++               * Then switch to connected state.
++               */
++              xenbus_switch_state(xdev, XenbusStateConnected);
++              break;
++
++      default:
++              break;
++      }
++}
++
++static int pciback_setup_backend(struct pciback_device *pdev)
++{
++      /* Get configuration from xend (if available now) */
++      int domain, bus, slot, func;
++      int err = 0;
++      int i, num_devs;
++      char dev_str[64];
++      char state_str[64];
++
++      spin_lock(&pdev->dev_lock);
++
++      /* It's possible we could get the call to setup twice, so make sure
++       * we're not already connected.
++       */
++      if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++          XenbusStateInitWait)
++              goto out;
++
++      dev_dbg(&pdev->xdev->dev, "getting be setup\n");
++
++      err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
++                         &num_devs);
++      if (err != 1) {
++              if (err >= 0)
++                      err = -EINVAL;
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error reading number of devices");
++              goto out;
++      }
++
++      for (i = 0; i < num_devs; i++) {
++              int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
++              if (unlikely(l >= (sizeof(dev_str) - 1))) {
++                      err = -ENOMEM;
++                      xenbus_dev_fatal(pdev->xdev, err,
++                                       "String overflow while reading "
++                                       "configuration");
++                      goto out;
++              }
++
++              err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str,
++                                 "%x:%x:%x.%x", &domain, &bus, &slot, &func);
++              if (err < 0) {
++                      xenbus_dev_fatal(pdev->xdev, err,
++                                       "Error reading device configuration");
++                      goto out;
++              }
++              if (err != 4) {
++                      err = -EINVAL;
++                      xenbus_dev_fatal(pdev->xdev, err,
++                                       "Error parsing pci device "
++                                       "configuration");
++                      goto out;
++              }
++
++              err = pciback_export_device(pdev, domain, bus, slot, func, i);
++              if (err)
++                      goto out;
++
++              /* Switch substate of this device. */
++              l = snprintf(state_str, sizeof(state_str), "state-%d", i);
++              if (unlikely(l >= (sizeof(state_str) - 1))) {
++                      err = -ENOMEM;
++                      xenbus_dev_fatal(pdev->xdev, err,
++                                       "String overflow while reading "
++                                       "configuration");
++                      goto out;
++              }
++              err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str,
++                                  "%d", XenbusStateInitialised);
++              if (err) {
++                      xenbus_dev_fatal(pdev->xdev, err, "Error switching "
++                                       "substate of dev-%d\n", i);
++                      goto out;
++              }       
++      }
++
++      err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
++      if (err) {
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error while publish PCI root buses "
++                               "for frontend");
++              goto out;
++      }
++
++      err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
++      if (err)
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error switching to initialised state!");
++
++      out:
++      spin_unlock(&pdev->dev_lock);
++
++      if (!err)
++              /* see if pcifront is already configured (if not, we'll wait) */
++              pciback_attach(pdev);
++
++      return err;
++}
++
++static void pciback_be_watch(struct xenbus_watch *watch,
++                           const char **vec, unsigned int len)
++{
++      struct pciback_device *pdev =
++          container_of(watch, struct pciback_device, be_watch);
++
++      switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
++      case XenbusStateInitWait:
++              pciback_setup_backend(pdev);
++              break;
++
++      default:
++              break;
++      }
++}
++
++static int pciback_xenbus_probe(struct xenbus_device *dev,
++                              const struct xenbus_device_id *id)
++{
++      int err = 0;
++      struct pciback_device *pdev = alloc_pdev(dev);
++
++      if (pdev == NULL) {
++              err = -ENOMEM;
++              xenbus_dev_fatal(dev, err,
++                               "Error allocating pciback_device struct");
++              goto out;
++      }
++
++      /* wait for xend to configure us */
++      err = xenbus_switch_state(dev, XenbusStateInitWait);
++      if (err)
++              goto out;
++
++      /* watch the backend node for backend configuration information */
++      err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
++                              pciback_be_watch);
++      if (err)
++              goto out;
++      pdev->be_watching = 1;
++
++      /* We need to force a call to our callback here in case
++       * xend already configured us!
++       */
++      pciback_be_watch(&pdev->be_watch, NULL, 0);
++
++      out:
++      return err;
++}
++
++static int pciback_xenbus_remove(struct xenbus_device *dev)
++{
++      struct pciback_device *pdev = dev->dev.driver_data;
++
++      if (pdev != NULL)
++              free_pdev(pdev);
++
++      return 0;
++}
++
++static const struct xenbus_device_id xenpci_ids[] = {
++      {"pci"},
++      {{0}},
++};
++
++static struct xenbus_driver xenbus_pciback_driver = {
++      .name                   = "pciback",
++      .owner                  = THIS_MODULE,
++      .ids                    = xenpci_ids,
++      .probe                  = pciback_xenbus_probe,
++      .remove                 = pciback_xenbus_remove,
++      .otherend_changed       = pciback_frontend_changed,
++};
++
++int __init pciback_xenbus_register(void)
++{
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      return xenbus_register_backend(&xenbus_pciback_driver);
++}
++
++void __exit pciback_xenbus_unregister(void)
++{
++      xenbus_unregister_driver(&xenbus_pciback_driver);
++}
+--- linux-2.6.18.8/drivers/xen/pcifront/Makefile       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pcifront/Makefile  2008-05-19 00:33:46.286814145 +0300
+@@ -0,0 +1,7 @@
++obj-y += pcifront.o
++
++pcifront-y := pci_op.o xenbus.o pci.o
++
++ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
++EXTRA_CFLAGS += -DDEBUG
++endif
+--- linux-2.6.18.8/drivers/xen/pcifront/pci.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pcifront/pci.c     2008-05-19 00:33:46.290814376 +0300
+@@ -0,0 +1,46 @@
++/*
++ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
++ *
++ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include "pcifront.h"
++
++DEFINE_SPINLOCK(pcifront_dev_lock);
++static struct pcifront_device *pcifront_dev = NULL;
++
++int pcifront_connect(struct pcifront_device *pdev)
++{
++      int err = 0;
++
++      spin_lock(&pcifront_dev_lock);
++
++      if (!pcifront_dev) {
++              dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
++              pcifront_dev = pdev;
++      }
++      else {
++              dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
++              err = -EEXIST;
++      }
++
++      spin_unlock(&pcifront_dev_lock);
++
++      return err;
++}
++
++void pcifront_disconnect(struct pcifront_device *pdev)
++{
++      spin_lock(&pcifront_dev_lock);
++
++      if (pdev == pcifront_dev) {
++              dev_info(&pdev->xdev->dev,
++                       "Disconnecting PCI Frontend Buses\n");
++              pcifront_dev = NULL;
++      }
++
++      spin_unlock(&pcifront_dev_lock);
++}
+--- linux-2.6.18.8/drivers/xen/pcifront/pci_op.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pcifront/pci_op.c  2008-05-19 00:33:46.290814376 +0300
+@@ -0,0 +1,551 @@
++/*
++ * PCI Frontend Operations - Communicates with frontend
++ *
++ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/version.h>
++#include <linux/init.h>
++#include <linux/pci.h>
++#include <linux/spinlock.h>
++#include <linux/time.h>
++#include <xen/evtchn.h>
++#include "pcifront.h"
++
++static int verbose_request = 0;
++module_param(verbose_request, int, 0644);
++
++#ifdef __ia64__
++static void pcifront_init_sd(struct pcifront_sd *sd,
++                           unsigned int domain, unsigned int bus,
++                           struct pcifront_device *pdev)
++{
++      int err, i, j, k, len, root_num, res_count;
++      struct acpi_resource res;
++      unsigned int d, b, byte;
++      unsigned long magic;
++      char str[64], tmp[3];
++      unsigned char *buf, *bufp;
++      u8 *ptr;
++
++      memset(sd, 0, sizeof(*sd));
++
++      sd->segment = domain;
++      sd->node = -1;  /* Revisit for NUMA */
++      sd->platform_data = pdev;
++
++      /* Look for resources for this controller in xenbus. */
++      err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, "root_num",
++                         "%d", &root_num);
++      if (err != 1)
++              return;
++
++      for (i = 0; i < root_num; i++) {
++              len = snprintf(str, sizeof(str), "root-%d", i);
++              if (unlikely(len >= (sizeof(str) - 1)))
++                      return;
++
++              err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
++                                 str, "%x:%x", &d, &b);
++              if (err != 2)
++                      return;
++
++              if (d == domain && b == bus)
++                      break;
++      }
++
++      if (i == root_num)
++              return;
++
++      len = snprintf(str, sizeof(str), "root-resource-magic");
++
++      err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
++                         str, "%lx", &magic);
++
++      if (err != 1)
++              return; /* No resources, nothing to do */
++
++      if (magic != (sizeof(res) * 2) + 1) {
++              printk(KERN_WARNING "pcifront: resource magic mismatch\n");
++              return;
++      }
++
++      len = snprintf(str, sizeof(str), "root-%d-resources", i);
++      if (unlikely(len >= (sizeof(str) - 1)))
++              return;
++
++      err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
++                         str, "%d", &res_count);
++
++      if (err != 1)
++              return; /* No resources, nothing to do */
++
++      sd->window = kzalloc(sizeof(*sd->window) * res_count, GFP_KERNEL);
++      if (!sd->window)
++              return;
++
++      /* magic is also the size of the byte stream in xenbus */
++      buf = kmalloc(magic, GFP_KERNEL);
++      if (!buf) {
++              kfree(sd->window);
++              sd->window = NULL;
++              return;
++      }
++
++      /* Read the resources out of xenbus */
++      for (j = 0; j < res_count; j++) {
++              memset(&res, 0, sizeof(res));
++              memset(buf, 0, magic);
++
++              len = snprintf(str, sizeof(str), "root-%d-resource-%d", i, j);
++              if (unlikely(len >= (sizeof(str) - 1)))
++                      return;
++
++              err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str,
++                                 "%s", buf);
++              if (err != 1) {
++                      printk(KERN_WARNING "pcifront: error reading "
++                             "resource %d on bus %04x:%02x\n",
++                             j, domain, bus);
++                      continue;
++              }
++
++              bufp = buf;
++              ptr = (u8 *)&res;
++              memset(tmp, 0, sizeof(tmp));
++
++              /* Copy ASCII byte stream into structure */
++              for (k = 0; k < magic - 1; k += 2) {
++                      memcpy(tmp, bufp, 2);
++                      bufp += 2;
++
++                      sscanf(tmp, "%02x", &byte);
++                      *ptr = byte;
++                      ptr++;
++              }
++
++              xen_add_resource(sd, domain, bus, &res);
++              sd->windows++;
++      }
++      kfree(buf);
++}
++#endif
++
++static int errno_to_pcibios_err(int errno)
++{
++      switch (errno) {
++      case XEN_PCI_ERR_success:
++              return PCIBIOS_SUCCESSFUL;
++
++      case XEN_PCI_ERR_dev_not_found:
++              return PCIBIOS_DEVICE_NOT_FOUND;
++
++      case XEN_PCI_ERR_invalid_offset:
++      case XEN_PCI_ERR_op_failed:
++              return PCIBIOS_BAD_REGISTER_NUMBER;
++
++      case XEN_PCI_ERR_not_implemented:
++              return PCIBIOS_FUNC_NOT_SUPPORTED;
++
++      case XEN_PCI_ERR_access_denied:
++              return PCIBIOS_SET_FAILED;
++      }
++      return errno;
++}
++
++static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
++{
++      int err = 0;
++      struct xen_pci_op *active_op = &pdev->sh_info->op;
++      unsigned long irq_flags;
++      evtchn_port_t port = pdev->evtchn;
++      s64 ns, ns_timeout;
++      struct timeval tv;
++
++      spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
++
++      memcpy(active_op, op, sizeof(struct xen_pci_op));
++
++      /* Go */
++      wmb();
++      set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
++      notify_remote_via_evtchn(port);
++
++      /*
++       * We set a poll timeout of 3 seconds but give up on return after
++       * 2 seconds. It is better to time out too late rather than too early
++       * (in the latter case we end up continually re-executing poll() with a
++       * timeout in the past). 1s difference gives plenty of slack for error.
++       */
++      do_gettimeofday(&tv);
++      ns_timeout = timeval_to_ns(&tv) + 2 * (s64)NSEC_PER_SEC;
++
++      clear_evtchn(port);
++
++      while (test_bit(_XEN_PCIF_active,
++                      (unsigned long *)&pdev->sh_info->flags)) {
++              if (HYPERVISOR_poll(&port, 1, jiffies + 3*HZ))
++                      BUG();
++              clear_evtchn(port);
++              do_gettimeofday(&tv);
++              ns = timeval_to_ns(&tv);
++              if (ns > ns_timeout) {
++                      dev_err(&pdev->xdev->dev,
++                              "pciback not responding!!!\n");
++                      clear_bit(_XEN_PCIF_active,
++                                (unsigned long *)&pdev->sh_info->flags);
++                      err = XEN_PCI_ERR_dev_not_found;
++                      goto out;
++              }
++      }
++
++      memcpy(op, active_op, sizeof(struct xen_pci_op));
++
++      err = op->err;
++      out:
++      spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
++      return err;
++}
++
++/* Access to this function is spinlocked in drivers/pci/access.c */
++static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
++                           int where, int size, u32 * val)
++{
++      int err = 0;
++      struct xen_pci_op op = {
++              .cmd    = XEN_PCI_OP_conf_read,
++              .domain = pci_domain_nr(bus),
++              .bus    = bus->number,
++              .devfn  = devfn,
++              .offset = where,
++              .size   = size,
++      };
++      struct pcifront_sd *sd = bus->sysdata;
++      struct pcifront_device *pdev = pcifront_get_pdev(sd);
++
++      if (verbose_request)
++              dev_info(&pdev->xdev->dev,
++                       "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
++                       pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
++                       PCI_FUNC(devfn), where, size);
++
++      err = do_pci_op(pdev, &op);
++
++      if (likely(!err)) {
++              if (verbose_request)
++                      dev_info(&pdev->xdev->dev, "read got back value %x\n",
++                               op.value);
++
++              *val = op.value;
++      } else if (err == -ENODEV) {
++              /* No device here, pretend that it just returned 0 */
++              err = 0;
++              *val = 0;
++      }
++
++      return errno_to_pcibios_err(err);
++}
++
++/* Access to this function is spinlocked in drivers/pci/access.c */
++static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
++                            int where, int size, u32 val)
++{
++      struct xen_pci_op op = {
++              .cmd    = XEN_PCI_OP_conf_write,
++              .domain = pci_domain_nr(bus),
++              .bus    = bus->number,
++              .devfn  = devfn,
++              .offset = where,
++              .size   = size,
++              .value  = val,
++      };
++      struct pcifront_sd *sd = bus->sysdata;
++      struct pcifront_device *pdev = pcifront_get_pdev(sd);
++
++      if (verbose_request)
++              dev_info(&pdev->xdev->dev,
++                       "write dev=%04x:%02x:%02x.%01x - "
++                       "offset %x size %d val %x\n",
++                       pci_domain_nr(bus), bus->number,
++                       PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
++
++      return errno_to_pcibios_err(do_pci_op(pdev, &op));
++}
++
++struct pci_ops pcifront_bus_ops = {
++      .read = pcifront_bus_read,
++      .write = pcifront_bus_write,
++};
++
++#ifdef CONFIG_PCI_MSI
++int pci_frontend_enable_msix(struct pci_dev *dev,
++              struct msix_entry *entries,
++              int nvec)
++{
++      int err;
++      int i;
++      struct xen_pci_op op = {
++              .cmd    = XEN_PCI_OP_enable_msix,
++              .domain = pci_domain_nr(dev->bus),
++              .bus = dev->bus->number,
++              .devfn = dev->devfn,
++              .value = nvec,
++      };
++      struct pcifront_sd *sd = dev->bus->sysdata;
++      struct pcifront_device *pdev = pcifront_get_pdev(sd);
++
++      if (nvec > SH_INFO_MAX_VEC) {
++              printk("too much vector for pci frontend%x\n", nvec);
++              return -EINVAL;
++      }
++
++      for (i = 0; i < nvec; i++) {
++              op.msix_entries[i].entry = entries[i].entry;
++              op.msix_entries[i].vector = entries[i].vector;
++      }
++
++      err = do_pci_op(pdev, &op);
++
++      if (!err) {
++              if (!op.value) {
++                      /* we get the result */
++                      for ( i = 0; i < nvec; i++)
++                              entries[i].vector = op.msix_entries[i].vector;
++                      return 0;
++              }
++              else {
++            printk("enable msix get value %x\n", op.value);
++                      return op.value;
++              }
++      }
++      else {
++        printk("enable msix get err %x\n", err);
++              return err;
++      }
++}
++
++void pci_frontend_disable_msix(struct pci_dev* dev)
++{
++      int err;
++      struct xen_pci_op op = {
++              .cmd    = XEN_PCI_OP_disable_msix,
++              .domain = pci_domain_nr(dev->bus),
++              .bus = dev->bus->number,
++              .devfn = dev->devfn,
++      };
++      struct pcifront_sd *sd = dev->bus->sysdata;
++      struct pcifront_device *pdev = pcifront_get_pdev(sd);
++
++      err = do_pci_op(pdev, &op);
++
++      /* What should do for error ? */
++      if (err)
++              printk("pci_disable_msix get err %x\n", err);
++}
++
++int pci_frontend_enable_msi(struct pci_dev *dev)
++{
++      int err;
++      struct xen_pci_op op = {
++              .cmd    = XEN_PCI_OP_enable_msi,
++              .domain = pci_domain_nr(dev->bus),
++              .bus = dev->bus->number,
++              .devfn = dev->devfn,
++      };
++      struct pcifront_sd *sd = dev->bus->sysdata;
++      struct pcifront_device *pdev = pcifront_get_pdev(sd);
++
++      err = do_pci_op(pdev, &op);
++      if (likely(!err)) {
++              dev->irq = op.value;
++      }
++      else {
++              printk("pci frontend enable msi failed for dev %x:%x \n",
++                              op.bus, op.devfn);
++              err = -EINVAL;
++      }
++      return err;
++}
++
++void pci_frontend_disable_msi(struct pci_dev* dev)
++{
++      int err;
++      struct xen_pci_op op = {
++              .cmd    = XEN_PCI_OP_disable_msi,
++              .domain = pci_domain_nr(dev->bus),
++              .bus = dev->bus->number,
++              .devfn = dev->devfn,
++      };
++      struct pcifront_sd *sd = dev->bus->sysdata;
++      struct pcifront_device *pdev = pcifront_get_pdev(sd);
++
++      err = do_pci_op(pdev, &op);
++      if (err == XEN_PCI_ERR_dev_not_found) {
++              /* XXX No response from backend, what shall we do? */
++              printk("get no response from backend for disable MSI\n");
++              return;
++      }
++      if (likely(!err))
++              dev->irq = op.value;
++      else
++              /* how can pciback notify us fail? */
++              printk("get fake response frombackend \n");
++}
++#endif /* CONFIG_PCI_MSI */
++
++/* Claim resources for the PCI frontend as-is, backend won't allow changes */
++static void pcifront_claim_resource(struct pci_dev *dev, void *data)
++{
++      struct pcifront_device *pdev = data;
++      int i;
++      struct resource *r;
++
++      for (i = 0; i < PCI_NUM_RESOURCES; i++) {
++              r = &dev->resource[i];
++
++              if (!r->parent && r->start && r->flags) {
++                      dev_dbg(&pdev->xdev->dev, "claiming resource %s/%d\n",
++                              pci_name(dev), i);
++                      pci_claim_resource(dev, i);
++              }
++      }
++}
++
++int __devinit pcifront_scan_root(struct pcifront_device *pdev,
++                               unsigned int domain, unsigned int bus)
++{
++      struct pci_bus *b;
++      struct pcifront_sd *sd = NULL;
++      struct pci_bus_entry *bus_entry = NULL;
++      int err = 0;
++
++#ifndef CONFIG_PCI_DOMAINS
++      if (domain != 0) {
++              dev_err(&pdev->xdev->dev,
++                      "PCI Root in non-zero PCI Domain! domain=%d\n", domain);
++              dev_err(&pdev->xdev->dev,
++                      "Please compile with CONFIG_PCI_DOMAINS\n");
++              err = -EINVAL;
++              goto err_out;
++      }
++#endif
++
++      dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
++               domain, bus);
++
++      bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
++      sd = kmalloc(sizeof(*sd), GFP_KERNEL);
++      if (!bus_entry || !sd) {
++              err = -ENOMEM;
++              goto err_out;
++      }
++      pcifront_init_sd(sd, domain, bus, pdev);
++
++      b = pci_scan_bus_parented(&pdev->xdev->dev, bus,
++                                &pcifront_bus_ops, sd);
++      if (!b) {
++              dev_err(&pdev->xdev->dev,
++                      "Error creating PCI Frontend Bus!\n");
++              err = -ENOMEM;
++              goto err_out;
++      }
++
++      pcifront_setup_root_resources(b, sd);
++      bus_entry->bus = b;
++
++      list_add(&bus_entry->list, &pdev->root_buses);
++
++      /* Claim resources before going "live" with our devices */
++      pci_walk_bus(b, pcifront_claim_resource, pdev);
++
++      pci_bus_add_devices(b);
++
++      return 0;
++
++      err_out:
++      kfree(bus_entry);
++      kfree(sd);
++
++      return err;
++}
++
++int __devinit pcifront_rescan_root(struct pcifront_device *pdev,
++                                 unsigned int domain, unsigned int bus)
++{
++      struct pci_bus *b;
++      struct pci_dev *d;
++      unsigned int devfn;
++
++#ifndef CONFIG_PCI_DOMAINS
++      if (domain != 0) {
++              dev_err(&pdev->xdev->dev,
++                      "PCI Root in non-zero PCI Domain! domain=%d\n", domain);
++              dev_err(&pdev->xdev->dev,
++                      "Please compile with CONFIG_PCI_DOMAINS\n");
++              return -EINVAL;
++      }
++#endif
++
++      dev_info(&pdev->xdev->dev, "Rescanning PCI Frontend Bus %04x:%02x\n",
++               domain, bus);
++
++      b = pci_find_bus(domain, bus);
++      if(!b)
++              /* If the bus is unknown, create it. */
++              return pcifront_scan_root(pdev, domain, bus);
++
++      /* Rescan the bus for newly attached functions and add.
++       * We omit handling of PCI bridge attachment because pciback prevents
++       * bridges from being exported.
++       */ 
++      for (devfn = 0; devfn < 0x100; devfn++) {
++              d = pci_get_slot(b, devfn);
++              if(d) {
++                      /* Device is already known. */
++                      pci_dev_put(d);
++                      continue;
++              }
++
++              d = pci_scan_single_device(b, devfn);
++              if (d) {
++                      dev_info(&pdev->xdev->dev, "New device on "
++                               "%04x:%02x:%02x.%02x found.\n", domain, bus,
++                               PCI_SLOT(devfn), PCI_FUNC(devfn));
++                      pci_bus_add_device(d);
++              }
++      }
++
++      return 0;
++}
++
++static void free_root_bus_devs(struct pci_bus *bus)
++{
++      struct pci_dev *dev;
++
++      while (!list_empty(&bus->devices)) {
++              dev = container_of(bus->devices.next, struct pci_dev,
++                                 bus_list);
++              dev_dbg(&dev->dev, "removing device\n");
++              pci_remove_bus_device(dev);
++      }
++}
++
++void pcifront_free_roots(struct pcifront_device *pdev)
++{
++      struct pci_bus_entry *bus_entry, *t;
++
++      dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n");
++
++      list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
++              list_del(&bus_entry->list);
++
++              free_root_bus_devs(bus_entry->bus);
++
++              kfree(bus_entry->bus->sysdata);
++
++              device_unregister(bus_entry->bus->bridge);
++              pci_remove_bus(bus_entry->bus);
++
++              kfree(bus_entry);
++      }
++}
+--- linux-2.6.18.8/drivers/xen/pcifront/pcifront.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pcifront/pcifront.h        2008-05-19 00:33:46.290814376 +0300
+@@ -0,0 +1,42 @@
++/*
++ * PCI Frontend - Common data structures & function declarations
++ *
++ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++#ifndef __XEN_PCIFRONT_H__
++#define __XEN_PCIFRONT_H__
++
++#include <linux/spinlock.h>
++#include <linux/pci.h>
++#include <xen/xenbus.h>
++#include <xen/interface/io/pciif.h>
++#include <xen/pcifront.h>
++
++struct pci_bus_entry {
++      struct list_head list;
++      struct pci_bus *bus;
++};
++
++struct pcifront_device {
++      struct xenbus_device *xdev;
++      struct list_head root_buses;
++      spinlock_t dev_lock;
++
++      int evtchn;
++      int gnt_ref;
++
++      /* Lock this when doing any operations in sh_info */
++      spinlock_t sh_info_lock;
++      struct xen_pci_sharedinfo *sh_info;
++};
++
++int pcifront_connect(struct pcifront_device *pdev);
++void pcifront_disconnect(struct pcifront_device *pdev);
++
++int pcifront_scan_root(struct pcifront_device *pdev,
++                     unsigned int domain, unsigned int bus);
++int pcifront_rescan_root(struct pcifront_device *pdev,
++                       unsigned int domain, unsigned int bus);
++void pcifront_free_roots(struct pcifront_device *pdev);
++
++#endif        /* __XEN_PCIFRONT_H__ */
+--- linux-2.6.18.8/drivers/xen/pcifront/xenbus.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/pcifront/xenbus.c  2008-05-19 00:33:46.318815990 +0300
+@@ -0,0 +1,454 @@
++/*
++ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
++ *
++ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/mm.h>
++#include <xen/xenbus.h>
++#include <xen/gnttab.h>
++#include "pcifront.h"
++
++#ifndef __init_refok
++#define __init_refok
++#endif
++
++#define INVALID_GRANT_REF (0)
++#define INVALID_EVTCHN    (-1)
++
++static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
++{
++      struct pcifront_device *pdev;
++
++      pdev = kzalloc(sizeof(struct pcifront_device), GFP_KERNEL);
++      if (pdev == NULL)
++              goto out;
++
++      pdev->sh_info =
++          (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
++      if (pdev->sh_info == NULL) {
++              kfree(pdev);
++              pdev = NULL;
++              goto out;
++      }
++      pdev->sh_info->flags = 0;
++
++      xdev->dev.driver_data = pdev;
++      pdev->xdev = xdev;
++
++      INIT_LIST_HEAD(&pdev->root_buses);
++
++      spin_lock_init(&pdev->dev_lock);
++      spin_lock_init(&pdev->sh_info_lock);
++
++      pdev->evtchn = INVALID_EVTCHN;
++      pdev->gnt_ref = INVALID_GRANT_REF;
++
++      dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
++              pdev, pdev->sh_info);
++      out:
++      return pdev;
++}
++
++static void free_pdev(struct pcifront_device *pdev)
++{
++      dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
++
++      pcifront_free_roots(pdev);
++
++      if (pdev->evtchn != INVALID_EVTCHN)
++              xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
++
++      if (pdev->gnt_ref != INVALID_GRANT_REF)
++              gnttab_end_foreign_access(pdev->gnt_ref,
++                                        (unsigned long)pdev->sh_info);
++
++      pdev->xdev->dev.driver_data = NULL;
++
++      kfree(pdev);
++}
++
++static int pcifront_publish_info(struct pcifront_device *pdev)
++{
++      int err = 0;
++      struct xenbus_transaction trans;
++
++      err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
++      if (err < 0)
++              goto out;
++
++      pdev->gnt_ref = err;
++
++      err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
++      if (err)
++              goto out;
++
++      do_publish:
++      err = xenbus_transaction_start(&trans);
++      if (err) {
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error writing configuration for backend "
++                               "(start transaction)");
++              goto out;
++      }
++
++      err = xenbus_printf(trans, pdev->xdev->nodename,
++                          "pci-op-ref", "%u", pdev->gnt_ref);
++      if (!err)
++              err = xenbus_printf(trans, pdev->xdev->nodename,
++                                  "event-channel", "%u", pdev->evtchn);
++      if (!err)
++              err = xenbus_printf(trans, pdev->xdev->nodename,
++                                  "magic", XEN_PCI_MAGIC);
++
++      if (err) {
++              xenbus_transaction_end(trans, 1);
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error writing configuration for backend");
++              goto out;
++      } else {
++              err = xenbus_transaction_end(trans, 0);
++              if (err == -EAGAIN)
++                      goto do_publish;
++              else if (err) {
++                      xenbus_dev_fatal(pdev->xdev, err,
++                                       "Error completing transaction "
++                                       "for backend");
++                      goto out;
++              }
++      }
++
++      xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
++
++      dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
++
++      out:
++      return err;
++}
++
++static int __devinit pcifront_try_connect(struct pcifront_device *pdev)
++{
++      int err = -EFAULT;
++      int i, num_roots, len;
++      char str[64];
++      unsigned int domain, bus;
++
++      spin_lock(&pdev->dev_lock);
++
++      /* Only connect once */
++      if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++          XenbusStateInitialised)
++              goto out;
++
++      err = pcifront_connect(pdev);
++      if (err) {
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error connecting PCI Frontend");
++              goto out;
++      }
++
++      err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
++                         "root_num", "%d", &num_roots);
++      if (err == -ENOENT) {
++              xenbus_dev_error(pdev->xdev, err,
++                               "No PCI Roots found, trying 0000:00");
++              err = pcifront_scan_root(pdev, 0, 0);
++              num_roots = 0;
++      } else if (err != 1) {
++              if (err == 0)
++                      err = -EINVAL;
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error reading number of PCI roots");
++              goto out;
++      }
++
++      for (i = 0; i < num_roots; i++) {
++              len = snprintf(str, sizeof(str), "root-%d", i);
++              if (unlikely(len >= (sizeof(str) - 1))) {
++                      err = -ENOMEM;
++                      goto out;
++              }
++
++              err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str,
++                                 "%x:%x", &domain, &bus);
++              if (err != 2) {
++                      if (err >= 0)
++                              err = -EINVAL;
++                      xenbus_dev_fatal(pdev->xdev, err,
++                                       "Error reading PCI root %d", i);
++                      goto out;
++              }
++
++              err = pcifront_scan_root(pdev, domain, bus);
++              if (err) {
++                      xenbus_dev_fatal(pdev->xdev, err,
++                                       "Error scanning PCI root %04x:%02x",
++                                       domain, bus);
++                      goto out;
++              }
++      }
++
++      err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
++      if (err)
++              goto out;
++
++      out:
++      spin_unlock(&pdev->dev_lock);
++      return err;
++}
++
++static int pcifront_try_disconnect(struct pcifront_device *pdev)
++{
++      int err = 0;
++      enum xenbus_state prev_state;
++
++      spin_lock(&pdev->dev_lock);
++
++      prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
++
++      if (prev_state < XenbusStateClosing)
++              err = xenbus_switch_state(pdev->xdev, XenbusStateClosing);
++
++      if (!err && prev_state == XenbusStateConnected)
++              pcifront_disconnect(pdev);
++
++      spin_unlock(&pdev->dev_lock);
++
++      return err;
++}
++
++static int __devinit pcifront_attach_devices(struct pcifront_device *pdev)
++{
++      int err = -EFAULT;
++      int i, num_roots, len;
++      unsigned int domain, bus;
++      char str[64];
++
++      spin_lock(&pdev->dev_lock);
++
++      if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++          XenbusStateReconfiguring)
++              goto out;
++
++      err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
++                         "root_num", "%d", &num_roots);
++      if (err == -ENOENT) {
++              xenbus_dev_error(pdev->xdev, err,
++                               "No PCI Roots found, trying 0000:00");
++              err = pcifront_rescan_root(pdev, 0, 0);
++              num_roots = 0;
++      } else if (err != 1) {
++              if (err == 0)
++                      err = -EINVAL;
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error reading number of PCI roots");
++              goto out;
++      }
++
++      for (i = 0; i < num_roots; i++) {
++              len = snprintf(str, sizeof(str), "root-%d", i);
++              if (unlikely(len >= (sizeof(str) - 1))) {
++                      err = -ENOMEM;
++                      goto out;
++              }
++
++              err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str,
++                                 "%x:%x", &domain, &bus);
++              if (err != 2) {
++                      if (err >= 0)
++                              err = -EINVAL;
++                      xenbus_dev_fatal(pdev->xdev, err,
++                                       "Error reading PCI root %d", i);
++                      goto out;
++              }
++
++              err = pcifront_rescan_root(pdev, domain, bus);
++              if (err) {
++                      xenbus_dev_fatal(pdev->xdev, err,
++                                       "Error scanning PCI root %04x:%02x",
++                                       domain, bus);
++                      goto out;
++              }
++      }
++
++      xenbus_switch_state(pdev->xdev, XenbusStateConnected);
++
++      out:
++      spin_unlock(&pdev->dev_lock);
++      return err;
++}
++
++static int pcifront_detach_devices(struct pcifront_device *pdev)
++{
++      int err = 0;
++      int i, num_devs;
++      unsigned int domain, bus, slot, func;
++      struct pci_bus *pci_bus;
++      struct pci_dev *pci_dev;
++      char str[64];
++
++      spin_lock(&pdev->dev_lock);
++
++      if (xenbus_read_driver_state(pdev->xdev->nodename) !=
++          XenbusStateConnected)
++              goto out;
++
++      err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, "num_devs", "%d",
++                         &num_devs);
++      if (err != 1) {
++              if (err >= 0)
++                      err = -EINVAL;
++              xenbus_dev_fatal(pdev->xdev, err,
++                               "Error reading number of PCI devices");
++              goto out;
++      }
++
++      /* Find devices being detached and remove them. */
++      for (i = 0; i < num_devs; i++) {
++              int l, state;
++              l = snprintf(str, sizeof(str), "state-%d", i);
++              if (unlikely(l >= (sizeof(str) - 1))) {
++                      err = -ENOMEM;
++                      goto out;
++              }
++              err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, "%d",
++                                 &state);
++              if (err != 1)
++                      state = XenbusStateUnknown;
++
++              if (state != XenbusStateClosing)
++                      continue;
++
++              /* Remove device. */
++              l = snprintf(str, sizeof(str), "vdev-%d", i);
++              if (unlikely(l >= (sizeof(str) - 1))) {
++                      err = -ENOMEM;
++                      goto out;
++              }
++              err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str,
++                                 "%x:%x:%x.%x", &domain, &bus, &slot, &func);
++              if (err != 4) {
++                      if (err >= 0)
++                              err = -EINVAL;
++                      xenbus_dev_fatal(pdev->xdev, err,
++                                       "Error reading PCI device %d", i);
++                      goto out;
++              }
++
++              pci_bus = pci_find_bus(domain, bus);
++              if(!pci_bus) {
++                      dev_dbg(&pdev->xdev->dev, "Cannot get bus %04x:%02x\n",
++                              domain, bus);
++                      continue;
++              }
++              pci_dev = pci_get_slot(pci_bus, PCI_DEVFN(slot, func));
++              if(!pci_dev) {
++                      dev_dbg(&pdev->xdev->dev,
++                              "Cannot get PCI device %04x:%02x:%02x.%02x\n",
++                              domain, bus, slot, func);
++                      continue;
++              }
++              pci_remove_bus_device(pci_dev);
++              pci_dev_put(pci_dev);
++
++              dev_dbg(&pdev->xdev->dev,
++                      "PCI device %04x:%02x:%02x.%02x removed.\n",
++                      domain, bus, slot, func);
++      }
++
++      err = xenbus_switch_state(pdev->xdev, XenbusStateReconfiguring);
++
++      out:
++      spin_unlock(&pdev->dev_lock);
++      return err;
++}
++
++static void __init_refok pcifront_backend_changed(struct xenbus_device *xdev,
++                                                enum xenbus_state be_state)
++{
++      struct pcifront_device *pdev = xdev->dev.driver_data;
++
++      switch (be_state) {
++      case XenbusStateClosing:
++              dev_warn(&xdev->dev, "backend going away!\n");
++              pcifront_try_disconnect(pdev);
++              break;
++
++      case XenbusStateUnknown:
++      case XenbusStateClosed:
++              dev_warn(&xdev->dev, "backend went away!\n");
++              pcifront_try_disconnect(pdev);
++
++              device_unregister(&pdev->xdev->dev);
++              break;
++
++      case XenbusStateConnected:
++              pcifront_try_connect(pdev);
++              break;
++
++      case XenbusStateReconfiguring:
++              pcifront_detach_devices(pdev);
++              break;
++
++      case XenbusStateReconfigured:
++              pcifront_attach_devices(pdev);
++              break;
++
++      default:
++              break;
++      }
++}
++
++static int pcifront_xenbus_probe(struct xenbus_device *xdev,
++                               const struct xenbus_device_id *id)
++{
++      int err = 0;
++      struct pcifront_device *pdev = alloc_pdev(xdev);
++
++      if (pdev == NULL) {
++              err = -ENOMEM;
++              xenbus_dev_fatal(xdev, err,
++                               "Error allocating pcifront_device struct");
++              goto out;
++      }
++
++      err = pcifront_publish_info(pdev);
++
++      out:
++      return err;
++}
++
++static int pcifront_xenbus_remove(struct xenbus_device *xdev)
++{
++      if (xdev->dev.driver_data)
++              free_pdev(xdev->dev.driver_data);
++
++      return 0;
++}
++
++static const struct xenbus_device_id xenpci_ids[] = {
++      {"pci"},
++      {{0}},
++};
++MODULE_ALIAS("xen:pci");
++
++static struct xenbus_driver xenbus_pcifront_driver = {
++      .name                   = "pcifront",
++      .owner                  = THIS_MODULE,
++      .ids                    = xenpci_ids,
++      .probe                  = pcifront_xenbus_probe,
++      .remove                 = pcifront_xenbus_remove,
++      .otherend_changed       = pcifront_backend_changed,
++};
++
++static int __init pcifront_init(void)
++{
++      if (!is_running_on_xen())
++              return -ENODEV;
++
++      return xenbus_register_frontend(&xenbus_pcifront_driver);
++}
++
++/* Initialize after the Xen PCI Frontend Stub is initialized */
++subsys_initcall(pcifront_init);
+--- linux-2.6.18.8/drivers/xen/privcmd/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/privcmd/Makefile   2008-05-19 00:33:46.322816221 +0300
+@@ -0,0 +1,3 @@
++
++obj-y += privcmd.o
++obj-$(CONFIG_COMPAT)  += compat_privcmd.o
+--- linux-2.6.18.8/drivers/xen/privcmd/compat_privcmd.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/privcmd/compat_privcmd.c   2008-05-19 00:33:46.346817604 +0300
+@@ -0,0 +1,73 @@
++/*
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
++ *
++ * Copyright (C) IBM Corp. 2006
++ *
++ * Authors: Jimi Xenidis <jimix@watson.ibm.com>
++ */
++
++#include <linux/config.h>
++#include <linux/compat.h>
++#include <linux/ioctl.h>
++#include <linux/syscalls.h>
++#include <asm/hypervisor.h>
++#include <asm/uaccess.h>
++#include <xen/public/privcmd.h>
++#include <xen/compat_ioctl.h>
++
++int privcmd_ioctl_32(int fd, unsigned int cmd, unsigned long arg)
++{
++      int ret;
++
++      switch (cmd) {
++      case IOCTL_PRIVCMD_MMAP_32: {
++              struct privcmd_mmap *p;
++              struct privcmd_mmap_32 *p32;
++              struct privcmd_mmap_32 n32;
++
++              p32 = compat_ptr(arg);
++              p = compat_alloc_user_space(sizeof(*p));
++              if (copy_from_user(&n32, p32, sizeof(n32)) ||
++                  put_user(n32.num, &p->num) ||
++                  put_user(n32.dom, &p->dom) ||
++                  put_user(compat_ptr(n32.entry), &p->entry))
++                      return -EFAULT;
++              
++              ret = sys_ioctl(fd, IOCTL_PRIVCMD_MMAP, (unsigned long)p);
++      }
++              break;
++      case IOCTL_PRIVCMD_MMAPBATCH_32: {
++              struct privcmd_mmapbatch *p;
++              struct privcmd_mmapbatch_32 *p32;
++              struct privcmd_mmapbatch_32 n32;
++
++              p32 = compat_ptr(arg);
++              p = compat_alloc_user_space(sizeof(*p));
++              if (copy_from_user(&n32, p32, sizeof(n32)) ||
++                  put_user(n32.num, &p->num) ||
++                  put_user(n32.dom, &p->dom) ||
++                  put_user(n32.addr, &p->addr) ||
++                  put_user(compat_ptr(n32.arr), &p->arr))
++                      return -EFAULT;
++              
++              ret = sys_ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, (unsigned long)p);
++      }
++              break;
++      default:
++              ret = -EINVAL;
++              break;
++      }
++      return ret;
++}
+--- linux-2.6.18.8/drivers/xen/privcmd/privcmd.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/privcmd/privcmd.c  2008-05-19 00:33:46.350817835 +0300
+@@ -0,0 +1,284 @@
++/******************************************************************************
++ * privcmd.c
++ * 
++ * Interface to privileged domain-0 commands.
++ * 
++ * Copyright (c) 2002-2004, K A Fraser, B Dragovic
++ */
++
++#include <linux/kernel.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/string.h>
++#include <linux/errno.h>
++#include <linux/mm.h>
++#include <linux/mman.h>
++#include <linux/swap.h>
++#include <linux/smp_lock.h>
++#include <linux/highmem.h>
++#include <linux/pagemap.h>
++#include <linux/seq_file.h>
++#include <asm/hypervisor.h>
++
++#include <asm/pgalloc.h>
++#include <asm/pgtable.h>
++#include <asm/uaccess.h>
++#include <asm/tlb.h>
++#include <asm/hypervisor.h>
++#include <xen/public/privcmd.h>
++#include <xen/interface/xen.h>
++#include <xen/xen_proc.h>
++#include <xen/features.h>
++
++static struct proc_dir_entry *privcmd_intf;
++static struct proc_dir_entry *capabilities_intf;
++
++#ifndef HAVE_ARCH_PRIVCMD_MMAP
++static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
++#endif
++
++static long privcmd_ioctl(struct file *file,
++                        unsigned int cmd, unsigned long data)
++{
++      int ret = -ENOSYS;
++      void __user *udata = (void __user *) data;
++
++      switch (cmd) {
++      case IOCTL_PRIVCMD_HYPERCALL: {
++              privcmd_hypercall_t hypercall;
++  
++              if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
++                      return -EFAULT;
++
++#if defined(__i386__)
++              if (hypercall.op >= (PAGE_SIZE >> 5))
++                      break;
++              __asm__ __volatile__ (
++                      "pushl %%ebx; pushl %%ecx; pushl %%edx; "
++                      "pushl %%esi; pushl %%edi; "
++                      "movl  8(%%eax),%%ebx ;"
++                      "movl 16(%%eax),%%ecx ;"
++                      "movl 24(%%eax),%%edx ;"
++                      "movl 32(%%eax),%%esi ;"
++                      "movl 40(%%eax),%%edi ;"
++                      "movl   (%%eax),%%eax ;"
++                      "shll $5,%%eax ;"
++                      "addl $hypercall_page,%%eax ;"
++                      "call *%%eax ;"
++                      "popl %%edi; popl %%esi; popl %%edx; "
++                      "popl %%ecx; popl %%ebx"
++                      : "=a" (ret) : "0" (&hypercall) : "memory" );
++#elif defined (__x86_64__)
++              if (hypercall.op < (PAGE_SIZE >> 5)) {
++                      long ign1, ign2, ign3;
++                      __asm__ __volatile__ (
++                              "movq %8,%%r10; movq %9,%%r8;"
++                              "shll $5,%%eax ;"
++                              "addq $hypercall_page,%%rax ;"
++                              "call *%%rax"
++                              : "=a" (ret), "=D" (ign1),
++                                "=S" (ign2), "=d" (ign3)
++                              : "0" ((unsigned int)hypercall.op),
++                              "1" (hypercall.arg[0]),
++                              "2" (hypercall.arg[1]),
++                              "3" (hypercall.arg[2]),
++                              "g" (hypercall.arg[3]),
++                              "g" (hypercall.arg[4])
++                              : "r8", "r10", "memory" );
++              }
++#else
++              ret = privcmd_hypercall(&hypercall);
++#endif
++      }
++      break;
++
++      case IOCTL_PRIVCMD_MMAP: {
++              privcmd_mmap_t mmapcmd;
++              privcmd_mmap_entry_t msg;
++              privcmd_mmap_entry_t __user *p;
++              struct mm_struct *mm = current->mm;
++              struct vm_area_struct *vma;
++              unsigned long va;
++              int i, rc;
++
++              if (!is_initial_xendomain())
++                      return -EPERM;
++
++              if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
++                      return -EFAULT;
++
++              p = mmapcmd.entry;
++              if (copy_from_user(&msg, p, sizeof(msg)))
++                      return -EFAULT;
++
++              down_write(&mm->mmap_sem);
++
++              vma = find_vma(mm, msg.va);
++              rc = -EINVAL;
++              if (!vma || (msg.va != vma->vm_start) ||
++                  !privcmd_enforce_singleshot_mapping(vma))
++                      goto mmap_out;
++
++              va = vma->vm_start;
++
++              for (i = 0; i < mmapcmd.num; i++) {
++                      rc = -EFAULT;
++                      if (copy_from_user(&msg, p, sizeof(msg)))
++                              goto mmap_out;
++
++                      /* Do not allow range to wrap the address space. */
++                      rc = -EINVAL;
++                      if ((msg.npages > (LONG_MAX >> PAGE_SHIFT)) ||
++                          ((unsigned long)(msg.npages << PAGE_SHIFT) >= -va))
++                              goto mmap_out;
++
++                      /* Range chunks must be contiguous in va space. */
++                      if ((msg.va != va) ||
++                          ((msg.va+(msg.npages<<PAGE_SHIFT)) > vma->vm_end))
++                              goto mmap_out;
++
++                      if ((rc = direct_remap_pfn_range(
++                              vma,
++                              msg.va & PAGE_MASK, 
++                              msg.mfn, 
++                              msg.npages << PAGE_SHIFT, 
++                              vma->vm_page_prot,
++                              mmapcmd.dom)) < 0)
++                              goto mmap_out;
++
++                      p++;
++                      va += msg.npages << PAGE_SHIFT;
++              }
++
++              rc = 0;
++
++      mmap_out:
++              up_write(&mm->mmap_sem);
++              ret = rc;
++      }
++      break;
++
++      case IOCTL_PRIVCMD_MMAPBATCH: {
++              privcmd_mmapbatch_t m;
++              struct mm_struct *mm = current->mm;
++              struct vm_area_struct *vma;
++              xen_pfn_t __user *p;
++              unsigned long addr, mfn, nr_pages;
++              int i;
++
++              if (!is_initial_xendomain())
++                      return -EPERM;
++
++              if (copy_from_user(&m, udata, sizeof(m)))
++                      return -EFAULT;
++
++              nr_pages = m.num;
++              if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
++                      return -EINVAL;
++
++              down_write(&mm->mmap_sem);
++
++              vma = find_vma(mm, m.addr);
++              if (!vma ||
++                  (m.addr != vma->vm_start) ||
++                  ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
++                  !privcmd_enforce_singleshot_mapping(vma)) {
++                      up_write(&mm->mmap_sem);
++                      return -EINVAL;
++              }
++
++              p = m.arr;
++              addr = m.addr;
++              for (i = 0; i < nr_pages; i++, addr += PAGE_SIZE, p++) {
++                      if (get_user(mfn, p)) {
++                              up_write(&mm->mmap_sem);
++                              return -EFAULT;
++                      }
++
++                      ret = direct_remap_pfn_range(vma, addr & PAGE_MASK,
++                                                   mfn, PAGE_SIZE,
++                                                   vma->vm_page_prot, m.dom);
++                      if (ret < 0)
++                              put_user(0xF0000000 | mfn, p);
++              }
++
++              up_write(&mm->mmap_sem);
++              ret = 0;
++      }
++      break;
++
++      default:
++              ret = -EINVAL;
++              break;
 +      }
 +
-+      xenbus_switch_state(dev, XenbusStateInitialised);
++      return ret;
++}
++
++#ifndef HAVE_ARCH_PRIVCMD_MMAP
++static struct page *privcmd_nopage(struct vm_area_struct *vma,
++                                 unsigned long address,
++                                 int *type)
++{
++      return NOPAGE_SIGBUS;
++}
++
++static struct vm_operations_struct privcmd_vm_ops = {
++      .nopage = privcmd_nopage
++};
++
++static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
++{
++      /* Unsupported for auto-translate guests. */
++      if (xen_feature(XENFEAT_auto_translated_physmap))
++              return -ENOSYS;
++
++      /* DONTCOPY is essential for Xen as copy_page_range is broken. */
++      vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
++      vma->vm_ops = &privcmd_vm_ops;
++      vma->vm_private_data = NULL;
++
 +      return 0;
++}
 +
-+ error_xenbus:
-+      xenbus_transaction_end(xbt, 1);
-+      xenbus_dev_fatal(dev, ret, "writing xenstore");
-+      return ret;
++static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
++{
++      return (xchg(&vma->vm_private_data, (void *)1) == NULL);
 +}
++#endif
 +
-+static void xenkbd_disconnect_backend(struct xenkbd_info *info)
++static const struct file_operations privcmd_file_ops = {
++      .unlocked_ioctl = privcmd_ioctl,
++      .mmap = privcmd_mmap,
++};
++
++static int capabilities_read(char *page, char **start, off_t off,
++                           int count, int *eof, void *data)
 +{
-+      if (info->irq >= 0)
-+              unbind_from_irqhandler(info->irq, info);
-+      info->irq = -1;
++      int len = 0;
++      *page = 0;
++
++      if (is_initial_xendomain())
++              len = sprintf( page, "control_d\n" );
++
++      *eof = 1;
++      return len;
 +}
 +
-+static void xenkbd_backend_changed(struct xenbus_device *dev,
-+                                 enum xenbus_state backend_state)
++static int __init privcmd_init(void)
 +{
-+      struct xenkbd_info *info = dev->dev.driver_data;
-+      int ret, val;
++      if (!is_running_on_xen())
++              return -ENODEV;
 +
-+      switch (backend_state) {
-+      case XenbusStateInitialising:
-+      case XenbusStateInitialised:
-+      case XenbusStateUnknown:
-+      case XenbusStateClosed:
-+              break;
++      privcmd_intf = create_xen_proc_entry("privcmd", 0400);
++      if (privcmd_intf != NULL)
++              privcmd_intf->proc_fops = &privcmd_file_ops;
 +
-+      case XenbusStateInitWait:
-+      InitWait:
-+              ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
-+                                 "feature-abs-pointer", "%d", &val);
-+              if (ret < 0)
-+                      val = 0;
-+              if (val) {
-+                      ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
-+                                          "request-abs-pointer", "1");
-+                      if (ret)
-+                              ; /* FIXME */
-+              }
-+              xenbus_switch_state(dev, XenbusStateConnected);
-+              break;
++      capabilities_intf = create_xen_proc_entry("capabilities", 0400 );
++      if (capabilities_intf != NULL)
++              capabilities_intf->read_proc = capabilities_read;
 +
-+      case XenbusStateConnected:
-+              /*
-+               * Work around xenbus race condition: If backend goes
-+               * through InitWait to Connected fast enough, we can
-+               * get Connected twice here.
-+               */
-+              if (dev->state != XenbusStateConnected)
-+                      goto InitWait; /* no InitWait seen yet, fudge it */
-+              break;
++      return 0;
++}
 +
-+      case XenbusStateClosing:
-+              xenbus_frontend_closed(dev);
-+              break;
++__initcall(privcmd_init);
+--- linux-2.6.18.8/drivers/xen/sfc_netback/Makefile    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/Makefile       2008-05-19 00:33:46.354818065 +0300
+@@ -0,0 +1,12 @@
++EXTRA_CFLAGS += -Idrivers/xen/sfc_netback -Idrivers/xen/sfc_netutil -Idrivers/xen/netback -Idrivers/net/sfc
++EXTRA_CFLAGS += -D__ci_driver__ 
++EXTRA_CFLAGS += -DEFX_USE_KCOMPAT
++EXTRA_CFLAGS += -Werror
++
++ifdef GCOV
++EXTRA_CFLAGS += -fprofile-arcs -ftest-coverage -DEFX_GCOV
++endif
++
++obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND) := sfc_netback.o
++
++sfc_netback-objs   := accel.o accel_fwd.o accel_msg.o accel_solarflare.o accel_xenbus.o accel_debugfs.o
+--- linux-2.6.18.8/drivers/xen/sfc_netback/accel.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/accel.c        2008-05-19 00:33:46.414821524 +0300
+@@ -0,0 +1,129 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#include "accel.h"
++#include "accel_msg_iface.h"
++#include "accel_solarflare.h"
++
++#include <linux/notifier.h>
++
++#ifdef EFX_GCOV
++#include "gcov.h"
++#endif
++
++static int netback_accel_netdev_event(struct notifier_block *nb,
++                                    unsigned long event, void *ptr)
++{
++      struct net_device *net_dev = (struct net_device *)ptr;
++      struct netback_accel *bend;
++
++      if ((event == NETDEV_UP) || (event == NETDEV_DOWN)) {
++              mutex_lock(&bend_list_mutex);
++              bend = bend_list;
++              while (bend != NULL) {
++                      mutex_lock(&bend->bend_mutex);
++                      /*
++                       * This happens when the shared pages have
++                       * been unmapped, but the bend not yet removed
++                       * from list
++                       */
++                      if (bend->shared_page == NULL)
++                              goto next;
++
++                      if (bend->net_dev->ifindex == net_dev->ifindex)
++                              netback_accel_set_interface_state
++                                      (bend, event == NETDEV_UP);
++
++              next:
++                      mutex_unlock(&bend->bend_mutex);
++                      bend = bend->next_bend;
++              }
++              mutex_unlock(&bend_list_mutex);
 +      }
++
++      return NOTIFY_DONE;
 +}
 +
-+static struct xenbus_device_id xenkbd_ids[] = {
-+      { "vkbd" },
-+      { "" }
-+};
-+MODULE_ALIAS("xen:vkbd");
 +
-+static struct xenbus_driver xenkbd = {
-+      .name = "vkbd",
-+      .owner = THIS_MODULE,
-+      .ids = xenkbd_ids,
-+      .probe = xenkbd_probe,
-+      .remove = xenkbd_remove,
-+      .resume = xenkbd_resume,
-+      .otherend_changed = xenkbd_backend_changed,
++static struct notifier_block netback_accel_netdev_notifier = {
++      .notifier_call = netback_accel_netdev_event,
 +};
 +
-+static int __init xenkbd_init(void)
++
++unsigned sfc_netback_max_pages = NETBACK_ACCEL_DEFAULT_MAX_BUF_PAGES;
++module_param_named(max_pages, sfc_netback_max_pages, uint, 0644);
++MODULE_PARM_DESC(max_pages, 
++               "The number of buffer pages to enforce on each guest");
++
++/* Initialise subsystems need for the accelerated fast path */
++static int __init netback_accel_init(void)
 +{
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++      int rc = 0;
 +
-+      /* Nothing to do if running in dom0. */
-+      if (is_initial_xendomain())
-+              return -ENODEV;
++#ifdef EFX_GCOV
++      gcov_provider_init(THIS_MODULE);
++#endif
 +
-+      return xenbus_register_frontend(&xenkbd);
++      rc = netback_accel_init_fwd();
++
++      if (rc == 0)
++              netback_accel_debugfs_init();
++
++      if (rc == 0)
++              rc = netback_accel_sf_init();
++
++      if (rc == 0)
++              rc = register_netdevice_notifier
++                      (&netback_accel_netdev_notifier);
++
++      /*
++       * What if no device was found, shouldn't we clean up stuff
++       * we've allocated for acceleration subsystem?
++       */
++
++      return rc;
 +}
 +
-+static void __exit xenkbd_cleanup(void)
++module_init(netback_accel_init);
++
++static void __exit netback_accel_exit(void)
 +{
-+      return xenbus_unregister_driver(&xenkbd);
++      unregister_netdevice_notifier(&netback_accel_netdev_notifier);
++
++      netback_accel_sf_shutdown();
++
++      netback_accel_shutdown_bends();
++
++      netback_accel_debugfs_fini();
++
++      netback_accel_shutdown_fwd();
++
++#ifdef EFX_GCOV
++      gcov_provider_fini(THIS_MODULE);
++#endif
 +}
 +
-+module_init(xenkbd_init);
-+module_exit(xenkbd_cleanup);
++module_exit(netback_accel_exit);
 +
 +MODULE_LICENSE("GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/gntdev/gntdev.c linux-2.6.18-xen.hg/drivers/xen/gntdev/gntdev.c
---- linux-2.6.18/drivers/xen/gntdev/gntdev.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/gntdev/gntdev.c    2007-12-23 11:15:34.051268764 +0100
-@@ -0,0 +1,973 @@
-+/******************************************************************************
-+ * gntdev.c
-+ * 
-+ * Device for accessing (in user-space) pages that have been granted by other
-+ * domains.
+--- linux-2.6.18.8/drivers/xen/sfc_netback/accel.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/accel.h        2008-05-19 00:33:46.414821524 +0300
+@@ -0,0 +1,393 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
 + *
-+ * Copyright (c) 2006-2007, D G Murray.
-+ * 
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef NETBACK_ACCEL_H
++#define NETBACK_ACCEL_H
++
++#include <linux/slab.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <linux/in.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
++#include <linux/mutex.h>
++#include <linux/wait.h>
++
++#include <xen/xenbus.h>
++
++#include "accel_shared_fifo.h"
++#include "accel_msg_iface.h"
++#include "accel_util.h"
++
++/**************************************************************************
++ * Datatypes
++ **************************************************************************/
++
++#define NETBACK_ACCEL_DEFAULT_MAX_FILTERS (8)
++#define NETBACK_ACCEL_DEFAULT_MAX_MCASTS (8)
++#define NETBACK_ACCEL_DEFAULT_MAX_BUF_PAGES (384)
++/* Variable to store module parameter for max_buf_pages */
++extern unsigned sfc_netback_max_pages;
++
++#define NETBACK_ACCEL_STATS 1
++
++#if NETBACK_ACCEL_STATS
++#define NETBACK_ACCEL_STATS_OP(x) x
++#else
++#define NETBACK_ACCEL_STATS_OP(x)
++#endif
++
++/*! Statistics for a given backend */
++struct netback_accel_stats {
++      /*! Number of eventq wakeup events */
++      u64 evq_wakeups;
++      /*! Number of eventq timeout events */
++      u64 evq_timeouts;
++      /*! Number of filters used */
++      u32 num_filters;
++      /*! Number of buffer pages registered */
++      u32 num_buffer_pages;
++};
++
++
++/* Debug fs nodes for each of the above stats */
++struct netback_accel_dbfs {
++      struct dentry *evq_wakeups;
++      struct dentry *evq_timeouts;
++      struct dentry *num_filters;
++      struct dentry *num_buffer_pages;
++};
++
++
++/*! Resource limits for a given NIC */
++struct netback_accel_limits {
++      int max_filters;            /*!< Max. number of filters to use. */
++      int max_mcasts;      /*!< Max. number  of mcast subscriptions */
++      int max_buf_pages;        /*!< Max. number of pages of NIC buffers */
++};
++
++
++/*! The state for an instance of the back end driver. */
++struct netback_accel {
++      /*! mutex to protect this state */
++      struct mutex bend_mutex;
++
++      /*! Watches on xenstore */
++      struct xenbus_watch domu_accel_watch;
++      struct xenbus_watch config_accel_watch;
++
++      /*! Pointer to whatever device cookie ties us in to the hypervisor */
++      void *hdev_data;
++
++      /*! FIFO indices. Next page is msg FIFOs */
++      struct net_accel_shared_page *shared_page;
++
++      /*! Defer control message processing */
++      struct work_struct handle_msg;
++
++      /*! Identifies other end VM and interface.*/
++      int far_end;
++      int vif_num;
++
++      /*!< To unmap the shared pages */
++      void *sh_pages_unmap;
++
++      /* Resource tracking */
++      /*! Limits on H/W & Dom0 resources */
++      struct netback_accel_limits quotas;
++
++      /* Hardware resources */
++      /*! The H/W type of associated NIC */
++      enum net_accel_hw_type hw_type;
++      /*! State of allocation */             
++      int hw_state;
++      /*! Index into ci_driver.nics[] for this interface */
++      int nic_index;
++      /*! How to set up the acceleration for this hardware */
++      int (*accel_setup)(struct netback_accel *); 
++      /*! And how to stop it. */
++      void (*accel_shutdown)(struct netback_accel *);
++
++      /*! The physical/real net_dev for this interface */
++      struct net_device *net_dev;
++
++      /*! Magic pointer to locate state in fowarding table */
++      void *fwd_priv;
++
++      /*! Message FIFO */
++      sh_msg_fifo2 to_domU;
++      /*! Message FIFO */
++      sh_msg_fifo2 from_domU;
++
++      /*! General notification channel id */
++      int msg_channel;
++      /*! General notification channel irq */
++      int msg_channel_irq;
++
++      /*! Event channel id dedicated to network packet interrupts. */
++      int net_channel; 
++      /*! Event channel irq dedicated to network packets interrupts */
++      int net_channel_irq; 
++
++      /*! The MAC address the frontend goes by. */
++      u8 mac[ETH_ALEN];
++      /*! Driver name of associated NIC */
++      char *nicname;    
++
++      /*! Array of pointers to buffer pages mapped */
++      grant_handle_t *buffer_maps; 
++      u64 *buffer_addrs;
++      /*! Index into buffer_maps */
++      int buffer_maps_index; 
++      /*! Max number of pages that domU is allowed/will request to map */
++      int max_pages; 
++
++      /*! Pointer to hardware specific private area */
++      void *accel_hw_priv; 
++
++      /*! Wait queue for changes in accelstate. */
++      wait_queue_head_t state_wait_queue;
++
++      /*! Current state of the frontend according to the xenbus
++       *  watch. */
++      XenbusState frontend_state;
++
++      /*! Current state of this backend. */
++      XenbusState backend_state;
++
++      /*! Non-zero if the backend is being removed. */
++      int removing;
++
++      /*! Non-zero if the setup_vnic has been called. */
++      int vnic_is_setup;
++
++#if NETBACK_ACCEL_STATS
++      struct netback_accel_stats stats;
++#endif        
++#if defined(CONFIG_DEBUG_FS)
++      char *dbfs_dir_name;
++      struct dentry *dbfs_dir;
++      struct netback_accel_dbfs dbfs;
++#endif
++
++      /*! List */
++      struct netback_accel *next_bend;
++};
++
++
++/*
++ * Values for netback_accel.hw_state.  States of resource allocation
++ * we can go through
++ */
++/*! No hardware has yet been allocated. */
++#define NETBACK_ACCEL_RES_NONE  (0)
++/*! Hardware has been allocated. */
++#define NETBACK_ACCEL_RES_ALLOC (1)
++#define NETBACK_ACCEL_RES_FILTER (2)
++#define NETBACK_ACCEL_RES_HWINFO (3)
++
++/*! Filtering specification. This assumes that for VNIC support we
++ *  will always want wildcard entries, so only specifies the
++ *  destination IP/port
++ */
++struct netback_accel_filter_spec {
++      /*! Internal, used to access efx_vi API */
++      void *filter_handle; 
++
++      /*! Destination IP in network order */
++      u32 destip_be;
++      /*! Destination port in network order */
++      u16 destport_be;
++      /*! Mac address */
++      u8  mac[ETH_ALEN];
++      /*! TCP or UDP */
++      u8  proto;      
++};
++
++
++/**************************************************************************
++ * From accel.c
++ **************************************************************************/
++
++/*! \brief Start up all the acceleration plugins 
++ *
++ * \return 0 on success, an errno on failure
++ */
++extern int netback_accel_init_accel(void);
++
++/*! \brief Shut down all the acceleration plugins 
++ */
++extern void netback_accel_shutdown_accel(void);
++
++
++/**************************************************************************
++ * From accel_fwd.c
++ **************************************************************************/
++
++/*! \brief Init the forwarding infrastructure
++ * \return 0 on success, or -ENOMEM if it couldn't get memory for the
++ * forward table 
++ */
++extern int netback_accel_init_fwd(void);
++
++/*! \brief Shut down the forwarding and free memory. */
++extern void netback_accel_shutdown_fwd(void);
++
++/*! Initialise each nic port's fowarding table */
++extern void *netback_accel_init_fwd_port(void);
++extern void netback_accel_shutdown_fwd_port(void *fwd_priv);
++
++/*! \brief Add an entry to the forwarding table. 
++ * \param mac : MAC address, used as hash key
++ * \param ctxt : value to associate with key (can be NULL, see
++ * netback_accel_fwd_set_context)
++ * \return 0 on success, -ENOMEM if table was full and could no grow it
++ */
++extern int netback_accel_fwd_add(const __u8 *mac, void *context,
++                               void *fwd_priv);
++
++/*! \brief Remove an entry from the forwarding table. 
++ * \param mac : the MAC address to remove
++ * \return nothing: it is not an error if the mac was not in the table
++ */
++extern void netback_accel_fwd_remove(const __u8 *mac, void *fwd_priv);
++
++/*! \brief Set the context pointer for an existing fwd table entry.
++ * \param mac : key that is already present in the table
++ * \param context : new value to associate with key
++ * \return 0 on success, -ENOENT if mac not present in table.
++ */
++extern int netback_accel_fwd_set_context(const __u8 *mac, void *context,
++                                       void *fwd_priv);
++
++/**************************************************************************
++ * From accel_msg.c
++ **************************************************************************/
++
++
++/*! \brief Send the start-of-day message that handshakes with the VNIC
++ *  and tells it its MAC address.
++ *
++ * \param bend The back end driver data structure
++ * \param version The version of communication to use, e.g. NET_ACCEL_MSG_VERSION
++ */
++extern void netback_accel_msg_tx_hello(struct netback_accel *bend,
++                                     unsigned version);
++
++/*! \brief Send a "there's a new local mac address" message 
++ *
++ * \param bend The back end driver data structure for the vnic to send
++ * the message to 
++ * \param mac Pointer to the new mac address
++ */
++extern void netback_accel_msg_tx_new_localmac(struct netback_accel *bend,
++                                            const void *mac);
++
++/*! \brief Send a "a mac address that was local has gone away" message 
++ *
++ * \param bend The back end driver data structure for the vnic to send
++ * the message to 
++ * \param mac Pointer to the old mac address
++ */
++extern void netback_accel_msg_tx_old_localmac(struct netback_accel *bend,
++                                            const void *mac);
++
++extern void netback_accel_set_interface_state(struct netback_accel *bend,
++                                            int up);
++
++/*! \brief Process the message queue for a bend that has just
++ * interrupted.
++ * 
++ * Demultiplexs an interrupt from the front end driver, taking
++ * messages from the fifo and taking appropriate action.
 + * 
++ * \param bend The back end driver data structure
++ */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++extern void netback_accel_msg_rx_handler(struct work_struct *arg);
++#else
++extern void netback_accel_msg_rx_handler(void *bend_void);
++#endif
++
++/**************************************************************************
++ * From accel_xenbus.c
++ **************************************************************************/
++/*! List of all the bends currently in existence. */
++extern struct netback_accel *bend_list;
++extern struct mutex bend_list_mutex;
++
++/*! \brief Probe a new network interface. */
++extern int netback_accel_probe(struct xenbus_device *dev);
++
++/*! \brief Remove a network interface. */
++extern int netback_accel_remove(struct xenbus_device *dev);
++
++/*! \brief Shutdown all accelerator backends */
++extern void netback_accel_shutdown_bends(void);
++
++/*! \brief Initiate the xenbus state teardown handshake */
++extern void netback_accel_set_closing(struct netback_accel *bend);
++
++/**************************************************************************
++ * From accel_debugfs.c
++ **************************************************************************/
++/*! Global statistics */
++struct netback_accel_global_stats {
++      /*! Number of TX packets seen through driverlink */
++      u64 dl_tx_packets;
++      /*! Number of TX packets seen through driverlink we didn't like */
++      u64 dl_tx_bad_packets;
++      /*! Number of RX packets seen through driverlink */
++      u64 dl_rx_packets;
++      /*! Number of mac addresses we are forwarding to */
++      u32 num_fwds;
++};
++
++/*! Debug fs entries for each of the above stats */
++struct netback_accel_global_dbfs {
++      struct dentry *dl_tx_packets;
++      struct dentry *dl_tx_bad_packets;
++      struct dentry *dl_rx_packets;
++      struct dentry *num_fwds;
++};
++
++#if NETBACK_ACCEL_STATS
++extern struct netback_accel_global_stats global_stats;
++#endif
++
++/*! \brief Initialise the debugfs root and populate with global stats */
++extern void netback_accel_debugfs_init(void);
++
++/*! \brief Remove our debugfs root directory */
++extern void netback_accel_debugfs_fini(void);
++
++/*! \brief Add per-bend statistics to debug fs */
++extern int netback_accel_debugfs_create(struct netback_accel *bend);
++/*! \brief Remove per-bend statistics from debug fs */
++extern int netback_accel_debugfs_remove(struct netback_accel *bend);
++
++#endif /* NETBACK_ACCEL_H */
++
++
+--- linux-2.6.18.8/drivers/xen/sfc_netback/accel_debugfs.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/accel_debugfs.c        2008-05-19 00:33:46.418821755 +0300
+@@ -0,0 +1,148 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <asm/atomic.h>
-+#include <linux/module.h>
-+#include <linux/kernel.h>
-+#include <linux/init.h>
 +#include <linux/fs.h>
-+#include <linux/device.h>
-+#include <linux/mm.h>
-+#include <linux/mman.h>
-+#include <asm/uaccess.h>
-+#include <asm/io.h>
-+#include <xen/gnttab.h>
-+#include <asm/hypervisor.h>
-+#include <xen/balloon.h>
-+#include <xen/evtchn.h>
-+#include <xen/driver_util.h>
++#include <linux/debugfs.h>
 +
-+#include <linux/types.h>
-+#include <xen/public/gntdev.h>
++#include "accel.h"
 +
++#if defined(CONFIG_DEBUG_FS)
++static struct dentry *sfc_debugfs_root = NULL;
++#endif
 +
-+#define DRIVER_AUTHOR "Derek G. Murray <Derek.Murray@cl.cam.ac.uk>"
-+#define DRIVER_DESC   "User-space granted page access driver"
++#if NETBACK_ACCEL_STATS
++struct netback_accel_global_stats global_stats;
++#if defined(CONFIG_DEBUG_FS)
++static struct netback_accel_global_dbfs  global_dbfs;
++#endif
++#endif
 +
-+MODULE_LICENSE("GPL");
-+MODULE_AUTHOR(DRIVER_AUTHOR);
-+MODULE_DESCRIPTION(DRIVER_DESC);
++void netback_accel_debugfs_init(void) 
++{
++#if defined(CONFIG_DEBUG_FS)
++      sfc_debugfs_root = debugfs_create_dir("sfc_netback", NULL);
++      if (sfc_debugfs_root == NULL)
++              return;
 +
-+#define MAX_GRANTS 128
++      global_dbfs.num_fwds = debugfs_create_u32
++              ("num_fwds", S_IRUSR | S_IRGRP | S_IROTH,
++               sfc_debugfs_root, &global_stats.num_fwds);
++      global_dbfs.dl_tx_packets = debugfs_create_u64
++              ("dl_tx_packets", S_IRUSR | S_IRGRP | S_IROTH,
++               sfc_debugfs_root, &global_stats.dl_tx_packets);
++      global_dbfs.dl_rx_packets = debugfs_create_u64
++              ("dl_rx_packets", S_IRUSR | S_IRGRP | S_IROTH,
++               sfc_debugfs_root, &global_stats.dl_rx_packets);
++      global_dbfs.dl_tx_bad_packets = debugfs_create_u64
++              ("dl_tx_bad_packets", S_IRUSR | S_IRGRP | S_IROTH,
++               sfc_debugfs_root, &global_stats.dl_tx_bad_packets);
++#endif
++}
 +
-+/* A slot can be in one of three states:
++
++void netback_accel_debugfs_fini(void)
++{
++#if defined(CONFIG_DEBUG_FS)
++      debugfs_remove(global_dbfs.num_fwds);
++      debugfs_remove(global_dbfs.dl_tx_packets);
++      debugfs_remove(global_dbfs.dl_rx_packets);
++      debugfs_remove(global_dbfs.dl_tx_bad_packets);
++
++      debugfs_remove(sfc_debugfs_root);
++#endif
++}
++
++
++int netback_accel_debugfs_create(struct netback_accel *bend)
++{
++#if defined(CONFIG_DEBUG_FS)
++      /* Smallest length is 7 (vif0.0\n) */
++      int length = 7, temp;
++
++      if (sfc_debugfs_root == NULL)
++              return -ENOENT;
++
++      /* Work out length of string representation of far_end and vif_num */
++      temp = bend->far_end;
++      while (temp > 9) {
++              length++;
++              temp = temp / 10;
++      }
++      temp = bend->vif_num;
++      while (temp > 9) {
++              length++;
++              temp = temp / 10;
++      }
++
++      bend->dbfs_dir_name = kmalloc(length, GFP_KERNEL);
++      if (bend->dbfs_dir_name == NULL)
++              return -ENOMEM;
++      sprintf(bend->dbfs_dir_name, "vif%d.%d", bend->far_end, bend->vif_num);
++
++      bend->dbfs_dir = debugfs_create_dir(bend->dbfs_dir_name, 
++                                          sfc_debugfs_root);
++      if (bend->dbfs_dir == NULL) {
++              kfree(bend->dbfs_dir_name);
++              return -ENOMEM;
++      }
++
++#if NETBACK_ACCEL_STATS
++      bend->dbfs.evq_wakeups = debugfs_create_u64
++              ("evq_wakeups", S_IRUSR | S_IRGRP | S_IROTH,
++               bend->dbfs_dir, &bend->stats.evq_wakeups);
++      bend->dbfs.evq_timeouts = debugfs_create_u64
++              ("evq_timeouts", S_IRUSR | S_IRGRP | S_IROTH,
++               bend->dbfs_dir, &bend->stats.evq_timeouts);
++      bend->dbfs.num_filters = debugfs_create_u32
++              ("num_filters", S_IRUSR | S_IRGRP | S_IROTH,
++               bend->dbfs_dir, &bend->stats.num_filters);
++      bend->dbfs.num_buffer_pages = debugfs_create_u32
++              ("num_buffer_pages", S_IRUSR | S_IRGRP | S_IROTH,
++               bend->dbfs_dir, &bend->stats.num_buffer_pages);
++#endif
++#endif
++        return 0;
++}
++
++
++int netback_accel_debugfs_remove(struct netback_accel *bend)
++{
++#if defined(CONFIG_DEBUG_FS)
++      if (bend->dbfs_dir != NULL) {
++#if NETBACK_ACCEL_STATS
++              debugfs_remove(bend->dbfs.evq_wakeups);
++              debugfs_remove(bend->dbfs.evq_timeouts);
++              debugfs_remove(bend->dbfs.num_filters);
++              debugfs_remove(bend->dbfs.num_buffer_pages);
++#endif
++              debugfs_remove(bend->dbfs_dir);
++      }
++
++      if (bend->dbfs_dir_name)
++              kfree(bend->dbfs_dir_name);
++#endif
++        return 0;
++}
++
++
+--- linux-2.6.18.8/drivers/xen/sfc_netback/accel_fwd.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/accel_fwd.c    2008-05-19 00:33:46.510827058 +0300
+@@ -0,0 +1,420 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
 + *
-+ * 0. GNTDEV_SLOT_INVALID:
-+ *    This slot is not associated with a grant reference, and is therefore free
-+ *    to be overwritten by a new grant reference.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
 + *
-+ * 1. GNTDEV_SLOT_NOT_YET_MAPPED:
-+ *    This slot is associated with a grant reference (via the 
-+ *    IOCTL_GNTDEV_MAP_GRANT_REF ioctl), but it has not yet been mmap()-ed.
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
 + *
-+ * 2. GNTDEV_SLOT_MAPPED:
-+ *    This slot is associated with a grant reference, and has been mmap()-ed.
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
-+typedef enum gntdev_slot_state {
-+      GNTDEV_SLOT_INVALID = 0,
-+      GNTDEV_SLOT_NOT_YET_MAPPED,
-+      GNTDEV_SLOT_MAPPED
-+} gntdev_slot_state_t;
 +
-+#define GNTDEV_INVALID_HANDLE    -1
-+#define GNTDEV_FREE_LIST_INVALID -1
-+/* Each opened instance of gntdev is associated with a list of grants,
-+ * represented by an array of elements of the following type,
-+ * gntdev_grant_info_t.
-+ */
-+typedef struct gntdev_grant_info {
-+      gntdev_slot_state_t state;
-+      union {
-+              uint32_t free_list_index;
-+              struct {
-+                      domid_t domid;
-+                      grant_ref_t ref;
-+                      grant_handle_t kernel_handle;
-+                      grant_handle_t user_handle;
-+                      uint64_t dev_bus_addr;
-+              } valid;
-+      } u;
-+} gntdev_grant_info_t;
++#include "accel.h"
++#include "accel_cuckoo_hash.h"
++#include "accel_util.h"
++#include "accel_solarflare.h"
 +
-+/* Private data structure, which is stored in the file pointer for files
-+ * associated with this device.
++#include "driverlink_api.h"
++
++#include <linux/if_arp.h>
++#include <linux/skbuff.h>
++#include <linux/list.h>
++
++/* State stored in the forward table */
++struct fwd_struct {
++      struct list_head link; /* Forms list */
++      void * context;
++      __u8 valid;
++      __u8 mac[ETH_ALEN];
++};
++
++/* Max value we support */
++#define NUM_FWDS_BITS 8
++#define NUM_FWDS (1 << NUM_FWDS_BITS)
++#define FWD_MASK (NUM_FWDS - 1)
++
++struct port_fwd {
++      /* Make a list */
++      struct list_head link;
++      /* Hash table to store the fwd_structs */
++      cuckoo_hash_table fwd_hash_table;
++      /* The array of fwd_structs */
++      struct fwd_struct *fwd_array;
++      /* Linked list of entries in use. */
++      struct list_head fwd_list;
++      /* Could do something clever with a reader/writer lock. */
++      spinlock_t fwd_lock;
++      /* Make find_free_entry() a bit faster by caching this */
++      int last_free_index;
++};
++
++/*
++ * This is unlocked as it's only called from dl probe and remove,
++ * which are themselves synchronised.  Could get rid of it entirely as
++ * it's never iterated, but useful for debug
 + */
-+typedef struct gntdev_file_private_data {
-+  
-+      /* Array of grant information. */
-+      gntdev_grant_info_t grants[MAX_GRANTS];
++static struct list_head port_fwds;
 +
-+      /* Read/write semaphore used to protect the grants array. */
-+      struct rw_semaphore grants_sem;
 +
-+      /* An array of indices of free slots in the grants array.
-+       * N.B. An entry in this list may temporarily have the value
-+       * GNTDEV_FREE_LIST_INVALID if the corresponding slot has been removed
-+       * from the list by the contiguous allocator, but the list has not yet
-+       * been compressed. However, this is not visible across invocations of
-+       * the device.
-+       */
-+      int32_t free_list[MAX_GRANTS];
++/* Search the fwd_array for an unused entry */
++static int fwd_find_free_entry(struct port_fwd *fwd_set)
++{
++      int index = fwd_set->last_free_index;
++
++      do {
++              if (!fwd_set->fwd_array[index].valid) {
++                      fwd_set->last_free_index = index;
++                      return index;
++              }
++              index++;
++              if (index >= NUM_FWDS)
++                      index = 0;
++      } while (index != fwd_set->last_free_index);
++
++      return -ENOMEM;
++}
++
++
++/* Look up a MAC in the hash table. Caller should hold table lock. */
++static inline struct fwd_struct *fwd_find_entry(const __u8 *mac,
++                                              struct port_fwd *fwd_set)
++{
++      cuckoo_hash_value value;
++      cuckoo_hash_mac_key key = cuckoo_mac_to_key(mac);
++
++      if (cuckoo_hash_lookup(&fwd_set->fwd_hash_table,
++                             (cuckoo_hash_key *)(&key),
++                             &value)) {
++              struct fwd_struct *fwd = &fwd_set->fwd_array[value];
++              DPRINTK_ON(memcmp(fwd->mac, mac, ETH_ALEN) != 0);
++              return fwd;
++      }
++
++      return NULL;
++}
++
++
++/* Initialise each nic port's fowarding table */
++void *netback_accel_init_fwd_port(void) 
++{     
++      struct port_fwd *fwd_set;
++
++      fwd_set = kzalloc(sizeof(struct port_fwd), GFP_KERNEL);
++      if (fwd_set == NULL) {
++              return NULL;
++      }
++
++      spin_lock_init(&fwd_set->fwd_lock);
 +      
-+      /* The number of free slots in the grants array. */
-+      uint32_t free_list_size;
++      fwd_set->fwd_array = kzalloc(sizeof (struct fwd_struct) * NUM_FWDS,
++                                   GFP_KERNEL);
++      if (fwd_set->fwd_array == NULL) {
++              kfree(fwd_set);
++              return NULL;
++      }
++      
++      if (cuckoo_hash_init(&fwd_set->fwd_hash_table, NUM_FWDS_BITS, 8) != 0) {
++              kfree(fwd_set->fwd_array);
++              kfree(fwd_set);
++              return NULL;
++      }
++      
++      INIT_LIST_HEAD(&fwd_set->fwd_list);
++      
++      list_add(&fwd_set->link, &port_fwds);
 +
-+      /* Read/write semaphore used to protect the free list. */
-+      struct rw_semaphore free_list_sem;
++      return fwd_set;
++}
++
++
++void netback_accel_shutdown_fwd_port(void *fwd_priv)
++{
++      struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
++
++      BUG_ON(fwd_priv == NULL);
 +      
-+      /* Index of the next slot after the most recent contiguous allocation, 
-+       * for use in a next-fit allocator.
++      BUG_ON(list_empty(&port_fwds));
++      list_del(&fwd_set->link);
++
++      BUG_ON(!list_empty(&fwd_set->fwd_list));
++
++      cuckoo_hash_destroy(&fwd_set->fwd_hash_table);
++      kfree(fwd_set->fwd_array);
++      kfree(fwd_set);
++}
++
++
++int netback_accel_init_fwd()
++{
++      INIT_LIST_HEAD(&port_fwds);
++      return 0;
++}
++
++
++void netback_accel_shutdown_fwd()
++{
++      BUG_ON(!list_empty(&port_fwds));
++}
++
++
++/*
++ * Add an entry to the forwarding table.  Returns -ENOMEM if no
++ * space.
++ */
++int netback_accel_fwd_add(const __u8 *mac, void *context, void *fwd_priv)
++{
++      struct fwd_struct *fwd;
++      int rc = 0, index;
++      unsigned long flags;
++      cuckoo_hash_mac_key key = cuckoo_mac_to_key(mac);
++      struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
++
++      BUG_ON(fwd_priv == NULL);
++
++      DPRINTK("Adding mac " MAC_FMT "\n", MAC_ARG(mac));
++       
++      spin_lock_irqsave(&fwd_set->fwd_lock, flags);
++      
++      if ((rc = fwd_find_free_entry(fwd_set)) < 0 ) {
++              spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
++              return rc;
++      }
++
++      index = rc;
++
++      /* Shouldn't already be in the table */
++      if (cuckoo_hash_lookup(&fwd_set->fwd_hash_table,
++                             (cuckoo_hash_key *)(&key), &rc) != 0) {
++              spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
++              EPRINTK("MAC address " MAC_FMT " already accelerated.\n",
++                      MAC_ARG(mac));
++              return -EEXIST;
++      }
++
++      if ((rc = cuckoo_hash_add(&fwd_set->fwd_hash_table,
++                                (cuckoo_hash_key *)(&key), index, 1)) == 0) {
++              fwd = &fwd_set->fwd_array[index];
++              fwd->valid = 1;
++              fwd->context = context;
++              memcpy(fwd->mac, mac, ETH_ALEN);
++              list_add(&fwd->link, &fwd_set->fwd_list);
++              NETBACK_ACCEL_STATS_OP(global_stats.num_fwds++);
++      }
++
++      spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
++
++      /*
++       * No need to tell frontend that this mac address is local -
++       * it should auto-discover through packets on fastpath what is
++       * local and what is not, and just being on same server
++       * doesn't make it local (it could be on a different
++       * bridge)
 +       */
-+      uint32_t next_fit_index;
 +
-+      /* Used to map grants into the kernel, before mapping them into user
-+       * space.
++      return rc;
++}
++
++
++/* remove an entry from the forwarding tables. */
++void netback_accel_fwd_remove(const __u8 *mac, void *fwd_priv)
++{
++      struct fwd_struct *fwd;
++      unsigned long flags;
++      cuckoo_hash_mac_key key = cuckoo_mac_to_key(mac);
++      struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
++
++      DPRINTK("Removing mac " MAC_FMT "\n", MAC_ARG(mac));
++
++      BUG_ON(fwd_priv == NULL);
++
++      spin_lock_irqsave(&fwd_set->fwd_lock, flags);
++
++      fwd = fwd_find_entry(mac, fwd_set);
++      if (fwd != NULL) {
++              BUG_ON(list_empty(&fwd_set->fwd_list));
++              list_del(&fwd->link);
++
++              fwd->valid = 0;
++              cuckoo_hash_remove(&fwd_set->fwd_hash_table, 
++                                 (cuckoo_hash_key *)(&key));
++              NETBACK_ACCEL_STATS_OP(global_stats.num_fwds--);
++      }
++      spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
++
++      /*
++       * No need to tell frontend that this is no longer present -
++       * the frontend is currently only interested in remote
++       * addresses and it works these out (mostly) by itself
 +       */
-+      struct page **foreign_pages;
++}
 +
-+} gntdev_file_private_data_t;
 +
-+/* Module lifecycle operations. */
-+static int __init gntdev_init(void);
-+static void __exit gntdev_exit(void);
++/* Set the context pointer for a hash table entry. */
++int netback_accel_fwd_set_context(const __u8 *mac, void *context, 
++                                void *fwd_priv)
++{
++      struct fwd_struct *fwd;
++      unsigned long flags;
++      int rc = -ENOENT;
++      struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
 +
-+module_init(gntdev_init);
-+module_exit(gntdev_exit);
++      BUG_ON(fwd_priv == NULL);
 +
-+/* File operations. */
-+static int gntdev_open(struct inode *inode, struct file *flip);
-+static int gntdev_release(struct inode *inode, struct file *flip);
-+static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma);
-+static long gntdev_ioctl(struct file *flip,
-+                       unsigned int cmd, unsigned long arg);
++      spin_lock_irqsave(&fwd_set->fwd_lock, flags);
++      fwd = fwd_find_entry(mac, fwd_set);
++      if (fwd != NULL) {
++              fwd->context = context;
++              rc = 0;
++      }
++      spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
++      return rc;
++}
 +
-+static const struct file_operations gntdev_fops = {
-+      .owner = THIS_MODULE,
-+      .open = gntdev_open,
-+      .release = gntdev_release,
-+      .mmap = gntdev_mmap,
-+      .unlocked_ioctl = gntdev_ioctl
-+};
 +
-+/* VM operations. */
-+static void gntdev_vma_close(struct vm_area_struct *vma);
-+static pte_t gntdev_clear_pte(struct vm_area_struct *vma, unsigned long addr,
-+                            pte_t *ptep, int is_fullmm);
++/**************************************************************************
++ * Process a received packet
++ **************************************************************************/
 +
-+static struct vm_operations_struct gntdev_vmops = {
-+      .close = gntdev_vma_close,
-+      .zap_pte = gntdev_clear_pte
-+};
++/*
++ * Returns whether or not we have a match in our forward table for the
++ * this skb. Must be called with appropriate fwd_lock already held
++ */
++static struct netback_accel *for_a_vnic(struct netback_pkt_buf *skb, 
++                                      struct port_fwd *fwd_set)
++{
++      struct fwd_struct *fwd;
++      struct netback_accel *retval = NULL;
 +
-+/* Global variables. */
++      fwd = fwd_find_entry(skb->mac.raw, fwd_set);
++      if (fwd != NULL)
++              retval = fwd->context;
++      return retval;
++}
 +
-+/* The driver major number, for use when unregistering the driver. */
-+static int gntdev_major;
 +
-+#define GNTDEV_NAME "gntdev"
++static inline int packet_is_arp_reply(struct sk_buff *skb)
++{
++      return skb->protocol == ntohs(ETH_P_ARP) 
++              && skb->nh.arph->ar_op == ntohs(ARPOP_REPLY);
++}
 +
-+/* Memory mapping functions
-+ * ------------------------
++
++static inline void hdr_to_filt(struct ethhdr *ethhdr, struct iphdr *ip,
++                             struct netback_accel_filter_spec *spec)
++{
++      spec->proto = ip->protocol;
++      spec->destip_be = ip->daddr;
++      memcpy(spec->mac, ethhdr->h_source, ETH_ALEN);
++
++      if (ip->protocol == IPPROTO_TCP) {
++              struct tcphdr *tcp = (struct tcphdr *)((char *)ip + 4 * ip->ihl);
++              spec->destport_be = tcp->dest;
++      } else {
++              struct udphdr *udp = (struct udphdr *)((char *)ip + 4 * ip->ihl);
++              EPRINTK_ON(ip->protocol != IPPROTO_UDP);
++              spec->destport_be = udp->dest;
++      }
++}
++
++
++static inline int netback_accel_can_filter(struct netback_pkt_buf *skb) 
++{
++      return (skb->protocol == htons(ETH_P_IP) && 
++              ((skb->nh.iph->protocol == IPPROTO_TCP) ||
++               (skb->nh.iph->protocol == IPPROTO_UDP)));
++}
++
++
++static inline void netback_accel_filter_packet(struct netback_accel *bend,
++                                             struct netback_pkt_buf *skb)
++{
++      struct netback_accel_filter_spec fs;
++      struct ethhdr *eh = (struct ethhdr *)(skb->mac.raw);
++
++      hdr_to_filt(eh, skb->nh.iph, &fs);
++      
++      netback_accel_filter_check_add(bend, &fs);
++}
++
++
++/*
++ * Receive a packet and do something appropriate with it. Return true
++ * to take exclusive ownership of the packet.  This is verging on
++ * solarflare specific
++ */
++void netback_accel_rx_packet(struct netback_pkt_buf *skb, void *fwd_priv)
++{
++      struct netback_accel *bend;
++      struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
++      unsigned long flags;
++
++      BUG_ON(fwd_priv == NULL);
++
++      /* Checking for bcast is cheaper so do that first */
++      if (is_broadcast_ether_addr(skb->mac.raw)) {
++              /* pass through the slow path by not claiming ownership */
++              return;
++      } else if (is_multicast_ether_addr(skb->mac.raw)) {
++              /* pass through the slow path by not claiming ownership */
++              return;
++      } else {
++              /* It is unicast */
++              spin_lock_irqsave(&fwd_set->fwd_lock, flags);
++              /* We insert filter to pass it off to a VNIC */
++              if ((bend = for_a_vnic(skb, fwd_set)) != NULL)
++                      if (netback_accel_can_filter(skb))
++                              netback_accel_filter_packet(bend, skb);
++              spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
++      }
++      return;
++}
++
++
++void netback_accel_tx_packet(struct sk_buff *skb, void *fwd_priv) 
++{
++      __u8 *mac;
++      unsigned long flags;
++      struct port_fwd *fwd_set = (struct port_fwd *)fwd_priv;
++      struct fwd_struct *fwd;
++
++      BUG_ON(fwd_priv == NULL);
++
++      if (is_broadcast_ether_addr(skb->mac.raw) && packet_is_arp_reply(skb)) {
++              /*
++               * update our fast path forwarding to reflect this
++               * gratuitous ARP
++               */ 
++              mac = skb->mac.raw+ETH_ALEN;
++
++              DPRINTK("%s: found gratuitous ARP for " MAC_FMT "\n",
++                      __FUNCTION__, MAC_ARG(mac));
++
++              spin_lock_irqsave(&fwd_set->fwd_lock, flags);
++              /*
++               * Might not be local, but let's tell them all it is,
++               * and they can restore the fastpath if they continue
++               * to get packets that way
++               */
++              list_for_each_entry(fwd, &fwd_set->fwd_list, link) {
++                      struct netback_accel *bend = fwd->context;
++                      if (bend != NULL)
++                              netback_accel_msg_tx_new_localmac(bend, mac);
++              }
++
++              spin_unlock_irqrestore(&fwd_set->fwd_lock, flags);
++      }
++      return;
++}
+--- linux-2.6.18.8/drivers/xen/sfc_netback/accel_msg.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/accel_msg.c    2008-05-19 00:33:46.602832361 +0300
+@@ -0,0 +1,392 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
 + *
-+ * Every granted page is mapped into both kernel and user space, and the two
-+ * following functions return the respective virtual addresses of these pages.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
 + *
-+ * When shadow paging is disabled, the granted page is mapped directly into
-+ * user space; when it is enabled, it is mapped into the kernel and remapped
-+ * into user space using vm_insert_page() (see gntdev_mmap(), below).
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+/* Returns the virtual address (in user space) of the @page_index'th page
-+ * in the given VM area.
-+ */
-+static inline unsigned long get_user_vaddr (struct vm_area_struct *vma,
-+                                          int page_index)
++#include <xen/evtchn.h>
++
++#include "accel.h"
++#include "accel_msg_iface.h"
++#include "accel_util.h"
++#include "accel_solarflare.h"
++
++/* Send a HELLO to front end to start things off */
++void netback_accel_msg_tx_hello(struct netback_accel *bend, unsigned version)
 +{
-+      return (unsigned long) vma->vm_start + (page_index << PAGE_SHIFT);
++      unsigned long lock_state;
++      struct net_accel_msg *msg = 
++              net_accel_msg_start_send(bend->shared_page,
++                                       &bend->to_domU, &lock_state);
++      /* The queue _cannot_ be full, we're the first users. */
++      EPRINTK_ON(msg == NULL);
++
++      if (msg != NULL) {
++              net_accel_msg_init(msg, NET_ACCEL_MSG_HELLO);
++              msg->u.hello.version = version;
++              msg->u.hello.max_pages = bend->quotas.max_buf_pages; 
++              VPRINTK("Sending hello to channel %d\n", bend->msg_channel);
++              net_accel_msg_complete_send_notify(bend->shared_page, 
++                                                 &bend->to_domU,
++                                                 &lock_state, 
++                                                 bend->msg_channel_irq);
++      }
 +}
 +
-+/* Returns the virtual address (in kernel space) of the @slot_index'th page
-+ * mapped by the gntdev instance that owns the given private data struct.
++/* Send a local mac message to vnic */
++static void netback_accel_msg_tx_localmac(struct netback_accel *bend, 
++                                        int type, const void *mac)
++{
++      unsigned long lock_state;
++      struct net_accel_msg *msg;
++
++      BUG_ON(bend == NULL || mac == NULL);
++
++      VPRINTK("Sending local mac message: " MAC_FMT "\n", 
++              MAC_ARG((const char *)mac));  
++      
++      msg = net_accel_msg_start_send(bend->shared_page, &bend->to_domU,
++                                     &lock_state);
++      
++      if (msg != NULL) {
++              net_accel_msg_init(msg, NET_ACCEL_MSG_LOCALMAC);
++              msg->u.localmac.flags = type;
++              memcpy(msg->u.localmac.mac, mac, ETH_ALEN);
++              net_accel_msg_complete_send_notify(bend->shared_page, 
++                                                 &bend->to_domU,
++                                                 &lock_state, 
++                                                 bend->msg_channel_irq);
++      } else {
++              /*
++               * TODO if this happens we may leave a domU
++               * fastpathing packets when they should be delivered
++               * locally.  Solution is get domU to timeout entries
++               * in its fastpath lookup table when it receives no RX
++               * traffic
++               */
++              EPRINTK("%s: saw full queue, may need ARP timer to recover\n",
++                      __FUNCTION__);
++      }
++}
++
++/* Send an add local mac message to vnic */
++void netback_accel_msg_tx_new_localmac(struct netback_accel *bend,
++                                     const void *mac)
++{
++      netback_accel_msg_tx_localmac(bend, NET_ACCEL_MSG_ADD, mac);
++}
++
++
++static int netback_accel_msg_rx_buffer_map(struct netback_accel *bend, 
++                                         struct net_accel_msg *msg)
++{
++      int log2_pages, rc;
++
++      /* Can only allocate in power of two */
++      log2_pages = log2_ge(msg->u.mapbufs.pages, 0);
++      if (msg->u.mapbufs.pages != pow2(log2_pages)) {
++              EPRINTK("%s: Can only alloc bufs in power of 2 sizes (%d)\n",
++                      __FUNCTION__, msg->u.mapbufs.pages);
++              rc = -EINVAL;
++              goto err_out;
++      }
++  
++      /*
++       * Sanity.  Assumes NET_ACCEL_MSG_MAX_PAGE_REQ is same for
++       * both directions/domains
++       */
++      if (msg->u.mapbufs.pages > NET_ACCEL_MSG_MAX_PAGE_REQ) {
++              EPRINTK("%s: too many pages in a single message: %d %d\n", 
++                      __FUNCTION__, msg->u.mapbufs.pages,
++                      NET_ACCEL_MSG_MAX_PAGE_REQ);
++              rc = -EINVAL;
++              goto err_out;
++      }
++  
++      if ((rc = netback_accel_add_buffers(bend, msg->u.mapbufs.pages, 
++                                          log2_pages, msg->u.mapbufs.grants, 
++                                          &msg->u.mapbufs.buf)) < 0) {
++              goto err_out;
++      }
++
++      msg->id |= NET_ACCEL_MSG_REPLY;
++  
++      return 0;
++
++ err_out:
++      EPRINTK("%s: err_out\n", __FUNCTION__);
++      msg->id |= NET_ACCEL_MSG_ERROR | NET_ACCEL_MSG_REPLY;
++      return rc;
++}
++
++
++/* Hint from frontend that one of our filters is out of date */
++static int netback_accel_process_fastpath(struct netback_accel *bend, 
++                                        struct net_accel_msg *msg)
++{
++      struct netback_accel_filter_spec spec;
++
++      if (msg->u.fastpath.flags & NET_ACCEL_MSG_REMOVE) {
++              /* 
++               * Would be nice to BUG() this but would leave us
++               * vulnerable to naughty frontend
++               */
++              EPRINTK_ON(msg->u.fastpath.flags & NET_ACCEL_MSG_ADD);
++              
++              memcpy(spec.mac, msg->u.fastpath.mac, ETH_ALEN);
++              spec.destport_be = msg->u.fastpath.port;
++              spec.destip_be = msg->u.fastpath.ip;
++              spec.proto = msg->u.fastpath.proto;
++
++              netback_accel_filter_remove_spec(bend, &spec);
++      }
++
++      return 0;
++}
++
++
++/* Flow control for message queues */
++inline void set_queue_not_full(struct netback_accel *bend)
++{
++      if (!test_and_set_bit(NET_ACCEL_MSG_AFLAGS_QUEUEUNOTFULL_B, 
++                            (unsigned long *)&bend->shared_page->aflags))
++              notify_remote_via_irq(bend->msg_channel_irq);
++      else
++              VPRINTK("queue not full bit already set, not signalling\n");
++}
++
++
++/* Flow control for message queues */
++inline void set_queue_full(struct netback_accel *bend)
++{
++      if (!test_and_set_bit(NET_ACCEL_MSG_AFLAGS_QUEUE0FULL_B,
++                            (unsigned long *)&bend->shared_page->aflags))
++              notify_remote_via_irq(bend->msg_channel_irq);
++      else
++              VPRINTK("queue full bit already set, not signalling\n");
++}
++
++
++void netback_accel_set_interface_state(struct netback_accel *bend, int up)
++{
++      bend->shared_page->net_dev_up = up;
++      if (!test_and_set_bit(NET_ACCEL_MSG_AFLAGS_NETUPDOWN_B, 
++                           (unsigned long *)&bend->shared_page->aflags))
++              notify_remote_via_irq(bend->msg_channel_irq);
++      else
++              VPRINTK("interface up/down bit already set, not signalling\n");
++}
++
++
++static int check_rx_hello_version(unsigned version) 
++{
++      /* Should only happen if there's been a version mismatch */
++      BUG_ON(version == NET_ACCEL_MSG_VERSION);
++
++      if (version > NET_ACCEL_MSG_VERSION) {
++              /* Newer protocol, we must refuse */
++              return -EPROTO;
++      }
++
++      if (version < NET_ACCEL_MSG_VERSION) {
++              /*
++               * We are newer, so have discretion to accept if we
++               * wish.  For now however, just reject
++               */
++              return -EPROTO;
++      }
++
++      return -EINVAL;
++}
++
++
++static int process_rx_msg(struct netback_accel *bend,
++                        struct net_accel_msg *msg)
++{
++      int err = 0;
++                    
++      switch (msg->id) {
++      case NET_ACCEL_MSG_REPLY | NET_ACCEL_MSG_HELLO:
++              /* Reply to a HELLO; mark ourselves as connected */
++              DPRINTK("got Hello reply, version %.8x\n",
++                      msg->u.hello.version);
++              
++              /*
++               * Check that we've not successfully done this
++               * already.  NB no check at the moment that this reply
++               * comes after we've actually sent a HELLO as that's
++               * not possible with the current code structure
++               */
++              if (bend->hw_state != NETBACK_ACCEL_RES_NONE)
++                      return -EPROTO;
++
++              /* Store max_pages for accel_setup */
++              if (msg->u.hello.max_pages > bend->quotas.max_buf_pages) {
++                      EPRINTK("More pages than quota allows (%d > %d)\n",
++                              msg->u.hello.max_pages, 
++                              bend->quotas.max_buf_pages);
++                      /* Force it down to the quota */
++                      msg->u.hello.max_pages = bend->quotas.max_buf_pages;
++              }
++              bend->max_pages = msg->u.hello.max_pages;
++              
++              /* Set up the hardware visible to the other end */
++              err = bend->accel_setup(bend);
++              if (err) {
++                      /* This is fatal */
++                      DPRINTK("Hello gave accel_setup error %d\n", err);
++                      netback_accel_set_closing(bend);
++              } else {
++                      /*
++                       * Now add the context so that packet
++                       * forwarding will commence
++                       */
++                      netback_accel_fwd_set_context(bend->mac, bend, 
++                                                    bend->fwd_priv);
++              }
++              break;
++      case NET_ACCEL_MSG_REPLY | NET_ACCEL_MSG_HELLO | NET_ACCEL_MSG_ERROR:
++              EPRINTK("got Hello error, versions us:%.8x them:%.8x\n",
++                      NET_ACCEL_MSG_VERSION, msg->u.hello.version);
++
++              if (bend->hw_state != NETBACK_ACCEL_RES_NONE)
++                      return -EPROTO;
++
++              if (msg->u.hello.version != NET_ACCEL_MSG_VERSION) {
++                      /* Error is due to version mismatch */
++                      err = check_rx_hello_version(msg->u.hello.version);
++                      if (err == 0) {
++                              /*
++                               * It's OK to be compatible, send
++                               * another hello with compatible version
++                               */
++                              netback_accel_msg_tx_hello
++                                      (bend, msg->u.hello.version);
++                      } else {
++                              /*
++                               * Tell frontend that we're not going to
++                               * send another HELLO by going to Closing.
++                               */
++                              netback_accel_set_closing(bend);
++                      }
++              } 
++              break;
++      case NET_ACCEL_MSG_MAPBUF:
++              VPRINTK("Got mapped buffers request %d\n",
++                      msg->u.mapbufs.reqid);
++
++              if (bend->hw_state == NETBACK_ACCEL_RES_NONE)
++                      return -EPROTO;
++
++              /*
++               * Frontend wants a buffer table entry for the
++               * supplied pages
++               */
++              err = netback_accel_msg_rx_buffer_map(bend, msg);
++              if (net_accel_msg_reply_notify(bend->shared_page,
++                                             bend->msg_channel_irq, 
++                                             &bend->to_domU, msg)) {
++                      /*
++                       * This is fatal as we can't tell the frontend
++                       * about the problem through the message
++                       * queue, and so would otherwise stalemate
++                       */
++                      netback_accel_set_closing(bend);
++              }
++              break;
++      case NET_ACCEL_MSG_FASTPATH:
++              DPRINTK("Got fastpath request\n");
++
++              if (bend->hw_state == NETBACK_ACCEL_RES_NONE)
++                      return -EPROTO;
++
++              err = netback_accel_process_fastpath(bend, msg);
++              break;
++      default:
++              EPRINTK("Huh? Message code is %x\n", msg->id);
++              err = -EPROTO;
++              break;
++      }
++      return err;
++}
++
++
++/*  Demultiplex an IRQ from the frontend driver.  */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++void netback_accel_msg_rx_handler(struct work_struct *arg)
++#else
++void netback_accel_msg_rx_handler(void *bend_void)
++#endif
++{
++      struct net_accel_msg msg;
++      int err, queue_was_full = 0;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++      struct netback_accel *bend = 
++              container_of(arg, struct netback_accel, handle_msg);
++#else
++      struct netback_accel *bend = (struct netback_accel *)bend_void;
++#endif
++
++      mutex_lock(&bend->bend_mutex);
++
++      /*
++       * This happens when the shared pages have been unmapped, but
++       * the workqueue not flushed yet
++       */
++      if (bend->shared_page == NULL)
++              goto done;
++
++      if ((bend->shared_page->aflags &
++           NET_ACCEL_MSG_AFLAGS_TO_DOM0_MASK) != 0) {
++              if (bend->shared_page->aflags &
++                  NET_ACCEL_MSG_AFLAGS_QUEUE0NOTFULL) {
++                      /* We've been told there may now be space. */
++                      clear_bit(NET_ACCEL_MSG_AFLAGS_QUEUE0NOTFULL_B, 
++                                (unsigned long *)&bend->shared_page->aflags);
++              }
++
++              if (bend->shared_page->aflags &
++                  NET_ACCEL_MSG_AFLAGS_QUEUEUFULL) {
++                      clear_bit(NET_ACCEL_MSG_AFLAGS_QUEUEUFULL_B, 
++                                (unsigned long *)&bend->shared_page->aflags);
++                      queue_was_full = 1;
++              }
++      }
++
++      while ((err = net_accel_msg_recv(bend->shared_page, &bend->from_domU,
++                                       &msg)) == 0) {
++              err = process_rx_msg(bend, &msg);
++              
++              if (err != 0) {
++                      EPRINTK("%s: Error %d\n", __FUNCTION__, err);
++                      goto err;
++              }
++      }
++
++ err:
++      /* There will be space now if we can make any. */
++      if (queue_was_full) 
++              set_queue_not_full(bend);
++ done:
++      mutex_unlock(&bend->bend_mutex);
++
++      return;
++}
+--- linux-2.6.18.8/drivers/xen/sfc_netback/accel_solarflare.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/accel_solarflare.c     2008-05-19 00:33:46.714838817 +0300
+@@ -0,0 +1,1253 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
-+static inline unsigned long get_kernel_vaddr (gntdev_file_private_data_t *priv,
-+                                            int slot_index)
++
++#include "common.h"
++
++#include "accel.h"
++#include "accel_solarflare.h"
++#include "accel_msg_iface.h"
++#include "accel_util.h"
++
++#include "accel_cuckoo_hash.h"
++
++#include "ci/driver/resource/efx_vi.h"
++
++#include "ci/efrm/nic_table.h" 
++#include "ci/efhw/public.h"
++
++#include <xen/evtchn.h>
++#include <xen/driver_util.h>
++#include <linux/list.h>
++#include <linux/mutex.h>
++
++#include "driverlink_api.h"
++
++#define SF_XEN_RX_USR_BUF_SIZE 2048
++
++struct falcon_bend_accel_priv {
++      struct efx_vi_state *efx_vih;
++
++      /*! Array of pointers to dma_map state, used so VNIC can
++       *  request their removal in a single message
++       */
++      struct efx_vi_dma_map_state **dma_maps;
++      /*! Index into dma_maps */
++      int dma_maps_index; 
++
++      /*! Serialises access to filters */
++      spinlock_t filter_lock;      
++      /*! Bitmap of which filters are free */
++      unsigned long free_filters;      
++      /*! Used for index normalisation */
++      u32 filter_idx_mask;            
++      struct netback_accel_filter_spec *fspecs; 
++      cuckoo_hash_table filter_hash_table;
++
++      u32 txdmaq_gnt;
++      u32 rxdmaq_gnt;
++      u32 doorbell_gnt;
++      u32 evq_rptr_gnt;
++      u32 evq_mem_gnts[EF_HW_FALCON_EVQ_PAGES];
++      u32 evq_npages;
++};
++
++/* Forward declaration */
++static int netback_accel_filter_init(struct netback_accel *);
++static void netback_accel_filter_shutdown(struct netback_accel *);
++
++/**************************************************************************
++ * 
++ * Driverlink stuff
++ *
++ **************************************************************************/
++
++struct driverlink_port {
++      struct list_head link;
++      enum net_accel_hw_type type;
++      struct net_device *net_dev;
++      struct efx_dl_device *efx_dl_dev;
++      int nic_index;
++      void *fwd_priv;
++};
++
++static struct list_head dl_ports;
++
++/* This mutex protects global state, such as the dl_ports list */
++DEFINE_MUTEX(accel_mutex);
++
++static int init_done = 0;
++
++/* The DL callbacks */
++
++
++#if defined(EFX_USE_FASTCALL)
++static enum efx_veto fastcall
++#else
++static enum efx_veto
++#endif
++bend_dl_tx_packet(struct efx_dl_device *efx_dl_dev,
++                struct sk_buff *skb)
 +{
-+      unsigned long pfn;
-+      void *kaddr;
-+      pfn = page_to_pfn(priv->foreign_pages[slot_index]);
-+      kaddr = pfn_to_kaddr(pfn);
-+      return (unsigned long) kaddr;
++      struct driverlink_port *port = efx_dl_dev->priv;
++
++      BUG_ON(port == NULL);
++
++      NETBACK_ACCEL_STATS_OP(global_stats.dl_tx_packets++);
++      if (skb->mac.raw != NULL)
++              netback_accel_tx_packet(skb, port->fwd_priv);
++      else {
++              DPRINTK("Ignoring packet with missing mac address\n");
++              NETBACK_ACCEL_STATS_OP(global_stats.dl_tx_bad_packets++);
++      }
++      return EFX_ALLOW_PACKET;
 +}
 +
-+/* Helper functions. */
++/* EFX_USE_FASTCALL */
++#if defined(EFX_USE_FASTCALL)
++static enum efx_veto fastcall
++#else
++static enum efx_veto
++#endif
++bend_dl_rx_packet(struct efx_dl_device *efx_dl_dev,
++                const char *pkt_buf, int pkt_len)
++{
++      struct driverlink_port *port = efx_dl_dev->priv;
++      struct netback_pkt_buf pkt;
++      struct ethhdr *eh;
 +
-+/* Adds information about a grant reference to the list of grants in the file's
-+ * private data structure. Returns non-zero on failure. On success, sets the
-+ * value of *offset to the offset that should be mmap()-ed in order to map the
-+ * grant reference.
++      BUG_ON(port == NULL);
++
++      pkt.mac.raw = (char *)pkt_buf;
++      pkt.nh.raw = (char *)pkt_buf + ETH_HLEN;
++      eh = (struct ethhdr *)pkt_buf;
++      pkt.protocol = eh->h_proto;
++
++      NETBACK_ACCEL_STATS_OP(global_stats.dl_rx_packets++);
++      netback_accel_rx_packet(&pkt, port->fwd_priv);
++      return EFX_ALLOW_PACKET;
++}
++
++
++/* Callbacks we'd like to get from the netdriver through driverlink */
++struct efx_dl_callbacks bend_dl_callbacks =
++      {
++              .tx_packet = bend_dl_tx_packet,
++              .rx_packet = bend_dl_rx_packet,
++      };
++
++
++static struct netback_accel_hooks accel_hooks = {
++      THIS_MODULE,
++      &netback_accel_probe,
++      &netback_accel_remove
++};
++
++
++/*
++ * Handy helper which given an efx_dl_device works out which
++ * efab_nic_t index into efrm_nic_table.nics[] it corresponds to 
 + */
-+static int add_grant_reference(struct file *flip,
-+                             struct ioctl_gntdev_grant_ref *op,
-+                             uint64_t *offset)
++static int efx_device_to_efab_nic_index(struct efx_dl_device *efx_dl_dev) 
++{
++      int i;
++
++      for (i = 0; i < EFHW_MAX_NR_DEVS; i++) {
++              struct efhw_nic *nic = efrm_nic_table.nic[i];
++
++              /*
++               * It's possible for the nic structure to have not
++               * been initialised if the resource driver failed its
++               * driverlink probe
++               */ 
++              if (nic == NULL || nic->net_driver_dev == NULL)
++                      continue;
++
++              /* Work out if these are talking about the same NIC */
++              if (nic->net_driver_dev->pci_dev == efx_dl_dev->pci_dev)
++                      return i;
++      }
++
++      return -1;
++}
++
++
++/* Driver link probe - register our callbacks */
++static int bend_dl_probe(struct efx_dl_device *efx_dl_dev,
++                       const struct net_device *net_dev,
++                       const struct efx_dl_device_info *dev_info,
++                       const char* silicon_rev)
++{
++      int rc;
++      enum net_accel_hw_type type;
++      struct driverlink_port *port;
++
++      DPRINTK("%s: %s\n", __FUNCTION__, silicon_rev);
++
++      if (strcmp(silicon_rev, "falcon/a1") == 0)
++              type = NET_ACCEL_MSG_HWTYPE_FALCON_A;
++      else if (strcmp(silicon_rev, "falcon/b0") == 0)
++              type = NET_ACCEL_MSG_HWTYPE_FALCON_B;
++      else {
++              EPRINTK("%s: unsupported silicon %s\n", __FUNCTION__,
++                      silicon_rev);
++              rc = -EINVAL;
++              goto fail1;
++      }
++      
++      port = kmalloc(sizeof(struct driverlink_port), GFP_KERNEL);
++      if (port == NULL) {
++              EPRINTK("%s: no memory for dl probe\n", __FUNCTION__);
++              rc = -ENOMEM;
++              goto fail1;
++      }
++
++      port->efx_dl_dev = efx_dl_dev;
++      efx_dl_dev->priv = port;
++
++      port->nic_index = efx_device_to_efab_nic_index(efx_dl_dev);
++      if (port->nic_index < 0) {
++              /*
++               * This can happen in theory if the resource driver
++               * failed to initialise properly
++               */
++              EPRINTK("%s: nic structure not found\n", __FUNCTION__);
++              rc = -EINVAL;
++              goto fail2;
++      }
++
++      port->fwd_priv = netback_accel_init_fwd_port();
++      if (port->fwd_priv == NULL) {
++              EPRINTK("%s: failed to set up forwarding for port\n",
++                      __FUNCTION__);
++              rc = -ENOMEM;
++              goto fail2;
++      }
++
++      rc = efx_dl_register_callbacks(efx_dl_dev, &bend_dl_callbacks);
++      if (rc != 0) {
++              EPRINTK("%s: register_callbacks failed\n", __FUNCTION__);
++              goto fail3;
++      }
++
++      port->type = type;
++      port->net_dev = (struct net_device *)net_dev;
++
++      mutex_lock(&accel_mutex);
++      list_add(&port->link, &dl_ports);
++      mutex_unlock(&accel_mutex);
++
++      rc = netback_connect_accelerator(NETBACK_ACCEL_VERSION, 0,
++                                       port->net_dev->name, &accel_hooks);
++
++      if (rc < 0) {
++              EPRINTK("Xen netback accelerator version mismatch\n");
++              goto fail4;
++      } else if (rc > 0) {
++              /*
++               * In future may want to add backwards compatibility
++               * and accept certain subsets of previous versions
++               */
++              EPRINTK("Xen netback accelerator version mismatch\n");
++              goto fail4;
++      } 
++
++      return 0;
++
++ fail4:
++      mutex_lock(&accel_mutex);
++      list_del(&port->link);
++      mutex_unlock(&accel_mutex);
++
++      efx_dl_unregister_callbacks(efx_dl_dev, &bend_dl_callbacks);
++ fail3: 
++      netback_accel_shutdown_fwd_port(port->fwd_priv);
++ fail2:
++      efx_dl_dev->priv = NULL;
++      kfree(port);
++ fail1:
++      return rc;
++}
++
++
++static void bend_dl_remove(struct efx_dl_device *efx_dl_dev)
++{
++      struct driverlink_port *port;
++
++      DPRINTK("Unregistering driverlink callbacks.\n");
++
++      mutex_lock(&accel_mutex);
++
++      port = (struct driverlink_port *)efx_dl_dev->priv;
++
++      BUG_ON(list_empty(&dl_ports));
++      BUG_ON(port == NULL);
++      BUG_ON(port->efx_dl_dev != efx_dl_dev);
++
++      netback_disconnect_accelerator(0, port->net_dev->name);
++
++      list_del(&port->link);
++
++      mutex_unlock(&accel_mutex);
++
++      efx_dl_unregister_callbacks(efx_dl_dev, &bend_dl_callbacks);
++      netback_accel_shutdown_fwd_port(port->fwd_priv);
++
++      efx_dl_dev->priv = NULL;
++      kfree(port);
++
++      return;
++}
++
++
++static struct efx_dl_driver bend_dl_driver = 
++      {
++              .name = "SFC Xen backend",
++              .probe = bend_dl_probe,
++              .remove = bend_dl_remove,
++      };
++
++
++int netback_accel_sf_init(void)
++{
++      int rc, nic_i;
++      struct efhw_nic *nic;
++
++      INIT_LIST_HEAD(&dl_ports);
++
++      rc = efx_dl_register_driver(&bend_dl_driver);
++      /* If we couldn't find the NET driver, give up */
++      if (rc == -ENOENT)
++              return rc;
++      
++      if (rc == 0) {
++              EFRM_FOR_EACH_NIC(nic_i, nic)
++                      falcon_nic_set_rx_usr_buf_size(nic, 
++                                                     SF_XEN_RX_USR_BUF_SIZE);
++      }
++
++      init_done = (rc == 0);
++      return rc;
++}
++
++
++void netback_accel_sf_shutdown(void)
++{
++      if (!init_done)
++              return;
++      DPRINTK("Unregistering driverlink driver\n");
++
++      /*
++       * This will trigger removal callbacks for all the devices, which
++       * will unregister their callbacks, disconnect from netfront, etc.
++       */
++      efx_dl_unregister_driver(&bend_dl_driver);
++}
++
++
++int netback_accel_sf_hwtype(struct netback_accel *bend)
++{
++      struct driverlink_port *port;
++
++      mutex_lock(&accel_mutex);
++
++      list_for_each_entry(port, &dl_ports, link) {
++              if (strcmp(bend->nicname, port->net_dev->name) == 0) {
++                      bend->hw_type = port->type;
++                      bend->accel_setup = netback_accel_setup_vnic_hw;
++                      bend->accel_shutdown = netback_accel_shutdown_vnic_hw;
++                      bend->fwd_priv = port->fwd_priv;
++                      /* This is just needed to pass to efx_vi_alloc */
++                      bend->nic_index = port->nic_index;
++                      bend->net_dev = port->net_dev;
++                      mutex_unlock(&accel_mutex);
++                      return 0;
++              }
++      }
++
++      mutex_unlock(&accel_mutex);
++
++      EPRINTK("Failed to identify backend device '%s' with a NIC\n",
++              bend->nicname);
++
++      return -ENOENT;
++}
++
++
++/****************************************************************************
++ * Resource management code
++ ***************************************************************************/
++
++static int alloc_page_state(struct netback_accel *bend, int max_pages)
 +{
-+      gntdev_file_private_data_t *private_data 
-+              = (gntdev_file_private_data_t *) flip->private_data;
++      struct falcon_bend_accel_priv *accel_hw_priv;
 +
-+      uint32_t slot_index;
++      if (max_pages < 0 || max_pages > bend->quotas.max_buf_pages) {
++              EPRINTK("%s: invalid max_pages: %d\n", __FUNCTION__, max_pages);
++              return -EINVAL;
++      }
 +
-+      if (unlikely(private_data->free_list_size == 0)) {
++      accel_hw_priv = kzalloc(sizeof(struct falcon_bend_accel_priv),
++                              GFP_KERNEL);
++      if (accel_hw_priv == NULL) {
++              EPRINTK("%s: no memory for accel_hw_priv\n", __FUNCTION__);
 +              return -ENOMEM;
 +      }
 +
-+      slot_index = private_data->free_list[--private_data->free_list_size];
++      accel_hw_priv->dma_maps = kzalloc
++              (sizeof(struct efx_vi_dma_map_state **) * 
++               (max_pages / NET_ACCEL_MSG_MAX_PAGE_REQ), GFP_KERNEL);
++      if (accel_hw_priv->dma_maps == NULL) {
++              EPRINTK("%s: no memory for dma_maps\n", __FUNCTION__);
++              kfree(accel_hw_priv);
++              return -ENOMEM;
++      }
 +
-+      /* Copy the grant information into file's private data. */
-+      private_data->grants[slot_index].state = GNTDEV_SLOT_NOT_YET_MAPPED;
-+      private_data->grants[slot_index].u.valid.domid = op->domid;
-+      private_data->grants[slot_index].u.valid.ref = op->ref;
++      bend->buffer_maps = kzalloc(sizeof(struct vm_struct *) * max_pages, 
++                                  GFP_KERNEL);
++      if (bend->buffer_maps == NULL) {
++              EPRINTK("%s: no memory for buffer_maps\n", __FUNCTION__);
++              kfree(accel_hw_priv->dma_maps);
++              kfree(accel_hw_priv);
++              return -ENOMEM;
++      }
 +
-+      /* The offset is calculated as the index of the chosen entry in the
-+       * file's private data's array of grant information. This is then
-+       * shifted to give an offset into the virtual "file address space".
-+       */
-+      *offset = slot_index << PAGE_SHIFT;
++      bend->buffer_addrs = kzalloc(sizeof(u64) * max_pages, GFP_KERNEL);
++      if (bend->buffer_addrs == NULL) {
++              kfree(bend->buffer_maps);
++              kfree(accel_hw_priv->dma_maps);
++              kfree(accel_hw_priv);
++              return -ENOMEM;
++      }
++
++      bend->accel_hw_priv = accel_hw_priv;
 +
 +      return 0;
 +}
 +
-+/* Adds the @count grant references to the contiguous range in the slot array
-+ * beginning at @first_slot. It is assumed that @first_slot was returned by a
-+ * previous invocation of find_contiguous_free_range(), during the same
-+ * invocation of the driver.
-+ */
-+static int add_grant_references(struct file *flip,
-+                              int count,
-+                              struct ioctl_gntdev_grant_ref *ops,
-+                              uint32_t first_slot)
++
++static int free_page_state(struct netback_accel *bend)
 +{
-+      gntdev_file_private_data_t *private_data 
-+              = (gntdev_file_private_data_t *) flip->private_data;
-+      int i;
-+      
-+      for (i = 0; i < count; ++i) {
++      struct falcon_bend_accel_priv *accel_hw_priv;
 +
-+              /* First, mark the slot's entry in the free list as invalid. */
-+              int free_list_index = 
-+                      private_data->grants[first_slot+i].u.free_list_index;
-+              private_data->free_list[free_list_index] = 
-+                      GNTDEV_FREE_LIST_INVALID;
++      DPRINTK("%s: %p\n", __FUNCTION__, bend);
 +
-+              /* Now, update the slot. */
-+              private_data->grants[first_slot+i].state = 
-+                      GNTDEV_SLOT_NOT_YET_MAPPED;
-+              private_data->grants[first_slot+i].u.valid.domid =
-+                      ops[i].domid;
-+              private_data->grants[first_slot+i].u.valid.ref = ops[i].ref;
++      accel_hw_priv = bend->accel_hw_priv;
++
++      if (accel_hw_priv) {
++              kfree(accel_hw_priv->dma_maps);
++              kfree(bend->buffer_maps);
++              kfree(bend->buffer_addrs);
++              kfree(accel_hw_priv);
++              bend->accel_hw_priv = NULL;
++              bend->max_pages = 0;
 +      }
 +
-+      return 0;       
++      return 0;
 +}
 +
-+/* Scans through the free list for @flip, removing entries that are marked as
-+ * GNTDEV_SLOT_INVALID. This will reduce the recorded size of the free list to
-+ * the number of valid entries.
-+ */
-+static void compress_free_list(struct file *flip) 
++
++/* The timeout event callback for the event q */
++static void bend_evq_timeout(void *context, int is_timeout)
 +{
-+      gntdev_file_private_data_t *private_data 
-+              = (gntdev_file_private_data_t *) flip->private_data;
-+      int i, j = 0, old_size;
-+      
-+      old_size = private_data->free_list_size;
-+      for (i = 0; i < old_size; ++i) {
-+              if (private_data->free_list[i] != GNTDEV_FREE_LIST_INVALID) {
-+                      private_data->free_list[j] = 
-+                              private_data->free_list[i];
-+                      ++j;
-+              } else {
-+                      --private_data->free_list_size;
-+              }
++      struct netback_accel *bend = (struct netback_accel *)context;
++      if (is_timeout) {
++              /* Pass event to vnic front end driver */
++              VPRINTK("timeout event to %d\n", bend->net_channel);
++              NETBACK_ACCEL_STATS_OP(bend->stats.evq_timeouts++);
++              notify_remote_via_irq(bend->net_channel_irq);
++      } else {
++              /* It's a wakeup event, used by Falcon */
++              VPRINTK("wakeup to %d\n", bend->net_channel);
++              NETBACK_ACCEL_STATS_OP(bend->stats.evq_wakeups++);
++              notify_remote_via_irq(bend->net_channel_irq);
 +      }
 +}
 +
-+/* Searches the grant array in the private data of @flip for a range of
-+ * @num_slots contiguous slots in the GNTDEV_SLOT_INVALID state.
-+ *
-+ * Returns the index of the first slot if a range is found, otherwise -ENOMEM.
++
++/*
++ * Create the eventq and associated gubbins for communication with the
++ * front end vnic driver
 + */
-+static int find_contiguous_free_range(struct file *flip,
-+                                    uint32_t num_slots) 
++static int ef_get_vnic(struct netback_accel *bend)
 +{
-+      gntdev_file_private_data_t *private_data 
-+              = (gntdev_file_private_data_t *) flip->private_data;
-+      
-+      int i;
-+      int start_index = private_data->next_fit_index;
-+      int range_start = 0, range_length;
++      struct falcon_bend_accel_priv *accel_hw_priv;
++      int rc = 0;
 +
-+      if (private_data->free_list_size < num_slots) {
-+              return -ENOMEM;
++      BUG_ON(bend->hw_state != NETBACK_ACCEL_RES_NONE);
++
++      /* Allocate page related state and accel_hw_priv */
++      rc = alloc_page_state(bend, bend->max_pages);
++      if (rc != 0) {
++              EPRINTK("Failed to allocate page state: %d\n", rc);
++              return rc;
 +      }
 +
-+      /* First search from the start_index to the end of the array. */
-+      range_length = 0;
-+      for (i = start_index; i < MAX_GRANTS; ++i) {
-+              if (private_data->grants[i].state == GNTDEV_SLOT_INVALID) {
-+                      if (range_length == 0) {
-+                              range_start = i;
-+                      }
-+                      ++range_length;
-+                      if (range_length == num_slots) {
-+                              return range_start;
-+                      }
-+              }
++      accel_hw_priv = bend->accel_hw_priv;
++
++      rc = efx_vi_alloc(&accel_hw_priv->efx_vih, bend->nic_index);
++      if (rc != 0) {
++              EPRINTK("%s: efx_vi_alloc failed %d\n", __FUNCTION__, rc);
++              free_page_state(bend);
++              return rc;
 +      }
-+      
-+      /* Now search from the start of the array to the start_index. */
-+      range_length = 0;
-+      for (i = 0; i < start_index; ++i) {
-+              if (private_data->grants[i].state == GNTDEV_SLOT_INVALID) {
-+                      if (range_length == 0) {
-+                              range_start = i;
-+                      }
-+                      ++range_length;
-+                      if (range_length == num_slots) {
-+                              return range_start;
-+                      }
-+              }
++
++      rc = efx_vi_eventq_register_callback(accel_hw_priv->efx_vih,
++                                           bend_evq_timeout,
++                                           bend);
++      if (rc != 0) {
++              EPRINTK("%s: register_callback failed %d\n", __FUNCTION__, rc);
++              efx_vi_free(accel_hw_priv->efx_vih);
++              free_page_state(bend);
++              return rc;
 +      }
++
++      bend->hw_state = NETBACK_ACCEL_RES_ALLOC;
 +      
-+      return -ENOMEM;
++      return 0;
 +}
 +
-+/* Interface functions. */
 +
-+/* Initialises the driver. Called when the module is loaded. */
-+static int __init gntdev_init(void)
++static void ef_free_vnic(struct netback_accel *bend)
 +{
-+      struct class *class;
-+      struct class_device *device;
++      struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
 +
-+      if (!is_running_on_xen()) {
-+              printk(KERN_ERR "You must be running Xen to use gntdev\n");
-+              return -ENODEV;
-+      }
++      BUG_ON(bend->hw_state != NETBACK_ACCEL_RES_ALLOC);
 +
-+      gntdev_major = register_chrdev(0, GNTDEV_NAME, &gntdev_fops);
-+      if (gntdev_major < 0)
-+      {
-+              printk(KERN_ERR "Could not register gntdev device\n");
-+              return -ENOMEM;
-+      }
++      efx_vi_eventq_kill_callback(accel_hw_priv->efx_vih);
 +
-+      /* Note that if the sysfs code fails, we will still initialise the
-+       * device, and output the major number so that the device can be
-+       * created manually using mknod.
-+       */
-+      if ((class = get_xen_class()) == NULL) {
-+              printk(KERN_ERR "Error setting up xen_class\n");
-+              printk(KERN_ERR "gntdev created with major number = %d\n", 
-+                     gntdev_major);
-+              return 0;
-+      }
++      DPRINTK("Hardware is freeable. Will proceed.\n");
 +
-+      device = class_device_create(class, NULL, MKDEV(gntdev_major, 0),
-+                                   NULL, GNTDEV_NAME);
-+      if (IS_ERR(device)) {
-+              printk(KERN_ERR "Error creating gntdev device in xen_class\n");
-+              printk(KERN_ERR "gntdev created with major number = %d\n",
-+                     gntdev_major);
-+              return 0;
-+      }
++      efx_vi_free(accel_hw_priv->efx_vih);
++      accel_hw_priv->efx_vih = NULL;
 +
-+      return 0;
++      VPRINTK("Free page state...\n");
++      free_page_state(bend);
++
++      bend->hw_state = NETBACK_ACCEL_RES_NONE;
 +}
 +
-+/* Cleans up and unregisters the driver. Called when the driver is unloaded.
-+ */
-+static void __exit gntdev_exit(void)
-+{
-+      struct class *class;
-+      if ((class = get_xen_class()) != NULL)
-+              class_device_destroy(class, MKDEV(gntdev_major, 0));
-+      unregister_chrdev(gntdev_major, GNTDEV_NAME);
++
++static inline void ungrant_or_crash(grant_ref_t gntref, int domain) {
++      if (net_accel_ungrant_page(gntref) == -EBUSY)
++              net_accel_shutdown_remote(domain);
 +}
 +
-+/* Called when the device is opened. */
-+static int gntdev_open(struct inode *inode, struct file *flip)
++
++static void netback_accel_release_hwinfo(struct netback_accel *bend)
 +{
-+      gntdev_file_private_data_t *private_data;
++      struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
 +      int i;
 +
-+      try_module_get(THIS_MODULE);
-+
-+      /* Allocate space for the per-instance private data. */
-+      private_data = kmalloc(sizeof(*private_data), GFP_KERNEL);
-+      if (!private_data)
-+              goto nomem_out;
++      DPRINTK("Remove dma q grants %d %d\n", accel_hw_priv->txdmaq_gnt,
++              accel_hw_priv->rxdmaq_gnt);
++      ungrant_or_crash(accel_hw_priv->txdmaq_gnt, bend->far_end);
++      ungrant_or_crash(accel_hw_priv->rxdmaq_gnt, bend->far_end);
 +
-+      /* Allocate space for the kernel-mapping of granted pages. */
-+      private_data->foreign_pages = 
-+              alloc_empty_pages_and_pagevec(MAX_GRANTS);
-+      if (!private_data->foreign_pages)
-+              goto nomem_out2;
++      DPRINTK("Remove doorbell grant %d\n", accel_hw_priv->doorbell_gnt);
++      ungrant_or_crash(accel_hw_priv->doorbell_gnt, bend->far_end);
 +
-+      /* Initialise the free-list, which contains all slots at first.
-+       */
-+      for (i = 0; i < MAX_GRANTS; ++i) {
-+              private_data->free_list[MAX_GRANTS - i - 1] = i;
-+              private_data->grants[i].state = GNTDEV_SLOT_INVALID;
-+              private_data->grants[i].u.free_list_index = MAX_GRANTS - i - 1;
++      if (bend->hw_type == NET_ACCEL_MSG_HWTYPE_FALCON_A) {
++              DPRINTK("Remove rptr grant %d\n", accel_hw_priv->evq_rptr_gnt);
++              ungrant_or_crash(accel_hw_priv->evq_rptr_gnt, bend->far_end);
 +      }
-+      private_data->free_list_size = MAX_GRANTS;
-+      private_data->next_fit_index = 0;
 +
-+      init_rwsem(&private_data->grants_sem);
-+      init_rwsem(&private_data->free_list_sem);
-+
-+      flip->private_data = private_data;
++      for (i = 0; i < accel_hw_priv->evq_npages; i++) {
++              DPRINTK("Remove evq grant %d\n", accel_hw_priv->evq_mem_gnts[i]);
++              ungrant_or_crash(accel_hw_priv->evq_mem_gnts[i], bend->far_end);
++      }
 +
-+      return 0;
++      bend->hw_state = NETBACK_ACCEL_RES_FILTER;
 +
-+nomem_out2:
-+      kfree(private_data);
-+nomem_out:
-+      return -ENOMEM;
++      return;
 +}
 +
-+/* Called when the device is closed.
-+ */
-+static int gntdev_release(struct inode *inode, struct file *flip)
-+{
-+      if (flip->private_data) {
-+              gntdev_file_private_data_t *private_data = 
-+                      (gntdev_file_private_data_t *) flip->private_data;
-+              if (private_data->foreign_pages) {
-+                      free_empty_pages_and_pagevec
-+                              (private_data->foreign_pages, MAX_GRANTS);
-+              }
-+              kfree(private_data);
-+      }
-+      module_put(THIS_MODULE);
-+      return 0;
-+}
 +
-+/* Called when an attempt is made to mmap() the device. The private data from
-+ * @flip contains the list of grant references that can be mapped. The vm_pgoff
-+ * field of @vma contains the index into that list that refers to the grant
-+ * reference that will be mapped. Only mappings that are a multiple of
-+ * PAGE_SIZE are handled.
-+ */
-+static int gntdev_mmap (struct file *flip, struct vm_area_struct *vma) 
++static int ef_bend_hwinfo_falcon_common(struct netback_accel *bend, 
++                                      struct net_accel_hw_falcon_b *hwinfo)
 +{
-+      struct gnttab_map_grant_ref op;
-+      unsigned long slot_index = vma->vm_pgoff;
-+      unsigned long kernel_vaddr, user_vaddr;
-+      uint32_t size = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-+      uint64_t ptep;
-+      int ret;
-+      int flags;
-+      int i;
-+      struct page *page;
-+      gntdev_file_private_data_t *private_data = flip->private_data;
++      struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
++      struct efx_vi_hw_resource_metadata res_mdata;
++      struct efx_vi_hw_resource res_array[EFX_VI_HW_RESOURCE_MAXSIZE];
++      int rc, len = EFX_VI_HW_RESOURCE_MAXSIZE, i, pfn = 0;
++      unsigned long txdmaq_pfn = 0, rxdmaq_pfn = 0;
 +
-+      if (unlikely(!private_data)) {
-+              printk(KERN_ERR "File's private data is NULL.\n");
-+              return -EINVAL;
++      rc = efx_vi_hw_resource_get_phys(accel_hw_priv->efx_vih, &res_mdata,
++                                       res_array, &len);
++      if (rc != 0) {
++              DPRINTK("%s: resource_get_phys returned %d\n",
++                      __FUNCTION__, rc);
++              return rc;
 +      }
 +
-+      if (unlikely((size <= 0) || (size + slot_index) > MAX_GRANTS)) {
-+              printk(KERN_ERR "Invalid number of pages or offset"
-+                     "(num_pages = %d, first_slot = %ld).\n",
-+                     size, slot_index);
-+              return -ENXIO;
-+      }
++      if (res_mdata.version != 0)
++              return -EPROTO;
 +
-+      if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) {
-+              printk(KERN_ERR "Writable mappings must be shared.\n");
-+              return -EINVAL;
-+      }
++      hwinfo->nic_arch = res_mdata.nic_arch;
++      hwinfo->nic_variant = res_mdata.nic_variant;
++      hwinfo->nic_revision = res_mdata.nic_revision;
 +
-+      /* Slots must be in the NOT_YET_MAPPED state. */
-+      down_write(&private_data->grants_sem);
-+      for (i = 0; i < size; ++i) {
-+              if (private_data->grants[slot_index + i].state != 
-+                  GNTDEV_SLOT_NOT_YET_MAPPED) {
-+                      printk(KERN_ERR "Slot (index = %ld) is in the wrong "
-+                             "state (%d).\n", slot_index + i, 
-+                             private_data->grants[slot_index + i].state);
-+                      up_write(&private_data->grants_sem);
-+                      return -EINVAL;
++      hwinfo->evq_order = res_mdata.evq_order;
++      hwinfo->evq_offs = res_mdata.evq_offs;
++      hwinfo->evq_capacity = res_mdata.evq_capacity;
++      hwinfo->instance = res_mdata.instance;
++      hwinfo->rx_capacity = res_mdata.rx_capacity;
++      hwinfo->tx_capacity = res_mdata.tx_capacity;
++
++      VPRINTK("evq_order %d evq_offs %d evq_cap %d inst %d rx_cap %d tx_cap %d\n",
++              hwinfo->evq_order, hwinfo->evq_offs, hwinfo->evq_capacity,
++              hwinfo->instance, hwinfo->rx_capacity, hwinfo->tx_capacity);
++
++      for (i = 0; i < len; i++) {
++              struct efx_vi_hw_resource *res = &(res_array[i]);
++              switch (res->type) {
++              case EFX_VI_HW_RESOURCE_TXDMAQ:
++                      txdmaq_pfn = page_to_pfn(virt_to_page(res->address));
++                      break;
++              case EFX_VI_HW_RESOURCE_RXDMAQ: 
++                      rxdmaq_pfn = page_to_pfn(virt_to_page(res->address));
++                      break;
++              case EFX_VI_HW_RESOURCE_EVQTIMER:
++                      break;
++              case EFX_VI_HW_RESOURCE_EVQRPTR:
++              case EFX_VI_HW_RESOURCE_EVQRPTR_OFFSET:
++                      hwinfo->evq_rptr = res->address;
++                      break;
++              case EFX_VI_HW_RESOURCE_EVQMEMKVA: 
++                      accel_hw_priv->evq_npages =  1 << res_mdata.evq_order;
++                      pfn = page_to_pfn(virt_to_page(res->address));
++                      break;
++              case EFX_VI_HW_RESOURCE_BELLPAGE:
++                      hwinfo->doorbell_mfn  = res->address;
++                      break;
++              default:
++                      EPRINTK("%s: Unknown hardware resource type %d\n",
++                              __FUNCTION__, res->type);
++                      break;
 +              }
 +      }
 +
-+      /* Install the hook for unmapping. */
-+      vma->vm_ops = &gntdev_vmops;
-+    
-+      /* The VM area contains pages from another VM. */
-+      vma->vm_flags |= VM_FOREIGN;
-+      vma->vm_private_data = kzalloc(size * sizeof(struct page_struct *), 
-+                                     GFP_KERNEL);
-+      if (vma->vm_private_data == NULL) {
-+              printk(KERN_ERR "Couldn't allocate mapping structure for VM "
-+                     "area.\n");
-+              return -ENOMEM;
-+      }
++      VPRINTK("Passing txdmaq page pfn %lx\n", txdmaq_pfn);
++      accel_hw_priv->txdmaq_gnt = hwinfo->txdmaq_gnt = 
++              net_accel_grant_page(bend->hdev_data, pfn_to_mfn(txdmaq_pfn), 
++                                   0);
 +
-+      /* This flag prevents Bad PTE errors when the memory is unmapped. */
-+      vma->vm_flags |= VM_RESERVED;
++      VPRINTK("Passing rxdmaq page pfn %lx\n", rxdmaq_pfn);
++      accel_hw_priv->rxdmaq_gnt = hwinfo->rxdmaq_gnt = 
++              net_accel_grant_page(bend->hdev_data, pfn_to_mfn(rxdmaq_pfn), 
++                                   0);
 +
-+      /* This flag prevents this VM area being copied on a fork(). A better
-+       * behaviour might be to explicitly carry out the appropriate mappings
-+       * on fork(), but I don't know if there's a hook for this.
-+       */
-+      vma->vm_flags |= VM_DONTCOPY;
++      VPRINTK("Passing doorbell page mfn %x\n", hwinfo->doorbell_mfn);
++      /* Make the relevant H/W pages mappable by the far end */
++      accel_hw_priv->doorbell_gnt = hwinfo->doorbell_gnt = 
++              net_accel_grant_page(bend->hdev_data, hwinfo->doorbell_mfn, 1);
++      
++      /* Now do the same for the memory pages */
++      /* Convert the page + length we got back for the evq to grants. */
++      for (i = 0; i < accel_hw_priv->evq_npages; i++) {
++              accel_hw_priv->evq_mem_gnts[i] = hwinfo->evq_mem_gnts[i] =
++                      net_accel_grant_page(bend->hdev_data, pfn_to_mfn(pfn), 0);
++              VPRINTK("Got grant %u for evq pfn %x\n", hwinfo->evq_mem_gnts[i], 
++                      pfn);
++              pfn++;
++      }
 +
-+#ifdef CONFIG_X86
-+      /* This flag ensures that the page tables are not unpinned before the
-+       * VM area is unmapped. Therefore Xen still recognises the PTE as
-+       * belonging to an L1 pagetable, and the grant unmap operation will
-+       * succeed, even if the process does not exit cleanly.
-+       */
-+      vma->vm_mm->context.has_foreign_mappings = 1;
-+#endif
++      return 0;
++}
 +
-+      for (i = 0; i < size; ++i) {
 +
-+              flags = GNTMAP_host_map;
-+              if (!(vma->vm_flags & VM_WRITE))
-+                      flags |= GNTMAP_readonly;
++static int ef_bend_hwinfo_falcon_a(struct netback_accel *bend, 
++                                 struct net_accel_hw_falcon_a *hwinfo)
++{
++      int rc;
++      struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
 +
-+              kernel_vaddr = get_kernel_vaddr(private_data, slot_index + i);
-+              user_vaddr = get_user_vaddr(vma, i);
-+              page = pfn_to_page(__pa(kernel_vaddr) >> PAGE_SHIFT);
++      if ((rc = ef_bend_hwinfo_falcon_common(bend, &hwinfo->common)) != 0)
++              return rc;
 +
-+              gnttab_set_map_op(&op, kernel_vaddr, flags,   
-+                                private_data->grants[slot_index+i]
-+                                .u.valid.ref, 
-+                                private_data->grants[slot_index+i]
-+                                .u.valid.domid);
++      /*
++       * Note that unlike the above, where the message field is the
++       * page number, here evq_rptr is the entire address because
++       * it is currently a pointer into the densely mapped timer page.
++       */
++      VPRINTK("Passing evq_rptr pfn %x for rptr %x\n", 
++              hwinfo->common.evq_rptr >> PAGE_SHIFT,
++              hwinfo->common.evq_rptr);
++      rc = net_accel_grant_page(bend->hdev_data, 
++                                hwinfo->common.evq_rptr >> PAGE_SHIFT, 0);
++      if (rc < 0)
++              return rc;
 +
-+              /* Carry out the mapping of the grant reference. */
-+              ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, 
-+                                              &op, 1);
-+              BUG_ON(ret);
-+              if (op.status) {
-+                      printk(KERN_ERR "Error mapping the grant reference "
-+                             "into the kernel (%d). domid = %d; ref = %d\n",
-+                             op.status,
-+                             private_data->grants[slot_index+i]
-+                             .u.valid.domid,
-+                             private_data->grants[slot_index+i]
-+                             .u.valid.ref);
-+                      goto undo_map_out;
-+              }
++      accel_hw_priv->evq_rptr_gnt = hwinfo->evq_rptr_gnt = rc;
++      VPRINTK("evq_rptr_gnt got %d\n", hwinfo->evq_rptr_gnt);
++      
++      return 0;
++}
 +
-+              /* Store a reference to the page that will be mapped into user
-+               * space.
-+               */
-+              ((struct page **) vma->vm_private_data)[i] = page;
 +
-+              /* Mark mapped page as reserved. */
-+              SetPageReserved(page);
++static int ef_bend_hwinfo_falcon_b(struct netback_accel *bend, 
++                                 struct net_accel_hw_falcon_b *hwinfo)
++{
++      return ef_bend_hwinfo_falcon_common(bend, hwinfo);
++}
 +
-+              /* Record the grant handle, for use in the unmap operation. */
-+              private_data->grants[slot_index+i].u.valid.kernel_handle = 
-+                      op.handle;
-+              private_data->grants[slot_index+i].u.valid.dev_bus_addr = 
-+                      op.dev_bus_addr;
-+              
-+              private_data->grants[slot_index+i].state = GNTDEV_SLOT_MAPPED;
-+              private_data->grants[slot_index+i].u.valid.user_handle =
-+                      GNTDEV_INVALID_HANDLE;
 +
-+              /* Now perform the mapping to user space. */
-+              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
++/*
++ * Fill in the message with a description of the hardware resources, based on
++ * the H/W type
++ */
++static int netback_accel_hwinfo(struct netback_accel *bend, 
++                              struct net_accel_msg_hw *msgvi)
++{
++      int rc = 0;
++      
++      BUG_ON(bend->hw_state != NETBACK_ACCEL_RES_FILTER);
 +
-+                      /* NOT USING SHADOW PAGE TABLES. */
-+                      /* In this case, we map the grant(s) straight into user
-+                       * space.
-+                       */
++      msgvi->type = bend->hw_type;
++      switch (bend->hw_type) {
++      case NET_ACCEL_MSG_HWTYPE_FALCON_A:
++              rc = ef_bend_hwinfo_falcon_a(bend, &msgvi->resources.falcon_a);
++              break;
++      case NET_ACCEL_MSG_HWTYPE_FALCON_B:
++              rc = ef_bend_hwinfo_falcon_b(bend, &msgvi->resources.falcon_b);
++              break;
++      case NET_ACCEL_MSG_HWTYPE_NONE:
++              /* Nothing to do. The slow path should just work. */
++              break;
++      }
 +
-+                      /* Get the machine address of the PTE for the user 
-+                       *  page.
-+                       */
-+                      if ((ret = create_lookup_pte_addr(vma->vm_mm, 
-+                                                        vma->vm_start 
-+                                                        + (i << PAGE_SHIFT), 
-+                                                        &ptep)))
-+                      {
-+                              printk(KERN_ERR "Error obtaining PTE pointer "
-+                                     "(%d).\n", ret);
-+                              goto undo_map_out;
-+                      }
-+                      
-+                      /* Configure the map operation. */
++      if (rc == 0)
++              bend->hw_state = NETBACK_ACCEL_RES_HWINFO;
 +              
-+                      /* The reference is to be used by host CPUs. */
-+                      flags = GNTMAP_host_map;
-+                      
-+                      /* Specifies a user space mapping. */
-+                      flags |= GNTMAP_application_map;
-+                      
-+                      /* The map request contains the machine address of the
-+                       * PTE to update.
-+                       */
-+                      flags |= GNTMAP_contains_pte;
-+                      
-+                      if (!(vma->vm_flags & VM_WRITE))
-+                              flags |= GNTMAP_readonly;
++      return rc;
++}
 +
-+                      gnttab_set_map_op(&op, ptep, flags, 
-+                                        private_data->grants[slot_index+i]
-+                                        .u.valid.ref, 
-+                                        private_data->grants[slot_index+i]
-+                                        .u.valid.domid);
 +
-+                      /* Carry out the mapping of the grant reference. */
-+                      ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref,
-+                                                      &op, 1);
-+                      BUG_ON(ret);
-+                      if (op.status) {
-+                              printk(KERN_ERR "Error mapping the grant "
-+                                     "reference into user space (%d). domid "
-+                                     "= %d; ref = %d\n", op.status,
-+                                     private_data->grants[slot_index+i].u
-+                                     .valid.domid,
-+                                     private_data->grants[slot_index+i].u
-+                                     .valid.ref);
-+                              goto undo_map_out;
-+                      }
-+                      
-+                      /* Record the grant handle, for use in the unmap 
-+                       * operation. 
-+                       */
-+                      private_data->grants[slot_index+i].u.
-+                              valid.user_handle = op.handle;
++/* Allocate hardware resources and make them available to the client domain */
++int netback_accel_setup_vnic_hw(struct netback_accel *bend)
++{
++      struct net_accel_msg msg;
++      int err;
 +
-+                      /* Update p2m structure with the new mapping. */
-+                      set_phys_to_machine(__pa(kernel_vaddr) >> PAGE_SHIFT,
-+                                          FOREIGN_FRAME(private_data->
-+                                                        grants[slot_index+i]
-+                                                        .u.valid.dev_bus_addr
-+                                                        >> PAGE_SHIFT));
-+              } else {
-+                      /* USING SHADOW PAGE TABLES. */
-+                      /* In this case, we simply insert the page into the VM
-+                       * area. */
-+                      ret = vm_insert_page(vma, user_vaddr, page);
-+              }
++      /* Allocate the event queue, VI and so on. */
++      err = ef_get_vnic(bend);
++      if (err) {
++              EPRINTK("Failed to allocate hardware resource for bend:"
++                      "error %d\n", err);
++              return err;
++      }
 +
++      /* Set up the filter management */
++      err = netback_accel_filter_init(bend);
++      if (err) {
++              EPRINTK("Filter setup failed, error %d", err);
++              ef_free_vnic(bend);
++              return err;
 +      }
 +
-+      up_write(&private_data->grants_sem);
-+      return 0;
++      net_accel_msg_init(&msg, NET_ACCEL_MSG_SETHW);
 +
-+undo_map_out:
-+      /* If we have a mapping failure, the unmapping will be taken care of
-+       * by do_mmap_pgoff(), which will eventually call gntdev_clear_pte().
-+       * All we need to do here is free the vma_private_data.
++      /*
++       * Extract the low-level hardware info we will actually pass to the
++       * other end, and set up the grants/ioremap permissions needed
 +       */
-+      kfree(vma->vm_private_data);
++      err = netback_accel_hwinfo(bend, &msg.u.hw);
 +
-+      /* THIS IS VERY UNPLEASANT: do_mmap_pgoff() will set the vma->vm_file
-+       * to NULL on failure. However, we need this in gntdev_clear_pte() to
-+       * unmap the grants. Therefore, we smuggle a reference to the file's
-+       * private data in the VM area's private data pointer.
++      if (err != 0) {
++              netback_accel_filter_shutdown(bend);
++              ef_free_vnic(bend);
++              return err;
++      }
++
++      /* Send the message, this is a reply to a hello-reply */
++      err = net_accel_msg_reply_notify(bend->shared_page, 
++                                       bend->msg_channel_irq, 
++                                       &bend->to_domU, &msg);
++
++      /*
++       * The message should succeed as it's logically a reply and we
++       * guarantee space for replies, but a misbehaving frontend
++       * could result in that behaviour, so be tolerant
 +       */
-+      vma->vm_private_data = private_data;
-+      
-+      up_write(&private_data->grants_sem);
++      if (err != 0) {
++              netback_accel_release_hwinfo(bend);
++              netback_accel_filter_shutdown(bend);
++              ef_free_vnic(bend);
++      }
 +
-+      return -ENOMEM;
++      return err;
 +}
 +
-+static pte_t gntdev_clear_pte(struct vm_area_struct *vma, unsigned long addr,
-+                            pte_t *ptep, int is_fullmm)
-+{
-+      int slot_index, ret;
-+      pte_t copy;
-+      struct gnttab_unmap_grant_ref op;
-+      gntdev_file_private_data_t *private_data;
 +
-+      /* THIS IS VERY UNPLEASANT: do_mmap_pgoff() will set the vma->vm_file
-+       * to NULL on failure. However, we need this in gntdev_clear_pte() to
-+       * unmap the grants. Therefore, we smuggle a reference to the file's
-+       * private data in the VM area's private data pointer.
-+       */
-+      if (vma->vm_file) {
-+              private_data = (gntdev_file_private_data_t *)
-+                      vma->vm_file->private_data;
-+      } else if (vma->vm_private_data) {
-+              private_data = (gntdev_file_private_data_t *)
-+                      vma->vm_private_data;
-+      } else {
-+              private_data = NULL; /* gcc warning */
++/* Free hardware resources  */
++void netback_accel_shutdown_vnic_hw(struct netback_accel *bend)
++{
++      /*
++       * Only try and release resources if accel_hw_priv was setup,
++       * otherwise there is nothing to do as we're on "null-op"
++       * acceleration
++       */
++      switch (bend->hw_state) {
++      case NETBACK_ACCEL_RES_HWINFO:
++              VPRINTK("Release hardware resources\n");
++              netback_accel_release_hwinfo(bend);
++              /* deliberate drop through */
++      case NETBACK_ACCEL_RES_FILTER:          
++              VPRINTK("Free filters...\n");
++              netback_accel_filter_shutdown(bend);
++              /* deliberate drop through */
++      case NETBACK_ACCEL_RES_ALLOC:
++              VPRINTK("Free vnic...\n");
++              ef_free_vnic(bend);
++              /* deliberate drop through */
++      case NETBACK_ACCEL_RES_NONE:
++              break;
++      default:
 +              BUG();
 +      }
++}
 +
-+      /* Copy the existing value of the PTE for returning. */
-+      copy = *ptep;
++/**************************************************************************
++ * 
++ * Buffer table stuff
++ *
++ **************************************************************************/
 +
-+      /* Calculate the grant relating to this PTE. */
-+      slot_index = vma->vm_pgoff + ((addr - vma->vm_start) >> PAGE_SHIFT);
++/*
++ * Undo any allocation that netback_accel_msg_rx_buffer_map() has made
++ * if it fails half way through
++ */
++static inline void buffer_map_cleanup(struct netback_accel *bend, int i)
++{
++      while (i > 0) {
++              i--;
++              bend->buffer_maps_index--;
++              net_accel_unmap_device_page(bend->hdev_data, 
++                                          bend->buffer_maps[bend->buffer_maps_index],
++                                          bend->buffer_addrs[bend->buffer_maps_index]);
++      }
++}
 +
-+      /* Only unmap grants if the slot has been mapped. This could be being
-+       * called from a failing mmap().
-+       */
-+      if (private_data->grants[slot_index].state == GNTDEV_SLOT_MAPPED) {
 +
-+              /* First, we clear the user space mapping, if it has been made.
-+               */
-+              if (private_data->grants[slot_index].u.valid.user_handle !=
-+                  GNTDEV_INVALID_HANDLE && 
-+                  !xen_feature(XENFEAT_auto_translated_physmap)) {
-+                      /* NOT USING SHADOW PAGE TABLES. */
-+                      gnttab_set_unmap_op(&op, virt_to_machine(ptep), 
-+                                          GNTMAP_contains_pte,
-+                                          private_data->grants[slot_index]
-+                                          .u.valid.user_handle);
-+                      ret = HYPERVISOR_grant_table_op(
-+                              GNTTABOP_unmap_grant_ref, &op, 1);
-+                      BUG_ON(ret);
-+                      if (op.status)
-+                              printk("User unmap grant status = %d\n", 
-+                                     op.status);
-+              } else {
-+                      /* USING SHADOW PAGE TABLES. */
-+                      pte_clear_full(vma->vm_mm, addr, ptep, is_fullmm);
-+              }
++int netback_accel_add_buffers(struct netback_accel *bend, int pages, int log2_pages,
++                            u32 *grants, u32 *buf_addr_out)
++{
++      struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
++      unsigned long long addr_array[NET_ACCEL_MSG_MAX_PAGE_REQ];
++      int rc, i, index;
++      u64 dev_bus_addr;
 +
-+              /* Finally, we unmap the grant from kernel space. */
-+              gnttab_set_unmap_op(&op, 
-+                                  get_kernel_vaddr(private_data, slot_index),
-+                                  GNTMAP_host_map, 
-+                                  private_data->grants[slot_index].u.valid
-+                                  .kernel_handle);
-+              ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, 
-+                                              &op, 1);
-+              BUG_ON(ret);
-+              if (op.status)
-+                      printk("Kernel unmap grant status = %d\n", op.status);
++      /* Make sure we can't overflow the dma_maps array */
++      if (accel_hw_priv->dma_maps_index >= 
++          bend->max_pages / NET_ACCEL_MSG_MAX_PAGE_REQ) {
++              EPRINTK("%s: too many buffer table allocations: %d %d\n",
++                      __FUNCTION__, accel_hw_priv->dma_maps_index, 
++                      bend->max_pages / NET_ACCEL_MSG_MAX_PAGE_REQ);
++              return -EINVAL;
++      }
 +
++      /* Make sure we can't overflow the buffer_maps array */
++      if (bend->buffer_maps_index + pages > bend->max_pages) {
++              EPRINTK("%s: too many pages mapped: %d + %d > %d\n", 
++                      __FUNCTION__, bend->buffer_maps_index,
++                      pages, bend->max_pages);
++              return -EINVAL;
++      }
 +
-+              /* Return slot to the not-yet-mapped state, so that it may be
-+               * mapped again, or removed by a subsequent ioctl.
-+               */
-+              private_data->grants[slot_index].state = 
-+                      GNTDEV_SLOT_NOT_YET_MAPPED;
++      for (i = 0; i < pages; i++) {
++              VPRINTK("%s: mapping page %d\n", __FUNCTION__, i);
++              rc = net_accel_map_device_page
++                      (bend->hdev_data, grants[i],
++                       &bend->buffer_maps[bend->buffer_maps_index],
++                       &dev_bus_addr);
++    
++              if (rc != 0) {
++                      EPRINTK("error in net_accel_map_device_page\n");
++                      buffer_map_cleanup(bend, i);
++                      return rc;
++              }
++              
++              bend->buffer_addrs[bend->buffer_maps_index] = dev_bus_addr;
 +
-+              /* Invalidate the physical to machine mapping for this page. */
-+              set_phys_to_machine(__pa(get_kernel_vaddr(private_data, 
-+                                                        slot_index)) 
-+                                  >> PAGE_SHIFT, INVALID_P2M_ENTRY);
++              bend->buffer_maps_index++;
 +
-+      } else {
-+              pte_clear_full(vma->vm_mm, addr, ptep, is_fullmm);
++              addr_array[i] = dev_bus_addr;
 +      }
 +
-+      return copy;
-+}
++      VPRINTK("%s: mapping dma addresses to vih %p\n", __FUNCTION__, 
++              accel_hw_priv->efx_vih);
 +
-+/* "Destructor" for a VM area.
-+ */
-+static void gntdev_vma_close(struct vm_area_struct *vma) {
-+      if (vma->vm_private_data) {
-+              kfree(vma->vm_private_data);
++      index = accel_hw_priv->dma_maps_index;
++      if ((rc = efx_vi_dma_map_addrs(accel_hw_priv->efx_vih, addr_array, pages,
++                                     &(accel_hw_priv->dma_maps[index]))) < 0) {
++              EPRINTK("error in dma_map_pages\n");
++              buffer_map_cleanup(bend, i);
++              return rc;
 +      }
++
++      accel_hw_priv->dma_maps_index++;
++      NETBACK_ACCEL_STATS_OP(bend->stats.num_buffer_pages += pages);
++
++      //DPRINTK("%s: getting map address\n", __FUNCTION__);
++
++      *buf_addr_out = efx_vi_dma_get_map_addr(accel_hw_priv->efx_vih, 
++                                              accel_hw_priv->dma_maps[index]);
++
++      //DPRINTK("%s: done\n", __FUNCTION__);
++
++      return 0;
 +}
 +
-+/* Called when an ioctl is made on the device.
-+ */
-+static long gntdev_ioctl(struct file *flip,
-+                       unsigned int cmd, unsigned long arg)
++
++int netback_accel_remove_buffers(struct netback_accel *bend)
 +{
-+      int rc = 0;
-+      gntdev_file_private_data_t *private_data = 
-+              (gntdev_file_private_data_t *) flip->private_data;
++      /* Only try to free buffers if accel_hw_priv was setup */
++      if (bend->hw_state != NETBACK_ACCEL_RES_NONE) {
++              struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
++              int i;
 +
-+      switch (cmd) {
-+      case IOCTL_GNTDEV_MAP_GRANT_REF:
-+      {
-+              struct ioctl_gntdev_map_grant_ref op;
-+              down_write(&private_data->grants_sem);
-+              down_write(&private_data->free_list_sem);
++              efx_vi_reset(accel_hw_priv->efx_vih);
 +
-+              if ((rc = copy_from_user(&op, (void __user *) arg, 
-+                                       sizeof(op)))) {
-+                      rc = -EFAULT;
-+                      goto map_out;
++              while (accel_hw_priv->dma_maps_index > 0) {
++                      accel_hw_priv->dma_maps_index--;
++                      i = accel_hw_priv->dma_maps_index;
++                      efx_vi_dma_unmap_addrs(accel_hw_priv->efx_vih, 
++                                             accel_hw_priv->dma_maps[i]);
 +              }
-+              if (unlikely(op.count <= 0)) {
-+                      rc = -EINVAL;
-+                      goto map_out;
++              
++              while (bend->buffer_maps_index > 0) {
++                      VPRINTK("Unmapping granted buffer %d\n", 
++                              bend->buffer_maps_index);
++                      bend->buffer_maps_index--;
++                      i = bend->buffer_maps_index;
++                      net_accel_unmap_device_page(bend->hdev_data, 
++                                                  bend->buffer_maps[i],
++                                                  bend->buffer_addrs[i]);
 +              }
 +
-+              if (op.count == 1) {
-+                      if ((rc = add_grant_reference(flip, &op.refs[0],
-+                                                    &op.index)) < 0) {
-+                              printk(KERN_ERR "Adding grant reference "
-+                                     "failed (%d).\n", rc);
-+                              goto map_out;
-+                      }
-+              } else {
-+                      struct ioctl_gntdev_grant_ref *refs, *u;
-+                      refs = kmalloc(op.count * sizeof(*refs), GFP_KERNEL);
-+                      if (!refs) {
-+                              rc = -ENOMEM;
-+                              goto map_out;
-+                      }
-+                      u = ((struct ioctl_gntdev_map_grant_ref *)arg)->refs;
-+                      if ((rc = copy_from_user(refs,
-+                                               (void __user *)u,
-+                                               sizeof(*refs) * op.count))) {
-+                              printk(KERN_ERR "Copying refs from user failed"
-+                                     " (%d).\n", rc);
-+                              rc = -EINVAL;
-+                              goto map_out;
-+                      }
-+                      if ((rc = find_contiguous_free_range(flip, op.count))
-+                          < 0) {
-+                              printk(KERN_ERR "Finding contiguous range "
-+                                     "failed (%d).\n", rc);
-+                              kfree(refs);
-+                              goto map_out;
-+                      }
-+                      op.index = rc << PAGE_SHIFT;
-+                      if ((rc = add_grant_references(flip, op.count,
-+                                                     refs, rc))) {
-+                              printk(KERN_ERR "Adding grant references "
-+                                     "failed (%d).\n", rc);
-+                              kfree(refs);
-+                              goto map_out;
-+                      }
-+                      compress_free_list(flip);
-+                      kfree(refs);
-+              }
-+              if ((rc = copy_to_user((void __user *) arg, 
-+                                     &op, 
-+                                     sizeof(op)))) {
-+                      printk(KERN_ERR "Copying result back to user failed "
-+                             "(%d)\n", rc);
-+                      rc = -EFAULT;
-+                      goto map_out;
-+              }
-+      map_out:
-+              up_write(&private_data->grants_sem);
-+              up_write(&private_data->free_list_sem);
-+              return rc;
++              NETBACK_ACCEL_STATS_OP(bend->stats.num_buffer_pages = 0);
 +      }
-+      case IOCTL_GNTDEV_UNMAP_GRANT_REF:
-+      {
-+              struct ioctl_gntdev_unmap_grant_ref op;
-+              int i, start_index;
 +
-+              down_write(&private_data->grants_sem);
-+              down_write(&private_data->free_list_sem);
++      return 0;
++}
 +
-+              if ((rc = copy_from_user(&op, 
-+                                       (void __user *) arg, 
-+                                       sizeof(op)))) {
-+                      rc = -EFAULT;
-+                      goto unmap_out;
-+              }
++/**************************************************************************
++ * 
++ * Filter stuff
++ *
++ **************************************************************************/
 +
-+              start_index = op.index >> PAGE_SHIFT;
++static int netback_accel_filter_init(struct netback_accel *bend)
++{
++      struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
++      int i, rc;
 +
-+              /* First, check that all pages are in the NOT_YET_MAPPED
-+               * state.
-+               */
-+              for (i = 0; i < op.count; ++i) {
-+                      if (unlikely
-+                          (private_data->grants[start_index + i].state
-+                           != GNTDEV_SLOT_NOT_YET_MAPPED)) {
-+                              if (private_data->grants[start_index + i].state
-+                                  == GNTDEV_SLOT_INVALID) {
-+                                      printk(KERN_ERR
-+                                             "Tried to remove an invalid "
-+                                             "grant at offset 0x%x.",
-+                                             (start_index + i) 
-+                                             << PAGE_SHIFT);
-+                                      rc = -EINVAL;
-+                              } else {
-+                                      printk(KERN_ERR
-+                                             "Tried to remove a grant which "
-+                                             "is currently mmap()-ed at "
-+                                             "offset 0x%x.",
-+                                             (start_index + i) 
-+                                             << PAGE_SHIFT);
-+                                      rc = -EBUSY;
-+                              }
-+                              goto unmap_out;
-+                      }
-+              }
++      BUG_ON(bend->hw_state != NETBACK_ACCEL_RES_ALLOC);
 +
-+              /* Unmap pages and add them to the free list.
-+               */
-+              for (i = 0; i < op.count; ++i) {
-+                      private_data->grants[start_index+i].state = 
-+                              GNTDEV_SLOT_INVALID;
-+                      private_data->grants[start_index+i].u.free_list_index =
-+                              private_data->free_list_size;
-+                      private_data->free_list[private_data->free_list_size] =
-+                              start_index + i;
-+                      ++private_data->free_list_size;
-+              }
-+              compress_free_list(flip);
++      spin_lock_init(&accel_hw_priv->filter_lock);
 +
-+      unmap_out:
-+              up_write(&private_data->grants_sem);
-+              up_write(&private_data->free_list_sem);
++      if ((rc = cuckoo_hash_init(&accel_hw_priv->filter_hash_table, 
++                                 5 /* space for 32 filters */, 8)) != 0) {
++              EPRINTK("Failed to initialise filter hash table\n");
 +              return rc;
 +      }
-+      case IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR:
-+      {
-+              struct ioctl_gntdev_get_offset_for_vaddr op;
-+              struct vm_area_struct *vma;
-+              unsigned long vaddr;
 +
-+              if ((rc = copy_from_user(&op, 
-+                                       (void __user *) arg, 
-+                                       sizeof(op)))) {
-+                      rc = -EFAULT;
-+                      goto get_offset_out;
-+              }
-+              vaddr = (unsigned long)op.vaddr;
++      accel_hw_priv->fspecs = kzalloc(sizeof(struct netback_accel_filter_spec) *
++                                      bend->quotas.max_filters,
++                                      GFP_KERNEL);
 +
-+              down_read(&current->mm->mmap_sem);              
-+              vma = find_vma(current->mm, vaddr);
-+              if (vma == NULL) {
-+                      rc = -EFAULT;
-+                      goto get_offset_unlock_out;
-+              }
-+              if ((!vma->vm_ops) || (vma->vm_ops != &gntdev_vmops)) {
-+                      printk(KERN_ERR "The vaddr specified does not belong "
-+                             "to a gntdev instance: %#lx\n", vaddr);
-+                      rc = -EFAULT;
-+                      goto get_offset_unlock_out;
-+              }
-+              if (vma->vm_start != vaddr) {
-+                      printk(KERN_ERR "The vaddr specified in an "
-+                             "IOCTL_GNTDEV_GET_OFFSET_FOR_VADDR must be at "
-+                             "the start of the VM area. vma->vm_start = "
-+                             "%#lx; vaddr = %#lx\n",
-+                             vma->vm_start, vaddr);
-+                      rc = -EFAULT;
-+                      goto get_offset_unlock_out;
-+              }
-+              op.offset = vma->vm_pgoff << PAGE_SHIFT;
-+              op.count = (vma->vm_end - vma->vm_start) >> PAGE_SHIFT;
-+              up_read(&current->mm->mmap_sem);
-+              if ((rc = copy_to_user((void __user *) arg, 
-+                                     &op, 
-+                                     sizeof(op)))) {
-+                      rc = -EFAULT;
-+                      goto get_offset_out;
-+              }
-+              goto get_offset_out;
-+      get_offset_unlock_out:
-+              up_read(&current->mm->mmap_sem);
-+      get_offset_out:
-+              return rc;
++      if (accel_hw_priv->fspecs == NULL) {
++              EPRINTK("No memory for filter specs.\n");
++              cuckoo_hash_destroy(&accel_hw_priv->filter_hash_table);
++              return -ENOMEM;
 +      }
-+      default:
-+              return -ENOIOCTLCMD;
++
++      for (i = 0; i < bend->quotas.max_filters; i++) {
++              accel_hw_priv->free_filters |= (1 << i);
 +      }
 +
++      /* Base mask on highest set bit in max_filters  */
++      accel_hw_priv->filter_idx_mask = (1 << fls(bend->quotas.max_filters)) - 1;
++      VPRINTK("filter setup: max is %x mask is %x\n",
++              bend->quotas.max_filters, accel_hw_priv->filter_idx_mask);
++
++      bend->hw_state = NETBACK_ACCEL_RES_FILTER;
++
 +      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/gntdev/Makefile linux-2.6.18-xen.hg/drivers/xen/gntdev/Makefile
---- linux-2.6.18/drivers/xen/gntdev/Makefile   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/gntdev/Makefile    2007-12-23 11:15:34.047935255 +0100
-@@ -0,0 +1 @@
-+obj-$(CONFIG_XEN_GRANT_DEV) := gntdev.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/Kconfig linux-2.6.18-xen.hg/drivers/xen/Kconfig
---- linux-2.6.18/drivers/xen/Kconfig   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/Kconfig    2007-12-23 11:15:33.537908474 +0100
-@@ -0,0 +1,286 @@
-+#
-+# This Kconfig describe xen options
-+#
 +
-+mainmenu "Xen Configuration"
 +
-+config XEN
-+      bool
-+      default y if X86_XEN || X86_64_XEN
-+      help
-+        This is the Linux Xen port.
++static inline void make_filter_key(cuckoo_hash_ip_key *key,  
++                                 struct netback_accel_filter_spec *filt)
 +
-+if XEN
-+config XEN_INTERFACE_VERSION
-+      hex
-+      default 0x00030207
++{
++      key->local_ip = filt->destip_be;
++      key->local_port = filt->destport_be;
++      key->proto = filt->proto;
++}
 +
-+menu "XEN"
 +
-+config XEN_PRIVILEGED_GUEST
-+      bool "Privileged Guest (domain 0)"
-+      default n
-+      help
-+        Support for privileged operation (domain 0)
++static inline 
++void netback_accel_free_filter(struct falcon_bend_accel_priv *accel_hw_priv,
++                             int filter)
++{
++      cuckoo_hash_ip_key filter_key;
 +
-+config XEN_UNPRIVILEGED_GUEST
-+      def_bool !XEN_PRIVILEGED_GUEST
++      if (!(accel_hw_priv->free_filters & (1 << filter))) {
++              efx_vi_filter_stop(accel_hw_priv->efx_vih, 
++                                 accel_hw_priv->fspecs[filter].filter_handle);
++              make_filter_key(&filter_key, &(accel_hw_priv->fspecs[filter]));
++              if (cuckoo_hash_remove(&accel_hw_priv->filter_hash_table,
++                                     (cuckoo_hash_key *)&filter_key)) {
++                      EPRINTK("%s: Couldn't find filter to remove from table\n",
++                              __FUNCTION__);
++                      BUG();
++              }
++      }
++}
 +
-+config XEN_PRIVCMD
-+      def_bool y
-+      depends on PROC_FS
 +
-+config XEN_XENBUS_DEV
-+      def_bool y
-+      depends on PROC_FS
++static void netback_accel_filter_shutdown(struct netback_accel *bend)
++{
++      struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
++      int i;
++      unsigned long flags;
 +
-+config XEN_BACKEND
-+        tristate "Backend driver support"
-+        default XEN_PRIVILEGED_GUEST
-+        help
-+          Support for backend device drivers that provide I/O services
-+          to other virtual machines.
++      BUG_ON(bend->hw_state != NETBACK_ACCEL_RES_FILTER);
 +
-+config XEN_BLKDEV_BACKEND
-+      tristate "Block-device backend driver"
-+        depends on XEN_BACKEND
-+      default XEN_BACKEND
-+      help
-+        The block-device backend driver allows the kernel to export its
-+        block devices to other guests via a high-performance shared-memory
-+        interface.
++      spin_lock_irqsave(&accel_hw_priv->filter_lock, flags);
 +
-+config XEN_BLKDEV_TAP
-+      tristate "Block-device tap backend driver"
-+      depends on XEN_BACKEND
-+      default XEN_BACKEND
-+      help
-+        The block tap driver is an alternative to the block back driver 
-+          and allows VM block requests to be redirected to userspace through
-+          a device interface.  The tap allows user-space development of 
-+          high-performance block backends, where disk images may be implemented
-+          as files, in memory, or on other hosts across the network.  This 
-+        driver can safely coexist with the existing blockback driver.
++      BUG_ON(accel_hw_priv->fspecs == NULL);
 +
-+config XEN_NETDEV_BACKEND
-+      tristate "Network-device backend driver"
-+        depends on XEN_BACKEND && NET
-+      default XEN_BACKEND
-+      help
-+        The network-device backend driver allows the kernel to export its
-+        network devices to other guests via a high-performance shared-memory
-+        interface.
++      for (i = 0; i < bend->quotas.max_filters; i++) {
++              netback_accel_free_filter(accel_hw_priv, i);
++      }
++      
++      kfree(accel_hw_priv->fspecs);
++      accel_hw_priv->fspecs = NULL;
++      accel_hw_priv->free_filters = 0;
++      
++      cuckoo_hash_destroy(&accel_hw_priv->filter_hash_table);
 +
-+config XEN_NETDEV_PIPELINED_TRANSMITTER
-+      bool "Pipelined transmitter (DANGEROUS)"
-+      depends on XEN_NETDEV_BACKEND
-+      help
-+        If the net backend is a dumb domain, such as a transparent Ethernet
-+        bridge with no local IP interface, it is safe to say Y here to get
-+        slightly lower network overhead.
-+        If the backend has a local IP interface; or may be doing smart things
-+        like reassembling packets to perform firewall filtering; or if you
-+        are unsure; or if you experience network hangs when this option is
-+        enabled; then you must say N here.
++      spin_unlock_irqrestore(&accel_hw_priv->filter_lock, flags);
 +
-+config XEN_NETDEV_LOOPBACK
-+      tristate "Network-device loopback driver"
-+      depends on XEN_NETDEV_BACKEND
-+      help
-+        A two-interface loopback device to emulate a local netfront-netback
-+        connection. If unsure, it is probably safe to say N here.
++      bend->hw_state = NETBACK_ACCEL_RES_ALLOC;
++}
 +
-+config XEN_PCIDEV_BACKEND
-+      tristate "PCI-device backend driver"
-+      depends on PCI && XEN_BACKEND
-+      default XEN_BACKEND
-+      help
-+        The PCI device backend driver allows the kernel to export arbitrary
-+        PCI devices to other guests. If you select this to be a module, you
-+        will need to make sure no other driver has bound to the device(s)
-+        you want to make visible to other guests.
 +
-+choice
-+      prompt "PCI Backend Mode"
-+      depends on XEN_PCIDEV_BACKEND
-+      default XEN_PCIDEV_BACKEND_VPCI if !IA64
-+      default XEN_PCIDEV_BACKEND_CONTROLLER if IA64
++/*! Suggest a filter to replace when we want to insert a new one and have
++ *  none free.
++ */
++static unsigned get_victim_filter(struct netback_accel *bend)
++{
++      /*
++       * We could attempt to get really clever, and may do at some
++       * point, but random replacement is v. cheap and low on
++       * pathological worst cases.
++       */
++      unsigned index, cycles;
 +
-+config XEN_PCIDEV_BACKEND_VPCI
-+      bool "Virtual PCI"
-+      ---help---
-+        This PCI Backend hides the true PCI topology and makes the frontend
-+        think there is a single PCI bus with only the exported devices on it.
-+        For example, a device at 03:05.0 will be re-assigned to 00:00.0. A
-+        second device at 02:1a.1 will be re-assigned to 00:01.1.
++      rdtscl(cycles);
 +
-+config XEN_PCIDEV_BACKEND_PASS
-+      bool "Passthrough"
-+      ---help---
-+        This PCI Backend provides a real view of the PCI topology to the
-+        frontend (for example, a device at 06:01.b will still appear at
-+        06:01.b to the frontend). This is similar to how Xen 2.0.x exposed
-+        PCI devices to its driver domains. This may be required for drivers
-+        which depend on finding their hardward in certain bus/slot
-+        locations.
++      /*
++       * Some doubt about the quality of the bottom few bits, so
++       * throw 'em * away
++       */
++      index = (cycles >> 4) & ((struct falcon_bend_accel_priv *)
++                               bend->accel_hw_priv)->filter_idx_mask;
++      /*
++       * We don't enforce that the number of filters is a power of
++       * two, but the masking gets us to within one subtraction of a
++       * valid index
++       */
++      if (index >= bend->quotas.max_filters)
++              index -= bend->quotas.max_filters;
++      DPRINTK("backend %s->%d has no free filters. Filter %d will be evicted\n",
++              bend->nicname, bend->far_end, index);
++      return index;
++}
 +
-+config XEN_PCIDEV_BACKEND_SLOT
-+      bool "Slot"
-+      ---help---
-+        This PCI Backend hides the true PCI topology and makes the frontend
-+        think there is a single PCI bus with only the exported devices on it.
-+        Contrary to the virtual PCI backend, a function becomes a new slot.
-+        For example, a device at 03:05.2 will be re-assigned to 00:00.0. A
-+        second device at 02:1a.1 will be re-assigned to 00:01.0.
 +
-+config XEN_PCIDEV_BACKEND_CONTROLLER
-+      bool "Controller"
-+      depends on IA64
-+      ---help---
-+        This PCI backend virtualizes the PCI bus topology by providing a
-+        virtual bus per PCI root device.  Devices which are physically under
-+        the same root bus will appear on the same virtual bus.  For systems
-+        with complex I/O addressing, this is the only backend which supports
-+        extended I/O port spaces and MMIO translation offsets.  This backend
-+        also supports slot virtualization.  For example, a device at
-+        0000:01:02.1 will be re-assigned to 0000:00:00.0.  A second device
-+        at 0000:02:05.0 (behind a P2P bridge on bus 0000:01) will be
-+        re-assigned to 0000:00:01.0.  A third device at 0000:16:05.0 (under
-+        a different PCI root bus) will be re-assigned to 0000:01:00.0.
++/* Add a filter for the specified IP/port to the backend */
++int 
++netback_accel_filter_check_add(struct netback_accel *bend, 
++                             struct netback_accel_filter_spec *filt)
++{
++      struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
++      struct netback_accel_filter_spec *fs;
++      unsigned filter_index;
++      unsigned long flags;
++      int rc, recycling = 0;
++      cuckoo_hash_ip_key filter_key, evict_key;
 +
-+endchoice
++      BUG_ON(filt->proto != IPPROTO_TCP && filt->proto != IPPROTO_UDP);
 +
-+config XEN_PCIDEV_BE_DEBUG
-+      bool "PCI Backend Debugging"
-+      depends on XEN_PCIDEV_BACKEND
++      DPRINTK("Will add %s filter for dst ip %08x and dst port %d\n", 
++              (filt->proto == IPPROTO_TCP) ? "TCP" : "UDP",
++              be32_to_cpu(filt->destip_be), be16_to_cpu(filt->destport_be));
 +
-+config XEN_TPMDEV_BACKEND
-+      tristate "TPM-device backend driver"
-+        depends on XEN_BACKEND
-+      help
-+        The TPM-device backend driver
++      spin_lock_irqsave(&accel_hw_priv->filter_lock, flags);
++      /*
++       * Check to see if we're already filtering this IP address and
++       * port. Happens if you insert a filter mid-stream as there
++       * are many packets backed up to be delivered to dom0 already
++       */
++      make_filter_key(&filter_key, filt);
++      if (cuckoo_hash_lookup(&accel_hw_priv->filter_hash_table, 
++                             (cuckoo_hash_key *)(&filter_key), 
++                             &filter_index)) {
++              DPRINTK("Found matching filter %d already in table\n", 
++                      filter_index);
++              rc = -1;
++              goto out;
++      }
 +
-+config XEN_BLKDEV_FRONTEND
-+      tristate "Block-device frontend driver"
-+      default y
-+      help
-+        The block-device frontend driver allows the kernel to access block
-+        devices mounted within another guest OS. Unless you are building a
-+        dedicated device-driver domain, or your master control domain
-+        (domain 0), then you almost certainly want to say Y here.
++      if (accel_hw_priv->free_filters == 0) {
++              filter_index = get_victim_filter(bend);
++              recycling = 1;
++      } else {
++              filter_index = __ffs(accel_hw_priv->free_filters);
++              clear_bit(filter_index, &accel_hw_priv->free_filters);
++      }
 +
-+config XEN_NETDEV_FRONTEND
-+      tristate "Network-device frontend driver"
-+      depends on NET
-+      default y
-+      help
-+        The network-device frontend driver allows the kernel to access
-+        network interfaces within another guest OS. Unless you are building a
-+        dedicated device-driver domain, or your master control domain
-+        (domain 0), then you almost certainly want to say Y here.
++      fs = &accel_hw_priv->fspecs[filter_index];
 +
-+config XEN_GRANT_DEV
-+      tristate "User-space granted page access driver"
-+      default XEN_PRIVILEGED_GUEST
-+      help
-+        Device for accessing (in user-space) pages that have been granted
-+        by other domains.
++      if (recycling) {
++              DPRINTK("Removing filter index %d handle %p\n", filter_index,
++                      fs->filter_handle);
 +
-+config XEN_FRAMEBUFFER
-+      tristate "Framebuffer-device frontend driver"
-+      depends on FB
-+      select FB_CFB_FILLRECT
-+      select FB_CFB_COPYAREA
-+      select FB_CFB_IMAGEBLIT
-+      default y
-+      help
-+        The framebuffer-device frontend drivers allows the kernel to create a
-+        virtual framebuffer.  This framebuffer can be viewed in another
-+        domain.  Unless this domain has access to a real video card, you
-+        probably want to say Y here.
++              if ((rc = efx_vi_filter_stop(accel_hw_priv->efx_vih, 
++                                           fs->filter_handle)) != 0) {
++                      EPRINTK("Couldn't clear NIC filter table entry %d\n", rc);
++              }
 +
-+config XEN_KEYBOARD
-+      tristate "Keyboard-device frontend driver"
-+      depends on XEN_FRAMEBUFFER && INPUT
-+      default y
-+      help
-+        The keyboard-device frontend driver allows the kernel to create a
-+        virtual keyboard.  This keyboard can then be driven by another
-+        domain.  If you've said Y to CONFIG_XEN_FRAMEBUFFER, you probably
-+        want to say Y here.
++              make_filter_key(&evict_key, fs);
++              if (cuckoo_hash_remove(&accel_hw_priv->filter_hash_table,
++                                     (cuckoo_hash_key *)&evict_key)) {
++                      EPRINTK("Couldn't find filter to remove from table\n");
++                      BUG();
++              }
++              NETBACK_ACCEL_STATS_OP(bend->stats.num_filters--);
++      }
 +
-+config XEN_SCRUB_PAGES
-+      bool "Scrub memory before freeing it to Xen"
-+      default y
-+      help
-+        Erase memory contents before freeing it back to Xen's global
-+        pool. This ensures that any secrets contained within that
-+        memory (e.g., private keys) cannot be found by other guests that
-+        may be running on the machine. Most people will want to say Y here.
-+        If security is not a concern then you may increase performance by
-+        saying N.
++      /* Update the filter spec with new details */
++      *fs = *filt;
 +
-+config XEN_DISABLE_SERIAL
-+      bool "Disable serial port drivers"
-+      default y
-+      help
-+        Disable serial port drivers, allowing the Xen console driver
-+        to provide a serial console at ttyS0.
++      if ((rc = cuckoo_hash_add(&accel_hw_priv->filter_hash_table, 
++                                (cuckoo_hash_key *)&filter_key, filter_index,
++                                1)) != 0) {
++              EPRINTK("Error (%d) adding filter to table\n", rc);
++              accel_hw_priv->free_filters |= (1 << filter_index);
++              goto out;
++      }
 +
-+config XEN_SYSFS
-+      tristate "Export Xen attributes in sysfs"
-+      depends on SYSFS
-+      select SYS_HYPERVISOR
-+      default y
-+      help
-+        Xen hypervisor attributes will show up under /sys/hypervisor/.
++      rc = efx_vi_filter(accel_hw_priv->efx_vih, filt->proto, filt->destip_be,
++                         filt->destport_be, 
++                         (struct filter_resource_t **)&fs->filter_handle);
 +
-+choice
-+      prompt "Xen version compatibility"
-+      default XEN_COMPAT_030002_AND_LATER
++      if (rc != 0) {
++              EPRINTK("Hardware filter insertion failed. Error %d\n", rc);
++              accel_hw_priv->free_filters |= (1 << filter_index);
++              cuckoo_hash_remove(&accel_hw_priv->filter_hash_table, 
++                                 (cuckoo_hash_key *)&filter_key);
++              rc = -1;
++              goto out;
++      }
++
++      NETBACK_ACCEL_STATS_OP(bend->stats.num_filters++);
++
++      VPRINTK("%s: success index %d handle %p\n", __FUNCTION__, filter_index, 
++              fs->filter_handle);
++
++      rc = filter_index;
++ out:
++      spin_unlock_irqrestore(&accel_hw_priv->filter_lock, flags);
++      return rc;
++}
++
++
++/* Remove a filter entry for the specific device and IP/port */
++static void netback_accel_filter_remove(struct netback_accel *bend, 
++                                      int filter_index)
++{
++      struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
++
++      BUG_ON(accel_hw_priv->free_filters & (1 << filter_index));
++      netback_accel_free_filter(accel_hw_priv, filter_index);
++      accel_hw_priv->free_filters |= (1 << filter_index);
++}
++
++
++/* Remove a filter entry for the specific device and IP/port */
++void netback_accel_filter_remove_spec(struct netback_accel *bend, 
++                                    struct netback_accel_filter_spec *filt)
++{
++      struct falcon_bend_accel_priv *accel_hw_priv = bend->accel_hw_priv;
++      unsigned filter_found;
++      unsigned long flags;
++      cuckoo_hash_ip_key filter_key;
++      struct netback_accel_filter_spec *fs;
++
++      if (filt->proto == IPPROTO_TCP) {
++              DPRINTK("Remove TCP filter for dst ip %08x and dst port %d\n",
++                      be32_to_cpu(filt->destip_be),
++                      be16_to_cpu(filt->destport_be));
++      } else if (filt->proto == IPPROTO_UDP) {
++              DPRINTK("Remove UDP filter for dst ip %08x and dst port %d\n",
++                      be32_to_cpu(filt->destip_be),
++                      be16_to_cpu(filt->destport_be));
++      } else {
++              /*
++               * This could be provoked by an evil frontend, so can't
++               * BUG(), but harmless as it should fail tests below 
++               */
++              DPRINTK("Non-TCP/UDP filter dst ip %08x and dst port %d\n",
++                      be32_to_cpu(filt->destip_be),
++                      be16_to_cpu(filt->destport_be));
++      }
++
++      spin_lock_irqsave(&accel_hw_priv->filter_lock, flags);
++
++      make_filter_key(&filter_key, filt);
++      if (!cuckoo_hash_lookup(&accel_hw_priv->filter_hash_table, 
++                             (cuckoo_hash_key *)(&filter_key), 
++                             &filter_found)) {
++              EPRINTK("Couldn't find matching filter already in table\n");
++              goto out;
++      }
++      
++      /* Do a full check to make sure we've not had a hash collision */
++      fs = &accel_hw_priv->fspecs[filter_found];
++      if (fs->destip_be == filt->destip_be &&
++          fs->destport_be == filt->destport_be &&
++          fs->proto == filt->proto &&
++          !memcmp(fs->mac, filt->mac, ETH_ALEN)) {
++              netback_accel_filter_remove(bend, filter_found);
++      } else {
++              EPRINTK("Entry in hash table does not match filter spec\n");
++              goto out;
++      }
++
++ out:
++      spin_unlock_irqrestore(&accel_hw_priv->filter_lock, flags);
++}
+--- linux-2.6.18.8/drivers/xen/sfc_netback/accel_solarflare.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/accel_solarflare.h     2008-05-19 00:33:46.786842968 +0300
+@@ -0,0 +1,88 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      config XEN_COMPAT_030002_AND_LATER
-+              bool "3.0.2 and later"
++#ifndef NETBACK_ACCEL_SOLARFLARE_H
++#define NETBACK_ACCEL_SOLARFLARE_H
 +
-+      config XEN_COMPAT_030004_AND_LATER
-+              bool "3.0.4 and later"
++#include "accel.h"
++#include "accel_msg_iface.h"
 +
-+      config XEN_COMPAT_030100_AND_LATER
-+              bool "3.1.0 and later"
++#include "driverlink_api.h"
 +
-+      config XEN_COMPAT_LATEST_ONLY
-+              bool "no compatibility code"
++#define MAX_NICS 5
++#define MAX_PORTS 2
 +
-+endchoice
 +
-+config XEN_COMPAT
-+      hex
-+      default 0xffffff if XEN_COMPAT_LATEST_ONLY
-+      default 0x030100 if XEN_COMPAT_030100_AND_LATER
-+      default 0x030004 if XEN_COMPAT_030004_AND_LATER
-+      default 0x030002 if XEN_COMPAT_030002_AND_LATER
-+      default 0
++extern int netback_accel_sf_init(void);
++extern void netback_accel_sf_shutdown(void);
++extern int netback_accel_sf_hwtype(struct netback_accel *bend);
 +
-+endmenu
++extern int netback_accel_sf_char_init(void);
++extern void netback_accel_sf_char_shutdown(void);
 +
-+config HAVE_IRQ_IGNORE_UNHANDLED
-+      def_bool y
++extern int netback_accel_setup_vnic_hw(struct netback_accel *bend);
++extern void netback_accel_shutdown_vnic_hw(struct netback_accel *bend);
 +
-+config NO_IDLE_HZ
-+      def_bool y
++extern int netback_accel_add_buffers(struct netback_accel *bend, int pages, 
++                                   int log2_pages, u32 *grants,
++                                   u32 *buf_addr_out);
++extern int netback_accel_remove_buffers(struct netback_accel *bend);
 +
-+config XEN_SMPBOOT
-+      def_bool y
-+      depends on SMP && !PPC_XEN
 +
-+config XEN_BALLOON
-+      def_bool y
-+      depends on !PPC_XEN
++/* Add a filter for the specified IP/port to the backend */
++extern int
++netback_accel_filter_check_add(struct netback_accel *bend, 
++                             struct netback_accel_filter_spec *filt);
++/* Remove a filter entry for the specific device and IP/port */
++extern
++void netback_accel_filter_remove_index(struct netback_accel *bend, 
++                                     int filter_index);
++extern
++void netback_accel_filter_remove_spec(struct netback_accel *bend, 
++                                    struct netback_accel_filter_spec *filt);
 +
-+config XEN_XENCOMM
-+      bool
++/* This is designed to look a bit like a skb */
++struct netback_pkt_buf {
++      union {
++              unsigned char *raw;
++      } mac;
++      union {
++              struct iphdr  *iph;
++              struct arphdr *arph;
++              unsigned char *raw;
++      } nh;
++      int protocol;
++};
 +
-+config XEN_DEVMEM
-+      def_bool y
++/*! \brief Handle a received packet: insert fast path filters as necessary
++ * \param skb The packet buffer
++ */
++extern void netback_accel_rx_packet(struct netback_pkt_buf *skb, void *fwd_priv);
 +
-+endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/Makefile linux-2.6.18-xen.hg/drivers/xen/Makefile
---- linux-2.6.18/drivers/xen/Makefile  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/Makefile   2007-12-23 11:15:33.537908474 +0100
-@@ -0,0 +1,20 @@
-+obj-y += core/
-+obj-y += console/
-+obj-y += evtchn/
-+obj-y += xenbus/
-+obj-y += char/
++/*! \brief Handle a transmitted packet: update fast path filters as necessary
++ * \param skb The packet buffer
++ */
++extern void netback_accel_tx_packet(struct sk_buff *skb, void *fwd_priv);
 +
-+obj-y += util.o
-+obj-$(CONFIG_XEN_BALLOON)             += balloon/
-+obj-$(CONFIG_XEN_BLKDEV_BACKEND)      += blkback/
-+obj-$(CONFIG_XEN_BLKDEV_TAP)          += blktap/
-+obj-$(CONFIG_XEN_NETDEV_BACKEND)      += netback/
-+obj-$(CONFIG_XEN_TPMDEV_BACKEND)      += tpmback/
-+obj-$(CONFIG_XEN_BLKDEV_FRONTEND)     += blkfront/
-+obj-$(CONFIG_XEN_NETDEV_FRONTEND)     += netfront/
-+obj-$(CONFIG_XEN_PCIDEV_BACKEND)      += pciback/
-+obj-$(CONFIG_XEN_PCIDEV_FRONTEND)     += pcifront/
-+obj-$(CONFIG_XEN_FRAMEBUFFER)         += fbfront/
-+obj-$(CONFIG_XEN_KEYBOARD)            += fbfront/
-+obj-$(CONFIG_XEN_PRIVCMD)     += privcmd/
-+obj-$(CONFIG_XEN_GRANT_DEV)   += gntdev/
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/netback/accel.c linux-2.6.18-xen.hg/drivers/xen/netback/accel.c
---- linux-2.6.18/drivers/xen/netback/accel.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/netback/accel.c    2007-12-23 11:15:34.051268764 +0100
-@@ -0,0 +1,269 @@
-+/******************************************************************************
-+ * drivers/xen/netback/accel.c
++#endif /* NETBACK_ACCEL_SOLARFLARE_H */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/accel_xenbus.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/accel_xenbus.c 2008-05-19 00:33:46.878848271 +0300
+@@ -0,0 +1,831 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
 + *
-+ * Interface between backend virtual network device and accelerated plugin. 
-+ * 
-+ * Copyright (C) 2007 Solarflare Communications, Inc
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <linux/list.h>
-+#include <asm/atomic.h>
-+#include <xen/xenbus.h>
++#include <xen/evtchn.h>
 +#include <linux/mutex.h>
 +
++/* drivers/xen/netback/common.h */
 +#include "common.h"
 +
-+#if 0
-+#undef DPRINTK
-+#define DPRINTK(fmt, args...)                                         \
-+      printk("netback/accel (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
-+#endif
++#include "accel.h"
++#include "accel_solarflare.h"
++#include "accel_util.h"
 +
-+/* 
-+ * A list of available netback accelerator plugin modules (each list
-+ * entry is of type struct netback_accelerator) 
-+ */ 
-+static struct list_head accelerators_list;
-+/* Lock used to protect access to accelerators_list */
-+DEFINE_MUTEX(accelerators_mutex);
++#define NODENAME_PATH_FMT "backend/vif/%d/%d"
 +
-+/* 
-+ * Compare a backend to an accelerator, and decide if they are
-+ * compatible (i.e. if the accelerator should be used by the
-+ * backend) 
++#define NETBACK_ACCEL_FROM_XENBUS_DEVICE(_dev) (struct netback_accel *) \
++      ((struct backend_info *)(_dev)->dev.driver_data)->netback_accel_priv
++
++/* List of all the bends currently in existence. */
++struct netback_accel *bend_list = NULL;
++DEFINE_MUTEX(bend_list_mutex);
++
++/* Put in bend_list.  Must hold bend_list_mutex */
++static void link_bend(struct netback_accel *bend)
++{
++      bend->next_bend = bend_list;
++      bend_list = bend;
++}
++
++/* Remove from bend_list,  Must hold bend_list_mutex */
++static void unlink_bend(struct netback_accel *bend)
++{
++      struct netback_accel *tmp = bend_list;
++      struct netback_accel *prev = NULL;
++      while (tmp != NULL) {
++              if (tmp == bend) {
++                      if (prev != NULL)
++                              prev->next_bend = bend->next_bend;
++                      else
++                              bend_list = bend->next_bend;
++                      return;
++              }
++              prev = tmp;
++              tmp = tmp->next_bend;
++      }
++}
++
++
++/* Demultiplex a message IRQ from the frontend driver.  */
++static irqreturn_t msgirq_from_frontend(int irq, void *context, 
++                                   struct pt_regs *unused)
++{
++      struct xenbus_device *dev = context;
++      struct netback_accel *bend = NETBACK_ACCEL_FROM_XENBUS_DEVICE(dev);
++      VPRINTK("irq %d from device %s\n", irq, dev->nodename);
++      schedule_work(&bend->handle_msg);
++      return IRQ_HANDLED;
++}
++
++
++/*
++ * Demultiplex an IRQ from the frontend driver.  This is never used
++ * functionally, but we need it to pass to the bind function, and may
++ * get called spuriously
 + */
-+static int match_accelerator(struct xenbus_device *xendev,
-+                           struct backend_info *be, 
-+                           struct netback_accelerator *accelerator)
++static irqreturn_t netirq_from_frontend(int irq, void *context, 
++                                      struct pt_regs *unused)
 +{
-+      int rc = 0;
-+      char *eth_name = xenbus_read(XBT_NIL, xendev->nodename, "accel", NULL);
++      VPRINTK("netirq %d from device %s\n", irq,
++              ((struct xenbus_device *)context)->nodename);
 +      
-+      if (IS_ERR(eth_name)) {
-+              /* Probably means not present */
-+              DPRINTK("%s: no match due to xenbus_read accel error %d\n", 
-+                      __FUNCTION__, PTR_ERR(eth_name));
-+              return 0;
-+      } else {
-+              if (!strcmp(eth_name, accelerator->eth_name))
-+                      rc = 1;
-+              kfree(eth_name);
-+              return rc;
++      return IRQ_HANDLED;
++}
++
++
++/* Read the limits values of the xenbus structure. */
++static 
++void cfg_hw_quotas(struct xenbus_device *dev, struct netback_accel *bend)
++{
++      int err = xenbus_gather
++              (XBT_NIL, dev->nodename,
++               "limits/max-filters", "%d", &bend->quotas.max_filters,
++               "limits/max-buf-pages", "%d", &bend->quotas.max_buf_pages,
++               "limits/max-mcasts", "%d", &bend->quotas.max_mcasts,
++               NULL);
++      if (err) {
++              /*
++               * TODO what if they have previously been set by the
++               * user?  This will overwrite with defaults.  Maybe
++               * not what we want to do, but useful in startup
++               * case 
++               */
++              DPRINTK("Failed to read quotas from xenbus, using defaults\n");
++              bend->quotas.max_filters = NETBACK_ACCEL_DEFAULT_MAX_FILTERS;
++              bend->quotas.max_buf_pages = sfc_netback_max_pages;
++              bend->quotas.max_mcasts = NETBACK_ACCEL_DEFAULT_MAX_MCASTS;
 +      }
++
++      return;
 +}
 +
 +
-+static void do_probe(struct backend_info *be, 
-+                   struct netback_accelerator *accelerator,
-+                   struct xenbus_device *xendev) 
++static void bend_config_accel_change(struct xenbus_watch *watch,
++                                   const char **vec, unsigned int len)
 +{
-+      be->accelerator = accelerator;
-+      atomic_inc(&be->accelerator->use_count);
-+      if (be->accelerator->hooks->probe(xendev) != 0) {
-+              atomic_dec(&be->accelerator->use_count);
-+              module_put(be->accelerator->hooks->owner);
-+              be->accelerator = NULL;
++      struct netback_accel *bend;
++
++      bend = container_of(watch, struct netback_accel, config_accel_watch);
++
++      mutex_lock(&bend->bend_mutex);
++      if (bend->config_accel_watch.node != NULL) {
++              struct xenbus_device *dev = 
++                      (struct xenbus_device *)bend->hdev_data;
++              DPRINTK("Watch matched, got dev %p otherend %p\n",
++                      dev, dev->otherend);
++              if(!xenbus_exists(XBT_NIL, watch->node, "")) {
++                      DPRINTK("Ignoring watch as otherend seems invalid\n");
++                      goto out;
++              }
++              
++              cfg_hw_quotas(dev, bend);
 +      }
++ out:
++      mutex_unlock(&bend->bend_mutex);
++      return;
 +}
 +
 +
 +/*
-+ * Notify suitable backends that a new accelerator is available and
-+ * connected.  This will also notify the accelerator plugin module
-+ * that it is being used for a device through the probe hook.
++ * Setup watch on "limits" in the backend vif info to know when
++ * configuration has been set
 + */
-+static int netback_accelerator_probe_backend(struct device *dev, void *arg)
++static int setup_config_accel_watch(struct xenbus_device *dev,
++                                  struct netback_accel *bend)
 +{
-+      struct netback_accelerator *accelerator = 
-+              (struct netback_accelerator *)arg;
-+      struct xenbus_device *xendev = to_xenbus_device(dev);
++      int err;
 +
-+      if (!strcmp("vif", xendev->devicetype)) {
-+              struct backend_info *be = xendev->dev.driver_data;
++      VPRINTK("Setting watch on %s/%s\n", dev->nodename, "limits");
 +
-+              if (match_accelerator(xendev, be, accelerator) &&
-+                  try_module_get(accelerator->hooks->owner)) {
-+                      do_probe(be, accelerator, xendev);
-+              }
++      err = xenbus_watch_path2(dev, dev->nodename, "limits", 
++                               &bend->config_accel_watch, 
++                               bend_config_accel_change);
++
++      if (err) {
++              EPRINTK("%s: Failed to register xenbus watch: %d\n",
++                      __FUNCTION__, err);
++              bend->config_accel_watch.node = NULL;
++              return err;
 +      }
 +      return 0;
 +}
 +
 +
-+/*
-+ * Notify suitable backends that an accelerator is unavailable.
-+ */
-+static int netback_accelerator_remove_backend(struct device *dev, void *arg)
++static int 
++cfg_frontend_info(struct xenbus_device *dev, struct netback_accel *bend,
++                int *grants)
 +{
-+      struct xenbus_device *xendev = to_xenbus_device(dev);
-+      struct netback_accelerator *accelerator = 
-+              (struct netback_accelerator *)arg;
-+      
-+      if (!strcmp("vif", xendev->devicetype)) {
-+              struct backend_info *be = xendev->dev.driver_data;
++      /* Get some info from xenbus on the event channel and shmem grant */
++      int err = xenbus_gather(XBT_NIL, dev->otherend, 
++                              "accel-msg-channel", "%u", &bend->msg_channel, 
++                              "accel-ctrl-page", "%d", &(grants[0]),
++                              "accel-msg-page", "%d", &(grants[1]),
++                              "accel-net-channel", "%u", &bend->net_channel,
++                              NULL);
++      if (err)
++              EPRINTK("failed to read event channels or shmem grant: %d\n",
++                      err);
++      else
++              DPRINTK("got event chan %d and net chan %d from frontend\n",
++                      bend->msg_channel, bend->net_channel);
++      return err;
++}
 +
-+              if (be->accelerator == accelerator) {
-+                      be->accelerator->hooks->remove(xendev);
-+                      atomic_dec(&be->accelerator->use_count);
-+                      module_put(be->accelerator->hooks->owner);
-+                      be->accelerator = NULL;
++
++/* Setup all the comms needed to chat with the front end driver */
++static int setup_vnic(struct xenbus_device *dev)
++{
++      struct netback_accel *bend;
++      int grants[2], err, msgs_per_queue;
++
++      bend = NETBACK_ACCEL_FROM_XENBUS_DEVICE(dev);
++
++      err = cfg_frontend_info(dev, bend, grants);
++      if (err)
++              goto fail1;
++
++      /*
++       * If we get here, both frontend Connected and configuration
++       * options available.  All is well.
++       */
++
++      /* Get the hardware quotas for the VNIC in question.  */
++      cfg_hw_quotas(dev, bend);
++
++      /* Set up the deferred work handlers */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++      INIT_WORK(&bend->handle_msg, 
++                netback_accel_msg_rx_handler);
++#else
++      INIT_WORK(&bend->handle_msg, 
++                netback_accel_msg_rx_handler,
++                (void*)bend);
++#endif
++
++      /* Request the frontend mac */
++      err = net_accel_xen_net_read_mac(dev, bend->mac);
++      if (err)
++              goto fail2;
++
++      /* Set up the shared page. */
++      bend->shared_page = net_accel_map_grants_contig(dev, grants, 2, 
++                                                      &bend->sh_pages_unmap);
++
++      if (bend->shared_page == NULL) {
++              EPRINTK("failed to map shared page for %s\n", dev->otherend);
++              err = -ENOMEM;
++              goto fail2;
++      }
++
++      /* Initialise the shared page(s) used for comms */
++      net_accel_msg_init_page(bend->shared_page, PAGE_SIZE, 
++                              bend->net_dev->flags & IFF_UP);
++
++      msgs_per_queue = (PAGE_SIZE/2) / sizeof(struct net_accel_msg);
++
++      net_accel_msg_init_queue
++              (&bend->to_domU, &bend->shared_page->queue0,
++               (struct net_accel_msg *)((__u8*)bend->shared_page + PAGE_SIZE),
++               msgs_per_queue);
++
++      net_accel_msg_init_queue
++              (&bend->from_domU, &bend->shared_page->queue1, 
++               (struct net_accel_msg *)((__u8*)bend->shared_page + 
++                                        (3 * PAGE_SIZE / 2)),
++               msgs_per_queue);
++
++      /* Bind the message event channel to a handler
++       *
++       * Note that we will probably get a spurious interrupt when we
++       * do this, so it must not be done until we have set up
++       * everything we need to handle it.
++       */
++      err = bind_interdomain_evtchn_to_irqhandler(dev->otherend_id,
++                                                  bend->msg_channel,
++                                                  msgirq_from_frontend,
++                                                  0,
++                                                  "netback_accel",
++                                                  dev);
++      if (err < 0) {
++              EPRINTK("failed to bind event channel: %d\n", err);
++              goto fail3;
++      }
++      else
++              bend->msg_channel_irq = err;
++
++      /* TODO: No need to bind this evtchn to an irq. */
++      err = bind_interdomain_evtchn_to_irqhandler(dev->otherend_id,
++                                                  bend->net_channel,
++                                                  netirq_from_frontend,
++                                                  0,
++                                                  "netback_accel",
++                                                  dev);
++      if (err < 0) {
++              EPRINTK("failed to bind net channel: %d\n", err);
++              goto fail4;
++      }  
++      else
++              bend->net_channel_irq = err;
++
++      /*
++       * Grab ourselves an entry in the forwarding hash table. We do
++       * this now so we don't have the embarassmesnt of sorting out
++       * an allocation failure while at IRQ. Because we pass NULL as
++       * the context, the actual hash lookup will succeed for this
++       * NIC, but the check for somewhere to forward to will
++       * fail. This is necessary to prevent forwarding before
++       * hardware resources are set up
++       */
++      err = netback_accel_fwd_add(bend->mac, NULL, bend->fwd_priv);
++      if (err) {
++              EPRINTK("failed to add to fwd hash table\n");
++              goto fail5;
++      }
++
++      /*
++       * Say hello to frontend.  Important to do this straight after
++       * obtaining the message queue as otherwise we are vulnerable
++       * to an evil frontend sending a HELLO-REPLY before we've sent
++       * the HELLO and confusing us
++       */
++      netback_accel_msg_tx_hello(bend, NET_ACCEL_MSG_VERSION);
++      return 0;
++
++ fail5:
++      unbind_from_irqhandler(bend->net_channel_irq, dev);
++ fail4:
++      unbind_from_irqhandler(bend->msg_channel_irq, dev);
++ fail3:
++      net_accel_unmap_grants_contig(dev, bend->sh_pages_unmap);
++      bend->shared_page = NULL;
++      bend->sh_pages_unmap = NULL;
++ fail2:
++ fail1:
++      return err;
++}
++
++
++static int read_nicname(struct xenbus_device *dev, struct netback_accel *bend)
++{
++      int len;
++
++      /* nic name used to select interface used for acceleration */
++      bend->nicname = xenbus_read(XBT_NIL, dev->nodename, "accel", &len);
++      if (IS_ERR(bend->nicname))
++              return PTR_ERR(bend->nicname);
++
++      return 0;
++}
++
++static const char *frontend_name = "sfc_netfront";
++
++static int publish_frontend_name(struct xenbus_device *dev)
++{
++      struct xenbus_transaction tr;
++      int err;
++      
++      /* Publish the name of the frontend driver */
++      do {
++              err = xenbus_transaction_start(&tr);
++              if (err != 0) { 
++                      EPRINTK("%s: transaction start failed\n", __FUNCTION__);
++                      return err;
++              }
++              err = xenbus_printf(tr, dev->nodename, "accel-frontend", 
++                                  "%s", frontend_name);
++              if (err != 0) {
++                      EPRINTK("%s: xenbus_printf failed\n", __FUNCTION__);
++                      xenbus_transaction_end(tr, 1);
++                      return err;
 +              }
++              err = xenbus_transaction_end(tr, 0);
++      } while (err == -EAGAIN);
++      
++      if (err != 0) {
++              EPRINTK("failed to end frontend name transaction\n");
++              return err;
 +      }
 +      return 0;
 +}
 +
 +
++static int unpublish_frontend_name(struct xenbus_device *dev)
++{
++      struct xenbus_transaction tr;
++      int err;
++
++      do {
++              err = xenbus_transaction_start(&tr);
++              if (err != 0)
++                      break;
++              err = xenbus_rm(tr, dev->nodename, "accel-frontend");
++              if (err != 0) {
++                      xenbus_transaction_end(tr, 1);
++                      break;
++              }
++              err = xenbus_transaction_end(tr, 0);
++      } while (err == -EAGAIN);
++
++      return err;
++}
++
++
++static void cleanup_vnic(struct netback_accel *bend)
++{
++      struct xenbus_device *dev;
++
++      dev = (struct xenbus_device *)bend->hdev_data;
++
++      DPRINTK("%s: bend %p dev %p\n", __FUNCTION__, bend, dev);
++
++      DPRINTK("%s: Remove %p's mac from fwd table...\n", 
++              __FUNCTION__, bend);
++      netback_accel_fwd_remove(bend->mac, bend->fwd_priv);
++
++      /* Free buffer table allocations */
++      netback_accel_remove_buffers(bend);
++
++      DPRINTK("%s: Release hardware resources...\n", __FUNCTION__);
++      if (bend->accel_shutdown)
++              bend->accel_shutdown(bend);
++
++      if (bend->net_channel_irq) {
++              unbind_from_irqhandler(bend->net_channel_irq, dev);
++              bend->net_channel_irq = 0;
++      }
++
++      if (bend->msg_channel_irq) {
++              unbind_from_irqhandler(bend->msg_channel_irq, dev);
++              bend->msg_channel_irq = 0;
++      }
++
++      if (bend->sh_pages_unmap) {
++              DPRINTK("%s: Unmap grants %p\n", __FUNCTION__, 
++                      bend->sh_pages_unmap);
++              net_accel_unmap_grants_contig(dev, bend->sh_pages_unmap);
++              bend->sh_pages_unmap = NULL;
++              bend->shared_page = NULL;
++      }
++}
++
++
++/*************************************************************************/
 +
 +/*
-+ * Entry point for an netback accelerator plugin module.  Called to
-+ * advertise its presence, and connect to any suitable backends.
++ * The following code handles accelstate changes between the frontend
++ * and the backend.  It calls setup_vnic and cleanup_vnic in matching
++ * pairs in response to transitions.
++ *
++ * Valid state transitions for Dom0 are as follows:
++ *
++ * Closed->Init       on probe or in response to Init from domU
++ * Closed->Closing    on error/remove
++ *
++ * Init->Connected    in response to Connected from domU
++ * Init->Closing      on error/remove or in response to Closing from domU
++ *
++ * Connected->Closing on error/remove or in response to Closing from domU
++ *
++ * Closing->Closed    in response to Closed from domU
++ *
 + */
-+int netback_connect_accelerator(unsigned version, int id, const char *eth_name, 
-+                              struct netback_accel_hooks *hooks)
++
++
++static void netback_accel_frontend_changed(struct xenbus_device *dev,
++                                         XenbusState frontend_state)
 +{
-+      struct netback_accelerator *new_accelerator;
-+      unsigned eth_name_len;
++      struct netback_accel *bend = NETBACK_ACCEL_FROM_XENBUS_DEVICE(dev);
++      XenbusState backend_state;
 +
-+      if (version != NETBACK_ACCEL_VERSION) {
-+              if (version > NETBACK_ACCEL_VERSION) {
-+                      /* Caller has higher version number, leave it
-+                         up to them to decide whether to continue.
-+                         They can recall with a lower number if
-+                         they're happy to be compatible with us */
-+                      return NETBACK_ACCEL_VERSION;
-+              } else {
-+                      /* We have a more recent version than caller.
-+                         Currently reject, but may in future be able
-+                         to be backwardly compatible */
-+                      return -EPROTO;
++      DPRINTK("%s: changing from %s to %s. nodename %s, otherend %s\n",
++              __FUNCTION__, xenbus_strstate(bend->frontend_state),
++              xenbus_strstate(frontend_state),dev->nodename, dev->otherend);
++
++      /*
++       * Ignore duplicate state changes.  This can happen if the
++       * frontend changes state twice in quick succession and the
++       * first watch fires in the backend after the second
++       * transition has completed.
++       */
++      if (bend->frontend_state == frontend_state)
++              return;
++
++      bend->frontend_state = frontend_state;
++      backend_state = bend->backend_state;
++
++      switch (frontend_state) {
++      case XenbusStateInitialising:
++              if (backend_state == XenbusStateClosed &&
++                  !bend->removing)
++                      backend_state = XenbusStateInitialising;
++              break;
++
++      case XenbusStateConnected:
++              if (backend_state == XenbusStateInitialising) {
++                      if (!bend->vnic_is_setup &&
++                          setup_vnic(dev) == 0) {
++                              bend->vnic_is_setup = 1;
++                              backend_state = XenbusStateConnected;
++                      } else {
++                              backend_state = XenbusStateClosing;
++                      }
++              }
++              break;
++
++      case XenbusStateInitWait:
++      case XenbusStateInitialised:
++      default:
++              DPRINTK("Unknown state %s (%d) from frontend.\n",
++                      xenbus_strstate(frontend_state), frontend_state);
++              /* Unknown state.  Fall through. */
++      case XenbusStateClosing:
++              if (backend_state != XenbusStateClosed)
++                      backend_state = XenbusStateClosing;
++
++              /*
++               * The bend will now persist (with watches active) in
++               * case the frontend comes back again, eg. after
++               * frontend module reload or suspend/resume
++               */
++
++              break;
++
++      case XenbusStateUnknown:
++      case XenbusStateClosed:
++              if (bend->vnic_is_setup) {
++                      bend->vnic_is_setup = 0;
++                      cleanup_vnic(bend);
 +              }
++
++              if (backend_state == XenbusStateClosing)
++                      backend_state = XenbusStateClosed;
++              break;
 +      }
 +
-+      new_accelerator = 
-+              kmalloc(sizeof(struct netback_accelerator), GFP_KERNEL);
-+      if (!new_accelerator) {
-+              DPRINTK("%s: failed to allocate memory for accelerator\n",
-+                      __FUNCTION__);
-+              return -ENOMEM;
++      if (backend_state != bend->backend_state) {
++              DPRINTK("Switching from state %s (%d) to %s (%d)\n",
++                      xenbus_strstate(bend->backend_state),
++                      bend->backend_state,
++                      xenbus_strstate(backend_state), backend_state);
++              bend->backend_state = backend_state;
++              net_accel_update_state(dev, backend_state);
 +      }
 +
-+      new_accelerator->id = id;
-+      
-+      eth_name_len = strlen(eth_name)+1;
-+      new_accelerator->eth_name = kmalloc(eth_name_len, GFP_KERNEL);
-+      if (!new_accelerator->eth_name) {
-+              DPRINTK("%s: failed to allocate memory for eth_name string\n",
-+                      __FUNCTION__);
-+              kfree(new_accelerator);
++      wake_up(&bend->state_wait_queue);
++}
++
++
++/* accelstate on the frontend's xenbus node has changed */
++static void bend_domu_accel_change(struct xenbus_watch *watch,
++                                 const char **vec, unsigned int len)
++{
++      int state;
++      struct netback_accel *bend;
++
++      bend = container_of(watch, struct netback_accel, domu_accel_watch);
++      if (bend->domu_accel_watch.node != NULL) {
++              struct xenbus_device *dev = 
++                      (struct xenbus_device *)bend->hdev_data;
++              VPRINTK("Watch matched, got dev %p otherend %p\n",
++                      dev, dev->otherend);
++              /*
++               * dev->otherend != NULL check to protect against
++               * watch firing when domain goes away and we haven't
++               * yet cleaned up
++               */
++              if (!dev->otherend ||
++                  !xenbus_exists(XBT_NIL, watch->node, "") ||
++                  strncmp(dev->otherend, vec[XS_WATCH_PATH],
++                          strlen(dev->otherend))) {
++                      DPRINTK("Ignoring watch as otherend seems invalid\n");
++                      return;
++              }
++
++              mutex_lock(&bend->bend_mutex);
++
++              xenbus_scanf(XBT_NIL, dev->otherend, "accelstate", "%d", 
++                           &state);
++              netback_accel_frontend_changed(dev, state);
++
++              mutex_unlock(&bend->bend_mutex);
++      }
++}
++
++/* Setup watch on frontend's accelstate */
++static int setup_domu_accel_watch(struct xenbus_device *dev,
++                                struct netback_accel *bend)
++{
++      int err;
++
++      VPRINTK("Setting watch on %s/%s\n", dev->otherend, "accelstate");
++
++      err = xenbus_watch_path2(dev, dev->otherend, "accelstate", 
++                               &bend->domu_accel_watch, 
++                               bend_domu_accel_change);
++      if (err) {
++              EPRINTK("%s: Failed to register xenbus watch: %d\n",
++                      __FUNCTION__, err);
++              goto fail;
++      }
++      return 0;
++ fail:
++      bend->domu_accel_watch.node = NULL;
++      return err;
++}
++
++
++int netback_accel_probe(struct xenbus_device *dev)
++{
++      struct netback_accel *bend;
++      struct backend_info *binfo;
++      int err;
++
++      DPRINTK("%s: passed device %s\n", __FUNCTION__, dev->nodename);
++
++      /* Allocate structure to store all our state... */
++      bend = kzalloc(sizeof(struct netback_accel), GFP_KERNEL);
++      if (bend == NULL) {
++              DPRINTK("%s: no memory for bend\n", __FUNCTION__);
 +              return -ENOMEM;
 +      }
-+      strlcpy(new_accelerator->eth_name, eth_name, eth_name_len);
 +      
-+      new_accelerator->hooks = hooks;
++      mutex_init(&bend->bend_mutex);
 +
-+      atomic_set(&new_accelerator->use_count, 0);
++      mutex_lock(&bend->bend_mutex);
++
++      /* ...and store it where we can get at it */
++      binfo = (struct backend_info *) dev->dev.driver_data;
++      binfo->netback_accel_priv = bend;
++      /* And vice-versa */
++      bend->hdev_data = dev;
++
++      DPRINTK("%s: Adding bend %p to list\n", __FUNCTION__, bend);
 +      
-+      mutex_lock(&accelerators_mutex);
-+      list_add(&new_accelerator->link, &accelerators_list);
++      init_waitqueue_head(&bend->state_wait_queue);
++      bend->vnic_is_setup = 0;
++      bend->frontend_state = XenbusStateUnknown;
++      bend->backend_state = XenbusStateClosed;
++      bend->removing = 0;
++
++      sscanf(dev->nodename, NODENAME_PATH_FMT, &bend->far_end, 
++             &bend->vif_num);
++
++      err = read_nicname(dev, bend);
++      if (err) {
++              /*
++               * Technically not an error, just means we're not 
++               * supposed to accelerate this
++               */
++              DPRINTK("failed to get device name\n");
++              goto fail_nicname;
++      }
++
++      /*
++       * Look up the device name in the list of NICs provided by
++       * driverlink to get the hardware type.
++       */
++      err = netback_accel_sf_hwtype(bend);
++      if (err) {
++              /*
++               * Technically not an error, just means we're not
++               * supposed to accelerate this, probably belongs to
++               * some other backend
++               */
++              DPRINTK("failed to match device name\n");
++              goto fail_init_type;
++      }
++
++      err = publish_frontend_name(dev);
++      if (err)
++              goto fail_publish;
++
++      err = netback_accel_debugfs_create(bend);
++      if (err)
++              goto fail_debugfs;
 +      
-+      /* tell existing backends about new plugin */
-+      xenbus_for_each_backend(new_accelerator, 
-+                              netback_accelerator_probe_backend);
++      mutex_unlock(&bend->bend_mutex);
 +
-+      mutex_unlock(&accelerators_mutex);
++      err = setup_config_accel_watch(dev, bend);
++      if (err)
++              goto fail_config_watch;
++
++      err = setup_domu_accel_watch(dev, bend);
++      if (err)
++              goto fail_domu_watch;
++
++      /*
++       * Indicate to the other end that we're ready to start unless
++       * the watch has already fired.
++       */
++      mutex_lock(&bend->bend_mutex);
++      if (bend->backend_state == XenbusStateClosed) {
++              bend->backend_state = XenbusStateInitialising;
++              net_accel_update_state(dev, XenbusStateInitialising);
++      }
++      mutex_unlock(&bend->bend_mutex);
++
++      mutex_lock(&bend_list_mutex);
++      link_bend(bend);
++      mutex_unlock(&bend_list_mutex);
 +
 +      return 0;
 +
++fail_domu_watch:
++
++      unregister_xenbus_watch(&bend->config_accel_watch);
++      kfree(bend->config_accel_watch.node);
++fail_config_watch:
++
++      /*
++       * Flush the scheduled work queue before freeing bend to get
++       * rid of any pending netback_accel_msg_rx_handler()
++       */
++      flush_scheduled_work();
++
++      mutex_lock(&bend->bend_mutex);
++      net_accel_update_state(dev, XenbusStateUnknown);
++      netback_accel_debugfs_remove(bend);
++fail_debugfs:
++
++      unpublish_frontend_name(dev);
++fail_publish:
++
++      /* No need to reverse netback_accel_sf_hwtype. */
++fail_init_type:
++
++      kfree(bend->nicname);
++fail_nicname:
++      binfo->netback_accel_priv = NULL;
++      mutex_unlock(&bend->bend_mutex);
++      kfree(bend);
++      return err;
 +}
-+EXPORT_SYMBOL_GPL(netback_connect_accelerator);
 +
 +
-+/* 
-+ * Disconnect an accelerator plugin module that has previously been
-+ * connected.
-+ */
-+void netback_disconnect_accelerator(int id, const char *eth_name)
++int netback_accel_remove(struct xenbus_device *dev)
 +{
-+      struct netback_accelerator *accelerator, *next;
++      struct backend_info *binfo;
++      struct netback_accel *bend; 
++      int frontend_state;
 +
-+      mutex_lock(&accelerators_mutex);
-+      list_for_each_entry_safe(accelerator, next, &accelerators_list, link) {
-+              if (!strcmp(eth_name, accelerator->eth_name)) {
-+                      xenbus_for_each_backend
-+                              (accelerator, netback_accelerator_remove_backend);
-+                      BUG_ON(atomic_read(&accelerator->use_count) != 0);
-+                      list_del(&accelerator->link);                           
-+                      kfree(accelerator->eth_name);
-+                      kfree(accelerator);
-+                      break;
-+              }
++      binfo = (struct backend_info *) dev->dev.driver_data;
++      bend = (struct netback_accel *) binfo->netback_accel_priv;
++
++      DPRINTK("%s: dev %p bend %p\n", __FUNCTION__, dev, bend);
++      
++      BUG_ON(bend == NULL);
++      
++      mutex_lock(&bend_list_mutex);
++      unlink_bend(bend);
++      mutex_unlock(&bend_list_mutex);
++
++      mutex_lock(&bend->bend_mutex);
++
++      /* Reject any requests to connect. */
++      bend->removing = 1;
++
++      /*
++       * Switch to closing to tell the other end that we're going
++       * away.
++       */
++      if (bend->backend_state != XenbusStateClosing) {
++              bend->backend_state = XenbusStateClosing;
++              net_accel_update_state(dev, XenbusStateClosing);
 +      }
-+      mutex_unlock(&accelerators_mutex);
-+}
-+EXPORT_SYMBOL_GPL(netback_disconnect_accelerator);
 +
++      frontend_state = (int)XenbusStateUnknown;
++      xenbus_scanf(XBT_NIL, dev->otherend, "accelstate", "%d",
++                   &frontend_state);
 +
-+void netback_probe_accelerators(struct backend_info *be,
-+                              struct xenbus_device *dev)
-+{
-+      struct netback_accelerator *accelerator;
++      mutex_unlock(&bend->bend_mutex);
 +
-+      /* 
-+       * Check list of accelerators to see if any is suitable, and
-+       * use it if it is.
++      /*
++       * Wait until this end goes to the closed state.  This happens
++       * in response to the other end going to the closed state.
++       * Don't bother doing this if the other end is already closed
++       * because if it is then there is nothing to do.
 +       */
-+      mutex_lock(&accelerators_mutex);
-+      list_for_each_entry(accelerator, &accelerators_list, link) { 
-+              if (match_accelerator(dev, be, accelerator) &&
-+                  try_module_get(accelerator->hooks->owner)) {
-+                      do_probe(be, accelerator, dev);
-+                      break;
-+              }
++      if (frontend_state != (int)XenbusStateClosed &&
++          frontend_state != (int)XenbusStateUnknown)
++              wait_event(bend->state_wait_queue,
++                         bend->backend_state == XenbusStateClosed);
++
++      unregister_xenbus_watch(&bend->domu_accel_watch);
++      kfree(bend->domu_accel_watch.node);
++
++      unregister_xenbus_watch(&bend->config_accel_watch);
++      kfree(bend->config_accel_watch.node);
++
++      /*
++       * Flush the scheduled work queue before freeing bend to get
++       * rid of any pending netback_accel_msg_rx_handler()
++       */
++      flush_scheduled_work();
++
++      mutex_lock(&bend->bend_mutex);
++
++      /* Tear down the vnic if it was set up. */
++      if (bend->vnic_is_setup) {
++              bend->vnic_is_setup = 0;
++              cleanup_vnic(bend);
 +      }
-+      mutex_unlock(&accelerators_mutex);
++
++      bend->backend_state = XenbusStateUnknown;
++      net_accel_update_state(dev, XenbusStateUnknown);
++
++      netback_accel_debugfs_remove(bend);
++
++      unpublish_frontend_name(dev);
++
++      kfree(bend->nicname);
++
++      binfo->netback_accel_priv = NULL;
++
++      mutex_unlock(&bend->bend_mutex);
++
++      kfree(bend);
++
++      return 0;
 +}
 +
 +
-+void netback_remove_accelerators(struct backend_info *be,
-+                               struct xenbus_device *dev)
++void netback_accel_shutdown_bends(void)
 +{
-+      mutex_lock(&accelerators_mutex);
-+      /* Notify the accelerator (if any) of this device's removal */
-+      if (be->accelerator != NULL) {
-+              be->accelerator->hooks->remove(dev);
-+              atomic_dec(&be->accelerator->use_count);
-+              module_put(be->accelerator->hooks->owner);
-+              be->accelerator = NULL;
-+      }
-+      mutex_unlock(&accelerators_mutex);
++      mutex_lock(&bend_list_mutex);
++      /*
++       * I think we should have had a remove callback for all
++       * interfaces before being allowed to unload the module
++       */
++      BUG_ON(bend_list != NULL);
++      mutex_unlock(&bend_list_mutex);
 +}
 +
 +
-+void netif_accel_init(void)
++void netback_accel_set_closing(struct netback_accel *bend) 
 +{
-+      INIT_LIST_HEAD(&accelerators_list);
++
++      bend->backend_state = XenbusStateClosing;
++      net_accel_update_state((struct xenbus_device *)bend->hdev_data,
++                             XenbusStateClosing);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/netback/common.h linux-2.6.18-xen.hg/drivers/xen/netback/common.h
---- linux-2.6.18/drivers/xen/netback/common.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/netback/common.h   2007-12-23 11:15:34.051268764 +0100
-@@ -0,0 +1,217 @@
-+/******************************************************************************
-+ * arch/xen/drivers/netif/backend/common.h
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/compat/gcc.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/compat/gcc.h        2008-05-19 00:33:47.466882166 +0300
+@@ -0,0 +1,158 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#ifndef __NETIF__BACKEND__COMMON_H__
-+#define __NETIF__BACKEND__COMMON_H__
++/*! \cidoxg_include_ci_compat  */
 +
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/interrupt.h>
-+#include <linux/slab.h>
-+#include <linux/ip.h>
-+#include <linux/in.h>
-+#include <linux/netdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/wait.h>
-+#include <xen/evtchn.h>
-+#include <xen/interface/io/netif.h>
-+#include <asm/io.h>
-+#include <asm/pgalloc.h>
-+#include <xen/interface/grant_table.h>
-+#include <xen/gnttab.h>
-+#include <xen/driver_util.h>
-+#include <xen/xenbus.h>
++#ifndef __CI_COMPAT_GCC_H__
++#define __CI_COMPAT_GCC_H__
 +
-+#define DPRINTK(_f, _a...)                    \
-+      pr_debug("(file=%s, line=%d) " _f,      \
-+               __FILE__ , __LINE__ , ## _a )
-+#define IPRINTK(fmt, args...)                         \
-+      printk(KERN_INFO "xen_net: " fmt, ##args)
-+#define WPRINTK(fmt, args...)                         \
-+      printk(KERN_WARNING "xen_net: " fmt, ##args)
 +
-+typedef struct netif_st {
-+      /* Unique identifier for this interface. */
-+      domid_t          domid;
-+      unsigned int     handle;
++#define CI_HAVE_INT64
 +
-+      u8               fe_dev_addr[6];
 +
-+      /* Physical parameters of the comms window. */
-+      grant_handle_t   tx_shmem_handle;
-+      grant_ref_t      tx_shmem_ref;
-+      grant_handle_t   rx_shmem_handle;
-+      grant_ref_t      rx_shmem_ref;
-+      unsigned int     irq;
++#if defined(__linux__) && defined(__KERNEL__)
 +
-+      /* The shared rings and indexes. */
-+      netif_tx_back_ring_t tx;
-+      netif_rx_back_ring_t rx;
-+      struct vm_struct *tx_comms_area;
-+      struct vm_struct *rx_comms_area;
++# include <linux/types.h>
 +
-+      /* Set of features that can be turned on in dev->features. */
-+      int features;
++typedef __u64                 ci_uint64;
++typedef __s64                 ci_int64;
++# if BITS_PER_LONG == 32
++typedef __s32                 ci_ptr_arith_t;
++typedef __u32                 ci_uintptr_t;
++# else
++typedef __s64                 ci_ptr_arith_t;
++typedef __u64                 ci_uintptr_t;
++# endif
 +
-+      /* Internal feature information. */
-+      u8 can_queue:1; /* can queue packets for receiver? */
-+      u8 copying_receiver:1;  /* copy packets to receiver?       */
 +
-+      /* Allow netif_be_start_xmit() to peek ahead in the rx request ring. */
-+      RING_IDX rx_req_cons_peek;
++/* it's not obvious to me why the below is wrong for x64_64, but
++ * gcc seems to complain on this platform
++ */
++# if defined(__ia64__)
++#  define CI_PRId64            "ld"
++#  define CI_PRIi64            "li"
++#  define CI_PRIo64            "lo"
++#  define CI_PRIu64            "lu"
++#  define CI_PRIx64            "lx"
++#  define CI_PRIX64            "lX"
++# else
++#  define CI_PRId64            "lld"
++#  define CI_PRIi64            "lli"
++#  define CI_PRIo64            "llo"
++#  define CI_PRIu64            "llu"
++#  define CI_PRIx64            "llx"
++#  define CI_PRIX64            "llX"
++# endif
 +
-+      /* Transmit shaping: allow 'credit_bytes' every 'credit_usec'. */
-+      unsigned long   credit_bytes;
-+      unsigned long   credit_usec;
-+      unsigned long   remaining_credit;
-+      struct timer_list credit_timeout;
++# define CI_PRId32            "d"
++# define CI_PRIi32            "i"
++# define CI_PRIo32            "o"
++# define CI_PRIu32            "u"
++# define CI_PRIx32            "x"
++# define CI_PRIX32            "X"
 +
-+      /* Enforce draining of the transmit queue. */
-+      struct timer_list tx_queue_timeout;
++#else
 +
-+      /* Miscellaneous private stuff. */
-+      struct list_head list;  /* scheduling list */
-+      atomic_t         refcnt;
-+      struct net_device *dev;
-+      struct net_device_stats stats;
++# include <stdint.h>
++# include <inttypes.h>
 +
-+      unsigned int carrier;
++typedef uint64_t              ci_uint64;
++typedef int64_t               ci_int64;
++typedef intptr_t              ci_ptr_arith_t;
++typedef uintptr_t             ci_uintptr_t;
 +
-+      wait_queue_head_t waiting_to_free;
-+} netif_t;
++# define CI_PRId64            PRId64
++# define CI_PRIi64            PRIi64
++# define CI_PRIo64            PRIo64
++# define CI_PRIu64            PRIu64
++# define CI_PRIx64            PRIx64
++# define CI_PRIX64            PRIX64
++
++# define CI_PRId32            PRId32
++# define CI_PRIi32            PRIi32
++# define CI_PRIo32            PRIo32
++# define CI_PRIu32            PRIu32
++# define CI_PRIx32            PRIx32
++# define CI_PRIX32            PRIX32
++
++#endif
++
++
++typedef ci_uint64                       ci_fixed_descriptor_t;
++
++#define from_fixed_descriptor(desc) ((ci_uintptr_t)(desc))
++#define to_fixed_descriptor(desc) ((ci_fixed_descriptor_t)(ci_uintptr_t)(desc))
 +
++
++#if __GNUC__ >= 3 && !defined(__cplusplus)
 +/*
-+ * Implement our own carrier flag: the network stack's version causes delays
-+ * when the carrier is re-enabled (in particular, dev_activate() may not
-+ * immediately be called, which can cause packet loss; also the etherbridge
-+ * can be rather lazy in activating its port).
++** Checks that [p_mbr] has the same type as [&c_type::mbr_name].
++*/
++# define CI_CONTAINER(c_type, mbr_name, p_mbr)                                \
++   __builtin_choose_expr(                                             \
++     __builtin_types_compatible_p(__typeof__(&((c_type*)0)->mbr_name),        \
++                               __typeof__(p_mbr)),                    \
++     __CI_CONTAINER(c_type, mbr_name, p_mbr), (void)0)
++
++# define ci_restrict  __restrict__
++#endif
++
++
++#if !defined(__KERNEL__) || defined(__unix__)
++#define CI_HAVE_NPRINTF  1
++#endif
++
++
++/* At what version was this introduced? */
++#if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ > 91)
++# define CI_LIKELY(t)    __builtin_expect((t), 1)
++# define CI_UNLIKELY(t)  __builtin_expect((t), 0)
++#endif
++
++/**********************************************************************
++ * Attributes
 + */
-+#define netback_carrier_on(netif)     ((netif)->carrier = 1)
-+#define netback_carrier_off(netif)    ((netif)->carrier = 0)
-+#define netback_carrier_ok(netif)     ((netif)->carrier)
++#if __GNUC__ >= 3 && defined(NDEBUG)
++# define CI_HF __attribute__((visibility("hidden")))
++# define CI_HV __attribute__((visibility("hidden")))
++#else
++# define CI_HF
++# define CI_HV
++#endif
 +
-+enum {
-+      NETBK_DONT_COPY_SKB,
-+      NETBK_DELAYED_COPY_SKB,
-+      NETBK_ALWAYS_COPY_SKB,
-+};
++#if __GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
++# define ci_noinline  static __attribute__((__noinline__))
++/* (Linux 2.6 defines its own "noinline", so we use the "__noinline__" form) */
++#else
++# define ci_noinline  static
++#endif
 +
-+extern int netbk_copy_skb_mode;
++#define CI_ALIGN(x) __attribute__ ((aligned (x)))
 +
-+/* Function pointers into netback accelerator plugin modules */
-+struct netback_accel_hooks {
-+      struct module *owner;
-+      int  (*probe)(struct xenbus_device *dev);
-+      int (*remove)(struct xenbus_device *dev);
-+};
++#define CI_PRINTF_LIKE(a,b) __attribute__((format(printf,a,b)))
 +
-+/* Structure to track the state of a netback accelerator plugin */
-+struct netback_accelerator {
-+      struct list_head link;
-+      int id;
-+      char *eth_name;
-+      atomic_t use_count;
-+      struct netback_accel_hooks *hooks;
-+};
++#endif  /* __CI_COMPAT_GCC_H__ */
 +
-+struct backend_info {
-+      struct xenbus_device *dev;
-+      netif_t *netif;
-+      enum xenbus_state frontend_state;
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/compat/gcc_x86.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/compat/gcc_x86.h    2008-05-19 00:33:47.538886316 +0300
+@@ -0,0 +1,115 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      /* State relating to the netback accelerator */
-+      void *netback_accel_priv;
-+      /* The accelerator that this backend is currently using */
-+      struct netback_accelerator *accelerator;
-+};
++/*! \cidoxg_include_ci_compat  */
 +
-+#define NETBACK_ACCEL_VERSION 0x00010001
++#ifndef __CI_COMPAT_GCC_X86_H__
++#define __CI_COMPAT_GCC_X86_H__
++
++/*
++** The facts:
++**
++**   SSE   sfence
++**   SSE2  lfence, mfence, pause
++*/
 +
 +/* 
-+ * Connect an accelerator plugin module to netback.  Returns zero on
-+ * success, < 0 on error, > 0 (with highest version number supported)
-+ * if version mismatch.
++   Barriers to enforce ordering with respect to:
++
++   normal memory use: ci_wmb, ci_rmb, ci_wmb
++   IO bus access use: ci_wiob, ci_riob, ci_iob
++*/
++#if defined(__x86_64__)
++# define ci_x86_mb() __asm__ __volatile__ ("lock; addl $0,0(%%rsp)":::"memory")
++#else
++# define ci_x86_mb() __asm__ __volatile__ ("lock; addl $0,0(%%esp)":::"memory")
++#endif
++
++/* ?? measure the impact of latency of sfence on a modern processor before we
++   take a decision on how to integrate with respect to writecombining */
++
++/* DJR: I don't think we need to add "memory" here.  It means the asm does
++** something to memory that GCC doesn't understand.  But all this does is
++** commit changes that GCC thinks have already happened.  NB. GCC will not
++** reorder across a __volatile__ __asm__ anyway.
++*/
++#define ci_gcc_fence()    __asm__ __volatile__ ("")
++
++#if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
++# define ci_x86_sfence()  __asm__ __volatile__ ("sfence")
++# define ci_x86_lfence()  __asm__ __volatile__ ("lfence")
++# define ci_x86_mfence()  __asm__ __volatile__ ("mfence")
++#else
++# define ci_x86_sfence()  __asm__ __volatile__ (".byte 0x0F, 0xAE, 0xF8")
++# define ci_x86_lfence()  __asm__ __volatile__ (".byte 0x0F, 0xAE, 0xE8")
++# define ci_x86_mfence()  __asm__ __volatile__ (".byte 0x0F, 0xAE, 0xF0")
++#endif
++
++
++/* x86 processors to P4 Xeon store in-order unless executing streaming
++   extensions or when using writecombining 
++
++   Hence we do not define ci_wmb to use sfence by default. Requirement is that
++   we do not use writecombining to memory and any code which uses SSE
++   extensions must call sfence directly 
++
++   We need to track non intel clones which may support out of order store.
++
++*/
++
++#if CI_CPU_OOS
++# if CI_CPU_HAS_SSE
++#  define ci_wmb()    ci_x86_sfence()
++# else
++#  define ci_wmb()    ci_x86_mb()
++# endif
++#else
++# define ci_wmb()       ci_gcc_fence()
++#endif
++
++#if CI_CPU_HAS_SSE2
++# define ci_rmb()     ci_x86_lfence()
++# define ci_mb()      ci_x86_mfence()
++# define ci_riob()    ci_x86_lfence()
++# define ci_wiob()    ci_x86_sfence()
++# define ci_iob()     ci_x86_mfence()
++#else
++# if CI_CPU_HAS_SSE
++#  define ci_wiob()   ci_x86_sfence()
++# else
++#  define ci_wiob()   ci_x86_mb()
++# endif
++# define ci_rmb()     ci_x86_mb()
++# define ci_mb()      ci_x86_mb()
++# define ci_riob()    ci_x86_mb()
++# define ci_iob()     ci_x86_mb()
++#endif
++
++typedef unsigned long   ci_phys_addr_t;
++#define ci_phys_addr_fmt  "%lx"
++
++#endif  /* __CI_COMPAT_GCC_X86_H__ */
++
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/compat/primitive.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/compat/primitive.h  2008-05-19 00:33:47.562887700 +0300
+@@ -0,0 +1,77 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
-+extern int netback_connect_accelerator(unsigned version,
-+                                     int id, const char *eth_name, 
-+                                     struct netback_accel_hooks *hooks);
-+/* Disconnect a previously connected accelerator plugin module */
-+extern void netback_disconnect_accelerator(int id, const char *eth_name);
++/*! \cidoxg_include_ci_compat  */
 +
++#ifndef __CI_COMPAT_PRIMITIVE_H__
++#define __CI_COMPAT_PRIMITIVE_H__
 +
-+extern
-+void netback_probe_accelerators(struct backend_info *be,
-+                              struct xenbus_device *dev);
-+extern
-+void netback_remove_accelerators(struct backend_info *be,
-+                               struct xenbus_device *dev);
-+extern
-+void netif_accel_init(void);
 +
++/**********************************************************************
++ * Primitive types.
++ */
 +
-+#define NET_TX_RING_SIZE __RING_SIZE((netif_tx_sring_t *)0, PAGE_SIZE)
-+#define NET_RX_RING_SIZE __RING_SIZE((netif_rx_sring_t *)0, PAGE_SIZE)
++typedef unsigned char                   ci_uint8;
++typedef char                            ci_int8;
 +
-+void netif_disconnect(netif_t *netif);
++typedef unsigned short                  ci_uint16;
++typedef short                           ci_int16;
 +
-+netif_t *netif_alloc(domid_t domid, unsigned int handle);
-+int netif_map(netif_t *netif, unsigned long tx_ring_ref,
-+            unsigned long rx_ring_ref, unsigned int evtchn);
++typedef unsigned int                    ci_uint32;
++typedef int                             ci_int32;
 +
-+#define netif_get(_b) (atomic_inc(&(_b)->refcnt))
-+#define netif_put(_b)                                         \
-+      do {                                                    \
-+              if ( atomic_dec_and_test(&(_b)->refcnt) )       \
-+                      wake_up(&(_b)->waiting_to_free);        \
-+      } while (0)
++/* 64-bit support is platform dependent. */
 +
-+void netif_xenbus_init(void);
 +
-+#define netif_schedulable(netif)                              \
-+      (netif_running((netif)->dev) && netback_carrier_ok(netif))
++/**********************************************************************
++ * Other fancy types.
++ */
 +
-+void netif_schedule_work(netif_t *netif);
-+void netif_deschedule_work(netif_t *netif);
++typedef ci_uint8                        ci_octet;
 +
-+int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev);
-+struct net_device_stats *netif_be_get_stats(struct net_device *dev);
-+irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs);
++typedef enum {
++  CI_FALSE = 0,
++  CI_TRUE
++} ci_boolean_t;
 +
-+static inline int netbk_can_queue(struct net_device *dev)
-+{
-+      netif_t *netif = netdev_priv(dev);
-+      return netif->can_queue;
-+}
 +
-+static inline int netbk_can_sg(struct net_device *dev)
-+{
-+      netif_t *netif = netdev_priv(dev);
-+      return netif->features & NETIF_F_SG;
-+}
++/**********************************************************************
++ * Some nice types you'd always assumed were standards.
++ * (Really, they are SYSV "standards".)
++ */
 +
-+#endif /* __NETIF__BACKEND__COMMON_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/netback/interface.c linux-2.6.18-xen.hg/drivers/xen/netback/interface.c
---- linux-2.6.18/drivers/xen/netback/interface.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/netback/interface.c        2007-12-23 11:15:34.054602273 +0100
-@@ -0,0 +1,336 @@
-+/******************************************************************************
-+ * arch/xen/drivers/netif/backend/interface.c
-+ * 
-+ * Network-device interface management.
-+ * 
-+ * Copyright (c) 2004-2005, Keir Fraser
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++#ifdef _WIN32
++typedef unsigned long                   ulong;              
++typedef unsigned int                    uint;
++typedef char*                           caddr_t;
++#elif defined(__linux__) && defined(__KERNEL__)
++#include <linux/types.h>
++#elif defined(__linux__)
++#include <sys/types.h>
++#endif
++
++
++#endif  /* __CI_COMPAT_PRIMITIVE_H__ */
++
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/compat/sysdep.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/compat/sysdep.h     2008-05-19 00:33:47.666893695 +0300
+@@ -0,0 +1,166 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include "common.h"
-+#include <linux/ethtool.h>
-+#include <linux/rtnetlink.h>
++/*! \cidoxg_include_ci_compat  */
 +
-+/*
-+ * Module parameter 'queue_length':
-+ * 
-+ * Enables queuing in the network stack when a client has run out of receive
-+ * descriptors. Although this feature can improve receive bandwidth by avoiding
-+ * packet loss, it can also result in packets sitting in the 'tx_queue' for
-+ * unbounded time. This is bad if those packets hold onto foreign resources.
-+ * For example, consider a packet that holds onto resources belonging to the
-+ * guest for which it is queued (e.g., packet received on vif1.0, destined for
-+ * vif1.1 which is not activated in the guest): in this situation the guest
-+ * will never be destroyed, unless vif1.1 is taken down. To avoid this, we
-+ * run a timer (tx_queue_timeout) to drain the queue when the interface is
-+ * blocked.
++#ifndef __CI_COMPAT_SYSDEP_H__
++#define __CI_COMPAT_SYSDEP_H__
++
++
++/**********************************************************************
++ * Platform definition fixups.
 + */
-+static unsigned long netbk_queue_length = 32;
-+module_param_named(queue_length, netbk_queue_length, ulong, 0);
 +
-+static void __netif_up(netif_t *netif)
-+{
-+      enable_irq(netif->irq);
-+      netif_schedule_work(netif);
-+}
++#if defined(__ci_ul_driver__) && !defined(__ci_driver__)
++# define __ci_driver__
++#endif
 +
-+static void __netif_down(netif_t *netif)
-+{
-+      disable_irq(netif->irq);
-+      netif_deschedule_work(netif);
-+}
++#if defined(__ci_driver__) && !defined(__ci_ul_driver__) && \
++   !defined(__KERNEL__)
++# define __KERNEL__
++#endif
 +
-+static int net_open(struct net_device *dev)
-+{
-+      netif_t *netif = netdev_priv(dev);
-+      if (netback_carrier_ok(netif)) {
-+              __netif_up(netif);
-+              netif_start_queue(dev);
-+      }
-+      return 0;
-+}
 +
-+static int net_close(struct net_device *dev)
-+{
-+      netif_t *netif = netdev_priv(dev);
-+      if (netback_carrier_ok(netif))
-+              __netif_down(netif);
-+      netif_stop_queue(dev);
-+      return 0;
-+}
++/**********************************************************************
++ * Sanity checks (no cheating!)
++ */
 +
-+static int netbk_change_mtu(struct net_device *dev, int mtu)
-+{
-+      int max = netbk_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
++#if defined(__KERNEL__) && !defined(__ci_driver__)
++# error Insane.
++#endif
 +
-+      if (mtu > max)
-+              return -EINVAL;
-+      dev->mtu = mtu;
-+      return 0;
-+}
++#if defined(__KERNEL__) && defined(__ci_ul_driver__)
++# error Madness.
++#endif
 +
-+static int netbk_set_sg(struct net_device *dev, u32 data)
-+{
-+      if (data) {
-+              netif_t *netif = netdev_priv(dev);
++#if defined(__unix__) && defined(_WIN32)
++# error Strange.
++#endif
 +
-+              if (!(netif->features & NETIF_F_SG))
-+                      return -ENOSYS;
-+      }
++#if defined(__GNUC__) && defined(_MSC_VER)
++# error Crazy.
++#endif
 +
-+      return ethtool_op_set_sg(dev, data);
-+}
 +
-+static int netbk_set_tso(struct net_device *dev, u32 data)
-+{
-+      if (data) {
-+              netif_t *netif = netdev_priv(dev);
++/**********************************************************************
++ * Compiler and processor dependencies.
++ */
 +
-+              if (!(netif->features & NETIF_F_TSO))
-+                      return -ENOSYS;
-+      }
++#if defined(__GNUC__)
 +
-+      return ethtool_op_set_tso(dev, data);
-+}
++# include <ci/compat/gcc.h>
++
++# if defined(__i386__)
++#  include <ci/compat/x86.h>
++#  include <ci/compat/gcc_x86.h>
++# elif defined(__x86_64__)
++#  include <ci/compat/x86_64.h>
++#  include <ci/compat/gcc_x86.h>
++# elif defined(__PPC__)
++#  include <ci/compat/ppc.h>
++#  include <ci/compat/gcc_ppc.h>
++# elif defined(__ia64__)
++#  include <ci/compat/ia64.h>
++#  include <ci/compat/gcc_ia64.h>
++# else
++#  error Unknown processor - GNU C
++# endif
 +
-+static struct ethtool_ops network_ethtool_ops =
-+{
-+      .get_tx_csum = ethtool_op_get_tx_csum,
-+      .set_tx_csum = ethtool_op_set_tx_csum,
-+      .get_sg = ethtool_op_get_sg,
-+      .set_sg = netbk_set_sg,
-+      .get_tso = ethtool_op_get_tso,
-+      .set_tso = netbk_set_tso,
-+      .get_link = ethtool_op_get_link,
-+};
++#elif defined(_MSC_VER)
 +
-+netif_t *netif_alloc(domid_t domid, unsigned int handle)
-+{
-+      int err = 0;
-+      struct net_device *dev;
-+      netif_t *netif;
-+      char name[IFNAMSIZ] = {};
++# include <ci/compat/msvc.h>
 +
-+      snprintf(name, IFNAMSIZ - 1, "vif%u.%u", domid, handle);
-+      dev = alloc_netdev(sizeof(netif_t), name, ether_setup);
-+      if (dev == NULL) {
-+              DPRINTK("Could not create netif: out of memory\n");
-+              return ERR_PTR(-ENOMEM);
-+      }
++# if defined(__i386__)
++#  include <ci/compat/x86.h>
++#  include <ci/compat/msvc_x86.h>
++# elif defined(__x86_64__)
++#  include <ci/compat/x86_64.h>
++#  include <ci/compat/msvc_x86_64.h>
++# else
++#  error Unknown processor MSC
++# endif
 +
-+      netif = netdev_priv(dev);
-+      memset(netif, 0, sizeof(*netif));
-+      netif->domid  = domid;
-+      netif->handle = handle;
-+      atomic_set(&netif->refcnt, 1);
-+      init_waitqueue_head(&netif->waiting_to_free);
-+      netif->dev = dev;
++#elif defined(__PGI)
++
++# include <ci/compat/x86.h>
++# include <ci/compat/pg_x86.h>
++
++#elif defined(__INTEL_COMPILER)
++
++/* Intel compilers v7 claim to be very gcc compatible. */
++# if __INTEL_COMPILER >= 700
++#  include <ci/compat/gcc.h>
++#  include <ci/compat/x86.h>
++#  include <ci/compat/gcc_x86.h>
++# else
++#  error Old Intel compiler not supported.  Yet.
++# endif
++
++#else
++# error Unknown compiler.
++#endif
++
++
++/**********************************************************************
++ * Misc stuff (that probably shouldn't be here).
++ */
++
++#ifdef __sun
++# ifdef __KERNEL__
++#  define _KERNEL
++#  define _SYSCALL32
++#  ifdef _LP64
++#   define _SYSCALL32_IMPL
++#  endif
++# else
++#  define _REENTRANT
++# endif
++#endif
++
++
++/**********************************************************************
++ * Defaults for anything left undefined.
++ */
++
++#ifndef  CI_LIKELY
++# define CI_LIKELY(t)    (t)
++# define CI_UNLIKELY(t)  (t)
++#endif
++
++#ifndef  ci_restrict
++# define ci_restrict
++#endif
++
++#ifndef  ci_inline
++# define ci_inline  static inline
++#endif
++
++#ifndef  ci_noinline
++# define ci_noinline  static
++#endif
++
++#endif  /* __CI_COMPAT_SYSDEP_H__ */
++
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/compat/utils.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/compat/utils.h      2008-05-19 00:33:47.670893925 +0300
+@@ -0,0 +1,269 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++/*
++ * \author  djr
++ *  \brief  Handy utility macros.
++ *   \date  2003/01/17
++ */
++
++/*! \cidoxg_include_ci_compat  */
++
++#ifndef __CI_COMPAT_UTILS_H__
++#define __CI_COMPAT_UTILS_H__
 +
-+      netback_carrier_off(netif);
 +
-+      netif->credit_bytes = netif->remaining_credit = ~0UL;
-+      netif->credit_usec  = 0UL;
-+      init_timer(&netif->credit_timeout);
-+      /* Initialize 'expires' now: it's used to track the credit window. */
-+      netif->credit_timeout.expires = jiffies;
++/**********************************************************************
++ * Alignment -- [align] must be a power of 2.
++ **********************************************************************/
 +
-+      init_timer(&netif->tx_queue_timeout);
++  /*! Align forward onto next boundary. */
 +
-+      dev->hard_start_xmit = netif_be_start_xmit;
-+      dev->get_stats       = netif_be_get_stats;
-+      dev->open            = net_open;
-+      dev->stop            = net_close;
-+      dev->change_mtu      = netbk_change_mtu;
-+      dev->features        = NETIF_F_IP_CSUM;
++#define CI_ALIGN_FWD(p, align)               (((p)+(align)-1u) & ~((align)-1u))
 +
-+      SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
 +
-+      dev->tx_queue_len = netbk_queue_length;
++  /*! Align back onto prev boundary. */
 +
-+      /*
-+       * Initialise a dummy MAC address. We choose the numerically
-+       * largest non-broadcast address to prevent the address getting
-+       * stolen by an Ethernet bridge for STP purposes.
-+       * (FE:FF:FF:FF:FF:FF)
-+       */ 
-+      memset(dev->dev_addr, 0xFF, ETH_ALEN);
-+      dev->dev_addr[0] &= ~0x01;
++#define CI_ALIGN_BACK(p, align)              ((p) & ~((align)-1u))
 +
-+      rtnl_lock();
-+      err = register_netdevice(dev);
-+      rtnl_unlock();
-+      if (err) {
-+              DPRINTK("Could not register new net device %s: err=%d\n",
-+                      dev->name, err);
-+              free_netdev(dev);
-+              return ERR_PTR(err);
-+      }
 +
-+      DPRINTK("Successfully created netif\n");
-+      return netif;
-+}
++  /*! How far to next boundary? */
 +
-+static int map_frontend_pages(
-+      netif_t *netif, grant_ref_t tx_ring_ref, grant_ref_t rx_ring_ref)
-+{
-+      struct gnttab_map_grant_ref op;
++#define CI_ALIGN_NEEDED(p, align, signed_t)  (-(signed_t)(p) & ((align)-1u))
 +
-+      gnttab_set_map_op(&op, (unsigned long)netif->tx_comms_area->addr,
-+                        GNTMAP_host_map, tx_ring_ref, netif->domid);
-+    
-+      if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
-+              BUG();
 +
-+      if (op.status) { 
-+              DPRINTK(" Gnttab failure mapping tx_ring_ref!\n");
-+              return op.status;
-+      }
++  /*! How far beyond prev boundary? */
 +
-+      netif->tx_shmem_ref    = tx_ring_ref;
-+      netif->tx_shmem_handle = op.handle;
++#define CI_OFFSET(p, align)                  ((p) & ((align)-1u))
 +
-+      gnttab_set_map_op(&op, (unsigned long)netif->rx_comms_area->addr,
-+                        GNTMAP_host_map, rx_ring_ref, netif->domid);
 +
-+      if (HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1))
-+              BUG();
++  /*! Does object fit in gap before next boundary? */
 +
-+      if (op.status) {
-+              DPRINTK(" Gnttab failure mapping rx_ring_ref!\n");
-+              return op.status;
-+      }
++#define CI_FITS(p, size, align, signed_t)                     \
++  (CI_ALIGN_NEEDED((p) + 1, (align), signed_t) + 1 >= (size))
 +
-+      netif->rx_shmem_ref    = rx_ring_ref;
-+      netif->rx_shmem_handle = op.handle;
 +
-+      return 0;
-+}
++  /*! Align forward onto next boundary. */
 +
-+static void unmap_frontend_pages(netif_t *netif)
-+{
-+      struct gnttab_unmap_grant_ref op;
++#define CI_PTR_ALIGN_FWD(p, align)                                       \
++  ((char*) CI_ALIGN_FWD(((ci_ptr_arith_t)(p)), ((ci_ptr_arith_t)(align))))
 +
-+      gnttab_set_unmap_op(&op, (unsigned long)netif->tx_comms_area->addr,
-+                          GNTMAP_host_map, netif->tx_shmem_handle);
++  /*! Align back onto prev boundary. */
 +
-+      if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
-+              BUG();
++#define CI_PTR_ALIGN_BACK(p, align)                                       \
++  ((char*) CI_ALIGN_BACK(((ci_ptr_arith_t)(p)), ((ci_ptr_arith_t)(align))))
 +
-+      gnttab_set_unmap_op(&op, (unsigned long)netif->rx_comms_area->addr,
-+                          GNTMAP_host_map, netif->rx_shmem_handle);
++  /*! How far to next boundary? */
 +
-+      if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1))
-+              BUG();
-+}
++#define CI_PTR_ALIGN_NEEDED(p, align)                                 \
++  CI_ALIGN_NEEDED(((ci_ptr_arith_t)(p)), ((ci_ptr_arith_t)(align)),   \
++                ci_ptr_arith_t)
 +
-+int netif_map(netif_t *netif, unsigned long tx_ring_ref,
-+            unsigned long rx_ring_ref, unsigned int evtchn)
-+{
-+      int err = -ENOMEM;
-+      netif_tx_sring_t *txs;
-+      netif_rx_sring_t *rxs;
++  /*! How far to next boundary? NZ = not zero i.e. give align if on boundary  */
 +
-+      /* Already connected through? */
-+      if (netif->irq)
-+              return 0;
++#define CI_PTR_ALIGN_NEEDED_NZ(p, align)                                      \
++  ((align) - (((char*)p) -                                                      \
++  ((char*) CI_ALIGN_BACK(((ci_ptr_arith_t)(p)), ((ci_ptr_arith_t)(align))))))
 +
-+      netif->tx_comms_area = alloc_vm_area(PAGE_SIZE);
-+      if (netif->tx_comms_area == NULL)
-+              return -ENOMEM;
-+      netif->rx_comms_area = alloc_vm_area(PAGE_SIZE);
-+      if (netif->rx_comms_area == NULL)
-+              goto err_rx;
++  /*! How far beyond prev boundary? */
 +
-+      err = map_frontend_pages(netif, tx_ring_ref, rx_ring_ref);
-+      if (err)
-+              goto err_map;
++#define CI_PTR_OFFSET(p, align)                                       \
++  CI_OFFSET(((ci_ptr_arith_t)(p)), ((ci_ptr_arith_t)(align)))
 +
-+      err = bind_interdomain_evtchn_to_irqhandler(
-+              netif->domid, evtchn, netif_be_int, 0,
-+              netif->dev->name, netif);
-+      if (err < 0)
-+              goto err_hypervisor;
-+      netif->irq = err;
-+      disable_irq(netif->irq);
 +
-+      txs = (netif_tx_sring_t *)netif->tx_comms_area->addr;
-+      BACK_RING_INIT(&netif->tx, txs, PAGE_SIZE);
++  /* Same as CI_ALIGN_FWD and CI_ALIGN_BACK. */
 +
-+      rxs = (netif_rx_sring_t *)
-+              ((char *)netif->rx_comms_area->addr);
-+      BACK_RING_INIT(&netif->rx, rxs, PAGE_SIZE);
++#define CI_ROUND_UP(i, align)      (((i)+(align)-1u) & ~((align)-1u))
 +
-+      netif->rx_req_cons_peek = 0;
++#define CI_ROUND_DOWN(i, align)    ((i) & ~((align)-1u))
 +
-+      netif_get(netif);
 +
-+      rtnl_lock();
-+      netback_carrier_on(netif);
-+      if (netif_running(netif->dev))
-+              __netif_up(netif);
-+      rtnl_unlock();
++/**********************************************************************
++ * Byte-order
++ **********************************************************************/
 +
-+      return 0;
-+err_hypervisor:
-+      unmap_frontend_pages(netif);
-+err_map:
-+      free_vm_area(netif->rx_comms_area);
-+err_rx:
-+      free_vm_area(netif->tx_comms_area);
-+      return err;
-+}
++/* These are not flags.  They are enumeration values for use with
++ * CI_MY_BYTE_ORDER. */
++#define CI_BIG_ENDIAN          1
++#define CI_LITTLE_ENDIAN       0
 +
-+void netif_disconnect(netif_t *netif)
-+{
-+      if (netback_carrier_ok(netif)) {
-+              rtnl_lock();
-+              netback_carrier_off(netif);
-+              netif_carrier_off(netif->dev); /* discard queued packets */
-+              if (netif_running(netif->dev))
-+                      __netif_down(netif);
-+              rtnl_unlock();
-+              netif_put(netif);
-+      }
++/*
++** Note that these byte-swapping primitives may leave junk in bits above
++** the range they operate on.
++**
++** The CI_BSWAP_nn() routines require that bits above [nn] are zero.  Use
++** CI_BSWAPM_nn(x) if this cannot be guaranteed.
++*/
 +
-+      atomic_dec(&netif->refcnt);
-+      wait_event(netif->waiting_to_free, atomic_read(&netif->refcnt) == 0);
++/* ?? May be able to improve on some of these with inline assembler on some
++** platforms.
++*/
 +
-+      del_timer_sync(&netif->credit_timeout);
-+      del_timer_sync(&netif->tx_queue_timeout);
++#define CI_BSWAP_16(v)    ((((v) & 0xff) << 8) | ((v) >> 8))
++#define CI_BSWAPM_16(v)   ((((v) & 0xff) << 8) | (((v) & 0xff00) >> 8))
++
++#define CI_BSWAP_32(v)    (((v) >> 24)               |        \
++                         (((v) & 0x00ff0000) >> 8) |  \
++                         (((v) & 0x0000ff00) << 8) |  \
++                         ((v) << 24))
++#define CI_BSWAPM_32(v)   ((((v) & 0xff000000) >> 24) |       \
++                         (((v) & 0x00ff0000) >> 8)  | \
++                         (((v) & 0x0000ff00) << 8)  | \
++                         ((v) << 24))
++
++#define CI_BSWAP_64(v)    (((v) >> 56)                        |       \
++                         (((v) & 0x00ff000000000000) >> 40) | \
++                         (((v) & 0x0000ff0000000000) >> 24) | \
++                         (((v) & 0x000000ff00000000) >> 8)  | \
++                         (((v) & 0x00000000ff000000) << 8)  | \
++                         (((v) & 0x0000000000ff0000) << 24) | \
++                         (((v) & 0x000000000000ff00) << 40) | \
++                         ((v) << 56))
++
++# define CI_BSWAPPED_16_IF(c,v)  ((c) ? CI_BSWAP_16(v) : (v))
++# define CI_BSWAPPED_32_IF(c,v)  ((c) ? CI_BSWAP_32(v) : (v))
++# define CI_BSWAPPED_64_IF(c,v)  ((c) ? CI_BSWAP_64(v) : (v))
++# define CI_BSWAP_16_IF(c,v)     do{ if((c)) (v) = CI_BSWAP_16(v); }while(0)
++# define CI_BSWAP_32_IF(c,v)     do{ if((c)) (v) = CI_BSWAP_32(v); }while(0)
++# define CI_BSWAP_64_IF(c,v)     do{ if((c)) (v) = CI_BSWAP_64(v); }while(0)
++
++#if (CI_MY_BYTE_ORDER == CI_LITTLE_ENDIAN)
++# define CI_BSWAP_LE16(v)    (v)
++# define CI_BSWAP_LE32(v)    (v)
++# define CI_BSWAP_LE64(v)    (v)
++# define CI_BSWAP_BE16(v)    CI_BSWAP_16(v)
++# define CI_BSWAP_BE32(v)    CI_BSWAP_32(v)
++# define CI_BSWAP_BE64(v)    CI_BSWAP_64(v)
++# define CI_BSWAPM_LE16(v)   (v)
++# define CI_BSWAPM_LE32(v)   (v)
++# define CI_BSWAPM_LE64(v)   (v)
++# define CI_BSWAPM_BE16(v)   CI_BSWAPM_16(v)
++# define CI_BSWAPM_BE32(v)   CI_BSWAPM_32(v)
++#elif (CI_MY_BYTE_ORDER == CI_BIG_ENDIAN)
++# define CI_BSWAP_BE16(v)    (v)
++# define CI_BSWAP_BE32(v)    (v)
++# define CI_BSWAP_BE64(v)    (v)
++# define CI_BSWAP_LE16(v)    CI_BSWAP_16(v)
++# define CI_BSWAP_LE32(v)    CI_BSWAP_32(v)
++# define CI_BSWAP_LE64(v)    CI_BSWAP_64(v)
++# define CI_BSWAPM_BE16(v)   (v)
++# define CI_BSWAPM_BE32(v)   (v)
++# define CI_BSWAPM_BE64(v)   (v)
++# define CI_BSWAPM_LE16(v)   CI_BSWAPM_16(v)
++# define CI_BSWAPM_LE32(v)   CI_BSWAPM_32(v)
++#else
++# error Bad endian.
++#endif
 +
-+      if (netif->irq)
-+              unbind_from_irqhandler(netif->irq, netif);
-+      
-+      unregister_netdev(netif->dev);
 +
-+      if (netif->tx.sring) {
-+              unmap_frontend_pages(netif);
-+              free_vm_area(netif->tx_comms_area);
-+              free_vm_area(netif->rx_comms_area);
-+      }
++/**********************************************************************
++ * Get pointer to struct from pointer to member
++ **********************************************************************/
 +
-+      free_netdev(netif->dev);
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/netback/loopback.c linux-2.6.18-xen.hg/drivers/xen/netback/loopback.c
---- linux-2.6.18/drivers/xen/netback/loopback.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/netback/loopback.c 2007-12-23 11:15:34.054602273 +0100
-@@ -0,0 +1,324 @@
-+/******************************************************************************
-+ * netback/loopback.c
-+ * 
-+ * A two-interface loopback device to emulate a local netfront-netback
-+ * connection. This ensures that local packet delivery looks identical
-+ * to inter-domain delivery. Most importantly, packets delivered locally
-+ * originating from other domains will get *copied* when they traverse this
-+ * driver. This prevents unbounded delays in socket-buffer queues from
-+ * causing the netback driver to "seize up".
-+ * 
-+ * This driver creates a symmetric pair of loopback interfaces with names
-+ * vif0.0 and veth0. The intention is that 'vif0.0' is bound to an Ethernet
-+ * bridge, just like a proper netback interface, while a local IP interface
-+ * is configured on 'veth0'.
-+ * 
-+ * As with a real netback interface, vif0.0 is configured with a suitable
-+ * dummy MAC address. No default is provided for veth0: a reasonable strategy
-+ * is to transfer eth0's MAC address to veth0, and give eth0 a dummy address
-+ * (to avoid confusing the Etherbridge).
-+ * 
-+ * Copyright (c) 2005 K A Fraser
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
++#define CI_MEMBER_OFFSET(c_type, mbr_name)  \
++  ((ci_uint32) (ci_uintptr_t)(&((c_type*)0)->mbr_name))
 +
-+#include <linux/module.h>
-+#include <linux/netdevice.h>
-+#include <linux/inetdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/ethtool.h>
-+#include <net/dst.h>
-+#include <net/xfrm.h>         /* secpath_reset() */
-+#include <asm/hypervisor.h>   /* is_initial_xendomain() */
++#define CI_MEMBER_SIZE(c_type, mbr_name)        \
++  sizeof(((c_type*)0)->mbr_name)
 +
-+static int nloopbacks = -1;
-+module_param(nloopbacks, int, 0);
-+MODULE_PARM_DESC(nloopbacks, "Number of netback-loopback devices to create");
++#define __CI_CONTAINER(c_type, mbr_name, p_mbr)  \
++  ( (c_type*) ((char*)(p_mbr) - CI_MEMBER_OFFSET(c_type, mbr_name)) )
 +
-+struct net_private {
-+      struct net_device *loopback_dev;
-+      struct net_device_stats stats;
-+};
++#ifndef CI_CONTAINER
++# define CI_CONTAINER(t,m,p)  __CI_CONTAINER(t,m,p)
++#endif
 +
-+static int loopback_open(struct net_device *dev)
-+{
-+      struct net_private *np = netdev_priv(dev);
-+      memset(&np->stats, 0, sizeof(np->stats));
-+      netif_start_queue(dev);
-+      return 0;
-+}
 +
-+static int loopback_close(struct net_device *dev)
-+{
-+      netif_stop_queue(dev);
-+      return 0;
-+}
++/**********************************************************************
++ * Structure member initialiser.
++ **********************************************************************/
 +
-+#ifdef CONFIG_X86
-+static int is_foreign(unsigned long pfn)
-+{
-+      /* NB. Play it safe for auto-translation mode. */
-+      return (xen_feature(XENFEAT_auto_translated_physmap) ||
-+              (phys_to_machine_mapping[pfn] & FOREIGN_FRAME_BIT));
-+}
-+#else
-+/* How to detect a foreign mapping? Play it safe. */
-+#define is_foreign(pfn)       (1)
++#ifndef CI_STRUCT_MBR
++# define CI_STRUCT_MBR(name, val)     .name = val
 +#endif
 +
-+static int skb_remove_foreign_references(struct sk_buff *skb)
-+{
-+      struct page *page;
-+      unsigned long pfn;
-+      int i, off;
-+      char *vaddr;
 +
-+      BUG_ON(skb_shinfo(skb)->frag_list);
++/**********************************************************************
++ * min / max
++ **********************************************************************/ 
 +
-+      if (skb_cloned(skb) &&
-+          unlikely(pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
-+              return 0;
++#define CI_MIN(x,y) (((x) < (y)) ? (x) : (y))
++#define CI_MAX(x,y) (((x) > (y)) ? (x) : (y))
 +
-+      for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
-+              pfn = page_to_pfn(skb_shinfo(skb)->frags[i].page);
-+              if (!is_foreign(pfn))
-+                      continue;
-+              
-+              page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
-+              if (unlikely(!page))
-+                      return 0;
++/**********************************************************************
++ * abs
++ **********************************************************************/ 
 +
-+              vaddr = kmap_skb_frag(&skb_shinfo(skb)->frags[i]);
-+              off = skb_shinfo(skb)->frags[i].page_offset;
-+              memcpy(page_address(page) + off,
-+                     vaddr + off,
-+                     skb_shinfo(skb)->frags[i].size);
-+              kunmap_skb_frag(vaddr);
++#define CI_ABS(x) (((x) < 0) ? -(x) : (x))
 +
-+              put_page(skb_shinfo(skb)->frags[i].page);
-+              skb_shinfo(skb)->frags[i].page = page;
-+      }
++/**********************************************************************
++ * Conditional debugging
++ **********************************************************************/ 
 +
-+      return 1;
-+}
++#ifdef NDEBUG
++# define CI_DEBUG(x)
++# define CI_NDEBUG(x)      x
++# define CI_IF_DEBUG(y,n)  (n)
++# define CI_DEBUG_ARG(x)
++#else
++# define CI_DEBUG(x)       x
++# define CI_NDEBUG(x)
++# define CI_IF_DEBUG(y,n)  (y)
++# define CI_DEBUG_ARG(x)   ,x
++#endif
 +
-+static int loopback_start_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+      struct net_private *np = netdev_priv(dev);
++#ifdef __KERNEL__
++#define CI_KERNEL_ARG(x)   ,x
++#else
++#define CI_KERNEL_ARG(x)
++#endif
 +
-+      if (!skb_remove_foreign_references(skb)) {
-+              np->stats.tx_dropped++;
-+              dev_kfree_skb(skb);
-+              return 0;
-+      }
++#ifdef _WIN32
++# define CI_KERNEL_ARG_WIN(x) CI_KERNEL_ARG(x)
++# define CI_ARG_WIN(x) ,x
++#else
++# define CI_KERNEL_ARG_WIN(x)
++# define CI_ARG_WIN(x) 
++#endif
 +
-+      dst_release(skb->dst);
-+      skb->dst = NULL;
++#ifdef __unix__
++# define CI_KERNEL_ARG_UNIX(x) CI_KERNEL_ARG(x)
++# define CI_ARG_UNIX(x) ,x
++#else
++# define CI_KERNEL_ARG_UNIX(x)
++# define CI_ARG_UNIX(x) 
++#endif
 +
-+      skb_orphan(skb);
++#ifdef __linux__
++# define CI_KERNEL_ARG_LINUX(x) CI_KERNEL_ARG(x)
++# define CI_ARG_LINUX(x) ,x
++#else
++# define CI_KERNEL_ARG_LINUX(x)
++# define CI_ARG_LINUX(x) 
++#endif
 +
-+      np->stats.tx_bytes += skb->len;
-+      np->stats.tx_packets++;
 +
-+      /* Switch to loopback context. */
-+      dev = np->loopback_dev;
-+      np  = netdev_priv(dev);
++#endif  /* __CI_COMPAT_UTILS_H__ */
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/compat/x86.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/compat/x86.h        2008-05-19 00:33:47.734897614 +0300
+@@ -0,0 +1,48 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      np->stats.rx_bytes += skb->len;
-+      np->stats.rx_packets++;
++/*! \cidoxg_include_ci_compat  */
 +
-+      if (skb->ip_summed == CHECKSUM_HW) {
-+              /* Defer checksum calculation. */
-+              skb->proto_csum_blank = 1;
-+              /* Must be a local packet: assert its integrity. */
-+              skb->proto_data_valid = 1;
-+      }
++#ifndef __CI_COMPAT_X86_H__
++#define __CI_COMPAT_X86_H__
 +
-+      skb->ip_summed = skb->proto_data_valid ?
-+              CHECKSUM_UNNECESSARY : CHECKSUM_NONE;
 +
-+      skb->pkt_type = PACKET_HOST; /* overridden by eth_type_trans() */
-+      skb->protocol = eth_type_trans(skb, dev);
-+      skb->dev      = dev;
-+      dev->last_rx  = jiffies;
++#define CI_MY_BYTE_ORDER   CI_LITTLE_ENDIAN
 +
-+      /* Flush netfilter context: rx'ed skbuffs not expected to have any. */
-+      nf_reset(skb);
-+      secpath_reset(skb);
++#define CI_WORD_SIZE       4
++#define CI_PTR_SIZE        4
 +
-+      netif_rx(skb);
++#define CI_PAGE_SIZE       4096
++#define CI_PAGE_SHIFT      12
++#define CI_PAGE_MASK       (~(CI_PAGE_SIZE - 1))
 +
-+      return 0;
-+}
++#define CI_CPU_HAS_SSE           1    /* SSE extensions supported */
++#define CI_CPU_HAS_SSE2          0    /* SSE2 extensions supported */
++#define CI_CPU_OOS       0    /* CPU does out of order stores */
 +
-+static struct net_device_stats *loopback_get_stats(struct net_device *dev)
-+{
-+      struct net_private *np = netdev_priv(dev);
-+      return &np->stats;
-+}
 +
-+static struct ethtool_ops network_ethtool_ops =
-+{
-+      .get_tx_csum = ethtool_op_get_tx_csum,
-+      .set_tx_csum = ethtool_op_set_tx_csum,
-+      .get_sg = ethtool_op_get_sg,
-+      .set_sg = ethtool_op_set_sg,
-+      .get_tso = ethtool_op_get_tso,
-+      .set_tso = ethtool_op_set_tso,
-+      .get_link = ethtool_op_get_link,
-+};
++#endif  /* __CI_COMPAT_X86_H__ */
 +
-+/*
-+ * Nothing to do here. Virtual interface is point-to-point and the
-+ * physical interface is probably promiscuous anyway.
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/compat/x86_64.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/compat/x86_64.h     2008-05-19 00:33:47.866905224 +0300
+@@ -0,0 +1,54 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
-+static void loopback_set_multicast_list(struct net_device *dev)
-+{
-+}
 +
-+static void loopback_construct(struct net_device *dev, struct net_device *lo)
-+{
-+      struct net_private *np = netdev_priv(dev);
++/*
++ * \author  djr
++ *  \brief  Arch stuff for AMD x86_64.
++ *   \date  2004/08/17
++ */
 +
-+      np->loopback_dev     = lo;
++/*! \cidoxg_include_ci_compat  */
++#ifndef __CI_COMPAT_X86_64_H__
++#define __CI_COMPAT_X86_64_H__
 +
-+      dev->open            = loopback_open;
-+      dev->stop            = loopback_close;
-+      dev->hard_start_xmit = loopback_start_xmit;
-+      dev->get_stats       = loopback_get_stats;
-+      dev->set_multicast_list = loopback_set_multicast_list;
-+      dev->change_mtu      = NULL; /* allow arbitrary mtu */
 +
-+      dev->tx_queue_len    = 0;
++#define CI_MY_BYTE_ORDER      CI_LITTLE_ENDIAN
 +
-+      dev->features        = (NETIF_F_HIGHDMA |
-+                              NETIF_F_LLTX |
-+                              NETIF_F_TSO |
-+                              NETIF_F_SG |
-+                              NETIF_F_IP_CSUM);
++#define CI_WORD_SIZE          8
++#define CI_PTR_SIZE           8
 +
-+      SET_ETHTOOL_OPS(dev, &network_ethtool_ops);
++#define CI_PAGE_SIZE          4096
++#define CI_PAGE_SHIFT         12
++#define CI_PAGE_MASK          (~(CI_PAGE_SIZE - 1))
 +
-+      /*
-+       * We do not set a jumbo MTU on the interface. Otherwise the network
-+       * stack will try to send large packets that will get dropped by the
-+       * Ethernet bridge (unless the physical Ethernet interface is
-+       * configured to transfer jumbo packets). If a larger MTU is desired
-+       * then the system administrator can specify it using the 'ifconfig'
-+       * command.
-+       */
-+      /*dev->mtu             = 16*1024;*/
-+}
++#define CI_CPU_HAS_SSE                1       /* SSE extensions supported */
 +
-+static int __init make_loopback(int i)
-+{
-+      struct net_device *dev1, *dev2;
-+      char dev_name[IFNAMSIZ];
-+      int err = -ENOMEM;
++/* SSE2 disabled while investigating BUG1060 */
++#define CI_CPU_HAS_SSE2               0       /* SSE2 extensions supported */
++#define CI_CPU_OOS            0       /* CPU does out of order stores */
 +
-+      sprintf(dev_name, "vif0.%d", i);
-+      dev1 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup);
-+      if (!dev1)
-+              return err;
 +
-+      sprintf(dev_name, "veth%d", i);
-+      dev2 = alloc_netdev(sizeof(struct net_private), dev_name, ether_setup);
-+      if (!dev2)
-+              goto fail_netdev2;
++#endif  /* __CI_COMPAT_X86_64_H__ */
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/compat.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/compat.h    2008-05-19 00:33:47.278871329 +0300
+@@ -0,0 +1,53 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      loopback_construct(dev1, dev2);
-+      loopback_construct(dev2, dev1);
++/*
++ * \author  djr
++ *  \brief  Compatability layer.  Provides definitions of fundamental
++ *          types and definitions that are used throughout CI source
++ *          code.  It does not introduce any link time dependencies,
++ *          or include any unnecessary system headers.
++ */
++/*! \cidoxg_include_ci */
 +
-+      /*
-+       * Initialise a dummy MAC address for the 'dummy backend' interface. We
-+       * choose the numerically largest non-broadcast address to prevent the
-+       * address getting stolen by an Ethernet bridge for STP purposes.
-+       */
-+      memset(dev1->dev_addr, 0xFF, ETH_ALEN);
-+      dev1->dev_addr[0] &= ~0x01;
++#ifndef __CI_COMPAT_H__
++#define __CI_COMPAT_H__
 +
-+      if ((err = register_netdev(dev1)) != 0)
-+              goto fail;
++#ifdef __cplusplus
++extern "C" {
++#endif
 +
-+      if ((err = register_netdev(dev2)) != 0) {
-+              unregister_netdev(dev1);
-+              goto fail;
-+      }
++#include <ci/compat/primitive.h>
++#include <ci/compat/sysdep.h>
++#include <ci/compat/utils.h>
 +
-+      return 0;
 +
-+ fail:
-+      free_netdev(dev2);
-+ fail_netdev2:
-+      free_netdev(dev1);
-+      return err;
++#ifdef __cplusplus
 +}
++#endif
 +
-+static void __exit clean_loopback(int i)
-+{
-+      struct net_device *dev1, *dev2;
-+      char dev_name[IFNAMSIZ];
++#endif  /* __CI_COMPAT_H__ */
 +
-+      sprintf(dev_name, "vif0.%d", i);
-+      dev1 = dev_get_by_name(dev_name);
-+      sprintf(dev_name, "veth%d", i);
-+      dev2 = dev_get_by_name(dev_name);
-+      if (dev1 && dev2) {
-+              unregister_netdev(dev2);
-+              unregister_netdev(dev1);
-+              free_netdev(dev2);
-+              free_netdev(dev1);
-+      }
-+}
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/driver/resource/efx_vi.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/driver/resource/efx_vi.h    2008-05-19 00:33:47.926908682 +0300
+@@ -0,0 +1,276 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file contains public EFX VI API to Solarflare resource manager.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static int __init loopback_init(void)
-+{
-+      int i, err = 0;
++#ifndef __CI_DRIVER_RESOURCE_EFX_VI_H__
++#define __CI_DRIVER_RESOURCE_EFX_VI_H__
 +
-+      if (nloopbacks == -1)
-+              nloopbacks = is_initial_xendomain() ? 4 : 0;
++/* Default size of event queue in the efx_vi resource.  Copied from
++ * CI_CFG_NETIF_EVENTQ_SIZE */
++#define EFX_VI_EVENTQ_SIZE_DEFAULT 1024
 +
-+      for (i = 0; i < nloopbacks; i++)
-+              if ((err = make_loopback(i)) != 0)
-+                      break;
++extern int efx_vi_eventq_size;
 +
-+      return err;
-+}
++/**************************************************************************
++ * efx_vi_state types, allocation and free
++ **************************************************************************/
 +
-+module_init(loopback_init);
++/*! Handle for refering to a efx_vi */
++struct efx_vi_state;
 +
-+static void __exit loopback_exit(void)
-+{
-+      int i;
++/*!
++ * Allocate an efx_vi, including event queue and pt_endpoint
++ *
++ * \param vih_out Pointer to a handle that is set on success
++ * \param nic_index Index of NIC to apply this resource to
++ * \return Zero on success (and vih_out set), non-zero on failure.
++ */
++extern int
++efx_vi_alloc(struct efx_vi_state **vih_out, int nic_index);
 +
-+      for (i = nloopbacks; i-- > 0; )
-+              clean_loopback(i);
-+}
++/*!
++ * Free a previously allocated efx_vi
++ *
++ * \param vih The handle of the efx_vi to free
++ */
++extern void
++efx_vi_free(struct efx_vi_state *vih);
 +
-+module_exit(loopback_exit);
++/*!
++ * Reset a previously allocated efx_vi
++ *
++ * \param vih The handle of the efx_vi to reset
++ */
++extern void
++efx_vi_reset(struct efx_vi_state *vih);
 +
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/netback/Makefile linux-2.6.18-xen.hg/drivers/xen/netback/Makefile
---- linux-2.6.18/drivers/xen/netback/Makefile  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/netback/Makefile   2007-12-23 11:15:34.051268764 +0100
-@@ -0,0 +1,5 @@
-+obj-$(CONFIG_XEN_NETDEV_BACKEND) := netbk.o
-+obj-$(CONFIG_XEN_NETDEV_LOOPBACK) += netloop.o
++/**************************************************************************
++ * efx_vi_eventq types and functions
++ **************************************************************************/
 +
-+netbk-y   := netback.o xenbus.o interface.o accel.o
-+netloop-y := loopback.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/netback/netback.c linux-2.6.18-xen.hg/drivers/xen/netback/netback.c
---- linux-2.6.18/drivers/xen/netback/netback.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/netback/netback.c  2007-12-23 11:15:34.054602273 +0100
-@@ -0,0 +1,1608 @@
-+/******************************************************************************
-+ * drivers/xen/netback/netback.c
-+ * 
-+ * Back-end of the driver for virtual network devices. This portion of the
-+ * driver exports a 'unified' network-device interface that can be accessed
-+ * by any operating system that implements a compatible front end. A 
-+ * reference front-end implementation can be found in:
-+ *  drivers/xen/netfront/netfront.c
-+ * 
-+ * Copyright (c) 2002-2005, K A Fraser
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++/*!
++ * Register a function to receive callbacks when event queue timeouts
++ * or wakeups occur.  Only one function per efx_vi can be registered
++ * at once.
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param callback The function to callback
++ * \param context An argument to pass to the callback function
++ * \return Zero on success, non-zero on failure.
 + */
++extern int
++efx_vi_eventq_register_callback(struct efx_vi_state *vih,
++                              void (*callback)(void *context, int is_timeout),
++                              void *context);
 +
-+#include "common.h"
-+#include <xen/balloon.h>
-+#include <xen/interface/memory.h>
++/*!
++ * Remove the current eventq timeout or wakeup callback function
++ *
++ * \param vih The handle to identify the efx_vi
++ * \return Zero on success, non-zero on failure
++ */
++extern int
++efx_vi_eventq_kill_callback(struct efx_vi_state *vih);
 +
-+/*define NETBE_DEBUG_INTERRUPT*/
++/**************************************************************************
++ * efx_vi_dma_map types and functions
++ **************************************************************************/
 +
-+/* extra field used in struct page */
-+#define netif_page_index(pg) (*(long *)&(pg)->mapping)
++/*!
++ * Handle for refering to a efx_vi
++ */
++struct efx_vi_dma_map_state;
 +
-+struct netbk_rx_meta {
-+      skb_frag_t frag;
-+      int id;
-+      u8 copy:1;
-+};
++/*!
++ * Map a list of buffer pages so they are registered with the hardware
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param addrs An array of page pointers to map
++ * \param n_addrs Length of the page pointer array.  Must be a power of two.
++ * \param dmh_out Set on success to a handle used to refer to this mapping
++ * \return Zero on success, non-zero on failure.
++ */
++extern int
++efx_vi_dma_map_pages(struct efx_vi_state *vih, struct page **pages,
++                       int n_pages, struct efx_vi_dma_map_state **dmh_out);
++extern int
++efx_vi_dma_map_addrs(struct efx_vi_state *vih,
++                   unsigned long long *dev_bus_addrs, int n_pages,
++                   struct efx_vi_dma_map_state **dmh_out);
 +
-+struct netbk_tx_pending_inuse {
-+      struct list_head list;
-+      unsigned long alloc_time;
-+};
++/*!
++ * Unmap a previously mapped set of pages so they are no longer registered
++ * with the hardware.
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param dmh The handle to identify the dma mapping
++ */
++extern void
++efx_vi_dma_unmap_pages(struct efx_vi_state *vih,
++                     struct efx_vi_dma_map_state *dmh);
++extern void
++efx_vi_dma_unmap_addrs(struct efx_vi_state *vih,
++                     struct efx_vi_dma_map_state *dmh);
 +
-+static void netif_idx_release(u16 pending_idx);
-+static void netif_page_release(struct page *page);
-+static void make_tx_response(netif_t *netif, 
-+                           netif_tx_request_t *txp,
-+                           s8       st);
-+static netif_rx_response_t *make_rx_response(netif_t *netif, 
-+                                           u16      id, 
-+                                           s8       st,
-+                                           u16      offset,
-+                                           u16      size,
-+                                           u16      flags);
++/*!
++ * Retrieve the buffer address of the mapping
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param dmh The handle to identify the buffer mapping
++ * \return The buffer address on success, or zero on failure
++ */
++extern unsigned
++efx_vi_dma_get_map_addr(struct efx_vi_state *vih,
++                      struct efx_vi_dma_map_state *dmh);
 +
-+static void net_tx_action(unsigned long unused);
-+static DECLARE_TASKLET(net_tx_tasklet, net_tx_action, 0);
++/**************************************************************************
++ * efx_vi filter functions
++ **************************************************************************/
 +
-+static void net_rx_action(unsigned long unused);
-+static DECLARE_TASKLET(net_rx_tasklet, net_rx_action, 0);
++#define EFX_VI_STATIC_FILTERS 32
 +
-+static struct timer_list net_timer;
-+static struct timer_list netbk_tx_pending_timer;
++/*! Handle to refer to a filter instance */
++struct filter_resource_t;
 +
-+#define MAX_PENDING_REQS 256
++/*!
++ * Allocate and add a filter
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param protocol The protocol of the new filter: UDP or TCP
++ * \param ip_addr_be32 The local ip address of the filter
++ * \param port_le16 The local port of the filter
++ * \param fh_out Set on success to be a handle to refer to this filter
++ * \return Zero on success, non-zero on failure.
++ */
++extern int
++efx_vi_filter(struct efx_vi_state *vih, int protocol, unsigned ip_addr_be32,
++            int port_le16, struct filter_resource_t **fh_out);
 +
-+static struct sk_buff_head rx_queue;
++/*!
++ * Remove a filter and free resources associated with it
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param fh The handle to identify the filter
++ * \return Zero on success, non-zero on failure
++ */
++extern int
++efx_vi_filter_stop(struct efx_vi_state *vih, struct filter_resource_t *fh);
++
++/**************************************************************************
++ * efx_vi hw resources types and functions
++ **************************************************************************/
++
++/*! Constants for the type field in efx_vi_hw_resource */
++#define EFX_VI_HW_RESOURCE_TXDMAQ    0x0      /* PFN of TX DMA Q */
++#define EFX_VI_HW_RESOURCE_RXDMAQ    0x1      /* PFN of RX DMA Q */
++#define EFX_VI_HW_RESOURCE_TXBELL    0x2      /* PFN of TX Doorbell (EF1) */
++#define EFX_VI_HW_RESOURCE_RXBELL    0x3      /* PFN of RX Doorbell (EF1) */
++#define EFX_VI_HW_RESOURCE_EVQTIMER  0x4      /* Address of event q timer */
++
++/* Address of event q pointer (EF1) */
++#define EFX_VI_HW_RESOURCE_EVQPTR    0x5
++/* Address of register pointer (Falcon A) */
++#define EFX_VI_HW_RESOURCE_EVQRPTR   0x6
++/* Offset of register pointer (Falcon B) */
++#define EFX_VI_HW_RESOURCE_EVQRPTR_OFFSET 0x7
++/* Address of mem KVA */
++#define EFX_VI_HW_RESOURCE_EVQMEMKVA 0x8
++/* PFN of doorbell page (Falcon) */
++#define EFX_VI_HW_RESOURCE_BELLPAGE  0x9
++
++/*! How large an array to allocate for the get_() functions - smaller
++  than the total number of constants as some are mutually exclusive */
++#define EFX_VI_HW_RESOURCE_MAXSIZE   0x7
++
++/*! Constants for the mem_type field in efx_vi_hw_resource */
++#define EFX_VI_HW_RESOURCE_IOBUFFER   0       /* Host memory */
++#define EFX_VI_HW_RESOURCE_PERIPHERAL 1       /* Card memory/registers */
++
++/*!
++ * Data structure providing information on a hardware resource mapping
++ */
++struct efx_vi_hw_resource {
++      u8 type;                /*!< What this resource represents */
++      u8 mem_type;            /*!< What type of memory is it in, eg,
++                               * host or iomem */
++      u8 more_to_follow;      /*!< Is this part of a multi-region resource */
++      u32 length;             /*!< Length of the resource in bytes */
++      unsigned long address;  /*!< Address of this resource */
++};
++
++/*!
++ * Metadata concerning the list of hardware resource mappings
++ */
++struct efx_vi_hw_resource_metadata {
++      int version;
++      int evq_order;
++      int evq_offs;
++      int evq_capacity;
++      int instance;
++      unsigned rx_capacity;
++      unsigned tx_capacity;
++      int nic_arch;
++      int nic_revision;
++      char nic_variant;
++};
++
++/*!
++ * Obtain a list of hardware resource mappings, using virtual addresses
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param mdata Pointer to a structure to receive the metadata
++ * \param hw_res_array An array to receive the list of hardware resources
++ * \param length The length of hw_res_array.  Updated on success to contain
++ * the number of entries in the supplied array that were used.
++ * \return Zero on success, non-zero on failure
++ */
++extern int
++efx_vi_hw_resource_get_virt(struct efx_vi_state *vih,
++                          struct efx_vi_hw_resource_metadata *mdata,
++                          struct efx_vi_hw_resource *hw_res_array,
++                          int *length);
 +
-+static struct page **mmap_pages;
-+static inline unsigned long idx_to_pfn(unsigned int idx)
-+{
-+      return page_to_pfn(mmap_pages[idx]);
-+}
++/*!
++ * Obtain a list of hardware resource mappings, using physical addresses
++ *
++ * \param vih The handle to identify the efx_vi
++ * \param mdata Pointer to a structure to receive the metadata
++ * \param hw_res_array An array to receive the list of hardware resources
++ * \param length The length of hw_res_array.  Updated on success to contain
++ * the number of entries in the supplied array that were used.
++ * \return Zero on success, non-zero on failure
++ */
++extern int
++efx_vi_hw_resource_get_phys(struct efx_vi_state *vih,
++                          struct efx_vi_hw_resource_metadata *mdata,
++                          struct efx_vi_hw_resource *hw_res_array,
++                          int *length);
++
++#endif /* __CI_DRIVER_RESOURCE_EFX_VI_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efhw/common.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efhw/common.h       2008-05-19 00:33:48.038915138 +0300
+@@ -0,0 +1,102 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides API of the efhw library which may be used both from
++ * the kernel and from the user-space code.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static inline unsigned long idx_to_kaddr(unsigned int idx)
-+{
-+      return (unsigned long)pfn_to_kaddr(idx_to_pfn(idx));
-+}
++#ifndef __CI_EFHW_COMMON_H__
++#define __CI_EFHW_COMMON_H__
 +
-+#define PKT_PROT_LEN 64
++#include <ci/efhw/common_sysdep.h>
 +
-+static struct pending_tx_info {
-+      netif_tx_request_t req;
-+      netif_t *netif;
-+} pending_tx_info[MAX_PENDING_REQS];
-+static u16 pending_ring[MAX_PENDING_REQS];
-+typedef unsigned int PEND_RING_IDX;
-+#define MASK_PEND_IDX(_i) ((_i)&(MAX_PENDING_REQS-1))
-+static PEND_RING_IDX pending_prod, pending_cons;
-+#define NR_PENDING_REQS (MAX_PENDING_REQS - pending_prod + pending_cons)
++enum efhw_arch {
++      EFHW_ARCH_FALCON,
++      EFHW_ARCH_SIENA,
++};
 +
-+/* Freed TX SKBs get batched on this ring before return to pending_ring. */
-+static u16 dealloc_ring[MAX_PENDING_REQS];
-+static PEND_RING_IDX dealloc_prod, dealloc_cons;
++typedef uint32_t efhw_buffer_addr_t;
++#define EFHW_BUFFER_ADDR_FMT  "[ba:%"PRIx32"]"
 +
-+/* Doubly-linked list of in-use pending entries. */
-+static struct netbk_tx_pending_inuse pending_inuse[MAX_PENDING_REQS];
-+static LIST_HEAD(pending_inuse_head);
++/*! Comment? */
++typedef union {
++      uint64_t u64;
++      struct {
++              uint32_t a;
++              uint32_t b;
++      } opaque;
++      struct {
++              uint32_t code;
++              uint32_t status;
++      } ev1002;
++} efhw_event_t;
++
++/* Flags for TX/RX queues */
++#define EFHW_VI_JUMBO_EN           0x01  /*! scatter RX over multiple desc */
++#define EFHW_VI_ISCSI_RX_HDIG_EN   0x02  /*! iscsi rx header digest */
++#define EFHW_VI_ISCSI_TX_HDIG_EN   0x04  /*! iscsi tx header digest */
++#define EFHW_VI_ISCSI_RX_DDIG_EN   0x08  /*! iscsi rx data digest */
++#define EFHW_VI_ISCSI_TX_DDIG_EN   0x10  /*! iscsi tx data digest */
++#define EFHW_VI_TX_PHYS_ADDR_EN    0x20  /*! TX physical address mode */
++#define EFHW_VI_RX_PHYS_ADDR_EN    0x40  /*! RX physical address mode */
++#define EFHW_VI_RM_WITH_INTERRUPT  0x80  /*! VI with an interrupt */
++#define EFHW_VI_TX_IP_CSUM_DIS     0x100 /*! enable ip checksum generation */
++#define EFHW_VI_TX_TCPUDP_CSUM_DIS 0x200 /*! enable tcp/udp checksum
++                                         generation */
++#define EFHW_VI_TX_TCPUDP_ONLY     0x400 /*! drop non-tcp/udp packets */
++
++/* Types of hardware filter */
++/* Each of these values implicitly selects scatter filters on B0 - or in
++   EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK if a non-scatter filter is required */
++#define EFHW_IP_FILTER_TYPE_UDP_WILDCARD  (0) /* dest host only */
++#define EFHW_IP_FILTER_TYPE_UDP_FULL      (1) /* dest host and port */
++#define EFHW_IP_FILTER_TYPE_TCP_WILDCARD  (2) /* dest based filter */
++#define EFHW_IP_FILTER_TYPE_TCP_FULL      (3) /* src  filter */
++/* Same again, but with RSS (for B0 only) */
++#define EFHW_IP_FILTER_TYPE_UDP_WILDCARD_RSS_B0  (4)
++#define EFHW_IP_FILTER_TYPE_UDP_FULL_RSS_B0      (5)
++#define EFHW_IP_FILTER_TYPE_TCP_WILDCARD_RSS_B0  (6)
++#define EFHW_IP_FILTER_TYPE_TCP_FULL_RSS_B0      (7)
++
++#define EFHW_IP_FILTER_TYPE_FULL_MASK      (0x1) /* Mask for full / wildcard */
++#define EFHW_IP_FILTER_TYPE_TCP_MASK       (0x2) /* Mask for TCP type */
++#define EFHW_IP_FILTER_TYPE_RSS_B0_MASK    (0x4) /* Mask for B0 RSS enable */
++#define EFHW_IP_FILTER_TYPE_NOSCAT_B0_MASK (0x8) /* Mask for B0 SCATTER dsbl */
++
++#define EFHW_IP_FILTER_TYPE_MASK      (0xffff) /* Mask of types above */
++
++#define EFHW_IP_FILTER_BROADCAST      (0x10000) /* driverlink filter
++                                                   support */
++
++#endif /* __CI_EFHW_COMMON_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efhw/common_sysdep.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efhw/common_sysdep.h        2008-05-19 00:33:48.054916061 +0300
+@@ -0,0 +1,67 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides version-independent Linux kernel API for
++ * userland-to-kernel interfaces.
++ * Only kernels >=2.6.9 are supported.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static struct sk_buff_head tx_queue;
++#ifndef __CI_EFHW_COMMON_LINUX_H__
++#define __CI_EFHW_COMMON_LINUX_H__
 +
-+static grant_handle_t grant_tx_handle[MAX_PENDING_REQS];
-+static gnttab_unmap_grant_ref_t tx_unmap_ops[MAX_PENDING_REQS];
-+static gnttab_map_grant_ref_t tx_map_ops[MAX_PENDING_REQS];
++#include <linux/types.h>
++#include <linux/version.h>
 +
-+static struct list_head net_schedule_list;
-+static spinlock_t net_schedule_list_lock;
++/* Dirty hack, but Linux kernel does not provide DMA_ADDR_T_FMT */
++#if BITS_PER_LONG == 64 || defined(CONFIG_HIGHMEM64G)
++#define DMA_ADDR_T_FMT "%llx"
++#else
++#define DMA_ADDR_T_FMT "%x"
++#endif
 +
-+#define MAX_MFN_ALLOC 64
-+static unsigned long mfn_list[MAX_MFN_ALLOC];
-+static unsigned int alloc_index = 0;
++/* Linux kernel also does not provide PRIx32... Sigh. */
++#define PRIx32 "x"
++#define PRIx64 "llx"
 +
-+/* Setting this allows the safe use of this driver without netloop. */
-+static int MODPARM_copy_skb = 1;
-+module_param_named(copy_skb, MODPARM_copy_skb, bool, 0);
-+MODULE_PARM_DESC(copy_skb, "Copy data received from netfront without netloop");
 +
-+int netbk_copy_skb_mode;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
++enum {
++      false = 0,
++      true = 1
++};
 +
-+static inline unsigned long alloc_mfn(void)
-+{
-+      BUG_ON(alloc_index == 0);
-+      return mfn_list[--alloc_index];
-+}
++typedef _Bool bool;
++#endif /* LINUX_VERSION_CODE < 2.6.19 */
 +
-+static int check_mfn(int nr)
-+{
-+      struct xen_memory_reservation reservation = {
-+              .extent_order = 0,
-+              .domid        = DOMID_SELF
-+      };
++#endif /* __CI_EFHW_COMMON_LINUX_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efhw/debug.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efhw/debug.h        2008-05-19 00:33:48.054916061 +0300
+@@ -0,0 +1,84 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides debug-related API for efhw library using Linux kernel
++ * primitives.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      if (likely(alloc_index >= nr))
-+              return 0;
++#ifndef __CI_EFHW_DEBUG_LINUX_H__
++#define __CI_EFHW_DEBUG_LINUX_H__
 +
-+      set_xen_guest_handle(reservation.extent_start, mfn_list + alloc_index);
-+      reservation.nr_extents = MAX_MFN_ALLOC - alloc_index;
-+      alloc_index += HYPERVISOR_memory_op(XENMEM_increase_reservation,
-+                                          &reservation);
++#define EFHW_PRINTK_PREFIX "[sfc efhw] "
 +
-+      return alloc_index >= nr ? 0 : -ENOMEM;
-+}
++#define EFHW_PRINTK(level, fmt, ...) \
++      printk(level EFHW_PRINTK_PREFIX fmt "\n", __VA_ARGS__)
 +
-+static inline void maybe_schedule_tx_action(void)
-+{
-+      smp_mb();
-+      if ((NR_PENDING_REQS < (MAX_PENDING_REQS/2)) &&
-+          !list_empty(&net_schedule_list))
-+              tasklet_schedule(&net_tx_tasklet);
-+}
++/* Following macros should be used with non-zero format parameters
++ * due to __VA_ARGS__ limitations.  Use "%s" with __FUNCTION__ if you can't
++ * find better parameters. */
++#define EFHW_ERR(fmt, ...)     EFHW_PRINTK(KERN_ERR, fmt, __VA_ARGS__)
++#define EFHW_WARN(fmt, ...)    EFHW_PRINTK(KERN_WARNING, fmt, __VA_ARGS__)
++#define EFHW_NOTICE(fmt, ...)  EFHW_PRINTK(KERN_NOTICE, fmt, __VA_ARGS__)
++#if 0 && !defined(NDEBUG)
++#define EFHW_TRACE(fmt, ...) EFHW_PRINTK(KERN_DEBUG, fmt, __VA_ARGS__)
++#else
++#define EFHW_TRACE(fmt, ...)
++#endif
 +
-+static struct sk_buff *netbk_copy_skb(struct sk_buff *skb)
-+{
-+      struct skb_shared_info *ninfo;
-+      struct sk_buff *nskb;
-+      unsigned long offset;
-+      int ret;
-+      int len;
-+      int headlen;
++#ifndef NDEBUG
++#define EFHW_ASSERT(cond)  BUG_ON((cond) == 0)
++#define EFHW_DO_DEBUG(expr) expr
++#else
++#define EFHW_ASSERT(cond)
++#define EFHW_DO_DEBUG(expr)
++#endif
 +
-+      BUG_ON(skb_shinfo(skb)->frag_list != NULL);
++#define EFHW_TEST(expr)                       \
++      do {                            \
++              if (unlikely(!(expr)))  \
++              BUG();                  \
++      } while (0)
 +
-+      nskb = alloc_skb(SKB_MAX_HEAD(0), GFP_ATOMIC | __GFP_NOWARN);
-+      if (unlikely(!nskb))
-+              goto err;
++/* Build time asserts. We paste the line number into the type name
++ * so that the macro can be used more than once per file even if the
++ * compiler objects to multiple identical typedefs. Collisions
++ * between use in different header files is still possible. */
++#ifndef EFHW_BUILD_ASSERT
++#define __EFHW_BUILD_ASSERT_NAME(_x) __EFHW_BUILD_ASSERT_ILOATHECPP(_x)
++#define __EFHW_BUILD_ASSERT_ILOATHECPP(_x)  __EFHW_BUILD_ASSERT__ ##_x
++#define EFHW_BUILD_ASSERT(e) \
++      typedef char __EFHW_BUILD_ASSERT_NAME(__LINE__)[(e) ? 1 : -1]
++#endif
 +
-+      skb_reserve(nskb, 16 + NET_IP_ALIGN);
-+      headlen = nskb->end - nskb->data;
-+      if (headlen > skb_headlen(skb))
-+              headlen = skb_headlen(skb);
-+      ret = skb_copy_bits(skb, 0, __skb_put(nskb, headlen), headlen);
-+      BUG_ON(ret);
++#endif /* __CI_EFHW_DEBUG_LINUX_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efhw/efhw_config.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efhw/efhw_config.h  2008-05-19 00:33:48.054916061 +0300
+@@ -0,0 +1,43 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides some limits used in both kernel and userland code.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      ninfo = skb_shinfo(nskb);
-+      ninfo->gso_size = skb_shinfo(skb)->gso_size;
-+      ninfo->gso_type = skb_shinfo(skb)->gso_type;
++#ifndef __CI_EFHW_EFAB_CONFIG_H__
++#define __CI_EFHW_EFAB_CONFIG_H__
 +
-+      offset = headlen;
-+      len = skb->len - headlen;
++#define EFHW_MAX_NR_DEVS 5    /* max number of efhw devices supported */
 +
-+      nskb->len = skb->len;
-+      nskb->data_len = len;
-+      nskb->truesize += len;
++#endif /* __CI_EFHW_EFAB_CONFIG_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efhw/efhw_types.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efhw/efhw_types.h   2008-05-19 00:33:48.058916291 +0300
+@@ -0,0 +1,342 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides struct efhw_nic and some related types.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      while (len) {
-+              struct page *page;
-+              int copy;
-+              int zero;
++#ifndef __CI_EFHW_EFAB_TYPES_H__
++#define __CI_EFHW_EFAB_TYPES_H__
 +
-+              if (unlikely(ninfo->nr_frags >= MAX_SKB_FRAGS)) {
-+                      dump_stack();
-+                      goto err_free;
-+              }
++#include <ci/efhw/efhw_config.h>
++#include <ci/efhw/hardware_sysdep.h>
++#include <ci/efhw/iopage_types.h>
++#include <ci/efhw/sysdep.h>
 +
-+              copy = len >= PAGE_SIZE ? PAGE_SIZE : len;
-+              zero = len >= PAGE_SIZE ? 0 : __GFP_ZERO;
++/*--------------------------------------------------------------------
++ *
++ * hardware limits used in the types
++ *
++ *--------------------------------------------------------------------*/
 +
-+              page = alloc_page(GFP_ATOMIC | __GFP_NOWARN | zero);
-+              if (unlikely(!page))
-+                      goto err_free;
++#define EFHW_KEVENTQ_MAX    8
 +
-+              ret = skb_copy_bits(skb, offset, page_address(page), copy);
-+              BUG_ON(ret);
++/*--------------------------------------------------------------------
++ *
++ * forward type declarations
++ *
++ *--------------------------------------------------------------------*/
 +
-+              ninfo->frags[ninfo->nr_frags].page = page;
-+              ninfo->frags[ninfo->nr_frags].page_offset = 0;
-+              ninfo->frags[ninfo->nr_frags].size = copy;
-+              ninfo->nr_frags++;
++struct efhw_nic;
 +
-+              offset += copy;
-+              len -= copy;
-+      }
++/*--------------------------------------------------------------------
++ *
++ * Managed interface
++ *
++ *--------------------------------------------------------------------*/
 +
-+      offset = nskb->data - skb->data;
++struct efhw_buffer_table_allocation{
++      unsigned base;
++      unsigned order;
++};
 +
-+      nskb->h.raw = skb->h.raw + offset;
-+      nskb->nh.raw = skb->nh.raw + offset;
-+      nskb->mac.raw = skb->mac.raw + offset;
++struct eventq_resource_hardware {
++      /*!iobuffer allocated for eventq - can be larger than eventq */
++      efhw_iopages_t iobuff;
++      unsigned iobuff_off;
++      struct efhw_buffer_table_allocation buf_tbl_alloc;
++      int capacity;           /*!< capacity of event queue */
++};
 +
-+      return nskb;
++/*--------------------------------------------------------------------
++ *
++ * event queues and event driven callbacks
++ *
++ *--------------------------------------------------------------------*/
 +
-+ err_free:
-+      kfree_skb(nskb);
-+ err:
-+      return NULL;
-+}
++struct efhw_keventq {
++      volatile int lock;
++      caddr_t evq_base;
++      int32_t evq_ptr;
++      uint32_t evq_mask;
++      unsigned instance;
++      struct eventq_resource_hardware hw;
++      struct efhw_ev_handler *ev_handlers;
++};
 +
-+static inline int netbk_max_required_rx_slots(netif_t *netif)
-+{
-+      if (netif->features & (NETIF_F_SG|NETIF_F_TSO))
-+              return MAX_SKB_FRAGS + 2; /* header + extra_info + frags */
-+      return 1; /* all in one */
-+}
++/**********************************************************************
++ * Portable HW interface. ***************************************
++ **********************************************************************/
 +
-+static inline int netbk_queue_full(netif_t *netif)
-+{
-+      RING_IDX peek   = netif->rx_req_cons_peek;
-+      RING_IDX needed = netbk_max_required_rx_slots(netif);
++/*--------------------------------------------------------------------
++ *
++ * EtherFabric Functional units - configuration and control
++ *
++ *--------------------------------------------------------------------*/
 +
-+      return ((netif->rx.sring->req_prod - peek) < needed) ||
-+             ((netif->rx.rsp_prod_pvt + NET_RX_RING_SIZE - peek) < needed);
-+}
++struct efhw_func_ops {
 +
-+static void tx_queue_callback(unsigned long data)
-+{
-+      netif_t *netif = (netif_t *)data;
-+      if (netif_schedulable(netif))
-+              netif_wake_queue(netif->dev);
-+}
++  /*-------------- Initialisation ------------ */
 +
-+int netif_be_start_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+      netif_t *netif = netdev_priv(dev);
++      /*! close down all hardware functional units - leaves NIC in a safe
++         state for driver unload */
++      void (*close_hardware) (struct efhw_nic *nic);
 +
-+      BUG_ON(skb->dev != dev);
++      /*! initialise all hardware functional units */
++      int (*init_hardware) (struct efhw_nic *nic,
++                            struct efhw_ev_handler *,
++                            const uint8_t *mac_addr);
 +
-+      /* Drop the packet if the target domain has no receive buffers. */
-+      if (unlikely(!netif_schedulable(netif) || netbk_queue_full(netif)))
-+              goto drop;
++  /*-------------- Interrupt support  ------------ */
 +
-+      /*
-+       * Copy the packet here if it's destined for a flipping interface
-+       * but isn't flippable (e.g. extra references to data).
-+       * XXX For now we also copy skbuffs whose head crosses a page
-+       * boundary, because netbk_gop_skb can't handle them.
++      /*! Main interrupt routine
++       **        This function returns,
++       **  - zero,       if the IRQ was not generated by EF1
++       **  - non-zero,   if EF1 was the source of the IRQ
++       **
++       **
++       ** opaque is an OS provided pointer for use by the OS callbacks
++       ** e.g in Windows used to indicate DPC scheduled
 +       */
-+      if (!netif->copying_receiver ||
-+          ((skb_headlen(skb) + offset_in_page(skb->data)) >= PAGE_SIZE)) {
-+              struct sk_buff *nskb = netbk_copy_skb(skb);
-+              if ( unlikely(nskb == NULL) )
-+                      goto drop;
-+              /* Copy only the header fields we use in this driver. */
-+              nskb->dev = skb->dev;
-+              nskb->ip_summed = skb->ip_summed;
-+              nskb->proto_data_valid = skb->proto_data_valid;
-+              dev_kfree_skb(skb);
-+              skb = nskb;
-+      }
-+
-+      netif->rx_req_cons_peek += skb_shinfo(skb)->nr_frags + 1 +
-+                                 !!skb_shinfo(skb)->gso_size;
-+      netif_get(netif);
-+
-+      if (netbk_can_queue(dev) && netbk_queue_full(netif)) {
-+              netif->rx.sring->req_event = netif->rx_req_cons_peek +
-+                      netbk_max_required_rx_slots(netif);
-+              mb(); /* request notification /then/ check & stop the queue */
-+              if (netbk_queue_full(netif)) {
-+                      netif_stop_queue(dev);
-+                      /*
-+                       * Schedule 500ms timeout to restart the queue, thus
-+                       * ensuring that an inactive queue will be drained.
-+                       * Packets will be immediately be dropped until more
-+                       * receive buffers become available (see
-+                       * netbk_queue_full() check above).
-+                       */
-+                      netif->tx_queue_timeout.data = (unsigned long)netif;
-+                      netif->tx_queue_timeout.function = tx_queue_callback;
-+                      __mod_timer(&netif->tx_queue_timeout, jiffies + HZ/2);
-+              }
-+      }
-+
-+      skb_queue_tail(&rx_queue, skb);
-+      tasklet_schedule(&net_rx_tasklet);
-+
-+      return 0;
++      int (*interrupt) (struct efhw_nic *nic);
 +
-+ drop:
-+      netif->stats.tx_dropped++;
-+      dev_kfree_skb(skb);
-+      return 0;
-+}
++      /*! Enable given interrupt mask for the given IRQ unit */
++      void (*interrupt_enable) (struct efhw_nic *nic, uint idx);
 +
-+#if 0
-+static void xen_network_done_notify(void)
-+{
-+      static struct net_device *eth0_dev = NULL;
-+      if (unlikely(eth0_dev == NULL))
-+              eth0_dev = __dev_get_by_name("eth0");
-+      netif_rx_schedule(eth0_dev);
-+}
-+/* 
-+ * Add following to poll() function in NAPI driver (Tigon3 is example):
-+ *  if ( xen_network_done() )
-+ *      tg3_enable_ints(tp);
-+ */
-+int xen_network_done(void)
-+{
-+      return skb_queue_empty(&rx_queue);
-+}
-+#endif
++      /*! Disable given interrupt mask for the given IRQ unit */
++      void (*interrupt_disable) (struct efhw_nic *nic, uint idx);
 +
-+struct netrx_pending_operations {
-+      unsigned trans_prod, trans_cons;
-+      unsigned mmu_prod, mmu_cons;
-+      unsigned mcl_prod, mcl_cons;
-+      unsigned copy_prod, copy_cons;
-+      unsigned meta_prod, meta_cons;
-+      mmu_update_t *mmu;
-+      gnttab_transfer_t *trans;
-+      gnttab_copy_t *copy;
-+      multicall_entry_t *mcl;
-+      struct netbk_rx_meta *meta;
-+};
++      /*! Set interrupt moderation strategy for the given IRQ unit
++       ** val is in usec
++       */
++      void (*set_interrupt_moderation)(struct efhw_nic *nic,
++                                       uint idx, uint val);
 +
-+/* Set up the grant operations for this fragment.  If it's a flipping
-+   interface, we also set up the unmap request from here. */
-+static u16 netbk_gop_frag(netif_t *netif, struct netbk_rx_meta *meta,
-+                        int i, struct netrx_pending_operations *npo,
-+                        struct page *page, unsigned long size,
-+                        unsigned long offset)
-+{
-+      mmu_update_t *mmu;
-+      gnttab_transfer_t *gop;
-+      gnttab_copy_t *copy_gop;
-+      multicall_entry_t *mcl;
-+      netif_rx_request_t *req;
-+      unsigned long old_mfn, new_mfn;
++  /*-------------- Event support  ------------ */
 +
-+      old_mfn = virt_to_mfn(page_address(page));
++      /*! Enable the given event queue
++         depending on the underlying implementation (EF1 or Falcon) then
++         either a q_base_addr in host memory, or a buffer base id should
++         be proivded
++       */
++      void (*event_queue_enable) (struct efhw_nic *nic,
++                                  uint evq,   /* evnt queue index */
++                                  uint evq_size,      /* units of #entries */
++                                  dma_addr_t q_base_addr, uint buf_base_id);
 +
-+      req = RING_GET_REQUEST(&netif->rx, netif->rx.req_cons + i);
-+      if (netif->copying_receiver) {
-+              /* The fragment needs to be copied rather than
-+                 flipped. */
-+              meta->copy = 1;
-+              copy_gop = npo->copy + npo->copy_prod++;
-+              copy_gop->flags = GNTCOPY_dest_gref;
-+              if (PageForeign(page)) {
-+                      struct pending_tx_info *src_pend =
-+                              &pending_tx_info[netif_page_index(page)];
-+                      copy_gop->source.domid = src_pend->netif->domid;
-+                      copy_gop->source.u.ref = src_pend->req.gref;
-+                      copy_gop->flags |= GNTCOPY_source_gref;
-+              } else {
-+                      copy_gop->source.domid = DOMID_SELF;
-+                      copy_gop->source.u.gmfn = old_mfn;
-+              }
-+              copy_gop->source.offset = offset;
-+              copy_gop->dest.domid = netif->domid;
-+              copy_gop->dest.offset = 0;
-+              copy_gop->dest.u.ref = req->gref;
-+              copy_gop->len = size;
-+      } else {
-+              meta->copy = 0;
-+              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+                      new_mfn = alloc_mfn();
++      /*! Disable the given event queue (and any associated timer) */
++      void (*event_queue_disable) (struct efhw_nic *nic, uint evq,
++                                   int timer_only);
 +
-+                      /*
-+                       * Set the new P2M table entry before
-+                       * reassigning the old data page. Heed the
-+                       * comment in pgtable-2level.h:pte_page(). :-)
-+                       */
-+                      set_phys_to_machine(page_to_pfn(page), new_mfn);
++      /*! request wakeup from the NIC on a given event Q */
++      void (*wakeup_request) (struct efhw_nic *nic, dma_addr_t q_base_addr,
++                              int next_i, int evq);
 +
-+                      mcl = npo->mcl + npo->mcl_prod++;
-+                      MULTI_update_va_mapping(mcl,
-+                                           (unsigned long)page_address(page),
-+                                           pfn_pte_ma(new_mfn, PAGE_KERNEL),
-+                                           0);
++      /*! Push a SW event on a given eventQ */
++      void (*sw_event) (struct efhw_nic *nic, int data, int evq);
 +
-+                      mmu = npo->mmu + npo->mmu_prod++;
-+                      mmu->ptr = ((maddr_t)new_mfn << PAGE_SHIFT) |
-+                              MMU_MACHPHYS_UPDATE;
-+                      mmu->val = page_to_pfn(page);
-+              }
++  /*-------------- Filter support  ------------ */
 +
-+              gop = npo->trans + npo->trans_prod++;
-+              gop->mfn = old_mfn;
-+              gop->domid = netif->domid;
-+              gop->ref = req->gref;
-+      }
-+      return req->id;
-+}
++      /*! Setup a given filter - The software can request a filter_i,
++       * but some EtherFabric implementations will override with
++       * a more suitable index
++       */
++      int (*ipfilter_set) (struct efhw_nic *nic, int type,
++                           int *filter_i, int dmaq,
++                           unsigned saddr_be32, unsigned sport_be16,
++                           unsigned daddr_be32, unsigned dport_be16);
 +
-+static void netbk_gop_skb(struct sk_buff *skb,
-+                        struct netrx_pending_operations *npo)
-+{
-+      netif_t *netif = netdev_priv(skb->dev);
-+      int nr_frags = skb_shinfo(skb)->nr_frags;
-+      int i;
-+      int extra;
-+      struct netbk_rx_meta *head_meta, *meta;
++      /*! Attach a given filter to a DMAQ */
++      void (*ipfilter_attach) (struct efhw_nic *nic, int filter_idx,
++                               int dmaq_idx);
 +
-+      head_meta = npo->meta + npo->meta_prod++;
-+      head_meta->frag.page_offset = skb_shinfo(skb)->gso_type;
-+      head_meta->frag.size = skb_shinfo(skb)->gso_size;
-+      extra = !!head_meta->frag.size + 1;
++      /*! Detach a filter from its DMAQ */
++      void (*ipfilter_detach) (struct efhw_nic *nic, int filter_idx);
 +
-+      for (i = 0; i < nr_frags; i++) {
-+              meta = npo->meta + npo->meta_prod++;
-+              meta->frag = skb_shinfo(skb)->frags[i];
-+              meta->id = netbk_gop_frag(netif, meta, i + extra, npo,
-+                                        meta->frag.page,
-+                                        meta->frag.size,
-+                                        meta->frag.page_offset);
-+      }
++      /*! Clear down a given filter */
++      void (*ipfilter_clear) (struct efhw_nic *nic, int filter_idx);
 +
-+      /*
-+       * This must occur at the end to ensure that we don't trash skb_shinfo
-+       * until we're done. We know that the head doesn't cross a page
-+       * boundary because such packets get copied in netif_be_start_xmit.
-+       */
-+      head_meta->id = netbk_gop_frag(netif, head_meta, 0, npo,
-+                                     virt_to_page(skb->data),
-+                                     skb_headlen(skb),
-+                                     offset_in_page(skb->data));
++  /*-------------- DMA support  ------------ */
 +
-+      netif->rx.req_cons += nr_frags + extra;
-+}
++      /*! Initialise NIC state for a given TX DMAQ */
++      void (*dmaq_tx_q_init) (struct efhw_nic *nic,
++                              uint dmaq, uint evq, uint owner, uint tag,
++                              uint dmaq_size, uint buf_idx, uint flags);
 +
-+static inline void netbk_free_pages(int nr_frags, struct netbk_rx_meta *meta)
-+{
-+      int i;
++      /*! Initialise NIC state for a given RX DMAQ */
++      void (*dmaq_rx_q_init) (struct efhw_nic *nic,
++                              uint dmaq, uint evq, uint owner, uint tag,
++                              uint dmaq_size, uint buf_idx, uint flags);
 +
-+      for (i = 0; i < nr_frags; i++)
-+              put_page(meta[i].frag.page);
-+}
++      /*! Disable a given TX DMAQ */
++      void (*dmaq_tx_q_disable) (struct efhw_nic *nic, uint dmaq);
 +
-+/* This is a twin to netbk_gop_skb.  Assume that netbk_gop_skb was
-+   used to set up the operations on the top of
-+   netrx_pending_operations, which have since been done.  Check that
-+   they didn't give any errors and advance over them. */
-+static int netbk_check_gop(int nr_frags, domid_t domid,
-+                         struct netrx_pending_operations *npo)
-+{
-+      multicall_entry_t *mcl;
-+      gnttab_transfer_t *gop;
-+      gnttab_copy_t     *copy_op;
-+      int status = NETIF_RSP_OKAY;
-+      int i;
++      /*! Disable a given RX DMAQ */
++      void (*dmaq_rx_q_disable) (struct efhw_nic *nic, uint dmaq);
 +
-+      for (i = 0; i <= nr_frags; i++) {
-+              if (npo->meta[npo->meta_cons + i].copy) {
-+                      copy_op = npo->copy + npo->copy_cons++;
-+                      if (copy_op->status != GNTST_okay) {
-+                              DPRINTK("Bad status %d from copy to DOM%d.\n",
-+                                      copy_op->status, domid);
-+                              status = NETIF_RSP_ERROR;
-+                      }
-+              } else {
-+                      if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+                              mcl = npo->mcl + npo->mcl_cons++;
-+                              /* The update_va_mapping() must not fail. */
-+                              BUG_ON(mcl->result != 0);
-+                      }
++      /*! Flush a given TX DMA channel */
++      int (*flush_tx_dma_channel) (struct efhw_nic *nic, uint dmaq);
 +
-+                      gop = npo->trans + npo->trans_cons++;
-+                      /* Check the reassignment error code. */
-+                      if (gop->status != 0) {
-+                              DPRINTK("Bad status %d from grant transfer to DOM%u\n",
-+                                      gop->status, domid);
-+                              /*
-+                               * Page no longer belongs to us unless
-+                               * GNTST_bad_page, but that should be
-+                               * a fatal error anyway.
-+                               */
-+                              BUG_ON(gop->status == GNTST_bad_page);
-+                              status = NETIF_RSP_ERROR;
-+                      }
-+              }
-+      }
++      /*! Flush a given RX DMA channel */
++      int (*flush_rx_dma_channel) (struct efhw_nic *nic, uint dmaq);
 +
-+      return status;
-+}
++  /*-------------- Buffer table Support ------------ */
 +
-+static void netbk_add_frag_responses(netif_t *netif, int status,
-+                                   struct netbk_rx_meta *meta, int nr_frags)
-+{
-+      int i;
-+      unsigned long offset;
++      /*! Initialise a buffer table page */
++      void (*buffer_table_set) (struct efhw_nic *nic,
++                                dma_addr_t dma_addr,
++                                uint bufsz, uint region,
++                                int own_id, int buffer_id);
 +
-+      for (i = 0; i < nr_frags; i++) {
-+              int id = meta[i].id;
-+              int flags = (i == nr_frags - 1) ? 0 : NETRXF_more_data;
++      /*! Initialise a block of buffer table pages */
++      void (*buffer_table_set_n) (struct efhw_nic *nic, int buffer_id,
++                                  dma_addr_t dma_addr,
++                                  uint bufsz, uint region,
++                                  int n_pages, int own_id);
 +
-+              if (meta[i].copy)
-+                      offset = 0;
-+              else
-+                      offset = meta[i].frag.page_offset;
-+              make_rx_response(netif, id, status, offset,
-+                               meta[i].frag.size, flags);
-+      }
-+}
++      /*! Clear a block of buffer table pages */
++      void (*buffer_table_clear) (struct efhw_nic *nic, int buffer_id,
++                                  int num);
 +
-+static void net_rx_action(unsigned long unused)
-+{
-+      netif_t *netif = NULL;
-+      s8 status;
-+      u16 id, irq, flags;
-+      netif_rx_response_t *resp;
-+      multicall_entry_t *mcl;
-+      struct sk_buff_head rxq;
-+      struct sk_buff *skb;
-+      int notify_nr = 0;
-+      int ret;
-+      int nr_frags;
-+      int count;
-+      unsigned long offset;
++      /*! Commit a buffer table update  */
++      void (*buffer_table_commit) (struct efhw_nic *nic);
 +
-+      /*
-+       * Putting hundreds of bytes on the stack is considered rude.
-+       * Static works because a tasklet can only be on one CPU at any time.
-+       */
-+      static multicall_entry_t rx_mcl[NET_RX_RING_SIZE+3];
-+      static mmu_update_t rx_mmu[NET_RX_RING_SIZE];
-+      static gnttab_transfer_t grant_trans_op[NET_RX_RING_SIZE];
-+      static gnttab_copy_t grant_copy_op[NET_RX_RING_SIZE];
-+      static unsigned char rx_notify[NR_IRQS];
-+      static u16 notify_list[NET_RX_RING_SIZE];
-+      static struct netbk_rx_meta meta[NET_RX_RING_SIZE];
++};
 +
-+      struct netrx_pending_operations npo = {
-+              mmu: rx_mmu,
-+              trans: grant_trans_op,
-+              copy: grant_copy_op,
-+              mcl: rx_mcl,
-+              meta: meta};
 +
-+      skb_queue_head_init(&rxq);
++/*----------------------------------------------------------------------------
++ *
++ * NIC type
++ *
++ *---------------------------------------------------------------------------*/
 +
-+      count = 0;
++struct efhw_device_type {
++      int  arch;            /* enum efhw_arch */
++      char variant;         /* 'A', 'B', ... */
++      int  revision;        /* 0, 1, ... */
++};
 +
-+      while ((skb = skb_dequeue(&rx_queue)) != NULL) {
-+              nr_frags = skb_shinfo(skb)->nr_frags;
-+              *(int *)skb->cb = nr_frags;
 +
-+              if (!xen_feature(XENFEAT_auto_translated_physmap) &&
-+                  !((netif_t *)netdev_priv(skb->dev))->copying_receiver &&
-+                  check_mfn(nr_frags + 1)) {
-+                      /* Memory squeeze? Back off for an arbitrary while. */
-+                      if ( net_ratelimit() )
-+                              WPRINTK("Memory squeeze in netback "
-+                                      "driver.\n");
-+                      mod_timer(&net_timer, jiffies + HZ);
-+                      skb_queue_head(&rx_queue, skb);
-+                      break;
-+              }
++/*----------------------------------------------------------------------------
++ *
++ * EtherFabric NIC instance - nic.c for HW independent functions
++ *
++ *---------------------------------------------------------------------------*/
 +
-+              netbk_gop_skb(skb, &npo);
++/*! */
++struct efhw_nic {
++      /*! zero base index in efrm_nic_table.nic array */
++      volatile int index;
++      int ifindex;            /*!< OS level nic index */
++#ifdef HAS_NET_NAMESPACE
++      struct net *nd_net;
++#endif
 +
-+              count += nr_frags + 1;
++      struct efhw_device_type devtype;
 +
-+              __skb_queue_tail(&rxq, skb);
++      /*! Options that can be set by user. */
++      unsigned options;
++# define NIC_OPT_EFTEST             0x1       /* owner is an eftest app */
 +
-+              /* Filled the batch queue? */
-+              if (count + MAX_SKB_FRAGS >= NET_RX_RING_SIZE)
-+                      break;
-+      }
++# define NIC_OPT_DEFAULT            0
 +
-+      if (npo.mcl_prod &&
-+          !xen_feature(XENFEAT_auto_translated_physmap)) {
-+              mcl = npo.mcl + npo.mcl_prod++;
++      /*! Internal flags that indicate hardware properties at runtime. */
++      unsigned flags;
++# define NIC_FLAG_NO_INTERRUPT          0x01 /* to be set at init time only */
++# define NIC_FLAG_TRY_MSI               0x02
++# define NIC_FLAG_MSI                   0x04
++# define NIC_FLAG_OS_IRQ_EN             0x08
++# define NIC_FLAG_10G                   0x10
 +
-+              BUG_ON(mcl[-1].op != __HYPERVISOR_update_va_mapping);
-+              mcl[-1].args[MULTI_UVMFLAGS_INDEX] = UVMF_TLB_FLUSH|UVMF_ALL;
++      unsigned mtu;           /*!< MAC MTU (includes MAC hdr) */
 +
-+              mcl->op = __HYPERVISOR_mmu_update;
-+              mcl->args[0] = (unsigned long)rx_mmu;
-+              mcl->args[1] = npo.mmu_prod;
-+              mcl->args[2] = 0;
-+              mcl->args[3] = DOMID_SELF;
-+      }
++      /* hardware resources */
 +
-+      if (npo.trans_prod) {
-+              mcl = npo.mcl + npo.mcl_prod++;
-+              mcl->op = __HYPERVISOR_grant_table_op;
-+              mcl->args[0] = GNTTABOP_transfer;
-+              mcl->args[1] = (unsigned long)grant_trans_op;
-+              mcl->args[2] = npo.trans_prod;
-+      }
++      /*! I/O address of the start of the bar */
++      efhw_ioaddr_t bar_ioaddr;
 +
-+      if (npo.copy_prod) {
-+              mcl = npo.mcl + npo.mcl_prod++;
-+              mcl->op = __HYPERVISOR_grant_table_op;
-+              mcl->args[0] = GNTTABOP_copy;
-+              mcl->args[1] = (unsigned long)grant_copy_op;
-+              mcl->args[2] = npo.copy_prod;
-+      }
++      /*! Bar number of control aperture. */
++      unsigned ctr_ap_bar;
++      /*! Length of control aperture in bytes. */
++      unsigned ctr_ap_bytes;
 +
-+      /* Nothing to do? */
-+      if (!npo.mcl_prod)
-+              return;
++      uint8_t mac_addr[ETH_ALEN];     /*!< mac address  */
 +
-+      BUG_ON(npo.copy_prod > NET_RX_RING_SIZE);
-+      BUG_ON(npo.mmu_prod > NET_RX_RING_SIZE);
-+      BUG_ON(npo.trans_prod > NET_RX_RING_SIZE);
-+      BUG_ON(npo.mcl_prod > NET_RX_RING_SIZE+3);
-+      BUG_ON(npo.meta_prod > NET_RX_RING_SIZE);
++      /*! EtherFabric Functional Units -- functions */
++      const struct efhw_func_ops *efhw_func;
 +
-+      ret = HYPERVISOR_multicall(npo.mcl, npo.mcl_prod);
-+      BUG_ON(ret != 0);
++      /* Value read from FPGA version register.  Zero for asic. */
++      unsigned fpga_version;
 +
-+      while ((skb = __skb_dequeue(&rxq)) != NULL) {
-+              nr_frags = *(int *)skb->cb;
++      /*! This lock protects a number of misc NIC resources.  It should
++       * only be used for things that can be at the bottom of the lock
++       * order.  ie. You mustn't attempt to grab any other lock while
++       * holding this one.
++       */
++      spinlock_t *reg_lock;
++      spinlock_t the_reg_lock;
 +
-+              netif = netdev_priv(skb->dev);
-+              /* We can't rely on skb_release_data to release the
-+                 pages used by fragments for us, since it tries to
-+                 touch the pages in the fraglist.  If we're in
-+                 flipping mode, that doesn't work.  In copying mode,
-+                 we still have access to all of the pages, and so
-+                 it's safe to let release_data deal with it. */
-+              /* (Freeing the fragments is safe since we copy
-+                 non-linear skbs destined for flipping interfaces) */
-+              if (!netif->copying_receiver) {
-+                      atomic_set(&(skb_shinfo(skb)->dataref), 1);
-+                      skb_shinfo(skb)->frag_list = NULL;
-+                      skb_shinfo(skb)->nr_frags = 0;
-+                      netbk_free_pages(nr_frags, meta + npo.meta_cons + 1);
-+              }
++      int buf_commit_outstanding;     /*!< outstanding buffer commits */
 +
-+              netif->stats.tx_bytes += skb->len;
-+              netif->stats.tx_packets++;
++      /*! interrupt callbacks (hard-irq) */
++      void (*irq_handler) (struct efhw_nic *, int unit);
 +
-+              status = netbk_check_gop(nr_frags, netif->domid, &npo);
++      /*! event queues per driver */
++      struct efhw_keventq evq[EFHW_KEVENTQ_MAX];
 +
-+              id = meta[npo.meta_cons].id;
-+              flags = nr_frags ? NETRXF_more_data : 0;
++/* for marking when we are not using an IRQ unit
++      - 0 is a valid offset to an IRQ unit on EF1! */
++#define EFHW_IRQ_UNIT_UNUSED  0xffff
++      /*! interrupt unit in use  */
++      unsigned int irq_unit[EFHW_KEVENTQ_MAX];
++      efhw_iopage_t irq_iobuff;       /*!<  Falcon SYSERR interrupt */
 +
-+              if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
-+                      flags |= NETRXF_csum_blank | NETRXF_data_validated;
-+              else if (skb->proto_data_valid) /* remote but checksummed? */
-+                      flags |= NETRXF_data_validated;
++      /* The new driverlink infrastructure. */
++      struct efx_dl_device *net_driver_dev;
++      struct efx_dlfilt_cb_s *dlfilter_cb;
 +
-+              if (meta[npo.meta_cons].copy)
-+                      offset = 0;
-+              else
-+                      offset = offset_in_page(skb->data);
-+              resp = make_rx_response(netif, id, status, offset,
-+                                      skb_headlen(skb), flags);
++      /*! Bit masks of the sizes of event queues and dma queues supported
++       * by the nic. */
++      unsigned evq_sizes;
++      unsigned rxq_sizes;
++      unsigned txq_sizes;
 +
-+              if (meta[npo.meta_cons].frag.size) {
-+                      struct netif_extra_info *gso =
-+                              (struct netif_extra_info *)
-+                              RING_GET_RESPONSE(&netif->rx,
-+                                                netif->rx.rsp_prod_pvt++);
++      /* Size of filter table (including odd and even banks). */
++      unsigned filter_tbl_size;
++};
 +
-+                      resp->flags |= NETRXF_extra_info;
 +
-+                      gso->u.gso.size = meta[npo.meta_cons].frag.size;
-+                      gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
-+                      gso->u.gso.pad = 0;
-+                      gso->u.gso.features = 0;
++#define EFHW_KVA(nic)       ((nic)->bar_ioaddr)
 +
-+                      gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
-+                      gso->flags = 0;
-+              }
 +
-+              netbk_add_frag_responses(netif, status,
-+                                       meta + npo.meta_cons + 1,
-+                                       nr_frags);
++#endif /* __CI_EFHW_EFHW_TYPES_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efhw/hardware_sysdep.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efhw/hardware_sysdep.h      2008-05-19 00:33:48.058916291 +0300
+@@ -0,0 +1,84 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides version-independent Linux kernel API for header files
++ * with hardware-related definitions (in ci/driver/efab/hardware*).
++ * Only kernels >=2.6.9 are supported.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+              RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->rx, ret);
-+              irq = netif->irq;
-+              if (ret && !rx_notify[irq]) {
-+                      rx_notify[irq] = 1;
-+                      notify_list[notify_nr++] = irq;
-+              }
++#ifndef __CI_EFHW_HARDWARE_LINUX_H__
++#define __CI_EFHW_HARDWARE_LINUX_H__
 +
-+              if (netif_queue_stopped(netif->dev) &&
-+                  netif_schedulable(netif) &&
-+                  !netbk_queue_full(netif))
-+                      netif_wake_queue(netif->dev);
++#include <asm/io.h>
 +
-+              netif_put(netif);
-+              dev_kfree_skb(skb);
-+              npo.meta_cons += nr_frags + 1;
-+      }
++#ifdef __LITTLE_ENDIAN
++#define EFHW_IS_LITTLE_ENDIAN
++#elif __BIG_ENDIAN
++#define EFHW_IS_BIG_ENDIAN
++#else
++#error Unknown endianness
++#endif
++
++#ifndef mmiowb
++      #if defined(__i386__) || defined(__x86_64__)
++              #define mmiowb()
++      #elif defined(__ia64__)
++              #ifndef ia64_mfa
++                      #define ia64_mfa() asm volatile ("mf.a" ::: "memory")
++              #endif
++      #define mmiowb ia64_mfa
++      #else
++      #error "Need definition for mmiowb()"
++      #endif
++#endif
 +
-+      while (notify_nr != 0) {
-+              irq = notify_list[--notify_nr];
-+              rx_notify[irq] = 0;
-+              notify_remote_via_irq(irq);
-+      }
++typedef char *efhw_ioaddr_t;
 +
-+      /* More work to do? */
-+      if (!skb_queue_empty(&rx_queue) && !timer_pending(&net_timer))
-+              tasklet_schedule(&net_rx_tasklet);
-+#if 0
-+      else
-+              xen_network_done_notify();
++#ifndef readq
++static inline uint64_t __readq(void __iomem *addr)
++{
++      return *(volatile uint64_t *)addr;
++}
++#define readq(x) __readq(x)
 +#endif
++
++#ifndef writeq
++static inline void __writeq(uint64_t v, void __iomem *addr)
++{
++      *(volatile uint64_t *)addr = v;
 +}
++#define writeq(val, addr) __writeq((val), (addr))
++#endif
 +
-+static void net_alarm(unsigned long unused)
++#endif /* __CI_EFHW_HARDWARE_LINUX_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efhw/iopage_types.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efhw/iopage_types.h 2008-05-19 00:33:48.058916291 +0300
+@@ -0,0 +1,188 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides efhw_page_t and efhw_iopage_t for Linux kernel.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFHW_IOPAGE_LINUX_H__
++#define __CI_EFHW_IOPAGE_LINUX_H__
++
++#include <linux/gfp.h>
++#include <linux/hardirq.h>
++#include <ci/efhw/debug.h>
++
++/*--------------------------------------------------------------------
++ *
++ * efhw_page_t: A single page of memory.  Directly mapped in the driver,
++ * and can be mapped to userlevel.
++ *
++ *--------------------------------------------------------------------*/
++
++typedef struct {
++      unsigned long kva;
++} efhw_page_t;
++
++static inline int efhw_page_alloc(efhw_page_t *p)
 +{
-+      tasklet_schedule(&net_rx_tasklet);
++      p->kva = __get_free_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL);
++      return p->kva ? 0 : -ENOMEM;
 +}
 +
-+static void netbk_tx_pending_timeout(unsigned long unused)
++static inline int efhw_page_alloc_zeroed(efhw_page_t *p)
 +{
-+      tasklet_schedule(&net_tx_tasklet);
++      p->kva = get_zeroed_page(in_interrupt()? GFP_ATOMIC : GFP_KERNEL);
++      return p->kva ? 0 : -ENOMEM;
 +}
 +
-+struct net_device_stats *netif_be_get_stats(struct net_device *dev)
++static inline void efhw_page_free(efhw_page_t *p)
 +{
-+      netif_t *netif = netdev_priv(dev);
-+      return &netif->stats;
++      free_page(p->kva);
++      EFHW_DO_DEBUG(memset(p, 0, sizeof(*p)));
 +}
 +
-+static int __on_net_schedule_list(netif_t *netif)
++static inline char *efhw_page_ptr(efhw_page_t *p)
 +{
-+      return netif->list.next != NULL;
++      return (char *)p->kva;
 +}
 +
-+static void remove_from_net_schedule_list(netif_t *netif)
++static inline unsigned efhw_page_pfn(efhw_page_t *p)
 +{
-+      spin_lock_irq(&net_schedule_list_lock);
-+      if (likely(__on_net_schedule_list(netif))) {
-+              list_del(&netif->list);
-+              netif->list.next = NULL;
-+              netif_put(netif);
-+      }
-+      spin_unlock_irq(&net_schedule_list_lock);
++      return (unsigned)(__pa(p->kva) >> PAGE_SHIFT);
 +}
 +
-+static void add_to_net_schedule_list_tail(netif_t *netif)
++static inline void efhw_page_mark_invalid(efhw_page_t *p)
 +{
-+      if (__on_net_schedule_list(netif))
-+              return;
++      p->kva = 0;
++}
 +
-+      spin_lock_irq(&net_schedule_list_lock);
-+      if (!__on_net_schedule_list(netif) &&
-+          likely(netif_schedulable(netif))) {
-+              list_add_tail(&netif->list, &net_schedule_list);
-+              netif_get(netif);
-+      }
-+      spin_unlock_irq(&net_schedule_list_lock);
++static inline int efhw_page_is_valid(efhw_page_t *p)
++{
++      return p->kva != 0;
 +}
 +
-+/*
-+ * Note on CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER:
-+ * If this driver is pipelining transmit requests then we can be very
-+ * aggressive in avoiding new-packet notifications -- frontend only needs to
-+ * send a notification if there are no outstanding unreceived responses.
-+ * If we may be buffer transmit buffers for any reason then we must be rather
-+ * more conservative and treat this as the final check for pending work.
-+ */
-+void netif_schedule_work(netif_t *netif)
++static inline void efhw_page_init_from_va(efhw_page_t *p, void *va)
 +{
-+      int more_to_do;
++      p->kva = (unsigned long)va;
++}
 +
-+#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
-+      more_to_do = RING_HAS_UNCONSUMED_REQUESTS(&netif->tx);
-+#else
-+      RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
-+#endif
++/*--------------------------------------------------------------------
++ *
++ * efhw_iopage_t: A single page of memory.  Directly mapped in the driver,
++ * and can be mapped to userlevel.  Can also be accessed by the NIC.
++ *
++ *--------------------------------------------------------------------*/
 +
-+      if (more_to_do) {
-+              add_to_net_schedule_list_tail(netif);
-+              maybe_schedule_tx_action();
-+      }
-+}
++typedef struct {
++      efhw_page_t p;
++      dma_addr_t dma_addr;
++} efhw_iopage_t;
 +
-+void netif_deschedule_work(netif_t *netif)
++static inline dma_addr_t efhw_iopage_dma_addr(efhw_iopage_t *p)
 +{
-+      remove_from_net_schedule_list(netif);
++      return p->dma_addr;
 +}
 +
++#define efhw_iopage_ptr(iop)          efhw_page_ptr(&(iop)->p)
++#define efhw_iopage_pfn(iop)          efhw_page_pfn(&(iop)->p)
++#define efhw_iopage_mark_invalid(iop) efhw_page_mark_invalid(&(iop)->p)
++#define efhw_iopage_is_valid(iop)     efhw_page_is_valid(&(iop)->p)
 +
-+static void tx_add_credit(netif_t *netif)
++/*--------------------------------------------------------------------
++ *
++ * efhw_iopages_t: A set of pages that are contiguous in physical memory.
++ * Directly mapped in the driver, and can be mapped to userlevel.  Can also
++ * be accessed by the NIC.
++ *
++ * NB. The O/S may be unwilling to allocate many, or even any of these.  So
++ * only use this type where the NIC really needs a physically contiguous
++ * buffer.
++ *
++ *--------------------------------------------------------------------*/
++
++typedef struct {
++      caddr_t kva;
++      unsigned order;
++      dma_addr_t dma_addr;
++} efhw_iopages_t;
++
++static inline caddr_t efhw_iopages_ptr(efhw_iopages_t *p)
 +{
-+      unsigned long max_burst, max_credit;
++      return p->kva;
++}
 +
-+      /*
-+       * Allow a burst big enough to transmit a jumbo packet of up to 128kB.
-+       * Otherwise the interface can seize up due to insufficient credit.
-+       */
-+      max_burst = RING_GET_REQUEST(&netif->tx, netif->tx.req_cons)->size;
-+      max_burst = min(max_burst, 131072UL);
-+      max_burst = max(max_burst, netif->credit_bytes);
++static inline unsigned efhw_iopages_pfn(efhw_iopages_t *p)
++{
++      return (unsigned)(__pa(p->kva) >> PAGE_SHIFT);
++}
 +
-+      /* Take care that adding a new chunk of credit doesn't wrap to zero. */
-+      max_credit = netif->remaining_credit + netif->credit_bytes;
-+      if (max_credit < netif->remaining_credit)
-+              max_credit = ULONG_MAX; /* wrapped: clamp to ULONG_MAX */
++static inline dma_addr_t efhw_iopages_dma_addr(efhw_iopages_t *p)
++{
++      return p->dma_addr;
++}
 +
-+      netif->remaining_credit = min(max_credit, max_burst);
++static inline unsigned efhw_iopages_size(efhw_iopages_t *p)
++{
++      return 1u << (p->order + PAGE_SHIFT);
 +}
 +
-+static void tx_credit_callback(unsigned long data)
++/* efhw_iopage_t <-> efhw_iopages_t conversions for handling physically
++ * contiguous allocations in iobufsets for iSCSI.  This allows the
++ * essential information about contiguous allocations from
++ * efhw_iopages_alloc() to be saved away in the efhw_iopage_t array in an
++ * iobufset.  (Changing the iobufset resource to use a union type would
++ * involve a lot of code changes, and make the iobufset's metadata larger
++ * which could be bad as it's supposed to fit into a single page on some
++ * platforms.)
++ */
++static inline void
++efhw_iopage_init_from_iopages(efhw_iopage_t *iopage,
++                          efhw_iopages_t *iopages, unsigned pageno)
 +{
-+      netif_t *netif = (netif_t *)data;
-+      tx_add_credit(netif);
-+      netif_schedule_work(netif);
++      iopage->p.kva = ((unsigned long)efhw_iopages_ptr(iopages))
++          + (pageno * PAGE_SIZE);
++      iopage->dma_addr = efhw_iopages_dma_addr(iopages) +
++          (pageno * PAGE_SIZE);
 +}
 +
-+static inline int copy_pending_req(PEND_RING_IDX pending_idx)
++static inline void
++efhw_iopages_init_from_iopage(efhw_iopages_t *iopages,
++                          efhw_iopage_t *iopage, unsigned order)
 +{
-+      return gnttab_copy_grant_page(grant_tx_handle[pending_idx],
-+                                    &mmap_pages[pending_idx]);
++      iopages->kva = (caddr_t) efhw_iopage_ptr(iopage);
++      EFHW_ASSERT(iopages->kva);
++      iopages->order = order;
++      iopages->dma_addr = efhw_iopage_dma_addr(iopage);
 +}
 +
-+inline static void net_tx_action_dealloc(void)
++#endif /* __CI_EFHW_IOPAGE_LINUX_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efhw/public.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efhw/public.h       2008-05-19 00:33:48.058916291 +0300
+@@ -0,0 +1,83 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides public API of efhw library exported from the SFC
++ * resource driver.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef __CI_EFHW_PUBLIC_H__
++#define __CI_EFHW_PUBLIC_H__
++
++#include <ci/efhw/common.h>
++#include <ci/efhw/efhw_types.h>
++
++/*! Returns true if we have some EtherFabric functional units -
++  whether configured or not */
++static inline int efhw_nic_have_functional_units(struct efhw_nic *nic)
 +{
-+      struct netbk_tx_pending_inuse *inuse, *n;
-+      gnttab_unmap_grant_ref_t *gop;
-+      u16 pending_idx;
-+      PEND_RING_IDX dc, dp;
-+      netif_t *netif;
-+      int ret;
-+      LIST_HEAD(list);
++      return nic->efhw_func != 0;
++}
 +
-+      dc = dealloc_cons;
-+      gop = tx_unmap_ops;
++/*! Returns true if the EtherFabric functional units have been configured  */
++static inline int efhw_nic_have_hw(struct efhw_nic *nic)
++{
++      return efhw_nic_have_functional_units(nic) && (EFHW_KVA(nic) != 0);
++}
 +
-+      /*
-+       * Free up any grants we have finished using
-+       */
-+      do {
-+              dp = dealloc_prod;
++/*! Helper function to allocate the iobuffer needed by an eventq
++ *   - it ensures the eventq has the correct alignment for the NIC
++ *
++ * \param rm        Event-queue resource manager
++ * \param instance  Event-queue instance (index)
++ * \param buf_bytes Requested size of eventq
++ * \return          < 0 if iobuffer allocation fails
++ */
++int efhw_nic_event_queue_alloc_iobuffer(struct efhw_nic *nic,
++                                      struct eventq_resource_hardware *h,
++                                      int evq_instance, unsigned buf_bytes);
 +
-+              /* Ensure we see all indices enqueued by netif_idx_release(). */
-+              smp_rmb();
++extern void falcon_nic_set_rx_usr_buf_size(struct efhw_nic *,
++                                         int rx_usr_buf_size);
 +
-+              while (dc != dp) {
-+                      unsigned long pfn;
++extern void
++falcon_nic_rx_filter_ctl_set(struct efhw_nic *nic, uint32_t tcp_full,
++                           uint32_t tcp_wild,
++                           uint32_t udp_full, uint32_t udp_wild);
 +
-+                      pending_idx = dealloc_ring[MASK_PEND_IDX(dc++)];
-+                      list_move_tail(&pending_inuse[pending_idx].list, &list);
++extern void
++falcon_nic_rx_filter_ctl_get(struct efhw_nic *nic, uint32_t *tcp_full,
++                           uint32_t *tcp_wild,
++                           uint32_t *udp_full, uint32_t *udp_wild);
 +
-+                      pfn = idx_to_pfn(pending_idx);
-+                      /* Already unmapped? */
-+                      if (!phys_to_machine_mapping_valid(pfn))
-+                              continue;
++#endif /* __CI_EFHW_PUBLIC_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efhw/sysdep.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efhw/sysdep.h       2008-05-19 00:33:48.062916522 +0300
+@@ -0,0 +1,72 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides version-independent Linux kernel API for efhw library.
++ * Only kernels >=2.6.9 are supported.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+                      gnttab_set_unmap_op(gop, idx_to_kaddr(pending_idx),
-+                                          GNTMAP_host_map,
-+                                          grant_tx_handle[pending_idx]);
-+                      gop++;
-+              }
++#ifndef __CI_EFHW_SYSDEP_LINUX_H__
++#define __CI_EFHW_SYSDEP_LINUX_H__
 +
-+              if (netbk_copy_skb_mode != NETBK_DELAYED_COPY_SKB ||
-+                  list_empty(&pending_inuse_head))
-+                      break;
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <linux/if_ether.h>
 +
-+              /* Copy any entries that have been pending for too long. */
-+              list_for_each_entry_safe(inuse, n, &pending_inuse_head, list) {
-+                      if (time_after(inuse->alloc_time + HZ / 2, jiffies))
-+                              break;
++#include <linux/netdevice.h> /* necessary for etherdevice.h on some kernels */
++#include <linux/etherdevice.h>
 +
-+                      switch (copy_pending_req(inuse - pending_inuse)) {
-+                      case 0:
-+                              list_move_tail(&inuse->list, &list);
-+                              continue;
-+                      case -EBUSY:
-+                              list_del_init(&inuse->list);
-+                              continue;
-+                      case -ENOENT:
-+                              continue;
-+                      }
++#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,21)
++static inline int is_local_ether_addr(const u8 *addr)
++{
++      return (0x02 & addr[0]);
++}
++#endif
 +
-+                      break;
-+              }
-+      } while (dp != dealloc_prod);
++typedef unsigned long irq_flags_t;
 +
-+      dealloc_cons = dc;
++#define spin_lock_destroy(l_)  do {} while (0)
 +
-+      ret = HYPERVISOR_grant_table_op(
-+              GNTTABOP_unmap_grant_ref, tx_unmap_ops, gop - tx_unmap_ops);
-+      BUG_ON(ret);
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
++#define HAS_NET_NAMESPACE
++#endif
 +
-+      list_for_each_entry_safe(inuse, n, &list, list) {
-+              pending_idx = inuse - pending_inuse;
++/* Funny, but linux has round_up for x86 only, defined in
++ * x86-specific header */
++#ifndef round_up
++#define round_up(x, y) (((x) + (y) - 1) & ~((y)-1))
++#endif
 +
-+              netif = pending_tx_info[pending_idx].netif;
++#endif /* __CI_EFHW_SYSDEP_LINUX_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efrm/nic_table.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efrm/nic_table.h    2008-05-19 00:33:48.070916983 +0300
+@@ -0,0 +1,98 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides public API for NIC table.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+              make_tx_response(netif, &pending_tx_info[pending_idx].req, 
-+                               NETIF_RSP_OKAY);
++#ifndef __CI_EFRM_NIC_TABLE_H__
++#define __CI_EFRM_NIC_TABLE_H__
 +
-+              /* Ready for next use. */
-+              gnttab_reset_grant_page(mmap_pages[pending_idx]);
++#include <ci/efhw/efhw_types.h>
++#include <ci/efrm/sysdep.h>
 +
-+              pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
++/*--------------------------------------------------------------------
++ *
++ * struct efrm_nic_table - top level driver object keeping all NICs -
++ * implemented in driver_object.c
++ *
++ *--------------------------------------------------------------------*/
 +
-+              netif_put(netif);
++/*! Comment? */
++struct efrm_nic_table {
++      /*! nics attached to this driver */
++      struct efhw_nic *nic[EFHW_MAX_NR_DEVS];
++      /*! pointer to an arbitrary struct efhw_nic if one exists;
++       * for code which does not care which NIC it wants but
++       * still needs one. Note you cannot assume nic[0] exists. */
++      struct efhw_nic *a_nic;
++      uint32_t nic_count;     /*!< number of nics attached to this driver */
++      spinlock_t lock;        /*!< lock for table modifications */
++      atomic_t ref_count;     /*!< refcount for users of nic table */
++};
 +
-+              list_del_init(&inuse->list);
-+      }
-+}
++/* Resource driver structures used by other drivers as well */
++extern struct efrm_nic_table efrm_nic_table;
 +
-+static void netbk_tx_err(netif_t *netif, netif_tx_request_t *txp, RING_IDX end)
++static inline void efrm_nic_table_hold(void)
 +{
-+      RING_IDX cons = netif->tx.req_cons;
++      atomic_inc(&efrm_nic_table.ref_count);
++}
 +
-+      do {
-+              make_tx_response(netif, txp, NETIF_RSP_ERROR);
-+              if (cons >= end)
-+                      break;
-+              txp = RING_GET_REQUEST(&netif->tx, cons++);
-+      } while (1);
-+      netif->tx.req_cons = cons;
-+      netif_schedule_work(netif);
-+      netif_put(netif);
++static inline void efrm_nic_table_rele(void)
++{
++      atomic_dec(&efrm_nic_table.ref_count);
 +}
 +
-+static int netbk_count_requests(netif_t *netif, netif_tx_request_t *first,
-+                              netif_tx_request_t *txp, int work_to_do)
++static inline int efrm_nic_table_held(void)
 +{
-+      RING_IDX cons = netif->tx.req_cons;
-+      int frags = 0;
++      return (atomic_read(&efrm_nic_table.ref_count) != 0);
++}
 +
-+      if (!(first->flags & NETTXF_more_data))
-+              return 0;
++/* Run code block _x multiple times with variable nic set to each
++ * registered NIC in turn.
++ * DO NOT "break" out of this loop early. */
++#define EFRM_FOR_EACH_NIC(_nic_i, _nic)                                       \
++      for ((_nic_i) = (efrm_nic_table_hold(), 0);                     \
++           (_nic_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0); \
++           (_nic_i)++)                                                \
++              if (((_nic) = efrm_nic_table.nic[_nic_i]))
 +
-+      do {
-+              if (frags >= work_to_do) {
-+                      DPRINTK("Need more frags\n");
-+                      return -frags;
-+              }
++#define EFRM_FOR_EACH_NIC_IN_SET(_set, _i, _nic)                      \
++      for ((_i) = (efrm_nic_table_hold(), 0);                         \
++           (_i) < EFHW_MAX_NR_DEVS || (efrm_nic_table_rele(), 0);     \
++           ++(_i))                                                    \
++              if (((_nic) = efrm_nic_table.nic[_i]) &&                \
++                  efrm_nic_set_read((_set), (_i)))
 +
-+              if (unlikely(frags >= MAX_SKB_FRAGS)) {
-+                      DPRINTK("Too many frags\n");
-+                      return -frags;
-+              }
++#endif /* __CI_EFRM_NIC_TABLE_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efrm/sysdep.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efrm/sysdep.h       2008-05-19 00:33:48.426937504 +0300
+@@ -0,0 +1,54 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides Linux-like system-independent API for efrm library.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+              memcpy(txp, RING_GET_REQUEST(&netif->tx, cons + frags),
-+                     sizeof(*txp));
-+              if (txp->size > first->size) {
-+                      DPRINTK("Frags galore\n");
-+                      return -frags;
-+              }
++#ifndef __CI_EFRM_SYSDEP_H__
++#define __CI_EFRM_SYSDEP_H__
 +
-+              first->size -= txp->size;
-+              frags++;
++/* Spinlocks are defined in efhw/sysdep.h */
++#include <ci/efhw/sysdep.h>
 +
-+              if (unlikely((txp->offset + txp->size) > PAGE_SIZE)) {
-+                      DPRINTK("txp->offset: %x, size: %u\n",
-+                              txp->offset, txp->size);
-+                      return -frags;
-+              }
-+      } while ((txp++)->flags & NETTXF_more_data);
++#if defined(__linux__) && defined(__KERNEL__)
 +
-+      return frags;
-+}
++# include <ci/efrm/sysdep_linux.h>
 +
-+static gnttab_map_grant_ref_t *netbk_get_requests(netif_t *netif,
-+                                                struct sk_buff *skb,
-+                                                netif_tx_request_t *txp,
-+                                                gnttab_map_grant_ref_t *mop)
-+{
-+      struct skb_shared_info *shinfo = skb_shinfo(skb);
-+      skb_frag_t *frags = shinfo->frags;
-+      unsigned long pending_idx = *((u16 *)skb->data);
-+      int i, start;
++#else
 +
-+      /* Skip first skb fragment if it is on same page as header fragment. */
-+      start = ((unsigned long)shinfo->frags[0].page == pending_idx);
++# include <ci/efrm/sysdep_ci2linux.h>
 +
-+      for (i = start; i < shinfo->nr_frags; i++, txp++) {
-+              pending_idx = pending_ring[MASK_PEND_IDX(pending_cons++)];
++#endif
 +
-+              gnttab_set_map_op(mop++, idx_to_kaddr(pending_idx),
-+                                GNTMAP_host_map | GNTMAP_readonly,
-+                                txp->gref, netif->domid);
++#endif /* __CI_EFRM_SYSDEP_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/efrm/sysdep_linux.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/efrm/sysdep_linux.h 2008-05-19 00:33:48.426937504 +0300
+@@ -0,0 +1,248 @@
++/****************************************************************************
++ * Driver for Solarflare network controllers -
++ *          resource management for Xen backend, OpenOnload, etc
++ *           (including support for SFE4001 10GBT NIC)
++ *
++ * This file provides version-independent Linux kernel API for efrm library.
++ * Only kernels >=2.6.9 are supported.
++ *
++ * Copyright 2005-2007: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Kfifo API is partially stolen from linux-2.6.22/include/linux/list.h
++ * Copyright (C) 2004 Stelian Pop <stelian@popies.net>
++ *
++ * Developed and maintained by Solarflare Communications:
++ *                      <linux-xen-drivers@solarflare.com>
++ *                      <onload-dev@solarflare.com>
++ *
++ * Certain parts of the driver were implemented by
++ *          Alexandra Kossovsky <Alexandra.Kossovsky@oktetlabs.ru>
++ *          OKTET Labs Ltd, Russia,
++ *          http://oktetlabs.ru, <info@oktetlabs.ru>
++ *          by request of Solarflare Communications
++ *
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+              memcpy(&pending_tx_info[pending_idx].req, txp, sizeof(*txp));
-+              netif_get(netif);
-+              pending_tx_info[pending_idx].netif = netif;
-+              frags[i].page = (void *)pending_idx;
-+      }
++#ifndef __CI_EFRM_SYSDEP_LINUX_H__
++#define __CI_EFRM_SYSDEP_LINUX_H__
 +
-+      return mop;
++#include <linux/version.h>
++#include <linux/list.h>
++#include <linux/vmalloc.h>
++#include <linux/errno.h>
++#include <linux/string.h>
++#include <linux/workqueue.h>
++#include <linux/gfp.h>
++#include <linux/slab.h>
++#include <linux/hardirq.h>
++#include <linux/kernel.h>
++#include <linux/if_ether.h>
++#include <linux/completion.h>
++#include <linux/in.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++/* get roundup_pow_of_two(), which was in kernel.h in early kernel versions */
++#include <linux/log2.h>
++#endif
++
++/********************************************************************
++ *
++ * List API
++ *
++ ********************************************************************/
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)
++static inline void
++list_replace_init(struct list_head *old, struct list_head *new)
++{
++      new->next = old->next;
++      new->next->prev = new;
++      new->prev = old->prev;
++      new->prev->next = new;
++      INIT_LIST_HEAD(old);
 +}
++#endif
 +
-+static int netbk_tx_check_mop(struct sk_buff *skb,
-+                             gnttab_map_grant_ref_t **mopp)
++static inline struct list_head *list_pop(struct list_head *list)
 +{
-+      gnttab_map_grant_ref_t *mop = *mopp;
-+      int pending_idx = *((u16 *)skb->data);
-+      netif_t *netif = pending_tx_info[pending_idx].netif;
-+      netif_tx_request_t *txp;
-+      struct skb_shared_info *shinfo = skb_shinfo(skb);
-+      int nr_frags = shinfo->nr_frags;
-+      int i, err, start;
++      struct list_head *link = list->next;
++      list_del(link);
++      return link;
++}
 +
-+      /* Check status of header. */
-+      err = mop->status;
-+      if (unlikely(err)) {
-+              txp = &pending_tx_info[pending_idx].req;
-+              make_tx_response(netif, txp, NETIF_RSP_ERROR);
-+              pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
-+              netif_put(netif);
-+      } else {
-+              set_phys_to_machine(
-+                      __pa(idx_to_kaddr(pending_idx)) >> PAGE_SHIFT,
-+                      FOREIGN_FRAME(mop->dev_bus_addr >> PAGE_SHIFT));
-+              grant_tx_handle[pending_idx] = mop->handle;
-+      }
++static inline struct list_head *list_pop_tail(struct list_head *list)
++{
++      struct list_head *link = list->prev;
++      list_del(link);
++      return link;
++}
 +
-+      /* Skip first skb fragment if it is on same page as header fragment. */
-+      start = ((unsigned long)shinfo->frags[0].page == pending_idx);
++/********************************************************************
++ *
++ * Workqueue API
++ *
++ ********************************************************************/
 +
-+      for (i = start; i < nr_frags; i++) {
-+              int j, newerr;
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
++#define NEED_OLD_WORK_API
 +
-+              pending_idx = (unsigned long)shinfo->frags[i].page;
++/**
++ * The old and new work function prototypes just change
++ * the type of the pointer in the only argument, so it's
++ * safe to cast one function type to the other
++ */
++typedef void (*efrm_old_work_func_t) (void *p);
 +
-+              /* Check error status: if okay then remember grant handle. */
-+              newerr = (++mop)->status;
-+              if (likely(!newerr)) {
-+                      set_phys_to_machine(
-+                              __pa(idx_to_kaddr(pending_idx))>>PAGE_SHIFT,
-+                              FOREIGN_FRAME(mop->dev_bus_addr>>PAGE_SHIFT));
-+                      grant_tx_handle[pending_idx] = mop->handle;
-+                      /* Had a previous error? Invalidate this fragment. */
-+                      if (unlikely(err))
-+                              netif_idx_release(pending_idx);
-+                      continue;
-+              }
++#undef INIT_WORK
++#define INIT_WORK(_work, _func)                                       \
++      do {                                                    \
++              INIT_LIST_HEAD(&(_work)->entry);                \
++              (_work)->pending = 0;                           \
++              PREPARE_WORK((_work),                           \
++                           (efrm_old_work_func_t) (_func),    \
++                           (_work));                          \
++      } while (0)
 +
-+              /* Error on this fragment: respond to client with an error. */
-+              txp = &pending_tx_info[pending_idx].req;
-+              make_tx_response(netif, txp, NETIF_RSP_ERROR);
-+              pending_ring[MASK_PEND_IDX(pending_prod++)] = pending_idx;
-+              netif_put(netif);
++#endif
 +
-+              /* Not the first error? Preceding frags already invalidated. */
-+              if (err)
-+                      continue;
++/********************************************************************
++ *
++ * Kfifo API
++ *
++ ********************************************************************/
 +
-+              /* First error: invalidate header and preceding fragments. */
-+              pending_idx = *((u16 *)skb->data);
-+              netif_idx_release(pending_idx);
-+              for (j = start; j < i; j++) {
-+                      pending_idx = (unsigned long)shinfo->frags[i].page;
-+                      netif_idx_release(pending_idx);
-+              }
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
 +
-+              /* Remember the error: invalidate all subsequent fragments. */
-+              err = newerr;
-+      }
++#if !defined(RHEL_RELEASE_CODE) || (RHEL_RELEASE_CODE < 1029)
++typedef unsigned gfp_t;
++#endif
 +
-+      *mopp = mop + 1;
-+      return err;
-+}
++#define HAS_NO_KFIFO
 +
-+static void netbk_fill_frags(struct sk_buff *skb)
-+{
-+      struct skb_shared_info *shinfo = skb_shinfo(skb);
-+      int nr_frags = shinfo->nr_frags;
-+      int i;
++struct kfifo {
++      unsigned char *buffer;  /* the buffer holding the data */
++      unsigned int size;      /* the size of the allocated buffer */
++      unsigned int in;        /* data is added at offset (in % size) */
++      unsigned int out;       /* data is extracted from off. (out % size) */
++      spinlock_t *lock;       /* protects concurrent modifications */
++};
 +
-+      for (i = 0; i < nr_frags; i++) {
-+              skb_frag_t *frag = shinfo->frags + i;
-+              netif_tx_request_t *txp;
-+              unsigned long pending_idx;
++extern struct kfifo *kfifo_init(unsigned char *buffer, unsigned int size,
++                              gfp_t gfp_mask, spinlock_t *lock);
++extern struct kfifo *kfifo_alloc(unsigned int size, gfp_t gfp_mask,
++                               spinlock_t *lock);
++extern void kfifo_free(struct kfifo *fifo);
++extern unsigned int __kfifo_put(struct kfifo *fifo,
++                              unsigned char *buffer, unsigned int len);
++extern unsigned int __kfifo_get(struct kfifo *fifo,
++                              unsigned char *buffer, unsigned int len);
 +
-+              pending_idx = (unsigned long)frag->page;
++/**
++ * kfifo_put - puts some data into the FIFO
++ * @fifo: the fifo to be used.
++ * @buffer: the data to be added.
++ * @len: the length of the data to be added.
++ *
++ * This function copies at most @len bytes from the @buffer into
++ * the FIFO depending on the free space, and returns the number of
++ * bytes copied.
++ */
++static inline unsigned int
++kfifo_put(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
++{
++      unsigned long flags;
++      unsigned int ret;
 +
-+              pending_inuse[pending_idx].alloc_time = jiffies;
-+              list_add_tail(&pending_inuse[pending_idx].list,
-+                            &pending_inuse_head);
++      spin_lock_irqsave(fifo->lock, flags);
 +
-+              txp = &pending_tx_info[pending_idx].req;
-+              frag->page = virt_to_page(idx_to_kaddr(pending_idx));
-+              frag->size = txp->size;
-+              frag->page_offset = txp->offset;
++      ret = __kfifo_put(fifo, buffer, len);
 +
-+              skb->len += txp->size;
-+              skb->data_len += txp->size;
-+              skb->truesize += txp->size;
-+      }
++      spin_unlock_irqrestore(fifo->lock, flags);
++
++      return ret;
 +}
 +
-+int netbk_get_extras(netif_t *netif, struct netif_extra_info *extras,
-+                   int work_to_do)
++/**
++ * kfifo_get - gets some data from the FIFO
++ * @fifo: the fifo to be used.
++ * @buffer: where the data must be copied.
++ * @len: the size of the destination buffer.
++ *
++ * This function copies at most @len bytes from the FIFO into the
++ * @buffer and returns the number of copied bytes.
++ */
++static inline unsigned int
++kfifo_get(struct kfifo *fifo, unsigned char *buffer, unsigned int len)
 +{
-+      struct netif_extra_info extra;
-+      RING_IDX cons = netif->tx.req_cons;
++      unsigned long flags;
++      unsigned int ret;
 +
-+      do {
-+              if (unlikely(work_to_do-- <= 0)) {
-+                      DPRINTK("Missing extra info\n");
-+                      return -EBADR;
-+              }
++      spin_lock_irqsave(fifo->lock, flags);
 +
-+              memcpy(&extra, RING_GET_REQUEST(&netif->tx, cons),
-+                     sizeof(extra));
-+              if (unlikely(!extra.type ||
-+                           extra.type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
-+                      netif->tx.req_cons = ++cons;
-+                      DPRINTK("Invalid extra type: %d\n", extra.type);
-+                      return -EINVAL;
-+              }
++      ret = __kfifo_get(fifo, buffer, len);
 +
-+              memcpy(&extras[extra.type - 1], &extra, sizeof(extra));
-+              netif->tx.req_cons = ++cons;
-+      } while (extra.flags & XEN_NETIF_EXTRA_FLAG_MORE);
++      /*
++       * optimization: if the FIFO is empty, set the indices to 0
++       * so we don't wrap the next time
++       */
++      if (fifo->in == fifo->out)
++              fifo->in = fifo->out = 0;
 +
-+      return work_to_do;
++      spin_unlock_irqrestore(fifo->lock, flags);
++
++      return ret;
 +}
 +
-+static int netbk_set_skb_gso(struct sk_buff *skb, struct netif_extra_info *gso)
++/**
++ * __kfifo_len - returns the number of bytes available in the FIFO, no locking version
++ * @fifo: the fifo to be used.
++ */
++static inline unsigned int __kfifo_len(struct kfifo *fifo)
 +{
-+      if (!gso->u.gso.size) {
-+              DPRINTK("GSO size must not be zero.\n");
-+              return -EINVAL;
-+      }
++      return fifo->in - fifo->out;
++}
 +
-+      /* Currently only TCPv4 S.O. is supported. */
-+      if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
-+              DPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
-+              return -EINVAL;
-+      }
++/**
++ * kfifo_len - returns the number of bytes available in the FIFO
++ * @fifo: the fifo to be used.
++ */
++static inline unsigned int kfifo_len(struct kfifo *fifo)
++{
++      unsigned long flags;
++      unsigned int ret;
 +
-+      skb_shinfo(skb)->gso_size = gso->u.gso.size;
-+      skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
++      spin_lock_irqsave(fifo->lock, flags);
 +
-+      /* Header must be checked, and gso_segs computed. */
-+      skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
-+      skb_shinfo(skb)->gso_segs = 0;
++      ret = __kfifo_len(fifo);
 +
-+      return 0;
++      spin_unlock_irqrestore(fifo->lock, flags);
++
++      return ret;
 +}
 +
-+/* Called after netfront has transmitted */
-+static void net_tx_action(unsigned long unused)
++#else
++#include <linux/kfifo.h>
++#endif
++
++static inline void kfifo_vfree(struct kfifo *fifo)
 +{
-+      struct list_head *ent;
-+      struct sk_buff *skb;
-+      netif_t *netif;
-+      netif_tx_request_t txreq;
-+      netif_tx_request_t txfrags[MAX_SKB_FRAGS];
-+      struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
-+      u16 pending_idx;
-+      RING_IDX i;
-+      gnttab_map_grant_ref_t *mop;
-+      unsigned int data_len;
-+      int ret, work_to_do;
++      vfree(fifo->buffer);
++      kfree(fifo);
++}
 +
-+      if (dealloc_cons != dealloc_prod)
-+              net_tx_action_dealloc();
++#endif /* __CI_EFRM_SYSDEP_LINUX_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/tools/config.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/tools/config.h      2008-05-19 00:33:48.478940502 +0300
+@@ -0,0 +1,49 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      mop = tx_map_ops;
-+      while (((NR_PENDING_REQS + MAX_SKB_FRAGS) < MAX_PENDING_REQS) &&
-+              !list_empty(&net_schedule_list)) {
-+              /* Get a netif from the list with work to do. */
-+              ent = net_schedule_list.next;
-+              netif = list_entry(ent, netif_t, list);
-+              netif_get(netif);
-+              remove_from_net_schedule_list(netif);
++/*! \cidoxg_include_ci_tools */
 +
-+              RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, work_to_do);
-+              if (!work_to_do) {
-+                      netif_put(netif);
-+                      continue;
-+              }
++#ifndef __CI_TOOLS_CONFIG_H__
++#define __CI_TOOLS_CONFIG_H__
 +
-+              i = netif->tx.req_cons;
-+              rmb(); /* Ensure that we see the request before we copy it. */
-+              memcpy(&txreq, RING_GET_REQUEST(&netif->tx, i), sizeof(txreq));
 +
-+              /* Credit-based scheduling. */
-+              if (txreq.size > netif->remaining_credit) {
-+                      unsigned long now = jiffies;
-+                      unsigned long next_credit = 
-+                              netif->credit_timeout.expires +
-+                              msecs_to_jiffies(netif->credit_usec / 1000);
++/**********************************************************************
++ * Debugging.
++ */
 +
-+                      /* Timer could already be pending in rare cases. */
-+                      if (timer_pending(&netif->credit_timeout)) {
-+                              netif_put(netif);
-+                              continue;
-+                      }
++#define CI_INCLUDE_ASSERT_VALID           0
 +
-+                      /* Passed the point where we can replenish credit? */
-+                      if (time_after_eq(now, next_credit)) {
-+                              netif->credit_timeout.expires = now;
-+                              tx_add_credit(netif);
-+                      }
++/* Set non-zero to allow info about who has allocated what to appear in
++ * /proc/drivers/level5/mem.
++ * However - Note that doing so can lead to segfault when you unload the
++ * driver, and other weirdness.  i.e. I don't think the code for is quite
++ * right (written by Oktet, hacked by gel), but it does work well enough to be
++ * useful.
++ */
++#define CI_MEMLEAK_DEBUG_ALLOC_TABLE    0
 +
-+                      /* Still too big to send right now? Set a callback. */
-+                      if (txreq.size > netif->remaining_credit) {
-+                              netif->credit_timeout.data     =
-+                                      (unsigned long)netif;
-+                              netif->credit_timeout.function =
-+                                      tx_credit_callback;
-+                              __mod_timer(&netif->credit_timeout,
-+                                          next_credit);
-+                              netif_put(netif);
-+                              continue;
-+                      }
-+              }
-+              netif->remaining_credit -= txreq.size;
 +
-+              work_to_do--;
-+              netif->tx.req_cons = ++i;
++#endif  /* __CI_TOOLS_CONFIG_H__ */
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/tools/debug.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/tools/debug.h       2008-05-19 00:33:48.518942808 +0300
+@@ -0,0 +1,336 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++/*! \cidoxg_include_ci_tools */
++
++#ifndef __CI_TOOLS_DEBUG_H__
++#define __CI_TOOLS_DEBUG_H__
++
++#define CI_LOG_E(x)       x              /* errors      */
++#define CI_LOG_W(x)       x              /* warnings    */
++#define CI_LOG_I(x)       x              /* information */
++#define CI_LOG_V(x)       x              /* verbose     */
++
++/* Build time asserts. We paste the line number into the type name
++ * so that the macro can be used more than once per file even if the
++ * compiler objects to multiple identical typedefs. Collisions
++ * between use in different header files is still possible. */
++#ifndef CI_BUILD_ASSERT
++#define __CI_BUILD_ASSERT_NAME(_x) __CI_BUILD_ASSERT_ILOATHECPP(_x)
++#define __CI_BUILD_ASSERT_ILOATHECPP(_x)  __CI_BUILD_ASSERT__ ##_x
++#define CI_BUILD_ASSERT(e)\
++ typedef char  __CI_BUILD_ASSERT_NAME(__LINE__)[(e)?1:-1]
++#endif
++
++
++#ifdef NDEBUG
++
++# define _ci_check(exp, file, line)
++# define _ci_assert2(e, x, y, file, line)
++# define _ci_assert(exp, file, line)
++# define _ci_assert_equal(exp1, exp2, file, line)
++# define _ci_assert_equiv(exp1, exp2, file, line)
++# define _ci_assert_nequal(exp1, exp2, file, line)
++# define _ci_assert_le(exp1, exp2, file, line)
++# define _ci_assert_lt(exp1, exp2, file, line)
++# define _ci_assert_ge(exp1, exp2, file, line)
++# define _ci_assert_gt(exp1, exp2, file, line)
++# define _ci_assert_impl(exp1, exp2, file, line)
++
++# define _ci_verify(exp, file, line) \
++  do { \
++    (void)(exp); \
++  } while (0)
++
++# define CI_DEBUG_TRY(exp) \
++  do { \
++    (void)(exp); \
++  } while (0)
++
++#define CI_TRACE(exp,fmt)
++#define CI_TRACE_INT(integer)
++#define CI_TRACE_INT32(integer)
++#define CI_TRACE_INT64(integer)
++#define CI_TRACE_UINT(integer)
++#define CI_TRACE_UINT32(integer)
++#define CI_TRACE_UINT64(integer)
++#define CI_TRACE_HEX(integer)
++#define CI_TRACE_HEX32(integer)
++#define CI_TRACE_HEX64(integer)
++#define CI_TRACE_PTR(pointer)
++#define CI_TRACE_STRING(string)
++#define CI_TRACE_MAC(mac)
++#define CI_TRACE_IP(ip_be32)
++#define CI_TRACE_ARP(arp_pkt)
 +
-+              memset(extras, 0, sizeof(extras));
-+              if (txreq.flags & NETTXF_extra_info) {
-+                      work_to_do = netbk_get_extras(netif, extras,
-+                                                    work_to_do);
-+                      i = netif->tx.req_cons;
-+                      if (unlikely(work_to_do < 0)) {
-+                              netbk_tx_err(netif, &txreq, i);
-+                              continue;
-+                      }
-+              }
++#else
 +
-+              ret = netbk_count_requests(netif, &txreq, txfrags, work_to_do);
-+              if (unlikely(ret < 0)) {
-+                      netbk_tx_err(netif, &txreq, i - ret);
-+                      continue;
-+              }
-+              i += ret;
++# define _CI_ASSERT_FMT   "\nfrom %s:%d"
 +
-+              if (unlikely(txreq.size < ETH_HLEN)) {
-+                      DPRINTK("Bad packet size: %d\n", txreq.size);
-+                      netbk_tx_err(netif, &txreq, i);
-+                      continue;
-+              }
++# define _ci_check(exp, file, line)                             \
++  do {                                                          \
++    if (CI_UNLIKELY(!(exp)))                                    \
++      ci_warn(("ci_check(%s)"_CI_ASSERT_FMT, #exp,              \
++               (file), (line)));                                \
++  } while (0)
 +
-+              /* No crossing a page as the payload mustn't fragment. */
-+              if (unlikely((txreq.offset + txreq.size) > PAGE_SIZE)) {
-+                      DPRINTK("txreq.offset: %x, size: %u, end: %lu\n", 
-+                              txreq.offset, txreq.size, 
-+                              (txreq.offset &~PAGE_MASK) + txreq.size);
-+                      netbk_tx_err(netif, &txreq, i);
-+                      continue;
-+              }
++/*
++ * NOTE: ci_fail() emits the file and line where the assert is actually
++ *       coded.
++ */
 +
-+              pending_idx = pending_ring[MASK_PEND_IDX(pending_cons)];
++# define _ci_assert(exp, file, line)                            \
++  do {                                                          \
++    if (CI_UNLIKELY(!(exp)))                                    \
++      ci_fail(("ci_assert(%s)"_CI_ASSERT_FMT, #exp,           \
++               (file), (line)));                                \
++  } while (0)
 +
-+              data_len = (txreq.size > PKT_PROT_LEN &&
-+                          ret < MAX_SKB_FRAGS) ?
-+                      PKT_PROT_LEN : txreq.size;
++# define _ci_assert2(e, x, y, file, line)  do {                 \
++    if(CI_UNLIKELY( ! (e) ))                                    \
++      ci_fail(("ci_assert(%s)\nwhere [%s=%"CI_PRIx64"] "        \
++               "[%s=%"CI_PRIx64"]\nat %s:%d\nfrom %s:%d", #e    \
++               , #x, (ci_uint64)(ci_uintptr_t)(x)               \
++               , #y, (ci_uint64)(ci_uintptr_t)(y),              \
++               __FILE__, __LINE__, (file), (line)));            \
++  } while (0)
 +
-+              skb = alloc_skb(data_len + 16 + NET_IP_ALIGN,
-+                              GFP_ATOMIC | __GFP_NOWARN);
-+              if (unlikely(skb == NULL)) {
-+                      DPRINTK("Can't allocate a skb in start_xmit.\n");
-+                      netbk_tx_err(netif, &txreq, i);
-+                      break;
-+              }
++# define _ci_verify(exp, file, line)                            \
++  do {                                                          \
++    if (CI_UNLIKELY(!(exp)))                                    \
++      ci_fail(("ci_verify(%s)"_CI_ASSERT_FMT, #exp,             \
++               (file), (line)));                                \
++  } while (0)
 +
-+              /* Packets passed to netif_rx() must have some headroom. */
-+              skb_reserve(skb, 16 + NET_IP_ALIGN);
++# define _ci_assert_equal(x, y, f, l)  _ci_assert2((x)==(y), x, y, (f), (l))
++# define _ci_assert_nequal(x, y, f, l) _ci_assert2((x)!=(y), x, y, (f), (l))
++# define _ci_assert_le(x, y, f, l)     _ci_assert2((x)<=(y), x, y, (f), (l))
++# define _ci_assert_lt(x, y, f, l)     _ci_assert2((x)< (y), x, y, (f), (l))
++# define _ci_assert_ge(x, y, f, l)     _ci_assert2((x)>=(y), x, y, (f), (l))
++# define _ci_assert_gt(x, y, f, l)     _ci_assert2((x)> (y), x, y, (f), (l))
++# define _ci_assert_or(x, y, f, l)     _ci_assert2((x)||(y), x, y, (f), (l))
++# define _ci_assert_impl(x, y, f, l)   _ci_assert2(!(x) || (y), x, y, (f), (l))
++# define _ci_assert_equiv(x, y, f, l)  _ci_assert2(!(x)== !(y), x, y, (f), (l))
 +
-+              if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
-+                      struct netif_extra_info *gso;
-+                      gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
++#define _ci_assert_equal_msg(exp1, exp2, msg, file, line)       \
++  do {                                                          \
++    if (CI_UNLIKELY((exp1)!=(exp2)))                            \
++      ci_fail(("ci_assert_equal_msg(%s == %s) were "            \
++               "(%"CI_PRIx64":%"CI_PRIx64") with msg[%c%c%c%c]" \
++               _CI_ASSERT_FMT, #exp1, #exp2,                    \
++               (ci_uint64)(ci_uintptr_t)(exp1),                 \
++               (ci_uint64)(ci_uintptr_t)(exp2),                 \
++               (((ci_uint32)msg) >> 24) && 0xff,                \
++               (((ci_uint32)msg) >> 16) && 0xff,                \
++               (((ci_uint32)msg) >> 8 ) && 0xff,                \
++               (((ci_uint32)msg)      ) && 0xff,                \
++               (file), (line)));                                \
++  } while (0)
 +
-+                      if (netbk_set_skb_gso(skb, gso)) {
-+                              kfree_skb(skb);
-+                              netbk_tx_err(netif, &txreq, i);
-+                              continue;
-+                      }
-+              }
++# define CI_DEBUG_TRY(exp)  CI_TRY(exp)
 +
-+              gnttab_set_map_op(mop, idx_to_kaddr(pending_idx),
-+                                GNTMAP_host_map | GNTMAP_readonly,
-+                                txreq.gref, netif->domid);
-+              mop++;
++#define CI_TRACE(exp,fmt)                                             \
++  ci_log("%s:%d:%s] " #exp "=" fmt,                                     \
++         __FILE__, __LINE__, __FUNCTION__, (exp))
 +
-+              memcpy(&pending_tx_info[pending_idx].req,
-+                     &txreq, sizeof(txreq));
-+              pending_tx_info[pending_idx].netif = netif;
-+              *((u16 *)skb->data) = pending_idx;
 +
-+              __skb_put(skb, data_len);
++#define CI_TRACE_INT(integer)                                         \
++  ci_log("%s:%d:%s] " #integer "=%d",                                   \
++         __FILE__, __LINE__, __FUNCTION__, (integer))
 +
-+              skb_shinfo(skb)->nr_frags = ret;
-+              if (data_len < txreq.size) {
-+                      skb_shinfo(skb)->nr_frags++;
-+                      skb_shinfo(skb)->frags[0].page =
-+                              (void *)(unsigned long)pending_idx;
-+              } else {
-+                      /* Discriminate from any valid pending_idx value. */
-+                      skb_shinfo(skb)->frags[0].page = (void *)~0UL;
-+              }
 +
-+              __skb_queue_tail(&tx_queue, skb);
++#define CI_TRACE_INT32(integer)                                               \
++  ci_log("%s:%d:%s] " #integer "=%d",                                   \
++         __FILE__, __LINE__, __FUNCTION__, ((ci_int32)integer))
 +
-+              pending_cons++;
 +
-+              mop = netbk_get_requests(netif, skb, txfrags, mop);
++#define CI_TRACE_INT64(integer)                                               \
++  ci_log("%s:%d:%s] " #integer "=%lld",                                 \
++         __FILE__, __LINE__, __FUNCTION__, ((ci_int64)integer))
 +
-+              netif->tx.req_cons = i;
-+              netif_schedule_work(netif);
 +
-+              if ((mop - tx_map_ops) >= ARRAY_SIZE(tx_map_ops))
-+                      break;
-+      }
++#define CI_TRACE_UINT(integer)                                                \
++  ci_log("%s:%d:%s] " #integer "=%ud",                                  \
++         __FILE__, __LINE__, __FUNCTION__, (integer))
 +
-+      if (mop == tx_map_ops)
-+              return;
 +
-+      ret = HYPERVISOR_grant_table_op(
-+              GNTTABOP_map_grant_ref, tx_map_ops, mop - tx_map_ops);
-+      BUG_ON(ret);
++#define CI_TRACE_UINT32(integer)                                      \
++  ci_log("%s:%d:%s] " #integer "=%ud",                                  \
++         __FILE__, __LINE__, __FUNCTION__, ((ci_uint32)integer))
 +
-+      mop = tx_map_ops;
-+      while ((skb = __skb_dequeue(&tx_queue)) != NULL) {
-+              netif_tx_request_t *txp;
 +
-+              pending_idx = *((u16 *)skb->data);
-+              netif       = pending_tx_info[pending_idx].netif;
-+              txp         = &pending_tx_info[pending_idx].req;
++#define CI_TRACE_UINT64(integer)                                      \
++  ci_log("%s:%d:%s] " #integer "=%ulld",                                \
++         __FILE__, __LINE__, __FUNCTION__, ((ci_uint64)integer))
 +
-+              /* Check the remap error code. */
-+              if (unlikely(netbk_tx_check_mop(skb, &mop))) {
-+                      DPRINTK("netback grant failed.\n");
-+                      skb_shinfo(skb)->nr_frags = 0;
-+                      kfree_skb(skb);
-+                      continue;
-+              }
 +
-+              data_len = skb->len;
-+              memcpy(skb->data,
-+                     (void *)(idx_to_kaddr(pending_idx)|txp->offset),
-+                     data_len);
-+              if (data_len < txp->size) {
-+                      /* Append the packet payload as a fragment. */
-+                      txp->offset += data_len;
-+                      txp->size -= data_len;
-+              } else {
-+                      /* Schedule a response immediately. */
-+                      netif_idx_release(pending_idx);
-+              }
++#define CI_TRACE_HEX(integer)                                         \
++  ci_log("%s:%d:%s] " #integer "=0x%x",                                 \
++         __FILE__, __LINE__, __FUNCTION__, (integer))
 +
-+              /*
-+               * Old frontends do not assert data_validated but we
-+               * can infer it from csum_blank so test both flags.
-+               */
-+              if (txp->flags & (NETTXF_data_validated|NETTXF_csum_blank)) {
-+                      skb->ip_summed = CHECKSUM_UNNECESSARY;
-+                      skb->proto_data_valid = 1;
-+              } else {
-+                      skb->ip_summed = CHECKSUM_NONE;
-+                      skb->proto_data_valid = 0;
-+              }
-+              skb->proto_csum_blank = !!(txp->flags & NETTXF_csum_blank);
 +
-+              netbk_fill_frags(skb);
++#define CI_TRACE_HEX32(integer)                                               \
++  ci_log("%s:%d:%s] " #integer "=0x%x",                                 \
++         __FILE__, __LINE__, __FUNCTION__, ((ci_uint32)integer))
 +
-+              skb->dev      = netif->dev;
-+              skb->protocol = eth_type_trans(skb, skb->dev);
 +
-+              netif->stats.rx_bytes += skb->len;
-+              netif->stats.rx_packets++;
++#define CI_TRACE_HEX64(integer)                                               \
++  ci_log("%s:%d:%s] " #integer "=0x%llx",                               \
++         __FILE__, __LINE__, __FUNCTION__, ((ci_uint64)integer))
 +
-+              if (unlikely(netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB) &&
-+                  unlikely(skb_linearize(skb))) {
-+                      DPRINTK("Can't linearize skb in net_tx_action.\n");
-+                      kfree_skb(skb);
-+                      continue;
-+              }
 +
-+              netif_rx(skb);
-+              netif->dev->last_rx = jiffies;
-+      }
++#define CI_TRACE_PTR(pointer)                                         \
++  ci_log("%s:%d:%s] " #pointer "=0x%p",                                 \
++         __FILE__, __LINE__, __FUNCTION__, (pointer))
++
++
++#define CI_TRACE_STRING(string)                                               \
++  ci_log("%s:%d:%s] " #string "=%s",                                    \
++         __FILE__, __LINE__, __FUNCTION__, (string))
++
++
++#define CI_TRACE_MAC(mac)                                             \
++  ci_log("%s:%d:%s] " #mac "=" CI_MAC_PRINTF_FORMAT,                    \
++         __FILE__, __LINE__, __FUNCTION__, CI_MAC_PRINTF_ARGS(mac))
++
++
++#define CI_TRACE_IP(ip_be32)                                          \
++  ci_log("%s:%d:%s] " #ip_be32 "=" CI_IP_PRINTF_FORMAT, __FILE__,       \
++         __LINE__, __FUNCTION__, CI_IP_PRINTF_ARGS(&(ip_be32)))
++
++
++#define CI_TRACE_ARP(arp_pkt)                                           \
++  ci_log("%s:%d:%s]\n"CI_ARP_PRINTF_FORMAT,                             \
++         __FILE__, __LINE__, __FUNCTION__, CI_ARP_PRINTF_ARGS(arp_pkt))
++
++#endif  /* NDEBUG */
++
++#define ci_check(exp) \
++        _ci_check(exp, __FILE__, __LINE__)
++
++#define ci_assert(exp) \
++        _ci_assert(exp, __FILE__, __LINE__)
++
++#define ci_verify(exp) \
++        _ci_verify(exp, __FILE__, __LINE__)
++
++#define ci_assert_equal(exp1, exp2) \
++        _ci_assert_equal(exp1, exp2, __FILE__, __LINE__)
++
++#define ci_assert_equal_msg(exp1, exp2, msg) \
++        _ci_assert_equal_msg(exp1, exp2, msg, __FILE__, __LINE__)
++
++#define ci_assert_nequal(exp1, exp2) \
++        _ci_assert_nequal(exp1, exp2, __FILE__, __LINE__)
++
++#define ci_assert_le(exp1, exp2) \
++        _ci_assert_le(exp1, exp2, __FILE__, __LINE__)
++
++#define ci_assert_lt(exp1, exp2) \
++        _ci_assert_lt(exp1, exp2, __FILE__, __LINE__)
++
++#define ci_assert_ge(exp1, exp2) \
++        _ci_assert_ge(exp1, exp2, __FILE__, __LINE__)
++
++#define ci_assert_gt(exp1, exp2) \
++        _ci_assert_gt(exp1, exp2, __FILE__, __LINE__)
++
++#define ci_assert_impl(exp1, exp2) \
++        _ci_assert_impl(exp1, exp2, __FILE__, __LINE__)
 +
-+      if (netbk_copy_skb_mode == NETBK_DELAYED_COPY_SKB &&
-+          !list_empty(&pending_inuse_head)) {
-+              struct netbk_tx_pending_inuse *oldest;
++#define ci_assert_equiv(exp1, exp2) \
++        _ci_assert_equiv(exp1, exp2, __FILE__, __LINE__)
 +
-+              oldest = list_entry(pending_inuse_head.next,
-+                                  struct netbk_tx_pending_inuse, list);
-+              mod_timer(&netbk_tx_pending_timer, oldest->alloc_time + HZ);
-+      }
-+}
 +
-+static void netif_idx_release(u16 pending_idx)
-+{
-+      static DEFINE_SPINLOCK(_lock);
-+      unsigned long flags;
++#define CI_TEST(exp)                            \
++  do{                                           \
++    if( CI_UNLIKELY(!(exp)) )                   \
++      ci_fail(("CI_TEST(%s)", #exp));           \
++  }while(0)
 +
-+      spin_lock_irqsave(&_lock, flags);
-+      dealloc_ring[MASK_PEND_IDX(dealloc_prod)] = pending_idx;
-+      /* Sync with net_tx_action_dealloc: insert idx /then/ incr producer. */
-+      smp_wmb();
-+      dealloc_prod++;
-+      spin_unlock_irqrestore(&_lock, flags);
 +
-+      tasklet_schedule(&net_tx_tasklet);
-+}
++#define CI_TRY(exp)                           \
++  do{                                         \
++    int _trc;                                 \
++    _trc=(exp);                                       \
++    if( CI_UNLIKELY(_trc < 0) )                       \
++      ci_sys_fail(#exp, _trc);                        \
++  }while(0)
 +
-+static void netif_page_release(struct page *page)
-+{
-+      netif_idx_release(netif_page_index(page));
-+}
 +
-+irqreturn_t netif_be_int(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+      netif_t *netif = dev_id;
++#define CI_TRY_RET(exp)                                                        \
++  do{                                                                  \
++    int _trc;                                                          \
++    _trc=(exp);                                                                \
++    if( CI_UNLIKELY(_trc < 0) ) {                                      \
++      ci_log("%s returned %d at %s:%d", #exp, _trc, __FILE__, __LINE__); \
++      return _trc;                                                     \
++    }                                                                  \
++  }while(0)
 +
-+      add_to_net_schedule_list_tail(netif);
-+      maybe_schedule_tx_action();
++#define CI_LOGLEVEL_TRY_RET(logfn, exp)                                    \
++  do{                                                                  \
++    int _trc;                                                          \
++    _trc=(exp);                                                                \
++    if( CI_UNLIKELY(_trc < 0) ) {                                      \
++      logfn (ci_log("%s returned %d at %s:%d", #exp, _trc, __FILE__, __LINE__)); \
++      return _trc;                                                     \
++    }                                                                  \
++  }while(0)
 +
-+      if (netif_schedulable(netif) && !netbk_queue_full(netif))
-+              netif_wake_queue(netif->dev);
 +
-+      return IRQ_HANDLED;
-+}
++#define CI_SOCK_TRY(exp)                      \
++  do{                                         \
++    ci_sock_err_t _trc;                               \
++    _trc=(exp);                                       \
++    if( CI_UNLIKELY(!ci_sock_errok(_trc)) )   \
++      ci_sys_fail(#exp, _trc.val);            \
++  }while(0)
 +
-+static void make_tx_response(netif_t *netif, 
-+                           netif_tx_request_t *txp,
-+                           s8       st)
-+{
-+      RING_IDX i = netif->tx.rsp_prod_pvt;
-+      netif_tx_response_t *resp;
-+      int notify;
 +
-+      resp = RING_GET_RESPONSE(&netif->tx, i);
-+      resp->id     = txp->id;
-+      resp->status = st;
++#define CI_SOCK_TRY_RET(exp)                                               \
++  do{                                                                      \
++    ci_sock_err_t _trc;                                                            \
++    _trc=(exp);                                                                    \
++    if( CI_UNLIKELY(!ci_sock_errok(_trc)) ) {                              \
++      ci_log("%s returned %d at %s:%d", #exp, _trc.val, __FILE__, __LINE__); \
++      return ci_sock_errcode(_trc);                                        \
++    }                                                                      \
++  }while(0)
 +
-+      if (txp->flags & NETTXF_extra_info)
-+              RING_GET_RESPONSE(&netif->tx, ++i)->status = NETIF_RSP_NULL;
 +
-+      netif->tx.rsp_prod_pvt = ++i;
-+      RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(&netif->tx, notify);
-+      if (notify)
-+              notify_remote_via_irq(netif->irq);
++#define CI_SOCK_TRY_SOCK_RET(exp)                                          \
++  do{                                                                      \
++    ci_sock_err_t _trc;                                                            \
++    _trc=(exp);                                                                    \
++    if( CI_UNLIKELY(!ci_sock_errok(_trc)) ) {                              \
++      ci_log("%s returned %d at %s:%d", #exp, _trc.val, __FILE__, __LINE__); \
++      return _trc;                                                         \
++    }                                                                      \
++  }while(0)
++
++#endif  /* __CI_TOOLS_DEBUG_H__ */
++
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/tools/log.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/tools/log.h 2008-05-19 00:33:48.534943730 +0300
+@@ -0,0 +1,262 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+#ifdef CONFIG_XEN_NETDEV_PIPELINED_TRANSMITTER
-+      if (i == netif->tx.req_cons) {
-+              int more_to_do;
-+              RING_FINAL_CHECK_FOR_REQUESTS(&netif->tx, more_to_do);
-+              if (more_to_do)
-+                      add_to_net_schedule_list_tail(netif);
-+      }
-+#endif
-+}
++/*
++ * \author  djr
++ *  \brief  Functions for logging and pretty-printing.
++ *   \date  2002/08/07
++ */
 +
-+static netif_rx_response_t *make_rx_response(netif_t *netif, 
-+                                           u16      id, 
-+                                           s8       st,
-+                                           u16      offset,
-+                                           u16      size,
-+                                           u16      flags)
-+{
-+      RING_IDX i = netif->rx.rsp_prod_pvt;
-+      netif_rx_response_t *resp;
++/*! \cidoxg_include_ci_tools */
 +
-+      resp = RING_GET_RESPONSE(&netif->rx, i);
-+      resp->offset     = offset;
-+      resp->flags      = flags;
-+      resp->id         = id;
-+      resp->status     = (s16)size;
-+      if (st < 0)
-+              resp->status = (s16)st;
++#ifndef __CI_TOOLS_LOG_H__
++#define __CI_TOOLS_LOG_H__
 +
-+      netif->rx.rsp_prod_pvt = ++i;
++#include <stdarg.h>
 +
-+      return resp;
-+}
 +
-+#ifdef NETBE_DEBUG_INTERRUPT
-+static irqreturn_t netif_be_dbg(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+      struct list_head *ent;
-+      netif_t *netif;
-+      int i = 0;
++/**********************************************************************
++ * Logging.
++ */
 +
-+      printk(KERN_ALERT "netif_schedule_list:\n");
-+      spin_lock_irq(&net_schedule_list_lock);
++/* size of internal log buffer */ 
++#define  CI_LOG_MAX_LINE        512
++/* uses of ci_log must ensure that all trace messages are shorter than this */ 
++#define  CI_LOG_MAX_MSG_LENGTH        (CI_LOG_MAX_LINE-50)
 +
-+      list_for_each (ent, &net_schedule_list) {
-+              netif = list_entry(ent, netif_t, list);
-+              printk(KERN_ALERT " %d: private(rx_req_cons=%08x "
-+                     "rx_resp_prod=%08x\n",
-+                     i, netif->rx.req_cons, netif->rx.rsp_prod_pvt);
-+              printk(KERN_ALERT "   tx_req_cons=%08x tx_resp_prod=%08x)\n",
-+                     netif->tx.req_cons, netif->tx.rsp_prod_pvt);
-+              printk(KERN_ALERT "   shared(rx_req_prod=%08x "
-+                     "rx_resp_prod=%08x\n",
-+                     netif->rx.sring->req_prod, netif->rx.sring->rsp_prod);
-+              printk(KERN_ALERT "   rx_event=%08x tx_req_prod=%08x\n",
-+                     netif->rx.sring->rsp_event, netif->tx.sring->req_prod);
-+              printk(KERN_ALERT "   tx_resp_prod=%08x, tx_event=%08x)\n",
-+                     netif->tx.sring->rsp_prod, netif->tx.sring->rsp_event);
-+              i++;
-+      }
++extern void ci_vlog(const char* fmt, va_list args)  CI_HF;
++extern void ci_log(const char* fmt, ...) CI_PRINTF_LIKE(1,2) CI_HF;
 +
-+      spin_unlock_irq(&net_schedule_list_lock);
-+      printk(KERN_ALERT " ** End of netif_schedule_list **\n");
++  /*! Set the prefix for log messages.
++  **
++  ** Uses the storage pointed to by \em prefix.  Therefore \em prefix must
++  ** be allocated on the heap, or statically.
++  */
++extern void ci_set_log_prefix(const char* prefix)  CI_HF;
++
++typedef void (*ci_log_fn_t)(const char* msg);
++extern ci_log_fn_t  ci_log_fn  CI_HV;
++
++/* Log functions. */
++extern void ci_log_null(const char* msg) CI_HF;
++extern void ci_log_stderr(const char* msg) CI_HF;
++extern void ci_log_stdout(const char* msg) CI_HF;
++extern void ci_log_syslog(const char* msg) CI_HF;
++
++/*! Call the following to install special logging behaviours. */
++extern void ci_log_buffer_till_fail(void) CI_HF;
++extern void ci_log_buffer_till_exit(void) CI_HF;
++
++extern void __ci_log_unique(const char* msg) CI_HF;
++extern ci_log_fn_t __ci_log_unique_fn CI_HV;
++ci_inline void ci_log_uniquify(void) {
++  if( ci_log_fn != __ci_log_unique ) {
++    __ci_log_unique_fn = ci_log_fn;
++    ci_log_fn = __ci_log_unique;
++  }
++}
 +
-+      return IRQ_HANDLED;
++extern void ci_log_file(const char* msg) CI_HF;
++extern int  ci_log_file_fd CI_HV;
++
++extern void __ci_log_nth(const char* msg) CI_HF;
++extern ci_log_fn_t __ci_log_nth_fn CI_HV;
++extern int  ci_log_nth_n CI_HV;  /* default 100 */
++ci_inline void ci_log_nth(void) {
++  if( ci_log_fn != __ci_log_nth ) {
++    __ci_log_nth_fn = ci_log_fn;
++    ci_log_fn = __ci_log_nth;
++  }
 +}
++
++extern int  ci_log_level  CI_HV;
++
++extern int  ci_log_options  CI_HV;
++#define CI_LOG_PID            0x1
++#define CI_LOG_TID            0x2
++#define CI_LOG_TIME           0x4
++#define CI_LOG_DELTA          0x8
++
++/**********************************************************************
++ * Used to define which mode we are in
++ */
++#if (defined(_WIN32) && !defined(__KERNEL__))
++typedef enum {
++  ci_log_md_NULL=0,
++    ci_log_md_ioctl,
++    ci_log_md_stderr,
++    ci_log_md_stdout,
++    ci_log_md_file,
++    ci_log_md_serial,
++    ci_log_md_syslog,
++    ci_log_md_pidfile
++} ci_log_mode_t;
++extern ci_log_mode_t ci_log_mode;
 +#endif
 +
-+static int __init netback_init(void)
-+{
-+      int i;
-+      struct page *page;
++/**********************************************************************
++ * Pretty-printing.
++ */
 +
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++extern char ci_printable_char(char c) CI_HF;
 +
-+      /* We can increase reservation by this much in net_rx_action(). */
-+      balloon_update_driver_allowance(NET_RX_RING_SIZE);
++extern void (*ci_hex_dump_formatter)(char* buf, const ci_octet* s,
++                                   int i, int off, int len) CI_HV;
++extern void ci_hex_dump_format_octets(char*,const ci_octet*,int,int,int) CI_HF;
++extern void ci_hex_dump_format_dwords(char*,const ci_octet*,int,int,int) CI_HF;
 +
-+      skb_queue_head_init(&rx_queue);
-+      skb_queue_head_init(&tx_queue);
++extern void ci_hex_dump_row(char* buf, volatile const void* s, int len,
++                          ci_ptr_arith_t address) CI_HF;
++  /*!< A row contains up to 16 bytes.  Row starts at [address & 15u], so
++  ** therefore [len + (address & 15u)] must be <= 16.
++  */
 +
-+      init_timer(&net_timer);
-+      net_timer.data = 0;
-+      net_timer.function = net_alarm;
++extern void ci_hex_dump(ci_log_fn_t, volatile const void*,
++                      int len, ci_ptr_arith_t address) CI_HF;
 +
-+      init_timer(&netbk_tx_pending_timer);
-+      netbk_tx_pending_timer.data = 0;
-+      netbk_tx_pending_timer.function = netbk_tx_pending_timeout;
++extern int  ci_hex_dump_to_raw(const char* src_hex, void* buf,
++                             unsigned* addr_out_opt, int* skip)  CI_HF;
++  /*!< Recovers raw data from a single line of a hex dump.  [buf] must be at
++  ** least 16 bytes long.  Returns the number of bytes written to [buf] (in
++  ** range 1 -> 16), or -1 if [src_hex] doesn't contain hex data.  Does not
++  ** cope with missing bytes at the start of a line.
++  */
 +
-+      mmap_pages = alloc_empty_pages_and_pagevec(MAX_PENDING_REQS);
-+      if (mmap_pages == NULL) {
-+              printk("%s: out of memory\n", __FUNCTION__);
-+              return -ENOMEM;
-+      }
++extern int ci_format_eth_addr(char* buf, const void* eth_mac_addr,
++                            char sep)  CI_HF;
++  /*!< This will write 18 characters to <buf> including terminating null.
++  ** Returns number of bytes written excluding null.  If [sep] is zero, ':'
++  ** is used.
++  */
 +
-+      for (i = 0; i < MAX_PENDING_REQS; i++) {
-+              page = mmap_pages[i];
-+              SetPageForeign(page, netif_page_release);
-+              netif_page_index(page) = i;
-+              INIT_LIST_HEAD(&pending_inuse[i].list);
-+      }
++extern int ci_parse_eth_addr(void* eth_mac_addr,
++                           const char* str, char sep) CI_HF;
++  /*!< If [sep] is zero, absolutely any separator is accepted (even
++  ** inconsistent separators).  Returns 0 on success, -1 on error.
++  */
 +
-+      pending_cons = 0;
-+      pending_prod = MAX_PENDING_REQS;
-+      for (i = 0; i < MAX_PENDING_REQS; i++)
-+              pending_ring[i] = i;
++extern int ci_format_ip4_addr(char* buf, unsigned addr_be32) CI_HF;
++  /*!< Formats the IP address (in network endian) in dotted-quad.  Returns
++  ** the number of bytes written (up to 15), excluding the null.  [buf]
++  ** must be at least 16 bytes long.
++  */
 +
-+      spin_lock_init(&net_schedule_list_lock);
-+      INIT_LIST_HEAD(&net_schedule_list);
 +
-+      netbk_copy_skb_mode = NETBK_DONT_COPY_SKB;
-+      if (MODPARM_copy_skb) {
-+              if (HYPERVISOR_grant_table_op(GNTTABOP_unmap_and_replace,
-+                                            NULL, 0))
-+                      netbk_copy_skb_mode = NETBK_ALWAYS_COPY_SKB;
-+              else
-+                      netbk_copy_skb_mode = NETBK_DELAYED_COPY_SKB;
-+      }
++/**********************************************************************
++ * Error checking.
++ */
 +
-+      netif_accel_init();
++extern void (*ci_fail_stop_fn)(void) CI_HV;
 +
-+      netif_xenbus_init();
++extern void ci_fail_stop(void) CI_HF;
++extern void ci_fail_hang(void) CI_HF;
++extern void ci_fail_bomb(void) CI_HF;
++extern void ci_backtrace(void) CI_HF;
 +
-+#ifdef NETBE_DEBUG_INTERRUPT
-+      (void)bind_virq_to_irqhandler(VIRQ_DEBUG,
-+                                    0,
-+                                    netif_be_dbg,
-+                                    SA_SHIRQ, 
-+                                    "net-be-dbg",
-+                                    &netif_be_dbg);
++#if defined __linux__ && !defined __KERNEL__
++extern void ci_fail_abort (void) CI_HF;
 +#endif
 +
-+      return 0;
-+}
++#ifdef __GNUC__
++extern void
++__ci_fail(const char*, ...) CI_PRINTF_LIKE(1,2) CI_HF;
++#else
++# if _PREFAST_
++  extern void _declspec(noreturn) __ci_fail(const char* fmt, ...);
++# else 
++  extern void __ci_fail(const char* fmt, ...);
++# endif
 +
-+module_init(netback_init);
++#endif
 +
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/netback/xenbus.c linux-2.6.18-xen.hg/drivers/xen/netback/xenbus.c
---- linux-2.6.18/drivers/xen/netback/xenbus.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/netback/xenbus.c   2007-12-23 11:15:34.054602273 +0100
-@@ -0,0 +1,452 @@
-+/*  Xenbus code for netif backend
-+    Copyright (C) 2005 Rusty Russell <rusty@rustcorp.com.au>
-+    Copyright (C) 2005 XenSource Ltd
++#define ci_warn(x)                                                       \
++  do{ ci_log("WARN at %s:%d", __FILE__, __LINE__); }while(0)
 +
-+    This program is free software; you can redistribute it and/or modify
-+    it under the terms of the GNU General Public License as published by
-+    the Free Software Foundation; either version 2 of the License, or
-+    (at your option) any later version.
++#define ci_fail(x)                                                       \
++  do{ ci_log("FAIL at %s:%d", __FILE__, __LINE__);  __ci_fail x; }while(0)
 +
-+    This program is distributed in the hope that it will be useful,
-+    but WITHOUT ANY WARRANTY; without even the implied warranty of
-+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-+    GNU General Public License for more details.
++extern void __ci_sys_fail(const char* fn, int rc,
++                        const char* file, int line) CI_HF;
++#define ci_sys_fail(fn, rc)  __ci_sys_fail(fn, rc, __FILE__, __LINE__)
 +
-+    You should have received a copy of the GNU General Public License
-+    along with this program; if not, write to the Free Software
-+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-+*/
++/**********************************************************************
++ * Logging to buffer (src/citools/log_buffer.c)
++ */
 +
-+#include <stdarg.h>
-+#include <linux/module.h>
-+#include <xen/xenbus.h>
-+#include "common.h"
++/*! Divert ci_log() messages to the log buffer
++ *  normally they go to the  system console */
++extern void ci_log_buffer_till_fail(void) CI_HF;
 +
-+#if 0
-+#undef DPRINTK
-+#define DPRINTK(fmt, args...) \
-+    printk("netback/xenbus (%s:%d) " fmt ".\n", __FUNCTION__, __LINE__, ##args)
-+#endif
++/*! Dump the contents of the log buffer to the system console */
++extern void ci_log_buffer_dump(void) CI_HF;
 +
 +
-+static int connect_rings(struct backend_info *);
-+static void connect(struct backend_info *);
-+static void backend_create_netif(struct backend_info *be);
++/**********************************************************************
++ * Some useful pretty-printing.
++ */
 +
-+static int netback_remove(struct xenbus_device *dev)
-+{
-+      struct backend_info *be = dev->dev.driver_data;
++#ifdef  __linux__
++# define CI_SOCKCALL_FLAGS_FMT        "%s%s%s%s%s%s%s%s%s%s%s"
 +
-+      netback_remove_accelerators(be, dev);
++# define CI_SOCKCALL_FLAGS_PRI_ARG(x)         \
++  (((x) & MSG_OOB         ) ? "OOB "         :""),    \
++  (((x) & MSG_PEEK        ) ? "PEEK "        :""),    \
++  (((x) & MSG_DONTROUTE   ) ? "DONTROUTE "   :""),    \
++  (((x) & MSG_EOR         ) ? "EOR "         :""),    \
++  (((x) & MSG_CTRUNC      ) ? "CTRUNC "      :""),    \
++  (((x) & MSG_TRUNC       ) ? "TRUNC "       :""),    \
++  (((x) & MSG_WAITALL     ) ? "WAITALL "     :""),    \
++  (((x) & MSG_DONTWAIT    ) ? "DONTWAIT "    :""),    \
++  (((x) & MSG_NOSIGNAL    ) ? "NOSIGNAL "    :""),    \
++  (((x) & MSG_ERRQUEUE    ) ? "ERRQUEUE "    :""),    \
++  (((x) & MSG_CONFIRM     ) ? "CONFIRM "     :"")
++#endif
 +
-+      if (be->netif) {
-+              netif_disconnect(be->netif);
-+              be->netif = NULL;
-+      }
-+      kfree(be);
-+      dev->dev.driver_data = NULL;
-+      return 0;
-+}
++#ifdef  _WIN32
++# define CI_SOCKCALL_FLAGS_FMT        "%s%s%s"
 +
++# define CI_SOCKCALL_FLAGS_PRI_ARG(x)         \
++  (((x) & MSG_OOB         ) ? "OOB "         :""),    \
++  (((x) & MSG_PEEK        ) ? "PEEK "        :""),    \
++  (((x) & MSG_DONTROUTE   ) ? "DONTROUTE "   :"")
++#endif
 +
-+/**
-+ * Entry point to this code when a new device is created.  Allocate the basic
-+ * structures and switch to InitWait.
++#ifdef  __sun__
++# define CI_SOCKCALL_FLAGS_FMT        "%s%s%s%s%s%s%s%s%s"
++
++# define CI_SOCKCALL_FLAGS_PRI_ARG(x)         \
++  (((x) & MSG_OOB         ) ? "OOB "         :""),    \
++  (((x) & MSG_PEEK        ) ? "PEEK "        :""),    \
++  (((x) & MSG_DONTROUTE   ) ? "DONTROUTE "   :""),    \
++  (((x) & MSG_EOR         ) ? "EOR "         :""),    \
++  (((x) & MSG_CTRUNC      ) ? "CTRUNC "      :""),    \
++  (((x) & MSG_TRUNC       ) ? "TRUNC "       :""),    \
++  (((x) & MSG_WAITALL     ) ? "WAITALL "     :""),    \
++  (((x) & MSG_DONTWAIT    ) ? "DONTWAIT "    :""),    \
++  (((x) & MSG_NOTIFICATION) ? "NOTIFICATION" :"")
++#endif
++
++#endif  /* __CI_TOOLS_LOG_H__ */
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/tools/platform/gcc_x86.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/tools/platform/gcc_x86.h    2008-05-19 00:33:48.578946266 +0300
+@@ -0,0 +1,361 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
-+static int netback_probe(struct xenbus_device *dev,
-+                       const struct xenbus_device_id *id)
-+{
-+      const char *message;
-+      struct xenbus_transaction xbt;
-+      int err;
-+      int sg;
-+      struct backend_info *be = kzalloc(sizeof(struct backend_info),
-+                                        GFP_KERNEL);
-+      if (!be) {
-+              xenbus_dev_fatal(dev, -ENOMEM,
-+                               "allocating backend structure");
-+              return -ENOMEM;
-+      }
 +
-+      be->dev = dev;
-+      dev->dev.driver_data = be;
++/*! \cidoxg_include_ci_tools_platform  */
 +
-+      sg = 1;
-+      if (netbk_copy_skb_mode == NETBK_ALWAYS_COPY_SKB)
-+              sg = 0;
++#ifndef __CI_TOOLS_GCC_X86_H__
++#define __CI_TOOLS_GCC_X86_H__
 +
-+      do {
-+              err = xenbus_transaction_start(&xbt);
-+              if (err) {
-+                      xenbus_dev_fatal(dev, err, "starting transaction");
-+                      goto fail;
-+              }
 +
-+              err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", sg);
-+              if (err) {
-+                      message = "writing feature-sg";
-+                      goto abort_transaction;
-+              }
++/**********************************************************************
++ * Free-running cycle counters.
++ */
 +
-+              err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4",
-+                                  "%d", sg);
-+              if (err) {
-+                      message = "writing feature-gso-tcpv4";
-+                      goto abort_transaction;
-+              }
++#define CI_HAVE_FRC64
++#define CI_HAVE_FRC32
 +
-+              /* We support rx-copy path. */
-+              err = xenbus_printf(xbt, dev->nodename,
-+                                  "feature-rx-copy", "%d", 1);
-+              if (err) {
-+                      message = "writing feature-rx-copy";
-+                      goto abort_transaction;
-+              }
++#define ci_frc32(pval)  __asm__ __volatile__("rdtsc" : "=a" (*pval) : : "edx")
 +
-+              /*
-+               * We don't support rx-flip path (except old guests who don't
-+               * grok this feature flag).
-+               */
-+              err = xenbus_printf(xbt, dev->nodename,
-+                                  "feature-rx-flip", "%d", 0);
-+              if (err) {
-+                      message = "writing feature-rx-flip";
-+                      goto abort_transaction;
-+              }
++#if defined(__x86_64__)
++ci_inline void ci_frc64(ci_uint64* pval) {
++  /* temp fix until we figure how to get this out in one bite */         
++  ci_uint64 low, high;
++  __asm__ __volatile__("rdtsc" : "=a" (low) , "=d" (high));           
++  *pval = (high << 32) | low;
++}
 +
-+              err = xenbus_transaction_end(xbt, 0);
-+      } while (err == -EAGAIN);
++#else
++#define ci_frc64(pval)  __asm__ __volatile__("rdtsc" : "=A" (*pval))
++#endif
 +
-+      if (err) {
-+              xenbus_dev_fatal(dev, err, "completing transaction");
-+              goto fail;
-+      }
++#define ci_frc_flush()  /* ?? Need a pipeline barrier. */
 +
-+      netback_probe_accelerators(be, dev);
 +
-+      err = xenbus_switch_state(dev, XenbusStateInitWait);
-+      if (err)
-+              goto fail;
++/**********************************************************************
++ * Atomic integer.
++ */
 +
-+      /* This kicks hotplug scripts, so do it immediately. */
-+      backend_create_netif(be);
++/*
++** int  ci_atomic_read(a)         { return a->n;        }
++** void ci_atomic_set(a, v)       { a->n = v;           }
++** void ci_atomic_inc(a)          { ++a->n;             }
++** void ci_atomic_dec(a)          { --a->n;             }
++** int  ci_atomic_inc_and_test(a) { return ++a->n == 0; }
++** int  ci_atomic_dec_and_test(a) { return --a->n == 0; }
++** void ci_atomic_and(a, v)       { a->n &= v;          }
++** void ci_atomic_or(a, v)        { a->n |= v;          }
++*/
 +
-+      return 0;
++typedef struct { volatile ci_int32 n; } ci_atomic_t;
 +
-+abort_transaction:
-+      xenbus_transaction_end(xbt, 1);
-+      xenbus_dev_fatal(dev, err, "%s", message);
-+fail:
-+      DPRINTK("failed");
-+      netback_remove(dev);
-+      return err;
-+}
++#define CI_ATOMIC_INITIALISER(i)  {(i)}
 +
++static inline ci_int32  ci_atomic_read(const ci_atomic_t* a) { return a->n; }
++static inline void ci_atomic_set(ci_atomic_t* a, int v) { a->n = v; ci_wmb();   }
 +
-+/**
-+ * Handle the creation of the hotplug script environment.  We add the script
-+ * and vif variables to the environment, for the benefit of the vif-* hotplug
-+ * scripts.
-+ */
-+static int netback_uevent(struct xenbus_device *xdev, char **envp,
-+                        int num_envp, char *buffer, int buffer_size)
-+{
-+      struct backend_info *be = xdev->dev.driver_data;
-+      netif_t *netif = be->netif;
-+      int i = 0, length = 0;
-+      char *val;
++static inline void ci_atomic_inc(ci_atomic_t* a)
++{ __asm__ __volatile__("lock; incl %0" : "+m" (a->n)); }
 +
-+      DPRINTK("netback_uevent");
++ 
++static inline void ci_atomic_dec(ci_atomic_t* a)
++{ __asm__ __volatile__("lock; decl %0" : "+m" (a->n)); }
++
++static inline int ci_atomic_inc_and_test(ci_atomic_t* a) {
++  char r;
++  __asm__ __volatile__("lock; incl %0; sete %1"
++                     : "+m" (a->n), "=qm" (r));
++  return r;
++}
++
++static inline int ci_atomic_dec_and_test(ci_atomic_t* a) {
++  char r;
++  __asm__ __volatile__("lock; decl %0; sete %1"
++                     : "+m" (a->n), "=qm" (r));
++  return r;
++}
++
++ci_inline int
++ci_atomic_xadd (ci_atomic_t *a, int v) {
++   __asm__ ("lock xadd %0, %1" : "=r" (v), "+m" (a->n) : "0" (v));
++  return v;
++}
++ci_inline int
++ci_atomic_xchg (ci_atomic_t *a, int v) {
++   __asm__ ("lock xchg %0, %1" : "=r" (v), "+m" (a->n) : "0" (v));
++  return v;
++}
++
++ci_inline void ci_atomic32_or(volatile ci_uint32* p, ci_uint32 mask)
++{ __asm__ __volatile__("lock; orl %1, %0" : "+m" (*p) : "ir" (mask)); }
++
++ci_inline void ci_atomic32_and(volatile ci_uint32* p, ci_uint32 mask)
++{ __asm__ __volatile__("lock; andl %1, %0" : "+m" (*p) : "ir" (mask)); }
++
++ci_inline void ci_atomic32_add(volatile ci_uint32* p, ci_uint32 v)
++{ __asm__ __volatile__("lock; addl %1, %0" : "+m" (*p) : "ir" (v)); }
++
++#define ci_atomic_or(a, v)   ci_atomic32_or ((ci_uint32*) &(a)->n, (v))
++#define ci_atomic_and(a, v)  ci_atomic32_and((ci_uint32*) &(a)->n, (v))
++#define ci_atomic_add(a, v)  ci_atomic32_add((ci_uint32*) &(a)->n, (v))
++
++extern int ci_glibc_uses_nptl (void) CI_HF;
++extern int ci_glibc_nptl_broken(void) CI_HF;
++extern int ci_glibc_gs_get_is_multihreaded_offset (void) CI_HF;
++extern int ci_glibc_gs_is_multihreaded_offset CI_HV;
++
++#if !defined(__x86_64__)
++#ifdef __GLIBC__
++/* Returns non-zero if the calling process might be mulithreaded, returns 0 if
++ * it definitely isn't (i.e. if reimplementing this function for other
++ * architectures and platforms, you can safely just return 1).
++ */
++static inline int ci_is_multithreaded (void) {
++
++  while (1) {
++    if (ci_glibc_gs_is_multihreaded_offset >= 0) {
++      /* NPTL keeps a variable that tells us this hanging off gs (i.e. in thread-
++       * local storage); just return this
++       */
++      int r;
++      __asm__ __volatile__ ("movl %%gs:(%1), %0"
++                            : "=r" (r)
++                            : "r" (ci_glibc_gs_is_multihreaded_offset));
++      return r;
++    }
++
++    if (ci_glibc_gs_is_multihreaded_offset == -2) {
++      /* This means we've already determined that the libc version is NOT good
++       * for our funky "is multithreaded" hack
++       */
++      return 1;
++    }
++
++    /* If we get here, it means this is the first time the function has been
++     * called -- detect the libc version and go around again.
++     */
++    ci_glibc_gs_is_multihreaded_offset = ci_glibc_gs_get_is_multihreaded_offset ();
 +
-+      val = xenbus_read(XBT_NIL, xdev->nodename, "script", NULL);
-+      if (IS_ERR(val)) {
-+              int err = PTR_ERR(val);
-+              xenbus_dev_fatal(xdev, err, "reading script");
-+              return err;
-+      }
-+      else {
-+              add_uevent_var(envp, num_envp, &i, buffer, buffer_size,
-+                             &length, "script=%s", val);
-+              kfree(val);
-+      }
++    /* Go around again.  We do the test here rather than at the top so that we go
++     * quicker in the common the case
++     */
++  }
++}
 +
-+      add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-+                     "vif=%s", netif->dev->name);
++#else    /* def __GLIBC__ */
 +
-+      envp[i] = NULL;
++#define ci_is_multithreaded() 1 /* ?? Is the the POSIX way of finding out */
++                                /*    whether the appication is single */
++                                /*    threaded? */
 +
-+      return 0;
++#endif   /* def __GLIBC__ */
++
++#else    /* defined __x86_64__ */
++
++static inline int ci_is_multithreaded (void) {
++  /* Now easy way to tell on x86_64; so assume we're multithreaded */
++  return 1;
 +}
 +
++#endif    /* defined __x86_64__ */
 +
-+static void backend_create_netif(struct backend_info *be)
-+{
-+      int err;
-+      long handle;
-+      struct xenbus_device *dev = be->dev;
 +
-+      if (be->netif != NULL)
-+              return;
++/**********************************************************************
++ * Compare and swap.
++ */
 +
-+      err = xenbus_scanf(XBT_NIL, dev->nodename, "handle", "%li", &handle);
-+      if (err != 1) {
-+              xenbus_dev_fatal(dev, err, "reading handle");
-+              return;
-+      }
++#define CI_HAVE_COMPARE_AND_SWAP
 +
-+      be->netif = netif_alloc(dev->otherend_id, handle);
-+      if (IS_ERR(be->netif)) {
-+              err = PTR_ERR(be->netif);
-+              be->netif = NULL;
-+              xenbus_dev_fatal(dev, err, "creating interface");
-+              return;
-+      }
++ci_inline int ci_cas32_succeed(volatile ci_int32* p, ci_int32 oldval,
++                               ci_int32 newval) {
++  char ret;
++  ci_int32 prevval;
++  __asm__ __volatile__("lock; cmpxchgl %3, %1; sete %0"
++                     : "=q"(ret), "+m"(*p), "=a"(prevval)
++                     : "r"(newval), "a"(oldval));
++  return ret;
++}
 +
-+      kobject_uevent(&dev->dev.kobj, KOBJ_ONLINE);
++ci_inline int ci_cas32_fail(volatile ci_int32* p, ci_int32 oldval,
++                            ci_int32 newval) {
++  char ret;
++  ci_int32 prevval;
++  __asm__ __volatile__("lock; cmpxchgl %3, %1; setne %0"
++                     : "=q"(ret), "+m"(*p), "=a"(prevval)
++                     : "r"(newval), "a"(oldval));
++  return ret;
 +}
 +
++#ifdef __x86_64__
++ci_inline int ci_cas64_succeed(volatile ci_int64* p, ci_int64 oldval,
++                             ci_int64 newval) {
++  char ret;
++  ci_int64 prevval;
++  __asm__ __volatile__("lock; cmpxchgq %3, %1; sete %0"
++                     : "=q"(ret), "+m"(*p), "=a"(prevval)
++                     : "r"(newval), "a"(oldval));
++  return ret;
++}
++
++ci_inline int ci_cas64_fail(volatile ci_int64* p, ci_int64 oldval,
++                          ci_int64 newval) {
++  char ret;
++  ci_int64 prevval;
++  __asm__ __volatile__("lock; cmpxchgq %3, %1; setne %0"
++                     : "=q"(ret), "+m"(*p), "=a"(prevval)
++                     : "r"(newval), "a"(oldval));
++  return ret;
++}
++#endif
++
++ci_inline int ci_cas32u_succeed(volatile ci_uint32* p, ci_uint32 oldval, ci_uint32 newval) {
++  char ret;
++  ci_uint32 prevval;
++  __asm__ __volatile__("lock; cmpxchgl %3, %1; sete %0"
++                     : "=q"(ret), "+m"(*p), "=a"(prevval)
++                     : "r"(newval), "a"(oldval));
++  return ret;
++}
++
++ci_inline int ci_cas32u_fail(volatile ci_uint32* p, ci_uint32 oldval, ci_uint32 newval) {
++  char ret;
++  ci_uint32 prevval;
++  __asm__ __volatile__("lock; cmpxchgl %3, %1; setne %0"
++                     : "=q"(ret), "+m"(*p), "=a"(prevval)
++                     : "r"(newval), "a"(oldval));
++  return ret;
++}
++
++ci_inline int ci_cas64u_succeed(volatile ci_uint64* p, ci_uint64 oldval,
++                             ci_uint64 newval) {
++  char ret;
++  ci_uint64 prevval;
++  __asm__ __volatile__("lock; cmpxchgq %3, %1; sete %0"
++                     : "=q"(ret), "+m"(*p), "=a"(prevval)
++                     : "r"(newval), "a"(oldval));
++  return ret;
++}
++
++ci_inline int ci_cas64u_fail(volatile ci_uint64* p, ci_uint64 oldval,
++                          ci_uint64 newval) {
++  char ret;
++  ci_uint64 prevval;
++  __asm__ __volatile__("lock; cmpxchgq %3, %1; setne %0"
++                     : "=q"(ret), "+m"(*p), "=a"(prevval)
++                     : "r"(newval), "a"(oldval));
++  return ret;
++}
 +
-+/**
-+ * Callback received when the frontend's state changes.
-+ */
-+static void frontend_changed(struct xenbus_device *dev,
-+                           enum xenbus_state frontend_state)
-+{
-+      struct backend_info *be = dev->dev.driver_data;
++#ifdef __x86_64__
 +
-+      DPRINTK("%s", xenbus_strstate(frontend_state));
++# define ci_cas_uintptr_succeed(p,o,n)                                \
++    ci_cas64u_succeed((volatile ci_uint64*) (p), (o), (n))
++# define ci_cas_uintptr_fail(p,o,n)                           \
++    ci_cas64u_fail((volatile ci_uint64*) (p), (o), (n))
 +
-+      be->frontend_state = frontend_state;
++#else
 +
-+      switch (frontend_state) {
-+      case XenbusStateInitialising:
-+              if (dev->state == XenbusStateClosed) {
-+                      printk(KERN_INFO "%s: %s: prepare for reconnect\n",
-+                             __FUNCTION__, dev->nodename);
-+                      if (be->netif) {
-+                              netif_disconnect(be->netif);
-+                              be->netif = NULL;
-+                      }
-+                      xenbus_switch_state(dev, XenbusStateInitWait);
-+              }
-+              break;
++# define ci_cas_uintptr_succeed(p,o,n)                                \
++    ci_cas32u_succeed((volatile ci_uint32*) (p), (o), (n))
++# define ci_cas_uintptr_fail(p,o,n)                           \
++    ci_cas32u_fail((volatile ci_uint32*) (p), (o), (n))
 +
-+      case XenbusStateInitialised:
-+              break;
++#endif
 +
-+      case XenbusStateConnected:
-+              backend_create_netif(be);
-+              if (be->netif)
-+                      connect(be);
-+              break;
 +
-+      case XenbusStateClosing:
-+              xenbus_switch_state(dev, XenbusStateClosing);
-+              break;
++/**********************************************************************
++ * Atomic bit field.
++ */
 +
-+      case XenbusStateClosed:
-+              xenbus_switch_state(dev, XenbusStateClosed);
-+              if (xenbus_dev_is_online(dev))
-+                      break;
-+              /* fall through if not online */
-+      case XenbusStateUnknown:
-+              if (be->netif != NULL)
-+                      kobject_uevent(&dev->dev.kobj, KOBJ_OFFLINE);
-+              device_unregister(&dev->dev);
-+              break;
++typedef ci_uint32  ci_bits;
++#define CI_BITS_N                     32u
 +
-+      default:
-+              xenbus_dev_fatal(dev, -EINVAL, "saw state %d at frontend",
-+                               frontend_state);
-+              break;
-+      }
++#define CI_BITS_DECLARE(name, n)                      \
++  ci_bits name[((n) + CI_BITS_N - 1u) / CI_BITS_N]
++
++ci_inline void ci_bits_clear_all(volatile ci_bits* b, int n_bits)
++{ memset((void*) b, 0, (n_bits+CI_BITS_N-1u) / CI_BITS_N * sizeof(ci_bits)); }
++
++ci_inline void ci_bit_set(volatile ci_bits* b, int i) {
++  __asm__ __volatile__("lock; btsl %1, %0"
++                     : "=m" (*b)
++                     : "Ir" (i));
 +}
 +
++ci_inline void ci_bit_clear(volatile ci_bits* b, int i) {
++  __asm__ __volatile__("lock; btrl %1, %0"
++                     : "=m" (*b)
++                     : "Ir" (i));
++}
 +
-+static void xen_net_read_rate(struct xenbus_device *dev,
-+                            unsigned long *bytes, unsigned long *usec)
-+{
-+      char *s, *e;
-+      unsigned long b, u;
-+      char *ratestr;
++ci_inline int  ci_bit_test(volatile ci_bits* b, int i) {
++  char rc;
++  __asm__("btl %2, %1; setc %0"
++        : "=r" (rc)
++        : "m" (*b), "Ir" (i));
++  return rc;
++}
 +
-+      /* Default to unlimited bandwidth. */
-+      *bytes = ~0UL;
-+      *usec = 0;
++ci_inline int ci_bit_test_and_set(volatile ci_bits* b, int i) {
++  char rc;
++  __asm__ __volatile__("lock; btsl %2, %1; setc %0"
++                     : "=r" (rc), "+m" (*b)
++                     : "Ir" (i));
++  return rc;
++}
 +
-+      ratestr = xenbus_read(XBT_NIL, dev->nodename, "rate", NULL);
-+      if (IS_ERR(ratestr))
-+              return;
++ci_inline int ci_bit_test_and_clear(volatile ci_bits* b, int i) {
++  char rc;
++  __asm__ __volatile__("lock; btrl %2, %1; setc %0"
++                     : "=r" (rc), "+m" (*b)
++                     : "Ir" (i));
++  return rc;
++}
 +
-+      s = ratestr;
-+      b = simple_strtoul(s, &e, 10);
-+      if ((s == e) || (*e != ','))
-+              goto fail;
++/* These mask ops only work within a single ci_bits word. */
++#define ci_bit_mask_set(b,m)  ci_atomic32_or((b), (m))
++#define ci_bit_mask_clear(b,m)        ci_atomic32_and((b), ~(m))
 +
-+      s = e + 1;
-+      u = simple_strtoul(s, &e, 10);
-+      if ((s == e) || (*e != '\0'))
-+              goto fail;
 +
-+      *bytes = b;
-+      *usec = u;
++/**********************************************************************
++ * Misc.
++ */
 +
-+      kfree(ratestr);
-+      return;
++#if __GNUC__ >= 3
++# define ci_spinloop_pause()  __asm__("pause") 
++#else
++# define ci_spinloop_pause()  __asm__(".byte 0xf3, 0x90")
++#endif
 +
-+ fail:
-+      WPRINTK("Failed to parse network rate limit. Traffic unlimited.\n");
-+      kfree(ratestr);
-+}
 +
-+static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
-+{
-+      char *s, *e, *macstr;
-+      int i;
++#define CI_HAVE_ADDC32
++#define ci_add_carry32(sum, v)  __asm__("addl %1, %0 ;"                         \
++                                      "adcl $0, %0 ;"                   \
++                                      : "=r" (sum)                      \
++                                      : "g" ((ci_uint32) v), "0" (sum))
 +
-+      macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
-+      if (IS_ERR(macstr))
-+              return PTR_ERR(macstr);
 +
-+      for (i = 0; i < ETH_ALEN; i++) {
-+              mac[i] = simple_strtoul(s, &e, 16);
-+              if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
-+                      kfree(macstr);
-+                      return -ENOENT;
-+              }
-+              s = e+1;
-+      }
++#endif  /* __CI_TOOLS_GCC_X86_H__ */
 +
-+      kfree(macstr);
-+      return 0;
-+}
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/tools/platform/linux_kernel.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/tools/platform/linux_kernel.h       2008-05-19 00:33:48.578946266 +0300
+@@ -0,0 +1,362 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static void connect(struct backend_info *be)
-+{
-+      int err;
-+      struct xenbus_device *dev = be->dev;
 +
-+      err = connect_rings(be);
-+      if (err)
-+              return;
++/*! \cidoxg_include_ci_tools_platform  */
 +
-+      err = xen_net_read_mac(dev, be->netif->fe_dev_addr);
-+      if (err) {
-+              xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
-+              return;
-+      }
++#ifndef __CI_TOOLS_LINUX_KERNEL_H__
++#define __CI_TOOLS_LINUX_KERNEL_H__
 +
-+      xen_net_read_rate(dev, &be->netif->credit_bytes,
-+                        &be->netif->credit_usec);
-+      be->netif->remaining_credit = be->netif->credit_bytes;
++/**********************************************************************
++ * Need to know the kernel version.
++ */
 +
-+      xenbus_switch_state(dev, XenbusStateConnected);
++#ifndef LINUX_VERSION_CODE
++# include <linux/version.h>
++# ifndef UTS_RELEASE
++   /* 2.6.18 onwards defines UTS_RELEASE in a separate header */
++#  include <linux/utsrelease.h>
++# endif
++#endif
 +
-+      netif_wake_queue(be->netif->dev);
-+}
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) || \
++    LINUX_VERSION_CODE >= KERNEL_VERSION(2,7,0)
++# error "Linux 2.6 required"
++#endif
 +
 +
-+static int connect_rings(struct backend_info *be)
-+{
-+      struct xenbus_device *dev = be->dev;
-+      unsigned long tx_ring_ref, rx_ring_ref;
-+      unsigned int evtchn, rx_copy;
-+      int err;
-+      int val;
++#include <linux/slab.h>     /* kmalloc / kfree */
++#include <linux/vmalloc.h>  /* vmalloc / vfree */
++#include <linux/interrupt.h>/* in_interrupt()  */
++#include <linux/in.h>
++#include <linux/in6.h>
++#include <linux/spinlock.h>
++#include <linux/highmem.h>
++#include <linux/smp_lock.h>
++#include <linux/ctype.h>
++#include <linux/uio.h>
++#include <asm/current.h>
++#include <asm/errno.h>
++#include <asm/kmap_types.h>
++#include <asm/semaphore.h>
 +
-+      DPRINTK("");
++#include <ci/tools/config.h>
 +
-+      err = xenbus_gather(XBT_NIL, dev->otherend,
-+                          "tx-ring-ref", "%lu", &tx_ring_ref,
-+                          "rx-ring-ref", "%lu", &rx_ring_ref,
-+                          "event-channel", "%u", &evtchn, NULL);
-+      if (err) {
-+              xenbus_dev_fatal(dev, err,
-+                               "reading %s/ring-ref and event-channel",
-+                               dev->otherend);
-+              return err;
-+      }
++#define ci_in_irq        in_irq
++#define ci_in_interrupt  in_interrupt
++#define ci_in_atomic     in_atomic
 +
-+      err = xenbus_scanf(XBT_NIL, dev->otherend, "request-rx-copy", "%u",
-+                         &rx_copy);
-+      if (err == -ENOENT) {
-+              err = 0;
-+              rx_copy = 0;
-+      }
-+      if (err < 0) {
-+              xenbus_dev_fatal(dev, err, "reading %s/request-rx-copy",
-+                               dev->otherend);
-+              return err;
-+      }
-+      be->netif->copying_receiver = !!rx_copy;
 +
-+      if (be->netif->dev->tx_queue_len != 0) {
-+              if (xenbus_scanf(XBT_NIL, dev->otherend,
-+                               "feature-rx-notify", "%d", &val) < 0)
-+                      val = 0;
-+              if (val)
-+                      be->netif->can_queue = 1;
-+              else
-+                      /* Must be non-zero for pfifo_fast to work. */
-+                      be->netif->dev->tx_queue_len = 1;
-+      }
++/**********************************************************************
++ * Misc stuff.
++ */
 +
-+      if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-sg", "%d", &val) < 0)
-+              val = 0;
-+      if (val) {
-+              be->netif->features |= NETIF_F_SG;
-+              be->netif->dev->features |= NETIF_F_SG;
-+      }
++#ifdef BUG
++# define  CI_BOMB     BUG
++#endif
 +
-+      if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-gso-tcpv4", "%d",
-+                       &val) < 0)
-+              val = 0;
-+      if (val) {
-+              be->netif->features |= NETIF_F_TSO;
-+              be->netif->dev->features |= NETIF_F_TSO;
-+      }
++ci_inline void* __ci_alloc(size_t n)
++{ return kmalloc(n, (in_interrupt() ? GFP_ATOMIC : GFP_KERNEL)); }
 +
-+      if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-no-csum-offload",
-+                       "%d", &val) < 0)
-+              val = 0;
-+      if (val) {
-+              be->netif->features &= ~NETIF_F_IP_CSUM;
-+              be->netif->dev->features &= ~NETIF_F_IP_CSUM;
-+      }
++ci_inline void* __ci_atomic_alloc(size_t n)
++{ return kmalloc(n, GFP_ATOMIC ); }
 +
-+      /* Map the shared frame, irq etc. */
-+      err = netif_map(be->netif, tx_ring_ref, rx_ring_ref, evtchn);
-+      if (err) {
-+              xenbus_dev_fatal(dev, err,
-+                               "mapping shared-frames %lu/%lu port %u",
-+                               tx_ring_ref, rx_ring_ref, evtchn);
-+              return err;
-+      }
-+      return 0;
-+}
++ci_inline void  __ci_free(void* p)     { return kfree(p);   }
++ci_inline void* __ci_vmalloc(size_t n) { return vmalloc(n); }
++ci_inline void  __ci_vfree(void* p)    { return vfree(p);   }
 +
 +
-+/* ** Driver Registration ** */
++#if CI_MEMLEAK_DEBUG_ALLOC_TABLE
++  #define ci_alloc(s)     ci_alloc_memleak_debug (s, __FILE__, __LINE__)
++  #define ci_atomic_alloc(s)  ci_atomic_alloc_memleak_debug(s, __FILE__, __LINE__)
++  #define ci_free         ci_free_memleak_debug
++  #define ci_vmalloc(s)   ci_vmalloc_memleak_debug (s, __FILE__,__LINE__)
++  #define ci_vfree        ci_vfree_memleak_debug
++  #define ci_alloc_fn     ci_alloc_fn_memleak_debug
++  #define ci_vmalloc_fn   ci_vmalloc_fn_memleak_debug
++#else /* !CI_MEMLEAK_DEBUG_ALLOC_TABLE */
++  #define ci_alloc_fn     __ci_alloc
++  #define ci_vmalloc_fn   __ci_vmalloc
++#endif 
 +
++#ifndef ci_alloc
++  #define ci_atomic_alloc __ci_atomic_alloc
++  #define ci_alloc        __ci_alloc
++  #define ci_free         __ci_free
++  #define ci_vmalloc      __ci_vmalloc
++  #define ci_vmalloc_fn   __ci_vmalloc
++  #define ci_vfree        __ci_vfree
++#endif
 +
-+static struct xenbus_device_id netback_ids[] = {
-+      { "vif" },
-+      { "" }
-+};
++#define ci_sprintf        sprintf
++#define ci_vsprintf       vsprintf
++#define ci_snprintf       snprintf
++#define ci_vsnprintf      vsnprintf
++#define ci_sscanf         sscanf
 +
 +
-+static struct xenbus_driver netback = {
-+      .name = "vif",
-+      .owner = THIS_MODULE,
-+      .ids = netback_ids,
-+      .probe = netback_probe,
-+      .remove = netback_remove,
-+      .uevent = netback_uevent,
-+      .otherend_changed = frontend_changed,
-+};
++#define CI_LOG_FN_DEFAULT  ci_log_syslog
 +
 +
-+void netif_xenbus_init(void)
-+{
-+      xenbus_register_backend(&netback);
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/netfront/accel.c linux-2.6.18-xen.hg/drivers/xen/netfront/accel.c
---- linux-2.6.18/drivers/xen/netfront/accel.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/netfront/accel.c   2007-12-23 11:15:34.057935783 +0100
-@@ -0,0 +1,833 @@
-+/******************************************************************************
-+ * Virtual network driver for conversing with remote driver backends.
++/*--------------------------------------------------------------------
 + *
-+ * Copyright (C) 2007 Solarflare Communications, Inc.
++ * irqs_disabled - needed for kmap helpers on some kernels 
 + *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
++ *--------------------------------------------------------------------*/
++#ifdef irqs_disabled
++# define ci_irqs_disabled irqs_disabled
++#else
++# if defined(__i386__) | defined(__x86_64__)
++#   define ci_irqs_disabled(x)                  \
++  ({                                            \
++    unsigned long flags;                        \
++    local_save_flags(flags);                    \
++    !(flags & (1<<9));                          \
++  })
++# else
++#  error "Need to implement irqs_disabled() for your architecture"
++# endif
++#endif
++
++
++/**********************************************************************
++ * kmap helpers. 
 + *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
++ * Use ci_k(un)map for code paths which are not in an atomic context.
++ * For atomic code you need to use ci_k(un)map_in_atomic. This will grab
++ * one of the per-CPU kmap slots.
 + *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
++ * NB in_interrupt != in_irq. If you don't know the difference then
++ * don't use kmap_in_atomic
++ *
++ * 2.4 allocates kmap slots by function. We are going to re-use the
++ * skb module's slot - we also use the same interlock
++ * 
++ * 2.6 allocates kmap slots by type as well as by function. We are
++ * going to use the currently (2.6.10) unsused SOFTIRQ slot 
 + *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
 + */
 +
-+#include <linux/netdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/list.h>
-+#include <linux/mutex.h>
++ci_inline void* ci_kmap(struct page *page) {
++  CI_DEBUG(if( ci_in_atomic() | ci_in_interrupt() | ci_in_irq() )  BUG());
++  return kmap(page);
++}
 +
-+#include <xen/xenbus.h>
++ci_inline void ci_kunmap(struct page *page) {
++  kunmap(page);
++}
 +
-+#include "netfront.h"
++#define CI_KM_SLOT KM_SOFTIRQ0
 +
-+#define DPRINTK(fmt, args...)                         \
-+      pr_debug("netfront/accel (%s:%d) " fmt,         \
-+             __FUNCTION__, __LINE__, ##args)
-+#define IPRINTK(fmt, args...)                         \
-+      printk(KERN_INFO "netfront/accel: " fmt, ##args)
-+#define WPRINTK(fmt, args...)                         \
-+      printk(KERN_WARNING "netfront/accel: " fmt, ##args)
 +
-+static int netfront_remove_accelerator(struct netfront_info *np,
-+                                     struct xenbus_device *dev);
-+static int netfront_load_accelerator(struct netfront_info *np, 
-+                                   struct xenbus_device *dev, 
-+                                   const char *frontend);
++typedef struct semaphore ci_semaphore_t;
 +
-+/*
-+ * List of all netfront accelerator plugin modules available.  Each
-+ * list entry is of type struct netfront_accelerator.
-+ */ 
-+static struct list_head accelerators_list;
++ci_inline void
++ci_sem_init (ci_semaphore_t *sem, int val) {
++  sema_init (sem, val);
++}
 +
-+/* Lock to protect access to accelerators_list */
-+static spinlock_t accelerators_lock;
++ci_inline void
++ci_sem_down (ci_semaphore_t *sem) {
++  down (sem);
++}
 +
-+/* Mutex to prevent concurrent loads and suspends, etc. */
-+DEFINE_MUTEX(accelerator_mutex);
++ci_inline int
++ci_sem_trydown (ci_semaphore_t *sem) {
++  return down_trylock (sem);
++}
 +
-+void netif_init_accel(void)
++ci_inline void
++ci_sem_up (ci_semaphore_t *sem) {
++  up (sem);
++}
++
++ci_inline int
++ci_sem_get_count(ci_semaphore_t *sem) {
++  return sem->count.counter;
++}
++
++ci_inline void* ci_kmap_in_atomic(struct page *page) 
 +{
-+      INIT_LIST_HEAD(&accelerators_list);
-+      spin_lock_init(&accelerators_lock);
++  CI_DEBUG(if( ci_in_irq() )  BUG());
++
++  /* iSCSI can call without in_interrupt() but with irqs_disabled()
++     and in a context that can't sleep, so we need to check that
++     too */
++  if(ci_in_interrupt() || ci_irqs_disabled())
++    return kmap_atomic(page, CI_KM_SLOT);
++  else
++    return kmap(page);
 +}
 +
-+void netif_exit_accel(void)
++ci_inline void ci_kunmap_in_atomic(struct page *page, void* kaddr) 
 +{
-+      struct netfront_accelerator *accelerator, *tmp;
-+      unsigned long flags;
++  CI_DEBUG(if( ci_in_irq() )  BUG());
 +
-+      spin_lock_irqsave(&accelerators_lock, flags);
++  /* iSCSI can call without in_interrupt() but with irqs_disabled()
++     and in a context that can't sleep, so we need to check that
++     too */
++  if(ci_in_interrupt() || ci_irqs_disabled())
++    kunmap_atomic(kaddr, CI_KM_SLOT);
++  else
++    kunmap(page);
++}
 +
-+      list_for_each_entry_safe(accelerator, tmp, &accelerators_list, link) {
-+              BUG_ON(!list_empty(&accelerator->vif_states));
++/**********************************************************************
++ * spinlock implementation: used by <ci/tools/spinlock.h>
++ */
 +
-+              list_del(&accelerator->link);
-+              kfree(accelerator->frontend);
-+              kfree(accelerator);
-+      }
++#define CI_HAVE_SPINLOCKS
 +
-+      spin_unlock_irqrestore(&accelerators_lock, flags);
-+}
++typedef ci_uintptr_t                          ci_lock_holder_t;
++#define ci_lock_thisthread            (ci_lock_holder_t)current                       
++#define ci_lock_no_holder     (ci_lock_holder_t)NULL
 +
++typedef spinlock_t                    ci_lock_i;
++typedef spinlock_t                    ci_irqlock_i;
++typedef unsigned long                 ci_irqlock_state_t;
 +
-+/* 
-+ * Watch the configured accelerator and change plugin if it's modified 
++#define IRQLOCK_CYCLES  500000
++
++#define ci_lock_ctor_i(l)             spin_lock_init(l)
++#define ci_lock_dtor_i(l)             do{}while(0)
++#define ci_lock_lock_i(l)             spin_lock(l)
++#define ci_lock_trylock_i(l)          spin_trylock(l)
++#define ci_lock_unlock_i(l)           spin_unlock(l)
++
++#define ci_irqlock_ctor_i(l)          spin_lock_init(l)
++#define ci_irqlock_dtor_i(l)          do{}while(0)
++#define ci_irqlock_lock_i(l,s)                spin_lock_irqsave(l,*(s))
++#define ci_irqlock_unlock_i(l,s)      spin_unlock_irqrestore(l, *(s))
++
++
++/**********************************************************************
++ * register access
 + */
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-+static void accel_watch_work(struct work_struct *context)
-+#else
-+static void accel_watch_work(void *context)
-+#endif
-+{
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-+      struct netfront_accel_vif_state *vif_state = 
-+              container_of(context, struct netfront_accel_vif_state, 
-+                           accel_work);
++
++#include <asm/io.h>
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9)
++typedef volatile void __iomem*        ioaddr_t;
 +#else
-+        struct netfront_accel_vif_state *vif_state = 
-+              (struct netfront_accel_vif_state *)context;
++typedef unsigned long ioaddr_t;
 +#endif
-+      struct netfront_info *np = vif_state->np;
-+      char *accel_frontend;
-+      int accel_len, rc = -1;
 +
-+      mutex_lock(&accelerator_mutex);
 +
-+      accel_frontend = xenbus_read(XBT_NIL, np->xbdev->otherend, 
-+                                   "accel-frontend", &accel_len);
-+      if (IS_ERR(accel_frontend)) {
-+              accel_frontend = NULL;
-+              netfront_remove_accelerator(np, np->xbdev);
-+      } else {
-+              /* If this is the first time, request the accelerator,
-+                 otherwise only request one if it has changed */
-+              if (vif_state->accel_frontend == NULL) {
-+                      rc = netfront_load_accelerator(np, np->xbdev, 
-+                                                     accel_frontend);
-+              } else {
-+                      if (strncmp(vif_state->accel_frontend, accel_frontend,
-+                                  accel_len)) {
-+                              netfront_remove_accelerator(np, np->xbdev);
-+                              rc = netfront_load_accelerator(np, np->xbdev, 
-+                                                             accel_frontend);
-+                      }
-+              }
-+      }
 +
-+      /* Get rid of previous state and replace with the new name */
-+      if (vif_state->accel_frontend != NULL)
-+              kfree(vif_state->accel_frontend);
-+      vif_state->accel_frontend = accel_frontend;
++/**********************************************************************
++ * thread implementation -- kernel dependancies probably should be
++ * moved to driver/linux_kernel.h
++ */
 +
-+      mutex_unlock(&accelerator_mutex);
++#define ci_linux_daemonize(name) daemonize(name)
 +
-+      if (rc == 0) {
-+              DPRINTK("requesting module %s\n", accel_frontend);
-+              request_module("%s", accel_frontend);
-+              /*
-+               * Module should now call netfront_accelerator_loaded() once
-+               * it's up and running, and we can continue from there 
-+               */
-+      }
-+}
++#include <linux/workqueue.h>
 +
 +
-+static void accel_watch_changed(struct xenbus_watch *watch,
-+                              const char **vec, unsigned int len)
-+{
-+      struct netfront_accel_vif_state *vif_state = 
-+              container_of(watch, struct netfront_accel_vif_state,
-+                           accel_watch);
-+      schedule_work(&vif_state->accel_work);
-+}
++typedef struct {
++  void*                       (*fn)(void* arg);
++  void*                       arg;
++  const char*         name;
++  int                 thrd_id;
++  struct completion   exit_event;
++  struct work_struct  keventd_witem;
++} ci_kernel_thread_t;
 +
 +
-+void netfront_accelerator_add_watch(struct netfront_info *np)
-+{
-+      int err;
-+      
-+      /* Check we're not trying to overwrite an existing watch */
-+      BUG_ON(np->accel_vif_state.accel_watch.node != NULL);
++typedef ci_kernel_thread_t* cithread_t;
 +
-+      /* Get a watch on the accelerator plugin */
-+      err = xenbus_watch_path2(np->xbdev, np->xbdev->otherend, 
-+                               "accel-frontend", 
-+                               &np->accel_vif_state.accel_watch,
-+                               accel_watch_changed);
-+      if (err) {
-+              DPRINTK("%s: Failed to register accel watch: %d\n",
-+                        __FUNCTION__, err);
-+              np->accel_vif_state.accel_watch.node = NULL;
-+        }
-+}
 +
++extern int cithread_create(cithread_t* tid, void* (*fn)(void*), void* arg,
++                         const char* name);
++extern int cithread_detach(cithread_t kt);
++extern int cithread_join(cithread_t kt);
 +
-+static
-+void netfront_accelerator_remove_watch(struct netfront_info *np)
-+{
-+      struct netfront_accel_vif_state *vif_state = &np->accel_vif_state;
 +
-+      /* Get rid of watch on accelerator plugin */
-+      if (vif_state->accel_watch.node != NULL) {
-+              unregister_xenbus_watch(&vif_state->accel_watch);
-+              kfree(vif_state->accel_watch.node);
-+              vif_state->accel_watch.node = NULL;
++/* Kernel sysctl variables. */
++extern int sysctl_tcp_wmem[3];
++extern int sysctl_tcp_rmem[3];
++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
++#define LINUX_HAS_SYSCTL_MEM_MAX
++extern ci_uint32 sysctl_wmem_max;
++extern ci_uint32 sysctl_rmem_max;
++#endif
 +
-+              flush_scheduled_work();
 +
-+              /* Clean up any state left from watch */
-+              if (vif_state->accel_frontend != NULL) {
-+                      kfree(vif_state->accel_frontend);
-+                      vif_state->accel_frontend = NULL;
-+              }
-+      }       
-+}
++/*--------------------------------------------------------------------
++ *
++ * ci_bigbuf_t: An abstraction of a large buffer.  Needed because in the
++ * Linux kernel, large buffers need to be allocated with vmalloc(), whereas
++ * smaller buffers should use kmalloc().  This abstraction chooses the
++ * appropriate mechansim.
++ *
++ *--------------------------------------------------------------------*/
 +
++typedef struct {
++  char*               p;
++  int         is_vmalloc;
++} ci_bigbuf_t;
 +
-+/* 
-+ * Initialise the accel_vif_state field in the netfront state
-+ */ 
-+void init_accelerator_vif(struct netfront_info *np,
-+                        struct xenbus_device *dev)
-+{
-+      np->accelerator = NULL;
 +
-+      /* It's assumed that these things don't change */
-+      np->accel_vif_state.np = np;
-+      np->accel_vif_state.dev = dev;
++ci_inline int ci_bigbuf_alloc(ci_bigbuf_t* bb, size_t bytes) {
++  if( bytes >= CI_PAGE_SIZE && ! ci_in_atomic() ) {
++    bb->is_vmalloc = 1;
++    if( (bb->p = vmalloc(bytes)) )  return 0;
++  }
++  bb->is_vmalloc = 0;
++  bb->p = kmalloc(bytes, ci_in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
++  return bb->p ? 0 : -ENOMEM;
++}
 +
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-+      INIT_WORK(&np->accel_vif_state.accel_work, accel_watch_work);
-+#else
-+      INIT_WORK(&np->accel_vif_state.accel_work, accel_watch_work, 
-+                &np->accel_vif_state);
-+#endif
++ci_inline void ci_bigbuf_free(ci_bigbuf_t* bb) {
++  if( bb->is_vmalloc )  vfree(bb->p);
++  else                  kfree(bb->p);
 +}
 +
++ci_inline char* ci_bigbuf_ptr(ci_bigbuf_t* bb)
++{ return bb->p; }
 +
-+/*
-+ * Compare a frontend description string against an accelerator to see
-+ * if they match.  Would ultimately be nice to replace the string with
-+ * a unique numeric identifier for each accelerator.
++/**********************************************************************
++ * struct iovec abstraction (for Windows port)
 + */
-+static int match_accelerator(const char *frontend, 
-+                           struct netfront_accelerator *accelerator)
++
++typedef struct iovec ci_iovec;
++
++/* Accessors for buffer/length */
++#define CI_IOVEC_BASE(i) ((i)->iov_base)
++#define CI_IOVEC_LEN(i)  ((i)->iov_len)
++
++/**********************************************************************
++ * Signals
++ */
++
++ci_inline void
++ci_send_sig(int signum)
 +{
-+      return strcmp(frontend, accelerator->frontend) == 0;
++  send_sig(signum, current, 0);
 +}
 +
++#endif  /* __CI_TOOLS_LINUX_KERNEL_H__ */
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netback/ci/tools/sysdep.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netback/ci/tools/sysdep.h      2008-05-19 00:33:48.582946497 +0300
+@@ -0,0 +1,132 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++/*! \cidoxg_include_ci_tools */
 +
-+/* 
-+ * Add a frontend vif to the list of vifs that is using a netfront
-+ * accelerator plugin module.
++#ifndef __CI_TOOLS_SYSDEP_H__
++#define __CI_TOOLS_SYSDEP_H__
++
++/* Make this header self-sufficient */
++#include <ci/compat.h>
++#include <ci/tools/log.h>
++#include <ci/tools/debug.h>
++
++
++/**********************************************************************
++ * Platform dependencies.
 + */
-+static void add_accelerator_vif(struct netfront_accelerator *accelerator,
-+                              struct netfront_info *np)
-+{
-+      unsigned long flags;
 +
-+      /* Need lock to write list */
-+      spin_lock_irqsave(&accelerator->vif_states_lock, flags);
++#if defined(__KERNEL__)
 +
-+      if (np->accelerator == NULL) {
-+              np->accelerator = accelerator;
-+              
-+              list_add(&np->accel_vif_state.link, &accelerator->vif_states);
-+      } else {
-+              /* 
-+               * May get here legitimately if suspend_cancel is
-+               * called, but in that case configuration should not
-+               * have changed
-+               */
-+              BUG_ON(np->accelerator != accelerator);
-+      }
++# if defined(__linux__)
++#  include <ci/tools/platform/linux_kernel.h>
++# elif defined(_WIN32)
++#  include <ci/tools/platform/win32_kernel.h>
++# elif defined(__sun__)
++#  include <ci/tools/platform/sunos_kernel.h>
++# else
++#  error Unknown platform.
++# endif
 +
-+      spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
-+}
++#elif defined(_WIN32)
 +
++# include <ci/tools/platform/win32.h>
 +
-+/*
-+ * Initialise the state to track an accelerator plugin module.
-+ */ 
-+static int init_accelerator(const char *frontend, 
-+                          struct netfront_accelerator **result,
-+                          struct netfront_accel_hooks *hooks)
-+{
-+      struct netfront_accelerator *accelerator = 
-+              kmalloc(sizeof(struct netfront_accelerator), GFP_KERNEL);
-+      unsigned long flags;
-+      int frontend_len;
++#elif defined(__unix__)
 +
-+      if (!accelerator) {
-+              DPRINTK("no memory for accelerator\n");
-+              return -ENOMEM;
-+      }
++# include <ci/tools/platform/unix.h>
 +
-+      frontend_len = strlen(frontend) + 1;
-+      accelerator->frontend = kmalloc(frontend_len, GFP_KERNEL);
-+      if (!accelerator->frontend) {
-+              DPRINTK("no memory for accelerator\n");
-+              kfree(accelerator);
-+              return -ENOMEM;
-+      }
-+      strlcpy(accelerator->frontend, frontend, frontend_len);
-+      
-+      INIT_LIST_HEAD(&accelerator->vif_states);
-+      spin_lock_init(&accelerator->vif_states_lock);
++#else
 +
-+      accelerator->hooks = hooks;
++# error Unknown platform.
 +
-+      spin_lock_irqsave(&accelerators_lock, flags);
-+      list_add(&accelerator->link, &accelerators_list);
-+      spin_unlock_irqrestore(&accelerators_lock, flags);
++#endif
 +
-+      *result = accelerator;
++#if defined(__linux__)
++/*! Linux sendfile() support enable/disable. */
++# define CI_HAVE_SENDFILE            /* provide sendfile i/f */
 +
-+      return 0;
-+}                                     
++# define CI_HAVE_OS_NOPAGE
++#endif
 +
++#if defined(__sun__)
++# define CI_HAVE_SENDFILE          /* provide sendfile i/f */
++# define CI_HAVE_SENDFILEV           /* provide sendfilev i/f */
 +
-+/* 
-+ * Modify the hooks stored in the per-vif state to match that in the
-+ * netfront accelerator's state.
++# define CI_IOCTL_SENDFILE           /*  use efrm CI_SENDFILEV ioctl */
++#endif
++
++#if defined(_WIN32)
++typedef ci_uint32 ci_uerr_t; /* range of OS user-mode return codes */
++typedef ci_uint32 ci_kerr_t; /* range of OS kernel-mode return codes */
++#elif defined(__unix__)
++typedef ci_int32 ci_uerr_t; /* range of OS user-mode return codes */
++typedef ci_int32 ci_kerr_t; /* range of OS kernel-mode return codes */
++#endif
++
++
++/**********************************************************************
++ * Compiler and processor dependencies.
 + */
-+static void 
-+accelerator_set_vif_state_hooks(struct netfront_accel_vif_state *vif_state)
-+{
-+      /* This function must be called with the vif_states_lock held */
 +
-+      DPRINTK("%p\n",vif_state);
++#if defined(__GNUC__)
 +
-+      /* Make sure there are no data path operations going on */
-+      netif_poll_disable(vif_state->np->netdev);
-+      netif_tx_lock_bh(vif_state->np->netdev);
++#if defined(__i386__) || defined(__x86_64__)
++# include <ci/tools/platform/gcc_x86.h>
++#elif defined(__PPC__)
++#  include <ci/tools/platform/gcc_ppc.h>
++#elif defined(__ia64__)
++#  include <ci/tools/platform/gcc_ia64.h>
++#else
++# error Unknown processor.
++#endif
 +
-+      vif_state->hooks = vif_state->np->accelerator->hooks;
++#elif defined(_MSC_VER)
 +
-+      netif_tx_unlock_bh(vif_state->np->netdev);
-+      netif_poll_enable(vif_state->np->netdev);
-+}
++#if defined(__i386__)
++# include <ci/tools/platform/msvc_x86.h>
++# elif defined(__x86_64__)
++# include <ci/tools/platform/msvc_x86_64.h>
++#else
++# error Unknown processor.
++#endif
 +
++#elif defined(__PGI)
 +
-+static void accelerator_probe_new_vif(struct netfront_info *np,
-+                                    struct xenbus_device *dev, 
-+                                    struct netfront_accelerator *accelerator)
-+{
-+      struct netfront_accel_hooks *hooks;
-+      unsigned long flags;
++# include <ci/tools/platform/pg_x86.h>
 +
-+      DPRINTK("\n");
++#elif defined(__INTEL_COMPILER)
 +
-+      /* Include this frontend device on the accelerator's list */
-+      add_accelerator_vif(accelerator, np);
-+      
-+      hooks = accelerator->hooks;
-+      
-+      if (hooks) {
-+              if (hooks->new_device(np->netdev, dev) == 0) {
-+                      spin_lock_irqsave
-+                              (&accelerator->vif_states_lock, flags);
++/* Intel compilers v7 claim to be very gcc compatible. */
++# include <ci/tools/platform/gcc_x86.h>
 +
-+                      accelerator_set_vif_state_hooks(&np->accel_vif_state);
++#else
++# error Unknown compiler.
++#endif
 +
-+                      spin_unlock_irqrestore
-+                              (&accelerator->vif_states_lock, flags);
-+              }
-+      }
 +
-+      return;
-+}
++#endif  /* __CI_TOOLS_SYSDEP_H__ */
 +
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/Makefile   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/Makefile      2008-05-19 00:33:48.582946497 +0300
+@@ -0,0 +1,11 @@
++EXTRA_CFLAGS += -Idrivers/xen/sfc_netfront -Idrivers/xen/sfc_netutil -Idrivers/xen/netfront
++EXTRA_CFLAGS += -D__ci_driver__
++EXTRA_CFLAGS += -Werror
 +
-+/*  
-+ * Request that a particular netfront accelerator plugin is loaded.
-+ * Usually called as a result of the vif configuration specifying
-+ * which one to use. Must be called with accelerator_mutex held 
++ifdef GCOV
++EXTRA_CFLAGS += -fprofile-arcs -ftest-coverage -DEFX_GCOV
++endif
++
++obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND)   := sfc_netfront.o
++
++sfc_netfront-objs := accel_msg.o accel_bufs.o accel_netfront.o accel_vi.o accel_xenbus.o accel_tso.o accel_ssr.o accel_debugfs.o falcon_event.o falcon_vi.o pt_tx.o vi_init.o
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel.h       2008-05-19 00:33:48.598947419 +0300
+@@ -0,0 +1,477 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
-+static int netfront_load_accelerator(struct netfront_info *np, 
-+                                   struct xenbus_device *dev, 
-+                                   const char *frontend)
-+{
-+      struct netfront_accelerator *accelerator;
-+      int rc = 0;
 +
-+      DPRINTK(" %s\n", frontend);
++#ifndef NETFRONT_ACCEL_H
++#define NETFRONT_ACCEL_H
 +
-+      /* 
-+       * Look at list of loaded accelerators to see if the requested
-+       * one is already there 
-+       */
-+      list_for_each_entry(accelerator, &accelerators_list, link) {
-+              if (match_accelerator(frontend, accelerator)) {
-+                      accelerator_probe_new_vif(np, dev, accelerator);
-+                      return 0;
-+              }
-+      }
++#include "accel_msg_iface.h"
++#include "accel_cuckoo_hash.h"
++#include "accel_bufs.h"
++
++#include "etherfabric/ef_vi.h"
++
++#include <xen/xenbus.h>
++#include <xen/evtchn.h>
 +
-+      /* Couldn't find it, so create a new one and load the module */
-+      if ((rc = init_accelerator(frontend, &accelerator, NULL)) < 0) {
-+              return rc;
-+      }
++#include <linux/kernel.h>
++#include <linux/list.h>
 +
-+      /* Include this frontend device on the accelerator's list */
-+      add_accelerator_vif(accelerator, np);
++enum netfront_accel_post_status {
++      NETFRONT_ACCEL_STATUS_GOOD,
++      NETFRONT_ACCEL_STATUS_BUSY,
++      NETFRONT_ACCEL_STATUS_CANT
++};
 +
-+      return rc;
-+}
++#define NETFRONT_ACCEL_STATS 1
++#if NETFRONT_ACCEL_STATS
++#define NETFRONT_ACCEL_STATS_OP(x) x
++#else
++#define NETFRONT_ACCEL_STATS_OP(x)
++#endif
 +
 +
-+/*
-+ * Go through all the netfront vifs and see if they have requested
-+ * this accelerator.  Notify the accelerator plugin of the relevant
-+ * device if so.  Called when an accelerator plugin module is first
-+ * loaded and connects to netfront.
-+ */
-+static void 
-+accelerator_probe_vifs(struct netfront_accelerator *accelerator,
-+                     struct netfront_accel_hooks *hooks)
-+{
-+      struct netfront_accel_vif_state *vif_state, *tmp;
-+      unsigned long flags;
++enum netfront_accel_msg_state {
++      NETFRONT_ACCEL_MSG_NONE = 0,
++      NETFRONT_ACCEL_MSG_HELLO = 1,
++      NETFRONT_ACCEL_MSG_HW = 2
++};
 +
-+      DPRINTK("%p\n", accelerator);
 +
-+      /* 
-+       * Store the hooks for future calls to probe a new device, and
-+       * to wire into the vif_state once the accelerator plugin is
-+       * ready to accelerate each vif
-+       */
-+      BUG_ON(hooks == NULL);
-+      accelerator->hooks = hooks;
++typedef struct {
++      u32 in_progress;
++      u32 total_len;
++      struct sk_buff *skb;
++} netfront_accel_jumbo_state;
 +
-+      /* 
-+       *  currently hold accelerator_mutex, so don't need
-+       *  vif_states_lock to read the list
-+       */
-+      list_for_each_entry_safe(vif_state, tmp, &accelerator->vif_states,
-+                               link) {
-+              struct netfront_info *np = vif_state->np;
-+              
-+              if (hooks->new_device(np->netdev, vif_state->dev) == 0) {
-+                      spin_lock_irqsave
-+                              (&accelerator->vif_states_lock, flags);
 +
-+                      accelerator_set_vif_state_hooks(vif_state);
++struct netfront_accel_ssr_state {
++      /** List of tracked connections. */
++      struct list_head conns;
 +
-+                      spin_unlock_irqrestore
-+                              (&accelerator->vif_states_lock, flags);
-+              }
-+      }
-+}
++      /** Free efx_ssr_conn instances. */
++      struct list_head free_conns;
++};
 +
 +
-+/* 
-+ * Called by the netfront accelerator plugin module when it has loaded 
-+ */
-+int netfront_accelerator_loaded(int version, const char *frontend, 
-+                              struct netfront_accel_hooks *hooks)
-+{
-+      struct netfront_accelerator *accelerator;
++struct netfront_accel_netdev_stats {
++      /* Fastpath stats. */
++      u32 fastpath_rx_pkts;
++      u32 fastpath_rx_bytes;
++      u32 fastpath_rx_errors;
++      u32 fastpath_tx_pkts; 
++      u32 fastpath_tx_bytes;
++      u32 fastpath_tx_errors;
++};
 +
-+      if (version != NETFRONT_ACCEL_VERSION) {
-+              if (version > NETFRONT_ACCEL_VERSION) {
-+                      /* Caller has higher version number, leave it
-+                         up to them to decide whether to continue.
-+                         They can re-call with a lower number if
-+                         they're happy to be compatible with us */
-+                      return NETFRONT_ACCEL_VERSION;
-+              } else {
-+                      /* We have a more recent version than caller.
-+                         Currently reject, but may in future be able
-+                         to be backwardly compatible */
-+                      return -EPROTO;
-+              }
-+      }
 +
-+      mutex_lock(&accelerator_mutex);
++struct netfront_accel_netdev_dbfs {
++      struct dentry *fastpath_rx_pkts;
++      struct dentry *fastpath_rx_bytes;
++      struct dentry *fastpath_rx_errors;
++      struct dentry *fastpath_tx_pkts; 
++      struct dentry *fastpath_tx_bytes;
++      struct dentry *fastpath_tx_errors;
++};
 +
-+      /* 
-+       * Look through list of accelerators to see if it has already
-+       * been requested
-+       */
-+      list_for_each_entry(accelerator, &accelerators_list, link) {
-+              if (match_accelerator(frontend, accelerator)) {
-+                      accelerator_probe_vifs(accelerator, hooks);
-+                      goto out;
-+              }
-+      }
 +
-+      /*
-+       * If it wasn't in the list, add it now so that when it is
-+       * requested the caller will find it
-+       */
-+      DPRINTK("Couldn't find matching accelerator (%s)\n",
-+              frontend);
++struct netfront_accel_stats {
++      /** Fast path events */
++      u64 fastpath_tx_busy;
 +
-+      init_accelerator(frontend, &accelerator, hooks);
++      /** TX DMA queue status */
++      u64 fastpath_tx_completions;
 +
-+ out:
-+      mutex_unlock(&accelerator_mutex);
-+      return 0;
-+}
-+EXPORT_SYMBOL_GPL(netfront_accelerator_loaded);
++      /** The number of events processed. */
++      u64 event_count;
 +
++      /** Number of frame trunc events seen on fastpath */
++      u64 fastpath_frm_trunc;
 +
-+/* 
-+ * Remove the hooks from a single vif state.
-+ */
-+static void 
-+accelerator_remove_single_hook(struct netfront_accelerator *accelerator,
-+                             struct netfront_accel_vif_state *vif_state)
-+{
-+      /* Make sure there are no data path operations going on */
-+      netif_poll_disable(vif_state->np->netdev);
-+      netif_tx_lock_bh(vif_state->np->netdev);
++      /** Number of no rx descriptor trunc events seen on fastpath */
++      u64 rx_no_desc_trunc;
 +
-+      /* 
-+       * Remove the hooks, but leave the vif_state on the
-+       * accelerator's list as that signifies this vif is
-+       * interested in using that accelerator if it becomes
-+       * available again
-+       */
-+      vif_state->hooks = NULL;
-+      
-+      netif_tx_unlock_bh(vif_state->np->netdev);
-+      netif_poll_enable(vif_state->np->netdev);                      
-+}
++      /** The number of misc bad events (e.g. RX_DISCARD) processed. */
++      u64 bad_event_count;
 +
++      /** Number of events dealt with in poll loop */
++      u32 events_per_poll_max;
++      u32 events_per_poll_tx_max;
++      u32 events_per_poll_rx_max;
 +
-+/* 
-+ * Safely remove the accelerator function hooks from a netfront state.
-+ */
-+static void accelerator_remove_hooks(struct netfront_accelerator *accelerator)
-+{
-+      struct netfront_accel_hooks *hooks;
-+      struct netfront_accel_vif_state *vif_state, *tmp;
-+      unsigned long flags;
++      /** Largest number of concurrently outstanding tx descriptors */
++      u32 fastpath_tx_pending_max;
 +
-+      /* Mutex is held so don't need vif_states_lock to iterate list */
-+      list_for_each_entry_safe(vif_state, tmp,
-+                               &accelerator->vif_states,
-+                               link) {
-+              spin_lock_irqsave(&accelerator->vif_states_lock, flags);
++      /** The number of events since the last interrupts. */
++      u32 event_count_since_irq;
 +
-+              if(vif_state->hooks) {
-+                      hooks = vif_state->hooks;
-+                      
-+                      /* Last chance to get statistics from the accelerator */
-+                      hooks->get_stats(vif_state->np->netdev,
-+                                       &vif_state->np->stats);
++      /** The max number of events between interrupts. */
++      u32 events_per_irq_max;
 +
-+                      spin_unlock_irqrestore(&accelerator->vif_states_lock,
-+                                             flags);
++      /** The number of interrupts. */
++      u64 irq_count;
 +
-+                      accelerator_remove_single_hook(accelerator, vif_state);
++      /** The number of useless interrupts. */
++      u64 useless_irq_count;
 +
-+                      accelerator->hooks->remove(vif_state->dev);
-+              } else {
-+                      spin_unlock_irqrestore(&accelerator->vif_states_lock,
-+                                             flags);
-+              }
-+      }
-+      
-+      accelerator->hooks = NULL;
-+}
++      /** The number of polls scheduled. */
++      u64 poll_schedule_count;
 +
++      /** The number of polls called. */
++      u64 poll_call_count;
 +
-+/* 
-+ * Called by a netfront accelerator when it is unloaded.  This safely
-+ * removes the hooks into the plugin and blocks until all devices have
-+ * finished using it, so on return it is safe to unload.
-+ */
-+void netfront_accelerator_stop(const char *frontend)
-+{
-+      struct netfront_accelerator *accelerator;
-+      unsigned long flags;
++      /** The number of rechecks. */
++      u64 poll_reschedule_count;
 +
-+      mutex_lock(&accelerator_mutex);
-+      spin_lock_irqsave(&accelerators_lock, flags);
++      /** Number of times we've called netif_stop_queue/netif_wake_queue */
++      u64 queue_stops;
++      u64 queue_wakes;
 +
-+      list_for_each_entry(accelerator, &accelerators_list, link) {
-+              if (match_accelerator(frontend, accelerator)) {
-+                      spin_unlock_irqrestore(&accelerators_lock, flags);
++      /** SSR stats */
++      u64 ssr_bursts;
++      u64 ssr_drop_stream;
++      u64 ssr_misorder;
++      u64 ssr_slow_start;
++      u64 ssr_merges;
++      u64 ssr_too_many;
++      u64 ssr_new_stream;
++};
 +
-+                      accelerator_remove_hooks(accelerator);
 +
-+                      goto out;
-+              }
-+      }
-+      spin_unlock_irqrestore(&accelerators_lock, flags);
-+ out:
-+      mutex_unlock(&accelerator_mutex);
-+}
-+EXPORT_SYMBOL_GPL(netfront_accelerator_stop);
++struct netfront_accel_dbfs {
++      struct dentry *fastpath_tx_busy;
++      struct dentry *fastpath_tx_completions;
++      struct dentry *fastpath_tx_pending_max;
++      struct dentry *fastpath_frm_trunc;
++      struct dentry *rx_no_desc_trunc;
++      struct dentry *event_count;
++      struct dentry *bad_event_count;
++      struct dentry *events_per_poll_max;
++      struct dentry *events_per_poll_rx_max;
++      struct dentry *events_per_poll_tx_max;
++      struct dentry *event_count_since_irq;
++      struct dentry *events_per_irq_max;
++      struct dentry *irq_count;
++      struct dentry *useless_irq_count;
++      struct dentry *poll_schedule_count;
++      struct dentry *poll_call_count;
++      struct dentry *poll_reschedule_count;
++      struct dentry *queue_stops;
++      struct dentry *queue_wakes;
++      struct dentry *ssr_bursts;
++      struct dentry *ssr_drop_stream;
++      struct dentry *ssr_misorder;
++      struct dentry *ssr_slow_start;
++      struct dentry *ssr_merges;
++      struct dentry *ssr_too_many;
++      struct dentry *ssr_new_stream;
++};
++
 +
++typedef struct netfront_accel_vnic {
++      struct netfront_accel_vnic *next;
++      
++      struct mutex vnic_mutex;
 +
-+/* Helper for call_remove and do_suspend */
-+static int do_remove(struct netfront_info *np, struct xenbus_device *dev,
-+                   unsigned long *lock_flags)
-+{
-+      struct netfront_accelerator *accelerator = np->accelerator;
-+      struct netfront_accel_hooks *hooks;
-+      int rc = 0;
-+ 
-+      if (np->accel_vif_state.hooks) {
-+              hooks = np->accel_vif_state.hooks;
++      spinlock_t tx_lock;
 +
-+              /* Last chance to get statistics from the accelerator */
-+              hooks->get_stats(np->netdev, &np->stats);
++      struct netfront_accel_bufpages bufpages;
++      struct netfront_accel_bufinfo *rx_bufs;
++      struct netfront_accel_bufinfo *tx_bufs;
++      
++      /** Hardware & VI state */
++      ef_vi vi;
 +
-+              spin_unlock_irqrestore(&accelerator->vif_states_lock, 
-+                                     *lock_flags);
++      ef_vi_state *vi_state;
 +
-+              /* 
-+               * Try and do the opposite of accelerator_probe_new_vif
-+               * to ensure there's no state pointing back at the 
-+               * netdev 
-+               */
-+              accelerator_remove_single_hook(accelerator, 
-+                                             &np->accel_vif_state);
++      ef_eventq_state evq_state;
 +
-+              rc = accelerator->hooks->remove(dev);
++      void *evq_mapping;
 +
-+              spin_lock_irqsave(&accelerator->vif_states_lock, *lock_flags);
-+      }
-+ 
-+      return rc;
-+}
++      /** Hardware dependant state */
++      union {
++              struct {
++                      /** Falcon A or B */
++                      enum net_accel_hw_type type; 
++                      u32 *evq_rptr;
++                      u32 *doorbell;
++                      void *evq_rptr_mapping;
++                      void *doorbell_mapping;
++                      void *txdmaq_mapping;
++                      void *rxdmaq_mapping;
++              } falcon;
++      } hw;
++  
++      /** RX DMA queue status */
++      u32 rx_dma_level;
 +
++      /** Number of RX descriptors waiting to be pushed to the card. */
++      u32 rx_dma_batched;
++#define NETFRONT_ACCEL_RX_DESC_BATCH 16
 +
-+static int netfront_remove_accelerator(struct netfront_info *np,
-+                                     struct xenbus_device *dev)
-+{
-+      struct netfront_accelerator *accelerator;
-+      struct netfront_accel_vif_state *tmp_vif_state;
-+      unsigned long flags;
-+      int rc = 0; 
++      /**
++       * Hash table of remote mac addresses to decide whether to try
++       * fast path
++       */
++      cuckoo_hash_table fastpath_table;
++      spinlock_t table_lock;
 +
-+      /* Check that we've got a device that was accelerated */
-+      if (np->accelerator == NULL)
-+              return rc;
++      /** the local mac address of virtual interface we're accelerating */
++      u8 mac[ETH_ALEN];
 +
-+      accelerator = np->accelerator;
++      int rx_pkt_stride;
++      int rx_skb_stride;
 +
-+      spin_lock_irqsave(&accelerator->vif_states_lock, flags); 
++      /**
++       * Keep track of fragments of jumbo packets as events are
++       * delivered by NIC 
++       */
++      netfront_accel_jumbo_state jumbo_state;
 +
-+      list_for_each_entry(tmp_vif_state, &accelerator->vif_states,
-+                          link) {
-+              if (tmp_vif_state == &np->accel_vif_state) {
-+                      list_del(&np->accel_vif_state.link);
-+                      break;
-+              }
-+      }
++      struct net_device *net_dev;
 +
-+      rc = do_remove(np, dev, &flags);
++      /** These two gate the enabling of fast path operations */
++      int frontend_ready;
++      int backend_netdev_up;
 +
-+      np->accelerator = NULL;
++      int irq_enabled;
++      spinlock_t irq_enabled_lock;
 +
-+      spin_unlock_irqrestore(&accelerator->vif_states_lock, flags); 
++      int tx_enabled;
 +
-+      return rc;
-+}
++      int poll_enabled;
 +
++      /** A spare slot for a TX packet.  This is treated as an extension
++       * of the DMA queue. */
++      struct sk_buff *tx_skb;
 +
-+int netfront_accelerator_call_remove(struct netfront_info *np,
-+                                   struct xenbus_device *dev)
-+{
-+      int rc;
-+      netfront_accelerator_remove_watch(np);
-+      mutex_lock(&accelerator_mutex);
-+      rc = netfront_remove_accelerator(np, dev);
-+      mutex_unlock(&accelerator_mutex);
-+      return rc;
-+}
++      /** Keep track of fragments of SSR packets */
++      struct netfront_accel_ssr_state ssr_state;
 +
-+  
-+int netfront_accelerator_suspend(struct netfront_info *np,
-+                               struct xenbus_device *dev)
-+{
-+      unsigned long flags;
-+      int rc = 0;
-+      
-+      netfront_accelerator_remove_watch(np);
++      struct xenbus_device *dev;
 +
-+      mutex_lock(&accelerator_mutex);
++      /** Event channel for messages */
++      int msg_channel;
++      int msg_channel_irq;
 +
-+      /* Check that we've got a device that was accelerated */
-+      if (np->accelerator == NULL)
-+              goto out;
++      /** Event channel for network interrupts. */
++      int net_channel;
++      int net_channel_irq;
 +
-+      /* 
-+       * Call the remove accelerator hook, but leave the vif_state
-+       * on the accelerator's list in case there is a suspend_cancel.
-+       */
-+      spin_lock_irqsave(&np->accelerator->vif_states_lock, flags); 
-+      
-+      rc = do_remove(np, dev, &flags);
++      struct net_accel_shared_page *shared_page;
 +
-+      spin_unlock_irqrestore(&np->accelerator->vif_states_lock, flags); 
-+ out:
-+      mutex_unlock(&accelerator_mutex);
-+      return rc;
-+}
-+  
-+  
-+int netfront_accelerator_suspend_cancel(struct netfront_info *np,
-+                                      struct xenbus_device *dev)
-+{
-+      struct netfront_accel_vif_state *accel_vif_state = NULL;
-+ 
-+      mutex_lock(&accelerator_mutex);
++      grant_ref_t ctrl_page_gnt;
++      grant_ref_t msg_page_gnt;
 +
-+      /* Check that we've got a device that was accelerated */
-+      if (np->accelerator == NULL)
-+              goto out;
++      /** Message Qs, 1 each way. */
++      sh_msg_fifo2 to_dom0;
++      sh_msg_fifo2 from_dom0;
 +
-+      /* Find the vif_state from the accelerator's list */
-+      list_for_each_entry(accel_vif_state, &np->accelerator->vif_states,
-+                          link) {
-+              if (accel_vif_state->dev == dev) {
-+                      BUG_ON(accel_vif_state != &np->accel_vif_state);
-+ 
-+                      /*
-+                       * Kick things off again to restore
-+                       * acceleration as it was before suspend 
-+                       */
-+                      accelerator_probe_new_vif(np, dev, np->accelerator);
-+ 
-+                      break;
-+              }
-+      }
-+      
-+ out:
-+      mutex_unlock(&accelerator_mutex);
-+      netfront_accelerator_add_watch(np);
-+      return 0;
-+}
-+ 
-+ 
-+void netfront_accelerator_resume(struct netfront_info *np,
-+                               struct xenbus_device *dev)
-+{
-+      struct netfront_accel_vif_state *accel_vif_state = NULL;
-+      spinlock_t *vif_states_lock;
-+      unsigned long flags;
-+ 
-+      mutex_lock(&accelerator_mutex);
++      enum netfront_accel_msg_state msg_state;
 +
-+      /* Check that we've got a device that was accelerated */
-+      if(np->accelerator == NULL)
-+              goto out;
++      /** Watch on accelstate */
++      struct xenbus_watch backend_accel_watch;
++      /** Watch on frontend's MAC address */
++      struct xenbus_watch mac_address_watch;
 +
-+      /* Find the vif_state from the accelerator's list */
-+      list_for_each_entry(accel_vif_state, &np->accelerator->vif_states, 
-+                          link) {
-+              if (accel_vif_state->dev == dev) {
-+                      BUG_ON(accel_vif_state != &np->accel_vif_state);
-+ 
-+                      vif_states_lock = &np->accelerator->vif_states_lock;
-+                      spin_lock_irqsave(vif_states_lock, flags); 
-+ 
-+                      /* 
-+                       * Remove it from the accelerator's list so
-+                       * state is consistent for probing new vifs
-+                       * when they get connected
-+                       */
-+                      list_del(&accel_vif_state->link);
-+                      np->accelerator = NULL;
-+ 
-+                      spin_unlock_irqrestore(vif_states_lock, flags); 
-+                      
-+                      break;
-+              }
-+      }
++      /** Work to process received irq/msg */
++      struct work_struct msg_from_bend;
 +
-+ out:
-+      mutex_unlock(&accelerator_mutex);
-+      return;
-+}
++      /** Wait queue for changes in accelstate. */
++      wait_queue_head_t state_wait_queue;
 +
++      /** The current accelstate of this driver. */
++      XenbusState frontend_state;
 +
-+int netfront_check_accelerator_queue_ready(struct net_device *dev,
-+                                         struct netfront_info *np)
-+{
-+      struct netfront_accelerator *accelerator;
-+      struct netfront_accel_hooks *hooks;
-+      int rc = 1;
-+      unsigned long flags;
++      /** The most recent accelstate seen by the xenbus watch. */
++      XenbusState backend_state;
 +
-+      accelerator = np->accelerator;
++      /** Non-zero if we should reject requests to connect. */
++      int removing;
 +
-+      /* Call the check_ready accelerator hook. */ 
-+      if (np->accel_vif_state.hooks && accelerator) {
-+              spin_lock_irqsave(&accelerator->vif_states_lock, flags); 
-+              hooks = np->accel_vif_state.hooks;
-+              if (hooks && np->accelerator == accelerator)
-+                      rc = np->accel_vif_state.hooks->check_ready(dev);
-+              spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
-+      }
++      /** Non-zero if the domU shared state has been initialised. */
++      int domU_state_is_setup;
 +
-+      return rc;
-+}
++      /** Non-zero if the dom0 shared state has been initialised. */
++      int dom0_state_is_setup;
 +
++      /* Those statistics that are added to the netdev stats */
++      struct netfront_accel_netdev_stats netdev_stats;
++      struct netfront_accel_netdev_stats stats_last_read;
++#ifdef CONFIG_DEBUG_FS
++      struct netfront_accel_netdev_dbfs netdev_dbfs;
++#endif
 +
-+void netfront_accelerator_call_stop_napi_irq(struct netfront_info *np,
-+                                           struct net_device *dev)
-+{
-+      struct netfront_accelerator *accelerator;
-+      struct netfront_accel_hooks *hooks;
-+      unsigned long flags;
++      /* These statistics are internal and optional */
++#if NETFRONT_ACCEL_STATS
++      struct netfront_accel_stats stats;
++#ifdef CONFIG_DEBUG_FS
++      struct netfront_accel_dbfs dbfs;
++#endif
++#endif
 +
-+      accelerator = np->accelerator;
++      /** Debufs fs dir for this interface */
++      struct dentry *dbfs_dir;
++} netfront_accel_vnic;
 +
-+      /* Call the stop_napi_interrupts accelerator hook. */
-+      if (np->accel_vif_state.hooks && accelerator != NULL) {
-+              spin_lock_irqsave(&accelerator->vif_states_lock, flags); 
-+              hooks = np->accel_vif_state.hooks;
-+              if (hooks && np->accelerator == accelerator)
-+                      np->accel_vif_state.hooks->stop_napi_irq(dev);
-+              spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
-+      }
-+}
 +
++/* Module parameters */
++extern unsigned sfc_netfront_max_pages;
++extern unsigned sfc_netfront_buffer_split;
 +
-+int netfront_accelerator_call_get_stats(struct netfront_info *np,
-+                                      struct net_device *dev)
-+{
-+      struct netfront_accelerator *accelerator;
-+      struct netfront_accel_hooks *hooks;
-+      unsigned long flags;
-+      int rc = 0;
++extern const char *frontend_name;
++extern struct netfront_accel_hooks accel_hooks;
++extern struct workqueue_struct *netfront_accel_workqueue;
 +
-+      accelerator = np->accelerator;
 +
-+      /* Call the get_stats accelerator hook. */
-+      if (np->accel_vif_state.hooks && accelerator != NULL) {
-+              spin_lock_irqsave(&accelerator->vif_states_lock, flags); 
-+              hooks = np->accel_vif_state.hooks;
-+              if (hooks && np->accelerator == accelerator)
-+                      rc = np->accel_vif_state.hooks->get_stats(dev,
-+                                                                &np->stats);
-+              spin_unlock_irqrestore(&accelerator->vif_states_lock, flags);
-+      }
-+      return rc;
-+}
++extern
++void netfront_accel_vi_ctor(netfront_accel_vnic *vnic);
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/netfront/Makefile linux-2.6.18-xen.hg/drivers/xen/netfront/Makefile
---- linux-2.6.18/drivers/xen/netfront/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/netfront/Makefile  2007-12-23 11:15:34.054602273 +0100
-@@ -0,0 +1,4 @@
++extern
++int netfront_accel_vi_init(netfront_accel_vnic *vnic, 
++                         struct net_accel_msg_hw *hw_msg);
 +
-+obj-$(CONFIG_XEN_NETDEV_FRONTEND)     := xennet.o
++extern
++void netfront_accel_vi_dtor(netfront_accel_vnic *vnic);
 +
-+xennet-objs := netfront.o accel.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/netfront/netfront.c linux-2.6.18-xen.hg/drivers/xen/netfront/netfront.c
---- linux-2.6.18/drivers/xen/netfront/netfront.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/netfront/netfront.c        2007-12-23 11:15:34.057935783 +0100
-@@ -0,0 +1,2217 @@
-+/******************************************************************************
-+ * Virtual network driver for conversing with remote driver backends.
-+ *
-+ * Copyright (c) 2002-2005, K A Fraser
-+ * Copyright (c) 2005, XenSource Ltd
-+ * Copyright (C) 2007 Solarflare Communications, Inc.
++
++/**
++ * Add new buffers which have been registered with the NIC.
 + *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
++ * @v   vnic     The vnic instance to process the response.
 + *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
++ * The buffers contained in the message are added to the buffer pool.
++ */
++extern
++void netfront_accel_vi_add_bufs(netfront_accel_vnic *vnic, int is_rx);
++
++/**
++ * Put a packet on the tx DMA queue.
 + *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
++ * @v  vnic    The vnic instance to accept the packet.
++ * @v  skb     A sk_buff to send.
 + *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
++ * Attempt to send a packet.  On success, the skb is owned by the DMA
++ * queue and will be released when the completion event arrives.
 + */
++extern enum netfront_accel_post_status
++netfront_accel_vi_tx_post(netfront_accel_vnic *vnic,
++                        struct sk_buff *skb);
 +
-+#include <linux/module.h>
-+#include <linux/version.h>
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+#include <linux/errno.h>
-+#include <linux/netdevice.h>
-+#include <linux/inetdevice.h>
-+#include <linux/etherdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/init.h>
-+#include <linux/bitops.h>
-+#include <linux/ethtool.h>
-+#include <linux/in.h>
-+#include <linux/if_ether.h>
-+#include <linux/io.h>
-+#include <linux/moduleparam.h>
-+#include <net/sock.h>
-+#include <net/pkt_sched.h>
-+#include <net/arp.h>
-+#include <net/route.h>
-+#include <asm/uaccess.h>
-+#include <xen/evtchn.h>
-+#include <xen/xenbus.h>
-+#include <xen/interface/io/netif.h>
-+#include <xen/interface/memory.h>
-+#include <xen/balloon.h>
-+#include <asm/page.h>
-+#include <asm/maddr.h>
-+#include <asm/uaccess.h>
-+#include <xen/interface/grant_table.h>
-+#include <xen/gnttab.h>
-+#include <xen/hypercall.h>
-+
-+struct netfront_cb {
-+      struct page *page;
-+      unsigned offset;
-+};
-+
-+#define NETFRONT_SKB_CB(skb)  ((struct netfront_cb *)((skb)->cb))
-+
-+#include "netfront.h"
 +
-+/*
-+ * Mutually-exclusive module options to select receive data path:
-+ *  rx_copy : Packets are copied by network backend into local memory
-+ *  rx_flip : Page containing packet data is transferred to our ownership
-+ * For fully-virtualised guests there is no option - copying must be used.
-+ * For paravirtualised guests, flipping is the default.
++/**
++ * Process events in response to an interrupt.
++ *
++ * @v   vnic       The vnic instance to poll.
++ * @v   rx_packets The maximum number of rx packets to process.
++ * @ret rx_done    The number of rx packets processed.
++ *
++ * The vnic will process events until there are no more events
++ * remaining or the specified number of rx packets has been processed.
++ * The split from the interrupt call is to allow Linux NAPI
++ * polling.
 + */
-+#ifdef CONFIG_XEN
-+static int MODPARM_rx_copy = 0;
-+module_param_named(rx_copy, MODPARM_rx_copy, bool, 0);
-+MODULE_PARM_DESC(rx_copy, "Copy packets from network card (rather than flip)");
-+static int MODPARM_rx_flip = 0;
-+module_param_named(rx_flip, MODPARM_rx_flip, bool, 0);
-+MODULE_PARM_DESC(rx_flip, "Flip packets from network card (rather than copy)");
-+#else
-+static const int MODPARM_rx_copy = 1;
-+static const int MODPARM_rx_flip = 0;
-+#endif
-+
-+#define RX_COPY_THRESHOLD 256
++extern
++int netfront_accel_vi_poll(netfront_accel_vnic *vnic, int rx_packets);
 +
-+/* If we don't have GSO, fake things up so that we never try to use it. */
-+#if defined(NETIF_F_GSO)
-+#define HAVE_GSO                      1
-+#define HAVE_TSO                      1 /* TSO is a subset of GSO */
-+#define HAVE_CSUM_OFFLOAD             1
-+static inline void dev_disable_gso_features(struct net_device *dev)
-+{
-+      /* Turn off all GSO bits except ROBUST. */
-+      dev->features &= (1 << NETIF_F_GSO_SHIFT) - 1;
-+      dev->features |= NETIF_F_GSO_ROBUST;
-+}
-+#elif defined(NETIF_F_TSO)
-+#define HAVE_GSO                     0
-+#define HAVE_TSO                       1
 +
-+/* Some older kernels cannot cope with incorrect checksums,
-+ * particularly in netfilter. I'm not sure there is 100% correlation
-+ * with the presence of NETIF_F_TSO but it appears to be a good first
-+ * approximiation.
++/**
++ * Iterate over the fragments of a packet buffer.
++ *
++ * @v   skb      The packet buffer to examine.
++ * @v   idx      A variable name for the fragment index.
++ * @v   data     A variable name for the address of the fragment data.
++ * @v   length   A variable name for the fragment length.
++ * @v   code     A section of code to execute for each fragment.
++ *
++ * This macro iterates over the fragments in a packet buffer and
++ * executes the code for each of them.
 + */
-+#define HAVE_CSUM_OFFLOAD              0
++#define NETFRONT_ACCEL_PKTBUFF_FOR_EACH_FRAGMENT(skb, frag_idx,               \
++                                               frag_data, frag_len,   \
++                                               code)                  \
++      do {                                                            \
++              int frag_idx;                                           \
++              void *frag_data;                                        \
++              unsigned int      frag_len;                             \
++                                                                      \
++              frag_data = skb->data;                                  \
++              frag_len = skb_headlen(skb);                            \
++              frag_idx = 0;                                           \
++              while (1) { /* For each fragment */                     \
++                      code;                                           \
++                      if (frag_idx >= skb_shinfo(skb)->nr_frags) {    \
++                              break;                                  \
++                      } else {                                        \
++                              skb_frag_t *fragment;                   \
++                              fragment = &skb_shinfo(skb)->frags[frag_idx]; \
++                              frag_len = fragment->size;              \
++                              frag_data = ((void*)page_address(fragment->page) \
++                                           + fragment->page_offset);  \
++                      };                                              \
++                      frag_idx++;                                     \
++              }                                                       \
++      } while(0)
 +
-+#define gso_size tso_size
-+#define gso_segs tso_segs
-+static inline void dev_disable_gso_features(struct net_device *dev)
-+{
-+       /* Turn off all TSO bits. */
-+       dev->features &= ~NETIF_F_TSO;
-+}
-+static inline int skb_is_gso(const struct sk_buff *skb)
-+{
-+        return skb_shinfo(skb)->tso_size;
-+}
-+static inline int skb_gso_ok(struct sk_buff *skb, int features)
++static inline
++void netfront_accel_disable_net_interrupts(netfront_accel_vnic *vnic)
 +{
-+        return (features & NETIF_F_TSO);
++      mask_evtchn(vnic->net_channel);
 +}
 +
-+static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
++static inline
++void netfront_accel_enable_net_interrupts(netfront_accel_vnic *vnic)
 +{
-+        return skb_is_gso(skb) &&
-+               (!skb_gso_ok(skb, dev->features) ||
-+                unlikely(skb->ip_summed != CHECKSUM_HW));
++      unmask_evtchn(vnic->net_channel);
 +}
++
++void netfront_accel_msg_tx_fastpath(netfront_accel_vnic *vnic, const void *mac,
++                                  u32 ip, u16 port, u8 protocol);
++
++/* Process an IRQ received from back end driver */
++irqreturn_t netfront_accel_msg_channel_irq_from_bend(int irq, void *context, 
++                                                   struct pt_regs *unused);
++irqreturn_t netfront_accel_net_channel_irq_from_bend(int irq, void *context, 
++                                                   struct pt_regs *unused);
++
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++extern void netfront_accel_msg_from_bend(struct work_struct *context);
 +#else
-+#define HAVE_GSO                      0
-+#define HAVE_TSO                      0
-+#define HAVE_CSUM_OFFLOAD             0
-+#define netif_needs_gso(dev, skb)     0
-+#define dev_disable_gso_features(dev) ((void)0)
-+#define ethtool_op_set_tso(dev, data) (-ENOSYS)
++extern void netfront_accel_msg_from_bend(void *context);
 +#endif
 +
-+#define GRANT_INVALID_REF     0
++extern void vnic_stop_fastpath(netfront_accel_vnic *vnic);
 +
-+struct netfront_rx_info {
-+      struct netif_rx_response rx;
-+      struct netif_extra_info extras[XEN_NETIF_EXTRA_TYPE_MAX - 1];
-+};
++extern int netfront_accel_probe(struct net_device *net_dev, 
++                              struct xenbus_device *dev);
++extern int netfront_accel_remove(struct xenbus_device *dev);
++extern void netfront_accel_set_closing(netfront_accel_vnic *vnic);
 +
-+/*
-+ * Implement our own carrier flag: the network stack's version causes delays
-+ * when the carrier is re-enabled (in particular, dev_activate() may not
-+ * immediately be called, which can cause packet loss).
-+ */
-+#define netfront_carrier_on(netif)    ((netif)->carrier = 1)
-+#define netfront_carrier_off(netif)   ((netif)->carrier = 0)
-+#define netfront_carrier_ok(netif)    ((netif)->carrier)
++extern int netfront_accel_vi_enable_interrupts(netfront_accel_vnic *vnic);
 +
-+/*
-+ * Access macros for acquiring freeing slots in tx_skbs[].
++extern void netfront_accel_debugfs_init(void);
++extern void netfront_accel_debugfs_fini(void);
++extern int netfront_accel_debugfs_create(netfront_accel_vnic *vnic);
++extern int netfront_accel_debugfs_remove(netfront_accel_vnic *vnic);
++
++#endif /* NETFRONT_ACCEL_H */
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel_bufs.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel_bufs.c  2008-05-19 00:33:48.598947419 +0300
+@@ -0,0 +1,393 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+static inline void add_id_to_freelist(struct sk_buff **list, unsigned short id)
-+{
-+      list[id] = list[0];
-+      list[0]  = (void *)(unsigned long)id;
-+}
++#include <xen/gnttab.h>
 +
-+static inline unsigned short get_id_from_freelist(struct sk_buff **list)
-+{
-+      unsigned int id = (unsigned int)(unsigned long)list[0];
-+      list[0] = list[id];
-+      return id;
-+}
++#include "accel_bufs.h"
++#include "accel_util.h"
 +
-+static inline int xennet_rxidx(RING_IDX idx)
-+{
-+      return idx & (NET_RX_RING_SIZE - 1);
-+}
++#include "accel.h"
 +
-+static inline struct sk_buff *xennet_get_rx_skb(struct netfront_info *np,
-+                                              RING_IDX ri)
-+{
-+      int i = xennet_rxidx(ri);
-+      struct sk_buff *skb = np->rx_skbs[i];
-+      np->rx_skbs[i] = NULL;
-+      return skb;
-+}
 +
-+static inline grant_ref_t xennet_get_rx_ref(struct netfront_info *np,
-+                                          RING_IDX ri)
++static int 
++netfront_accel_alloc_buf_desc_blocks(struct netfront_accel_bufinfo *manager,
++                                   int pages)
 +{
-+      int i = xennet_rxidx(ri);
-+      grant_ref_t ref = np->grant_rx_ref[i];
-+      np->grant_rx_ref[i] = GRANT_INVALID_REF;
-+      return ref;
++      manager->desc_blocks = 
++              kzalloc(sizeof(struct netfront_accel_pkt_desc *) * 
++                      NETFRONT_ACCEL_BUF_NUM_BLOCKS(pages), GFP_KERNEL);
++      if (manager->desc_blocks == NULL) {
++              return -ENOMEM;
++      }
++      
++      return 0;
 +}
 +
-+#define DPRINTK(fmt, args...)                         \
-+      pr_debug("netfront (%s:%d) " fmt,               \
-+               __FUNCTION__, __LINE__, ##args)
-+#define IPRINTK(fmt, args...)                         \
-+      printk(KERN_INFO "netfront: " fmt, ##args)
-+#define WPRINTK(fmt, args...)                         \
-+      printk(KERN_WARNING "netfront: " fmt, ##args)
-+
-+static int setup_device(struct xenbus_device *, struct netfront_info *);
-+static struct net_device *create_netdev(struct xenbus_device *);
-+
-+static void end_access(int, void *);
-+static void netif_disconnect_backend(struct netfront_info *);
++static int 
++netfront_accel_alloc_buf_lists(struct netfront_accel_bufpages *bufpages,
++                             int pages)
++{
++      bufpages->page_list = kmalloc(pages * sizeof(void *), GFP_KERNEL);
++      if (bufpages->page_list == NULL) {
++              return -ENOMEM;
++      }
 +
-+static int network_connect(struct net_device *);
-+static void network_tx_buf_gc(struct net_device *);
-+static void network_alloc_rx_buffers(struct net_device *);
-+static void send_fake_arp(struct net_device *);
++      bufpages->grant_list = kzalloc(pages * sizeof(grant_ref_t), GFP_KERNEL);
++      if (bufpages->grant_list == NULL) {
++              kfree(bufpages->page_list);
++              bufpages->page_list = NULL;
++              return -ENOMEM;
++      }
 +
-+static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs);
++      return 0;
++}
 +
-+#ifdef CONFIG_SYSFS
-+static int xennet_sysfs_addif(struct net_device *netdev);
-+static void xennet_sysfs_delif(struct net_device *netdev);
-+#else /* !CONFIG_SYSFS */
-+#define xennet_sysfs_addif(dev) (0)
-+#define xennet_sysfs_delif(dev) do { } while(0)
-+#endif
 +
-+static inline int xennet_can_sg(struct net_device *dev)
++int netfront_accel_alloc_buffer_mem(struct netfront_accel_bufpages *bufpages,
++                                  struct netfront_accel_bufinfo *rx_manager,
++                                  struct netfront_accel_bufinfo *tx_manager,
++                                  int pages)
 +{
-+      return dev->features & NETIF_F_SG;
-+}
++      int n, rc;
 +
-+/**
-+ * Entry point to this code when a new device is created.  Allocate the basic
-+ * structures and the ring buffers for communication with the backend, and
-+ * inform the backend of the appropriate details for those.
-+ */
-+static int __devinit netfront_probe(struct xenbus_device *dev,
-+                                  const struct xenbus_device_id *id)
-+{
-+      int err;
-+      struct net_device *netdev;
-+      struct netfront_info *info;
++      if ((rc = netfront_accel_alloc_buf_desc_blocks
++           (rx_manager, pages - (pages / sfc_netfront_buffer_split))) < 0) {
++              goto rx_fail;
++      }
 +
-+      netdev = create_netdev(dev);
-+      if (IS_ERR(netdev)) {
-+              err = PTR_ERR(netdev);
-+              xenbus_dev_fatal(dev, err, "creating netdev");
-+              return err;
++      if ((rc = netfront_accel_alloc_buf_desc_blocks
++           (tx_manager, pages / sfc_netfront_buffer_split)) < 0) {
++              goto tx_fail;
 +      }
 +
-+      info = netdev_priv(netdev);
-+      dev->dev.driver_data = info;
++      if ((rc = netfront_accel_alloc_buf_lists(bufpages, pages)) < 0) {
++              goto lists_fail;
++      }
 +
-+      err = register_netdev(info->netdev);
-+      if (err) {
-+              printk(KERN_WARNING "%s: register_netdev err=%d\n",
-+                     __FUNCTION__, err);
-+              goto fail;
++      for (n = 0; n < pages; n++) {
++              void *tmp = (void*)__get_free_page(GFP_KERNEL);
++              if (tmp == NULL)
++                      break;
++
++              bufpages->page_list[n] = tmp;
 +      }
 +
-+      err = xennet_sysfs_addif(info->netdev);
-+      if (err) {
-+              unregister_netdev(info->netdev);
-+              printk(KERN_WARNING "%s: add sysfs failed err=%d\n",
-+                     __FUNCTION__, err);
-+              goto fail;
++      if (n != pages) {
++              EPRINTK("%s: not enough pages: %d != %d\n", __FUNCTION__, n, 
++                      pages);
++              for (; n >= 0; n--)
++                      free_page((unsigned long)(bufpages->page_list[n]));
++              rc = -ENOMEM;
++              goto pages_fail;
 +      }
 +
++      bufpages->max_pages = pages;
++      bufpages->page_reqs = 0;
++
 +      return 0;
 +
-+ fail:
-+      free_netdev(netdev);
-+      dev->dev.driver_data = NULL;
-+      return err;
-+}
++ pages_fail:
++      kfree(bufpages->page_list);
++      kfree(bufpages->grant_list);
 +
-+static int __devexit netfront_remove(struct xenbus_device *dev)
-+{
-+      struct netfront_info *info = dev->dev.driver_data;
++      bufpages->page_list = NULL;
++      bufpages->grant_list = NULL;
++ lists_fail:
++      kfree(tx_manager->desc_blocks);
++      tx_manager->desc_blocks = NULL;
 +
-+      DPRINTK("%s\n", dev->nodename);
++ tx_fail:
++      kfree(rx_manager->desc_blocks);
++      rx_manager->desc_blocks = NULL;
++ rx_fail:
++      return rc;
++}
 +
-+      netfront_accelerator_call_remove(info, dev);
 +
-+      netif_disconnect_backend(info);
++void netfront_accel_free_buffer_mem(struct netfront_accel_bufpages *bufpages,
++                                  struct netfront_accel_bufinfo *rx_manager,
++                                  struct netfront_accel_bufinfo *tx_manager)
++{
++      int i;
 +
-+      del_timer_sync(&info->rx_refill_timer);
++      for (i = 0; i < bufpages->max_pages; i++) {
++              if (bufpages->grant_list[i] != 0)
++                      net_accel_ungrant_page(bufpages->grant_list[i]);
++              free_page((unsigned long)(bufpages->page_list[i]));
++      }
 +
-+      xennet_sysfs_delif(info->netdev);
++      if (bufpages->max_pages) {
++              kfree(bufpages->page_list);
++              kfree(bufpages->grant_list);
++              kfree(rx_manager->desc_blocks);
++              kfree(tx_manager->desc_blocks);
++      }
++}
 +
-+      unregister_netdev(info->netdev);
 +
-+      free_netdev(info->netdev);
++/*
++ * Allocate memory for the buffer manager and create a lock.  If no
++ * lock is supplied its own is allocated.
++ */
++struct netfront_accel_bufinfo *netfront_accel_init_bufs(spinlock_t *lock)
++{
++      struct netfront_accel_bufinfo *res = kmalloc(sizeof(*res), GFP_KERNEL);
++      if (res != NULL) {
++              res->npages = res->nused = 0;
++              res->first_free = -1;
 +
-+      return 0;
++              if (lock == NULL) {
++                      res->lock = kmalloc(sizeof(*res->lock), GFP_KERNEL);
++                      if (res->lock == NULL) {
++                              kfree(res);
++                              return NULL;
++                      }
++                      spin_lock_init(res->lock);
++                      res->internally_locked = 1;
++              } else {
++                      res->lock = lock;
++                      res->internally_locked = 0;
++              }
++              
++              res->desc_blocks = NULL;
++      }
++
++      return res;
 +}
 +
 +
-+static int netfront_suspend(struct xenbus_device *dev)
++void netfront_accel_fini_bufs(struct netfront_accel_bufinfo *bufs)
 +{
-+      struct netfront_info *info = dev->dev.driver_data;
-+      return netfront_accelerator_suspend(info, dev);
++      if (bufs->internally_locked)
++              kfree(bufs->lock);
++      kfree(bufs);
 +}
 +
 +
-+static int netfront_suspend_cancel(struct xenbus_device *dev)
++int netfront_accel_buf_map_request(struct xenbus_device *dev,
++                                 struct netfront_accel_bufpages *bufpages,
++                                 struct net_accel_msg *msg, 
++                                 int pages, int offset)
 +{
-+      struct netfront_info *info = dev->dev.driver_data;
-+      return netfront_accelerator_suspend_cancel(info, dev);
-+}
++      int i, mfn;
++      int err;
 +
++      net_accel_msg_init(msg, NET_ACCEL_MSG_MAPBUF);
 +
-+/**
-+ * We are reconnecting to the backend, due to a suspend/resume, or a backend
-+ * driver restart.  We tear down our netif structure and recreate it, but
-+ * leave the device-layer structures intact so that this is transparent to the
-+ * rest of the kernel.
-+ */
-+static int netfront_resume(struct xenbus_device *dev)
-+{
-+      struct netfront_info *info = dev->dev.driver_data;
++      BUG_ON(pages > NET_ACCEL_MSG_MAX_PAGE_REQ);
 +
-+      DPRINTK("%s\n", dev->nodename);
++      msg->u.mapbufs.pages = pages;
 +
-+      netfront_accelerator_resume(info, dev);
++      for (i = 0; i < msg->u.mapbufs.pages; i++) {
++              /* 
++               * This can happen if we tried to send this message
++               * earlier but the queue was full.
++               */
++              if (bufpages->grant_list[offset+i] != 0) {
++                      msg->u.mapbufs.grants[i] = 
++                              bufpages->grant_list[offset+i];
++                      continue;
++              }
++
++              mfn = virt_to_mfn(bufpages->page_list[offset+i]);
++              VPRINTK("%s: Granting page %d, mfn %08x\n",
++                      __FUNCTION__, i, mfn);
++
++              bufpages->grant_list[offset+i] =
++                      net_accel_grant_page(dev, mfn, 0);
++              msg->u.mapbufs.grants[i] = bufpages->grant_list[offset+i];
++
++              if (msg->u.mapbufs.grants[i] < 0) {
++                      EPRINTK("%s: Failed to grant buffer: %d\n",
++                              __FUNCTION__, msg->u.mapbufs.grants[i]);
++                      err = -EIO;
++                      goto error;
++              }
++      }
++
++      /* This is interpreted on return as the offset in the the page_list */
++      msg->u.mapbufs.reqid = offset;
 +
-+      netif_disconnect_backend(info);
 +      return 0;
++
++error:
++      /* Ungrant all the pages we've successfully granted. */
++      for (i--; i >= 0; i--) {
++              net_accel_ungrant_page(bufpages->grant_list[offset+i]);
++              bufpages->grant_list[offset+i] = 0;
++      }
++      return err;
 +}
 +
-+static int xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
++
++/* Process a response to a buffer request. */
++int netfront_accel_add_bufs(struct netfront_accel_bufpages *bufpages,
++                          struct netfront_accel_bufinfo *manager, 
++                          struct net_accel_msg *msg)
 +{
-+      char *s, *e, *macstr;
-+      int i;
++      int msg_pages, page_offset, i, newtot;
++      int old_block_count, new_block_count;
++      u32 msg_buf;
++      unsigned long flags;
 +
-+      macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
-+      if (IS_ERR(macstr))
-+              return PTR_ERR(macstr);
++      VPRINTK("%s: manager %p msg %p\n", __FUNCTION__, manager, msg);
 +
-+      for (i = 0; i < ETH_ALEN; i++) {
-+              mac[i] = simple_strtoul(s, &e, 16);
-+              if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
-+                      kfree(macstr);
-+                      return -ENOENT;
++      BUG_ON(msg->id != (NET_ACCEL_MSG_MAPBUF | NET_ACCEL_MSG_REPLY));
++
++      msg_pages = msg->u.mapbufs.pages;
++      msg_buf = msg->u.mapbufs.buf;
++      page_offset = msg->u.mapbufs.reqid;
++
++      spin_lock_irqsave(manager->lock, flags);
++      newtot = manager->npages + msg_pages;
++      old_block_count = 
++              (manager->npages + NETFRONT_ACCEL_BUF_PAGES_PER_BLOCK - 1) >>
++              NETFRONT_ACCEL_BUF_PAGES_PER_BLOCK_SHIFT;
++      new_block_count = 
++              (newtot + NETFRONT_ACCEL_BUF_PAGES_PER_BLOCK - 1) >>
++              NETFRONT_ACCEL_BUF_PAGES_PER_BLOCK_SHIFT;
++
++      for (i = old_block_count; i < new_block_count; i++) {
++              struct netfront_accel_pkt_desc *block;
++              if (manager->desc_blocks[i] != NULL) {
++                      VPRINTK("Not needed\n");
++                      continue;
 +              }
-+              s = e+1;
++              block = kzalloc(NETFRONT_ACCEL_BUFS_PER_BLOCK * 
++                              sizeof(netfront_accel_pkt_desc), GFP_ATOMIC);
++              if (block == NULL) {
++                      spin_unlock_irqrestore(manager->lock, flags);
++                      return -ENOMEM;
++              }
++              manager->desc_blocks[i] = block;
 +      }
++      for (i = manager->npages; i < newtot; i++) {
++              int k, j = i - manager->npages;
++              int block_num;
++              int block_idx;
++              struct netfront_accel_pkt_desc *pkt;
 +
-+      kfree(macstr);
++              block_num = i >> NETFRONT_ACCEL_BUF_PAGES_PER_BLOCK_SHIFT;
++              block_idx = (NETFRONT_ACCEL_BUFS_PER_PAGE*i)
++                      & (NETFRONT_ACCEL_BUFS_PER_BLOCK-1);
++
++              pkt = manager->desc_blocks[block_num] + block_idx;
++              
++              for (k = 0; k < NETFRONT_ACCEL_BUFS_PER_PAGE; k++) {
++                      BUG_ON(page_offset + j >= bufpages->max_pages);
++
++                      pkt[k].buf_id = NETFRONT_ACCEL_BUFS_PER_PAGE * i + k;
++                      pkt[k].pkt_kva = bufpages->page_list[page_offset + j] +
++                              (PAGE_SIZE/NETFRONT_ACCEL_BUFS_PER_PAGE) * k;
++                      pkt[k].pkt_buff_addr = msg_buf +
++                              (PAGE_SIZE/NETFRONT_ACCEL_BUFS_PER_PAGE) * 
++                              (NETFRONT_ACCEL_BUFS_PER_PAGE * j + k);
++                      pkt[k].next_free = manager->first_free;
++                      manager->first_free = pkt[k].buf_id;
++                      *(int*)(pkt[k].pkt_kva) = pkt[k].buf_id;
++
++                      VPRINTK("buf %d desc %p kva %p buffaddr %x\n",
++                              pkt[k].buf_id, &(pkt[k]), pkt[k].pkt_kva, 
++                              pkt[k].pkt_buff_addr);
++              }
++      }
++      manager->npages = newtot;
++      spin_unlock_irqrestore(manager->lock, flags);
++      VPRINTK("Added %d pages. Total is now %d\n", msg_pages,
++              manager->npages);
 +      return 0;
 +}
 +
-+/* Common code used when first setting up, and when resuming. */
-+static int talk_to_backend(struct xenbus_device *dev,
-+                         struct netfront_info *info)
-+{
-+      const char *message;
-+      struct xenbus_transaction xbt;
-+      int err;
 +
-+      err = xen_net_read_mac(dev, info->mac);
-+      if (err) {
-+              xenbus_dev_fatal(dev, err, "parsing %s/mac", dev->nodename);
-+              goto out;
-+      }
++netfront_accel_pkt_desc *
++netfront_accel_buf_find(struct netfront_accel_bufinfo *manager, u16 id)
++{
++      netfront_accel_pkt_desc *pkt;
++      int block_num = id >> NETFRONT_ACCEL_BUFS_PER_BLOCK_SHIFT;
++      int block_idx = id & (NETFRONT_ACCEL_BUFS_PER_BLOCK - 1);
++      BUG_ON(id >= manager->npages * NETFRONT_ACCEL_BUFS_PER_PAGE);
++      BUG_ON(block_idx >= NETFRONT_ACCEL_BUFS_PER_BLOCK);
++      pkt = manager->desc_blocks[block_num] + block_idx;
++      return pkt;
++}
 +
-+      /* Create shared ring, alloc event channel. */
-+      err = setup_device(dev, info);
-+      if (err)
-+              goto out;
 +
-+      /* This will load an accelerator if one is configured when the
-+       * watch fires */
-+      netfront_accelerator_add_watch(info);
++/* Allocate a buffer from the buffer manager */
++netfront_accel_pkt_desc *
++netfront_accel_buf_get(struct netfront_accel_bufinfo *manager)
++{
++      int bufno = -1;
++      netfront_accel_pkt_desc *buf = NULL;
++      unsigned long flags = 0;
 +
-+again:
-+      err = xenbus_transaction_start(&xbt);
-+      if (err) {
-+              xenbus_dev_fatal(dev, err, "starting transaction");
-+              goto destroy_ring;
-+      }
++      /* Any spare? */
++      if (manager->first_free == -1)
++              return NULL;
++      /* Take lock */
++      if (manager->internally_locked)
++              spin_lock_irqsave(manager->lock, flags);
++      bufno = manager->first_free;
++      if (bufno != -1) {
++              buf = netfront_accel_buf_find(manager, bufno);
++              manager->first_free = buf->next_free;
++              manager->nused++;
++      }
++      /* Release lock */
++      if (manager->internally_locked)
++              spin_unlock_irqrestore(manager->lock, flags);
++
++      /* Tell the world */
++      VPRINTK("Allocated buffer %i, buffaddr %x\n", bufno,
++              buf->pkt_buff_addr);
 +
-+      err = xenbus_printf(xbt, dev->nodename, "tx-ring-ref","%u",
-+                          info->tx_ring_ref);
-+      if (err) {
-+              message = "writing tx ring-ref";
-+              goto abort_transaction;
-+      }
-+      err = xenbus_printf(xbt, dev->nodename, "rx-ring-ref","%u",
-+                          info->rx_ring_ref);
-+      if (err) {
-+              message = "writing rx ring-ref";
-+              goto abort_transaction;
-+      }
-+      err = xenbus_printf(xbt, dev->nodename,
-+                          "event-channel", "%u",
-+                          irq_to_evtchn_port(info->irq));
-+      if (err) {
-+              message = "writing event-channel";
-+              goto abort_transaction;
-+      }
++      return buf;
++}
 +
-+      err = xenbus_printf(xbt, dev->nodename, "request-rx-copy", "%u",
-+                          info->copying_receiver);
-+      if (err) {
-+              message = "writing request-rx-copy";
-+              goto abort_transaction;
-+      }
 +
-+      err = xenbus_printf(xbt, dev->nodename, "feature-rx-notify", "%d", 1);
-+      if (err) {
-+              message = "writing feature-rx-notify";
-+              goto abort_transaction;
-+      }
++/* Release a buffer back to the buffer manager pool */
++int netfront_accel_buf_put(struct netfront_accel_bufinfo *manager, u16 id)
++{
++      netfront_accel_pkt_desc *buf = netfront_accel_buf_find(manager, id);
++      unsigned long flags = 0;
++      unsigned was_empty = 0;
++      int bufno = id;
 +
-+      err = xenbus_printf(xbt, dev->nodename, "feature-no-csum-offload",
-+                          "%d", !HAVE_CSUM_OFFLOAD);
-+      if (err) {
-+              message = "writing feature-no-csum-offload";
-+              goto abort_transaction;
-+      }
++      VPRINTK("Freeing buffer %i\n", id);
++      BUG_ON(id == (u16)-1);
 +
-+      err = xenbus_printf(xbt, dev->nodename, "feature-sg", "%d", 1);
-+      if (err) {
-+              message = "writing feature-sg";
-+              goto abort_transaction;
-+      }
++      if (manager->internally_locked)
++              spin_lock_irqsave(manager->lock, flags);
 +
-+      err = xenbus_printf(xbt, dev->nodename, "feature-gso-tcpv4", "%d",
-+                          HAVE_TSO);
-+      if (err) {
-+              message = "writing feature-gso-tcpv4";
-+              goto abort_transaction;
-+      }
++      if (manager->first_free == -1)
++              was_empty = 1;
 +
-+      err = xenbus_transaction_end(xbt, 0);
-+      if (err) {
-+              if (err == -EAGAIN)
-+                      goto again;
-+              xenbus_dev_fatal(dev, err, "completing transaction");
-+              goto destroy_ring;
-+      }
++      buf->next_free = manager->first_free;
++      manager->first_free = bufno;
++      manager->nused--;
 +
-+      return 0;
++      if (manager->internally_locked)
++              spin_unlock_irqrestore(manager->lock, flags);
 +
-+ abort_transaction:
-+      xenbus_transaction_end(xbt, 1);
-+      xenbus_dev_fatal(dev, err, "%s", message);
-+ destroy_ring:
-+      netfront_accelerator_call_remove(info, dev);
-+      netif_disconnect_backend(info);
-+ out:
-+      return err;
++      return was_empty;
 +}
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel_bufs.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel_bufs.h  2008-05-19 00:33:48.618948572 +0300
+@@ -0,0 +1,181 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static int setup_device(struct xenbus_device *dev, struct netfront_info *info)
-+{
-+      struct netif_tx_sring *txs;
-+      struct netif_rx_sring *rxs;
-+      int err;
-+      struct net_device *netdev = info->netdev;
++#ifndef NETFRONT_ACCEL_BUFS_H
++#define NETFRONT_ACCEL_BUFS_H
 +
-+      info->tx_ring_ref = GRANT_INVALID_REF;
-+      info->rx_ring_ref = GRANT_INVALID_REF;
-+      info->rx.sring = NULL;
-+      info->tx.sring = NULL;
-+      info->irq = 0;
++#include <linux/skbuff.h>
++#include <linux/spinlock.h>
++#include <xen/xenbus.h>
 +
-+      txs = (struct netif_tx_sring *)get_zeroed_page(GFP_KERNEL);
-+      if (!txs) {
-+              err = -ENOMEM;
-+              xenbus_dev_fatal(dev, err, "allocating tx ring page");
-+              goto fail;
-+      }
-+      SHARED_RING_INIT(txs);
-+      FRONT_RING_INIT(&info->tx, txs, PAGE_SIZE);
++#include "accel_msg_iface.h"
 +
-+      err = xenbus_grant_ring(dev, virt_to_mfn(txs));
-+      if (err < 0) {
-+              free_page((unsigned long)txs);
-+              goto fail;
-+      }
-+      info->tx_ring_ref = err;
 +
-+      rxs = (struct netif_rx_sring *)get_zeroed_page(GFP_KERNEL);
-+      if (!rxs) {
-+              err = -ENOMEM;
-+              xenbus_dev_fatal(dev, err, "allocating rx ring page");
-+              goto fail;
-+      }
-+      SHARED_RING_INIT(rxs);
-+      FRONT_RING_INIT(&info->rx, rxs, PAGE_SIZE);
++/*! Buffer descriptor structure */
++typedef struct netfront_accel_pkt_desc {
++      int buf_id;
++      u32 pkt_buff_addr;
++      void *pkt_kva;
++      /* This is the socket buffer currently married to this buffer */
++      struct sk_buff *skb;
++      int next_free;
++} netfront_accel_pkt_desc;
++
++
++#define NETFRONT_ACCEL_DEFAULT_BUF_PAGES (384)
++#define NETFRONT_ACCEL_BUF_PAGES_PER_BLOCK_SHIFT (4)
++#define NETFRONT_ACCEL_BUF_PAGES_PER_BLOCK            \
++      (1 << (NETFRONT_ACCEL_BUF_PAGES_PER_BLOCK_SHIFT))
++#define NETFRONT_ACCEL_BUFS_PER_PAGE_SHIFT (1)
++#define NETFRONT_ACCEL_BUFS_PER_PAGE                  \
++      (1 << (NETFRONT_ACCEL_BUFS_PER_PAGE_SHIFT))
++#define NETFRONT_ACCEL_BUFS_PER_BLOCK_SHIFT           \
++      (NETFRONT_ACCEL_BUF_PAGES_PER_BLOCK_SHIFT +     \
++       NETFRONT_ACCEL_BUFS_PER_PAGE_SHIFT)
++#define NETFRONT_ACCEL_BUFS_PER_BLOCK                 \
++      (1 << NETFRONT_ACCEL_BUFS_PER_BLOCK_SHIFT)
++#define NETFRONT_ACCEL_BUF_NUM_BLOCKS(max_pages)                      \
++      (((max_pages)+NETFRONT_ACCEL_BUF_PAGES_PER_BLOCK-1) /           \
++       NETFRONT_ACCEL_BUF_PAGES_PER_BLOCK)
++
++/*! Buffer management structure. */
++struct netfront_accel_bufinfo {
++      /* number added to this manager */
++      unsigned npages;
++      /* number currently used from this manager */
++      unsigned nused;
++
++      int first_free;
++
++      int internally_locked;
++      spinlock_t *lock;
 +
-+      err = xenbus_grant_ring(dev, virt_to_mfn(rxs));
-+      if (err < 0) {
-+              free_page((unsigned long)rxs);
-+              goto fail;
-+      }
-+      info->rx_ring_ref = err;
++      /*
++       * array of pointers (length NETFRONT_ACCEL_BUF_NUM_BLOCKS) to
++       * pkt descs
++       */
++      struct netfront_accel_pkt_desc **desc_blocks; 
++};
 +
-+      memcpy(netdev->dev_addr, info->mac, ETH_ALEN);
 +
-+      err = bind_listening_port_to_irqhandler(
-+              dev->otherend_id, netif_int, SA_SAMPLE_RANDOM, netdev->name,
-+              netdev);
-+      if (err < 0)
-+              goto fail;
-+      info->irq = err;
++struct netfront_accel_bufpages {
++      /* length of lists of pages/grants */
++      int max_pages;
++      /* list of pages allocated for network buffers */
++      void **page_list;
++      /* list of grants for the above pages */
++      grant_ref_t *grant_list;
++      
++      /* number of page requests that have been made */
++      unsigned page_reqs;
++};
 +
-+      return 0;
 +
-+ fail:
-+      return err;
-+}
++/*! Allocate memory for the buffer manager, set up locks etc.
++ * Optionally takes a lock to use, if not supplied it makes its own.
++ *
++ * \return pointer to netfront_accel_bufinfo structure that represents the
++ * buffer manager
++ */
++extern struct netfront_accel_bufinfo *
++netfront_accel_init_bufs(spinlock_t *lock);
 +
-+/**
-+ * Callback received when the backend's state changes.
++/*! Allocate memory for the buffers
 + */
-+static void backend_changed(struct xenbus_device *dev,
-+                          enum xenbus_state backend_state)
-+{
-+      struct netfront_info *np = dev->dev.driver_data;
-+      struct net_device *netdev = np->netdev;
++extern int
++netfront_accel_alloc_buffer_mem(struct netfront_accel_bufpages *bufpages,
++                              struct netfront_accel_bufinfo *rx_res,
++                              struct netfront_accel_bufinfo *tx_res,
++                              int pages);
++extern void
++netfront_accel_free_buffer_mem(struct netfront_accel_bufpages *bufpages,
++                             struct netfront_accel_bufinfo *rx_res,
++                             struct netfront_accel_bufinfo *tx_res);
 +
-+      DPRINTK("%s\n", xenbus_strstate(backend_state));
++/*! Release memory for the buffer manager, buffers, etc.
++ *
++ * \param manager pointer to netfront_accel_bufinfo structure that
++ * represents the buffer manager
++ */
++extern void netfront_accel_fini_bufs(struct netfront_accel_bufinfo *manager);
 +
-+      switch (backend_state) {
-+      case XenbusStateInitialising:
-+      case XenbusStateInitialised:
-+      case XenbusStateConnected:
-+      case XenbusStateUnknown:
-+      case XenbusStateClosed:
-+              break;
++/*! Release a buffer.
++ *
++ * \param manager  The buffer manager which owns the buffer.
++ * \param id   The buffer identifier.
++ */
++extern int netfront_accel_buf_put(struct netfront_accel_bufinfo *manager, 
++                                u16 id);
 +
-+      case XenbusStateInitWait:
-+              if (dev->state != XenbusStateInitialising)
-+                      break;
-+              if (network_connect(netdev) != 0)
-+                      break;
-+              xenbus_switch_state(dev, XenbusStateConnected);
-+              send_fake_arp(netdev);
-+              break;
++/*! Get the packet descriptor associated with a buffer id.
++ *
++ * \param manager  The buffer manager which owns the buffer.
++ * \param id       The buffer identifier.
++ *
++ * The returned value is the packet descriptor for this buffer.
++ */
++extern netfront_accel_pkt_desc *
++netfront_accel_buf_find(struct netfront_accel_bufinfo *manager, u16 id);
 +
-+      case XenbusStateClosing:
-+              xenbus_frontend_closed(dev);
-+              break;
-+      }
-+}
 +
-+/** Send a packet on a net device to encourage switches to learn the
-+ * MAC. We send a fake ARP request.
++/*! Fill out a message request for some buffers to be mapped by the
++ * back end driver
++ * 
++ * \param manager The buffer manager 
++ * \param msg Pointer to an ef_msg to complete.
++ * \return 0 on success
++ */
++extern int 
++netfront_accel_buf_map_request(struct xenbus_device *dev,
++                             struct netfront_accel_bufpages *bufpages,
++                             struct net_accel_msg *msg, 
++                             int pages, int offset);
++
++/*! Process a response to a buffer request. 
++ * 
++ * Deal with a received message from the back end in response to our
++ * request for buffers
++ * 
++ * \param manager The buffer manager
++ * \param msg The received message from the back end describing new
++ * buffers
++ * \return 0 on success
++ */
++extern int 
++netfront_accel_add_bufs(struct netfront_accel_bufpages *bufpages,
++                      struct netfront_accel_bufinfo *manager,
++                      struct net_accel_msg *msg);
++
++
++/*! Allocate a buffer from the buffer manager 
 + *
-+ * @param dev device
-+ * @return 0 on success, error code otherwise
++ * \param manager The buffer manager data structure
++ * \param id On exit, the id of the buffer allocated
++ * \return Pointer to buffer descriptor.
 + */
-+static void send_fake_arp(struct net_device *dev)
-+{
-+#ifdef CONFIG_INET
-+      struct sk_buff *skb;
-+      u32             src_ip, dst_ip;
++struct netfront_accel_pkt_desc *
++netfront_accel_buf_get(struct netfront_accel_bufinfo *manager);
 +
-+      dst_ip = INADDR_BROADCAST;
-+      src_ip = inet_select_addr(dev, dst_ip, RT_SCOPE_LINK);
++#endif /* NETFRONT_ACCEL_BUFS_H */
 +
-+      /* No IP? Then nothing to do. */
-+      if (src_ip == 0)
-+              return;
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel_debugfs.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel_debugfs.c       2008-05-19 00:33:48.618948572 +0300
+@@ -0,0 +1,211 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      skb = arp_create(ARPOP_REPLY, ETH_P_ARP,
-+                       dst_ip, dev, src_ip,
-+                       /*dst_hw*/ NULL, /*src_hw*/ NULL,
-+                       /*target_hw*/ dev->dev_addr);
-+      if (skb == NULL)
-+              return;
++#include <linux/fs.h>
++#include <linux/debugfs.h>
++
++#include "accel.h"
++
++#if defined(CONFIG_DEBUG_FS)
++static struct dentry *sfc_debugfs_root = NULL;
++#endif
 +
-+      dev_queue_xmit(skb);
++void netfront_accel_debugfs_init(void) 
++{
++#if defined(CONFIG_DEBUG_FS)
++      sfc_debugfs_root = debugfs_create_dir(frontend_name, NULL);
 +#endif
 +}
 +
-+static inline int netfront_tx_slot_available(struct netfront_info *np)
++
++void netfront_accel_debugfs_fini(void)
 +{
-+      return ((np->tx.req_prod_pvt - np->tx.rsp_cons) <
-+              (TX_MAX_TARGET - MAX_SKB_FRAGS - 2));
++#if defined(CONFIG_DEBUG_FS)
++      if (sfc_debugfs_root)
++              debugfs_remove(sfc_debugfs_root);
++#endif
 +}
 +
 +
-+static inline void network_maybe_wake_tx(struct net_device *dev)
++int netfront_accel_debugfs_create(netfront_accel_vnic *vnic)
 +{
-+      struct netfront_info *np = netdev_priv(dev);
++#if defined(CONFIG_DEBUG_FS)
++      if (sfc_debugfs_root == NULL)
++              return -ENOENT;
 +
-+      if (unlikely(netif_queue_stopped(dev)) &&
-+          netfront_tx_slot_available(np) &&
-+          likely(netif_running(dev)) &&
-+          netfront_check_accelerator_queue_ready(dev, np))
-+              netif_wake_queue(dev);
++      vnic->dbfs_dir = debugfs_create_dir(vnic->net_dev->name, 
++                                          sfc_debugfs_root);
++      if (vnic->dbfs_dir == NULL)
++              return -ENOMEM;
++
++      vnic->netdev_dbfs.fastpath_rx_pkts = debugfs_create_u32
++              ("fastpath_rx_pkts", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->netdev_stats.fastpath_rx_pkts);
++      vnic->netdev_dbfs.fastpath_rx_bytes = debugfs_create_u32
++              ("fastpath_rx_bytes", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->netdev_stats.fastpath_rx_bytes);
++      vnic->netdev_dbfs.fastpath_rx_errors = debugfs_create_u32
++              ("fastpath_rx_errors", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->netdev_stats.fastpath_rx_errors);
++      vnic->netdev_dbfs.fastpath_tx_pkts = debugfs_create_u32
++              ("fastpath_tx_pkts", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->netdev_stats.fastpath_tx_pkts);
++      vnic->netdev_dbfs.fastpath_tx_bytes = debugfs_create_u32
++              ("fastpath_tx_bytes", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->netdev_stats.fastpath_tx_bytes);
++      vnic->netdev_dbfs.fastpath_tx_errors = debugfs_create_u32
++              ("fastpath_tx_errors", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->netdev_stats.fastpath_tx_errors);
++
++#if NETFRONT_ACCEL_STATS
++      vnic->dbfs.irq_count = debugfs_create_u64
++              ("irq_count", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.irq_count);
++      vnic->dbfs.useless_irq_count = debugfs_create_u64
++              ("useless_irq_count", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.useless_irq_count);
++      vnic->dbfs.poll_schedule_count = debugfs_create_u64
++              ("poll_schedule_count", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.poll_schedule_count);
++      vnic->dbfs.poll_call_count = debugfs_create_u64
++              ("poll_call_count", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.poll_call_count);
++      vnic->dbfs.poll_reschedule_count = debugfs_create_u64
++              ("poll_reschedule_count", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.poll_reschedule_count);
++      vnic->dbfs.queue_stops = debugfs_create_u64
++              ("queue_stops", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.queue_stops);
++      vnic->dbfs.queue_wakes = debugfs_create_u64
++              ("queue_wakes", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.queue_wakes);
++      vnic->dbfs.ssr_bursts = debugfs_create_u64
++              ("ssr_bursts", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.ssr_bursts);
++      vnic->dbfs.ssr_drop_stream = debugfs_create_u64
++              ("ssr_drop_stream", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.ssr_drop_stream);
++      vnic->dbfs.ssr_misorder = debugfs_create_u64
++              ("ssr_misorder", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.ssr_misorder);
++      vnic->dbfs.ssr_slow_start = debugfs_create_u64
++              ("ssr_slow_start", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.ssr_slow_start);
++      vnic->dbfs.ssr_merges = debugfs_create_u64
++              ("ssr_merges", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.ssr_merges);
++      vnic->dbfs.ssr_too_many = debugfs_create_u64
++              ("ssr_too_many", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.ssr_too_many);
++      vnic->dbfs.ssr_new_stream = debugfs_create_u64
++              ("ssr_new_stream", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.ssr_new_stream);
++
++      vnic->dbfs.fastpath_tx_busy = debugfs_create_u64
++              ("fastpath_tx_busy", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.fastpath_tx_busy);
++      vnic->dbfs.fastpath_tx_completions = debugfs_create_u64
++              ("fastpath_tx_completions", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.fastpath_tx_completions);
++      vnic->dbfs.fastpath_tx_pending_max = debugfs_create_u32
++              ("fastpath_tx_pending_max", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.fastpath_tx_pending_max);
++      vnic->dbfs.event_count = debugfs_create_u64
++              ("event_count", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.event_count);
++      vnic->dbfs.bad_event_count = debugfs_create_u64
++              ("bad_event_count", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.bad_event_count);
++      vnic->dbfs.event_count_since_irq = debugfs_create_u32
++              ("event_count_since_irq", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.event_count_since_irq);
++      vnic->dbfs.events_per_irq_max = debugfs_create_u32
++              ("events_per_irq_max", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.events_per_irq_max);
++      vnic->dbfs.fastpath_frm_trunc = debugfs_create_u64
++              ("fastpath_frm_trunc", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.fastpath_frm_trunc);
++      vnic->dbfs.rx_no_desc_trunc = debugfs_create_u64
++              ("rx_no_desc_trunc", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.rx_no_desc_trunc);
++      vnic->dbfs.events_per_poll_max = debugfs_create_u32
++              ("events_per_poll_max", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.events_per_poll_max);
++      vnic->dbfs.events_per_poll_rx_max = debugfs_create_u32
++              ("events_per_poll_rx_max", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.events_per_poll_rx_max);
++      vnic->dbfs.events_per_poll_tx_max = debugfs_create_u32
++              ("events_per_poll_tx_max", S_IRUSR | S_IRGRP | S_IROTH,
++               vnic->dbfs_dir, &vnic->stats.events_per_poll_tx_max);
++#endif
++#endif
++      return 0;
 +}
 +
 +
-+int netfront_check_queue_ready(struct net_device *dev)
++int netfront_accel_debugfs_remove(netfront_accel_vnic *vnic)
 +{
-+      struct netfront_info *np = netdev_priv(dev);
-+
-+      return unlikely(netif_queue_stopped(dev)) &&
-+              netfront_tx_slot_available(np) &&
-+              likely(netif_running(dev));
++#if defined(CONFIG_DEBUG_FS)
++      if (vnic->dbfs_dir != NULL) {
++              debugfs_remove(vnic->netdev_dbfs.fastpath_rx_pkts);
++              debugfs_remove(vnic->netdev_dbfs.fastpath_rx_bytes);
++              debugfs_remove(vnic->netdev_dbfs.fastpath_rx_errors);
++              debugfs_remove(vnic->netdev_dbfs.fastpath_tx_pkts);
++              debugfs_remove(vnic->netdev_dbfs.fastpath_tx_bytes);
++              debugfs_remove(vnic->netdev_dbfs.fastpath_tx_errors);
++              
++#if NETFRONT_ACCEL_STATS
++              debugfs_remove(vnic->dbfs.irq_count);
++              debugfs_remove(vnic->dbfs.useless_irq_count);
++              debugfs_remove(vnic->dbfs.poll_schedule_count);
++              debugfs_remove(vnic->dbfs.poll_call_count);
++              debugfs_remove(vnic->dbfs.poll_reschedule_count);
++              debugfs_remove(vnic->dbfs.queue_stops);
++              debugfs_remove(vnic->dbfs.queue_wakes);
++              debugfs_remove(vnic->dbfs.ssr_bursts);
++              debugfs_remove(vnic->dbfs.ssr_drop_stream);
++              debugfs_remove(vnic->dbfs.ssr_misorder);
++              debugfs_remove(vnic->dbfs.ssr_slow_start);
++              debugfs_remove(vnic->dbfs.ssr_merges);
++              debugfs_remove(vnic->dbfs.ssr_too_many);
++              debugfs_remove(vnic->dbfs.ssr_new_stream);
++              
++              debugfs_remove(vnic->dbfs.fastpath_tx_busy);
++              debugfs_remove(vnic->dbfs.fastpath_tx_completions);
++              debugfs_remove(vnic->dbfs.fastpath_tx_pending_max);
++              debugfs_remove(vnic->dbfs.event_count);
++              debugfs_remove(vnic->dbfs.bad_event_count);
++              debugfs_remove(vnic->dbfs.event_count_since_irq);
++              debugfs_remove(vnic->dbfs.events_per_irq_max);
++              debugfs_remove(vnic->dbfs.fastpath_frm_trunc);
++              debugfs_remove(vnic->dbfs.rx_no_desc_trunc);
++              debugfs_remove(vnic->dbfs.events_per_poll_max);
++              debugfs_remove(vnic->dbfs.events_per_poll_rx_max);
++              debugfs_remove(vnic->dbfs.events_per_poll_tx_max);
++#endif
++              debugfs_remove(vnic->dbfs_dir);
++      }
++#endif
++      return 0;
 +}
-+EXPORT_SYMBOL(netfront_check_queue_ready);
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel_msg.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel_msg.c   2008-05-19 00:33:48.618948572 +0300
+@@ -0,0 +1,566 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
++#include <linux/stddef.h>
++#include <linux/errno.h>
 +
-+static int network_open(struct net_device *dev)
-+{
-+      struct netfront_info *np = netdev_priv(dev);
++#include <xen/xenbus.h>
 +
-+      memset(&np->stats, 0, sizeof(np->stats));
++#include "accel.h"
++#include "accel_msg_iface.h"
++#include "accel_util.h"
++#include "accel_bufs.h"
 +
-+      spin_lock_bh(&np->rx_lock);
-+      if (netfront_carrier_ok(np)) {
-+              network_alloc_rx_buffers(dev);
-+              np->rx.sring->rsp_event = np->rx.rsp_cons + 1;
-+              if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)){
-+                      netfront_accelerator_call_stop_napi_irq(np, dev);
++#include "netfront.h" /* drivers/xen/netfront/netfront.h */
 +
-+                      netif_rx_schedule(dev);
-+              }
++static void vnic_start_interrupts(netfront_accel_vnic *vnic)
++{
++      unsigned long flags;
++      
++      /* Prime our interrupt */
++      spin_lock_irqsave(&vnic->irq_enabled_lock, flags);
++      if (!netfront_accel_vi_enable_interrupts(vnic)) {
++              /* Cripes, that was quick, better pass it up */
++              netfront_accel_disable_net_interrupts(vnic);
++              vnic->irq_enabled = 0;
++              NETFRONT_ACCEL_STATS_OP(vnic->stats.poll_schedule_count++);
++              netif_rx_schedule(vnic->net_dev);
++      } else {
++              /*
++               * Nothing yet, make sure we get interrupts through
++               * back end 
++               */
++              vnic->irq_enabled = 1;
++              netfront_accel_enable_net_interrupts(vnic);
 +      }
-+      spin_unlock_bh(&np->rx_lock);
++      spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags);
++}
 +
-+      network_maybe_wake_tx(dev);
 +
-+      return 0;
++static void vnic_stop_interrupts(netfront_accel_vnic *vnic)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&vnic->irq_enabled_lock, flags);
++      netfront_accel_disable_net_interrupts(vnic);
++      vnic->irq_enabled = 0;
++      spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags);
 +}
 +
-+static void network_tx_buf_gc(struct net_device *dev)
++
++static void vnic_start_fastpath(netfront_accel_vnic *vnic)
 +{
-+      RING_IDX cons, prod;
-+      unsigned short id;
-+      struct netfront_info *np = netdev_priv(dev);
-+      struct sk_buff *skb;
++      struct net_device *net_dev = vnic->net_dev;
++      unsigned long flags;
 +
-+      BUG_ON(!netfront_carrier_ok(np));
++      DPRINTK("%s\n", __FUNCTION__);
 +
-+      do {
-+              prod = np->tx.sring->rsp_prod;
-+              rmb(); /* Ensure we see responses up to 'rp'. */
++      spin_lock_irqsave(&vnic->tx_lock, flags);
++      vnic->tx_enabled = 1;
++      spin_unlock_irqrestore(&vnic->tx_lock, flags);
++      
++      netif_poll_disable(net_dev);
++      vnic->poll_enabled = 1;
++      netif_poll_enable(net_dev);
++      
++      vnic_start_interrupts(vnic);
++}
 +
-+              for (cons = np->tx.rsp_cons; cons != prod; cons++) {
-+                      struct netif_tx_response *txrsp;
 +
-+                      txrsp = RING_GET_RESPONSE(&np->tx, cons);
-+                      if (txrsp->status == NETIF_RSP_NULL)
-+                              continue;
++void vnic_stop_fastpath(netfront_accel_vnic *vnic)
++{
++      struct net_device *net_dev = vnic->net_dev;
++      struct netfront_info *np = (struct netfront_info *)netdev_priv(net_dev);
++      unsigned long flags1, flags2;
 +
-+                      id  = txrsp->id;
-+                      skb = np->tx_skbs[id];
-+                      if (unlikely(gnttab_query_foreign_access(
-+                              np->grant_tx_ref[id]) != 0)) {
-+                              printk(KERN_ALERT "network_tx_buf_gc: warning "
-+                                     "-- grant still in use by backend "
-+                                     "domain.\n");
-+                              BUG();
-+                      }
-+                      gnttab_end_foreign_access_ref(np->grant_tx_ref[id]);
-+                      gnttab_release_grant_reference(
-+                              &np->gref_tx_head, np->grant_tx_ref[id]);
-+                      np->grant_tx_ref[id] = GRANT_INVALID_REF;
-+                      add_id_to_freelist(np->tx_skbs, id);
-+                      dev_kfree_skb_irq(skb);
-+              }
++      DPRINTK("%s\n", __FUNCTION__);
 +
-+              np->tx.rsp_cons = prod;
++      vnic_stop_interrupts(vnic);
++      
++      spin_lock_irqsave(&vnic->tx_lock, flags1);
++      vnic->tx_enabled = 0;
++      spin_lock_irqsave(&np->tx_lock, flags2);
++      if (vnic->tx_skb != NULL) {
++              dev_kfree_skb_any(vnic->tx_skb);
++              vnic->tx_skb = NULL;
++              if (netfront_check_queue_ready(net_dev)) {
++                      netif_wake_queue(net_dev);
++                      NETFRONT_ACCEL_STATS_OP
++                              (vnic->stats.queue_wakes++);
++              }
++      }
++      spin_unlock_irqrestore(&np->tx_lock, flags2);
++      spin_unlock_irqrestore(&vnic->tx_lock, flags1);
++      
++      /* Must prevent polls and hold lock to modify poll_enabled */
++      netif_poll_disable(net_dev);
++      spin_lock_irqsave(&vnic->irq_enabled_lock, flags1);
++      vnic->poll_enabled = 0;
++      spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags1);
++      netif_poll_enable(net_dev);
++}
 +
-+              /*
-+               * Set a new event, then check for race with update of tx_cons.
-+               * Note that it is essential to schedule a callback, no matter
-+               * how few buffers are pending. Even if there is space in the
-+               * transmit ring, higher layers may be blocked because too much
-+               * data is outstanding: in such cases notification from Xen is
-+               * likely to be the only kick that we'll get.
-+               */
-+              np->tx.sring->rsp_event =
-+                      prod + ((np->tx.sring->req_prod - prod) >> 1) + 1;
-+              mb();
-+      } while ((cons == prod) && (prod != np->tx.sring->rsp_prod));
 +
-+      network_maybe_wake_tx(dev);
++static void netfront_accel_interface_up(netfront_accel_vnic *vnic)
++{
++
++      if (!vnic->backend_netdev_up) {
++              vnic->backend_netdev_up = 1;
++              
++              if (vnic->frontend_ready)
++                      vnic_start_fastpath(vnic);
++      }
 +}
 +
-+static void rx_refill_timeout(unsigned long data)
-+{
-+      struct net_device *dev = (struct net_device *)data;
-+      struct netfront_info *np = netdev_priv(dev);
 +
-+      netfront_accelerator_call_stop_napi_irq(np, dev);
++static void netfront_accel_interface_down(netfront_accel_vnic *vnic)
++{
 +
-+      netif_rx_schedule(dev);
++      if (vnic->backend_netdev_up) {
++              vnic->backend_netdev_up = 0;
++              
++              if (vnic->frontend_ready)
++                      vnic_stop_fastpath(vnic);
++      }
 +}
 +
-+static void network_alloc_rx_buffers(struct net_device *dev)
++
++static int vnic_add_bufs(netfront_accel_vnic *vnic, 
++                       struct net_accel_msg *msg)
 +{
-+      unsigned short id;
-+      struct netfront_info *np = netdev_priv(dev);
-+      struct sk_buff *skb;
-+      struct page *page;
-+      int i, batch_target, notify;
-+      RING_IDX req_prod = np->rx.req_prod_pvt;
-+      struct xen_memory_reservation reservation;
-+      grant_ref_t ref;
-+      unsigned long pfn;
-+      void *vaddr;
-+      int nr_flips;
-+      netif_rx_request_t *req;
++      int rc, offset;
++      struct netfront_accel_bufinfo *bufinfo;
++  
++      BUG_ON(msg->u.mapbufs.pages > NET_ACCEL_MSG_MAX_PAGE_REQ);
 +
-+      if (unlikely(!netfront_carrier_ok(np)))
-+              return;
++      offset = msg->u.mapbufs.reqid;
 +
-+      /*
-+       * Allocate skbuffs greedily, even though we batch updates to the
-+       * receive ring. This creates a less bursty demand on the memory
-+       * allocator, so should reduce the chance of failed allocation requests
-+       * both for ourself and for other kernel subsystems.
-+       */
-+      batch_target = np->rx_target - (req_prod - np->rx.rsp_cons);
-+      for (i = skb_queue_len(&np->rx_batch); i < batch_target; i++) {
-+              /*
-+               * Allocate an skb and a page. Do not use __dev_alloc_skb as
-+               * that will allocate page-sized buffers which is not
-+               * necessary here.
-+               * 16 bytes added as necessary headroom for netif_receive_skb.
-+               */
-+              skb = alloc_skb(RX_COPY_THRESHOLD + 16 + NET_IP_ALIGN,
-+                              GFP_ATOMIC | __GFP_NOWARN);
-+              if (unlikely(!skb))
-+                      goto no_skb;
++      if (offset < vnic->bufpages.max_pages - 
++          (vnic->bufpages.max_pages / sfc_netfront_buffer_split)) {
++              bufinfo = vnic->rx_bufs;
++      } else
++              bufinfo = vnic->tx_bufs;
 +
-+              page = alloc_page(GFP_ATOMIC | __GFP_NOWARN);
-+              if (!page) {
-+                      kfree_skb(skb);
-+no_skb:
-+                      /* Any skbuffs queued for refill? Force them out. */
-+                      if (i != 0)
-+                              goto refill;
-+                      /* Could not allocate any skbuffs. Try again later. */
-+                      mod_timer(&np->rx_refill_timer,
-+                                jiffies + (HZ/10));
-+                      break;
-+              }
++      /* Queue up some Rx buffers to start things off. */
++      if ((rc = netfront_accel_add_bufs(&vnic->bufpages, bufinfo, msg)) == 0) {
++              netfront_accel_vi_add_bufs(vnic, bufinfo == vnic->rx_bufs);
 +
-+              skb_reserve(skb, 16 + NET_IP_ALIGN); /* mimic dev_alloc_skb() */
-+              skb_shinfo(skb)->frags[0].page = page;
-+              skb_shinfo(skb)->nr_frags = 1;
-+              __skb_queue_tail(&np->rx_batch, skb);
++              if (offset + msg->u.mapbufs.pages == vnic->bufpages.max_pages) {
++                      VPRINTK("%s: got all buffers back\n", __FUNCTION__);
++                      vnic->frontend_ready = 1;
++                      if (vnic->backend_netdev_up)
++                              vnic_start_fastpath(vnic);
++              } else {
++                      VPRINTK("%s: got buffers back %d %d\n", __FUNCTION__, 
++                              offset, msg->u.mapbufs.pages);
++              }
 +      }
 +
-+      /* Is the batch large enough to be worthwhile? */
-+      if (i < (np->rx_target/2)) {
-+              if (req_prod > np->rx.sring->req_prod)
-+                      goto push;
-+              return;
-+      }
++      return rc;
++}
 +
-+      /* Adjust our fill target if we risked running out of buffers. */
-+      if (((req_prod - np->rx.sring->rsp_prod) < (np->rx_target / 4)) &&
-+          ((np->rx_target *= 2) > np->rx_max_target))
-+              np->rx_target = np->rx_max_target;
 +
-+ refill:
-+      for (nr_flips = i = 0; ; i++) {
-+              if ((skb = __skb_dequeue(&np->rx_batch)) == NULL)
-+                      break;
++/* The largest [o] such that (1u << o) <= n.  Requires n > 0. */
 +
-+              skb->dev = dev;
++inline unsigned log2_le(unsigned long n) {
++      unsigned order = 1;
++      while ((1ul << order) <= n) ++order;
++      return (order - 1);
++}
 +
-+              id = xennet_rxidx(req_prod + i);
++static int vnic_send_buffer_requests(netfront_accel_vnic *vnic,
++                                   struct netfront_accel_bufpages *bufpages)
++{
++      int pages, offset, rc = 0, sent = 0;
++      struct net_accel_msg msg;
 +
-+              BUG_ON(np->rx_skbs[id]);
-+              np->rx_skbs[id] = skb;
++      while (bufpages->page_reqs < bufpages->max_pages) {
++              offset = bufpages->page_reqs;
 +
-+              ref = gnttab_claim_grant_reference(&np->gref_rx_head);
-+              BUG_ON((signed short)ref < 0);
-+              np->grant_rx_ref[id] = ref;
++              pages = pow2(log2_le(bufpages->max_pages - 
++                                   bufpages->page_reqs));
++              pages = pages < NET_ACCEL_MSG_MAX_PAGE_REQ ? 
++                      pages : NET_ACCEL_MSG_MAX_PAGE_REQ;
 +
-+              pfn = page_to_pfn(skb_shinfo(skb)->frags[0].page);
-+              vaddr = page_address(skb_shinfo(skb)->frags[0].page);
++              BUG_ON(offset < 0);
++              BUG_ON(pages <= 0);
 +
-+              req = RING_GET_REQUEST(&np->rx, req_prod + i);
-+              if (!np->copying_receiver) {
-+                      gnttab_grant_foreign_transfer_ref(ref,
-+                                                        np->xbdev->otherend_id,
-+                                                        pfn);
-+                      np->rx_pfn_array[nr_flips] = pfn_to_mfn(pfn);
-+                      if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+                              /* Remove this page before passing
-+                               * back to Xen. */
-+                              set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
-+                              MULTI_update_va_mapping(np->rx_mcl+i,
-+                                                      (unsigned long)vaddr,
-+                                                      __pte(0), 0);
++              rc = netfront_accel_buf_map_request(vnic->dev, bufpages,
++                                                  &msg, pages, offset);
++              if (rc == 0) {
++                      rc = net_accel_msg_send(vnic->shared_page, 
++                                              &vnic->to_dom0, &msg);
++                      if (rc < 0) {
++                              VPRINTK("%s: queue full, stopping for now\n",
++                                      __FUNCTION__);
++                              break;
 +                      }
-+                      nr_flips++;
++                      sent++;
 +              } else {
-+                      gnttab_grant_foreign_access_ref(ref,
-+                                                      np->xbdev->otherend_id,
-+                                                      pfn_to_mfn(pfn),
-+                                                      0);
++                      EPRINTK("%s: problem with grant, stopping for now\n",
++                              __FUNCTION__);
++                      break;
 +              }
 +
-+              req->id = id;
-+              req->gref = ref;
++              bufpages->page_reqs += pages;
 +      }
 +
-+      if ( nr_flips != 0 ) {
-+              /* Tell the ballon driver what is going on. */
-+              balloon_update_driver_allowance(i);
-+
-+              set_xen_guest_handle(reservation.extent_start,
-+                                   np->rx_pfn_array);
-+              reservation.nr_extents   = nr_flips;
-+              reservation.extent_order = 0;
-+              reservation.address_bits = 0;
-+              reservation.domid        = DOMID_SELF;
-+
-+              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+                      /* After all PTEs have been zapped, flush the TLB. */
-+                      np->rx_mcl[i-1].args[MULTI_UVMFLAGS_INDEX] =
-+                              UVMF_TLB_FLUSH|UVMF_ALL;
++      if (sent)
++              net_accel_msg_notify(vnic->msg_channel_irq);
 +
-+                      /* Give away a batch of pages. */
-+                      np->rx_mcl[i].op = __HYPERVISOR_memory_op;
-+                      np->rx_mcl[i].args[0] = XENMEM_decrease_reservation;
-+                      np->rx_mcl[i].args[1] = (unsigned long)&reservation;
++      return rc;
++}
 +
-+                      /* Zap PTEs and give away pages in one big
-+                       * multicall. */
-+                      (void)HYPERVISOR_multicall(np->rx_mcl, i+1);
 +
-+                      /* Check return status of HYPERVISOR_memory_op(). */
-+                      if (unlikely(np->rx_mcl[i].result != i))
-+                              panic("Unable to reduce memory reservation\n");
-+              } else {
-+                      if (HYPERVISOR_memory_op(XENMEM_decrease_reservation,
-+                                               &reservation) != i)
-+                              panic("Unable to reduce memory reservation\n");
-+              }
-+      } else {
-+              wmb();
-+      }
++/*
++ * In response to dom0 saying "my queue is full", we reply with this
++ * when it is no longer full
++ */
++inline void vnic_set_queue_not_full(netfront_accel_vnic *vnic)
++{
 +
-+      /* Above is a suitable barrier to ensure backend will see requests. */
-+      np->rx.req_prod_pvt = req_prod + i;
-+ push:
-+      RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->rx, notify);
-+      if (notify)
-+              notify_remote_via_irq(np->irq);
++      if (test_and_set_bit(NET_ACCEL_MSG_AFLAGS_QUEUE0NOTFULL_B,
++                          (unsigned long *)&vnic->shared_page->aflags))
++              notify_remote_via_irq(vnic->msg_channel_irq);
++      else
++              VPRINTK("queue not full bit already set, not signalling\n");
 +}
 +
-+static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
-+                            struct netif_tx_request *tx)
++/* 
++ * Notify dom0 that the queue we want to use is full, it should
++ * respond by setting MSG_AFLAGS_QUEUEUNOTFULL in due course
++ */
++inline void vnic_set_queue_full(netfront_accel_vnic *vnic)
 +{
-+      struct netfront_info *np = netdev_priv(dev);
-+      char *data = skb->data;
-+      unsigned long mfn;
-+      RING_IDX prod = np->tx.req_prod_pvt;
-+      int frags = skb_shinfo(skb)->nr_frags;
-+      unsigned int offset = offset_in_page(data);
-+      unsigned int len = skb_headlen(skb);
-+      unsigned int id;
-+      grant_ref_t ref;
-+      int i;
-+
-+      while (len > PAGE_SIZE - offset) {
-+              tx->size = PAGE_SIZE - offset;
-+              tx->flags |= NETTXF_more_data;
-+              len -= tx->size;
-+              data += tx->size;
-+              offset = 0;
 +
-+              id = get_id_from_freelist(np->tx_skbs);
-+              np->tx_skbs[id] = skb_get(skb);
-+              tx = RING_GET_REQUEST(&np->tx, prod++);
-+              tx->id = id;
-+              ref = gnttab_claim_grant_reference(&np->gref_tx_head);
-+              BUG_ON((signed short)ref < 0);
++      if (!test_and_set_bit(NET_ACCEL_MSG_AFLAGS_QUEUEUFULL_B,
++                           (unsigned long *)&vnic->shared_page->aflags))
++              notify_remote_via_irq(vnic->msg_channel_irq);
++      else
++              VPRINTK("queue full bit already set, not signalling\n");
++}
 +
-+              mfn = virt_to_mfn(data);
-+              gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
-+                                              mfn, GTF_readonly);
 +
-+              tx->gref = np->grant_tx_ref[id] = ref;
-+              tx->offset = offset;
-+              tx->size = len;
-+              tx->flags = 0;
++static int vnic_check_hello_version(unsigned version) 
++{
++      if (version > NET_ACCEL_MSG_VERSION) {
++              /* Newer protocol, we must refuse */
++              return -EPROTO;
 +      }
 +
-+      for (i = 0; i < frags; i++) {
-+              skb_frag_t *frag = skb_shinfo(skb)->frags + i;
-+
-+              tx->flags |= NETTXF_more_data;
-+
-+              id = get_id_from_freelist(np->tx_skbs);
-+              np->tx_skbs[id] = skb_get(skb);
-+              tx = RING_GET_REQUEST(&np->tx, prod++);
-+              tx->id = id;
-+              ref = gnttab_claim_grant_reference(&np->gref_tx_head);
-+              BUG_ON((signed short)ref < 0);
-+
-+              mfn = pfn_to_mfn(page_to_pfn(frag->page));
-+              gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
-+                                              mfn, GTF_readonly);
-+
-+              tx->gref = np->grant_tx_ref[id] = ref;
-+              tx->offset = frag->page_offset;
-+              tx->size = frag->size;
-+              tx->flags = 0;
++      if (version < NET_ACCEL_MSG_VERSION) {
++              /*
++               * We are newer, so have discretion to accept if we
++               * wish.  For now however, just reject
++               */
++              return -EPROTO;
 +      }
 +
-+      np->tx.req_prod_pvt = prod;
++      BUG_ON(version != NET_ACCEL_MSG_VERSION);
++      return 0;
 +}
 +
-+static int network_start_xmit(struct sk_buff *skb, struct net_device *dev)
-+{
-+      unsigned short id;
-+      struct netfront_info *np = netdev_priv(dev);
-+      struct netif_tx_request *tx;
-+      struct netif_extra_info *extra;
-+      char *data = skb->data;
-+      RING_IDX i;
-+      grant_ref_t ref;
-+      unsigned long mfn;
-+      int notify;
-+      int frags = skb_shinfo(skb)->nr_frags;
-+      unsigned int offset = offset_in_page(data);
-+      unsigned int len = skb_headlen(skb);
 +
-+      /* Check the fast path, if hooks are available */
-+      if (np->accel_vif_state.hooks && 
-+          np->accel_vif_state.hooks->start_xmit(skb, dev)) { 
-+              /* Fast path has sent this packet */ 
-+              return 0; 
-+      } 
++static int vnic_process_hello_msg(netfront_accel_vnic *vnic,
++                                struct net_accel_msg *msg)
++{
++      int err = 0;
++      unsigned pages = sfc_netfront_max_pages;
 +
-+      frags += (offset + len + PAGE_SIZE - 1) / PAGE_SIZE;
-+      if (unlikely(frags > MAX_SKB_FRAGS + 1)) {
-+              printk(KERN_ALERT "xennet: skb rides the rocket: %d frags\n",
-+                     frags);
-+              dump_stack();
-+              goto drop;
++      if (vnic_check_hello_version(msg->u.hello.version) < 0) {
++              msg->id = NET_ACCEL_MSG_HELLO | NET_ACCEL_MSG_REPLY 
++                      | NET_ACCEL_MSG_ERROR;
++              msg->u.hello.version = NET_ACCEL_MSG_VERSION;
++      } else {
++              vnic->backend_netdev_up
++                      = vnic->shared_page->net_dev_up;
++              
++              msg->id = NET_ACCEL_MSG_HELLO | NET_ACCEL_MSG_REPLY;
++              msg->u.hello.version = NET_ACCEL_MSG_VERSION;
++              if (msg->u.hello.max_pages &&
++                  msg->u.hello.max_pages < pages)
++                      pages = msg->u.hello.max_pages;
++              msg->u.hello.max_pages = pages;
++              
++              /* Half of pages for rx, half for tx */ 
++              err = netfront_accel_alloc_buffer_mem(&vnic->bufpages,
++                                                    vnic->rx_bufs, 
++                                                    vnic->tx_bufs,
++                                                    pages);
++              if (err)
++                      msg->id |= NET_ACCEL_MSG_ERROR;         
 +      }
++      
++      /* Send reply */
++      net_accel_msg_reply_notify(vnic->shared_page, vnic->msg_channel_irq,
++                                 &vnic->to_dom0, msg);
++      return err;
++}
 +
-+      spin_lock_irq(&np->tx_lock);
 +
-+      if (unlikely(!netfront_carrier_ok(np) ||
-+                   (frags > 1 && !xennet_can_sg(dev)) ||
-+                   netif_needs_gso(dev, skb))) {
-+              spin_unlock_irq(&np->tx_lock);
-+              goto drop;
++static int vnic_process_localmac_msg(netfront_accel_vnic *vnic,
++                                   struct net_accel_msg *msg)
++{
++      unsigned long flags;
++      cuckoo_hash_mac_key key;
++
++      if (msg->u.localmac.flags & NET_ACCEL_MSG_ADD) {
++              DPRINTK("MAC has moved, could be local: " MAC_FMT "\n",
++                      MAC_ARG(msg->u.localmac.mac));
++              key = cuckoo_mac_to_key(msg->u.localmac.mac);
++              spin_lock_irqsave(&vnic->table_lock, flags);
++              /* Try to remove it, not a big deal if not there */
++              cuckoo_hash_remove(&vnic->fastpath_table, 
++                                 (cuckoo_hash_key *)&key);
++              spin_unlock_irqrestore(&vnic->table_lock, flags);
 +      }
++      
++      return 0;
++}
 +
-+      i = np->tx.req_prod_pvt;
 +
-+      id = get_id_from_freelist(np->tx_skbs);
-+      np->tx_skbs[id] = skb;
++static 
++int vnic_process_rx_msg(netfront_accel_vnic *vnic,
++                      struct net_accel_msg *msg)
++{
++      int err;
 +
-+      tx = RING_GET_REQUEST(&np->tx, i);
++      switch (msg->id) {
++      case NET_ACCEL_MSG_HELLO:
++              /* Hello, reply with Reply */
++              DPRINTK("got Hello, with version %.8x\n",
++                      msg->u.hello.version);
++              BUG_ON(vnic->msg_state != NETFRONT_ACCEL_MSG_NONE);
++              err = vnic_process_hello_msg(vnic, msg);
++              if (err == 0)
++                      vnic->msg_state = NETFRONT_ACCEL_MSG_HELLO;
++              break;
++      case NET_ACCEL_MSG_SETHW:
++              /* Hardware info message */
++              DPRINTK("got H/W info\n");
++              BUG_ON(vnic->msg_state != NETFRONT_ACCEL_MSG_HELLO);
++              err = netfront_accel_vi_init(vnic, &msg->u.hw);
++              if (err == 0)
++                      vnic->msg_state = NETFRONT_ACCEL_MSG_HW;
++              break;
++      case NET_ACCEL_MSG_MAPBUF | NET_ACCEL_MSG_REPLY:
++              VPRINTK("Got mapped buffers back\n");
++              BUG_ON(vnic->msg_state != NETFRONT_ACCEL_MSG_HW);
++              err = vnic_add_bufs(vnic, msg);
++              break;
++      case NET_ACCEL_MSG_MAPBUF | NET_ACCEL_MSG_REPLY | NET_ACCEL_MSG_ERROR:
++              /* No buffers.  Can't use the fast path. */
++              EPRINTK("Got mapped buffers error.  Cannot accelerate.\n");
++              BUG_ON(vnic->msg_state != NETFRONT_ACCEL_MSG_HW);
++              err = -EIO;
++              break;
++      case NET_ACCEL_MSG_LOCALMAC:
++              /* Should be add, remove not currently used */
++              EPRINTK_ON(!(msg->u.localmac.flags & NET_ACCEL_MSG_ADD));
++              BUG_ON(vnic->msg_state != NETFRONT_ACCEL_MSG_HW);
++              err = vnic_process_localmac_msg(vnic, msg);
++              break;
++      default:
++              EPRINTK("Huh? Message code is 0x%x\n", msg->id);
++              err = -EPROTO;
++              break;
++      }
 +
-+      tx->id   = id;
-+      ref = gnttab_claim_grant_reference(&np->gref_tx_head);
-+      BUG_ON((signed short)ref < 0);
-+      mfn = virt_to_mfn(data);
-+      gnttab_grant_foreign_access_ref(
-+              ref, np->xbdev->otherend_id, mfn, GTF_readonly);
-+      tx->gref = np->grant_tx_ref[id] = ref;
-+      tx->offset = offset;
-+      tx->size = len;
++      return err;
++}
 +
-+      tx->flags = 0;
-+      extra = NULL;
 +
-+      if (skb->ip_summed == CHECKSUM_HW) /* local packet? */
-+              tx->flags |= NETTXF_csum_blank | NETTXF_data_validated;
-+#ifdef CONFIG_XEN
-+      if (skb->proto_data_valid) /* remote but checksummed? */
-+              tx->flags |= NETTXF_data_validated;
++/* Process an IRQ received from back end driver */
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++void netfront_accel_msg_from_bend(struct work_struct *context)
++#else
++void netfront_accel_msg_from_bend(void *context)
++#endif
++{
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++      netfront_accel_vnic *vnic = 
++              container_of(context, netfront_accel_vnic, msg_from_bend);
++#else
++      netfront_accel_vnic *vnic = (netfront_accel_vnic *)context;
 +#endif
++      struct net_accel_msg msg;
++      int err, queue_was_full = 0;
++      
++      mutex_lock(&vnic->vnic_mutex);
 +
-+#if HAVE_TSO
-+      if (skb_shinfo(skb)->gso_size) {
-+              struct netif_extra_info *gso = (struct netif_extra_info *)
-+                      RING_GET_REQUEST(&np->tx, ++i);
++      /*
++       * This happens when the shared pages have been unmapped but
++       * the workqueue has yet to be flushed 
++       */
++      if (!vnic->dom0_state_is_setup) 
++              goto unlock_out;
 +
-+              if (extra)
-+                      extra->flags |= XEN_NETIF_EXTRA_FLAG_MORE;
-+              else
-+                      tx->flags |= NETTXF_extra_info;
++      while ((vnic->shared_page->aflags & NET_ACCEL_MSG_AFLAGS_TO_DOMU_MASK)
++             != 0) {
++              if (vnic->shared_page->aflags &
++                  NET_ACCEL_MSG_AFLAGS_QUEUEUNOTFULL) {
++                      /* We've been told there may now be space. */
++                      clear_bit(NET_ACCEL_MSG_AFLAGS_QUEUEUNOTFULL_B,
++                                (unsigned long *)&vnic->shared_page->aflags);
++              }
 +
-+              gso->u.gso.size = skb_shinfo(skb)->gso_size;
-+              gso->u.gso.type = XEN_NETIF_GSO_TYPE_TCPV4;
-+              gso->u.gso.pad = 0;
-+              gso->u.gso.features = 0;
++              if (vnic->shared_page->aflags &
++                  NET_ACCEL_MSG_AFLAGS_QUEUE0FULL) {
++                      /*
++                       * There will be space at the end of this
++                       * function if we can make any.
++                       */
++                      clear_bit(NET_ACCEL_MSG_AFLAGS_QUEUE0FULL_B,
++                                (unsigned long *)&vnic->shared_page->aflags);
++                      queue_was_full = 1;
++              }
++
++              if (vnic->shared_page->aflags &
++                  NET_ACCEL_MSG_AFLAGS_NETUPDOWN) {
++                      DPRINTK("%s: net interface change\n", __FUNCTION__);
++                      clear_bit(NET_ACCEL_MSG_AFLAGS_NETUPDOWN_B,
++                                (unsigned long *)&vnic->shared_page->aflags);
++                      if (vnic->shared_page->net_dev_up)
++                              netfront_accel_interface_up(vnic);
++                      else
++                              netfront_accel_interface_down(vnic);
++              }
++      }
 +
-+              gso->type = XEN_NETIF_EXTRA_TYPE_GSO;
-+              gso->flags = 0;
-+              extra = gso;
++      /* Pull msg out of shared memory */
++      while ((err = net_accel_msg_recv(vnic->shared_page, &vnic->from_dom0,
++                                       &msg)) == 0) {
++              err = vnic_process_rx_msg(vnic, &msg);
++              
++              if (err != 0)
++                      goto done;
 +      }
-+#endif
 +
-+      np->tx.req_prod_pvt = i + 1;
++      /*
++       * Send any pending buffer map request messages that we can,
++       * and mark domU->dom0 as full if necessary.  
++       */
++      if (vnic->msg_state == NETFRONT_ACCEL_MSG_HW &&
++          vnic->bufpages.page_reqs < vnic->bufpages.max_pages) {
++              if (vnic_send_buffer_requests(vnic, &vnic->bufpages) == -ENOSPC)
++                      vnic_set_queue_full(vnic);
++      }
 +
-+      xennet_make_frags(skb, dev, tx);
-+      tx->size = skb->len;
++      /* 
++       * If there are no messages then this is not an error.  It
++       * just means that we've finished processing the queue.
++       */
++      if (err == -ENOENT)
++              err = 0;
++ done:
++      /* We will now have made space in the dom0->domU queue if we can */
++      if (queue_was_full)
++              vnic_set_queue_not_full(vnic);
 +
-+      RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&np->tx, notify);
-+      if (notify)
-+              notify_remote_via_irq(np->irq);
++      if (err != 0) {
++              EPRINTK("%s returned %d\n", __FUNCTION__, err);
++              netfront_accel_set_closing(vnic);
++      }
 +
-+      np->stats.tx_bytes += skb->len;
-+      np->stats.tx_packets++;
++ unlock_out:
++      mutex_unlock(&vnic->vnic_mutex);
 +
-+      /* Note: It is not safe to access skb after network_tx_buf_gc()! */
-+      network_tx_buf_gc(dev);
++      return;
++}
 +
-+      if (!netfront_tx_slot_available(np))
-+              netif_stop_queue(dev);
 +
-+      spin_unlock_irq(&np->tx_lock);
++irqreturn_t netfront_accel_msg_channel_irq_from_bend(int irq, void *context, 
++                                               struct pt_regs *unused)
++{
++      netfront_accel_vnic *vnic = (netfront_accel_vnic *)context;
++      VPRINTK("irq %d from device %s\n", irq, vnic->dev->nodename);
 +
-+      return 0;
++      queue_work(netfront_accel_workqueue, &vnic->msg_from_bend);
 +
-+ drop:
-+      np->stats.tx_dropped++;
-+      dev_kfree_skb(skb);
-+      return 0;
++      return IRQ_HANDLED;
 +}
 +
-+static irqreturn_t netif_int(int irq, void *dev_id, struct pt_regs *ptregs)
++/* Process an interrupt received from the NIC via backend */
++irqreturn_t netfront_accel_net_channel_irq_from_bend(int irq, void *context, 
++                                                   struct pt_regs *unused)
 +{
-+      struct net_device *dev = dev_id;
-+      struct netfront_info *np = netdev_priv(dev);
++      netfront_accel_vnic *vnic = (netfront_accel_vnic *)context;
++      struct net_device *net_dev = vnic->net_dev;
 +      unsigned long flags;
 +
-+      spin_lock_irqsave(&np->tx_lock, flags);
-+
-+      if (likely(netfront_carrier_ok(np))) {
-+              network_tx_buf_gc(dev);
-+              /* Under tx_lock: protects access to rx shared-ring indexes. */
-+              if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) {
-+                      netfront_accelerator_call_stop_napi_irq(np, dev);
++      VPRINTK("net irq %d from device %s\n", irq, vnic->dev->nodename);
++      
++      NETFRONT_ACCEL_STATS_OP(vnic->stats.irq_count++);
 +
-+                      netif_rx_schedule(dev);
-+              }
-+      }
++      BUG_ON(net_dev==NULL);
 +
-+      spin_unlock_irqrestore(&np->tx_lock, flags);
++      spin_lock_irqsave(&vnic->irq_enabled_lock, flags);
++      if (vnic->irq_enabled) {
++              netfront_accel_disable_net_interrupts(vnic);
++              vnic->irq_enabled = 0;
++              spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags);
 +
++#if NETFRONT_ACCEL_STATS
++              vnic->stats.poll_schedule_count++;
++              if (vnic->stats.event_count_since_irq >
++                  vnic->stats.events_per_irq_max)
++                      vnic->stats.events_per_irq_max = 
++                              vnic->stats.event_count_since_irq;
++              vnic->stats.event_count_since_irq = 0;
++#endif
++              netif_rx_schedule(net_dev);
++      }
++      else {
++              spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags);
++              NETFRONT_ACCEL_STATS_OP(vnic->stats.useless_irq_count++);
++              DPRINTK("%s: irq when disabled\n", __FUNCTION__);
++      }
++      
 +      return IRQ_HANDLED;
 +}
 +
-+static void xennet_move_rx_slot(struct netfront_info *np, struct sk_buff *skb,
-+                              grant_ref_t ref)
++
++void netfront_accel_msg_tx_fastpath(netfront_accel_vnic *vnic, const void *mac,
++                                  u32 ip, u16 port, u8 protocol)
 +{
-+      int new = xennet_rxidx(np->rx.req_prod_pvt);
++      unsigned long lock_state;
++      struct net_accel_msg *msg;
 +
-+      BUG_ON(np->rx_skbs[new]);
-+      np->rx_skbs[new] = skb;
-+      np->grant_rx_ref[new] = ref;
-+      RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->id = new;
-+      RING_GET_REQUEST(&np->rx, np->rx.req_prod_pvt)->gref = ref;
-+      np->rx.req_prod_pvt++;
-+}
++      msg = net_accel_msg_start_send(vnic->shared_page, &vnic->to_dom0,
++                                     &lock_state);
 +
-+int xennet_get_extras(struct netfront_info *np,
-+                    struct netif_extra_info *extras, RING_IDX rp)
++      if (msg == NULL)
++              return;
 +
-+{
-+      struct netif_extra_info *extra;
-+      RING_IDX cons = np->rx.rsp_cons;
-+      int err = 0;
++      net_accel_msg_init(msg, NET_ACCEL_MSG_FASTPATH);
++      msg->u.fastpath.flags = NET_ACCEL_MSG_REMOVE;
++      memcpy(msg->u.fastpath.mac, mac, ETH_ALEN);
 +
-+      do {
-+              struct sk_buff *skb;
-+              grant_ref_t ref;
++      msg->u.fastpath.port = port;
++      msg->u.fastpath.ip = ip;
++      msg->u.fastpath.proto = protocol;
 +
-+              if (unlikely(cons + 1 == rp)) {
-+                      if (net_ratelimit())
-+                              WPRINTK("Missing extra info\n");
-+                      err = -EBADR;
-+                      break;
-+              }
++      net_accel_msg_complete_send_notify(vnic->shared_page, &vnic->to_dom0, 
++                                         &lock_state, vnic->msg_channel_irq);
++}
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel_netfront.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel_netfront.c      2008-05-19 00:33:48.618948572 +0300
+@@ -0,0 +1,319 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+              extra = (struct netif_extra_info *)
-+                      RING_GET_RESPONSE(&np->rx, ++cons);
++#include <linux/skbuff.h>
++#include <linux/netdevice.h>
 +
-+              if (unlikely(!extra->type ||
-+                           extra->type >= XEN_NETIF_EXTRA_TYPE_MAX)) {
-+                      if (net_ratelimit())
-+                              WPRINTK("Invalid extra type: %d\n",
-+                                      extra->type);
-+                      err = -EINVAL;
-+              } else {
-+                      memcpy(&extras[extra->type - 1], extra,
-+                             sizeof(*extra));
-+              }
++/* drivers/xen/netfront/netfront.h */
++#include "netfront.h"
 +
-+              skb = xennet_get_rx_skb(np, cons);
-+              ref = xennet_get_rx_ref(np, cons);
-+              xennet_move_rx_slot(np, skb, ref);
-+      } while (extra->flags & XEN_NETIF_EXTRA_FLAG_MORE);
++#include "accel.h"
++#include "accel_bufs.h"
++#include "accel_util.h"
++#include "accel_msg_iface.h"
++#include "accel_ssr.h"
++ 
++#ifdef EFX_GCOV
++#include "gcov.h"
++#endif
 +
-+      np->rx.rsp_cons = cons;
-+      return err;
-+}
++#define NETFRONT_ACCEL_VNIC_FROM_NETDEV(_nd)                          \
++      ((netfront_accel_vnic *)((struct netfront_info *)netdev_priv(net_dev))->accel_priv)
 +
-+static int xennet_get_responses(struct netfront_info *np,
-+                              struct netfront_rx_info *rinfo, RING_IDX rp,
-+                              struct sk_buff_head *list,
-+                              int *pages_flipped_p)
++static int netfront_accel_netdev_start_xmit(struct sk_buff *skb,
++                                          struct net_device *net_dev)
 +{
-+      int pages_flipped = *pages_flipped_p;
-+      struct mmu_update *mmu;
-+      struct multicall_entry *mcl;
-+      struct netif_rx_response *rx = &rinfo->rx;
-+      struct netif_extra_info *extras = rinfo->extras;
-+      RING_IDX cons = np->rx.rsp_cons;
-+      struct sk_buff *skb = xennet_get_rx_skb(np, cons);
-+      grant_ref_t ref = xennet_get_rx_ref(np, cons);
-+      int max = MAX_SKB_FRAGS + (rx->status <= RX_COPY_THRESHOLD);
-+      int frags = 1;
-+      int err = 0;
-+      unsigned long ret;
++      netfront_accel_vnic *vnic = NETFRONT_ACCEL_VNIC_FROM_NETDEV(net_dev);
++      struct netfront_info *np = 
++              (struct netfront_info *)netdev_priv(net_dev);
++      int handled, rc;
++      unsigned long flags1, flags2;
 +
-+      if (rx->flags & NETRXF_extra_info) {
-+              err = xennet_get_extras(np, extras, rp);
-+              cons = np->rx.rsp_cons;
++      BUG_ON(vnic == NULL);
++
++      /* Take our tx lock and hold for the duration */
++      spin_lock_irqsave(&vnic->tx_lock, flags1);
++
++      if (!vnic->tx_enabled) {
++              rc = 0;
++              goto unlock_out;
 +      }
 +
-+      for (;;) {
-+              unsigned long mfn;
++      handled = netfront_accel_vi_tx_post(vnic, skb);
++      if (handled == NETFRONT_ACCEL_STATUS_BUSY) {
++              BUG_ON(vnic->net_dev != net_dev);
++              DPRINTK("%s stopping queue\n", __FUNCTION__);
 +
-+              if (unlikely(rx->status < 0 ||
-+                           rx->offset + rx->status > PAGE_SIZE)) {
-+                      if (net_ratelimit())
-+                              WPRINTK("rx->offset: %x, size: %u\n",
-+                                      rx->offset, rx->status);
-+                      xennet_move_rx_slot(np, skb, ref);
-+                      err = -EINVAL;
-+                      goto next;
-+              }
++              /* Netfront's lock protects tx_skb */
++              spin_lock_irqsave(&np->tx_lock, flags2);
++              BUG_ON(vnic->tx_skb != NULL);
++              vnic->tx_skb = skb;
++              netif_stop_queue(net_dev);
++              spin_unlock_irqrestore(&np->tx_lock, flags2);
 +
-+              /*
-+               * This definitely indicates a bug, either in this driver or in
-+               * the backend driver. In future this should flag the bad
-+               * situation to the system controller to reboot the backed.
-+               */
-+              if (ref == GRANT_INVALID_REF) {
-+                      if (net_ratelimit())
-+                              WPRINTK("Bad rx response id %d.\n", rx->id);
-+                      err = -EINVAL;
-+                      goto next;
-+              }
++              NETFRONT_ACCEL_STATS_OP(vnic->stats.queue_stops++);
++      }
 +
-+              if (!np->copying_receiver) {
-+                      /* Memory pressure, insufficient buffer
-+                       * headroom, ... */
-+                      if (!(mfn = gnttab_end_foreign_transfer_ref(ref))) {
-+                              if (net_ratelimit())
-+                                      WPRINTK("Unfulfilled rx req "
-+                                              "(id=%d, st=%d).\n",
-+                                              rx->id, rx->status);
-+                              xennet_move_rx_slot(np, skb, ref);
-+                              err = -ENOMEM;
-+                              goto next;
-+                      }
++      if (handled == NETFRONT_ACCEL_STATUS_CANT)
++              rc = 0;
++      else
++              rc = 1;
 +
-+                      if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+                              /* Remap the page. */
-+                              struct page *page =
-+                                      skb_shinfo(skb)->frags[0].page;
-+                              unsigned long pfn = page_to_pfn(page);
-+                              void *vaddr = page_address(page);
++unlock_out:
++      spin_unlock_irqrestore(&vnic->tx_lock, flags1);
 +
-+                              mcl = np->rx_mcl + pages_flipped;
-+                              mmu = np->rx_mmu + pages_flipped;
++      return rc;
++}
 +
-+                              MULTI_update_va_mapping(mcl,
-+                                                      (unsigned long)vaddr,
-+                                                      pfn_pte_ma(mfn,
-+                                                                 PAGE_KERNEL),
-+                                                      0);
-+                              mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT)
-+                                      | MMU_MACHPHYS_UPDATE;
-+                              mmu->val = pfn;
 +
-+                              set_phys_to_machine(pfn, mfn);
-+                      }
-+                      pages_flipped++;
-+              } else {
-+                      ret = gnttab_end_foreign_access_ref(ref);
-+                      BUG_ON(!ret);
-+              }
++static int netfront_accel_netdev_poll(struct net_device *net_dev, int *budget)
++{
++      netfront_accel_vnic *vnic = NETFRONT_ACCEL_VNIC_FROM_NETDEV(net_dev);
++      int rx_allowed = *budget, rx_done;
++      
++      BUG_ON(vnic == NULL);
 +
-+              gnttab_release_grant_reference(&np->gref_rx_head, ref);
++      /* Can check this without lock as modifier excludes polls */ 
++      if (!vnic->poll_enabled)
++              return 0;
 +
-+              __skb_queue_tail(list, skb);
++      rx_done = netfront_accel_vi_poll(vnic, rx_allowed);
++      *budget -= rx_done;
++      
++      NETFRONT_ACCEL_STATS_OP(vnic->stats.poll_call_count++);
 +
-+next:
-+              if (!(rx->flags & NETRXF_more_data))
-+                      break;
++      VPRINTK("%s: done %d allowed %d\n",
++              __FUNCTION__, rx_done, rx_allowed);
 +
-+              if (cons + frags == rp) {
-+                      if (net_ratelimit())
-+                              WPRINTK("Need more frags\n");
-+                      err = -ENOENT;
-+                      break;
-+              }
++      netfront_accel_ssr_end_of_burst(vnic, &vnic->ssr_state);
 +
-+              rx = RING_GET_RESPONSE(&np->rx, cons + frags);
-+              skb = xennet_get_rx_skb(np, cons + frags);
-+              ref = xennet_get_rx_ref(np, cons + frags);
-+              frags++;
++      if (rx_done < rx_allowed) {
++               return 0; /* Done */
 +      }
++      
++      NETFRONT_ACCEL_STATS_OP(vnic->stats.poll_reschedule_count++);
 +
-+      if (unlikely(frags > max)) {
-+              if (net_ratelimit())
-+                      WPRINTK("Too many frags\n");
-+              err = -E2BIG;
-+      }
++      return 1; /* More to do. */
++}
 +
-+      if (unlikely(err))
-+              np->rx.rsp_cons = cons + frags;
 +
-+      *pages_flipped_p = pages_flipped;
++/*
++ * Process request from netfront to start napi interrupt
++ * mode. (i.e. enable interrupts as it's finished polling)
++ */
++static int netfront_accel_start_napi_interrupts(struct net_device *net_dev) 
++{
++      netfront_accel_vnic *vnic = NETFRONT_ACCEL_VNIC_FROM_NETDEV(net_dev);
++      unsigned long flags;
 +
-+      return err;
-+}
++      BUG_ON(vnic == NULL);
++      
++      /*
++       * Can check this without lock as writer excludes poll before
++       * modifying
++       */
++      if (!vnic->poll_enabled)
++              return 0;
 +
-+static RING_IDX xennet_fill_frags(struct netfront_info *np,
-+                                struct sk_buff *skb,
-+                                struct sk_buff_head *list)
-+{
-+      struct skb_shared_info *shinfo = skb_shinfo(skb);
-+      int nr_frags = shinfo->nr_frags;
-+      RING_IDX cons = np->rx.rsp_cons;
-+      skb_frag_t *frag = shinfo->frags + nr_frags;
-+      struct sk_buff *nskb;
++      if (!netfront_accel_vi_enable_interrupts(vnic)) {
++              /* 
++               * There was something there, tell caller we had
++               * something to do.
++               */
++              return 1;
++      }
 +
-+      while ((nskb = __skb_dequeue(list))) {
-+              struct netif_rx_response *rx =
-+                      RING_GET_RESPONSE(&np->rx, ++cons);
++      spin_lock_irqsave(&vnic->irq_enabled_lock, flags);
++      vnic->irq_enabled = 1;
++      netfront_accel_enable_net_interrupts(vnic);
++      spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags);
 +
-+              frag->page = skb_shinfo(nskb)->frags[0].page;
-+              frag->page_offset = rx->offset;
-+              frag->size = rx->status;
++      return 0;
++}
 +
-+              skb->data_len += rx->status;
 +
-+              skb_shinfo(nskb)->nr_frags = 0;
-+              kfree_skb(nskb);
++/*
++ * Process request from netfront to stop napi interrupt
++ * mode. (i.e. disable interrupts as it's starting to poll 
++ */
++static void netfront_accel_stop_napi_interrupts(struct net_device *net_dev) 
++{
++      netfront_accel_vnic *vnic = NETFRONT_ACCEL_VNIC_FROM_NETDEV(net_dev);
++      unsigned long flags;
 +
-+              frag++;
-+              nr_frags++;
++      BUG_ON(vnic == NULL);
++
++      spin_lock_irqsave(&vnic->irq_enabled_lock, flags);
++
++      if (!vnic->poll_enabled) {
++              spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags);
++              return;
 +      }
 +
-+      shinfo->nr_frags = nr_frags;
-+      return cons;
++      netfront_accel_disable_net_interrupts(vnic);
++      vnic->irq_enabled = 0;
++      spin_unlock_irqrestore(&vnic->irq_enabled_lock, flags);
 +}
 +
-+static int xennet_set_skb_gso(struct sk_buff *skb,
-+                            struct netif_extra_info *gso)
++
++static int netfront_accel_check_ready(struct net_device *net_dev)
 +{
-+      if (!gso->u.gso.size) {
-+              if (net_ratelimit())
-+                      WPRINTK("GSO size must not be zero.\n");
-+              return -EINVAL;
-+      }
++      netfront_accel_vnic *vnic = NETFRONT_ACCEL_VNIC_FROM_NETDEV(net_dev);
 +
-+      /* Currently only TCPv4 S.O. is supported. */
-+      if (gso->u.gso.type != XEN_NETIF_GSO_TYPE_TCPV4) {
-+              if (net_ratelimit())
-+                      WPRINTK("Bad GSO type %d.\n", gso->u.gso.type);
-+              return -EINVAL;
-+      }
++      BUG_ON(vnic == NULL);
 +
-+#if HAVE_TSO
-+      skb_shinfo(skb)->gso_size = gso->u.gso.size;
-+#if HAVE_GSO
-+      skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
++      /* This is protected by netfront's lock */ 
++      return vnic->tx_skb == NULL;
++}
 +
-+      /* Header must be checked, and gso_segs computed. */
-+      skb_shinfo(skb)->gso_type |= SKB_GSO_DODGY;
-+#endif
-+      skb_shinfo(skb)->gso_segs = 0;
++
++static int netfront_accel_get_stats(struct net_device *net_dev,
++                                  struct net_device_stats *stats)
++{
++      netfront_accel_vnic *vnic = NETFRONT_ACCEL_VNIC_FROM_NETDEV(net_dev);
++      struct netfront_accel_netdev_stats now;
++
++      BUG_ON(vnic == NULL);
++
++      now.fastpath_rx_pkts   = vnic->netdev_stats.fastpath_rx_pkts;
++      now.fastpath_rx_bytes  = vnic->netdev_stats.fastpath_rx_bytes;
++      now.fastpath_rx_errors = vnic->netdev_stats.fastpath_rx_errors;
++      now.fastpath_tx_pkts   = vnic->netdev_stats.fastpath_tx_pkts;
++      now.fastpath_tx_bytes  = vnic->netdev_stats.fastpath_tx_bytes;
++      now.fastpath_tx_errors = vnic->netdev_stats.fastpath_tx_errors;
++      
++      stats->rx_packets += (now.fastpath_rx_pkts - 
++                            vnic->stats_last_read.fastpath_rx_pkts);
++      stats->rx_bytes   += (now.fastpath_rx_bytes -
++                            vnic->stats_last_read.fastpath_rx_bytes);
++      stats->rx_errors  += (now.fastpath_rx_errors - 
++                            vnic->stats_last_read.fastpath_rx_errors);
++      stats->tx_packets += (now.fastpath_tx_pkts - 
++                            vnic->stats_last_read.fastpath_tx_pkts);
++      stats->tx_bytes   += (now.fastpath_tx_bytes - 
++                            vnic->stats_last_read.fastpath_tx_bytes);
++      stats->tx_errors  += (now.fastpath_tx_errors - 
++                            vnic->stats_last_read.fastpath_tx_errors);
++      
++      vnic->stats_last_read = now;
 +
 +      return 0;
-+#else
-+      if (net_ratelimit())
-+              WPRINTK("GSO unsupported by this kernel.\n");
-+      return -EINVAL;
-+#endif
 +}
 +
-+static int netif_poll(struct net_device *dev, int *pbudget)
-+{
-+      struct netfront_info *np = netdev_priv(dev);
-+      struct sk_buff *skb;
-+      struct netfront_rx_info rinfo;
-+      struct netif_rx_response *rx = &rinfo.rx;
-+      struct netif_extra_info *extras = rinfo.extras;
-+      RING_IDX i, rp;
-+      struct multicall_entry *mcl;
-+      int work_done, budget, more_to_do = 1, accel_more_to_do = 1;
-+      struct sk_buff_head rxq;
-+      struct sk_buff_head errq;
-+      struct sk_buff_head tmpq;
-+      unsigned long flags;
-+      unsigned int len;
-+      int pages_flipped = 0;
-+      int err;
 +
-+      spin_lock(&np->rx_lock); /* no need for spin_lock_bh() in ->poll() */
++struct netfront_accel_hooks accel_hooks = {
++      .new_device         = &netfront_accel_probe,
++      .remove         = &netfront_accel_remove,
++      .netdev_poll       = &netfront_accel_netdev_poll,
++      .start_xmit         = &netfront_accel_netdev_start_xmit,
++      .start_napi_irq = &netfront_accel_start_napi_interrupts,
++      .stop_napi_irq   = &netfront_accel_stop_napi_interrupts,
++      .check_ready       = &netfront_accel_check_ready,
++      .get_stats           = &netfront_accel_get_stats
++};
 +
-+      if (unlikely(!netfront_carrier_ok(np))) {
-+              spin_unlock(&np->rx_lock);
-+              return 0;
-+      }
 +
-+      skb_queue_head_init(&rxq);
-+      skb_queue_head_init(&errq);
-+      skb_queue_head_init(&tmpq);
++unsigned sfc_netfront_max_pages = NETFRONT_ACCEL_DEFAULT_BUF_PAGES;
++module_param_named (max_pages, sfc_netfront_max_pages, uint, 0644);
++MODULE_PARM_DESC(max_pages, "Number of buffer pages to request");
 +
-+      if ((budget = *pbudget) > dev->quota)
-+              budget = dev->quota;
-+      rp = np->rx.sring->rsp_prod;
-+      rmb(); /* Ensure we see queued responses up to 'rp'. */
++unsigned sfc_netfront_buffer_split = 2;
++module_param_named (buffer_split, sfc_netfront_buffer_split, uint, 0644);
++MODULE_PARM_DESC(buffer_split, 
++               "Fraction of buffers to use for TX, rest for RX");
 +
-+      i = np->rx.rsp_cons;
-+      work_done = 0;
-+      while ((i != rp) && (work_done < budget)) {
-+              memcpy(rx, RING_GET_RESPONSE(&np->rx, i), sizeof(*rx));
-+              memset(extras, 0, sizeof(rinfo.extras));
 +
-+              err = xennet_get_responses(np, &rinfo, rp, &tmpq,
-+                                         &pages_flipped);
++const char *frontend_name = "sfc_netfront";
 +
-+              if (unlikely(err)) {
-+err:  
-+                      while ((skb = __skb_dequeue(&tmpq)))
-+                              __skb_queue_tail(&errq, skb);
-+                      np->stats.rx_errors++;
-+                      i = np->rx.rsp_cons;
-+                      continue;
-+              }
++struct workqueue_struct *netfront_accel_workqueue;
 +
-+              skb = __skb_dequeue(&tmpq);
++static int __init netfront_accel_init(void)
++{
++      int rc;
++#ifdef EFX_GCOV       
++      gcov_provider_init(THIS_MODULE);
++#endif
 +
-+              if (extras[XEN_NETIF_EXTRA_TYPE_GSO - 1].type) {
-+                      struct netif_extra_info *gso;
-+                      gso = &extras[XEN_NETIF_EXTRA_TYPE_GSO - 1];
++      /*
++       * If we're running on dom0, netfront hasn't initialised
++       * itself, so we need to keep away
++       */
++      if (is_initial_xendomain())
++              return 0;
 +
-+                      if (unlikely(xennet_set_skb_gso(skb, gso))) {
-+                              __skb_queue_head(&tmpq, skb);
-+                              np->rx.rsp_cons += skb_queue_len(&tmpq);
-+                              goto err;
-+                      }
-+              }
++      if (!is_pow2(sizeof(struct net_accel_msg)))
++              EPRINTK("%s: bad structure size\n", __FUNCTION__);
 +
-+              NETFRONT_SKB_CB(skb)->page = skb_shinfo(skb)->frags[0].page;
-+              NETFRONT_SKB_CB(skb)->offset = rx->offset;
++      netfront_accel_workqueue = create_workqueue(frontend_name);
 +
-+              len = rx->status;
-+              if (len > RX_COPY_THRESHOLD)
-+                      len = RX_COPY_THRESHOLD;
-+              skb_put(skb, len);
++      netfront_accel_debugfs_init();
 +
-+              if (rx->status > len) {
-+                      skb_shinfo(skb)->frags[0].page_offset =
-+                              rx->offset + len;
-+                      skb_shinfo(skb)->frags[0].size = rx->status - len;
-+                      skb->data_len = rx->status - len;
-+              } else {
-+                      skb_shinfo(skb)->frags[0].page = NULL;
-+                      skb_shinfo(skb)->nr_frags = 0;
-+              }
++      rc = netfront_accelerator_loaded(NETFRONT_ACCEL_VERSION,
++                                       frontend_name, &accel_hooks);
 +
-+              i = xennet_fill_frags(np, skb, &tmpq);
++      if (rc < 0) {
++              EPRINTK("Xen netfront accelerator version mismatch\n");
++              return -EINVAL;
++      }
 +
-+              /*
-+               * Truesize must approximates the size of true data plus
-+               * any supervisor overheads. Adding hypervisor overheads
-+               * has been shown to significantly reduce achievable
-+               * bandwidth with the default receive buffer size. It is
-+               * therefore not wise to account for it here.
-+               *
-+               * After alloc_skb(RX_COPY_THRESHOLD), truesize is set to
-+               * RX_COPY_THRESHOLD + the supervisor overheads. Here, we
-+               * add the size of the data pulled in xennet_fill_frags().
-+               *
-+               * We also adjust for any unused space in the main data
-+               * area by subtracting (RX_COPY_THRESHOLD - len). This is
-+               * especially important with drivers which split incoming
-+               * packets into header and data, using only 66 bytes of
-+               * the main data area (see the e1000 driver for example.)
-+               * On such systems, without this last adjustement, our
-+               * achievable receive throughout using the standard receive
-+               * buffer size was cut by 25%(!!!).
++      if (rc > 0) {
++              /* 
++               * In future may want to add backwards compatibility
++               * and accept certain subsets of previous versions
 +               */
-+              skb->truesize += skb->data_len - (RX_COPY_THRESHOLD - len);
-+              skb->len += skb->data_len;
++              EPRINTK("Xen netfront accelerator version mismatch\n");
++              return -EINVAL;
++      }
 +
-+              /*
-+               * Old backends do not assert data_validated but we
-+               * can infer it from csum_blank so test both flags.
-+               */
-+              if (rx->flags & (NETRXF_data_validated|NETRXF_csum_blank))
-+                      skb->ip_summed = CHECKSUM_UNNECESSARY;
-+              else
-+                      skb->ip_summed = CHECKSUM_NONE;
-+#ifdef CONFIG_XEN
-+              skb->proto_data_valid = (skb->ip_summed != CHECKSUM_NONE);
-+              skb->proto_csum_blank = !!(rx->flags & NETRXF_csum_blank);
-+#endif
-+              np->stats.rx_packets++;
-+              np->stats.rx_bytes += skb->len;
++      return 0;
++}
++module_init(netfront_accel_init);
 +
-+              __skb_queue_tail(&rxq, skb);
++static void __exit netfront_accel_exit(void)
++{
++      if (is_initial_xendomain())
++              return;
 +
-+              np->rx.rsp_cons = ++i;
-+              work_done++;
-+      }
++      DPRINTK("%s: unhooking\n", __FUNCTION__);
 +
-+      if (pages_flipped) {
-+              /* Some pages are no longer absent... */
-+              balloon_update_driver_allowance(-pages_flipped);
++      /* Unhook from normal netfront */
++      netfront_accelerator_stop(frontend_name);
 +
-+              /* Do all the remapping work and M2P updates. */
-+              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+                      mcl = np->rx_mcl + pages_flipped;
-+                      mcl->op = __HYPERVISOR_mmu_update;
-+                      mcl->args[0] = (unsigned long)np->rx_mmu;
-+                      mcl->args[1] = pages_flipped;
-+                      mcl->args[2] = 0;
-+                      mcl->args[3] = DOMID_SELF;
-+                      (void)HYPERVISOR_multicall(np->rx_mcl,
-+                                                 pages_flipped + 1);
-+              }
-+      }
++      DPRINTK("%s: done\n", __FUNCTION__);
 +
-+      while ((skb = __skb_dequeue(&errq)))
-+              kfree_skb(skb);
++      netfront_accel_debugfs_fini();
 +
-+      while ((skb = __skb_dequeue(&rxq)) != NULL) {
-+              struct page *page = NETFRONT_SKB_CB(skb)->page;
-+              void *vaddr = page_address(page);
-+              unsigned offset = NETFRONT_SKB_CB(skb)->offset;
++      flush_workqueue(netfront_accel_workqueue);
 +
-+              memcpy(skb->data, vaddr + offset, skb_headlen(skb));
++      destroy_workqueue(netfront_accel_workqueue);
 +
-+              if (page != skb_shinfo(skb)->frags[0].page)
-+                      __free_page(page);
++#ifdef EFX_GCOV
++      gcov_provider_fini(THIS_MODULE);
++#endif
++      return;
++}
++module_exit(netfront_accel_exit);
 +
-+              /* Ethernet work: Delayed to here as it peeks the header. */
-+              skb->protocol = eth_type_trans(skb, dev);
++MODULE_LICENSE("GPL");
 +
-+              /* Pass it up. */
-+              netif_receive_skb(skb);
-+              dev->last_rx = jiffies;
-+      }
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel_ssr.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel_ssr.c   2008-05-19 00:33:48.622948803 +0300
+@@ -0,0 +1,308 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      /* If we get a callback with very few responses, reduce fill target. */
-+      /* NB. Note exponential increase, linear decrease. */
-+      if (((np->rx.req_prod_pvt - np->rx.sring->rsp_prod) >
-+           ((3*np->rx_target) / 4)) &&
-+          (--np->rx_target < np->rx_min_target))
-+              np->rx_target = np->rx_min_target;
++#include <linux/socket.h>
++#include <linux/in.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/list.h>
++#include <net/ip.h>
++#include <net/checksum.h>
 +
-+      network_alloc_rx_buffers(dev);
++#include "accel.h"
++#include "accel_util.h"
++#include "accel_bufs.h"
 +
-+      if (work_done < budget) {
-+              /* there's some spare capacity, try the accelerated path */
-+              int accel_budget = budget - work_done;
-+              int accel_budget_start = accel_budget;
++#include "accel_ssr.h"
 +
-+              if (np->accel_vif_state.hooks) { 
-+                      accel_more_to_do =  
-+                              np->accel_vif_state.hooks->netdev_poll 
-+                              (dev, &accel_budget); 
-+                      work_done += (accel_budget_start - accel_budget); 
-+              } else
-+                      accel_more_to_do = 0;
++static inline int list_valid(struct list_head *lh) {
++      return(lh->next != NULL);
++}
++
++static void netfront_accel_ssr_deliver (struct netfront_accel_vnic *vnic,
++                                      struct netfront_accel_ssr_state *st,
++                                      struct netfront_accel_ssr_conn *c);
++
++/** Construct an efx_ssr_state.
++ *
++ * @v st     The SSR state (per channel per port)
++ * @v port   The port.
++ */
++void netfront_accel_ssr_init(struct netfront_accel_ssr_state *st) {
++      unsigned i;
++
++      INIT_LIST_HEAD(&st->conns);
++      INIT_LIST_HEAD(&st->free_conns);
++      for (i = 0; i < 8; ++i) {
++              struct netfront_accel_ssr_conn *c = 
++                      kmalloc(sizeof(*c), GFP_KERNEL);
++              if (c == NULL)  break;
++              c->n_in_order_pkts = 0;
++              c->skb = NULL;
++              list_add(&c->link, &st->free_conns);
 +      }
 +
-+      *pbudget   -= work_done;
-+      dev->quota -= work_done;
++}
 +
-+      if (work_done < budget) {
-+              local_irq_save(flags);
 +
-+              RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do);
++/** Destructor for an efx_ssr_state.
++ *
++ * @v st     The SSR state (per channel per port)
++ */
++void netfront_accel_ssr_fini(netfront_accel_vnic *vnic, 
++                           struct netfront_accel_ssr_state *st) {
++      struct netfront_accel_ssr_conn *c;
 +
-+              if (!more_to_do && !accel_more_to_do && 
-+                  np->accel_vif_state.hooks) {
-+                      /* 
-+                       *  Slow path has nothing more to do, see if
-+                       *  fast path is likewise
-+                       */
-+                      accel_more_to_do = 
-+                              np->accel_vif_state.hooks->start_napi_irq(dev);
-+              }
++      /* Return cleanly if efx_ssr_init() not previously called */
++      BUG_ON(list_valid(&st->conns) != list_valid(&st->free_conns));
++      if (! list_valid(&st->conns))
++              return;
 +
-+              if (!more_to_do && !accel_more_to_do)
-+                      __netif_rx_complete(dev);
++      while ( ! list_empty(&st->free_conns)) {
++              c = list_entry(st->free_conns.prev, 
++                             struct netfront_accel_ssr_conn, link);
++              list_del(&c->link);
++              BUG_ON(c->skb != NULL);
++              kfree(c);
++      }
++      while ( ! list_empty(&st->conns)) {
++              c = list_entry(st->conns.prev, 
++                             struct netfront_accel_ssr_conn, link);
++              list_del(&c->link);
++              if (c->skb)
++                      netfront_accel_ssr_deliver(vnic, st, c);
++              kfree(c);
++      }
++}
 +
-+              local_irq_restore(flags);
++
++/** Calc IP checksum and deliver to the OS
++ *
++ * @v st     The SSR state (per channel per port)
++ * @v c            The SSR connection state
++ */
++static void netfront_accel_ssr_deliver(netfront_accel_vnic *vnic,
++                                     struct netfront_accel_ssr_state *st,
++                                     struct netfront_accel_ssr_conn *c) {
++      BUG_ON(c->skb == NULL);
++
++      /*
++       * If we've chained packets together, recalculate the IP
++       * checksum.
++       */
++      if (skb_shinfo(c->skb)->frag_list) {
++              NETFRONT_ACCEL_STATS_OP(++vnic->stats.ssr_bursts);
++              c->iph->check = 0;
++              c->iph->check = ip_fast_csum((unsigned char *) c->iph, 
++                                           c->iph->ihl);
 +      }
 +
-+      spin_unlock(&np->rx_lock);
-+      
-+      return more_to_do | accel_more_to_do;
++      VPRINTK("%s: %d\n", __FUNCTION__, c->skb->len);
++
++      netif_receive_skb(c->skb); 
++      c->skb = NULL;
 +}
 +
-+static void netif_release_tx_bufs(struct netfront_info *np)
-+{
-+      struct sk_buff *skb;
-+      int i;
 +
-+      for (i = 1; i <= NET_TX_RING_SIZE; i++) {
-+              if ((unsigned long)np->tx_skbs[i] < PAGE_OFFSET)
-+                      continue;
++/** Push held skbs down into network stack.
++ *
++ * @v st       SSR state
++ *
++ * Only called if we are tracking one or more connections.
++ */
++void __netfront_accel_ssr_end_of_burst(netfront_accel_vnic *vnic, 
++                                     struct netfront_accel_ssr_state *st) {
++      struct netfront_accel_ssr_conn *c;
 +
-+              skb = np->tx_skbs[i];
-+              gnttab_end_foreign_access_ref(np->grant_tx_ref[i]);
-+              gnttab_release_grant_reference(
-+                      &np->gref_tx_head, np->grant_tx_ref[i]);
-+              np->grant_tx_ref[i] = GRANT_INVALID_REF;
-+              add_id_to_freelist(np->tx_skbs, i);
-+              dev_kfree_skb_irq(skb);
++      BUG_ON(list_empty(&st->conns));
++
++      list_for_each_entry(c, &st->conns, link)
++              if (c->skb)
++                      netfront_accel_ssr_deliver(vnic, st, c);
++
++      /* Time-out connections that have received no traffic for 20ms. */
++      c = list_entry(st->conns.prev, struct netfront_accel_ssr_conn,
++                     link);
++      if (jiffies - c->last_pkt_jiffies > (HZ / 50 + 1)) {
++              NETFRONT_ACCEL_STATS_OP(++vnic->stats.ssr_drop_stream);
++              list_del(&c->link);
++              list_add(&c->link, &st->free_conns);
 +      }
 +}
 +
-+static void netif_release_rx_bufs_flip(struct netfront_info *np)
-+{
-+      struct mmu_update      *mmu = np->rx_mmu;
-+      struct multicall_entry *mcl = np->rx_mcl;
-+      struct sk_buff_head free_list;
-+      struct sk_buff *skb;
-+      unsigned long mfn;
-+      int xfer = 0, noxfer = 0, unused = 0;
-+      int id, ref, rc;
 +
-+      skb_queue_head_init(&free_list);
++/** Process SKB and decide whether to dispatch it to the stack now or
++ * later.
++ *
++ * @v st       SSR state
++ * @v skb     SKB to exmaine
++ * @ret rc       0 => deliver SKB to kernel now, otherwise the SKB belongs
++ *           us.
++ */
++int netfront_accel_ssr_skb(struct netfront_accel_vnic *vnic,
++                         struct netfront_accel_ssr_state *st,
++                         struct sk_buff *skb) {
++      int data_length, dont_merge;
++      struct netfront_accel_ssr_conn *c;
++      struct iphdr *iph;
++      struct tcphdr *th;
++      unsigned th_seq;
 +
-+      spin_lock_bh(&np->rx_lock);
++      BUG_ON(skb_shinfo(skb)->frag_list != NULL);
++      BUG_ON(skb->next != NULL);
 +
-+      for (id = 0; id < NET_RX_RING_SIZE; id++) {
-+              if ((ref = np->grant_rx_ref[id]) == GRANT_INVALID_REF) {
-+                      unused++;
++      /* We're not interested if it isn't TCP over IPv4. */
++      iph = (struct iphdr *) skb->data;
++      if (skb->protocol != htons(ETH_P_IP) ||
++          iph->protocol != IPPROTO_TCP) {
++              return 0;
++      }
++
++      /* Ignore segments that fail csum or are fragmented. */
++      if (unlikely((skb->ip_summed - CHECKSUM_UNNECESSARY) |
++                   (iph->frag_off & htons(IP_MF | IP_OFFSET)))) {
++              return 0;
++      }
++
++      th = (struct tcphdr*)(skb->data + iph->ihl * 4);
++      data_length = ntohs(iph->tot_len) - iph->ihl * 4 - th->doff * 4;
++      th_seq = ntohl(th->seq);
++      dont_merge = (data_length == 0) | th->urg | th->syn | th->rst;
++
++      list_for_each_entry(c, &st->conns, link) {
++              if ((c->saddr  - iph->saddr) |
++                  (c->daddr  - iph->daddr) |
++                  (c->source - th->source) |
++                  (c->dest   - th->dest  ))
 +                      continue;
++
++              /* Re-insert at head of list to reduce lookup time. */
++              list_del(&c->link);
++              list_add(&c->link, &st->conns);
++              c->last_pkt_jiffies = jiffies;
++
++              if (unlikely(th_seq - c->next_seq)) {
++                      /* Out-of-order, so start counting again. */
++                      if (c->skb)
++                              netfront_accel_ssr_deliver(vnic, st, c);
++                      c->n_in_order_pkts = 0;
++                      c->next_seq = th_seq + data_length;
++                      NETFRONT_ACCEL_STATS_OP(++vnic->stats.ssr_misorder);
++                      return 0;
 +              }
++              c->next_seq = th_seq + data_length;
 +
-+              skb = np->rx_skbs[id];
-+              mfn = gnttab_end_foreign_transfer_ref(ref);
-+              gnttab_release_grant_reference(&np->gref_rx_head, ref);
-+              np->grant_rx_ref[id] = GRANT_INVALID_REF;
-+              add_id_to_freelist(np->rx_skbs, id);
++              if (++c->n_in_order_pkts < 300) {
++                      /* May be in slow-start, so don't merge. */
++                      NETFRONT_ACCEL_STATS_OP(++vnic->stats.ssr_slow_start);
++                      return 0;
++              }
 +
-+              if (0 == mfn) {
-+                      struct page *page = skb_shinfo(skb)->frags[0].page;
-+                      balloon_release_driver_page(page);
-+                      skb_shinfo(skb)->nr_frags = 0;
-+                      dev_kfree_skb(skb);
-+                      noxfer++;
-+                      continue;
++              if (unlikely(dont_merge)) {
++                      if (c->skb)
++                              netfront_accel_ssr_deliver(vnic, st, c);
++                      return 0;
 +              }
 +
-+              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+                      /* Remap the page. */
-+                      struct page *page = skb_shinfo(skb)->frags[0].page;
-+                      unsigned long pfn = page_to_pfn(page);
-+                      void *vaddr = page_address(page);
++              if (c->skb) {
++                      c->iph->tot_len = ntohs(c->iph->tot_len);
++                      c->iph->tot_len += data_length;
++                      c->iph->tot_len = htons(c->iph->tot_len);
++                      c->th->ack_seq = th->ack_seq;
++                      c->th->fin |= th->fin;
++                      c->th->psh |= th->psh;
++                      c->th->window = th->window;
 +
-+                      MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
-+                                              pfn_pte_ma(mfn, PAGE_KERNEL),
-+                                              0);
-+                      mcl++;
-+                      mmu->ptr = ((maddr_t)mfn << PAGE_SHIFT)
-+                              | MMU_MACHPHYS_UPDATE;
-+                      mmu->val = pfn;
-+                      mmu++;
++                      /* Remove the headers from this skb. */
++                      skb_pull(skb, skb->len - data_length);
 +
-+                      set_phys_to_machine(pfn, mfn);
-+              }
-+              __skb_queue_tail(&free_list, skb);
-+              xfer++;
-+      }
++                      /*
++                       * Tack the new skb onto the head skb's frag_list.
++                       * This is exactly the format that fragmented IP
++                       * datagrams are reassembled into.
++                       */
++                      BUG_ON(skb->next != 0);
++                      if ( ! skb_shinfo(c->skb)->frag_list)
++                              skb_shinfo(c->skb)->frag_list = skb;
++                      else
++                              c->skb_tail->next = skb;
++                      c->skb_tail = skb;
++                      c->skb->len += skb->len;
++                      c->skb->data_len += skb->len;
++                      c->skb->truesize += skb->truesize;
 +
-+      DPRINTK("%s: %d xfer, %d noxfer, %d unused\n",
-+              __FUNCTION__, xfer, noxfer, unused);
++                      NETFRONT_ACCEL_STATS_OP(++vnic->stats.ssr_merges);
 +
-+      if (xfer) {
-+              /* Some pages are no longer absent... */
-+              balloon_update_driver_allowance(-xfer);
++                      /*
++                       * If the next packet might push this super-packet
++                       * over the limit for an IP packet, deliver it now.
++                       * This is slightly conservative, but close enough.
++                       */
++                      if (c->skb->len + 
++                          (PAGE_SIZE / NETFRONT_ACCEL_BUFS_PER_PAGE)
++                          > 16384)
++                              netfront_accel_ssr_deliver(vnic, st, c);
 +
-+              if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-+                      /* Do all the remapping work and M2P updates. */
-+                      mcl->op = __HYPERVISOR_mmu_update;
-+                      mcl->args[0] = (unsigned long)np->rx_mmu;
-+                      mcl->args[1] = mmu - np->rx_mmu;
-+                      mcl->args[2] = 0;
-+                      mcl->args[3] = DOMID_SELF;
-+                      mcl++;
-+                      rc = HYPERVISOR_multicall_check(
-+                              np->rx_mcl, mcl - np->rx_mcl, NULL);
-+                      BUG_ON(rc);
++                      return 1;
++              }
++              else {
++                      c->iph = iph;
++                      c->th = th;
++                      c->skb = skb;
++                      return 1;
 +              }
 +      }
 +
-+      while ((skb = __skb_dequeue(&free_list)) != NULL)
-+              dev_kfree_skb(skb);
++      /* We're not yet tracking this connection. */
 +
-+      spin_unlock_bh(&np->rx_lock);
++      if (dont_merge) {
++              return 0;
++      }
++
++      if (list_empty(&st->free_conns)) {
++              c = list_entry(st->conns.prev, 
++                             struct netfront_accel_ssr_conn,
++                             link);
++              if (c->skb) {
++                      NETFRONT_ACCEL_STATS_OP(++vnic->stats.ssr_too_many);
++                      return 0;
++              }
++      }
++      else {
++              c = list_entry(st->free_conns.next,
++                             struct netfront_accel_ssr_conn,
++                             link);
++      }
++      list_del(&c->link);
++      list_add(&c->link, &st->conns);
++      c->saddr = iph->saddr;
++      c->daddr = iph->daddr;
++      c->source = th->source;
++      c->dest = th->dest;
++      c->next_seq = th_seq + data_length;
++      c->n_in_order_pkts = 0;
++      BUG_ON(c->skb != NULL);
++      NETFRONT_ACCEL_STATS_OP(++vnic->stats.ssr_new_stream);
++      return 0;
 +}
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel_ssr.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel_ssr.h   2008-05-19 00:33:48.622948803 +0300
+@@ -0,0 +1,88 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static void netif_release_rx_bufs_copy(struct netfront_info *np)
-+{
-+      struct sk_buff *skb;
-+      int i, ref;
-+      int busy = 0, inuse = 0;
++#ifndef NETFRONT_ACCEL_SSR_H
++#define NETFRONT_ACCEL_SSR_H
 +
-+      spin_lock_bh(&np->rx_lock);
++#include <linux/skbuff.h>
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/list.h>
 +
-+      for (i = 0; i < NET_RX_RING_SIZE; i++) {
-+              ref = np->grant_rx_ref[i];
++#include "accel.h"
 +
-+              if (ref == GRANT_INVALID_REF)
-+                      continue;
++/** State for Soft Segment Reassembly (SSR). */
 +
-+              inuse++;
++struct netfront_accel_ssr_conn {
++      struct list_head link;
 +
-+              skb = np->rx_skbs[i];
++      unsigned saddr, daddr;
++      unsigned short source, dest;
 +
-+              if (!gnttab_end_foreign_access_ref(ref))
-+              {
-+                      busy++;
-+                      continue;
-+              }
++      /** Number of in-order packets we've seen with payload. */
++      unsigned n_in_order_pkts;
 +
-+              gnttab_release_grant_reference(&np->gref_rx_head, ref);
-+              np->grant_rx_ref[i] = GRANT_INVALID_REF;
-+              add_id_to_freelist(np->rx_skbs, i);
++      /** Next in-order sequence number. */
++      unsigned next_seq;
 +
-+              skb_shinfo(skb)->nr_frags = 0;
-+              dev_kfree_skb(skb);
-+      }
++      /** Time we last saw a packet on this connection. */
++      unsigned long last_pkt_jiffies;
 +
-+      if (busy)
-+              DPRINTK("%s: Unable to release %d of %d inuse grant references out of %ld total.\n",
-+                      __FUNCTION__, busy, inuse, NET_RX_RING_SIZE);
++      /** The SKB we are currently holding.  If NULL, then all following
++       * fields are undefined.
++       */
++      struct sk_buff *skb;
 +
-+      spin_unlock_bh(&np->rx_lock);
-+}
++      /** The tail of the frag_list of SKBs we're holding.  Only valid
++       * after at least one merge.
++       */
++      struct sk_buff *skb_tail;
 +
-+static int network_close(struct net_device *dev)
-+{
-+      struct netfront_info *np = netdev_priv(dev);
-+      netif_stop_queue(np->netdev);
-+      return 0;
-+}
++      /** The IP header of the skb we are holding. */
++      struct iphdr *iph;
++      
++      /** The TCP header of the skb we are holding. */
++      struct tcphdr *th;
++};
 +
++extern void netfront_accel_ssr_init(struct netfront_accel_ssr_state *st);
++extern void netfront_accel_ssr_fini(netfront_accel_vnic *vnic,
++                                  struct netfront_accel_ssr_state *st);
 +
-+static struct net_device_stats *network_get_stats(struct net_device *dev)
-+{
-+      struct netfront_info *np = netdev_priv(dev);
++extern void
++__netfront_accel_ssr_end_of_burst(netfront_accel_vnic *vnic,
++                                struct netfront_accel_ssr_state *st);
 +
-+      netfront_accelerator_call_get_stats(np, dev);
-+      return &np->stats;
++extern int  netfront_accel_ssr_skb(netfront_accel_vnic *vnic,
++                                 struct netfront_accel_ssr_state *st,
++                                 struct sk_buff *skb);
++
++static inline void
++netfront_accel_ssr_end_of_burst (netfront_accel_vnic *vnic,
++                               struct netfront_accel_ssr_state *st) {
++      if ( ! list_empty(&st->conns) )
++              __netfront_accel_ssr_end_of_burst(vnic, st);
 +}
 +
-+static int xennet_change_mtu(struct net_device *dev, int mtu)
-+{
-+      int max = xennet_can_sg(dev) ? 65535 - ETH_HLEN : ETH_DATA_LEN;
++#endif /* NETFRONT_ACCEL_SSR_H */
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel_tso.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel_tso.c   2008-05-19 00:33:48.622948803 +0300
+@@ -0,0 +1,511 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      if (mtu > max)
-+              return -EINVAL;
-+      dev->mtu = mtu;
-+      return 0;
-+}
++#include <linux/pci.h>
++#include <linux/tcp.h>
++#include <linux/ip.h>
++#include <linux/in.h>
++#include <linux/if_ether.h>
 +
-+static int xennet_set_sg(struct net_device *dev, u32 data)
-+{
-+      if (data) {
-+              struct netfront_info *np = netdev_priv(dev);
-+              int val;
++#include "accel.h"
++#include "accel_util.h"
 +
-+              if (xenbus_scanf(XBT_NIL, np->xbdev->otherend, "feature-sg",
-+                               "%d", &val) < 0)
-+                      val = 0;
-+              if (!val)
-+                      return -ENOSYS;
-+      } else if (dev->mtu > ETH_DATA_LEN)
-+              dev->mtu = ETH_DATA_LEN;
++#include "accel_tso.h"
 +
-+      return ethtool_op_set_sg(dev, data);
-+}
++#define PTR_DIFF(p1, p2)  ((u8*)(p1) - (u8*)(p2))
++#define ETH_HDR_LEN(skb)  ((skb)->nh.raw - (skb)->data)
++#define SKB_TCP_OFF(skb)  PTR_DIFF ((skb)->h.th, (skb)->data)
++#define SKB_IP_OFF(skb)   PTR_DIFF ((skb)->nh.iph, (skb)->data)
 +
-+static int xennet_set_tso(struct net_device *dev, u32 data)
-+{
-+      if (data) {
-+              struct netfront_info *np = netdev_priv(dev);
-+              int val;
++/*
++ * Set a maximum number of buffers in each output packet to make life
++ * a little simpler - if this is reached it will just move on to
++ * another packet 
++ */
++#define ACCEL_TSO_MAX_BUFFERS (6)
 +
-+              if (xenbus_scanf(XBT_NIL, np->xbdev->otherend,
-+                               "feature-gso-tcpv4", "%d", &val) < 0)
-+                      val = 0;
-+              if (!val)
-+                      return -ENOSYS;
-+      }
++/** TSO State.
++ *
++ * The state used during segmentation.  It is put into this data structure
++ * just to make it easy to pass into inline functions.
++ */
++struct netfront_accel_tso_state {
++      /** bytes of data we've yet to segment */
++      unsigned remaining_len;
 +
-+      return ethtool_op_set_tso(dev, data);
-+}
++      /** current sequence number */
++      unsigned seqnum;
 +
-+static void xennet_set_features(struct net_device *dev)
-+{
-+      dev_disable_gso_features(dev);
-+      xennet_set_sg(dev, 0);
++      /** remaining space in current packet */
++      unsigned packet_space;
 +
-+      /* We need checksum offload to enable scatter/gather and TSO. */
-+      if (!(dev->features & NETIF_F_IP_CSUM))
-+              return;
++      /** List of packets to be output, containing the buffers and
++       *  iovecs to describe each packet 
++       */
++      struct netfront_accel_tso_output_packet *output_packets;
 +
-+      if (xennet_set_sg(dev, 1))
-+              return;
++      /** Total number of buffers in output_packets */
++      unsigned buffers;
 +
-+      /* Before 2.6.9 TSO seems to be unreliable so do not enable it
-+       * on older kernels.
++      /** Total number of packets in output_packets */
++      unsigned packets;
++
++      /** Input Fragment Cursor.
++       *
++       * Where we are in the current fragment of the incoming SKB.  These
++       * values get updated in place when we split a fragment over
++       * multiple packets.
 +       */
-+      if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,9))
-+              xennet_set_tso(dev, 1);
++      struct {
++              /** address of current position */
++              void *addr;
++              /** remaining length */   
++              unsigned int len;
++      } ifc; /*  == ifc Input Fragment Cursor */
++
++      /** Parameters.
++       *
++       * These values are set once at the start of the TSO send and do
++       * not get changed as the routine progresses.
++       */
++      struct {
++              /* the number of bytes of header */
++              unsigned int header_length;
++
++              /* The number of bytes to put in each outgoing segment. */
++              int full_packet_size;
++              
++              /* Current IP ID, host endian. */
++              unsigned ip_id;
++
++              /* Max size of each output packet payload */
++              int gso_size;
++      } p;
++};
++
++
++/**
++ * Verify that our various assumptions about sk_buffs and the conditions
++ * under which TSO will be attempted hold true.
++ *
++ * @v skb            The sk_buff to check.
++ */
++static inline void tso_check_safe(struct sk_buff *skb) {
++      EPRINTK_ON(skb->protocol != htons (ETH_P_IP));
++      EPRINTK_ON(((struct ethhdr*) skb->data)->h_proto != htons (ETH_P_IP));
++      EPRINTK_ON(skb->nh.iph->protocol != IPPROTO_TCP);
++      EPRINTK_ON((SKB_TCP_OFF(skb)
++                  + (skb->h.th->doff << 2u)) > skb_headlen(skb));
 +}
 +
-+static int network_connect(struct net_device *dev)
-+{
-+      struct netfront_info *np = netdev_priv(dev);
-+      int i, requeue_idx, err;
-+      struct sk_buff *skb;
-+      grant_ref_t ref;
-+      netif_rx_request_t *req;
-+      unsigned int feature_rx_copy, feature_rx_flip;
 +
-+      err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
-+                         "feature-rx-copy", "%u", &feature_rx_copy);
-+      if (err != 1)
-+              feature_rx_copy = 0;
-+      err = xenbus_scanf(XBT_NIL, np->xbdev->otherend,
-+                         "feature-rx-flip", "%u", &feature_rx_flip);
-+      if (err != 1)
-+              feature_rx_flip = 1;
++
++/** Parse the SKB header and initialise state. */
++static inline void tso_start(struct netfront_accel_tso_state *st, 
++                           struct sk_buff *skb) {
 +
 +      /*
-+       * Copy packets on receive path if:
-+       *  (a) This was requested by user, and the backend supports it; or
-+       *  (b) Flipping was requested, but this is unsupported by the backend.
-+       */
-+      np->copying_receiver = ((MODPARM_rx_copy && feature_rx_copy) ||
-+                              (MODPARM_rx_flip && !feature_rx_flip));
++       * All ethernet/IP/TCP headers combined size is TCP header size
++       * plus offset of TCP header relative to start of packet.
++       */
++      st->p.header_length = (skb->h.th->doff << 2u) + SKB_TCP_OFF(skb);
++      st->p.full_packet_size = (st->p.header_length
++                                + skb_shinfo(skb)->gso_size);
++      st->p.gso_size = skb_shinfo(skb)->gso_size;
 +
-+      err = talk_to_backend(np->xbdev, np);
-+      if (err)
-+              return err;
++      st->p.ip_id = htons(skb->nh.iph->id);
++      st->seqnum = ntohl(skb->h.th->seq);
 +
-+      xennet_set_features(dev);
++      EPRINTK_ON(skb->h.th->urg);
++      EPRINTK_ON(skb->h.th->syn);
++      EPRINTK_ON(skb->h.th->rst);
 +
-+      DPRINTK("device %s has %sing receive path.\n",
-+              dev->name, np->copying_receiver ? "copy" : "flipp");
++      st->remaining_len = skb->len - st->p.header_length;
 +
-+      spin_lock_bh(&np->rx_lock);
-+      spin_lock_irq(&np->tx_lock);
++      st->output_packets = NULL;
++      st->buffers = 0;
++      st->packets = 0;
 +
-+      /*
-+       * Recovery procedure:
-+       *  NB. Freelist index entries are always going to be less than
-+       *  PAGE_OFFSET, whereas pointers to skbs will always be equal or
-+       *  greater than PAGE_OFFSET: we use this property to distinguish
-+       *  them.
-+       */
++      VPRINTK("Starting new TSO: hl %d ps %d gso %d seq %x len %d\n",
++              st->p.header_length, st->p.full_packet_size, st->p.gso_size,
++              st->seqnum, skb->len);
++}
 +
-+      /* Step 1: Discard all pending TX packet fragments. */
-+      netif_release_tx_bufs(np);
++/**
++ * Add another NIC mapped buffer onto an output packet  
++ */ 
++static inline int tso_start_new_buffer(netfront_accel_vnic *vnic,
++                                     struct netfront_accel_tso_state *st,
++                                     int first)
++{
++      struct netfront_accel_tso_buffer *tso_buf;
++      struct netfront_accel_pkt_desc *buf;
 +
-+      /* Step 2: Rebuild the RX buffer freelist and the RX ring itself. */
-+      for (requeue_idx = 0, i = 0; i < NET_RX_RING_SIZE; i++) {
-+              if (!np->rx_skbs[i])
-+                      continue;
++      /* Get a mapped packet buffer */
++      buf = netfront_accel_buf_get(vnic->tx_bufs);
++      if (buf == NULL) {
++              DPRINTK("%s: No buffer for TX\n", __FUNCTION__);
++              return -1;
++      }
 +
-+              skb = np->rx_skbs[requeue_idx] = xennet_get_rx_skb(np, i);
-+              ref = np->grant_rx_ref[requeue_idx] = xennet_get_rx_ref(np, i);
-+              req = RING_GET_REQUEST(&np->rx, requeue_idx);
++      /* Store a bit of meta-data at the end */
++      tso_buf =(struct netfront_accel_tso_buffer *)
++              (buf->pkt_kva + NETFRONT_ACCEL_TSO_BUF_LENGTH
++               + sizeof(struct netfront_accel_tso_output_packet));
 +
-+              if (!np->copying_receiver) {
-+                      gnttab_grant_foreign_transfer_ref(
-+                              ref, np->xbdev->otherend_id,
-+                              page_to_pfn(skb_shinfo(skb)->frags->page));
-+              } else {
-+                      gnttab_grant_foreign_access_ref(
-+                              ref, np->xbdev->otherend_id,
-+                              pfn_to_mfn(page_to_pfn(skb_shinfo(skb)->
-+                                                     frags->page)),
-+                              0);
-+              }
-+              req->gref = ref;
-+              req->id   = requeue_idx;
++      tso_buf->buf = buf;
 +
-+              requeue_idx++;
++      tso_buf->length = 0;
++      
++      if (first) {
++              struct netfront_accel_tso_output_packet *output_packet 
++                      = (struct netfront_accel_tso_output_packet *)
++                      (buf->pkt_kva + NETFRONT_ACCEL_TSO_BUF_LENGTH);
++              output_packet->next = st->output_packets;
++              st->output_packets = output_packet;
++              tso_buf->next = NULL;
++              st->output_packets->tso_bufs = tso_buf;
++              st->output_packets->tso_bufs_len = 1;
++      } else {
++              tso_buf->next = st->output_packets->tso_bufs;
++              st->output_packets->tso_bufs = tso_buf;
++              st->output_packets->tso_bufs_len ++;
 +      }
 +
-+      np->rx.req_prod_pvt = requeue_idx;
++      BUG_ON(st->output_packets->tso_bufs_len > ACCEL_TSO_MAX_BUFFERS);
++      
++      st->buffers ++;
 +
 +      /*
-+       * Step 3: All public and private state should now be sane.  Get
-+       * ready to start sending and receiving packets and give the driver
-+       * domain a kick because we've probably just requeued some
-+       * packets.
++       * Store the context, set to NULL, last packet buffer will get
++       * non-NULL later
 +       */
-+      netfront_carrier_on(np);
-+      notify_remote_via_irq(np->irq);
-+      network_tx_buf_gc(dev);
-+      network_alloc_rx_buffers(dev);
-+
-+      spin_unlock_irq(&np->tx_lock);
-+      spin_unlock_bh(&np->rx_lock);
++      tso_buf->buf->skb = NULL;
 +
 +      return 0;
 +}
 +
-+static void netif_uninit(struct net_device *dev)
-+{
-+      struct netfront_info *np = netdev_priv(dev);
-+      netif_release_tx_bufs(np);
-+      if (np->copying_receiver)
-+              netif_release_rx_bufs_copy(np);
-+      else
-+              netif_release_rx_bufs_flip(np);
-+      gnttab_free_grant_references(np->gref_tx_head);
-+      gnttab_free_grant_references(np->gref_rx_head);
-+}
 +
-+static struct ethtool_ops network_ethtool_ops =
-+{
-+      .get_tx_csum = ethtool_op_get_tx_csum,
-+      .set_tx_csum = ethtool_op_set_tx_csum,
-+      .get_sg = ethtool_op_get_sg,
-+      .set_sg = xennet_set_sg,
-+#if HAVE_TSO
-+      .get_tso = ethtool_op_get_tso,
-+      .set_tso = xennet_set_tso,
-+#endif
-+      .get_link = ethtool_op_get_link,
-+};
++/* Generate a new header, and prepare for the new packet.
++ *
++ * @v vnic          VNIC
++ * @v skb            Socket buffer
++ * @v st              TSO state
++ * @ret rc          0 on success, or -1 if failed to alloc header
++ */
 +
-+#ifdef CONFIG_SYSFS
-+static ssize_t show_rxbuf_min(struct class_device *cd, char *buf)
++static inline 
++int tso_start_new_packet(netfront_accel_vnic *vnic,
++                       struct sk_buff *skb,
++                       struct netfront_accel_tso_state *st) 
 +{
-+      struct net_device *netdev = container_of(cd, struct net_device,
-+                                               class_dev);
-+      struct netfront_info *info = netdev_priv(netdev);
++      struct netfront_accel_tso_buffer *tso_buf;
++      struct iphdr *tsoh_iph;
++      struct tcphdr *tsoh_th;
++      unsigned ip_length;
 +
-+      return sprintf(buf, "%u\n", info->rx_min_target);
-+}
++      if (tso_start_new_buffer(vnic, st, 1) < 0) {
++              NETFRONT_ACCEL_STATS_OP(vnic->stats.fastpath_tx_busy++);
++              return -1;              
++      }
 +
-+static ssize_t store_rxbuf_min(struct class_device *cd,
-+                             const char *buf, size_t len)
-+{
-+      struct net_device *netdev = container_of(cd, struct net_device,
-+                                               class_dev);
-+      struct netfront_info *np = netdev_priv(netdev);
-+      char *endp;
-+      unsigned long target;
++      /* This has been set up by tso_start_new_buffer() */
++      tso_buf = st->output_packets->tso_bufs;
 +
-+      if (!capable(CAP_NET_ADMIN))
-+              return -EPERM;
++      /* Copy in the header */
++      memcpy(tso_buf->buf->pkt_kva, skb->data, st->p.header_length);
++      tso_buf->length = st->p.header_length;
 +
-+      target = simple_strtoul(buf, &endp, 0);
-+      if (endp == buf)
-+              return -EBADMSG;
++      tsoh_th = (struct tcphdr*) 
++              (tso_buf->buf->pkt_kva + SKB_TCP_OFF(skb));
++      tsoh_iph = (struct iphdr*) 
++              (tso_buf->buf->pkt_kva + SKB_IP_OFF(skb));
 +
-+      if (target < RX_MIN_TARGET)
-+              target = RX_MIN_TARGET;
-+      if (target > RX_MAX_TARGET)
-+              target = RX_MAX_TARGET;
++      /* Set to zero to encourage falcon to fill these in */
++      tsoh_th->check  = 0;
++      tsoh_iph->check = 0;
 +
-+      spin_lock_bh(&np->rx_lock);
-+      if (target > np->rx_max_target)
-+              np->rx_max_target = target;
-+      np->rx_min_target = target;
-+      if (target > np->rx_target)
-+              np->rx_target = target;
++      tsoh_th->seq = htonl(st->seqnum);
++      st->seqnum += st->p.gso_size;
 +
-+      network_alloc_rx_buffers(netdev);
++      if (st->remaining_len > st->p.gso_size) {
++              /* This packet will not finish the TSO burst. */
++              ip_length = st->p.full_packet_size - ETH_HDR_LEN(skb);
++              tsoh_th->fin = 0;
++              tsoh_th->psh = 0;
++      } else {
++              /* This packet will be the last in the TSO burst. */
++              ip_length = (st->p.header_length - ETH_HDR_LEN(skb)
++                           + st->remaining_len);
++              tsoh_th->fin = skb->h.th->fin;
++              tsoh_th->psh = skb->h.th->psh;
++      }
 +
-+      spin_unlock_bh(&np->rx_lock);
-+      return len;
-+}
++      tsoh_iph->tot_len = htons(ip_length);
 +
-+static ssize_t show_rxbuf_max(struct class_device *cd, char *buf)
-+{
-+      struct net_device *netdev = container_of(cd, struct net_device,
-+                                               class_dev);
-+      struct netfront_info *info = netdev_priv(netdev);
++      /* Linux leaves suitable gaps in the IP ID space for us to fill. */
++      tsoh_iph->id = st->p.ip_id++;
++      tsoh_iph->id = htons(tsoh_iph->id);
 +
-+      return sprintf(buf, "%u\n", info->rx_max_target);
++      st->packet_space = st->p.gso_size; 
++
++      st->packets++;
++
++      return 0;
 +}
 +
-+static ssize_t store_rxbuf_max(struct class_device *cd,
-+                             const char *buf, size_t len)
++
++
++static inline void tso_get_fragment(struct netfront_accel_tso_state *st, 
++                                  int len, void *addr)
 +{
-+      struct net_device *netdev = container_of(cd, struct net_device,
-+                                               class_dev);
-+      struct netfront_info *np = netdev_priv(netdev);
-+      char *endp;
-+      unsigned long target;
++      st->ifc.len = len;
++      st->ifc.addr = addr;
++      return;
++}
 +
-+      if (!capable(CAP_NET_ADMIN))
-+              return -EPERM;
 +
-+      target = simple_strtoul(buf, &endp, 0);
-+      if (endp == buf)
-+              return -EBADMSG;
++static inline void tso_unwind(netfront_accel_vnic *vnic, 
++                            struct netfront_accel_tso_state *st)
++{
++      struct netfront_accel_tso_buffer *tso_buf;
++      struct netfront_accel_tso_output_packet *output_packet;
 +
-+      if (target < RX_MIN_TARGET)
-+              target = RX_MIN_TARGET;
-+      if (target > RX_MAX_TARGET)
-+              target = RX_MAX_TARGET;
++      DPRINTK("%s\n", __FUNCTION__);
 +
-+      spin_lock_bh(&np->rx_lock);
-+      if (target < np->rx_min_target)
-+              np->rx_min_target = target;
-+      np->rx_max_target = target;
-+      if (target < np->rx_target)
-+              np->rx_target = target;
++      while (st->output_packets != NULL) {
++              output_packet = st->output_packets;
++              st->output_packets = output_packet->next;
++              while (output_packet->tso_bufs != NULL) {
++                      tso_buf = output_packet->tso_bufs;
++                      output_packet->tso_bufs = tso_buf->next;
 +
-+      network_alloc_rx_buffers(netdev);
++                      st->buffers --;
++                      output_packet->tso_bufs_len --;
 +
-+      spin_unlock_bh(&np->rx_lock);
-+      return len;
++                      netfront_accel_buf_put(vnic->tx_bufs, 
++                                             tso_buf->buf->buf_id);
++              }
++      }
++      BUG_ON(st->buffers != 0);
 +}
 +
-+static ssize_t show_rxbuf_cur(struct class_device *cd, char *buf)
++
++
++static inline
++void tso_fill_packet_with_fragment(netfront_accel_vnic *vnic,
++                                 struct netfront_accel_tso_state *st) 
 +{
-+      struct net_device *netdev = container_of(cd, struct net_device,
-+                                               class_dev);
-+      struct netfront_info *info = netdev_priv(netdev);
++      struct netfront_accel_tso_buffer *tso_buf;
++      int n, space;
 +
-+      return sprintf(buf, "%u\n", info->rx_target);
-+}
++      BUG_ON(st->output_packets == NULL);
++      BUG_ON(st->output_packets->tso_bufs == NULL);
 +
-+static const struct class_device_attribute xennet_attrs[] = {
-+      __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf_min, store_rxbuf_min),
-+      __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf_max, store_rxbuf_max),
-+      __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf_cur, NULL),
-+};
++      tso_buf = st->output_packets->tso_bufs;
 +
-+static int xennet_sysfs_addif(struct net_device *netdev)
-+{
-+      int i;
-+      int error = 0;
++      if (st->ifc.len == 0)  return;
++      if (st->packet_space == 0)  return;
++      if (tso_buf->length == NETFRONT_ACCEL_TSO_BUF_LENGTH) return;
 +
-+      for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
-+              error = class_device_create_file(&netdev->class_dev, 
-+                                               &xennet_attrs[i]);
-+              if (error)
-+                      goto fail;
-+      }
-+      return 0;
++      n = min(st->ifc.len, st->packet_space);
 +
-+ fail:
-+      while (--i >= 0)
-+              class_device_remove_file(&netdev->class_dev,
-+                                       &xennet_attrs[i]);
-+      return error;
-+}
++      space = NETFRONT_ACCEL_TSO_BUF_LENGTH - tso_buf->length;
++      n = min(n, space);
 +
-+static void xennet_sysfs_delif(struct net_device *netdev)
-+{
-+      int i;
++      st->packet_space -= n;
++      st->remaining_len -= n;
++      st->ifc.len -= n;
 +
-+      for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
-+              class_device_remove_file(&netdev->class_dev,
-+                                       &xennet_attrs[i]);
-+      }
-+}
++      memcpy(tso_buf->buf->pkt_kva + tso_buf->length, st->ifc.addr, n);
 +
-+#endif /* CONFIG_SYSFS */
++      tso_buf->length += n;
 +
++      BUG_ON(tso_buf->length > NETFRONT_ACCEL_TSO_BUF_LENGTH);
 +
-+/*
-+ * Nothing to do here. Virtual interface is point-to-point and the
-+ * physical interface is probably promiscuous anyway.
-+ */
-+static void network_set_multicast_list(struct net_device *dev)
-+{
++      st->ifc.addr += n;
++
++      return;
 +}
 +
-+static struct net_device * __devinit create_netdev(struct xenbus_device *dev)
++
++int netfront_accel_enqueue_skb_tso(netfront_accel_vnic *vnic,
++                                 struct sk_buff *skb)
 +{
-+      int i, err = 0;
-+      struct net_device *netdev = NULL;
-+      struct netfront_info *np = NULL;
++      struct netfront_accel_tso_state state;
++      struct netfront_accel_tso_buffer *tso_buf = NULL;
++      struct netfront_accel_tso_output_packet *reversed_list = NULL;
++      struct netfront_accel_tso_output_packet *tmp_pkt;
++      ef_iovec iovecs[ACCEL_TSO_MAX_BUFFERS];
++      int frag_i, rc, dma_id;
++      skb_frag_t *f;
 +
-+      netdev = alloc_etherdev(sizeof(struct netfront_info));
-+      if (!netdev) {
-+              printk(KERN_WARNING "%s> alloc_etherdev failed.\n",
-+                     __FUNCTION__);
-+              return ERR_PTR(-ENOMEM);
++      tso_check_safe(skb);
++
++      if (skb->ip_summed != CHECKSUM_HW)
++              EPRINTK("Trying to TSO send a packet without HW checksum\n");
++
++      tso_start(&state, skb);
++
++      /*
++       * Setup the first payload fragment.  If the skb header area
++       * contains exactly the headers and all payload is in the frag
++       * list things are little simpler
++       */
++      if (skb_headlen(skb) == state.p.header_length) {
++              /* Grab the first payload fragment. */
++              BUG_ON(skb_shinfo(skb)->nr_frags < 1);
++              frag_i = 0;
++              f = &skb_shinfo(skb)->frags[frag_i];
++              tso_get_fragment(&state, f->size, 
++                               page_address(f->page) + f->page_offset);
++      } else {
++              int hl = state.p.header_length;
++              tso_get_fragment(&state,  skb_headlen(skb) - hl, 
++                               skb->data + hl);
++              frag_i = -1;
 +      }
 +
-+      np                   = netdev_priv(netdev);
-+      np->xbdev            = dev;
++      if (tso_start_new_packet(vnic, skb, &state) < 0) {
++              DPRINTK("%s: out of first start-packet memory\n",
++                      __FUNCTION__);
++              goto unwind;
++      }
 +
-+      spin_lock_init(&np->tx_lock);
-+      spin_lock_init(&np->rx_lock);
++      while (1) {
++              tso_fill_packet_with_fragment(vnic, &state);
++              
++              /* Move onto the next fragment? */
++              if (state.ifc.len == 0) {
++                      if (++frag_i >= skb_shinfo(skb)->nr_frags)
++                              /* End of payload reached. */
++                              break;
++                      f = &skb_shinfo(skb)->frags[frag_i];
++                      tso_get_fragment(&state, f->size,
++                                       page_address(f->page) +
++                                       f->page_offset);
++              }
 +
-+      init_accelerator_vif(np, dev);
++              /* Start a new buffer? */
++              if ((state.output_packets->tso_bufs->length == 
++                   NETFRONT_ACCEL_TSO_BUF_LENGTH) &&
++                  tso_start_new_buffer(vnic, &state, 0)) {
++                      DPRINTK("%s: out of start-buffer memory\n",
++                              __FUNCTION__);
++                      goto unwind;
++              }
 +
-+      skb_queue_head_init(&np->rx_batch);
-+      np->rx_target     = RX_DFL_MIN_TARGET;
-+      np->rx_min_target = RX_DFL_MIN_TARGET;
-+      np->rx_max_target = RX_MAX_TARGET;
++              /* Start at new packet? */
++              if ((state.packet_space == 0 || 
++                   ((state.output_packets->tso_bufs_len >=
++                     ACCEL_TSO_MAX_BUFFERS) &&
++                    (state.output_packets->tso_bufs->length >= 
++                     NETFRONT_ACCEL_TSO_BUF_LENGTH))) &&
++                  tso_start_new_packet(vnic, skb, &state) < 0) {
++                      DPRINTK("%s: out of start-packet memory\n",
++                              __FUNCTION__);
++                      goto unwind;
++              }
 +
-+      init_timer(&np->rx_refill_timer);
-+      np->rx_refill_timer.data = (unsigned long)netdev;
-+      np->rx_refill_timer.function = rx_refill_timeout;
++      }
 +
-+      /* Initialise {tx,rx}_skbs as a free chain containing every entry. */
-+      for (i = 0; i <= NET_TX_RING_SIZE; i++) {
-+              np->tx_skbs[i] = (void *)((unsigned long) i+1);
-+              np->grant_tx_ref[i] = GRANT_INVALID_REF;
++      /* Check for space */
++      if (ef_vi_transmit_space(&vnic->vi) < state.buffers) {
++              DPRINTK("%s: Not enough TX space (%d)\n",
++                      __FUNCTION__, state.buffers);
++              goto unwind;
 +      }
 +
-+      for (i = 0; i < NET_RX_RING_SIZE; i++) {
-+              np->rx_skbs[i] = NULL;
-+              np->grant_rx_ref[i] = GRANT_INVALID_REF;
++      /*
++       * Store the skb context in the most recent buffer (i.e. the
++       * last buffer that will be sent)
++       */
++      state.output_packets->tso_bufs->buf->skb = skb;
++
++      /* Reverse the list of packets as we construct it on a stack */
++      while (state.output_packets != NULL) {
++              tmp_pkt = state.output_packets;
++              state.output_packets = tmp_pkt->next;
++              tmp_pkt->next = reversed_list;
++              reversed_list = tmp_pkt;
 +      }
 +
-+      /* A grant for every tx ring slot */
-+      if (gnttab_alloc_grant_references(TX_MAX_TARGET,
-+                                        &np->gref_tx_head) < 0) {
-+              printk(KERN_ALERT "#### netfront can't alloc tx grant refs\n");
-+              err = -ENOMEM;
-+              goto exit;
++      /* Pass off to hardware */
++      while (reversed_list != NULL) {
++              tmp_pkt = reversed_list;
++              reversed_list = tmp_pkt->next;
++
++              BUG_ON(tmp_pkt->tso_bufs_len > ACCEL_TSO_MAX_BUFFERS);
++              BUG_ON(tmp_pkt->tso_bufs_len == 0);
++
++              dma_id = tmp_pkt->tso_bufs->buf->buf_id;
++
++              /*
++               * Make an iovec of the buffers in the list, reversing
++               * the buffers as we go as they are constructed on a
++               * stack
++               */
++              tso_buf = tmp_pkt->tso_bufs;
++              for (frag_i = tmp_pkt->tso_bufs_len - 1;
++                   frag_i >= 0;
++                   frag_i--) {
++                      iovecs[frag_i].iov_base = tso_buf->buf->pkt_buff_addr;
++                      iovecs[frag_i].iov_len = tso_buf->length;
++                      tso_buf = tso_buf->next;
++              }
++
++              rc = ef_vi_transmitv(&vnic->vi, iovecs, tmp_pkt->tso_bufs_len,
++                                   dma_id);
++              /*
++               * We checked for space already, so it really should
++               * succeed
++               */
++              BUG_ON(rc != 0);
 +      }
-+      /* A grant for every rx ring slot */
-+      if (gnttab_alloc_grant_references(RX_MAX_TARGET,
-+                                        &np->gref_rx_head) < 0) {
-+              printk(KERN_ALERT "#### netfront can't alloc rx grant refs\n");
-+              err = -ENOMEM;
-+              goto exit_free_tx;
++
++      /* Track number of tx fastpath stats */
++      vnic->netdev_stats.fastpath_tx_bytes += skb->len;
++      vnic->netdev_stats.fastpath_tx_pkts += state.packets;
++#if NETFRONT_ACCEL_STATS
++      {
++              unsigned n;
++              n = vnic->netdev_stats.fastpath_tx_pkts -
++                      vnic->stats.fastpath_tx_completions;
++              if (n > vnic->stats.fastpath_tx_pending_max)
++                      vnic->stats.fastpath_tx_pending_max = n;
 +      }
++#endif
 +
-+      netdev->open            = network_open;
-+      netdev->hard_start_xmit = network_start_xmit;
-+      netdev->stop            = network_close;
-+      netdev->get_stats       = network_get_stats;
-+      netdev->poll            = netif_poll;
-+      netdev->set_multicast_list = network_set_multicast_list;
-+      netdev->uninit          = netif_uninit;
-+      netdev->change_mtu      = xennet_change_mtu;
-+      netdev->weight          = 64;
-+      netdev->features        = NETIF_F_IP_CSUM;
++      return NETFRONT_ACCEL_STATUS_GOOD;
++ 
++ unwind:
++      tso_unwind(vnic, &state);
 +
-+      SET_ETHTOOL_OPS(netdev, &network_ethtool_ops);
-+      SET_MODULE_OWNER(netdev);
-+      SET_NETDEV_DEV(netdev, &dev->dev);
++      NETFRONT_ACCEL_STATS_OP(vnic->stats.fastpath_tx_busy++);
 +
-+      np->netdev = netdev;
++      return NETFRONT_ACCEL_STATUS_BUSY;
++}
 +
-+      netfront_carrier_off(np);
 +
-+      return netdev;
 +
-+ exit_free_tx:
-+      gnttab_free_grant_references(np->gref_tx_head);
-+ exit:
-+      free_netdev(netdev);
-+      return ERR_PTR(err);
-+}
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel_tso.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel_tso.h   2008-05-19 00:33:48.622948803 +0300
+@@ -0,0 +1,57 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef NETFRONT_ACCEL_TSO_H
++#define NETFRONT_ACCEL_TSO_H
++
++#include "accel_bufs.h"
++
++/* Track the buffers used in each output packet */
++struct netfront_accel_tso_buffer {
++      struct netfront_accel_tso_buffer *next;
++      struct netfront_accel_pkt_desc *buf;
++      unsigned length;
++};
++
++/* Track the output packets formed from each input packet */
++struct netfront_accel_tso_output_packet {
++      struct netfront_accel_tso_output_packet *next;
++      struct netfront_accel_tso_buffer *tso_bufs;
++      unsigned tso_bufs_len;
++};
++
 +
-+#ifdef CONFIG_INET
 +/*
-+ * We use this notifier to send out a fake ARP reply to reset switches and
-+ * router ARP caches when an IP interface is brought up on a VIF.
++ * Max available space in a buffer for data once meta-data has taken
++ * its place 
 + */
-+static int
-+inetdev_notify(struct notifier_block *this, unsigned long event, void *ptr)
-+{
-+      struct in_ifaddr  *ifa = (struct in_ifaddr *)ptr;
-+      struct net_device *dev = ifa->ifa_dev->dev;
++#define NETFRONT_ACCEL_TSO_BUF_LENGTH                                 \
++      ((PAGE_SIZE / NETFRONT_ACCEL_BUFS_PER_PAGE)                     \
++       - sizeof(struct netfront_accel_tso_buffer)                     \
++       - sizeof(struct netfront_accel_tso_output_packet))
 +
-+      /* UP event and is it one of our devices? */
-+      if (event == NETDEV_UP && dev->open == network_open)
-+              send_fake_arp(dev);
++int netfront_accel_enqueue_skb_tso(netfront_accel_vnic *vnic,
++                                 struct sk_buff *skb);
 +
-+      return NOTIFY_DONE;
-+}
++#endif /* NETFRONT_ACCEL_TSO_H */
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel_vi.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel_vi.c    2008-05-19 00:33:48.626949033 +0300
+@@ -0,0 +1,1194 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+static struct notifier_block notifier_inetdev = {
-+      .notifier_call  = inetdev_notify,
-+      .next           = NULL,
-+      .priority       = 0
-+};
-+#endif
++#include <linux/if_ether.h>
++#include <linux/ip.h>
++#include <net/checksum.h>
++#include <asm/io.h>
 +
++#include "accel.h"
++#include "accel_util.h"
++#include "accel_bufs.h"
++#include "accel_tso.h"
++#include "accel_ssr.h"
++#include "netfront.h"
 +
-+static void netif_disconnect_backend(struct netfront_info *info)
-+{
-+      /* Stop old i/f to prevent errors whilst we rebuild the state. */
-+      spin_lock_bh(&info->rx_lock);
-+      spin_lock_irq(&info->tx_lock);
-+      netfront_carrier_off(info);
-+      spin_unlock_irq(&info->tx_lock);
-+      spin_unlock_bh(&info->rx_lock);
++#include "etherfabric/ef_vi.h"
 +
-+      if (info->irq)
-+              unbind_from_irqhandler(info->irq, info->netdev);
-+      info->irq = 0;
++/*
++ * Max available space in a buffer for data once meta-data has taken
++ * its place
++ */
++#define NETFRONT_ACCEL_TX_BUF_LENGTH                                  \
++      ((PAGE_SIZE / NETFRONT_ACCEL_BUFS_PER_PAGE)                     \
++       - sizeof(struct netfront_accel_tso_buffer))
 +
-+      end_access(info->tx_ring_ref, info->tx.sring);
-+      end_access(info->rx_ring_ref, info->rx.sring);
-+      info->tx_ring_ref = GRANT_INVALID_REF;
-+      info->rx_ring_ref = GRANT_INVALID_REF;
-+      info->tx.sring = NULL;
-+      info->rx.sring = NULL;
-+}
++#define ACCEL_TX_MAX_BUFFERS (6)
++#define ACCEL_VI_POLL_EVENTS (8)
 +
++static
++int netfront_accel_vi_init_fini(netfront_accel_vnic *vnic, 
++                              struct net_accel_msg_hw *hw_msg)
++{
++      struct ef_vi_nic_type nic_type;
++      struct net_accel_hw_falcon_b *hw_info;
++      void *io_kva, *evq_base, *rx_dma_kva, *tx_dma_kva, *doorbell_kva;
++      u32 *evq_gnts;
++      u32 evq_order;
++      int vi_state_size;
++      u8 vi_data[VI_MAPPINGS_SIZE];
++
++      if (hw_msg == NULL)
++              goto fini;
++
++      /* And create the local macs table lock */
++      spin_lock_init(&vnic->table_lock);
++      
++      /* Create fastpath table, initial size 8, key length 8 */
++      if (cuckoo_hash_init(&vnic->fastpath_table, 3, 8)) {
++              EPRINTK("failed to allocate fastpath table\n");
++              goto fail_cuckoo;
++      }
 +
-+static void end_access(int ref, void *page)
-+{
-+      if (ref != GRANT_INVALID_REF)
-+              gnttab_end_foreign_access(ref, (unsigned long)page);
-+}
++      vnic->hw.falcon.type = hw_msg->type;
 +
++      switch (hw_msg->type) {
++      case NET_ACCEL_MSG_HWTYPE_FALCON_A:
++              hw_info = &hw_msg->resources.falcon_a.common;
++              /* Need the extra rptr register page on A1 */
++              io_kva = net_accel_map_iomem_page
++                      (vnic->dev, hw_msg->resources.falcon_a.evq_rptr_gnt,
++                       &vnic->hw.falcon.evq_rptr_mapping);
++              if (io_kva == NULL) {
++                      EPRINTK("%s: evq_rptr permission failed\n", __FUNCTION__);
++                      goto evq_rptr_fail;
++              }
 +
-+/* ** Driver registration ** */
++              vnic->hw.falcon.evq_rptr = io_kva + 
++                      (hw_info->evq_rptr & (PAGE_SIZE - 1));
++              break;
++      case NET_ACCEL_MSG_HWTYPE_FALCON_B:
++              hw_info = &hw_msg->resources.falcon_b;
++              break;
++      default:
++              goto bad_type;
++      }
 +
++      /**** Event Queue ****/
 +
-+static struct xenbus_device_id netfront_ids[] = {
-+      { "vif" },
-+      { "" }
-+};
-+MODULE_ALIAS("xen:vif");
++      /* Map the event queue pages */
++      evq_gnts = hw_info->evq_mem_gnts;
++      evq_order = hw_info->evq_order;
 +
++      EPRINTK_ON(hw_info->evq_offs != 0);
 +
-+static struct xenbus_driver netfront = {
-+      .name = "vif",
-+      .owner = THIS_MODULE,
-+      .ids = netfront_ids,
-+      .probe = netfront_probe,
-+      .remove = __devexit_p(netfront_remove),
-+      .suspend = netfront_suspend,
-+      .suspend_cancel = netfront_suspend_cancel,
-+      .resume = netfront_resume,
-+      .otherend_changed = backend_changed,
-+};
++      DPRINTK("Will map evq %d pages\n", 1 << evq_order);
 +
++      evq_base =
++              net_accel_map_grants_contig(vnic->dev, evq_gnts, 1 << evq_order,
++                                          &vnic->evq_mapping);
++      if (evq_base == NULL) {
++              EPRINTK("%s: evq_base failed\n", __FUNCTION__);
++              goto evq_fail;
++      }
 +
-+static int __init netif_init(void)
-+{
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++      /**** Doorbells ****/
++      /* Set up the doorbell mappings. */
++      doorbell_kva = 
++              net_accel_map_iomem_page(vnic->dev, hw_info->doorbell_gnt,
++                                       &vnic->hw.falcon.doorbell_mapping);
++      if (doorbell_kva == NULL) {
++              EPRINTK("%s: doorbell permission failed\n", __FUNCTION__);
++              goto doorbell_fail;
++      }
++      vnic->hw.falcon.doorbell = doorbell_kva;
 +
-+#ifdef CONFIG_XEN
-+      if (MODPARM_rx_flip && MODPARM_rx_copy) {
-+              WPRINTK("Cannot specify both rx_copy and rx_flip.\n");
-+              return -EINVAL;
++      /* On Falcon_B we get the rptr from the doorbell page */
++      if (hw_msg->type == NET_ACCEL_MSG_HWTYPE_FALCON_B) {
++              vnic->hw.falcon.evq_rptr = 
++                      (u32 *)((char *)vnic->hw.falcon.doorbell 
++                              + hw_info->evq_rptr);
 +      }
 +
-+      if (!MODPARM_rx_flip && !MODPARM_rx_copy)
-+              MODPARM_rx_flip = 1; /* Default is to flip. */
-+#endif
++      /**** DMA Queue ****/
 +
-+      if (is_initial_xendomain())
-+              return 0;
++      /* Set up the DMA Queues from the message. */
++      tx_dma_kva = net_accel_map_grants_contig
++              (vnic->dev, &(hw_info->txdmaq_gnt), 1, 
++               &vnic->hw.falcon.txdmaq_mapping);
++      if (tx_dma_kva == NULL) {
++              EPRINTK("%s: TX dma failed\n", __FUNCTION__);
++              goto tx_dma_fail;
++      }
 +
-+      netif_init_accel();
++      rx_dma_kva = net_accel_map_grants_contig
++              (vnic->dev, &(hw_info->rxdmaq_gnt), 1, 
++               &vnic->hw.falcon.rxdmaq_mapping);
++      if (rx_dma_kva == NULL) {
++              EPRINTK("%s: RX dma failed\n", __FUNCTION__);
++              goto rx_dma_fail;
++      }
 +
-+      IPRINTK("Initialising virtual ethernet driver.\n");
++      /* Full confession */
++      DPRINTK("Mapped H/W"
++              "  Tx DMAQ grant %x -> %p\n"
++              "  Rx DMAQ grant %x -> %p\n"
++              "  EVQ grant %x -> %p\n",
++              hw_info->txdmaq_gnt, tx_dma_kva,
++              hw_info->rxdmaq_gnt, rx_dma_kva,
++              evq_gnts[0], evq_base
++              );
 +
-+#ifdef CONFIG_INET
-+      (void)register_inetaddr_notifier(&notifier_inetdev);
-+#endif
++      memset(vi_data, 0, sizeof(vi_data));
++      
++      /* TODO BUG11305: convert efhw_arch to ef_vi_arch
++       * e.g.
++       * arch = ef_vi_arch_from_efhw_arch(hw_info->nic_arch);
++       * assert(arch >= 0);
++       * nic_type.arch = arch;
++       */
++      nic_type.arch = (unsigned char)hw_info->nic_arch;
++      nic_type.variant = (char)hw_info->nic_variant;
++      nic_type.revision = (unsigned char)hw_info->nic_revision;
++      
++      ef_vi_init_mapping_evq(vi_data, nic_type, hw_info->instance, 
++                             1 << (evq_order + PAGE_SHIFT), evq_base, 
++                             (void *)0xdeadbeef);
++
++      ef_vi_init_mapping_vi(vi_data, nic_type, hw_info->rx_capacity, 
++                            hw_info->tx_capacity, hw_info->instance, 
++                            doorbell_kva, rx_dma_kva, tx_dma_kva, 0);
 +
-+      return xenbus_register_frontend(&netfront);
++      vi_state_size = ef_vi_calc_state_bytes(hw_info->rx_capacity,
++                                             hw_info->tx_capacity);
++      vnic->vi_state = (ef_vi_state *)kmalloc(vi_state_size, GFP_KERNEL);
++      if (vnic->vi_state == NULL) {
++              EPRINTK("%s: kmalloc for VI state failed\n", __FUNCTION__);
++              goto vi_state_fail;
++      }
++      ef_vi_init(&vnic->vi, vi_data, vnic->vi_state, &vnic->evq_state, 0);
++
++      ef_eventq_state_init(&vnic->vi);
++
++      ef_vi_state_init(&vnic->vi);
++
++      return 0;
++
++fini:
++      kfree(vnic->vi_state);
++      vnic->vi_state = NULL;
++vi_state_fail:
++      net_accel_unmap_grants_contig(vnic->dev, vnic->hw.falcon.rxdmaq_mapping);
++rx_dma_fail:
++      net_accel_unmap_grants_contig(vnic->dev, vnic->hw.falcon.txdmaq_mapping);
++tx_dma_fail:
++      net_accel_unmap_iomem_page(vnic->dev, vnic->hw.falcon.doorbell_mapping);
++      vnic->hw.falcon.doorbell = NULL;
++doorbell_fail:
++      net_accel_unmap_grants_contig(vnic->dev, vnic->evq_mapping);
++evq_fail:
++      if (vnic->hw.falcon.type == NET_ACCEL_MSG_HWTYPE_FALCON_A)
++              net_accel_unmap_iomem_page(vnic->dev, 
++                                         vnic->hw.falcon.evq_rptr_mapping);
++      vnic->hw.falcon.evq_rptr = NULL;
++evq_rptr_fail:
++bad_type:
++      cuckoo_hash_destroy(&vnic->fastpath_table);
++fail_cuckoo:
++      return -EIO;
 +}
-+module_init(netif_init);
 +
 +
-+static void __exit netif_exit(void)
++void netfront_accel_vi_ctor(netfront_accel_vnic *vnic)
 +{
-+      if (is_initial_xendomain())
-+              return;
-+
-+#ifdef CONFIG_INET
-+      unregister_inetaddr_notifier(&notifier_inetdev);
-+#endif
++      /* Just mark the VI as uninitialised. */
++      vnic->vi_state = NULL;
++}
 +
-+      netif_exit_accel();
 +
-+      return xenbus_unregister_driver(&netfront);
++int netfront_accel_vi_init(netfront_accel_vnic *vnic, struct net_accel_msg_hw *hw_msg)
++{
++      BUG_ON(hw_msg == NULL);
++      return netfront_accel_vi_init_fini(vnic, hw_msg);
 +}
-+module_exit(netif_exit);
 +
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/netfront/netfront.h linux-2.6.18-xen.hg/drivers/xen/netfront/netfront.h
---- linux-2.6.18/drivers/xen/netfront/netfront.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/netfront/netfront.h        2007-12-23 11:15:34.057935783 +0100
-@@ -0,0 +1,274 @@
-+/******************************************************************************
-+ * Virtual network driver for conversing with remote driver backends.
-+ *
-+ * Copyright (c) 2002-2005, K A Fraser
-+ * Copyright (c) 2005, XenSource Ltd
-+ * Copyright (C) 2007 Solarflare Communications, Inc.
-+ *
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ *
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
 +
-+#ifndef NETFRONT_H
-+#define NETFRONT_H
++void netfront_accel_vi_dtor(netfront_accel_vnic *vnic)
++{
++      if (vnic->vi_state != NULL)
++              netfront_accel_vi_init_fini(vnic, NULL);
++}
 +
-+#include <xen/interface/io/netif.h>
-+#include <linux/netdevice.h>
-+#include <linux/skbuff.h>
-+#include <linux/list.h>
 +
-+#define NET_TX_RING_SIZE __RING_SIZE((struct netif_tx_sring *)0, PAGE_SIZE)
-+#define NET_RX_RING_SIZE __RING_SIZE((struct netif_rx_sring *)0, PAGE_SIZE)
++static
++void netfront_accel_vi_post_rx(netfront_accel_vnic *vnic, u16 id,
++                             netfront_accel_pkt_desc *buf)
++{
 +
-+#include <xen/xenbus.h>
++      int idx = vnic->rx_dma_batched;
 +
-+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
-+#include <xen/platform-compat.h>
++#if 0
++      VPRINTK("Posting buffer %d (0x%08x) for rx at index %d, space is %d\n",
++              id, buf->pkt_buff_addr, idx, ef_vi_receive_space(&vnic->vi));
 +#endif
++      /* Set up a virtual buffer descriptor */
++      ef_vi_receive_init(&vnic->vi, buf->pkt_buff_addr, id,
++                         /*rx_bytes=max*/0);
 +
-+/* 
-+ * Function pointer table for hooks into a network acceleration
-+ * plugin.  These are called at appropriate points from the netfront
-+ * driver 
-+ */
-+struct netfront_accel_hooks {
-+      /* 
-+       * new_device: Accelerator hook to ask the plugin to support a
-+       * new network interface
-+       */
-+      int (*new_device)(struct net_device *net_dev, struct xenbus_device *dev);
-+      /*
-+       * remove: Opposite of new_device
-+       */
-+      int (*remove)(struct xenbus_device *dev);
-+      /*
-+       * The net_device is being polled, check the accelerated
-+       * hardware for any pending packets
-+       */
-+      int (*netdev_poll)(struct net_device *dev, int *pbudget);
-+      /*
-+       * start_xmit: Used to give the accelerated plugin the option
-+       * of sending a packet.  Returns non-zero if has done so, or
-+       * zero to decline and force the packet onto normal send
-+       * path
-+       */
-+      int (*start_xmit)(struct sk_buff *skb, struct net_device *dev);
-+      /* 
-+       * start/stop_napi_interrupts Used by netfront to indicate
-+       * when napi interrupts should be enabled or disabled 
-+       */
-+      int (*start_napi_irq)(struct net_device *dev);
-+      void (*stop_napi_irq)(struct net_device *dev);
++      idx++;
++
++      vnic->rx_dma_level++;
++      
 +      /* 
-+       * Called before re-enabling the TX queue to check the fast
-+       * path has slots too
++       * Only push the descriptor to the card if we've reached the
++       * batch size.  Otherwise, the descriptors can sit around for
++       * a while.  There will be plenty available.
 +       */
-+      int (*check_ready)(struct net_device *dev);
-+      /*
-+       * Get the fastpath network statistics
-+       */
-+      int (*get_stats)(struct net_device *dev,
-+                       struct net_device_stats *stats);
-+};
++      if (idx >= NETFRONT_ACCEL_RX_DESC_BATCH ||
++          vnic->rx_dma_level < NETFRONT_ACCEL_RX_DESC_BATCH) {
++#if 0
++              VPRINTK("Flushing %d rx descriptors.\n", idx);
++#endif
 +
++              /* Push buffer to hardware */
++              ef_vi_receive_push(&vnic->vi);
++              
++              idx = 0;
++      }
++      
++      vnic->rx_dma_batched = idx;
++}
 +
-+/* Version of API/protocol for communication between netfront and
-+   acceleration plugin supported */
-+#define NETFRONT_ACCEL_VERSION 0x00010003
 +
-+/* 
-+ * Per-netfront device state for the accelerator.  This is used to
-+ * allow efficient per-netfront device access to the accelerator
-+ * hooks 
-+ */
-+struct netfront_accel_vif_state {
-+      struct list_head link;
++inline
++void netfront_accel_vi_post_rx_or_free(netfront_accel_vnic *vnic, u16 id,
++                                     netfront_accel_pkt_desc *buf)
++{
 +
-+      struct xenbus_device *dev;
-+      struct netfront_info *np;
-+      struct netfront_accel_hooks *hooks;
++      VPRINTK("%s: %d\n", __FUNCTION__, id);
 +
-+      /* Watch on the accelerator configuration value */
-+      struct xenbus_watch accel_watch;
-+      /* Work item to process change in accelerator */
-+      struct work_struct accel_work;
-+      /* The string from xenbus last time accel_watch fired */
-+      char *accel_frontend;
-+}; 
++      if (ef_vi_receive_space(&vnic->vi) <= vnic->rx_dma_batched) {
++              VPRINTK("RX space is full\n");
++              netfront_accel_buf_put(vnic->rx_bufs, id);
++              return;
++      }
 +
-+/* 
-+ * Per-accelerator state stored in netfront.  These form a list that
-+ * is used to track which devices are accelerated by which plugins,
-+ * and what plugins are available/have been requested 
-+ */
-+struct netfront_accelerator {
-+      /* Used to make a list */
-+      struct list_head link;
-+      /* ID of the accelerator */
-+      int id;
++      VPRINTK("Completed buffer %d is reposted\n", id);
++      netfront_accel_vi_post_rx(vnic, id, buf);
++      
 +      /*
-+       * String describing the accelerator.  Currently this is the
-+       * name of the accelerator module.  This is provided by the
-+       * backend accelerator through xenstore 
++       * Let's see if there's any more to be pushed out to the NIC
++       * while we're here
 +       */
-+      char *frontend;
-+      /* The hooks into the accelerator plugin module */
-+      struct netfront_accel_hooks *hooks;
++      while (ef_vi_receive_space(&vnic->vi) > vnic->rx_dma_batched) {
++              /* Try to allocate a buffer. */
++              buf = netfront_accel_buf_get(vnic->rx_bufs);
++              if (buf == NULL)
++                      break;
++              
++              /* Add it to the rx dma queue. */
++              netfront_accel_vi_post_rx(vnic, buf->buf_id, buf);      
++      }
++}
 +
-+      /* 
-+       * List of per-netfront device state (struct
-+       * netfront_accel_vif_state) for each netfront device that is
-+       * using this accelerator
-+       */
-+      struct list_head vif_states;
-+      spinlock_t vif_states_lock;
-+};
 +
-+struct netfront_info {
-+      struct list_head list;
-+      struct net_device *netdev;
++void netfront_accel_vi_add_bufs(netfront_accel_vnic *vnic, int is_rx)
++{
 +
-+      struct net_device_stats stats;
++      while (is_rx && 
++             ef_vi_receive_space(&vnic->vi) > vnic->rx_dma_batched) {
++              netfront_accel_pkt_desc *buf;
++              
++              VPRINTK("%s: %d\n", __FUNCTION__, vnic->rx_dma_level);
++              
++              /* Try to allocate a buffer. */
++              buf = netfront_accel_buf_get(vnic->rx_bufs);
 +
-+      struct netif_tx_front_ring tx;
-+      struct netif_rx_front_ring rx;
++              if (buf == NULL)
++                      break;
++              
++              /* Add it to the rx dma queue. */
++              netfront_accel_vi_post_rx(vnic, buf->buf_id, buf);
++      }
 +
-+      spinlock_t   tx_lock;
-+      spinlock_t   rx_lock;
++      VPRINTK("%s: done\n", __FUNCTION__);
++}
 +
-+      unsigned int irq;
-+      unsigned int copying_receiver;
-+      unsigned int carrier;
 +
-+      /* Receive-ring batched refills. */
-+#define RX_MIN_TARGET 8
-+#define RX_DFL_MIN_TARGET 64
-+#define RX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
-+      unsigned rx_min_target, rx_max_target, rx_target;
-+      struct sk_buff_head rx_batch;
++struct netfront_accel_multi_state {
++      unsigned remaining_len;
 +
-+      struct timer_list rx_refill_timer;
++      unsigned buffers;
 +
-+      /*
-+       * {tx,rx}_skbs store outstanding skbuffs. The first entry in tx_skbs
-+       * is an index into a chain of free entries.
-+       */
-+      struct sk_buff *tx_skbs[NET_TX_RING_SIZE+1];
-+      struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
++      struct netfront_accel_tso_buffer *output_buffers;
 +
-+#define TX_MAX_TARGET min_t(int, NET_RX_RING_SIZE, 256)
-+      grant_ref_t gref_tx_head;
-+      grant_ref_t grant_tx_ref[NET_TX_RING_SIZE + 1];
-+      grant_ref_t gref_rx_head;
-+      grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
++      /* Where we are in the current fragment of the SKB. */
++      struct {
++              /* address of current position */
++              void *addr;
++              /* remaining length */    
++              unsigned int len;
++      } ifc; /*  == Input Fragment Cursor */
++};
 +
-+      struct xenbus_device *xbdev;
-+      int tx_ring_ref;
-+      int rx_ring_ref;
-+      u8 mac[ETH_ALEN];
 +
-+      unsigned long rx_pfn_array[NET_RX_RING_SIZE];
-+      struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
-+      struct mmu_update rx_mmu[NET_RX_RING_SIZE];
++static inline void multi_post_start(struct netfront_accel_multi_state *st, 
++                                  struct sk_buff *skb)
++{
++      st->remaining_len = skb->len;
++      st->output_buffers = NULL;
++      st->buffers = 0;
++      st->ifc.len = skb_headlen(skb);
++      st->ifc.addr = skb->data;
++}
 +
-+      /* Private pointer to state internal to accelerator module */
-+      void *accel_priv;
-+      /* The accelerator used by this netfront device */
-+      struct netfront_accelerator *accelerator;
-+      /* The accelerator state for this netfront device */
-+      struct netfront_accel_vif_state accel_vif_state;
-+};
++static int multi_post_start_new_buffer(netfront_accel_vnic *vnic, 
++                                     struct netfront_accel_multi_state *st)
++{
++      struct netfront_accel_tso_buffer *tso_buf;
++      struct netfront_accel_pkt_desc *buf;
 +
++      /* Get a mapped packet buffer */
++      buf = netfront_accel_buf_get(vnic->tx_bufs);
++      if (buf == NULL) {
++              DPRINTK("%s: No buffer for TX\n", __FUNCTION__);
++              return -1;
++      }
 +
-+/* Exported Functions */
++      /* Store a bit of meta-data at the end */
++      tso_buf = (struct netfront_accel_tso_buffer *)
++              (buf->pkt_kva + NETFRONT_ACCEL_TX_BUF_LENGTH);
 +
-+/*
-+ * Called by an accelerator plugin module when it has loaded.
-+ *
-+ * frontend: the string describing the accelerator, currently the module name 
-+ * hooks: the hooks for netfront to use to call into the accelerator
-+ * version: the version of API between frontend and plugin requested
-+ * 
-+ * return: 0 on success, <0 on error, >0 (with version supported) on
-+ * version mismatch
-+ */
-+extern int netfront_accelerator_loaded(int version, const char *frontend, 
-+                                     struct netfront_accel_hooks *hooks);
++      tso_buf->buf = buf;
 +
-+/* 
-+ * Called by an accelerator plugin module when it is about to unload.
-+ *
-+ * frontend: the string describing the accelerator.  Must match the
-+ * one passed to netfront_accelerator_loaded()
-+ */ 
-+extern void netfront_accelerator_stop(const char *frontend);
++      tso_buf->length = 0;
++      
++      tso_buf->next = st->output_buffers;
++      st->output_buffers = tso_buf;
++      st->buffers++;
 +
-+/* 
-+ * Called by an accelerator before waking the net device's TX queue to
-+ * ensure the slow path has available slots.  Returns true if OK to
-+ * wake, false if still busy 
-+ */
-+extern int netfront_check_queue_ready(struct net_device *net_dev);
++      BUG_ON(st->buffers >= ACCEL_TX_MAX_BUFFERS);
 +
++      /*
++       * Store the context, set to NULL, last packet buffer will get
++       * non-NULL later
++       */
++      tso_buf->buf->skb = NULL;
++      
++      return 0;
++}
 +
-+/* Internal-to-netfront Functions */
 +
-+/* 
-+ * Call into accelerator and check to see if it has tx space before we
-+ * wake the net device's TX queue.  Returns true if OK to wake, false
-+ * if still busy
-+ */ 
-+extern 
-+int netfront_check_accelerator_queue_ready(struct net_device *dev,
-+                                         struct netfront_info *np);
-+extern
-+int netfront_accelerator_call_remove(struct netfront_info *np,
-+                                   struct xenbus_device *dev);
-+extern
-+int netfront_accelerator_suspend(struct netfront_info *np,
-+                               struct xenbus_device *dev);
-+extern
-+int netfront_accelerator_suspend_cancel(struct netfront_info *np,
-+                                      struct xenbus_device *dev);
-+extern
-+void netfront_accelerator_resume(struct netfront_info *np,
-+                               struct xenbus_device *dev);
-+extern
-+void netfront_accelerator_call_stop_napi_irq(struct netfront_info *np,
-+                                           struct net_device *dev);
-+extern
-+int netfront_accelerator_call_get_stats(struct netfront_info *np,
-+                                      struct net_device *dev);
-+extern
-+void netfront_accelerator_add_watch(struct netfront_info *np);
++static void
++multi_post_fill_buffer_with_fragment(netfront_accel_vnic *vnic,
++                                   struct netfront_accel_multi_state *st)
++{
++      struct netfront_accel_tso_buffer *tso_buf;
++      unsigned n, space;
 +
-+extern
-+void netif_init_accel(void);
-+extern
-+void netif_exit_accel(void);
++      BUG_ON(st->output_buffers == NULL);
++      tso_buf = st->output_buffers;
 +
-+extern
-+void init_accelerator_vif(struct netfront_info *np,
-+                        struct xenbus_device *dev);
-+#endif /* NETFRONT_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/conf_space.c linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space.c
---- linux-2.6.18/drivers/xen/pciback/conf_space.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space.c       2007-12-23 11:15:34.061269291 +0100
-@@ -0,0 +1,426 @@
-+/*
-+ * PCI Backend - Functions for creating a virtual configuration space for
-+ *               exported PCI Devices.
-+ *               It's dangerous to allow PCI Driver Domains to change their
-+ *               device's resources (memory, i/o ports, interrupts). We need to
-+ *               restrict changes to certain PCI Configuration registers:
-+ *               BARs, INTERRUPT_PIN, most registers in the header...
-+ *
-+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ */
++      if (st->ifc.len == 0) return;
++      if (tso_buf->length == NETFRONT_ACCEL_TX_BUF_LENGTH) return;
 +
-+#include <linux/kernel.h>
-+#include <linux/pci.h>
-+#include "pciback.h"
-+#include "conf_space.h"
-+#include "conf_space_quirks.h"
++      BUG_ON(tso_buf->length > NETFRONT_ACCEL_TX_BUF_LENGTH);
 +
-+#define DEFINE_PCI_CONFIG(op,size,type)                       \
-+int pciback_##op##_config_##size                              \
-+(struct pci_dev *dev, int offset, type value, void *data)     \
-+{                                                             \
-+      return pci_##op##_config_##size (dev, offset, value);   \
-+}
++      space = NETFRONT_ACCEL_TX_BUF_LENGTH - tso_buf->length;
++      n = min(st->ifc.len, space);
 +
-+DEFINE_PCI_CONFIG(read, byte, u8 *)
-+DEFINE_PCI_CONFIG(read, word, u16 *)
-+DEFINE_PCI_CONFIG(read, dword, u32 *)
++      memcpy(tso_buf->buf->pkt_kva + tso_buf->length, st->ifc.addr, n);
 +
-+DEFINE_PCI_CONFIG(write, byte, u8)
-+DEFINE_PCI_CONFIG(write, word, u16)
-+DEFINE_PCI_CONFIG(write, dword, u32)
++      st->remaining_len -= n;
++      st->ifc.len -= n;
++      tso_buf->length += n;
++      st->ifc.addr += n;
 +
-+static int conf_space_read(struct pci_dev *dev,
-+                         struct config_field_entry *entry, int offset,
-+                         u32 * value)
++      BUG_ON(tso_buf->length > NETFRONT_ACCEL_TX_BUF_LENGTH);
++
++      return;
++}
++
++
++static inline void multi_post_unwind(netfront_accel_vnic *vnic,
++                                   struct netfront_accel_multi_state *st)
 +{
-+      int ret = 0;
-+      struct config_field *field = entry->field;
++      struct netfront_accel_tso_buffer *tso_buf;
 +
-+      *value = 0;
++      DPRINTK("%s\n", __FUNCTION__);
 +
-+      switch (field->size) {
-+      case 1:
-+              if (field->u.b.read)
-+                      ret = field->u.b.read(dev, offset, (u8 *) value,
-+                                            entry->data);
-+              break;
-+      case 2:
-+              if (field->u.w.read)
-+                      ret = field->u.w.read(dev, offset, (u16 *) value,
-+                                            entry->data);
-+              break;
-+      case 4:
-+              if (field->u.dw.read)
-+                      ret = field->u.dw.read(dev, offset, value, entry->data);
-+              break;
++      while (st->output_buffers != NULL) {
++              tso_buf = st->output_buffers;
++              st->output_buffers = tso_buf->next;
++              st->buffers--;
++              netfront_accel_buf_put(vnic->tx_bufs, tso_buf->buf->buf_id);
 +      }
-+      return ret;
++      BUG_ON(st->buffers != 0);
 +}
 +
-+static int conf_space_write(struct pci_dev *dev,
-+                          struct config_field_entry *entry, int offset,
-+                          u32 value)
++
++static enum netfront_accel_post_status
++netfront_accel_enqueue_skb_multi(netfront_accel_vnic *vnic, struct sk_buff *skb)
 +{
-+      int ret = 0;
-+      struct config_field *field = entry->field;
++      struct netfront_accel_tso_buffer *tso_buf;
++      struct netfront_accel_multi_state state;
++      ef_iovec iovecs[ACCEL_TX_MAX_BUFFERS];
++      skb_frag_t *f;
++      int frag_i, rc, dma_id;
 +
-+      switch (field->size) {
-+      case 1:
-+              if (field->u.b.write)
-+                      ret = field->u.b.write(dev, offset, (u8) value,
-+                                             entry->data);
-+              break;
-+      case 2:
-+              if (field->u.w.write)
-+                      ret = field->u.w.write(dev, offset, (u16) value,
-+                                             entry->data);
-+              break;
-+      case 4:
-+              if (field->u.dw.write)
-+                      ret = field->u.dw.write(dev, offset, value,
-+                                              entry->data);
-+              break;
++      multi_post_start(&state, skb);
++
++      frag_i = -1;
++
++      if (skb->ip_summed == CHECKSUM_HW) {
++              /* Set to zero to encourage falcon to work it out for us */
++              *(u16*)(skb->h.raw + skb->csum) = 0;
 +      }
-+      return ret;
++
++      if (multi_post_start_new_buffer(vnic, &state)) {
++              DPRINTK("%s: out of buffers\n", __FUNCTION__);
++              goto unwind;
++      }
++
++      while (1) {
++              multi_post_fill_buffer_with_fragment(vnic, &state);
++
++              /* Move onto the next fragment? */
++              if (state.ifc.len == 0) {
++                      if (++frag_i >= skb_shinfo(skb)->nr_frags)
++                              /* End of payload reached. */
++                              break;
++                      f = &skb_shinfo(skb)->frags[frag_i];
++                      state.ifc.len = f->size;
++                      state.ifc.addr = page_address(f->page) + f->page_offset;
++              }
++
++              /* Start a new buffer? */
++              if ((state.output_buffers->length == 
++                   NETFRONT_ACCEL_TX_BUF_LENGTH) &&
++                  multi_post_start_new_buffer(vnic, &state)) {
++                      DPRINTK("%s: out of buffers\n", __FUNCTION__);
++                      goto unwind;
++              }
++      }
++
++      /* Check for space */
++      if (ef_vi_transmit_space(&vnic->vi) < state.buffers) {
++              DPRINTK("%s: Not enough TX space (%d)\n", __FUNCTION__, state.buffers);
++              goto unwind;
++      }
++
++      /* Store the skb in what will be the last buffer's context */
++      state.output_buffers->buf->skb = skb;
++      /* Remember dma_id of what will be the last buffer */ 
++      dma_id = state.output_buffers->buf->buf_id;
++
++      /*
++       * Make an iovec of the buffers in the list, reversing the
++       * buffers as we go as they are constructed on a stack
++       */
++      tso_buf = state.output_buffers;
++      for (frag_i = state.buffers-1; frag_i >= 0; frag_i--) {
++              iovecs[frag_i].iov_base = tso_buf->buf->pkt_buff_addr;
++              iovecs[frag_i].iov_len = tso_buf->length;
++              tso_buf = tso_buf->next;
++      }
++      
++      rc = ef_vi_transmitv(&vnic->vi, iovecs, state.buffers, dma_id);
++
++      /* Track number of tx fastpath stats */
++      vnic->netdev_stats.fastpath_tx_bytes += skb->len;
++      vnic->netdev_stats.fastpath_tx_pkts ++;
++#if NETFRONT_ACCEL_STATS
++      {
++              u32 n;
++              n = vnic->netdev_stats.fastpath_tx_pkts -
++                      (u32)vnic->stats.fastpath_tx_completions;
++              if (n > vnic->stats.fastpath_tx_pending_max)
++                      vnic->stats.fastpath_tx_pending_max = n;
++      }
++#endif
++      return NETFRONT_ACCEL_STATUS_GOOD;
++
++unwind:
++      multi_post_unwind(vnic, &state);
++
++      NETFRONT_ACCEL_STATS_OP(vnic->stats.fastpath_tx_busy++);
++
++      return NETFRONT_ACCEL_STATUS_BUSY;
 +}
 +
-+static inline u32 get_mask(int size)
++
++static enum netfront_accel_post_status 
++netfront_accel_enqueue_skb_single(netfront_accel_vnic *vnic, struct sk_buff *skb)
 +{
-+      if (size == 1)
-+              return 0xff;
-+      else if (size == 2)
-+              return 0xffff;
-+      else
-+              return 0xffffffff;
++      struct netfront_accel_tso_buffer *tso_buf;
++      struct netfront_accel_pkt_desc *buf;
++      u8 *kva;
++      int rc;
++
++      if (ef_vi_transmit_space(&vnic->vi) < 1) {
++              DPRINTK("%s: No TX space\n", __FUNCTION__);
++              NETFRONT_ACCEL_STATS_OP(vnic->stats.fastpath_tx_busy++);
++              return NETFRONT_ACCEL_STATUS_BUSY;
++      }
++
++      buf = netfront_accel_buf_get(vnic->tx_bufs);
++      if (buf == NULL) {
++              DPRINTK("%s: No buffer for TX\n", __FUNCTION__);
++              NETFRONT_ACCEL_STATS_OP(vnic->stats.fastpath_tx_busy++);
++              return NETFRONT_ACCEL_STATUS_BUSY;
++      }
++
++      /* Track number of tx fastpath stats */
++      vnic->netdev_stats.fastpath_tx_pkts++;
++      vnic->netdev_stats.fastpath_tx_bytes += skb->len;
++
++#if NETFRONT_ACCEL_STATS
++      {
++              u32 n;
++              n = vnic->netdev_stats.fastpath_tx_pkts - 
++                      (u32)vnic->stats.fastpath_tx_completions;
++              if (n > vnic->stats.fastpath_tx_pending_max)
++                      vnic->stats.fastpath_tx_pending_max = n;
++      }
++#endif
++      
++      /* Store the context */
++      buf->skb = skb;
++      
++      kva = buf->pkt_kva;
++
++      if (skb->ip_summed == CHECKSUM_HW) {
++              /* Set to zero to encourage falcon to work it out for us */
++              *(u16*)(skb->h.raw + skb->csum) = 0;
++      }
++      NETFRONT_ACCEL_PKTBUFF_FOR_EACH_FRAGMENT
++              (skb, idx, frag_data, frag_len, {
++                      /* Copy in payload */
++                      VPRINTK("*** Copying %d bytes to %p\n", frag_len, kva);
++                      memcpy(kva, frag_data, frag_len);
++                      kva += frag_len;
++              });
++
++      VPRINTK("%s: id %d pkt %p kva %p buff_addr 0x%08x\n", __FUNCTION__,
++              buf->buf_id, buf, buf->pkt_kva, buf->pkt_buff_addr);
++
++
++      /* Set up the TSO meta-data for a single buffer/packet */
++      tso_buf = (struct netfront_accel_tso_buffer *)
++              (buf->pkt_kva + NETFRONT_ACCEL_TX_BUF_LENGTH);
++      tso_buf->next = NULL;
++      tso_buf->buf = buf;
++      tso_buf->length = skb->len;
++
++      rc = ef_vi_transmit(&vnic->vi, buf->pkt_buff_addr, skb->len,
++                          buf->buf_id);
++      /* We checked for space already, so it really should succeed */
++      BUG_ON(rc != 0);
++
++      return NETFRONT_ACCEL_STATUS_GOOD;
 +}
 +
-+static inline int valid_request(int offset, int size)
++
++enum netfront_accel_post_status 
++netfront_accel_vi_tx_post(netfront_accel_vnic *vnic, struct sk_buff *skb)
 +{
-+      /* Validate request (no un-aligned requests) */
-+      if ((size == 1 || size == 2 || size == 4) && (offset % size) == 0)
-+              return 1;
-+      return 0;
++      struct ethhdr *pkt_eth_hdr;
++      struct iphdr *pkt_ipv4_hdr;
++      int value, try_fastpath;
++
++      /*
++       * This assumes that the data field points to the dest mac
++       * address.
++       */
++      cuckoo_hash_mac_key key = cuckoo_mac_to_key(skb->data);
++
++      /*
++       * NB very important that all things that could return "CANT"
++       * are tested before things that return "BUSY" as if it it
++       * returns "BUSY" it is assumed that it won't return "CANT"
++       * next time it is tried
++       */
++
++      /*
++       * Do a fastpath send if fast path table lookup returns true.
++       * We do this without the table lock and so may get the wrong
++       * answer, but current opinion is that's not a big problem 
++       */
++      try_fastpath = cuckoo_hash_lookup(&vnic->fastpath_table, 
++                                        (cuckoo_hash_key *)(&key), &value);
++
++      if (!try_fastpath) {
++              VPRINTK("try fast path false for mac: " MAC_FMT "\n",
++                      MAC_ARG(skb->data));
++              
++              return NETFRONT_ACCEL_STATUS_CANT;
++      }
++
++      /* Check to see if the packet can be sent. */
++      if (skb_headlen(skb) < sizeof(*pkt_eth_hdr) + sizeof(*pkt_ipv4_hdr)) {
++              EPRINTK("%s: Packet header is too small\n", __FUNCTION__);
++              return NETFRONT_ACCEL_STATUS_CANT;
++      }
++
++      pkt_eth_hdr  = (void*)skb->data;
++      pkt_ipv4_hdr = (void*)(pkt_eth_hdr+1);
++
++      if (be16_to_cpu(pkt_eth_hdr->h_proto) != ETH_P_IP) {
++              DPRINTK("%s: Packet is not IPV4 (ether_type=0x%04x)\n", __FUNCTION__,
++                      be16_to_cpu(pkt_eth_hdr->h_proto));
++              return NETFRONT_ACCEL_STATUS_CANT;
++      }
++      
++      if (pkt_ipv4_hdr->protocol != IPPROTO_TCP &&
++          pkt_ipv4_hdr->protocol != IPPROTO_UDP) {
++              DPRINTK("%s: Packet is not TCP/UDP (ip_protocol=0x%02x)\n",
++                      __FUNCTION__, pkt_ipv4_hdr->protocol);
++              return NETFRONT_ACCEL_STATUS_CANT;
++      }
++      
++      VPRINTK("%s: %d bytes, gso %d\n", __FUNCTION__, skb->len, 
++              skb_shinfo(skb)->gso_size);
++      
++      if (skb_shinfo(skb)->gso_size) {
++              return netfront_accel_enqueue_skb_tso(vnic, skb);
++      }
++
++      if (skb->len <= NETFRONT_ACCEL_TX_BUF_LENGTH) {
++              return netfront_accel_enqueue_skb_single(vnic, skb);
++      }
++
++      return netfront_accel_enqueue_skb_multi(vnic, skb);
 +}
 +
-+static inline u32 merge_value(u32 val, u32 new_val, u32 new_val_mask,
-+                            int offset)
++
++/*
++ * Copy the data to required end destination. NB. len is the total new
++ * length of the socket buffer, not the amount of data to copy
++ */
++inline
++int ef_vnic_copy_to_skb(netfront_accel_vnic *vnic, struct sk_buff *skb, 
++                      struct netfront_accel_pkt_desc *buf, int len)
 +{
-+      if (offset >= 0) {
-+              new_val_mask <<= (offset * 8);
-+              new_val <<= (offset * 8);
-+      } else {
-+              new_val_mask >>= (offset * -8);
-+              new_val >>= (offset * -8);
++      int i, extra = len - skb->len;
++      char c;
++      int pkt_stride = vnic->rx_pkt_stride;
++      int skb_stride = vnic->rx_skb_stride;
++      char *skb_start;
++      
++      /*
++       * This pulls stuff into the cache - have seen performance
++       * benefit in this, but disabled by default
++       */
++      skb_start = skb->data;
++      if (pkt_stride) {
++              for (i = 0; i < len; i += pkt_stride) {
++                      c += ((volatile char*)(buf->pkt_kva))[i];
++              }
++      }
++      if (skb_stride) {
++              for (i = skb->len; i < len ; i += skb_stride) {
++                      c += ((volatile char*)(skb_start))[i];
++              }
 +      }
-+      val = (val & ~new_val_mask) | (new_val & new_val_mask);
 +
-+      return val;
++      if (skb_tailroom(skb) >= extra) {
++              memcpy(skb_put(skb, extra), buf->pkt_kva, extra);
++              return 0;
++      }
++
++      return -ENOSPC;
 +}
 +
-+static int pcibios_err_to_errno(int err)
++
++static void discard_jumbo_state(netfront_accel_vnic *vnic) 
 +{
-+      switch (err) {
-+      case PCIBIOS_SUCCESSFUL:
-+              return XEN_PCI_ERR_success;
-+      case PCIBIOS_DEVICE_NOT_FOUND:
-+              return XEN_PCI_ERR_dev_not_found;
-+      case PCIBIOS_BAD_REGISTER_NUMBER:
-+              return XEN_PCI_ERR_invalid_offset;
-+      case PCIBIOS_FUNC_NOT_SUPPORTED:
-+              return XEN_PCI_ERR_not_implemented;
-+      case PCIBIOS_SET_FAILED:
-+              return XEN_PCI_ERR_access_denied;
++
++      if (vnic->jumbo_state.skb != NULL) {
++              dev_kfree_skb_any(vnic->jumbo_state.skb);
++
++              vnic->jumbo_state.skb = NULL;
 +      }
-+      return err;
++      vnic->jumbo_state.in_progress = 0;
 +}
 +
-+int pciback_config_read(struct pci_dev *dev, int offset, int size,
-+                      u32 * ret_val)
++
++static void  netfront_accel_vi_rx_complete(netfront_accel_vnic *vnic,
++                                         struct sk_buff *skb)
 +{
-+      int err = 0;
-+      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+      struct config_field_entry *cfg_entry;
-+      struct config_field *field;
-+      int req_start, req_end, field_start, field_end;
-+      /* if read fails for any reason, return 0 (as if device didn't respond) */
-+      u32 value = 0, tmp_val;
++      cuckoo_hash_mac_key key;
++      unsigned long flags;
++      int value;
++      struct net_device *net_dev;
 +
-+      if (unlikely(verbose_request))
-+              printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x\n",
-+                     pci_name(dev), size, offset);
 +
-+      if (!valid_request(offset, size)) {
-+              err = XEN_PCI_ERR_invalid_offset;
-+              goto out;
-+      }
++      key = cuckoo_mac_to_key(skb->data + ETH_ALEN);
 +
-+      /* Get the real value first, then modify as appropriate */
-+      switch (size) {
-+      case 1:
-+              err = pci_read_config_byte(dev, offset, (u8 *) & value);
-+              break;
-+      case 2:
-+              err = pci_read_config_word(dev, offset, (u16 *) & value);
-+              break;
-+      case 4:
-+              err = pci_read_config_dword(dev, offset, &value);
-+              break;
++      /*
++       * If this is a MAC address that we want to do fast path TX
++       * to, and we don't already, add it to the fastpath table.
++       * The initial lookup is done without the table lock and so
++       * may get the wrong answer, but current opinion is that's not
++       * a big problem
++       */
++      if (is_valid_ether_addr(skb->data + ETH_ALEN) &&
++          !cuckoo_hash_lookup(&vnic->fastpath_table, (cuckoo_hash_key *)&key,
++                              &value)) {
++              spin_lock_irqsave(&vnic->table_lock, flags);
++                 
++              cuckoo_hash_add_check(&vnic->fastpath_table,
++                                    (cuckoo_hash_key *)&key,
++                                    1, 1);
++              
++              spin_unlock_irqrestore(&vnic->table_lock, flags);
 +      }
 +
-+      list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
-+              field = cfg_entry->field;
-+
-+              req_start = offset;
-+              req_end = offset + size;
-+              field_start = OFFSET(cfg_entry);
-+              field_end = OFFSET(cfg_entry) + field->size;
++      if (compare_ether_addr(skb->data, vnic->mac)) {
++              struct iphdr *ip = (struct iphdr *)(skb->data + ETH_HLEN);
++              u16 port;
 +
-+              if ((req_start >= field_start && req_start < field_end)
-+                  || (req_end > field_start && req_end <= field_end)) {
-+                      err = conf_space_read(dev, cfg_entry, field_start,
-+                                            &tmp_val);
-+                      if (err)
-+                              goto out;
++              DPRINTK("%s: saw wrong MAC address " MAC_FMT "\n", 
++                      __FUNCTION__, MAC_ARG(skb->data));
 +
-+                      value = merge_value(value, tmp_val,
-+                                          get_mask(field->size),
-+                                          field_start - req_start);
++              if (ip->protocol == IPPROTO_TCP) {
++                      struct tcphdr *tcp = (struct tcphdr *)
++                              ((char *)ip + 4 * ip->ihl);
++                      port = tcp->dest;
++              } else {
++                      struct udphdr *udp = (struct udphdr *)
++                              ((char *)ip + 4 * ip->ihl);
++                      EPRINTK_ON(ip->protocol != IPPROTO_UDP);
++                      port = udp->dest;
 +              }
++
++              netfront_accel_msg_tx_fastpath(vnic, skb->data,
++                                             ip->daddr, port,
++                                             ip->protocol);
 +      }
 +
-+      out:
-+      if (unlikely(verbose_request))
-+              printk(KERN_DEBUG "pciback: %s: read %d bytes at 0x%x = %x\n",
-+                     pci_name(dev), size, offset, value);
++      net_dev = vnic->net_dev;
++      skb->dev = net_dev;
++      skb->protocol = eth_type_trans(skb, net_dev);
++      /* CHECKSUM_UNNECESSARY as hardware has done it already */
++      skb->ip_summed = CHECKSUM_UNNECESSARY;
 +
-+      *ret_val = value;
-+      return pcibios_err_to_errno(err);
++      if (!netfront_accel_ssr_skb(vnic, &vnic->ssr_state, skb))
++              netif_receive_skb(skb);
 +}
 +
-+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value)
++
++static int netfront_accel_vi_poll_process_rx(netfront_accel_vnic *vnic, 
++                                           ef_event *ev)
 +{
-+      int err = 0, handled = 0;
-+      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+      struct config_field_entry *cfg_entry;
-+      struct config_field *field;
-+      u32 tmp_val;
-+      int req_start, req_end, field_start, field_end;
++      struct netfront_accel_bufinfo *bufinfo = vnic->rx_bufs;
++      struct netfront_accel_pkt_desc *buf = NULL;
++      struct sk_buff *skb;
++      int id, len, sop = 0, cont = 0;
 +
-+      if (unlikely(verbose_request))
-+              printk(KERN_DEBUG
-+                     "pciback: %s: write request %d bytes at 0x%x = %x\n",
-+                     pci_name(dev), size, offset, value);
++      VPRINTK("Rx event.\n");
++      /*
++       * Complete the receive operation, and get the request id of
++       * the buffer
++       */
++      id = ef_vi_receive_done(&vnic->vi, ev);
 +
-+      if (!valid_request(offset, size))
-+              return XEN_PCI_ERR_invalid_offset;
++      if (id < 0 || id >= bufinfo->npages*NETFRONT_ACCEL_BUFS_PER_PAGE) {
++              EPRINTK("Rx packet %d is invalid\n", id);
++              /* Carry on round the loop if more events */
++              goto bad_packet;
++      }
++      /* Get our buffer descriptor */
++      buf = netfront_accel_buf_find(bufinfo, id);
 +
-+      list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
-+              field = cfg_entry->field;
++      len = EF_EVENT_RX_BYTES(*ev);
 +
-+              req_start = offset;
-+              req_end = offset + size;
-+              field_start = OFFSET(cfg_entry);
-+              field_end = OFFSET(cfg_entry) + field->size;
++      /* An RX buffer has been removed from the DMA ring. */
++      vnic->rx_dma_level--;
 +
-+              if ((req_start >= field_start && req_start < field_end)
-+                  || (req_end > field_start && req_end <= field_end)) {
-+                      tmp_val = 0;
++      if (EF_EVENT_TYPE(*ev) == EF_EVENT_TYPE_RX) {
++              sop = EF_EVENT_RX_SOP(*ev);
++              cont = EF_EVENT_RX_CONT(*ev);
 +
-+                      err = pciback_config_read(dev, field_start,
-+                                                field->size, &tmp_val);
-+                      if (err)
-+                              break;
++              skb = vnic->jumbo_state.skb;
 +
-+                      tmp_val = merge_value(tmp_val, value, get_mask(size),
-+                                            req_start - field_start);
++              VPRINTK("Rx packet %d: %d bytes so far; sop %d; cont %d\n", 
++                      id, len, sop, cont);
 +
-+                      err = conf_space_write(dev, cfg_entry, field_start,
-+                                             tmp_val);
++              if (sop) {
++                      if (!vnic->jumbo_state.in_progress) {
++                              vnic->jumbo_state.in_progress = 1;
++                              BUG_ON(vnic->jumbo_state.skb != NULL);
++                      } else {
++                              /*
++                               * This fragment shows a missing tail in 
++                               * previous one, but is itself possibly OK
++                               */
++                              DPRINTK("sop and in_progress => no tail\n");
 +
-+                      /* handled is set true here, but not every byte
-+                       * may have been written! Properly detecting if
-+                       * every byte is handled is unnecessary as the
-+                       * flag is used to detect devices that need
-+                       * special helpers to work correctly.
-+                       */
-+                      handled = 1;
++                              /* Release the socket buffer we already had */
++                              discard_jumbo_state(vnic);
++
++                              /* Now start processing this fragment */
++                              vnic->jumbo_state.in_progress = 1;
++                              skb = NULL;
++                      }
++              } else if (!vnic->jumbo_state.in_progress) {
++                      DPRINTK("!sop and !in_progress => missing head\n");
++                      goto missing_head;
 +              }
-+      }
 +
-+      if (!handled && !err) {
-+              /* By default, anything not specificially handled above is
-+               * read-only. The permissive flag changes this behavior so
-+               * that anything not specifically handled above is writable.
-+               * This means that some fields may still be read-only because
-+               * they have entries in the config_field list that intercept
-+               * the write and do nothing. */
-+              if (dev_data->permissive) {
-+                      switch (size) {
-+                      case 1:
-+                              err = pci_write_config_byte(dev, offset,
-+                                                          (u8) value);
-+                              break;
-+                      case 2:
-+                              err = pci_write_config_word(dev, offset,
-+                                                          (u16) value);
-+                              break;
-+                      case 4:
-+                              err = pci_write_config_dword(dev, offset,
-+                                                           (u32) value);
-+                              break;
++              if (!cont) {
++                      /* Update state for next time */
++                      vnic->jumbo_state.in_progress = 0;
++                      vnic->jumbo_state.skb = NULL;
++              } else if (!vnic->jumbo_state.in_progress) {
++                      DPRINTK("cont and !in_progress => missing head\n");
++                      goto missing_head;
++              }
++
++              if (skb == NULL) {
++                      BUG_ON(!sop);
++
++                      if (!cont)
++                              skb = alloc_skb(len+NET_IP_ALIGN, GFP_ATOMIC);
++                      else
++                              skb = alloc_skb(vnic->net_dev->mtu+NET_IP_ALIGN, 
++                                              GFP_ATOMIC);
++
++                      if (skb == NULL) {
++                              DPRINTK("%s: Couldn't get an rx skb.\n",
++                                      __FUNCTION__);
++                              netfront_accel_vi_post_rx_or_free(vnic, (u16)id, buf);
++                              /*
++                               * Dropping this fragment means we
++                               * should discard the rest too
++                               */
++                              discard_jumbo_state(vnic);
++
++                              /* Carry on round the loop if more events */
++                              return 0;
 +                      }
-+              } else if (!dev_data->warned_on_write) {
-+                      dev_data->warned_on_write = 1;
-+                      dev_warn(&dev->dev, "Driver tried to write to a "
-+                               "read-only configuration space field at offset "
-+                               "0x%x, size %d. This may be harmless, but if "
-+                               "you have problems with your device:\n"
-+                               "1) see permissive attribute in sysfs\n"
-+                               "2) report problems to the xen-devel "
-+                               "mailing list along with details of your "
-+                               "device obtained from lspci.\n", offset, size);
++
++              }
++              
++              /* Copy the data to required end destination */
++              if (ef_vnic_copy_to_skb(vnic, skb, buf, len) != 0) {
++                      /*
++                       * No space in the skb - suggests > MTU packet
++                       * received
++                       */
++                      EPRINTK("%s: Rx packet too large (%d)\n",
++                              __FUNCTION__, len);
++                      netfront_accel_vi_post_rx_or_free(vnic, (u16)id, buf);
++                      discard_jumbo_state(vnic);
++                      return 0;
++              }
++              
++              /* Put the buffer back in the DMA queue. */
++              netfront_accel_vi_post_rx_or_free(vnic, (u16)id, buf);
++
++              if (cont) {
++                      vnic->jumbo_state.skb = skb;
++
++                      return 0;
++              } else {
++                      /* Track number of rx fastpath packets */
++                      vnic->netdev_stats.fastpath_rx_pkts++;
++                      vnic->netdev_stats.fastpath_rx_bytes += len;
++
++                      netfront_accel_vi_rx_complete(vnic, skb);
++
++                      return 1;
++              }
++      } else {
++              BUG_ON(EF_EVENT_TYPE(*ev) != EF_EVENT_TYPE_RX_DISCARD);
++
++              if (EF_EVENT_RX_DISCARD_TYPE(*ev) 
++                  == EF_EVENT_RX_DISCARD_TRUNC) {
++                      DPRINTK("%s: " EF_EVENT_FMT 
++                              " buffer %d FRM_TRUNC q_id %d\n",
++                              __FUNCTION__, EF_EVENT_PRI_ARG(*ev), id,
++                              EF_EVENT_RX_DISCARD_Q_ID(*ev) );
++                      NETFRONT_ACCEL_STATS_OP(++vnic->stats.fastpath_frm_trunc);
++              } else if (EF_EVENT_RX_DISCARD_TYPE(*ev) 
++                        == EF_EVENT_RX_DISCARD_OTHER) {
++                      DPRINTK("%s: " EF_EVENT_FMT 
++                              " buffer %d RX_DISCARD_OTHER q_id %d\n",
++                              __FUNCTION__, EF_EVENT_PRI_ARG(*ev), id,
++                              EF_EVENT_RX_DISCARD_Q_ID(*ev) );
++                      /*
++                       * Probably tail of packet for which error has
++                       * already been logged, so don't count in
++                       * stats
++                       */
++              } else {
++                      EPRINTK("%s: " EF_EVENT_FMT 
++                              " buffer %d rx discard type %d q_id %d\n",
++                              __FUNCTION__, EF_EVENT_PRI_ARG(*ev), id,
++                              EF_EVENT_RX_DISCARD_TYPE(*ev), 
++                              EF_EVENT_RX_DISCARD_Q_ID(*ev) );
++                      NETFRONT_ACCEL_STATS_OP(++vnic->stats.bad_event_count);
 +              }
 +      }
 +
-+      return pcibios_err_to_errno(err);
-+}
++      /* discard type drops through here */
 +
-+void pciback_config_free_dyn_fields(struct pci_dev *dev)
-+{
-+      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+      struct config_field_entry *cfg_entry, *t;
-+      struct config_field *field;
++bad_packet:
++      /* Release the socket buffer we already had */
++      discard_jumbo_state(vnic);
 +
-+      dev_dbg(&dev->dev,
-+              "free-ing dynamically allocated virtual configuration space fields\n");
++missing_head:
++      BUG_ON(vnic->jumbo_state.in_progress != 0);
++      BUG_ON(vnic->jumbo_state.skb != NULL);
 +
-+      list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
-+              field = cfg_entry->field;
++      if (id >= 0 && id < bufinfo->npages*NETFRONT_ACCEL_BUFS_PER_PAGE)
++              /* Put the buffer back in the DMA queue. */
++              netfront_accel_vi_post_rx_or_free(vnic, (u16)id, buf);
 +
-+              if (field->clean) {
-+                      field->clean(field);
++      vnic->netdev_stats.fastpath_rx_errors++;
 +
-+                      if (cfg_entry->data)
-+                              kfree(cfg_entry->data);
++      DPRINTK("%s experienced bad packet/missing fragment error: %d \n",
++              __FUNCTION__, ev->rx.flags);
 +
-+                      list_del(&cfg_entry->list);
-+                      kfree(cfg_entry);
-+              }
++      return 0;
++}
++
++
++static void netfront_accel_vi_not_busy(netfront_accel_vnic *vnic)
++{
++      struct netfront_info *np = ((struct netfront_info *)
++                                  netdev_priv(vnic->net_dev));
++      struct sk_buff *skb;
++      int handled;
++      unsigned long flags;
++      
++      /*
++       * TODO if we could safely check tx_skb == NULL and return
++       * early without taking the lock, that would obviously help
++       * performance
++       */
++
++      /* Take the netfront lock which protects tx_skb. */
++      spin_lock_irqsave(&np->tx_lock, flags);
++      if (vnic->tx_skb != NULL) {
++              DPRINTK("%s trying to send spare buffer\n", __FUNCTION__);
++              
++              skb = vnic->tx_skb;
++              vnic->tx_skb = NULL;
++
++              spin_unlock_irqrestore(&np->tx_lock, flags);
 +
++              handled = netfront_accel_vi_tx_post(vnic, skb);
++              
++              spin_lock_irqsave(&np->tx_lock, flags);
++
++              if (handled != NETFRONT_ACCEL_STATUS_BUSY) {
++                      DPRINTK("%s restarting tx\n", __FUNCTION__);
++                      if (netfront_check_queue_ready(vnic->net_dev)) {
++                              netif_wake_queue(vnic->net_dev);
++                              NETFRONT_ACCEL_STATS_OP
++                                      (vnic->stats.queue_wakes++);
++                      }
++              } else {
++                      vnic->tx_skb = skb;
++              }
++              
++              /*
++               * Should never get a CANT, as it checks that before
++               * deciding it was BUSY first time round 
++               */
++              BUG_ON(handled == NETFRONT_ACCEL_STATUS_CANT);
 +      }
++      spin_unlock_irqrestore(&np->tx_lock, flags);
 +}
 +
-+void pciback_config_reset_dev(struct pci_dev *dev)
++
++static void netfront_accel_vi_tx_complete(netfront_accel_vnic *vnic, 
++                                        struct netfront_accel_tso_buffer *tso_buf,
++                                        int is_last)
 +{
-+      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+      struct config_field_entry *cfg_entry;
-+      struct config_field *field;
++      struct netfront_accel_tso_buffer *next;
 +
-+      dev_dbg(&dev->dev, "resetting virtual configuration space\n");
++      /* 
++       * We get a single completion for every call to
++       * ef_vi_transmitv so handle any other buffers which are part
++       * of the same packet 
++       */
++      while (tso_buf != NULL) {
++              if (tso_buf->buf->skb != NULL) {
++                      dev_kfree_skb_any(tso_buf->buf->skb);
++                      tso_buf->buf->skb = NULL;
++              }
 +
-+      list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
-+              field = cfg_entry->field;
++              next = tso_buf->next;
 +
-+              if (field->reset)
-+                      field->reset(dev, OFFSET(cfg_entry), cfg_entry->data);
++              netfront_accel_buf_put(vnic->tx_bufs, tso_buf->buf->buf_id);
++
++              tso_buf = next;
 +      }
++
++      /*
++       * If this was the last one in the batch, we try and send any
++       * pending tx_skb. There should now be buffers and
++       * descriptors
++       */
++      if (is_last)
++              netfront_accel_vi_not_busy(vnic);
 +}
 +
-+void pciback_config_free_dev(struct pci_dev *dev)
++
++static void netfront_accel_vi_poll_process_tx(netfront_accel_vnic *vnic,
++                                            ef_event *ev)
 +{
-+      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+      struct config_field_entry *cfg_entry, *t;
-+      struct config_field *field;
++      struct netfront_accel_pkt_desc *buf;
++      struct netfront_accel_tso_buffer *tso_buf;
++      ef_request_id ids[EF_VI_TRANSMIT_BATCH];
++      int i, n_ids;
++      unsigned long flags;
 +
-+      dev_dbg(&dev->dev, "free-ing virtual configuration space fields\n");
++      /* Get the request ids for this tx completion event. */
++      n_ids = ef_vi_transmit_unbundle(&vnic->vi, ev, ids);
 +
-+      list_for_each_entry_safe(cfg_entry, t, &dev_data->config_fields, list) {
-+              list_del(&cfg_entry->list);
++      /* Take the tx buffer spin lock and hold for the duration */
++      spin_lock_irqsave(&vnic->tx_lock, flags);
 +
-+              field = cfg_entry->field;
++      for (i = 0; i < n_ids; ++i) {
++              VPRINTK("Tx packet %d complete\n", ids[i]);
++              buf = netfront_accel_buf_find(vnic->tx_bufs, ids[i]);
++              NETFRONT_ACCEL_STATS_OP(vnic->stats.fastpath_tx_completions++);
 +
-+              if (field->release)
-+                      field->release(dev, OFFSET(cfg_entry), cfg_entry->data);
++              tso_buf = (struct netfront_accel_tso_buffer *)
++                      (buf->pkt_kva + NETFRONT_ACCEL_TX_BUF_LENGTH);
++              BUG_ON(tso_buf->buf != buf);
 +
-+              kfree(cfg_entry);
++              netfront_accel_vi_tx_complete(vnic, tso_buf, i == (n_ids-1));
 +      }
++
++      spin_unlock_irqrestore(&vnic->tx_lock, flags);
 +}
 +
-+int pciback_config_add_field_offset(struct pci_dev *dev,
-+                                  struct config_field *field,
-+                                  unsigned int base_offset)
-+{
-+      int err = 0;
-+      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+      struct config_field_entry *cfg_entry;
-+      void *tmp;
 +
-+      cfg_entry = kmalloc(sizeof(*cfg_entry), GFP_KERNEL);
-+      if (!cfg_entry) {
-+              err = -ENOMEM;
-+              goto out;
-+      }
++int netfront_accel_vi_poll(netfront_accel_vnic *vnic, int rx_packets)
++{
++      ef_event ev[ACCEL_VI_POLL_EVENTS];
++      int rx_remain = rx_packets, rc, events, i;
++#if NETFRONT_ACCEL_STATS
++      int n_evs_polled = 0, rx_evs_polled = 0, tx_evs_polled = 0;
++#endif
++      BUG_ON(rx_packets <= 0);
 +
-+      cfg_entry->data = NULL;
-+      cfg_entry->field = field;
-+      cfg_entry->base_offset = base_offset;
++      events = ef_eventq_poll(&vnic->vi, ev, 
++                              min(rx_remain, ACCEL_VI_POLL_EVENTS));
++      i = 0;
++      NETFRONT_ACCEL_STATS_OP(n_evs_polled += events);
 +
-+      /* silently ignore duplicate fields */
-+      err = pciback_field_is_dup(dev,OFFSET(cfg_entry));
-+      if (err)
-+              goto out;
++      VPRINTK("%s: %d events\n", __FUNCTION__, events);
 +
-+      if (field->init) {
-+              tmp = field->init(dev, OFFSET(cfg_entry));
++      /* Loop over each event */
++      while (events) {
++              VPRINTK("%s: Event "EF_EVENT_FMT", index %lu\n", __FUNCTION__, 
++                      EF_EVENT_PRI_ARG(ev[i]),        
++                      (unsigned long)(vnic->vi.evq_state->evq_ptr));
 +
-+              if (IS_ERR(tmp)) {
-+                      err = PTR_ERR(tmp);
-+                      goto out;
++              if ((EF_EVENT_TYPE(ev[i]) == EF_EVENT_TYPE_RX) ||
++                  (EF_EVENT_TYPE(ev[i]) == EF_EVENT_TYPE_RX_DISCARD)) {
++                      rc = netfront_accel_vi_poll_process_rx(vnic, &ev[i]);
++                      rx_remain -= rc;
++                      BUG_ON(rx_remain < 0);
++                      NETFRONT_ACCEL_STATS_OP(rx_evs_polled++);
++              } else if (EF_EVENT_TYPE(ev[i]) == EF_EVENT_TYPE_TX) {
++                      netfront_accel_vi_poll_process_tx(vnic, &ev[i]);
++                      NETFRONT_ACCEL_STATS_OP(tx_evs_polled++);
++              } else if (EF_EVENT_TYPE(ev[i]) == 
++                         EF_EVENT_TYPE_RX_NO_DESC_TRUNC) {
++                      DPRINTK("%s: RX_NO_DESC_TRUNC " EF_EVENT_FMT "\n",
++                              __FUNCTION__, EF_EVENT_PRI_ARG(ev[i]));
++                      discard_jumbo_state(vnic);
++                      NETFRONT_ACCEL_STATS_OP(vnic->stats.rx_no_desc_trunc++);
++              } else {
++                      EPRINTK("Unexpected event " EF_EVENT_FMT "\n", 
++                              EF_EVENT_PRI_ARG(ev[i]));
++                      NETFRONT_ACCEL_STATS_OP(vnic->stats.bad_event_count++);
 +              }
 +
-+              cfg_entry->data = tmp;
-+      }
++              i++;
 +
-+      dev_dbg(&dev->dev, "added config field at offset 0x%02x\n",
-+              OFFSET(cfg_entry));
-+      list_add_tail(&cfg_entry->list, &dev_data->config_fields);
++              /* Carry on round the loop if more events and more space */
++              if (i == events) {
++                      if (rx_remain == 0)
++                              break;
 +
-+      out:
-+      if (err)
-+              kfree(cfg_entry);
++                      events = ef_eventq_poll(&vnic->vi, ev, 
++                                              min(rx_remain, 
++                                                  ACCEL_VI_POLL_EVENTS));
++                      i = 0;
++                      NETFRONT_ACCEL_STATS_OP(n_evs_polled += events);
++              }
++      }
++      
++#if NETFRONT_ACCEL_STATS
++      vnic->stats.event_count += n_evs_polled;
++      vnic->stats.event_count_since_irq += n_evs_polled;
++      if (n_evs_polled > vnic->stats.events_per_poll_max)
++              vnic->stats.events_per_poll_max = n_evs_polled;
++      if (rx_evs_polled > vnic->stats.events_per_poll_rx_max)
++              vnic->stats.events_per_poll_rx_max = rx_evs_polled;
++      if (tx_evs_polled > vnic->stats.events_per_poll_tx_max)
++              vnic->stats.events_per_poll_tx_max = tx_evs_polled;
++#endif
 +
-+      return err;
++      return rx_packets - rx_remain;
 +}
 +
-+/* This sets up the device's virtual configuration space to keep track of 
-+ * certain registers (like the base address registers (BARs) so that we can
-+ * keep the client from manipulating them directly.
-+ */
-+int pciback_config_init_dev(struct pci_dev *dev)
++
++int netfront_accel_vi_enable_interrupts(netfront_accel_vnic *vnic)
 +{
-+      int err = 0;
-+      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
++      u32 sw_evq_ptr;
 +
-+      dev_dbg(&dev->dev, "initializing virtual configuration space\n");
++      VPRINTK("%s: checking for event on %p\n", __FUNCTION__, &vnic->vi.evq_state);
 +
-+      INIT_LIST_HEAD(&dev_data->config_fields);
++      BUG_ON(vnic == NULL);
++      BUG_ON(vnic->vi.evq_state == NULL);
 +
-+      err = pciback_config_header_add_fields(dev);
-+      if (err)
-+              goto out;
++      /* Do a quick check for an event. */
++      if (ef_eventq_has_event(&vnic->vi)) {
++              VPRINTK("%s: found event\n",  __FUNCTION__);
++              return 0;
++      }
 +
-+      err = pciback_config_capability_add_fields(dev);
-+      if (err)
-+              goto out;
++      VPRINTK("evq_ptr=0x%08x  evq_mask=0x%08x\n",
++              vnic->evq_state.evq_ptr, vnic->vi.evq_mask);
++  
++      /* Request a wakeup from the hardware. */
++      sw_evq_ptr = vnic->evq_state.evq_ptr & vnic->vi.evq_mask;
 +
-+      err = pciback_config_quirks_init(dev);
++      BUG_ON(vnic->hw.falcon.evq_rptr == NULL);
 +
-+      out:
-+      return err;
-+}
++      VPRINTK("Requesting wakeup at 0x%08x, rptr %p\n", sw_evq_ptr,
++              vnic->hw.falcon.evq_rptr);
++      *(volatile u32 *)(vnic->hw.falcon.evq_rptr) = (sw_evq_ptr >> 3);
 +
-+int pciback_config_init(void)
-+{
-+      return pciback_config_capability_init();
++      return 1;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/conf_space_capability.c linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability.c
---- linux-2.6.18/drivers/xen/pciback/conf_space_capability.c   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability.c    2007-12-23 11:15:34.061269291 +0100
-@@ -0,0 +1,71 @@
-+/*
-+ * PCI Backend - Handles the virtual fields found on the capability lists
-+ *               in the configuration space.
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/accel_xenbus.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/accel_xenbus.c        2008-05-19 00:33:48.650950417 +0300
+@@ -0,0 +1,776 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
 + *
-+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <linux/kernel.h>
-+#include <linux/pci.h>
-+#include "pciback.h"
-+#include "conf_space.h"
-+#include "conf_space_capability.h"
++#include <linux/stddef.h>
++#include <linux/errno.h>
 +
-+static LIST_HEAD(capabilities);
++#include <xen/xenbus.h>
++#include <xen/evtchn.h>
++#include <xen/gnttab.h>
 +
-+static struct config_field caplist_header[] = {
-+      {
-+       .offset    = PCI_CAP_LIST_ID,
-+       .size      = 2, /* encompass PCI_CAP_LIST_ID & PCI_CAP_LIST_NEXT */
-+       .u.w.read  = pciback_read_config_word,
-+       .u.w.write = NULL,
-+      },
-+      {
-+       .size = 0,
-+      },
-+};
++#include "accel.h"
++#include "accel_util.h"
++#include "accel_msg_iface.h"
++#include "accel_bufs.h"
++#include "accel_ssr.h"
++/* drivers/xen/netfront/netfront.h */
++#include "netfront.h"
 +
-+static inline void register_capability(struct pciback_config_capability *cap)
++void netfront_accel_set_closing(netfront_accel_vnic *vnic) 
 +{
-+      list_add_tail(&cap->cap_list, &capabilities);
++
++      vnic->frontend_state = XenbusStateClosing;
++      net_accel_update_state(vnic->dev, XenbusStateClosing);
 +}
++      
 +
-+int pciback_config_capability_add_fields(struct pci_dev *dev)
++static void mac_address_change(struct xenbus_watch *watch,
++                             const char **vec, unsigned int len)
 +{
-+      int err = 0;
-+      struct pciback_config_capability *cap;
-+      int cap_offset;
++      netfront_accel_vnic *vnic;
++      struct xenbus_device *dev;
++      int rc;
 +
-+      list_for_each_entry(cap, &capabilities, cap_list) {
-+              cap_offset = pci_find_capability(dev, cap->capability);
-+              if (cap_offset) {
-+                      dev_dbg(&dev->dev, "Found capability 0x%x at 0x%x\n",
-+                              cap->capability, cap_offset);
++      DPRINTK("%s\n", __FUNCTION__);
++      
++      vnic = container_of(watch, netfront_accel_vnic, 
++                              mac_address_watch);
++      dev = vnic->dev;
 +
-+                      err = pciback_config_add_fields_offset(dev,
-+                                                             caplist_header,
-+                                                             cap_offset);
-+                      if (err)
-+                              goto out;
-+                      err = pciback_config_add_fields_offset(dev,
-+                                                             cap->fields,
-+                                                             cap_offset);
-+                      if (err)
-+                              goto out;
-+              }
-+      }
++      rc = net_accel_xen_net_read_mac(dev, vnic->mac);
 +
-+      out:
-+      return err;
++      if (rc != 0)
++              EPRINTK("%s: failed to read mac (%d)\n", __FUNCTION__, rc);
 +}
 +
-+extern struct pciback_config_capability pciback_config_capability_vpd;
-+extern struct pciback_config_capability pciback_config_capability_pm;
 +
-+int pciback_config_capability_init(void)
++static int setup_mac_address_watch(struct xenbus_device *dev,
++                                 netfront_accel_vnic *vnic)
 +{
-+      register_capability(&pciback_config_capability_vpd);
-+      register_capability(&pciback_config_capability_pm);
++      int err;
++
++      DPRINTK("Setting watch on %s/%s\n", dev->nodename, "mac");
++
++      err = xenbus_watch_path2(dev, dev->nodename, "mac", 
++                               &vnic->mac_address_watch, 
++                               mac_address_change);
++      if (err) {
++              EPRINTK("%s: Failed to register xenbus watch: %d\n",
++                      __FUNCTION__, err);
++              goto fail;
++      }
 +
 +      return 0;
++ fail:
++      vnic->mac_address_watch.node = NULL;
++      return err;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/conf_space_capability.h linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability.h
---- linux-2.6.18/drivers/xen/pciback/conf_space_capability.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability.h    2007-12-23 11:15:34.061269291 +0100
-@@ -0,0 +1,23 @@
-+/*
-+ * PCI Backend - Data structures for special overlays for structures on
-+ *               the capability list.
-+ *
-+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ */
-+
-+#ifndef __PCIBACK_CONFIG_CAPABILITY_H__
-+#define __PCIBACK_CONFIG_CAPABILITY_H__
 +
-+#include <linux/pci.h>
-+#include <linux/list.h>
 +
-+struct pciback_config_capability {
-+      struct list_head cap_list;
++/* Grant access to some pages and publish through xenbus */
++static int make_named_grant(struct xenbus_device *dev, void *page, 
++                          const char *name, grant_ref_t *gnt_ref)
++{
++      struct xenbus_transaction tr;
++      int err;
++      grant_ref_t gnt;
 +
-+      int capability;
++      gnt = net_accel_grant_page(dev, virt_to_mfn(page), 0);
++      if (gnt < 0)
++              return gnt;
 +
-+      /* If the device has the capability found above, add these fields */
-+      struct config_field *fields;
-+};
++      do {
++              err = xenbus_transaction_start(&tr);
++              if (err != 0) {
++                      EPRINTK("%s: transaction start failed %d\n",
++                              __FUNCTION__, err);
++                      return err;
++              }
++              err = xenbus_printf(tr, dev->nodename, name, "%d", gnt);
++              if (err != 0) {
++                      EPRINTK("%s: xenbus_printf failed %d\n", __FUNCTION__,
++                              err);
++                      xenbus_transaction_end(tr, 1);
++                      return err;
++              }
++              err = xenbus_transaction_end(tr, 0);
++      } while (err == -EAGAIN);
++      
++      if (err != 0) {
++              EPRINTK("%s: transaction end failed %d\n", __FUNCTION__, err);
++              return err;
++      }
++      
++      *gnt_ref = gnt;
 +
-+#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/conf_space_capability_pm.c linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability_pm.c
---- linux-2.6.18/drivers/xen/pciback/conf_space_capability_pm.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability_pm.c 2007-12-23 11:15:34.061269291 +0100
-@@ -0,0 +1,128 @@
-+/*
-+ * PCI Backend - Configuration space overlay for power management
-+ *
-+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ */
++      return 0;
++}
 +
-+#include <linux/pci.h>
-+#include "conf_space.h"
-+#include "conf_space_capability.h"
 +
-+static int pm_caps_read(struct pci_dev *dev, int offset, u16 *value,
-+                      void *data)
++static int remove_named_grant(struct xenbus_device *dev,
++                            const char *name, grant_ref_t gnt_ref)
 +{
++      struct xenbus_transaction tr;
 +      int err;
-+      u16 real_value;
 +
-+      err = pci_read_config_word(dev, offset, &real_value);
-+      if (err)
-+              goto out;
++      net_accel_ungrant_page(gnt_ref);
 +
-+      *value = real_value & ~PCI_PM_CAP_PME_MASK;
++      do {
++              err = xenbus_transaction_start(&tr);
++              if (err != 0) {
++                      EPRINTK("%s: transaction start failed %d\n",
++                              __FUNCTION__, err);
++                      return err;
++              }
++              err = xenbus_rm(tr, dev->nodename, name);
++              if (err != 0) {
++                      EPRINTK("%s: xenbus_rm failed %d\n", __FUNCTION__,
++                              err);
++                      xenbus_transaction_end(tr, 1);
++                      return err;
++              }
++              err = xenbus_transaction_end(tr, 0);
++      } while (err == -EAGAIN);
++      
++      if (err != 0) {
++              EPRINTK("%s: transaction end failed %d\n", __FUNCTION__, err);
++              return err;
++      }
 +
-+      out:
-+      return err;
++      return 0;
 +}
 +
-+/* PM_OK_BITS specifies the bits that the driver domain is allowed to change.
-+ * Can't allow driver domain to enable PMEs - they're shared */
-+#define PM_OK_BITS (PCI_PM_CTRL_PME_STATUS|PCI_PM_CTRL_DATA_SEL_MASK)
 +
-+static int pm_ctrl_write(struct pci_dev *dev, int offset, u16 new_value,
-+                       void *data)
++static 
++netfront_accel_vnic *netfront_accel_vnic_ctor(struct net_device *net_dev,
++                                            struct xenbus_device *dev)
 +{
++      struct netfront_info *np =
++              (struct netfront_info *)netdev_priv(net_dev);
++      netfront_accel_vnic *vnic;
 +      int err;
-+      u16 old_value;
-+      pci_power_t new_state, old_state;
-+
-+      err = pci_read_config_word(dev, offset, &old_value);
-+      if (err)
-+              goto out;
 +
-+      old_state = (pci_power_t)(old_value & PCI_PM_CTRL_STATE_MASK);
-+      new_state = (pci_power_t)(new_value & PCI_PM_CTRL_STATE_MASK);
++      /*
++       * A bug in earlier versions of Xen accel plugin system meant
++       * you could be probed twice for the same device on suspend
++       * cancel.  Be tolerant of that.
++       */ 
++      if (np->accel_priv != NULL)
++              return ERR_PTR(-EALREADY);
 +
-+      new_value &= PM_OK_BITS;
-+      if ((old_value & PM_OK_BITS) != new_value) {
-+              new_value = (old_value & ~PM_OK_BITS) | new_value;
-+              err = pci_write_config_word(dev, offset, new_value);
-+              if (err)
-+                      goto out;
++      /* Alloc mem for state */
++      vnic = kzalloc(sizeof(netfront_accel_vnic), GFP_KERNEL);
++      if (vnic == NULL) {
++              EPRINTK("%s: no memory for vnic state\n", __FUNCTION__);
++              return ERR_PTR(-ENOMEM);
 +      }
 +
-+      /* Let pci core handle the power management change */
-+      dev_dbg(&dev->dev, "set power state to %x\n", new_state);
-+      err = pci_set_power_state(dev, new_state);
-+      if (err) {
-+              err = PCIBIOS_SET_FAILED;
-+              goto out;
-+      }
++      spin_lock_init(&vnic->tx_lock);
 +
-+      /*
-+       * Device may lose PCI config info on D3->D0 transition. This
-+       * is a problem for some guests which will not reset BARs. Even
-+       * those that have a go will be foiled by our BAR-write handler
-+       * which will discard the write! Since Linux won't re-init
-+       * the config space automatically in all cases, we do it here.
-+       * Future: Should we re-initialise all first 64 bytes of config space?
-+       */
-+      if (new_state == PCI_D0 &&
-+          (old_state == PCI_D3hot || old_state == PCI_D3cold) &&
-+          !(old_value & PCI_PM_CTRL_NO_SOFT_RESET))
-+              pci_restore_bars(dev);
++      mutex_init(&vnic->vnic_mutex);
++      mutex_lock(&vnic->vnic_mutex);
 +
-+ out:
-+      return err;
-+}
++      /* Store so state can be retrieved from device */
++      BUG_ON(np->accel_priv != NULL);
++      np->accel_priv = vnic;
++      vnic->dev = dev;
++      vnic->net_dev = net_dev;
++      spin_lock_init(&vnic->irq_enabled_lock);
++      netfront_accel_ssr_init(&vnic->ssr_state);
 +
-+/* Ensure PMEs are disabled */
-+static void *pm_ctrl_init(struct pci_dev *dev, int offset)
-+{
-+      int err;
-+      u16 value;
++      init_waitqueue_head(&vnic->state_wait_queue);
++      vnic->backend_state = XenbusStateUnknown;
++      vnic->frontend_state = XenbusStateClosed;
++      vnic->removing = 0;
++      vnic->domU_state_is_setup = 0;
++      vnic->dom0_state_is_setup = 0;
++      vnic->poll_enabled = 0;
++      vnic->tx_enabled = 0;
++      vnic->tx_skb = NULL;
 +
-+      err = pci_read_config_word(dev, offset, &value);
-+      if (err)
-+              goto out;
++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
++      INIT_WORK(&vnic->msg_from_bend, netfront_accel_msg_from_bend);
++#else
++      INIT_WORK(&vnic->msg_from_bend, netfront_accel_msg_from_bend, vnic);
++#endif
 +
-+      if (value & PCI_PM_CTRL_PME_ENABLE) {
-+              value &= ~PCI_PM_CTRL_PME_ENABLE;
-+              err = pci_write_config_word(dev, offset, value);
-+      }
++      netfront_accel_debugfs_create(vnic);
 +
-+      out:
-+      return ERR_PTR(err);
-+}
++      mutex_unlock(&vnic->vnic_mutex);
 +
-+static struct config_field caplist_pm[] = {
-+      {
-+              .offset     = PCI_PM_PMC,
-+              .size       = 2,
-+              .u.w.read   = pm_caps_read,
-+      },
-+      {
-+              .offset     = PCI_PM_CTRL,
-+              .size       = 2,
-+              .init       = pm_ctrl_init,
-+              .u.w.read   = pciback_read_config_word,
-+              .u.w.write  = pm_ctrl_write,
-+      },
-+      {
-+              .offset     = PCI_PM_PPB_EXTENSIONS,
-+              .size       = 1,
-+              .u.b.read   = pciback_read_config_byte,
-+      },
-+      {
-+              .offset     = PCI_PM_DATA_REGISTER,
-+              .size       = 1,
-+              .u.b.read   = pciback_read_config_byte,
-+      },
-+      {
-+              .size = 0,
-+      },
-+};
++      err = net_accel_xen_net_read_mac(dev, vnic->mac);
++      if (err) 
++              goto fail_mac;
 +
-+struct pciback_config_capability pciback_config_capability_pm = {
-+      .capability = PCI_CAP_ID_PM,
-+      .fields = caplist_pm,
-+};
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/conf_space_capability_vpd.c linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability_vpd.c
---- linux-2.6.18/drivers/xen/pciback/conf_space_capability_vpd.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_capability_vpd.c        2007-12-23 11:15:34.061269291 +0100
-@@ -0,0 +1,42 @@
-+/*
-+ * PCI Backend - Configuration space overlay for Vital Product Data
-+ *
-+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ */
++      /* Setup a watch on the frontend's MAC address */
++      err = setup_mac_address_watch(dev, vnic);
++      if (err)
++              goto fail_mac;
 +
-+#include <linux/pci.h>
-+#include "conf_space.h"
-+#include "conf_space_capability.h"
++      return vnic;
 +
-+static int vpd_address_write(struct pci_dev *dev, int offset, u16 value,
-+                           void *data)
-+{
-+      /* Disallow writes to the vital product data */
-+      if (value & PCI_VPD_ADDR_F)
-+              return PCIBIOS_SET_FAILED;
-+      else
-+              return pci_write_config_word(dev, offset, value);
-+}
++fail_mac:
 +
-+static struct config_field caplist_vpd[] = {
-+      {
-+       .offset    = PCI_VPD_ADDR,
-+       .size      = 2,
-+       .u.w.read  = pciback_read_config_word,
-+       .u.w.write = vpd_address_write,
-+       },
-+      {
-+       .offset     = PCI_VPD_DATA,
-+       .size       = 4,
-+       .u.dw.read  = pciback_read_config_dword,
-+       .u.dw.write = NULL,
-+       },
-+      {
-+       .size = 0,
-+       },
-+};
-+ 
-+struct pciback_config_capability pciback_config_capability_vpd = {
-+      .capability = PCI_CAP_ID_VPD,
-+      .fields = caplist_vpd,
-+};
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/conf_space.h linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space.h
---- linux-2.6.18/drivers/xen/pciback/conf_space.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space.h       2007-12-23 11:15:34.061269291 +0100
-@@ -0,0 +1,126 @@
-+/*
-+ * PCI Backend - Common data structures for overriding the configuration space
-+ *
-+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ */
++      mutex_lock(&vnic->vnic_mutex);
 +
-+#ifndef __XEN_PCIBACK_CONF_SPACE_H__
-+#define __XEN_PCIBACK_CONF_SPACE_H__
++      netfront_accel_debugfs_remove(vnic);
 +
-+#include <linux/list.h>
-+#include <linux/err.h>
++      netfront_accel_ssr_fini(vnic, &vnic->ssr_state);
 +
-+/* conf_field_init can return an errno in a ptr with ERR_PTR() */
-+typedef void *(*conf_field_init) (struct pci_dev * dev, int offset);
-+typedef void (*conf_field_reset) (struct pci_dev * dev, int offset, void *data);
-+typedef void (*conf_field_free) (struct pci_dev * dev, int offset, void *data);
++      EPRINTK_ON(vnic->tx_skb != NULL);
 +
-+typedef int (*conf_dword_write) (struct pci_dev * dev, int offset, u32 value,
-+                               void *data);
-+typedef int (*conf_word_write) (struct pci_dev * dev, int offset, u16 value,
-+                              void *data);
-+typedef int (*conf_byte_write) (struct pci_dev * dev, int offset, u8 value,
-+                              void *data);
-+typedef int (*conf_dword_read) (struct pci_dev * dev, int offset, u32 * value,
-+                              void *data);
-+typedef int (*conf_word_read) (struct pci_dev * dev, int offset, u16 * value,
-+                             void *data);
-+typedef int (*conf_byte_read) (struct pci_dev * dev, int offset, u8 * value,
-+                             void *data);
++      vnic->frontend_state = XenbusStateUnknown;
++      net_accel_update_state(dev, XenbusStateUnknown);
 +
-+/* These are the fields within the configuration space which we
-+ * are interested in intercepting reads/writes to and changing their
-+ * values.
-+ */
-+struct config_field {
-+      unsigned int offset;
-+      unsigned int size;
-+      unsigned int mask;
-+      conf_field_init init;
-+      conf_field_reset reset;
-+      conf_field_free release;
-+      void (*clean) (struct config_field * field);
-+      union {
-+              struct {
-+                      conf_dword_write write;
-+                      conf_dword_read read;
-+              } dw;
-+              struct {
-+                      conf_word_write write;
-+                      conf_word_read read;
-+              } w;
-+              struct {
-+                      conf_byte_write write;
-+                      conf_byte_read read;
-+              } b;
-+      } u;
-+      struct list_head list;
-+};
++      mutex_unlock(&vnic->vnic_mutex);
 +
-+struct config_field_entry {
-+      struct list_head list;
-+      struct config_field *field;
-+      unsigned int base_offset;
-+      void *data;
-+};
++      np->accel_priv = NULL;
++      kfree(vnic);
 +
-+#define OFFSET(cfg_entry) ((cfg_entry)->base_offset+(cfg_entry)->field->offset)
++      return ERR_PTR(err);
++}
 +
-+/* Add fields to a device - the add_fields macro expects to get a pointer to
-+ * the first entry in an array (of which the ending is marked by size==0)
-+ */
-+int pciback_config_add_field_offset(struct pci_dev *dev,
-+                                  struct config_field *field,
-+                                  unsigned int offset);
 +
-+static inline int pciback_config_add_field(struct pci_dev *dev,
-+                                         struct config_field *field)
++static void netfront_accel_vnic_dtor(netfront_accel_vnic *vnic)
 +{
-+      return pciback_config_add_field_offset(dev, field, 0);
-+}
++      struct net_device *net_dev = vnic->net_dev;
++      struct netfront_info *np = 
++              (struct netfront_info *)netdev_priv(net_dev);
 +
-+static inline int pciback_config_add_fields(struct pci_dev *dev,
-+                                          struct config_field *field)
-+{
-+      int i, err = 0;
-+      for (i = 0; field[i].size != 0; i++) {
-+              err = pciback_config_add_field(dev, &field[i]);
-+              if (err)
-+                      break;
-+      }
-+      return err;
-+}
++      /*
++       * Now we don't hold the lock any more it is safe to remove
++       * this watch and synchonrise with the completion of
++       * watches
++       */
++      DPRINTK("%s: unregistering xenbus mac watch\n", __FUNCTION__);
++      unregister_xenbus_watch(&vnic->mac_address_watch);
++      kfree(vnic->mac_address_watch.node);
 +
-+static inline int pciback_config_add_fields_offset(struct pci_dev *dev,
-+                                                 struct config_field *field,
-+                                                 unsigned int offset)
-+{
-+      int i, err = 0;
-+      for (i = 0; field[i].size != 0; i++) {
-+              err = pciback_config_add_field_offset(dev, &field[i], offset);
-+              if (err)
-+                      break;
-+      }
-+      return err;
-+}
++      flush_workqueue(netfront_accel_workqueue);
 +
-+/* Read/Write the real configuration space */
-+int pciback_read_config_byte(struct pci_dev *dev, int offset, u8 * value,
-+                           void *data);
-+int pciback_read_config_word(struct pci_dev *dev, int offset, u16 * value,
-+                           void *data);
-+int pciback_read_config_dword(struct pci_dev *dev, int offset, u32 * value,
-+                            void *data);
-+int pciback_write_config_byte(struct pci_dev *dev, int offset, u8 value,
-+                            void *data);
-+int pciback_write_config_word(struct pci_dev *dev, int offset, u16 value,
-+                            void *data);
-+int pciback_write_config_dword(struct pci_dev *dev, int offset, u32 value,
-+                             void *data);
++      mutex_lock(&vnic->vnic_mutex);
 +
-+int pciback_config_capability_init(void);
++      netfront_accel_debugfs_remove(vnic);
 +
-+int pciback_config_header_add_fields(struct pci_dev *dev);
-+int pciback_config_capability_add_fields(struct pci_dev *dev);
++      netfront_accel_ssr_fini(vnic, &vnic->ssr_state);
 +
-+#endif                                /* __XEN_PCIBACK_CONF_SPACE_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/conf_space_header.c linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_header.c
---- linux-2.6.18/drivers/xen/pciback/conf_space_header.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_header.c        2007-12-23 11:15:34.064602797 +0100
-@@ -0,0 +1,323 @@
-+/*
-+ * PCI Backend - Handles the virtual fields in the configuration space headers.
-+ *
-+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ */
++      EPRINTK_ON(vnic->tx_skb != NULL);
 +
-+#include <linux/kernel.h>
-+#include <linux/pci.h>
-+#include "pciback.h"
-+#include "conf_space.h"
++      vnic->frontend_state = XenbusStateUnknown;
++      net_accel_update_state(vnic->dev, XenbusStateUnknown);
 +
-+struct pci_bar_info {
-+      u32 val;
-+      u32 len_val;
-+      int which;
-+};
++      mutex_unlock(&vnic->vnic_mutex);
 +
-+#define is_enable_cmd(value) ((value)&(PCI_COMMAND_MEMORY|PCI_COMMAND_IO))
-+#define is_master_cmd(value) ((value)&PCI_COMMAND_MASTER)
++      np->accel_priv = NULL;
++      kfree(vnic);
++}
 +
-+static int command_write(struct pci_dev *dev, int offset, u16 value, void *data)
++
++static int vnic_setup_domU_shared_state(struct xenbus_device *dev,
++                                      netfront_accel_vnic *vnic)
 +{
++      struct xenbus_transaction tr;
 +      int err;
++      int msgs_per_queue;
 +
-+      if (!dev->is_enabled && is_enable_cmd(value)) {
-+              if (unlikely(verbose_request))
-+                      printk(KERN_DEBUG "pciback: %s: enable\n",
-+                             pci_name(dev));
-+              err = pci_enable_device(dev);
-+              if (err)
-+                      return err;
-+      } else if (dev->is_enabled && !is_enable_cmd(value)) {
-+              if (unlikely(verbose_request))
-+                      printk(KERN_DEBUG "pciback: %s: disable\n",
-+                             pci_name(dev));
-+              pci_disable_device(dev);
-+      }
-+
-+      if (!dev->is_busmaster && is_master_cmd(value)) {
-+              if (unlikely(verbose_request))
-+                      printk(KERN_DEBUG "pciback: %s: set bus master\n",
-+                             pci_name(dev));
-+              pci_set_master(dev);
-+      }
 +
-+      if (value & PCI_COMMAND_INVALIDATE) {
-+              if (unlikely(verbose_request))
-+                      printk(KERN_DEBUG
-+                             "pciback: %s: enable memory-write-invalidate\n",
-+                             pci_name(dev));
-+              err = pci_set_mwi(dev);
-+              if (err) {
-+                      printk(KERN_WARNING
-+                             "pciback: %s: cannot enable memory-write-invalidate (%d)\n",
-+                             pci_name(dev), err);
-+                      value &= ~PCI_COMMAND_INVALIDATE;
-+              }
-+      }
++      DPRINTK("Setting up domU shared state.\n");
 +
-+      return pci_write_config_word(dev, offset, value);
-+}
++      msgs_per_queue = (PAGE_SIZE/2) / sizeof(struct net_accel_msg);
 +
-+static int rom_write(struct pci_dev *dev, int offset, u32 value, void *data)
-+{
-+      struct pci_bar_info *bar = data;
++      /* Allocate buffer state */
++      vnic->tx_bufs = netfront_accel_init_bufs(&vnic->tx_lock);
++      if (vnic->tx_bufs == NULL) {
++              err = -ENOMEM;
++              EPRINTK("%s: Failed to allocate tx buffers\n", __FUNCTION__);
++              goto fail_tx_bufs;
++      }
 +
-+      if (unlikely(!bar)) {
-+              printk(KERN_WARNING "pciback: driver data not found for %s\n",
-+                     pci_name(dev));
-+              return XEN_PCI_ERR_op_failed;
++      vnic->rx_bufs = netfront_accel_init_bufs(NULL);
++      if (vnic->rx_bufs == NULL) {
++              err = -ENOMEM;
++              EPRINTK("%s: Failed to allocate rx buffers\n", __FUNCTION__);
++              goto fail_rx_bufs;
 +      }
 +
-+      /* A write to obtain the length must happen as a 32-bit write.
-+       * This does not (yet) support writing individual bytes
++      /* 
++       * This allocates two pages, one for the shared page and one
++       * for the message queue.
 +       */
-+      if (value == ~PCI_ROM_ADDRESS_ENABLE)
-+              bar->which = 1;
-+      else {
-+              u32 tmpval;
-+              pci_read_config_dword(dev, offset, &tmpval);
-+              if (tmpval != bar->val && value == bar->val) {
-+                      /* Allow restoration of bar value. */
-+                      pci_write_config_dword(dev, offset, bar->val);
-+              }
-+              bar->which = 0;
++      vnic->shared_page = (struct net_accel_shared_page *)
++              __get_free_pages(GFP_KERNEL, 1);
++      if (vnic->shared_page == NULL) {
++              EPRINTK("%s: no memory for shared pages\n", __FUNCTION__);
++              err = -ENOMEM;
++              goto fail_shared_page;
 +      }
 +
-+      /* Do we need to support enabling/disabling the rom address here? */
++      net_accel_msg_init_queue
++              (&vnic->from_dom0, &vnic->shared_page->queue0, 
++               (struct net_accel_msg *)((u8*)vnic->shared_page + PAGE_SIZE),
++               msgs_per_queue);
 +
-+      return 0;
-+}
++      net_accel_msg_init_queue
++              (&vnic->to_dom0, &vnic->shared_page->queue1,
++               (struct net_accel_msg *)((u8*)vnic->shared_page +
++                                        (3 * PAGE_SIZE / 2)),
++               msgs_per_queue);
++      
++      vnic->msg_state = NETFRONT_ACCEL_MSG_NONE;
 +
-+/* For the BARs, only allow writes which write ~0 or
-+ * the correct resource information
-+ * (Needed for when the driver probes the resource usage)
-+ */
-+static int bar_write(struct pci_dev *dev, int offset, u32 value, void *data)
-+{
-+      struct pci_bar_info *bar = data;
++      err = make_named_grant(dev, vnic->shared_page, "accel-ctrl-page",
++                             &vnic->ctrl_page_gnt);
++      if (err) {
++              EPRINTK("couldn't make ctrl-page named grant\n");
++              goto fail_ctrl_page_grant;
++      }
 +
-+      if (unlikely(!bar)) {
-+              printk(KERN_WARNING "pciback: driver data not found for %s\n",
-+                     pci_name(dev));
-+              return XEN_PCI_ERR_op_failed;
++      err = make_named_grant(dev, (u8*)vnic->shared_page + PAGE_SIZE,
++                             "accel-msg-page", &vnic->msg_page_gnt);
++      if (err) {
++              EPRINTK("couldn't make msg-page named grant\n");
++              goto fail_msg_page_grant;
 +      }
 +
-+      /* A write to obtain the length must happen as a 32-bit write.
-+       * This does not (yet) support writing individual bytes
-+       */
-+      if (value == ~0)
-+              bar->which = 1;
-+      else {
-+              u32 tmpval;
-+              pci_read_config_dword(dev, offset, &tmpval);
-+              if (tmpval != bar->val && value == bar->val) {
-+                      /* Allow restoration of bar value. */
-+                      pci_write_config_dword(dev, offset, bar->val);
-+              }
-+              bar->which = 0;
++      /* Create xenbus msg event channel */
++      err = bind_listening_port_to_irqhandler
++              (dev->otherend_id, netfront_accel_msg_channel_irq_from_bend,
++               SA_SAMPLE_RANDOM, "vnicctrl", vnic);
++      if (err < 0) {
++              EPRINTK("Couldn't bind msg event channel\n");
++              goto fail_msg_irq;
++      }
++      vnic->msg_channel_irq = err;
++      vnic->msg_channel = irq_to_evtchn_port(vnic->msg_channel_irq);
++      
++      /* Create xenbus net event channel */
++      err = bind_listening_port_to_irqhandler
++              (dev->otherend_id, netfront_accel_net_channel_irq_from_bend,
++               SA_SAMPLE_RANDOM, "vnicfront", vnic);
++      if (err < 0) {
++              EPRINTK("Couldn't bind net event channel\n");
++              goto fail_net_irq;
 +      }
++      vnic->net_channel_irq = err;
++      vnic->net_channel = irq_to_evtchn_port(vnic->net_channel_irq);
++      /* Want to ensure we don't get interrupts before we're ready */
++      netfront_accel_disable_net_interrupts(vnic);
 +
-+      return 0;
-+}
++      DPRINTK("otherend %d has msg ch %u (%u) and net ch %u (%u)\n",
++              dev->otherend_id, vnic->msg_channel, vnic->msg_channel_irq, 
++              vnic->net_channel, vnic->net_channel_irq);
 +
-+static int bar_read(struct pci_dev *dev, int offset, u32 * value, void *data)
-+{
-+      struct pci_bar_info *bar = data;
++      do {
++              err = xenbus_transaction_start(&tr);
++              if (err != 0) {
++                      EPRINTK("%s: Transaction start failed %d\n",
++                              __FUNCTION__, err);
++                      goto fail_transaction;
++              }
 +
-+      if (unlikely(!bar)) {
-+              printk(KERN_WARNING "pciback: driver data not found for %s\n",
-+                     pci_name(dev));
-+              return XEN_PCI_ERR_op_failed;
-+      }
++              err = xenbus_printf(tr, dev->nodename, "accel-msg-channel",
++                                  "%u", vnic->msg_channel);
++              if (err != 0) {
++                      EPRINTK("%s: event channel xenbus write failed %d\n",
++                              __FUNCTION__, err);
++                      xenbus_transaction_end(tr, 1);
++                      goto fail_transaction;
++              }
 +
-+      *value = bar->which ? bar->len_val : bar->val;
++              err = xenbus_printf(tr, dev->nodename, "accel-net-channel",
++                                  "%u", vnic->net_channel);
++              if (err != 0) {
++                      EPRINTK("%s: net channel xenbus write failed %d\n",
++                              __FUNCTION__, err);
++                      xenbus_transaction_end(tr, 1);
++                      goto fail_transaction;
++              }
 +
-+      return 0;
-+}
++              err = xenbus_transaction_end(tr, 0);
++      } while (err == -EAGAIN);
 +
-+static inline void read_dev_bar(struct pci_dev *dev,
-+                              struct pci_bar_info *bar_info, int offset,
-+                              u32 len_mask)
-+{
-+      pci_read_config_dword(dev, offset, &bar_info->val);
-+      pci_write_config_dword(dev, offset, len_mask);
-+      pci_read_config_dword(dev, offset, &bar_info->len_val);
-+      pci_write_config_dword(dev, offset, bar_info->val);
-+}
++      if (err != 0) {
++              EPRINTK("%s: Transaction end failed %d\n", __FUNCTION__, err);
++              goto fail_transaction;
++      }
 +
-+static void *bar_init(struct pci_dev *dev, int offset)
-+{
-+      struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
++      DPRINTK("Completed setting up domU shared state\n");
 +
-+      if (!bar)
-+              return ERR_PTR(-ENOMEM);
++      return 0;
 +
-+      read_dev_bar(dev, bar, offset, ~0);
-+      bar->which = 0;
++fail_transaction:
 +
-+      return bar;
-+}
++      unbind_from_irqhandler(vnic->net_channel_irq, vnic);
++fail_net_irq:
 +
-+static void *rom_init(struct pci_dev *dev, int offset)
-+{
-+      struct pci_bar_info *bar = kmalloc(sizeof(*bar), GFP_KERNEL);
++      unbind_from_irqhandler(vnic->msg_channel_irq, vnic);
++fail_msg_irq:
 +
-+      if (!bar)
-+              return ERR_PTR(-ENOMEM);
++      remove_named_grant(dev, "accel-ctrl-page", vnic->ctrl_page_gnt);
++fail_msg_page_grant:
 +
-+      read_dev_bar(dev, bar, offset, ~PCI_ROM_ADDRESS_ENABLE);
-+      bar->which = 0;
++      remove_named_grant(dev, "accel-msg-page", vnic->msg_page_gnt);
++fail_ctrl_page_grant:
 +
-+      return bar;
-+}
++      free_pages((unsigned long)vnic->shared_page, 1);
++      vnic->shared_page = NULL;
++fail_shared_page:
 +
-+static void bar_reset(struct pci_dev *dev, int offset, void *data)
-+{
-+      struct pci_bar_info *bar = data;
++      netfront_accel_fini_bufs(vnic->rx_bufs);
++fail_rx_bufs:
 +
-+      bar->which = 0;
-+}
++      netfront_accel_fini_bufs(vnic->tx_bufs);
++fail_tx_bufs:
 +
-+static void bar_release(struct pci_dev *dev, int offset, void *data)
-+{
-+      kfree(data);
-+}
++      /* Undo the memory allocation created when we got the HELLO */
++      netfront_accel_free_buffer_mem(&vnic->bufpages,
++                                     vnic->rx_bufs,
++                                     vnic->tx_bufs);
 +
-+static int interrupt_read(struct pci_dev *dev, int offset, u8 * value,
-+                        void *data)
-+{
-+      *value = (u8) dev->irq;
++      DPRINTK("Failed to setup domU shared state with code %d\n", err);
 +
-+      return 0;
++      return err;
 +}
 +
-+static int bist_write(struct pci_dev *dev, int offset, u8 value, void *data)
++
++static void vnic_remove_domU_shared_state(struct xenbus_device *dev, 
++                                        netfront_accel_vnic *vnic)
 +{
-+      u8 cur_value;
-+      int err;
++      struct xenbus_transaction tr;
++      
++      /*
++       * Don't remove any watches because we currently hold the
++       * mutex and the watches take the mutex.
++       */
 +
-+      err = pci_read_config_byte(dev, offset, &cur_value);
-+      if (err)
-+              goto out;
++      DPRINTK("%s: removing event channel irq handlers %d %d\n",
++              __FUNCTION__, vnic->net_channel_irq, vnic->msg_channel_irq);
++      do {
++              if (xenbus_transaction_start(&tr) != 0)
++                      break;
++              xenbus_rm(tr, dev->nodename, "accel-msg-channel");
++              xenbus_rm(tr, dev->nodename, "accel-net-channel");
++      } while (xenbus_transaction_end(tr, 0) == -EAGAIN);
 +
-+      if ((cur_value & ~PCI_BIST_START) == (value & ~PCI_BIST_START)
-+          || value == PCI_BIST_START)
-+              err = pci_write_config_byte(dev, offset, value);
++      unbind_from_irqhandler(vnic->net_channel_irq, vnic);
++      unbind_from_irqhandler(vnic->msg_channel_irq, vnic);
 +
-+      out:
-+      return err;
++      /* ungrant pages for msg channel */
++      remove_named_grant(dev, "accel-ctrl-page", vnic->ctrl_page_gnt);
++      remove_named_grant(dev, "accel-msg-page", vnic->msg_page_gnt);
++      free_pages((unsigned long)vnic->shared_page, 1);
++      vnic->shared_page = NULL;
++
++      /* ungrant pages for buffers, and free buffer memory */
++      netfront_accel_free_buffer_mem(&vnic->bufpages,
++                                     vnic->rx_bufs,
++                                     vnic->tx_bufs);
++      netfront_accel_fini_bufs(vnic->rx_bufs);
++      netfront_accel_fini_bufs(vnic->tx_bufs);
 +}
 +
-+static struct config_field header_common[] = {
-+      {
-+       .offset    = PCI_COMMAND,
-+       .size      = 2,
-+       .u.w.read  = pciback_read_config_word,
-+       .u.w.write = command_write,
-+      },
-+      {
-+       .offset    = PCI_INTERRUPT_LINE,
-+       .size      = 1,
-+       .u.b.read  = interrupt_read,
-+      },
-+      {
-+       .offset    = PCI_INTERRUPT_PIN,
-+       .size      = 1,
-+       .u.b.read  = pciback_read_config_byte,
-+      },
-+      {
-+       /* Any side effects of letting driver domain control cache line? */
-+       .offset    = PCI_CACHE_LINE_SIZE,
-+       .size      = 1,
-+       .u.b.read  = pciback_read_config_byte,
-+       .u.b.write = pciback_write_config_byte,
-+      },
-+      {
-+       .offset    = PCI_LATENCY_TIMER,
-+       .size      = 1,
-+       .u.b.read  = pciback_read_config_byte,
-+      },
-+      {
-+       .offset    = PCI_BIST,
-+       .size      = 1,
-+       .u.b.read  = pciback_read_config_byte,
-+       .u.b.write = bist_write,
-+      },
-+      {
-+       .size = 0,
-+      },
-+};
 +
-+#define CFG_FIELD_BAR(reg_offset)                     \
-+      {                                               \
-+       .offset     = reg_offset,                      \
-+       .size       = 4,                               \
-+       .init       = bar_init,                        \
-+       .reset      = bar_reset,                       \
-+       .release    = bar_release,                     \
-+       .u.dw.read  = bar_read,                        \
-+       .u.dw.write = bar_write,                       \
-+       }
++static void vnic_setup_dom0_shared_state(struct xenbus_device *dev,
++                                      netfront_accel_vnic *vnic)
++{
++      DPRINTK("Setting up dom0 shared state\n");
 +
-+#define CFG_FIELD_ROM(reg_offset)                     \
-+      {                                               \
-+       .offset     = reg_offset,                      \
-+       .size       = 4,                               \
-+       .init       = rom_init,                        \
-+       .reset      = bar_reset,                       \
-+       .release    = bar_release,                     \
-+       .u.dw.read  = bar_read,                        \
-+       .u.dw.write = rom_write,                       \
-+       }
++      netfront_accel_vi_ctor(vnic);
 +
-+static struct config_field header_0[] = {
-+      CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
-+      CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
-+      CFG_FIELD_BAR(PCI_BASE_ADDRESS_2),
-+      CFG_FIELD_BAR(PCI_BASE_ADDRESS_3),
-+      CFG_FIELD_BAR(PCI_BASE_ADDRESS_4),
-+      CFG_FIELD_BAR(PCI_BASE_ADDRESS_5),
-+      CFG_FIELD_ROM(PCI_ROM_ADDRESS),
-+      {
-+       .size = 0,
-+      },
-+};
++      /*
++       * Message processing will be enabled when this function
++       * returns, but we might have missed an interrupt.  Schedule a
++       * check just in case.
++       */
++      queue_work(netfront_accel_workqueue, &vnic->msg_from_bend);
++}
 +
-+static struct config_field header_1[] = {
-+      CFG_FIELD_BAR(PCI_BASE_ADDRESS_0),
-+      CFG_FIELD_BAR(PCI_BASE_ADDRESS_1),
-+      CFG_FIELD_ROM(PCI_ROM_ADDRESS1),
-+      {
-+       .size = 0,
-+      },
-+};
 +
-+int pciback_config_header_add_fields(struct pci_dev *dev)
++static void vnic_remove_dom0_shared_state(struct xenbus_device *dev,
++                                        netfront_accel_vnic *vnic)
 +{
-+      int err;
++      DPRINTK("Removing dom0 shared state\n");
 +
-+      err = pciback_config_add_fields(dev, header_common);
-+      if (err)
-+              goto out;
++      vnic_stop_fastpath(vnic);
 +
-+      switch (dev->hdr_type) {
-+      case PCI_HEADER_TYPE_NORMAL:
-+              err = pciback_config_add_fields(dev, header_0);
-+              break;
++      netfront_accel_vi_dtor(vnic);
++}
 +
-+      case PCI_HEADER_TYPE_BRIDGE:
-+              err = pciback_config_add_fields(dev, header_1);
-+              break;
 +
-+      default:
-+              err = -EINVAL;
-+              printk(KERN_ERR "pciback: %s: Unsupported header type %d!\n",
-+                     pci_name(dev), dev->hdr_type);
-+              break;
-+      }
++/*************************************************************************/
 +
-+      out:
-+      return err;
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/conf_space_quirks.c linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_quirks.c
---- linux-2.6.18/drivers/xen/pciback/conf_space_quirks.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_quirks.c        2007-12-23 11:15:34.064602797 +0100
-@@ -0,0 +1,126 @@
 +/*
-+ * PCI Backend - Handle special overlays for broken devices.
++ * The following code handles accelstate changes between the frontend
++ * and the backend.  In response to transitions, calls the following
++ * functions in matching pairs:
++ *
++ *   vnic_setup_domU_shared_state
++ *   vnic_remove_domU_shared_state
++ *
++ *   vnic_setup_dom0_shared_state
++ *   vnic_remove_dom0_shared_state
++ *
++ * Valid state transitions for DomU are as follows:
++ *
++ * Closed->Init       on probe or in response to Init from dom0
++ *
++ * Init->Connected    in response to Init from dom0
++ * Init->Closing      on error providing dom0 is in Init
++ * Init->Closed       on remove or in response to Closing from dom0
++ *
++ * Connected->Closing on error/remove
++ * Connected->Closed  in response to Closing from dom0
++ *
++ * Closing->Closed    in response to Closing from dom0
 + *
-+ * Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ * Author: Chris Bookholt <hap10@epoch.ncsc.mil>
 + */
 +
-+#include <linux/kernel.h>
-+#include <linux/pci.h>
-+#include "pciback.h"
-+#include "conf_space.h"
-+#include "conf_space_quirks.h"
-+
-+LIST_HEAD(pciback_quirks);
 +
-+struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev)
++/* Function to deal with Xenbus accel state change in backend */
++static void netfront_accel_backend_accel_changed(netfront_accel_vnic *vnic,
++                                               XenbusState backend_state)
 +{
-+      struct pciback_config_quirk *tmp_quirk;
++      struct xenbus_device *dev = vnic->dev;
++      XenbusState frontend_state;
++      int state;
 +
-+      list_for_each_entry(tmp_quirk, &pciback_quirks, quirks_list)
-+          if (pci_match_id(&tmp_quirk->devid, dev))
-+              goto out;
-+      tmp_quirk = NULL;
-+      printk(KERN_DEBUG
-+             "quirk didn't match any device pciback knows about\n");
-+      out:
-+      return tmp_quirk;
-+}
++      DPRINTK("%s: changing from %s to %s. nodename %s, otherend %s\n",
++              __FUNCTION__, xenbus_strstate(vnic->backend_state),
++              xenbus_strstate(backend_state), dev->nodename, dev->otherend);
 +
-+static inline void register_quirk(struct pciback_config_quirk *quirk)
-+{
-+      list_add_tail(&quirk->quirks_list, &pciback_quirks);
-+}
++      /*
++       * Ignore duplicate state changes.  This can happen if the
++       * backend changes state twice in quick succession and the
++       * first watch fires in the frontend after the second
++       * transition has completed.
++       */
++      if (vnic->backend_state == backend_state)
++              return;
 +
-+int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg)
-+{
-+      int ret = 0;
-+      struct pciback_dev_data *dev_data = pci_get_drvdata(dev);
-+      struct config_field_entry *cfg_entry;
++      vnic->backend_state = backend_state;
++      frontend_state = vnic->frontend_state;
 +
-+      list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
-+              if ( OFFSET(cfg_entry) == reg) {
-+                      ret = 1;
-+                      break;
++      switch (backend_state) {
++      case XenbusStateInitialising:
++              /*
++               * It's possible for us to miss the closed state from
++               * dom0, so do the work here.
++               */
++              if (vnic->domU_state_is_setup) {
++                      vnic_remove_domU_shared_state(dev, vnic);
++                      vnic->domU_state_is_setup = 0;
++              }
++
++              if (frontend_state != XenbusStateInitialising) {
++                      /* Make sure the backend doesn't go away. */
++                      frontend_state = XenbusStateInitialising;
++                      net_accel_update_state(dev, frontend_state);
++                      xenbus_scanf(XBT_NIL, dev->otherend, "accelstate", "%d", &state);
++                      backend_state = (XenbusState)state;
++                      if (backend_state != XenbusStateInitialising)
++                              break;
 +              }
-+      }
-+      return ret;
-+}
 +
-+int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
-+                                  *field)
-+{
-+      int err = 0;
-+
-+      switch (field->size) {
-+      case 1:
-+              field->u.b.read = pciback_read_config_byte;
-+              field->u.b.write = pciback_write_config_byte;
-+              break;
-+      case 2:
-+              field->u.w.read = pciback_read_config_word;
-+              field->u.w.write = pciback_write_config_word;
++              /* Start the new connection. */
++              if (!vnic->removing) {
++                      BUG_ON(vnic->domU_state_is_setup);
++                      if (vnic_setup_domU_shared_state(dev, vnic) == 0) {
++                              vnic->domU_state_is_setup = 1;
++                              frontend_state = XenbusStateConnected;
++                      } else
++                              frontend_state = XenbusStateClosing;
++              }
 +              break;
-+      case 4:
-+              field->u.dw.read = pciback_read_config_dword;
-+              field->u.dw.write = pciback_write_config_dword;
++      case XenbusStateConnected:
++              if (vnic->domU_state_is_setup &&
++                  !vnic->dom0_state_is_setup) {
++                      vnic_setup_dom0_shared_state(dev, vnic);
++                      vnic->dom0_state_is_setup = 1;
++              }
 +              break;
 +      default:
-+              err = -EINVAL;
-+              goto out;
++      case XenbusStateClosing:
++              if (vnic->dom0_state_is_setup) {
++                      vnic_remove_dom0_shared_state(dev, vnic);
++                      vnic->dom0_state_is_setup = 0;
++              }
++              frontend_state = XenbusStateClosed;
++              break;
++      case XenbusStateUnknown:
++      case XenbusStateClosed:
++              if (vnic->domU_state_is_setup) {
++                      vnic_remove_domU_shared_state(dev, vnic);
++                      vnic->domU_state_is_setup = 0;
++              }
++              break;
 +      }
 +
-+      pciback_config_add_field(dev, field);
++      if (frontend_state != vnic->frontend_state) {
++              DPRINTK("Switching from state %s (%d) to %s (%d)\n",
++                      xenbus_strstate(vnic->frontend_state),
++                      vnic->frontend_state,
++                      xenbus_strstate(frontend_state), frontend_state);
++              vnic->frontend_state = frontend_state;
++              net_accel_update_state(dev, frontend_state);
++      }
 +
-+      out:
-+      return err;
++      wake_up(&vnic->state_wait_queue);
 +}
 +
-+int pciback_config_quirks_init(struct pci_dev *dev)
++
++static void backend_accel_state_change(struct xenbus_watch *watch,
++                                     const char **vec, unsigned int len)
 +{
-+      struct pciback_config_quirk *quirk;
-+      int ret = 0;
++      int state;
++      netfront_accel_vnic *vnic;
++      struct xenbus_device *dev;
 +
-+      quirk = kzalloc(sizeof(*quirk), GFP_ATOMIC);
-+      if (!quirk) {
-+              ret = -ENOMEM;
-+              goto out;
-+      }
++      DPRINTK("%s\n", __FUNCTION__);
 +
-+      quirk->devid.vendor = dev->vendor;
-+      quirk->devid.device = dev->device;
-+      quirk->devid.subvendor = dev->subsystem_vendor;
-+      quirk->devid.subdevice = dev->subsystem_device;
-+      quirk->devid.class = 0;
-+      quirk->devid.class_mask = 0;
-+      quirk->devid.driver_data = 0UL;
++      vnic = container_of(watch, struct netfront_accel_vnic,
++                              backend_accel_watch);
 +
-+      quirk->pdev = dev;
++      mutex_lock(&vnic->vnic_mutex);
 +
-+      register_quirk(quirk);
-+      out:
-+      return ret;
++      dev = vnic->dev;
++
++      state = (int)XenbusStateUnknown;
++      xenbus_scanf(XBT_NIL, dev->otherend, "accelstate", "%d", &state);
++      netfront_accel_backend_accel_changed(vnic, state);
++
++      mutex_unlock(&vnic->vnic_mutex);
 +}
 +
-+void pciback_config_field_free(struct config_field *field)
++
++static int setup_dom0_accel_watch(struct xenbus_device *dev,
++                                netfront_accel_vnic *vnic)
 +{
-+      kfree(field);
++      int err;
++
++      DPRINTK("Setting watch on %s/%s\n", dev->otherend, "accelstate");
++
++      err = xenbus_watch_path2(dev, dev->otherend, "accelstate", 
++                               &vnic->backend_accel_watch, 
++                               backend_accel_state_change);
++      if (err) {
++              EPRINTK("%s: Failed to register xenbus watch: %d\n",
++                      __FUNCTION__, err);
++              goto fail;
++      }
++      return 0;
++ fail:
++      vnic->backend_accel_watch.node = NULL;
++      return err;
 +}
 +
-+int pciback_config_quirk_release(struct pci_dev *dev)
++
++int netfront_accel_probe(struct net_device *net_dev, struct xenbus_device *dev)
 +{
-+      struct pciback_config_quirk *quirk;
-+      int ret = 0;
++      netfront_accel_vnic *vnic;
++      int err;
 +
-+      quirk = pciback_find_quirk(dev);
-+      if (!quirk) {
-+              ret = -ENXIO;
-+              goto out;
++      DPRINTK("Probe passed device %s\n", dev->nodename);
++
++      vnic = netfront_accel_vnic_ctor(net_dev, dev);
++      if (IS_ERR(vnic))
++              return PTR_ERR(vnic);
++
++      /*
++       * Setup a watch on the backend accel state.  This sets things
++       * going.
++       */
++      err = setup_dom0_accel_watch(dev, vnic);
++      if (err) {
++              netfront_accel_vnic_dtor(vnic);
++              EPRINTK("%s: probe failed with code %d\n", __FUNCTION__, err);
++              return err;
 +      }
 +
-+      list_del(&quirk->quirks_list);
-+      kfree(quirk);
++      /*
++       * Indicate to the other end that we're ready to start unless
++       * the watch has already fired.
++       */
++      mutex_lock(&vnic->vnic_mutex);
++      VPRINTK("setup success, updating accelstate\n");
++      if (vnic->frontend_state == XenbusStateClosed) {
++              vnic->frontend_state = XenbusStateInitialising;
++              net_accel_update_state(dev, XenbusStateInitialising);
++      }
++      mutex_unlock(&vnic->vnic_mutex);
 +
-+      out:
-+      return ret;
++      DPRINTK("Probe done device %s\n", dev->nodename);
++
++      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/conf_space_quirks.h linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_quirks.h
---- linux-2.6.18/drivers/xen/pciback/conf_space_quirks.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/conf_space_quirks.h        2007-12-23 11:15:34.064602797 +0100
-@@ -0,0 +1,35 @@
-+/*
-+ * PCI Backend - Data structures for special overlays for broken devices.
-+ *
-+ * Ryan Wilson <hap9@epoch.ncsc.mil>
-+ * Chris Bookholt <hap10@epoch.ncsc.mil>
-+ */
 +
-+#ifndef __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
-+#define __XEN_PCIBACK_CONF_SPACE_QUIRKS_H__
 +
-+#include <linux/pci.h>
-+#include <linux/list.h>
++int netfront_accel_remove(struct xenbus_device *dev)
++{
++      struct netfront_info *np =
++              (struct netfront_info *)dev->dev.driver_data;
++      netfront_accel_vnic *vnic = (netfront_accel_vnic *)np->accel_priv;
 +
-+struct pciback_config_quirk {
-+      struct list_head quirks_list;
-+      struct pci_device_id devid;
-+      struct pci_dev *pdev;
-+};
++      DPRINTK("%s %s\n", __FUNCTION__, dev->nodename);
 +
-+struct pciback_config_quirk *pciback_find_quirk(struct pci_dev *dev);
++      BUG_ON(vnic == NULL);
 +
-+int pciback_config_quirks_add_field(struct pci_dev *dev, struct config_field
-+                                  *field);
++      mutex_lock(&vnic->vnic_mutex);
 +
-+int pciback_config_quirks_remove_field(struct pci_dev *dev, int reg);
++      /* Reject any attempts to connect. */
++      vnic->removing = 1;
 +
-+int pciback_config_quirks_init(struct pci_dev *dev);
++      /* Close any existing connection. */
++      if (vnic->frontend_state == XenbusStateConnected) {
++              vnic->frontend_state = XenbusStateClosing;
++              net_accel_update_state(dev, XenbusStateClosing);
++      }
 +
-+void pciback_config_field_free(struct config_field *field);
++      mutex_unlock(&vnic->vnic_mutex);
 +
-+int pciback_config_quirk_release(struct pci_dev *dev);
++      DPRINTK("%s waiting for release of %s\n", __FUNCTION__, dev->nodename);
 +
-+int pciback_field_is_dup(struct pci_dev *dev, unsigned int reg);
++      /*
++       * Wait for the xenbus watch to release the shared resources.
++       * This indicates that dom0 has made the transition
++       * Closing->Closed or that dom0 was in Closed or Init and no
++       * resources were mapped.
++       */
++      wait_event(vnic->state_wait_queue,
++                 !vnic->domU_state_is_setup);
 +
-+#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/controller.c linux-2.6.18-xen.hg/drivers/xen/pciback/controller.c
---- linux-2.6.18/drivers/xen/pciback/controller.c      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/controller.c       2007-12-23 11:15:34.064602797 +0100
-@@ -0,0 +1,404 @@
-+/*
-+ * Copyright (C) 2007 Hewlett-Packard Development Company, L.P.
-+ *      Alex Williamson <alex.williamson@hp.com>
++      /*
++       * Now we don't need this watch anymore it is safe to remove
++       * it (and so synchronise with it completing if outstanding)
++       */
++      DPRINTK("%s: unregistering xenbus accel watch\n",
++              __FUNCTION__);
++      unregister_xenbus_watch(&vnic->backend_accel_watch);
++      kfree(vnic->backend_accel_watch.node);
++
++      netfront_accel_vnic_dtor(vnic);
++
++      DPRINTK("%s done %s\n", __FUNCTION__, dev->nodename);
++
++      return 0;
++}
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/ef_vi_falcon.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/ef_vi_falcon.h        2008-05-19 00:33:48.650950417 +0300
+@@ -0,0 +1,172 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
 + *
-+ * PCI "Controller" Backend - virtualize PCI bus topology based on PCI
-+ * controllers.  Devices under the same PCI controller are exposed on the
-+ * same virtual domain:bus.  Within a bus, device slots are virtualized
-+ * to compact the bus.
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
 + *
-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -98826,3323 +161240,5382 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/cont
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <linux/acpi.h>
-+#include <linux/list.h>
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include "pciback.h"
-+
-+#define PCI_MAX_BUSSES        255
-+#define PCI_MAX_SLOTS 32
-+
-+struct controller_dev_entry {
-+      struct list_head list;
-+      struct pci_dev *dev;
-+      unsigned int devfn;
-+};
-+
-+struct controller_list_entry {
-+      struct list_head list;
-+      struct pci_controller *controller;
-+      unsigned int domain;
-+      unsigned int bus;
-+      unsigned int next_devfn;
-+      struct list_head dev_list;
-+};
-+
-+struct controller_dev_data {
-+      struct list_head list;
-+      unsigned int next_domain;
-+      unsigned int next_bus;
-+      spinlock_t lock;
-+};
-+
-+struct walk_info {
-+      struct pciback_device *pdev;
-+      int resource_count;
-+      int root_num;
-+};
-+
-+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
-+                                  unsigned int domain, unsigned int bus,
-+                                  unsigned int devfn)
-+{
-+      struct controller_dev_data *dev_data = pdev->pci_dev_data;
-+      struct controller_dev_entry *dev_entry;
-+      struct controller_list_entry *cntrl_entry;
-+      struct pci_dev *dev = NULL;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&dev_data->lock, flags);
++/*
++ * \author  slp
++ *  \brief  Falcon specific definitions
++ *   \date  2004/08
++ */
 +
-+      list_for_each_entry(cntrl_entry, &dev_data->list, list) {
-+              if (cntrl_entry->domain != domain ||
-+                  cntrl_entry->bus != bus)
-+                      continue;
++#ifndef __EF_VI_FALCON_H__
++#define __EF_VI_FALCON_H__    
 +
-+              list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
-+                      if (devfn == dev_entry->devfn) {
-+                              dev = dev_entry->dev;
-+                              goto found;
-+                      }
-+              }
-+      }
-+found:
-+      spin_unlock_irqrestore(&dev_data->lock, flags);
++#define EFHW_4K               0x00001000u
++#define EFHW_8K               0x00002000u
 +
-+      return dev;
-+}
++/* include the autogenerated register definitions */
 +
-+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
-+{
-+      struct controller_dev_data *dev_data = pdev->pci_dev_data;
-+      struct controller_dev_entry *dev_entry;
-+      struct controller_list_entry *cntrl_entry;
-+      struct pci_controller *dev_controller = PCI_CONTROLLER(dev);
-+      unsigned long flags;
-+      int ret = 0, found = 0;
++#include "ef_vi_falcon_core.h"
++#include "ef_vi_falcon_desc.h"
++#include "ef_vi_falcon_event.h"
 +
-+      spin_lock_irqsave(&dev_data->lock, flags);
 +
-+      /* Look to see if we already have a domain:bus for this controller */
-+      list_for_each_entry(cntrl_entry, &dev_data->list, list) {
-+              if (cntrl_entry->controller == dev_controller) {
-+                      found = 1;
-+                      break;
-+              }
-+      }
++/*----------------------------------------------------------------------------
++ *
++ * Helpers to turn bit shifts into dword shifts and check that the bit fields 
++ * haven't overflown the dword etc. Aim is to preserve consistency with the 
++ * autogenerated headers - once stable we could hard code.
++ *
++ *---------------------------------------------------------------------------*/
 +
-+      if (!found) {
-+              cntrl_entry = kmalloc(sizeof(*cntrl_entry), GFP_ATOMIC);
-+              if (!cntrl_entry) {
-+                      ret =  -ENOMEM;
-+                      goto out;
-+              }
++/* mask constructors */
++#define __FALCON_MASK(WIDTH,T)  ((((T)1) << (WIDTH)) - 1)
++#define __EFVI_MASK32(WIDTH)  __FALCON_MASK((WIDTH),uint32_t)
++#define __EFVI_MASK64(WIDTH)  __FALCON_MASK((WIDTH),uint64_t)
 +
-+              cntrl_entry->controller = dev_controller;
-+              cntrl_entry->next_devfn = PCI_DEVFN(0, 0);
++#define __EFVI_FALCON_MASKFIELD32(LBN, WIDTH)   ((uint32_t)  \
++                             (__EFVI_MASK32(WIDTH) << (LBN)))
 +
-+              cntrl_entry->domain = dev_data->next_domain;
-+              cntrl_entry->bus = dev_data->next_bus++;
-+              if (dev_data->next_bus > PCI_MAX_BUSSES) {
-+                      dev_data->next_domain++;
-+                      dev_data->next_bus = 0;
-+              }
++/* constructors for fields which span the first and second dwords */
++#define __LW(LBN) (32 - LBN)
++#define LOW(v, LBN, WIDTH)   ((uint32_t)  \
++                               (((v) & __EFVI_MASK64(__LW((LBN)))) << (LBN)))
++#define HIGH(v, LBN, WIDTH)  ((uint32_t)(((v) >> __LW((LBN))) & \
++                                       __EFVI_MASK64((WIDTH - __LW((LBN))))))
++/* constructors for fields within the second dword */
++#define __DW2(LBN)      ((LBN) - 32)
 +
-+              INIT_LIST_HEAD(&cntrl_entry->dev_list);
++/* constructors for fields which span the second and third dwords */
++#define __LW2(LBN) (64 - LBN)
++#define LOW2(v, LBN, WIDTH) ((uint32_t) \
++                       (((v) & __EFVI_MASK64(__LW2((LBN)))) << ((LBN) - 32)))
++#define HIGH2(v, LBN, WIDTH)  ((uint32_t) \
++             (((v) >> __LW2((LBN))) & __EFVI_MASK64((WIDTH - __LW2((LBN))))))
 +
-+              list_add_tail(&cntrl_entry->list, &dev_data->list);
-+      }
++/* constructors for fields within the third dword */
++#define __DW3(LBN)      ((LBN) - 64)
 +
-+      if (PCI_SLOT(cntrl_entry->next_devfn) > PCI_MAX_SLOTS) {
-+              /*
-+               * While it seems unlikely, this can actually happen if
-+               * a controller has P2P bridges under it.
-+               */
-+              xenbus_dev_fatal(pdev->xdev, -ENOSPC, "Virtual bus %04x:%02x "
-+                               "is full, no room to export %04x:%02x:%02x.%x",
-+                               cntrl_entry->domain, cntrl_entry->bus,
-+                               pci_domain_nr(dev->bus), dev->bus->number,
-+                               PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
-+              ret = -ENOSPC;
-+              goto out;
-+      }
++                              
++/* constructors for fields which span the third and fourth dwords */
++#define __LW3(LBN) (96 - LBN)
++#define LOW3(v, LBN, WIDTH)   ((uint32_t)    \
++              (((v) & __EFVI_MASK64(__LW3((LBN)))) << ((LBN) - 64)))
++#define HIGH3(v, LBN, WIDTH)  ((unit32_t)    \
++             (((v) >> __LW3((LBN))) & __EFVI_MASK64((WIDTH - __LW3((LBN))))))
 +
-+      dev_entry = kmalloc(sizeof(*dev_entry), GFP_ATOMIC);
-+      if (!dev_entry) {
-+              if (list_empty(&cntrl_entry->dev_list)) {
-+                      list_del(&cntrl_entry->list);
-+                      kfree(cntrl_entry);
-+              }
-+              ret = -ENOMEM;
-+              goto out;
-+      }
++/* constructors for fields within the fourth dword */
++#define __DW4(LBN)      ((LBN) - 96)
 +
-+      dev_entry->dev = dev;
-+      dev_entry->devfn = cntrl_entry->next_devfn;
++/* checks that the autogenerated headers our consistent with our model */
++#define WIDTHCHCK(a, b) ef_assert((a) == (b))
++#define RANGECHCK(v, WIDTH) \
++                ef_assert(((uint64_t)(v) & ~(__EFVI_MASK64((WIDTH)))) == 0)
 +
-+      list_add_tail(&dev_entry->list, &cntrl_entry->dev_list);
++/* fields within the first dword */
++#define DWCHCK(LBN, WIDTH) ef_assert(((LBN) >= 0) &&(((LBN)+(WIDTH)) <= 32))
 +
-+      cntrl_entry->next_devfn += PCI_DEVFN(1, 0);
++/* fields which span the first and second dwords */
++#define LWCHK(LBN, WIDTH)  ef_assert(WIDTH >= __LW(LBN))
 +
-+out:
-+      spin_unlock_irqrestore(&dev_data->lock, flags);
-+      return ret;
-+}
++/*----------------------------------------------------------------------------
++ *
++ * Buffer virtual addresses (4K buffers) 
++ *
++ *---------------------------------------------------------------------------*/
 +
-+void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
-+{
-+      struct controller_dev_data *dev_data = pdev->pci_dev_data;
-+      struct controller_list_entry *cntrl_entry;
-+      struct controller_dev_entry *dev_entry = NULL;
-+      struct pci_dev *found_dev = NULL;
-+      unsigned long flags;
++/* Form a buffer virtual address from buffer ID and offset.  If the offset
++** is larger than the buffer size, then the buffer indexed will be
++** calculated appropriately.  It is the responsibility of the caller to
++** ensure that they have valid buffers programmed at that address.
++*/
++#define EFVI_FALCON_VADDR_4K_S        (12)         
++#define EFVI_FALCON_VADDR_M       0xfffff             /* post shift mask  */
 +
-+      spin_lock_irqsave(&dev_data->lock, flags);
 +
-+      list_for_each_entry(cntrl_entry, &dev_data->list, list) {
-+              if (cntrl_entry->controller != PCI_CONTROLLER(dev))
-+                      continue;
++#define EFVI_FALCON_BUFFER_4K_ADDR(id,off)      \
++  (((id) << EFVI_FALCON_VADDR_4K_S) + (off))
 +
-+              list_for_each_entry(dev_entry, &cntrl_entry->dev_list, list) {
-+                      if (dev_entry->dev == dev) {
-+                              found_dev = dev_entry->dev;
-+                              break;
-+                      }
-+              }
-+      }
++#define EFVI_FALCON_BUFFER_4K_PAGE(vaddr)                       \
++  (((vaddr) >> EFVI_FALCON_VADDR_4K_S) & EFVI_FALCON_VADDR_M)
 +
-+      if (!found_dev) {
-+              spin_unlock_irqrestore(&dev_data->lock, flags);
-+              return;
-+      }
++#define EFVI_FALCON_BUFFER_4K_OFF(vaddr)                \
++  ((vaddr) & __EFVI_MASK32(EFVI_FALCON_VADDR_4K_S))
++
++
++/*----------------------------------------------------------------------------
++ *
++ * Masks
++ *
++ *---------------------------------------------------------------------------*/
++
++#define EFVI_FALCON_CLOCK_ASIC_HZ    (125000)
++#define EFVI_FALCON_CLOCK_FPGA_HZ    (62500)
++#define EFVI_FALCON_CLOCK_HZ         EFVI_FALCON_CLOCK_ASIC_HZ
++
++
++/*----------------------------------------------------------------------------
++ *
++ * Timers
++ *
++ *---------------------------------------------------------------------------*/
++
++/* Event-Queue Timer granularity - measured in us 
++   Given by: 4096 * 3 cycle * clock period */
++
++#define EFVI_FALCON_EVQTIMER_PERIOD_US   ((4096 * 3 * 1000) / EFVI_FALCON_CLOCK_HZ)
++
++/* mode bits */
++#define EFVI_FALCON_TIMER_MODE_DIS     0     /* disabled */
++#define EFVI_FALCON_TIMER_MODE_RUN     1     /* started counting right away */
++#define EFVI_FALCON_TIMER_MODE_HOLD    2     /* trigger mode (user queues) */
++
++#define EFVI_FALCON_EVQTIMER_HOLD     (EFVI_FALCON_TIMER_MODE_HOLD << TIMER_MODE_LBN)
++#define EFVI_FALCON_EVQTIMER_RUN      (EFVI_FALCON_TIMER_MODE_RUN  << TIMER_MODE_LBN)
++#define EFVI_FALCON_EVQTIMER_DISABLE  (EFVI_FALCON_TIMER_MODE_DIS  << TIMER_MODE_LBN) 
++
++
++/* ---- efhw_event_t helpers --- */
++
++#define EFVI_FALCON_EVENT_CODE(evp) \
++       ((evp)->u64 & EFVI_FALCON_EVENT_CODE_MASK)
++
++#define EFVI_FALCON_EVENT_SW_DATA_MASK    0x0000ffff
++
++#define __EFVI_FALCON_OPEN_MASK(WIDTH)  ((((uint64_t)1) << (WIDTH)) - 1)
++
++#define EFVI_FALCON_EVENT_CODE_MASK \
++           (__EFVI_FALCON_OPEN_MASK(EV_CODE_WIDTH) << EV_CODE_LBN)
++
++
++#endif  /* __EF_VI_FALCON_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/ef_vi_falcon_core.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/ef_vi_falcon_core.h   2008-05-19 00:33:48.654950647 +0300
+@@ -0,0 +1,1075 @@
++
++#define  EFVI_FALCON_EXTENDED_P_BAR 1
++
++//////////////---- Bus Interface Unit Registers C Header ----//////////////
++#define IOM_IND_ADR_REG_OFST 0x0 // IO-mapped indirect access address register
++  #define IOM_AUTO_ADR_INC_EN_LBN 16
++  #define IOM_AUTO_ADR_INC_EN_WIDTH 1
++  #define IOM_IND_ADR_LBN 0
++  #define IOM_IND_ADR_WIDTH 16
++#define IOM_IND_DAT_REG_OFST 0x4 // IO-mapped indirect access data register
++  #define IOM_IND_DAT_LBN 0
++  #define IOM_IND_DAT_WIDTH 32
++#define ADR_REGION_REG_KER_OFST 0x0 // Address region register
++#define ADR_REGION_REG_OFST 0x0 // Address region register
++  #define ADR_REGION3_LBN 96
++  #define ADR_REGION3_WIDTH 18
++  #define ADR_REGION2_LBN 64
++  #define ADR_REGION2_WIDTH 18
++  #define ADR_REGION1_LBN 32
++  #define ADR_REGION1_WIDTH 18
++  #define ADR_REGION0_LBN 0
++  #define ADR_REGION0_WIDTH 18
++#define INT_EN_REG_KER_OFST 0x10 // Kernel driver Interrupt enable register
++  #define KER_INT_CHAR_LBN 4
++  #define KER_INT_CHAR_WIDTH 1
++  #define KER_INT_KER_LBN 3
++  #define KER_INT_KER_WIDTH 1
++  #define ILL_ADR_ERR_INT_EN_KER_LBN 2
++  #define ILL_ADR_ERR_INT_EN_KER_WIDTH 1
++  #define SRM_PERR_INT_EN_KER_LBN 1
++  #define SRM_PERR_INT_EN_KER_WIDTH 1
++  #define DRV_INT_EN_KER_LBN 0
++  #define DRV_INT_EN_KER_WIDTH 1
++#define INT_EN_REG_CHAR_OFST 0x20 // Char Driver interrupt enable register
++  #define CHAR_INT_CHAR_LBN 4
++  #define CHAR_INT_CHAR_WIDTH 1
++  #define CHAR_INT_KER_LBN 3
++  #define CHAR_INT_KER_WIDTH 1
++  #define ILL_ADR_ERR_INT_EN_CHAR_LBN 2
++  #define ILL_ADR_ERR_INT_EN_CHAR_WIDTH 1
++  #define SRM_PERR_INT_EN_CHAR_LBN 1
++  #define SRM_PERR_INT_EN_CHAR_WIDTH 1
++  #define DRV_INT_EN_CHAR_LBN 0
++  #define DRV_INT_EN_CHAR_WIDTH 1
++#define INT_ADR_REG_KER_OFST 0x30 // Interrupt host address for Kernel driver
++  #define INT_ADR_KER_LBN 0
++  #define INT_ADR_KER_WIDTH 64
++  #define DRV_INT_KER_LBN 32
++  #define DRV_INT_KER_WIDTH 1
++  #define EV_FF_HALF_INT_KER_LBN 3
++  #define EV_FF_HALF_INT_KER_WIDTH 1
++  #define EV_FF_FULL_INT_KER_LBN 2
++  #define EV_FF_FULL_INT_KER_WIDTH 1
++  #define ILL_ADR_ERR_INT_KER_LBN 1
++  #define ILL_ADR_ERR_INT_KER_WIDTH 1
++  #define SRAM_PERR_INT_KER_LBN 0
++  #define SRAM_PERR_INT_KER_WIDTH 1
++#define INT_ADR_REG_CHAR_OFST 0x40 // Interrupt host address for Char driver
++  #define INT_ADR_CHAR_LBN 0
++  #define INT_ADR_CHAR_WIDTH 64
++  #define DRV_INT_CHAR_LBN 32
++  #define DRV_INT_CHAR_WIDTH 1
++  #define EV_FF_HALF_INT_CHAR_LBN 3
++  #define EV_FF_HALF_INT_CHAR_WIDTH 1
++  #define EV_FF_FULL_INT_CHAR_LBN 2
++  #define EV_FF_FULL_INT_CHAR_WIDTH 1
++  #define ILL_ADR_ERR_INT_CHAR_LBN 1
++  #define ILL_ADR_ERR_INT_CHAR_WIDTH 1
++  #define SRAM_PERR_INT_CHAR_LBN 0
++  #define SRAM_PERR_INT_CHAR_WIDTH 1
++#define INT_ISR0_B0_OFST 0x90 // B0 only
++#define INT_ISR1_B0_OFST 0xA0
++#define INT_ACK_REG_KER_A1_OFST 0x50 // Kernel interrupt acknowledge register
++  #define RESERVED_LBN 0
++  #define RESERVED_WIDTH 32
++#define INT_ACK_REG_CHAR_A1_OFST 0x60 // CHAR interrupt acknowledge register
++  #define RESERVED_LBN 0
++  #define RESERVED_WIDTH 32
++//////////////---- Global CSR Registers C Header ----//////////////
++#define STRAP_REG_KER_OFST 0x200 // ASIC strap status register
++#define STRAP_REG_OFST 0x200 // ASIC strap status register
++  #define ONCHIP_SRAM_LBN 16
++  #define ONCHIP_SRAM_WIDTH 0
++  #define STRAP_ISCSI_EN_LBN 3
++  #define STRAP_ISCSI_EN_WIDTH 1
++  #define STRAP_PINS_LBN 0
++  #define STRAP_PINS_WIDTH 3
++#define GPIO_CTL_REG_KER_OFST 0x210 // GPIO control register
++#define GPIO_CTL_REG_OFST 0x210 // GPIO control register
++  #define GPIO_OEN_LBN 24
++  #define GPIO_OEN_WIDTH 4
++  #define GPIO_OUT_LBN 16
++  #define GPIO_OUT_WIDTH 4
++  #define GPIO_IN_LBN 8
++  #define GPIO_IN_WIDTH 4
++  #define GPIO_PWRUP_VALUE_LBN 0
++  #define GPIO_PWRUP_VALUE_WIDTH 4
++#define GLB_CTL_REG_KER_OFST 0x220 // Global control register
++#define GLB_CTL_REG_OFST 0x220 // Global control register
++  #define SWRST_LBN 0
++  #define SWRST_WIDTH 1
++#define FATAL_INTR_REG_KER_OFST 0x230 // Fatal interrupt register for Kernel
++  #define PCI_BUSERR_INT_KER_EN_LBN 43
++  #define PCI_BUSERR_INT_KER_EN_WIDTH 1
++  #define SRAM_OOB_INT_KER_EN_LBN 42
++  #define SRAM_OOB_INT_KER_EN_WIDTH 1
++  #define BUFID_OOB_INT_KER_EN_LBN 41
++  #define BUFID_OOB_INT_KER_EN_WIDTH 1
++  #define MEM_PERR_INT_KER_EN_LBN 40
++  #define MEM_PERR_INT_KER_EN_WIDTH 1
++  #define RBUF_OWN_INT_KER_EN_LBN 39
++  #define RBUF_OWN_INT_KER_EN_WIDTH 1
++  #define TBUF_OWN_INT_KER_EN_LBN 38
++  #define TBUF_OWN_INT_KER_EN_WIDTH 1
++  #define RDESCQ_OWN_INT_KER_EN_LBN 37
++  #define RDESCQ_OWN_INT_KER_EN_WIDTH 1
++  #define TDESCQ_OWN_INT_KER_EN_LBN 36
++  #define TDESCQ_OWN_INT_KER_EN_WIDTH 1
++  #define EVQ_OWN_INT_KER_EN_LBN 35
++  #define EVQ_OWN_INT_KER_EN_WIDTH 1
++  #define EVFF_OFLO_INT_KER_EN_LBN 34
++  #define EVFF_OFLO_INT_KER_EN_WIDTH 1
++  #define ILL_ADR_INT_KER_EN_LBN 33
++  #define ILL_ADR_INT_KER_EN_WIDTH 1
++  #define SRM_PERR_INT_KER_EN_LBN 32
++  #define SRM_PERR_INT_KER_EN_WIDTH 1
++  #define PCI_BUSERR_INT_KER_LBN 11
++  #define PCI_BUSERR_INT_KER_WIDTH 1
++  #define SRAM_OOB_INT_KER_LBN 10
++  #define SRAM_OOB_INT_KER_WIDTH 1
++  #define BUFID_OOB_INT_KER_LBN 9
++  #define BUFID_OOB_INT_KER_WIDTH 1
++  #define MEM_PERR_INT_KER_LBN 8
++  #define MEM_PERR_INT_KER_WIDTH 1
++  #define RBUF_OWN_INT_KER_LBN 7
++  #define RBUF_OWN_INT_KER_WIDTH 1
++  #define TBUF_OWN_INT_KER_LBN 6
++  #define TBUF_OWN_INT_KER_WIDTH 1
++  #define RDESCQ_OWN_INT_KER_LBN 5
++  #define RDESCQ_OWN_INT_KER_WIDTH 1
++  #define TDESCQ_OWN_INT_KER_LBN 4
++  #define TDESCQ_OWN_INT_KER_WIDTH 1
++  #define EVQ_OWN_INT_KER_LBN 3
++  #define EVQ_OWN_INT_KER_WIDTH 1
++  #define EVFF_OFLO_INT_KER_LBN 2
++  #define EVFF_OFLO_INT_KER_WIDTH 1
++  #define ILL_ADR_INT_KER_LBN 1
++  #define ILL_ADR_INT_KER_WIDTH 1
++  #define SRM_PERR_INT_KER_LBN 0
++  #define SRM_PERR_INT_KER_WIDTH 1
++#define FATAL_INTR_REG_OFST 0x240 // Fatal interrupt register for Char
++  #define PCI_BUSERR_INT_CHAR_EN_LBN 43
++  #define PCI_BUSERR_INT_CHAR_EN_WIDTH 1
++  #define SRAM_OOB_INT_CHAR_EN_LBN 42
++  #define SRAM_OOB_INT_CHAR_EN_WIDTH 1
++  #define BUFID_OOB_INT_CHAR_EN_LBN 41
++  #define BUFID_OOB_INT_CHAR_EN_WIDTH 1
++  #define MEM_PERR_INT_CHAR_EN_LBN 40
++  #define MEM_PERR_INT_CHAR_EN_WIDTH 1
++  #define RBUF_OWN_INT_CHAR_EN_LBN 39
++  #define RBUF_OWN_INT_CHAR_EN_WIDTH 1
++  #define TBUF_OWN_INT_CHAR_EN_LBN 38
++  #define TBUF_OWN_INT_CHAR_EN_WIDTH 1
++  #define RDESCQ_OWN_INT_CHAR_EN_LBN 37
++  #define RDESCQ_OWN_INT_CHAR_EN_WIDTH 1
++  #define TDESCQ_OWN_INT_CHAR_EN_LBN 36
++  #define TDESCQ_OWN_INT_CHAR_EN_WIDTH 1
++  #define EVQ_OWN_INT_CHAR_EN_LBN 35
++  #define EVQ_OWN_INT_CHAR_EN_WIDTH 1
++  #define EVFF_OFLO_INT_CHAR_EN_LBN 34
++  #define EVFF_OFLO_INT_CHAR_EN_WIDTH 1
++  #define ILL_ADR_INT_CHAR_EN_LBN 33
++  #define ILL_ADR_INT_CHAR_EN_WIDTH 1
++  #define SRM_PERR_INT_CHAR_EN_LBN 32
++  #define SRM_PERR_INT_CHAR_EN_WIDTH 1
++  #define FATAL_INTR_REG_EN_BITS    0xffffffffffffffffULL
++  #define PCI_BUSERR_INT_CHAR_LBN 11
++  #define PCI_BUSERR_INT_CHAR_WIDTH 1
++  #define SRAM_OOB_INT_CHAR_LBN 10
++  #define SRAM_OOB_INT_CHAR_WIDTH 1
++  #define BUFID_OOB_INT_CHAR_LBN 9
++  #define BUFID_OOB_INT_CHAR_WIDTH 1
++  #define MEM_PERR_INT_CHAR_LBN 8
++  #define MEM_PERR_INT_CHAR_WIDTH 1
++  #define RBUF_OWN_INT_CHAR_LBN 7
++  #define RBUF_OWN_INT_CHAR_WIDTH 1
++  #define TBUF_OWN_INT_CHAR_LBN 6
++  #define TBUF_OWN_INT_CHAR_WIDTH 1
++  #define RDESCQ_OWN_INT_CHAR_LBN 5
++  #define RDESCQ_OWN_INT_CHAR_WIDTH 1
++  #define TDESCQ_OWN_INT_CHAR_LBN 4
++  #define TDESCQ_OWN_INT_CHAR_WIDTH 1
++  #define EVQ_OWN_INT_CHAR_LBN 3
++  #define EVQ_OWN_INT_CHAR_WIDTH 1
++  #define EVFF_OFLO_INT_CHAR_LBN 2
++  #define EVFF_OFLO_INT_CHAR_WIDTH 1
++  #define ILL_ADR_INT_CHAR_LBN 1
++  #define ILL_ADR_INT_CHAR_WIDTH 1
++  #define SRM_PERR_INT_CHAR_LBN 0
++  #define SRM_PERR_INT_CHAR_WIDTH 1
++#define DP_CTRL_REG_OFST 0x250 // Datapath control register
++  #define FLS_EVQ_ID_LBN 0
++  #define FLS_EVQ_ID_WIDTH 12
++#define MEM_STAT_REG_KER_OFST 0x260 // Memory status register
++#define MEM_STAT_REG_OFST 0x260 // Memory status register
++  #define MEM_PERR_VEC_LBN 53
++  #define MEM_PERR_VEC_WIDTH 38
++  #define MBIST_CORR_LBN 38
++  #define MBIST_CORR_WIDTH 15
++  #define MBIST_ERR_LBN 0
++  #define MBIST_ERR_WIDTH 38
++#define DEBUG_REG_KER_OFST 0x270 // Debug register
++#define DEBUG_REG_OFST 0x270 // Debug register
++  #define DEBUG_BLK_SEL2_LBN 47
++  #define DEBUG_BLK_SEL2_WIDTH 3
++  #define DEBUG_BLK_SEL1_LBN 44
++  #define DEBUG_BLK_SEL1_WIDTH 3
++  #define DEBUG_BLK_SEL0_LBN 41
++  #define DEBUG_BLK_SEL0_WIDTH 3
++  #define MISC_DEBUG_ADDR_LBN 36
++  #define MISC_DEBUG_ADDR_WIDTH 5
++  #define SERDES_DEBUG_ADDR_LBN 31
++  #define SERDES_DEBUG_ADDR_WIDTH 5
++  #define EM_DEBUG_ADDR_LBN 26
++  #define EM_DEBUG_ADDR_WIDTH 5
++  #define SR_DEBUG_ADDR_LBN 21
++  #define SR_DEBUG_ADDR_WIDTH 5
++  #define EV_DEBUG_ADDR_LBN 16
++  #define EV_DEBUG_ADDR_WIDTH 5
++  #define RX_DEBUG_ADDR_LBN 11
++  #define RX_DEBUG_ADDR_WIDTH 5
++  #define TX_DEBUG_ADDR_LBN 6
++  #define TX_DEBUG_ADDR_WIDTH 5
++  #define BIU_DEBUG_ADDR_LBN 1
++  #define BIU_DEBUG_ADDR_WIDTH 5
++  #define DEBUG_EN_LBN 0
++  #define DEBUG_EN_WIDTH 1
++#define DRIVER_REG0_KER_OFST 0x280 // Driver scratch register 0
++#define DRIVER_REG0_OFST 0x280 // Driver scratch register 0
++  #define DRIVER_DW0_LBN 0
++  #define DRIVER_DW0_WIDTH 32
++#define DRIVER_REG1_KER_OFST 0x290 // Driver scratch register 1
++#define DRIVER_REG1_OFST 0x290 // Driver scratch register 1
++  #define DRIVER_DW1_LBN 0
++  #define DRIVER_DW1_WIDTH 32
++#define DRIVER_REG2_KER_OFST 0x2A0 // Driver scratch register 2
++#define DRIVER_REG2_OFST 0x2A0 // Driver scratch register 2
++  #define DRIVER_DW2_LBN 0
++  #define DRIVER_DW2_WIDTH 32
++#define DRIVER_REG3_KER_OFST 0x2B0 // Driver scratch register 3
++#define DRIVER_REG3_OFST 0x2B0 // Driver scratch register 3
++  #define DRIVER_DW3_LBN 0
++  #define DRIVER_DW3_WIDTH 32
++#define DRIVER_REG4_KER_OFST 0x2C0 // Driver scratch register 4
++#define DRIVER_REG4_OFST 0x2C0 // Driver scratch register 4
++  #define DRIVER_DW4_LBN 0
++  #define DRIVER_DW4_WIDTH 32
++#define DRIVER_REG5_KER_OFST 0x2D0 // Driver scratch register 5
++#define DRIVER_REG5_OFST 0x2D0 // Driver scratch register 5
++  #define DRIVER_DW5_LBN 0
++  #define DRIVER_DW5_WIDTH 32
++#define DRIVER_REG6_KER_OFST 0x2E0 // Driver scratch register 6
++#define DRIVER_REG6_OFST 0x2E0 // Driver scratch register 6
++  #define DRIVER_DW6_LBN 0
++  #define DRIVER_DW6_WIDTH 32
++#define DRIVER_REG7_KER_OFST 0x2F0 // Driver scratch register 7
++#define DRIVER_REG7_OFST 0x2F0 // Driver scratch register 7
++  #define DRIVER_DW7_LBN 0
++  #define DRIVER_DW7_WIDTH 32
++#define ALTERA_BUILD_REG_OFST 0x300 // Altera build register
++#define ALTERA_BUILD_REG_OFST 0x300 // Altera build register
++  #define ALTERA_BUILD_VER_LBN 0
++  #define ALTERA_BUILD_VER_WIDTH 32
++
++/* so called CSR spare register 
++    - contains separate parity enable bits for the various internal memory blocks */
++#define MEM_PARITY_ERR_EN_REG_KER 0x310 
++#define MEM_PARITY_ALL_BLOCKS_EN_LBN 64
++#define MEM_PARITY_ALL_BLOCKS_EN_WIDTH 38
++#define MEM_PARITY_TX_DATA_EN_LBN   72
++#define MEM_PARITY_TX_DATA_EN_WIDTH 2
++
++//////////////---- Event & Timer Module Registers C Header ----//////////////
++
++#if EFVI_FALCON_EXTENDED_P_BAR
++#define EVQ_RPTR_REG_KER_OFST 0x11B00 // Event queue read pointer register
++#else
++#define EVQ_RPTR_REG_KER_OFST 0x1B00 // Event queue read pointer register
++#endif
 +
-+      list_del(&dev_entry->list);
-+      kfree(dev_entry);
++#define EVQ_RPTR_REG_OFST 0xFA0000 // Event queue read pointer register array.
++  #define EVQ_RPTR_LBN 0
++  #define EVQ_RPTR_WIDTH 15
 +
-+      if (list_empty(&cntrl_entry->dev_list)) {
-+              list_del(&cntrl_entry->list);
-+              kfree(cntrl_entry);
-+      }
++#if EFVI_FALCON_EXTENDED_P_BAR
++#define EVQ_PTR_TBL_KER_OFST 0x11A00 // Event queue pointer table for kernel access
++#else
++#define EVQ_PTR_TBL_KER_OFST 0x1A00 // Event queue pointer table for kernel access
++#endif
++
++#define EVQ_PTR_TBL_CHAR_OFST 0xF60000 // Event queue pointer table for char direct access
++  #define EVQ_WKUP_OR_INT_EN_LBN 39
++  #define EVQ_WKUP_OR_INT_EN_WIDTH 1
++  #define EVQ_NXT_WPTR_LBN 24
++  #define EVQ_NXT_WPTR_WIDTH 15
++  #define EVQ_EN_LBN 23
++  #define EVQ_EN_WIDTH 1
++  #define EVQ_SIZE_LBN 20
++  #define EVQ_SIZE_WIDTH 3
++  #define EVQ_BUF_BASE_ID_LBN 0
++  #define EVQ_BUF_BASE_ID_WIDTH 20
++#define TIMER_CMD_REG_KER_OFST 0x420 // Timer table for kernel access. Page-mapped
++#define TIMER_CMD_REG_PAGE4_OFST 0x8420 // Timer table for user-level access. Page-mapped. For lowest 1K queues.
++#define TIMER_CMD_REG_PAGE123K_OFST 0x1000420 // Timer table for user-level access. Page-mapped. For upper 3K queues.
++#define TIMER_TBL_OFST 0xF70000 // Timer table for char driver direct access
++  #define TIMER_MODE_LBN 12
++  #define TIMER_MODE_WIDTH 2
++  #define TIMER_VAL_LBN 0
++  #define TIMER_VAL_WIDTH 12
++  #define TIMER_MODE_INT_HLDOFF 2
++  #define EVQ_BUF_SIZE_LBN 0
++  #define EVQ_BUF_SIZE_WIDTH 1
++#define DRV_EV_REG_KER_OFST 0x440 // Driver generated event register
++#define DRV_EV_REG_OFST 0x440 // Driver generated event register
++  #define DRV_EV_QID_LBN 64
++  #define DRV_EV_QID_WIDTH 12
++  #define DRV_EV_DATA_LBN 0
++  #define DRV_EV_DATA_WIDTH 64
++#define EVQ_CTL_REG_KER_OFST 0x450 // Event queue control register
++#define EVQ_CTL_REG_OFST 0x450 // Event queue control register
++  #define RX_EVQ_WAKEUP_MASK_B0_LBN 15
++  #define RX_EVQ_WAKEUP_MASK_B0_WIDTH 6
++  #define EVQ_OWNERR_CTL_LBN 14
++  #define EVQ_OWNERR_CTL_WIDTH 1
++  #define EVQ_FIFO_AF_TH_LBN 8
++  #define EVQ_FIFO_AF_TH_WIDTH 6
++  #define EVQ_FIFO_NOTAF_TH_LBN 0
++  #define EVQ_FIFO_NOTAF_TH_WIDTH 6
++//////////////---- SRAM Module Registers C Header ----//////////////
++#define BUF_TBL_CFG_REG_KER_OFST 0x600 // Buffer table configuration register
++#define BUF_TBL_CFG_REG_OFST 0x600 // Buffer table configuration register
++  #define BUF_TBL_MODE_LBN 3
++  #define BUF_TBL_MODE_WIDTH 1
++#define SRM_RX_DC_CFG_REG_KER_OFST 0x610 // SRAM receive descriptor cache configuration register
++#define SRM_RX_DC_CFG_REG_OFST 0x610 // SRAM receive descriptor cache configuration register
++  #define SRM_RX_DC_BASE_ADR_LBN 0
++  #define SRM_RX_DC_BASE_ADR_WIDTH 21
++#define SRM_TX_DC_CFG_REG_KER_OFST 0x620 // SRAM transmit descriptor cache configuration register
++#define SRM_TX_DC_CFG_REG_OFST 0x620 // SRAM transmit descriptor cache configuration register
++  #define SRM_TX_DC_BASE_ADR_LBN 0
++  #define SRM_TX_DC_BASE_ADR_WIDTH 21
++#define SRM_CFG_REG_KER_OFST 0x630 // SRAM configuration register
++#define SRM_CFG_REG_OFST 0x630 // SRAM configuration register
++  #define SRAM_OOB_ADR_INTEN_LBN 5
++  #define SRAM_OOB_ADR_INTEN_WIDTH 1
++  #define SRAM_OOB_BUF_INTEN_LBN 4
++  #define SRAM_OOB_BUF_INTEN_WIDTH 1
++  #define SRAM_BT_INIT_EN_LBN 3
++  #define SRAM_BT_INIT_EN_WIDTH 1
++  #define SRM_NUM_BANK_LBN 2
++  #define SRM_NUM_BANK_WIDTH 1
++  #define SRM_BANK_SIZE_LBN 0
++  #define SRM_BANK_SIZE_WIDTH 2
++#define BUF_TBL_UPD_REG_KER_OFST 0x650 // Buffer table update register
++#define BUF_TBL_UPD_REG_OFST 0x650 // Buffer table update register
++  #define BUF_UPD_CMD_LBN 63
++  #define BUF_UPD_CMD_WIDTH 1
++  #define BUF_CLR_CMD_LBN 62
++  #define BUF_CLR_CMD_WIDTH 1
++  #define BUF_CLR_END_ID_LBN 32
++  #define BUF_CLR_END_ID_WIDTH 20
++  #define BUF_CLR_START_ID_LBN 0
++  #define BUF_CLR_START_ID_WIDTH 20
++#define SRM_UPD_EVQ_REG_KER_OFST 0x660 // Buffer table update register
++#define SRM_UPD_EVQ_REG_OFST 0x660 // Buffer table update register
++  #define SRM_UPD_EVQ_ID_LBN 0
++  #define SRM_UPD_EVQ_ID_WIDTH 12
++#define SRAM_PARITY_REG_KER_OFST 0x670 // SRAM parity register.
++#define SRAM_PARITY_REG_OFST 0x670 // SRAM parity register.
++  #define FORCE_SRAM_PERR_LBN 0
++  #define FORCE_SRAM_PERR_WIDTH 1
++
++#if EFVI_FALCON_EXTENDED_P_BAR
++#define BUF_HALF_TBL_KER_OFST 0x18000 // Buffer table in half buffer table mode direct access by kernel driver
++#else
++#define BUF_HALF_TBL_KER_OFST 0x8000 // Buffer table in half buffer table mode direct access by kernel driver
++#endif
 +
-+      spin_unlock_irqrestore(&dev_data->lock, flags);
-+      pcistub_put_pci_dev(found_dev);
-+}
 +
-+int pciback_init_devices(struct pciback_device *pdev)
-+{
-+      struct controller_dev_data *dev_data;
++#define BUF_HALF_TBL_OFST 0x800000 // Buffer table in half buffer table mode direct access by char driver
++  #define BUF_ADR_HBUF_ODD_LBN 44
++  #define BUF_ADR_HBUF_ODD_WIDTH 20
++  #define BUF_OWNER_ID_HBUF_ODD_LBN 32
++  #define BUF_OWNER_ID_HBUF_ODD_WIDTH 12
++  #define BUF_ADR_HBUF_EVEN_LBN 12
++  #define BUF_ADR_HBUF_EVEN_WIDTH 20
++  #define BUF_OWNER_ID_HBUF_EVEN_LBN 0
++  #define BUF_OWNER_ID_HBUF_EVEN_WIDTH 12
 +
-+      dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
-+      if (!dev_data)
-+              return -ENOMEM;
 +
-+      spin_lock_init(&dev_data->lock);
++#if EFVI_FALCON_EXTENDED_P_BAR
++#define BUF_FULL_TBL_KER_OFST 0x18000 // Buffer table in full buffer table mode direct access by kernel driver
++#else
++#define BUF_FULL_TBL_KER_OFST 0x8000 // Buffer table in full buffer table mode direct access by kernel driver
++#endif
 +
-+      INIT_LIST_HEAD(&dev_data->list);
 +
-+      /* Starting domain:bus numbers */
-+      dev_data->next_domain = 0;
-+      dev_data->next_bus = 0;
 +
-+      pdev->pci_dev_data = dev_data;
 +
-+      return 0;
-+}
++#define BUF_FULL_TBL_OFST 0x800000 // Buffer table in full buffer table mode direct access by char driver
++  #define IP_DAT_BUF_SIZE_LBN 50
++  #define IP_DAT_BUF_SIZE_WIDTH 1
++  #define BUF_ADR_REGION_LBN 48
++  #define BUF_ADR_REGION_WIDTH 2
++  #define BUF_ADR_FBUF_LBN 14
++  #define BUF_ADR_FBUF_WIDTH 34
++  #define BUF_OWNER_ID_FBUF_LBN 0
++  #define BUF_OWNER_ID_FBUF_WIDTH 14
++#define SRM_DBG_REG_OFST 0x3000000 // SRAM debug access
++  #define SRM_DBG_LBN 0
++  #define SRM_DBG_WIDTH 64
++//////////////---- RX Datapath Registers C Header ----//////////////
 +
-+static acpi_status write_xenbus_resource(struct acpi_resource *res, void *data)
-+{
-+      struct walk_info *info = data;
-+      struct acpi_resource_address64 addr;
-+      acpi_status status;
-+      int i, len, err;
-+      char str[32], tmp[3];
-+      unsigned char *ptr, *buf;
++#define RX_CFG_REG_KER_OFST 0x800 // Receive configuration register
++#define RX_CFG_REG_OFST 0x800 // Receive configuration register
 +
-+      status = acpi_resource_to_address64(res, &addr);
++#if !defined(FALCON_64K_RXFIFO) && !defined(FALCON_PRE_02020029)
++# if !defined(FALCON_128K_RXFIFO)
++#  define FALCON_128K_RXFIFO
++# endif
++#endif
 +
-+      /* Do we care about this range?  Let's check. */
-+      if (!ACPI_SUCCESS(status) ||
-+          !(addr.resource_type == ACPI_MEMORY_RANGE ||
-+            addr.resource_type == ACPI_IO_RANGE) ||
-+          !addr.address_length || addr.producer_consumer != ACPI_PRODUCER)
-+              return AE_OK;
++#if defined(FALCON_128K_RXFIFO)
++
++/* new for B0 */
++  #define RX_TOEP_TCP_SUPPRESS_B0_LBN 48
++  #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1
++  #define RX_INGR_EN_B0_LBN 47
++  #define RX_INGR_EN_B0_WIDTH 1
++  #define RX_TOEP_IPV4_B0_LBN 46
++  #define RX_TOEP_IPV4_B0_WIDTH 1
++  #define RX_HASH_ALG_B0_LBN 45
++  #define RX_HASH_ALG_B0_WIDTH 1
++  #define RX_HASH_INSERT_HDR_B0_LBN 44
++  #define RX_HASH_INSERT_HDR_B0_WIDTH 1
++/* moved for B0 */
++  #define RX_DESC_PUSH_EN_B0_LBN 43
++  #define RX_DESC_PUSH_EN_B0_WIDTH 1
++  #define RX_RDW_PATCH_EN_LBN 42 /* Non head of line blocking */
++  #define RX_RDW_PATCH_EN_WIDTH 1
++  #define RX_PCI_BURST_SIZE_B0_LBN 39
++  #define RX_PCI_BURST_SIZE_B0_WIDTH 3
++  #define RX_OWNERR_CTL_B0_LBN 38
++  #define RX_OWNERR_CTL_B0_WIDTH 1
++  #define RX_XON_TX_TH_B0_LBN 33 
++  #define RX_XON_TX_TH_B0_WIDTH 5
++  #define RX_XOFF_TX_TH_B0_LBN 28 
++  #define RX_XOFF_TX_TH_B0_WIDTH 5
++  #define RX_USR_BUF_SIZE_B0_LBN 19
++  #define RX_USR_BUF_SIZE_B0_WIDTH 9
++  #define RX_XON_MAC_TH_B0_LBN 10
++  #define RX_XON_MAC_TH_B0_WIDTH 9
++  #define RX_XOFF_MAC_TH_B0_LBN 1
++  #define RX_XOFF_MAC_TH_B0_WIDTH 9
++  #define RX_XOFF_MAC_EN_B0_LBN 0
++  #define RX_XOFF_MAC_EN_B0_WIDTH 1
++
++#elif !defined(FALCON_PRE_02020029)
++/* new for B0 */
++  #define RX_TOEP_TCP_SUPPRESS_B0_LBN 46
++  #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1
++  #define RX_INGR_EN_B0_LBN 45
++  #define RX_INGR_EN_B0_WIDTH 1
++  #define RX_TOEP_IPV4_B0_LBN 44
++  #define RX_TOEP_IPV4_B0_WIDTH 1
++  #define RX_HASH_ALG_B0_LBN 43
++  #define RX_HASH_ALG_B0_WIDTH 41
++  #define RX_HASH_INSERT_HDR_B0_LBN 42
++  #define RX_HASH_INSERT_HDR_B0_WIDTH 1
++/* moved for B0 */
++  #define RX_DESC_PUSH_EN_B0_LBN 41
++  #define RX_DESC_PUSH_EN_B0_WIDTH 1
++  #define RX_PCI_BURST_SIZE_B0_LBN 37
++  #define RX_PCI_BURST_SIZE_B0_WIDTH 3
++  #define RX_OWNERR_CTL_B0_LBN 36
++  #define RX_OWNERR_CTL_B0_WIDTH 1
++  #define RX_XON_TX_TH_B0_LBN 31
++  #define RX_XON_TX_TH_B0_WIDTH 5
++  #define RX_XOFF_TX_TH_B0_LBN 26
++  #define RX_XOFF_TX_TH_B0_WIDTH 5
++  #define RX_USR_BUF_SIZE_B0_LBN 17
++  #define RX_USR_BUF_SIZE_B0_WIDTH 9
++  #define RX_XON_MAC_TH_B0_LBN 9
++  #define RX_XON_MAC_TH_B0_WIDTH 8
++  #define RX_XOFF_MAC_TH_B0_LBN 1
++  #define RX_XOFF_MAC_TH_B0_WIDTH 8
++  #define RX_XOFF_MAC_EN_B0_LBN 0
++  #define RX_XOFF_MAC_EN_B0_WIDTH 1
 +
-+      /*
-+       * Furthermore, we really only care to tell the guest about
-+       * address ranges that require address translation of some sort.
-+       */
-+      if (!(addr.resource_type == ACPI_MEMORY_RANGE &&
-+            addr.info.mem.translation) &&
-+          !(addr.resource_type == ACPI_IO_RANGE &&
-+            addr.info.io.translation))
-+              return AE_OK;
-+         
-+      /* Store the resource in xenbus for the guest */
-+      len = snprintf(str, sizeof(str), "root-%d-resource-%d",
-+                     info->root_num, info->resource_count);
-+      if (unlikely(len >= (sizeof(str) - 1)))
-+              return AE_OK;
++#else
++/* new for B0 */
++  #define RX_TOEP_TCP_SUPPRESS_B0_LBN 44
++  #define RX_TOEP_TCP_SUPPRESS_B0_WIDTH 1
++  #define RX_INGR_EN_B0_LBN 43
++  #define RX_INGR_EN_B0_WIDTH 1
++  #define RX_TOEP_IPV4_B0_LBN 42
++  #define RX_TOEP_IPV4_B0_WIDTH 1
++  #define RX_HASH_ALG_B0_LBN 41
++  #define RX_HASH_ALG_B0_WIDTH 41
++  #define RX_HASH_INSERT_HDR_B0_LBN 40
++  #define RX_HASH_INSERT_HDR_B0_WIDTH 1
++/* moved for B0 */
++  #define RX_DESC_PUSH_EN_B0_LBN 35
++  #define RX_DESC_PUSH_EN_B0_WIDTH 1
++  #define RX_PCI_BURST_SIZE_B0_LBN 35
++  #define RX_PCI_BURST_SIZE_B0_WIDTH 2
++  #define RX_OWNERR_CTL_B0_LBN 34
++  #define RX_OWNERR_CTL_B0_WIDTH 1
++  #define RX_XON_TX_TH_B0_LBN 29
++  #define RX_XON_TX_TH_B0_WIDTH 5
++  #define RX_XOFF_TX_TH_B0_LBN 24
++  #define RX_XOFF_TX_TH_B0_WIDTH 5
++  #define RX_USR_BUF_SIZE_B0_LBN 15
++  #define RX_USR_BUF_SIZE_B0_WIDTH 9
++  #define RX_XON_MAC_TH_B0_LBN 8
++  #define RX_XON_MAC_TH_B0_WIDTH 7
++  #define RX_XOFF_MAC_TH_B0_LBN 1
++  #define RX_XOFF_MAC_TH_B0_WIDTH 7
++  #define RX_XOFF_MAC_EN_B0_LBN 0
++  #define RX_XOFF_MAC_EN_B0_WIDTH 1
++
++#endif
++
++/* A0/A1 */
++  #define RX_PUSH_EN_A1_LBN 35
++  #define RX_PUSH_EN_A1_WIDTH 1
++  #define RX_PCI_BURST_SIZE_A1_LBN 31
++  #define RX_PCI_BURST_SIZE_A1_WIDTH 3
++  #define RX_OWNERR_CTL_A1_LBN 30
++  #define RX_OWNERR_CTL_A1_WIDTH 1
++  #define RX_XON_TX_TH_A1_LBN 25
++  #define RX_XON_TX_TH_A1_WIDTH 5
++  #define RX_XOFF_TX_TH_A1_LBN 20
++  #define RX_XOFF_TX_TH_A1_WIDTH 5
++  #define RX_USR_BUF_SIZE_A1_LBN 11
++  #define RX_USR_BUF_SIZE_A1_WIDTH 9
++  #define RX_XON_MAC_TH_A1_LBN 6
++  #define RX_XON_MAC_TH_A1_WIDTH 5
++  #define RX_XOFF_MAC_TH_A1_LBN 1
++  #define RX_XOFF_MAC_TH_A1_WIDTH 5
++  #define RX_XOFF_MAC_EN_A1_LBN 0
++  #define RX_XOFF_MAC_EN_A1_WIDTH 1
++
++#define RX_FILTER_CTL_REG_OFST 0x810 // Receive filter control registers
++  #define SCATTER_ENBL_NO_MATCH_Q_B0_LBN 40
++  #define SCATTER_ENBL_NO_MATCH_Q_B0_WIDTH 1
++  #define UDP_FULL_SRCH_LIMIT_LBN 32
++  #define UDP_FULL_SRCH_LIMIT_WIDTH 8
++  #define NUM_KER_LBN 24
++  #define NUM_KER_WIDTH 2
++  #define UDP_WILD_SRCH_LIMIT_LBN 16
++  #define UDP_WILD_SRCH_LIMIT_WIDTH 8
++  #define TCP_WILD_SRCH_LIMIT_LBN 8
++  #define TCP_WILD_SRCH_LIMIT_WIDTH 8
++  #define TCP_FULL_SRCH_LIMIT_LBN 0
++  #define TCP_FULL_SRCH_LIMIT_WIDTH 8
++#define RX_FLUSH_DESCQ_REG_KER_OFST 0x820 // Receive flush descriptor queue register
++#define RX_FLUSH_DESCQ_REG_OFST 0x820 // Receive flush descriptor queue register
++  #define RX_FLUSH_DESCQ_CMD_LBN 24
++  #define RX_FLUSH_DESCQ_CMD_WIDTH 1
++  #define RX_FLUSH_EVQ_ID_LBN 12
++  #define RX_FLUSH_EVQ_ID_WIDTH 12
++  #define RX_FLUSH_DESCQ_LBN 0
++  #define RX_FLUSH_DESCQ_WIDTH 12
++#define RX_DESC_UPD_REG_KER_OFST 0x830 // Kernel  receive descriptor update register. Page-mapped
++#define RX_DESC_UPD_REG_PAGE4_OFST 0x8830 // Char & user receive descriptor update register. Page-mapped. For lowest 1K queues.
++#define RX_DESC_UPD_REG_PAGE123K_OFST 0x1000830 // Char & user receive descriptor update register. Page-mapped. For upper 3K queues.
++  #define RX_DESC_WPTR_LBN 96
++  #define RX_DESC_WPTR_WIDTH 12
++  #define RX_DESC_PUSH_CMD_LBN 95
++  #define RX_DESC_PUSH_CMD_WIDTH 1
++  #define RX_DESC_LBN 0
++  #define RX_DESC_WIDTH 64
++  #define RX_KER_DESC_LBN 0
++  #define RX_KER_DESC_WIDTH 64
++  #define RX_USR_DESC_LBN 0
++  #define RX_USR_DESC_WIDTH 32
++#define RX_DC_CFG_REG_KER_OFST 0x840 // Receive descriptor cache configuration register
++#define RX_DC_CFG_REG_OFST 0x840 // Receive descriptor cache configuration register
++  #define RX_DC_SIZE_LBN 0
++  #define RX_DC_SIZE_WIDTH 2
++#define RX_DC_PF_WM_REG_KER_OFST 0x850 // Receive descriptor cache pre-fetch watermark register
++#define RX_DC_PF_WM_REG_OFST 0x850 // Receive descriptor cache pre-fetch watermark register
++  #define RX_DC_PF_LWM_LO_LBN 0
++  #define RX_DC_PF_LWM_LO_WIDTH 6
++
++#define RX_RSS_TKEY_B0_OFST 0x860 // RSS Toeplitz hash key (B0 only)
++
++#define RX_NODESC_DROP_REG 0x880
++  #define RX_NODESC_DROP_CNT_LBN 0
++  #define RX_NODESC_DROP_CNT_WIDTH 16
++
++#define XM_TX_CFG_REG_OFST 0x1230
++  #define XM_AUTO_PAD_LBN 5
++  #define XM_AUTO_PAD_WIDTH 1
++
++#define RX_FILTER_TBL0_OFST 0xF00000 // Receive filter table - even entries
++  #define RSS_EN_0_B0_LBN 110
++  #define RSS_EN_0_B0_WIDTH 1
++  #define SCATTER_EN_0_B0_LBN 109
++  #define SCATTER_EN_0_B0_WIDTH 1
++  #define TCP_UDP_0_LBN 108
++  #define TCP_UDP_0_WIDTH 1
++  #define RXQ_ID_0_LBN 96
++  #define RXQ_ID_0_WIDTH 12
++  #define DEST_IP_0_LBN 64
++  #define DEST_IP_0_WIDTH 32
++  #define DEST_PORT_TCP_0_LBN 48
++  #define DEST_PORT_TCP_0_WIDTH 16
++  #define SRC_IP_0_LBN 16
++  #define SRC_IP_0_WIDTH 32
++  #define SRC_TCP_DEST_UDP_0_LBN 0
++  #define SRC_TCP_DEST_UDP_0_WIDTH 16
++#define RX_FILTER_TBL1_OFST 0xF00010 // Receive filter table - odd entries
++  #define RSS_EN_1_B0_LBN 110
++  #define RSS_EN_1_B0_WIDTH 1
++  #define SCATTER_EN_1_B0_LBN 109
++  #define SCATTER_EN_1_B0_WIDTH 1
++  #define TCP_UDP_1_LBN 108
++  #define TCP_UDP_1_WIDTH 1
++  #define RXQ_ID_1_LBN 96
++  #define RXQ_ID_1_WIDTH 12
++  #define DEST_IP_1_LBN 64
++  #define DEST_IP_1_WIDTH 32
++  #define DEST_PORT_TCP_1_LBN 48
++  #define DEST_PORT_TCP_1_WIDTH 16
++  #define SRC_IP_1_LBN 16
++  #define SRC_IP_1_WIDTH 32
++  #define SRC_TCP_DEST_UDP_1_LBN 0
++  #define SRC_TCP_DEST_UDP_1_WIDTH 16
++
++#if EFVI_FALCON_EXTENDED_P_BAR
++#define RX_DESC_PTR_TBL_KER_OFST 0x11800 // Receive descriptor pointer kernel access
++#else
++#define RX_DESC_PTR_TBL_KER_OFST 0x1800 // Receive descriptor pointer kernel access
++#endif
++
++
++#define RX_DESC_PTR_TBL_OFST 0xF40000 // Receive descriptor pointer table
++  #define RX_ISCSI_DDIG_EN_LBN 88
++  #define RX_ISCSI_DDIG_EN_WIDTH 1
++  #define RX_ISCSI_HDIG_EN_LBN 87
++  #define RX_ISCSI_HDIG_EN_WIDTH 1
++  #define RX_DESC_PREF_ACT_LBN 86
++  #define RX_DESC_PREF_ACT_WIDTH 1
++  #define RX_DC_HW_RPTR_LBN 80
++  #define RX_DC_HW_RPTR_WIDTH 6
++  #define RX_DESCQ_HW_RPTR_LBN 68
++  #define RX_DESCQ_HW_RPTR_WIDTH 12
++  #define RX_DESCQ_SW_WPTR_LBN 56
++  #define RX_DESCQ_SW_WPTR_WIDTH 12
++  #define RX_DESCQ_BUF_BASE_ID_LBN 36
++  #define RX_DESCQ_BUF_BASE_ID_WIDTH 20
++  #define RX_DESCQ_EVQ_ID_LBN 24
++  #define RX_DESCQ_EVQ_ID_WIDTH 12
++  #define RX_DESCQ_OWNER_ID_LBN 10
++  #define RX_DESCQ_OWNER_ID_WIDTH 14
++  #define RX_DESCQ_LABEL_LBN 5
++  #define RX_DESCQ_LABEL_WIDTH 5
++  #define RX_DESCQ_SIZE_LBN 3
++  #define RX_DESCQ_SIZE_WIDTH 2
++  #define RX_DESCQ_TYPE_LBN 2
++  #define RX_DESCQ_TYPE_WIDTH 1
++  #define RX_DESCQ_JUMBO_LBN 1
++  #define RX_DESCQ_JUMBO_WIDTH 1
++  #define RX_DESCQ_EN_LBN 0
++  #define RX_DESCQ_EN_WIDTH 1
++
++
++#define RX_RSS_INDIR_TBL_B0_OFST 0xFB0000 // RSS indirection table (B0 only)
++  #define RX_RSS_INDIR_ENT_B0_LBN 0
++  #define RX_RSS_INDIR_ENT_B0_WIDTH 6
++
++//////////////---- TX Datapath Registers C Header ----//////////////
++#define TX_FLUSH_DESCQ_REG_KER_OFST 0xA00 // Transmit flush descriptor queue register
++#define TX_FLUSH_DESCQ_REG_OFST 0xA00 // Transmit flush descriptor queue register
++  #define TX_FLUSH_DESCQ_CMD_LBN 12
++  #define TX_FLUSH_DESCQ_CMD_WIDTH 1
++  #define TX_FLUSH_DESCQ_LBN 0
++  #define TX_FLUSH_DESCQ_WIDTH 12
++#define TX_DESC_UPD_REG_KER_OFST 0xA10 // Kernel transmit descriptor update register. Page-mapped
++#define TX_DESC_UPD_REG_PAGE4_OFST 0x8A10 // Char & user transmit descriptor update register. Page-mapped
++#define TX_DESC_UPD_REG_PAGE123K_OFST 0x1000A10 // Char & user transmit descriptor update register. Page-mapped
++  #define TX_DESC_WPTR_LBN 96
++  #define TX_DESC_WPTR_WIDTH 12
++  #define TX_DESC_PUSH_CMD_LBN 95
++  #define TX_DESC_PUSH_CMD_WIDTH 1
++  #define TX_DESC_LBN 0
++  #define TX_DESC_WIDTH 95
++  #define TX_KER_DESC_LBN 0
++  #define TX_KER_DESC_WIDTH 64
++  #define TX_USR_DESC_LBN 0
++  #define TX_USR_DESC_WIDTH 64
++#define TX_DC_CFG_REG_KER_OFST 0xA20 // Transmit descriptor cache configuration register
++#define TX_DC_CFG_REG_OFST 0xA20 // Transmit descriptor cache configuration register
++  #define TX_DC_SIZE_LBN 0
++  #define TX_DC_SIZE_WIDTH 2
++
++#if EFVI_FALCON_EXTENDED_P_BAR
++#define TX_DESC_PTR_TBL_KER_OFST 0x11900 // Transmit descriptor pointer.
++#else
++#define TX_DESC_PTR_TBL_KER_OFST 0x1900 // Transmit descriptor pointer.
++#endif
++
++
++#define TX_DESC_PTR_TBL_OFST 0xF50000 // Transmit descriptor pointer
++  #define TX_NON_IP_DROP_DIS_B0_LBN 91
++  #define TX_NON_IP_DROP_DIS_B0_WIDTH 1
++  #define TX_IP_CHKSM_DIS_B0_LBN 90
++  #define TX_IP_CHKSM_DIS_B0_WIDTH 1
++  #define TX_TCP_CHKSM_DIS_B0_LBN 89
++  #define TX_TCP_CHKSM_DIS_B0_WIDTH 1
++  #define TX_DESCQ_EN_LBN 88
++  #define TX_DESCQ_EN_WIDTH 1
++  #define TX_ISCSI_DDIG_EN_LBN 87
++  #define TX_ISCSI_DDIG_EN_WIDTH 1
++  #define TX_ISCSI_HDIG_EN_LBN 86
++  #define TX_ISCSI_HDIG_EN_WIDTH 1
++  #define TX_DC_HW_RPTR_LBN 80
++  #define TX_DC_HW_RPTR_WIDTH 6
++  #define TX_DESCQ_HW_RPTR_LBN 68
++  #define TX_DESCQ_HW_RPTR_WIDTH 12
++  #define TX_DESCQ_SW_WPTR_LBN 56
++  #define TX_DESCQ_SW_WPTR_WIDTH 12
++  #define TX_DESCQ_BUF_BASE_ID_LBN 36
++  #define TX_DESCQ_BUF_BASE_ID_WIDTH 20
++  #define TX_DESCQ_EVQ_ID_LBN 24
++  #define TX_DESCQ_EVQ_ID_WIDTH 12
++  #define TX_DESCQ_OWNER_ID_LBN 10
++  #define TX_DESCQ_OWNER_ID_WIDTH 14
++  #define TX_DESCQ_LABEL_LBN 5
++  #define TX_DESCQ_LABEL_WIDTH 5
++  #define TX_DESCQ_SIZE_LBN 3
++  #define TX_DESCQ_SIZE_WIDTH 2
++  #define TX_DESCQ_TYPE_LBN 1
++  #define TX_DESCQ_TYPE_WIDTH 2
++  #define TX_DESCQ_FLUSH_LBN 0
++  #define TX_DESCQ_FLUSH_WIDTH 1
++#define TX_CFG_REG_KER_OFST 0xA50 // Transmit configuration register
++#define TX_CFG_REG_OFST 0xA50 // Transmit configuration register
++  #define TX_IP_ID_P1_OFS_LBN 32
++  #define TX_IP_ID_P1_OFS_WIDTH 15
++  #define TX_IP_ID_P0_OFS_LBN 16
++  #define TX_IP_ID_P0_OFS_WIDTH 15
++  #define TX_TURBO_EN_LBN 3
++  #define TX_TURBO_EN_WIDTH 1 
++  #define TX_OWNERR_CTL_LBN 2
++  #define TX_OWNERR_CTL_WIDTH 2
++  #define TX_NON_IP_DROP_DIS_LBN 1
++  #define TX_NON_IP_DROP_DIS_WIDTH 1
++  #define TX_IP_ID_REP_EN_LBN 0
++  #define TX_IP_ID_REP_EN_WIDTH 1
++#define TX_RESERVED_REG_KER_OFST 0xA80 // Transmit configuration register
++#define TX_RESERVED_REG_OFST 0xA80 // Transmit configuration register
++  #define TX_CSR_PUSH_EN_LBN 89
++  #define TX_CSR_PUSH_EN_WIDTH 1
++  #define TX_RX_SPACER_LBN 64
++  #define TX_RX_SPACER_WIDTH 8
++  #define TX_SW_EV_EN_LBN 59
++  #define TX_SW_EV_EN_WIDTH 1
++  #define TX_RX_SPACER_EN_LBN 57
++  #define TX_RX_SPACER_EN_WIDTH 1
++  #define TX_CSR_PREF_WD_TMR_LBN 24
++  #define TX_CSR_PREF_WD_TMR_WIDTH 16
++  #define TX_CSR_ONLY1TAG_LBN 21
++  #define TX_CSR_ONLY1TAG_WIDTH 1
++  #define TX_PREF_THRESHOLD_LBN 19
++  #define TX_PREF_THRESHOLD_WIDTH 2
++  #define TX_ONE_PKT_PER_Q_LBN 18
++  #define TX_ONE_PKT_PER_Q_WIDTH 1
++  #define TX_DIS_NON_IP_EV_LBN 17
++  #define TX_DIS_NON_IP_EV_WIDTH 1
++  #define TX_DMA_SPACER_LBN 8
++  #define TX_DMA_SPACER_WIDTH 8
++  #define TX_FLUSH_MIN_LEN_EN_B0_LBN 7
++  #define TX_FLUSH_MIN_LEN_EN_B0_WIDTH 1
++  #define TX_TCP_DIS_A1_LBN 7
++  #define TX_TCP_DIS_A1_WIDTH 1
++  #define TX_IP_DIS_A1_LBN 6
++  #define TX_IP_DIS_A1_WIDTH 1
++  #define TX_MAX_CPL_LBN 2
++  #define TX_MAX_CPL_WIDTH 2
++  #define TX_MAX_PREF_LBN 0
++  #define TX_MAX_PREF_WIDTH 2
++#define TX_VLAN_REG_OFST 0xAE0 // Transmit VLAN tag register
++  #define TX_VLAN_EN_LBN 127
++  #define TX_VLAN_EN_WIDTH 1
++  #define TX_VLAN7_PORT1_EN_LBN 125
++  #define TX_VLAN7_PORT1_EN_WIDTH 1
++  #define TX_VLAN7_PORT0_EN_LBN 124
++  #define TX_VLAN7_PORT0_EN_WIDTH 1
++  #define TX_VLAN7_LBN 112
++  #define TX_VLAN7_WIDTH 12
++  #define TX_VLAN6_PORT1_EN_LBN 109
++  #define TX_VLAN6_PORT1_EN_WIDTH 1
++  #define TX_VLAN6_PORT0_EN_LBN 108
++  #define TX_VLAN6_PORT0_EN_WIDTH 1
++  #define TX_VLAN6_LBN 96
++  #define TX_VLAN6_WIDTH 12
++  #define TX_VLAN5_PORT1_EN_LBN 93
++  #define TX_VLAN5_PORT1_EN_WIDTH 1
++  #define TX_VLAN5_PORT0_EN_LBN 92
++  #define TX_VLAN5_PORT0_EN_WIDTH 1
++  #define TX_VLAN5_LBN 80
++  #define TX_VLAN5_WIDTH 12
++  #define TX_VLAN4_PORT1_EN_LBN 77
++  #define TX_VLAN4_PORT1_EN_WIDTH 1
++  #define TX_VLAN4_PORT0_EN_LBN 76
++  #define TX_VLAN4_PORT0_EN_WIDTH 1
++  #define TX_VLAN4_LBN 64
++  #define TX_VLAN4_WIDTH 12
++  #define TX_VLAN3_PORT1_EN_LBN 61
++  #define TX_VLAN3_PORT1_EN_WIDTH 1
++  #define TX_VLAN3_PORT0_EN_LBN 60
++  #define TX_VLAN3_PORT0_EN_WIDTH 1
++  #define TX_VLAN3_LBN 48
++  #define TX_VLAN3_WIDTH 12
++  #define TX_VLAN2_PORT1_EN_LBN 45
++  #define TX_VLAN2_PORT1_EN_WIDTH 1
++  #define TX_VLAN2_PORT0_EN_LBN 44
++  #define TX_VLAN2_PORT0_EN_WIDTH 1
++  #define TX_VLAN2_LBN 32
++  #define TX_VLAN2_WIDTH 12
++  #define TX_VLAN1_PORT1_EN_LBN 29
++  #define TX_VLAN1_PORT1_EN_WIDTH 1
++  #define TX_VLAN1_PORT0_EN_LBN 28
++  #define TX_VLAN1_PORT0_EN_WIDTH 1
++  #define TX_VLAN1_LBN 16
++  #define TX_VLAN1_WIDTH 12
++  #define TX_VLAN0_PORT1_EN_LBN 13
++  #define TX_VLAN0_PORT1_EN_WIDTH 1
++  #define TX_VLAN0_PORT0_EN_LBN 12
++  #define TX_VLAN0_PORT0_EN_WIDTH 1
++  #define TX_VLAN0_LBN 0
++  #define TX_VLAN0_WIDTH 12
++#define TX_FIL_CTL_REG_OFST 0xAF0 // Transmit filter control register
++  #define TX_MADR1_FIL_EN_LBN 65
++  #define TX_MADR1_FIL_EN_WIDTH 1
++  #define TX_MADR0_FIL_EN_LBN 64
++  #define TX_MADR0_FIL_EN_WIDTH 1
++  #define TX_IPFIL31_PORT1_EN_LBN 63
++  #define TX_IPFIL31_PORT1_EN_WIDTH 1
++  #define TX_IPFIL31_PORT0_EN_LBN 62
++  #define TX_IPFIL31_PORT0_EN_WIDTH 1
++  #define TX_IPFIL30_PORT1_EN_LBN 61
++  #define TX_IPFIL30_PORT1_EN_WIDTH 1
++  #define TX_IPFIL30_PORT0_EN_LBN 60
++  #define TX_IPFIL30_PORT0_EN_WIDTH 1
++  #define TX_IPFIL29_PORT1_EN_LBN 59
++  #define TX_IPFIL29_PORT1_EN_WIDTH 1
++  #define TX_IPFIL29_PORT0_EN_LBN 58
++  #define TX_IPFIL29_PORT0_EN_WIDTH 1
++  #define TX_IPFIL28_PORT1_EN_LBN 57
++  #define TX_IPFIL28_PORT1_EN_WIDTH 1
++  #define TX_IPFIL28_PORT0_EN_LBN 56
++  #define TX_IPFIL28_PORT0_EN_WIDTH 1
++  #define TX_IPFIL27_PORT1_EN_LBN 55
++  #define TX_IPFIL27_PORT1_EN_WIDTH 1
++  #define TX_IPFIL27_PORT0_EN_LBN 54
++  #define TX_IPFIL27_PORT0_EN_WIDTH 1
++  #define TX_IPFIL26_PORT1_EN_LBN 53
++  #define TX_IPFIL26_PORT1_EN_WIDTH 1
++  #define TX_IPFIL26_PORT0_EN_LBN 52
++  #define TX_IPFIL26_PORT0_EN_WIDTH 1
++  #define TX_IPFIL25_PORT1_EN_LBN 51
++  #define TX_IPFIL25_PORT1_EN_WIDTH 1
++  #define TX_IPFIL25_PORT0_EN_LBN 50
++  #define TX_IPFIL25_PORT0_EN_WIDTH 1
++  #define TX_IPFIL24_PORT1_EN_LBN 49
++  #define TX_IPFIL24_PORT1_EN_WIDTH 1
++  #define TX_IPFIL24_PORT0_EN_LBN 48
++  #define TX_IPFIL24_PORT0_EN_WIDTH 1
++  #define TX_IPFIL23_PORT1_EN_LBN 47
++  #define TX_IPFIL23_PORT1_EN_WIDTH 1
++  #define TX_IPFIL23_PORT0_EN_LBN 46
++  #define TX_IPFIL23_PORT0_EN_WIDTH 1
++  #define TX_IPFIL22_PORT1_EN_LBN 45
++  #define TX_IPFIL22_PORT1_EN_WIDTH 1
++  #define TX_IPFIL22_PORT0_EN_LBN 44
++  #define TX_IPFIL22_PORT0_EN_WIDTH 1
++  #define TX_IPFIL21_PORT1_EN_LBN 43
++  #define TX_IPFIL21_PORT1_EN_WIDTH 1
++  #define TX_IPFIL21_PORT0_EN_LBN 42
++  #define TX_IPFIL21_PORT0_EN_WIDTH 1
++  #define TX_IPFIL20_PORT1_EN_LBN 41
++  #define TX_IPFIL20_PORT1_EN_WIDTH 1
++  #define TX_IPFIL20_PORT0_EN_LBN 40
++  #define TX_IPFIL20_PORT0_EN_WIDTH 1
++  #define TX_IPFIL19_PORT1_EN_LBN 39
++  #define TX_IPFIL19_PORT1_EN_WIDTH 1
++  #define TX_IPFIL19_PORT0_EN_LBN 38
++  #define TX_IPFIL19_PORT0_EN_WIDTH 1
++  #define TX_IPFIL18_PORT1_EN_LBN 37
++  #define TX_IPFIL18_PORT1_EN_WIDTH 1
++  #define TX_IPFIL18_PORT0_EN_LBN 36
++  #define TX_IPFIL18_PORT0_EN_WIDTH 1
++  #define TX_IPFIL17_PORT1_EN_LBN 35
++  #define TX_IPFIL17_PORT1_EN_WIDTH 1
++  #define TX_IPFIL17_PORT0_EN_LBN 34
++  #define TX_IPFIL17_PORT0_EN_WIDTH 1
++  #define TX_IPFIL16_PORT1_EN_LBN 33
++  #define TX_IPFIL16_PORT1_EN_WIDTH 1
++  #define TX_IPFIL16_PORT0_EN_LBN 32
++  #define TX_IPFIL16_PORT0_EN_WIDTH 1
++  #define TX_IPFIL15_PORT1_EN_LBN 31
++  #define TX_IPFIL15_PORT1_EN_WIDTH 1
++  #define TX_IPFIL15_PORT0_EN_LBN 30
++  #define TX_IPFIL15_PORT0_EN_WIDTH 1
++  #define TX_IPFIL14_PORT1_EN_LBN 29
++  #define TX_IPFIL14_PORT1_EN_WIDTH 1
++  #define TX_IPFIL14_PORT0_EN_LBN 28
++  #define TX_IPFIL14_PORT0_EN_WIDTH 1
++  #define TX_IPFIL13_PORT1_EN_LBN 27
++  #define TX_IPFIL13_PORT1_EN_WIDTH 1
++  #define TX_IPFIL13_PORT0_EN_LBN 26
++  #define TX_IPFIL13_PORT0_EN_WIDTH 1
++  #define TX_IPFIL12_PORT1_EN_LBN 25
++  #define TX_IPFIL12_PORT1_EN_WIDTH 1
++  #define TX_IPFIL12_PORT0_EN_LBN 24
++  #define TX_IPFIL12_PORT0_EN_WIDTH 1
++  #define TX_IPFIL11_PORT1_EN_LBN 23
++  #define TX_IPFIL11_PORT1_EN_WIDTH 1
++  #define TX_IPFIL11_PORT0_EN_LBN 22
++  #define TX_IPFIL11_PORT0_EN_WIDTH 1
++  #define TX_IPFIL10_PORT1_EN_LBN 21
++  #define TX_IPFIL10_PORT1_EN_WIDTH 1
++  #define TX_IPFIL10_PORT0_EN_LBN 20
++  #define TX_IPFIL10_PORT0_EN_WIDTH 1
++  #define TX_IPFIL9_PORT1_EN_LBN 19
++  #define TX_IPFIL9_PORT1_EN_WIDTH 1
++  #define TX_IPFIL9_PORT0_EN_LBN 18
++  #define TX_IPFIL9_PORT0_EN_WIDTH 1
++  #define TX_IPFIL8_PORT1_EN_LBN 17
++  #define TX_IPFIL8_PORT1_EN_WIDTH 1
++  #define TX_IPFIL8_PORT0_EN_LBN 16
++  #define TX_IPFIL8_PORT0_EN_WIDTH 1
++  #define TX_IPFIL7_PORT1_EN_LBN 15
++  #define TX_IPFIL7_PORT1_EN_WIDTH 1
++  #define TX_IPFIL7_PORT0_EN_LBN 14
++  #define TX_IPFIL7_PORT0_EN_WIDTH 1
++  #define TX_IPFIL6_PORT1_EN_LBN 13
++  #define TX_IPFIL6_PORT1_EN_WIDTH 1
++  #define TX_IPFIL6_PORT0_EN_LBN 12
++  #define TX_IPFIL6_PORT0_EN_WIDTH 1
++  #define TX_IPFIL5_PORT1_EN_LBN 11
++  #define TX_IPFIL5_PORT1_EN_WIDTH 1
++  #define TX_IPFIL5_PORT0_EN_LBN 10
++  #define TX_IPFIL5_PORT0_EN_WIDTH 1
++  #define TX_IPFIL4_PORT1_EN_LBN 9
++  #define TX_IPFIL4_PORT1_EN_WIDTH 1
++  #define TX_IPFIL4_PORT0_EN_LBN 8
++  #define TX_IPFIL4_PORT0_EN_WIDTH 1
++  #define TX_IPFIL3_PORT1_EN_LBN 7
++  #define TX_IPFIL3_PORT1_EN_WIDTH 1
++  #define TX_IPFIL3_PORT0_EN_LBN 6
++  #define TX_IPFIL3_PORT0_EN_WIDTH 1
++  #define TX_IPFIL2_PORT1_EN_LBN 5
++  #define TX_IPFIL2_PORT1_EN_WIDTH 1
++  #define TX_IPFIL2_PORT0_EN_LBN 4
++  #define TX_IPFIL2_PORT0_EN_WIDTH 1
++  #define TX_IPFIL1_PORT1_EN_LBN 3
++  #define TX_IPFIL1_PORT1_EN_WIDTH 1
++  #define TX_IPFIL1_PORT0_EN_LBN 2
++  #define TX_IPFIL1_PORT0_EN_WIDTH 1
++  #define TX_IPFIL0_PORT1_EN_LBN 1
++  #define TX_IPFIL0_PORT1_EN_WIDTH 1
++  #define TX_IPFIL0_PORT0_EN_LBN 0
++  #define TX_IPFIL0_PORT0_EN_WIDTH 1
++#define TX_IPFIL_TBL_OFST 0xB00 // Transmit IP source address filter table
++  #define TX_IPFIL_MASK_LBN 32
++  #define TX_IPFIL_MASK_WIDTH 32
++  #define TX_IP_SRC_ADR_LBN 0
++  #define TX_IP_SRC_ADR_WIDTH 32
++#define TX_PACE_REG_A1_OFST 0xF80000 // Transmit pace control register
++#define TX_PACE_REG_B0_OFST 0xA90    // Transmit pace control register
++  #define TX_PACE_SB_AF_LBN 19
++  #define TX_PACE_SB_AF_WIDTH 10
++  #define TX_PACE_SB_NOTAF_LBN 9
++  #define TX_PACE_SB_NOTAF_WIDTH 10
++  #define TX_PACE_FB_BASE_LBN 5
++  #define TX_PACE_FB_BASE_WIDTH 4
++  #define TX_PACE_BIN_TH_LBN 0
++  #define TX_PACE_BIN_TH_WIDTH 5
++#define TX_PACE_TBL_A1_OFST 0xF80040 // Transmit pacing table
++#define TX_PACE_TBL_FIRST_QUEUE_A1 4
++#define TX_PACE_TBL_B0_OFST 0xF80000 // Transmit pacing table
++#define TX_PACE_TBL_FIRST_QUEUE_B0 0
++  #define TX_PACE_LBN 0
++  #define TX_PACE_WIDTH 5
++
++//////////////---- EE/Flash Registers C Header ----//////////////
++#define EE_SPI_HCMD_REG_KER_OFST 0x100 // SPI host command register
++#define EE_SPI_HCMD_REG_OFST 0x100 // SPI host command register
++  #define EE_SPI_HCMD_CMD_EN_LBN 31
++  #define EE_SPI_HCMD_CMD_EN_WIDTH 1
++  #define EE_WR_TIMER_ACTIVE_LBN 28
++  #define EE_WR_TIMER_ACTIVE_WIDTH 1
++  #define EE_SPI_HCMD_SF_SEL_LBN 24
++  #define EE_SPI_HCMD_SF_SEL_WIDTH 1
++  #define EE_SPI_HCMD_DABCNT_LBN 16
++  #define EE_SPI_HCMD_DABCNT_WIDTH 5
++  #define EE_SPI_HCMD_READ_LBN 15
++  #define EE_SPI_HCMD_READ_WIDTH 1
++  #define EE_SPI_HCMD_DUBCNT_LBN 12
++  #define EE_SPI_HCMD_DUBCNT_WIDTH 2
++  #define EE_SPI_HCMD_ADBCNT_LBN 8
++  #define EE_SPI_HCMD_ADBCNT_WIDTH 2
++  #define EE_SPI_HCMD_ENC_LBN 0
++  #define EE_SPI_HCMD_ENC_WIDTH 8
++#define EE_SPI_HADR_REG_KER_OFST 0X110 // SPI host address register
++#define EE_SPI_HADR_REG_OFST 0X110 // SPI host address register
++  #define EE_SPI_HADR_DUBYTE_LBN 24
++  #define EE_SPI_HADR_DUBYTE_WIDTH 8
++  #define EE_SPI_HADR_ADR_LBN 0
++  #define EE_SPI_HADR_ADR_WIDTH 24
++#define EE_SPI_HDATA_REG_KER_OFST 0x120 // SPI host data register
++#define EE_SPI_HDATA_REG_OFST 0x120 // SPI host data register
++  #define EE_SPI_HDATA3_LBN 96
++  #define EE_SPI_HDATA3_WIDTH 32
++  #define EE_SPI_HDATA2_LBN 64
++  #define EE_SPI_HDATA2_WIDTH 32
++  #define EE_SPI_HDATA1_LBN 32
++  #define EE_SPI_HDATA1_WIDTH 32
++  #define EE_SPI_HDATA0_LBN 0
++  #define EE_SPI_HDATA0_WIDTH 32
++#define EE_BASE_PAGE_REG_KER_OFST 0x130 // Expansion ROM base mirror register
++#define EE_BASE_PAGE_REG_OFST 0x130 // Expansion ROM base mirror register
++  #define EE_EXP_ROM_WINDOW_BASE_LBN 16
++  #define EE_EXP_ROM_WINDOW_BASE_WIDTH 13
++  #define EE_EXPROM_MASK_LBN 0
++  #define EE_EXPROM_MASK_WIDTH 13
++#define EE_VPD_CFG0_REG_KER_OFST 0X140 // SPI/VPD configuration register
++#define EE_VPD_CFG0_REG_OFST 0X140 // SPI/VPD configuration register
++  #define EE_SF_FASTRD_EN_LBN 127
++  #define EE_SF_FASTRD_EN_WIDTH 1
++  #define EE_SF_CLOCK_DIV_LBN 120
++  #define EE_SF_CLOCK_DIV_WIDTH 7
++  #define EE_VPD_WIP_POLL_LBN 119
++  #define EE_VPD_WIP_POLL_WIDTH 1
++  #define EE_VPDW_LENGTH_LBN 80
++  #define EE_VPDW_LENGTH_WIDTH 15
++  #define EE_VPDW_BASE_LBN 64
++  #define EE_VPDW_BASE_WIDTH 15
++  #define EE_VPD_WR_CMD_EN_LBN 56
++  #define EE_VPD_WR_CMD_EN_WIDTH 8
++  #define EE_VPD_BASE_LBN 32
++  #define EE_VPD_BASE_WIDTH 24
++  #define EE_VPD_LENGTH_LBN 16
++  #define EE_VPD_LENGTH_WIDTH 13
++  #define EE_VPD_AD_SIZE_LBN 8
++  #define EE_VPD_AD_SIZE_WIDTH 5
++  #define EE_VPD_ACCESS_ON_LBN 5
++  #define EE_VPD_ACCESS_ON_WIDTH 1
++#define EE_VPD_SW_CNTL_REG_KER_OFST 0X150 // VPD access SW control register
++#define EE_VPD_SW_CNTL_REG_OFST 0X150 // VPD access SW control register
++  #define EE_VPD_CYCLE_PENDING_LBN 31
++  #define EE_VPD_CYCLE_PENDING_WIDTH 1
++  #define EE_VPD_CYC_WRITE_LBN 28
++  #define EE_VPD_CYC_WRITE_WIDTH 1
++  #define EE_VPD_CYC_ADR_LBN 0
++  #define EE_VPD_CYC_ADR_WIDTH 15
++#define EE_VPD_SW_DATA_REG_KER_OFST 0x160 // VPD access SW data register
++#define EE_VPD_SW_DATA_REG_OFST 0x160 // VPD access SW data register
++  #define EE_VPD_CYC_DAT_LBN 0
++  #define EE_VPD_CYC_DAT_WIDTH 32
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/ef_vi_falcon_desc.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/ef_vi_falcon_desc.h   2008-05-19 00:33:48.674951800 +0300
+@@ -0,0 +1,43 @@
++//////////////---- Descriptors C Headers ----//////////////
++// Receive Kernel IP Descriptor
++  #define RX_KER_BUF_SIZE_LBN 48
++  #define RX_KER_BUF_SIZE_WIDTH 14
++  #define RX_KER_BUF_REGION_LBN 46
++  #define RX_KER_BUF_REGION_WIDTH 2
++      #define RX_KER_BUF_REGION0_DECODE 0
++      #define RX_KER_BUF_REGION1_DECODE 1
++      #define RX_KER_BUF_REGION2_DECODE 2
++      #define RX_KER_BUF_REGION3_DECODE 3
++  #define RX_KER_BUF_ADR_LBN 0
++  #define RX_KER_BUF_ADR_WIDTH 46
++// Receive User IP Descriptor
++  #define RX_USR_2BYTE_OFS_LBN 20
++  #define RX_USR_2BYTE_OFS_WIDTH 12
++  #define RX_USR_BUF_ID_LBN 0
++  #define RX_USR_BUF_ID_WIDTH 20
++// Transmit Kernel IP Descriptor
++  #define TX_KER_PORT_LBN 63
++  #define TX_KER_PORT_WIDTH 1
++  #define TX_KER_CONT_LBN 62
++  #define TX_KER_CONT_WIDTH 1
++  #define TX_KER_BYTE_CNT_LBN 48
++  #define TX_KER_BYTE_CNT_WIDTH 14
++  #define TX_KER_BUF_REGION_LBN 46
++  #define TX_KER_BUF_REGION_WIDTH 2
++      #define TX_KER_BUF_REGION0_DECODE 0
++      #define TX_KER_BUF_REGION1_DECODE 1
++      #define TX_KER_BUF_REGION2_DECODE 2
++      #define TX_KER_BUF_REGION3_DECODE 3
++  #define TX_KER_BUF_ADR_LBN 0
++  #define TX_KER_BUF_ADR_WIDTH 46
++// Transmit User IP Descriptor
++  #define TX_USR_PORT_LBN 47
++  #define TX_USR_PORT_WIDTH 1
++  #define TX_USR_CONT_LBN 46
++  #define TX_USR_CONT_WIDTH 1
++  #define TX_USR_BYTE_CNT_LBN 33
++  #define TX_USR_BYTE_CNT_WIDTH 13
++  #define TX_USR_BUF_ID_LBN 13
++  #define TX_USR_BUF_ID_WIDTH 20
++  #define TX_USR_BYTE_OFS_LBN 0
++  #define TX_USR_BYTE_OFS_WIDTH 13
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/ef_vi_falcon_event.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/ef_vi_falcon_event.h  2008-05-19 00:33:48.674951800 +0300
+@@ -0,0 +1,123 @@
++//////////////---- Events Format C Header ----//////////////
++//////////////---- Event entry ----//////////////
++  #define EV_CODE_LBN 60
++  #define EV_CODE_WIDTH 4
++      #define RX_IP_EV_DECODE 0
++      #define TX_IP_EV_DECODE 2
++      #define DRIVER_EV_DECODE 5
++      #define GLOBAL_EV_DECODE 6
++      #define DRV_GEN_EV_DECODE 7
++  #define EV_DATA_LBN 0
++  #define EV_DATA_WIDTH 60
++//////////////---- Receive IP events for both Kernel & User event queues ----//////////////
++  #define RX_EV_PKT_OK_LBN 56
++  #define RX_EV_PKT_OK_WIDTH 1
++  #define RX_EV_BUF_OWNER_ID_ERR_LBN 54
++  #define RX_EV_BUF_OWNER_ID_ERR_WIDTH 1
++  #define RX_EV_IP_HDR_CHKSUM_ERR_LBN 52
++  #define RX_EV_IP_HDR_CHKSUM_ERR_WIDTH 1
++  #define RX_EV_TCP_UDP_CHKSUM_ERR_LBN 51
++  #define RX_EV_TCP_UDP_CHKSUM_ERR_WIDTH 1
++  #define RX_EV_ETH_CRC_ERR_LBN 50
++  #define RX_EV_ETH_CRC_ERR_WIDTH 1
++  #define RX_EV_FRM_TRUNC_LBN 49
++  #define RX_EV_FRM_TRUNC_WIDTH 1
++  #define RX_EV_DRIB_NIB_LBN 48
++  #define RX_EV_DRIB_NIB_WIDTH 1
++  #define RX_EV_TOBE_DISC_LBN 47
++  #define RX_EV_TOBE_DISC_WIDTH 1
++  #define RX_EV_PKT_TYPE_LBN 44
++  #define RX_EV_PKT_TYPE_WIDTH 3
++      #define RX_EV_PKT_TYPE_ETH_DECODE 0
++      #define RX_EV_PKT_TYPE_LLC_DECODE 1
++      #define RX_EV_PKT_TYPE_JUMBO_DECODE 2
++      #define RX_EV_PKT_TYPE_VLAN_DECODE 3
++      #define RX_EV_PKT_TYPE_VLAN_LLC_DECODE 4
++      #define RX_EV_PKT_TYPE_VLAN_JUMBO_DECODE 5
++  #define RX_EV_HDR_TYPE_LBN 42
++  #define RX_EV_HDR_TYPE_WIDTH 2
++      #define RX_EV_HDR_TYPE_TCP_IPV4_DECODE 0
++      #define RX_EV_HDR_TYPE_UDP_IPV4_DECODE 1
++      #define RX_EV_HDR_TYPE_OTHER_IP_DECODE 2
++      #define RX_EV_HDR_TYPE_NON_IP_DECODE 3
++  #define RX_EV_DESC_Q_EMPTY_LBN 41
++  #define RX_EV_DESC_Q_EMPTY_WIDTH 1
++  #define RX_EV_MCAST_HASH_MATCH_LBN 40
++  #define RX_EV_MCAST_HASH_MATCH_WIDTH 1
++  #define RX_EV_MCAST_PKT_LBN 39
++  #define RX_EV_MCAST_PKT_WIDTH 1
++  #define RX_EV_Q_LABEL_LBN 32
++  #define RX_EV_Q_LABEL_WIDTH 5
++  #define RX_JUMBO_CONT_LBN 31
++  #define RX_JUMBO_CONT_WIDTH 1
++  #define RX_SOP_LBN 15
++  #define RX_SOP_WIDTH 1
++  #define RX_PORT_LBN 30
++  #define RX_PORT_WIDTH 1
++  #define RX_EV_BYTE_CNT_LBN 16
++  #define RX_EV_BYTE_CNT_WIDTH 14
++  #define RX_iSCSI_PKT_OK_LBN 14
++  #define RX_iSCSI_PKT_OK_WIDTH 1
++  #define RX_ISCSI_DDIG_ERR_LBN 13
++  #define RX_ISCSI_DDIG_ERR_WIDTH 1
++  #define RX_ISCSI_HDIG_ERR_LBN 12
++  #define RX_ISCSI_HDIG_ERR_WIDTH 1
++  #define RX_EV_DESC_PTR_LBN 0
++  #define RX_EV_DESC_PTR_WIDTH 12
++//////////////---- Transmit IP events for both Kernel & User event queues ----//////////////
++  #define TX_EV_PKT_ERR_LBN 38
++  #define TX_EV_PKT_ERR_WIDTH 1
++  #define TX_EV_PKT_TOO_BIG_LBN 37
++  #define TX_EV_PKT_TOO_BIG_WIDTH 1
++  #define TX_EV_Q_LABEL_LBN 32
++  #define TX_EV_Q_LABEL_WIDTH 5
++  #define TX_EV_PORT_LBN 16
++  #define TX_EV_PORT_WIDTH 1
++  #define TX_EV_WQ_FF_FULL_LBN 15
++  #define TX_EV_WQ_FF_FULL_WIDTH 1
++  #define TX_EV_BUF_OWNER_ID_ERR_LBN 14
++  #define TX_EV_BUF_OWNER_ID_ERR_WIDTH 1
++  #define TX_EV_COMP_LBN 12
++  #define TX_EV_COMP_WIDTH 1
++  #define TX_EV_DESC_PTR_LBN 0
++  #define TX_EV_DESC_PTR_WIDTH 12
++//////////////---- Char or Kernel driver events ----//////////////
++  #define DRIVER_EV_SUB_CODE_LBN 56
++  #define DRIVER_EV_SUB_CODE_WIDTH 4
++      #define TX_DESCQ_FLS_DONE_EV_DECODE 0x0
++      #define RX_DESCQ_FLS_DONE_EV_DECODE 0x1
++      #define EVQ_INIT_DONE_EV_DECODE 0x2
++      #define EVQ_NOT_EN_EV_DECODE 0x3
++      #define RX_DESCQ_FLSFF_OVFL_EV_DECODE 0x4
++      #define SRM_UPD_DONE_EV_DECODE 0x5
++      #define WAKE_UP_EV_DECODE 0x6
++      #define TX_PKT_NON_TCP_UDP_DECODE 0x9
++      #define TIMER_EV_DECODE 0xA
++      #define RX_DSC_ERROR_EV_DECODE 0xE
++  #define DRIVER_EV_TX_DESCQ_ID_LBN 0
++  #define DRIVER_EV_TX_DESCQ_ID_WIDTH 12
++  #define DRIVER_EV_RX_DESCQ_ID_LBN 0
++  #define DRIVER_EV_RX_DESCQ_ID_WIDTH 12
++  #define DRIVER_EV_EVQ_ID_LBN 0
++  #define DRIVER_EV_EVQ_ID_WIDTH 12
++  #define DRIVER_TMR_ID_LBN 0
++  #define DRIVER_TMR_ID_WIDTH 12
++  #define DRIVER_EV_SRM_UPD_LBN 0
++  #define DRIVER_EV_SRM_UPD_WIDTH 2
++      #define SRM_CLR_EV_DECODE 0
++      #define SRM_UPD_EV_DECODE 1
++      #define SRM_ILLCLR_EV_DECODE 2
++//////////////---- Global events. Sent to both event queue 0 and 4. ----//////////////
++  #define XFP_PHY_INTR_LBN 10
++  #define XFP_PHY_INTR_WIDTH 1
++  #define XG_PHY_INTR_LBN 9
++  #define XG_PHY_INTR_WIDTH 1
++  #define G_PHY1_INTR_LBN 8
++  #define G_PHY1_INTR_WIDTH 1
++  #define G_PHY0_INTR_LBN 7
++  #define G_PHY0_INTR_WIDTH 1
++//////////////---- Driver generated events ----//////////////
++  #define DRV_GEN_EV_CODE_LBN 60
++  #define DRV_GEN_EV_CODE_WIDTH 4
++  #define DRV_GEN_EV_DATA_LBN 0
++  #define DRV_GEN_EV_DATA_WIDTH 60
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/ef_vi_internal.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/ef_vi_internal.h      2008-05-19 00:33:48.674951800 +0300
+@@ -0,0 +1,256 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      buf = kzalloc((sizeof(*res) * 2) + 1, GFP_KERNEL);
-+      if (!buf)
-+              return AE_OK;
++/*
++ * \author  djr
++ *  \brief  Really-and-truely-honestly internal stuff for libef.
++ *   \date  2004/06/13
++ */
 +
-+      /* Clean out resource_source */
-+      res->data.address64.resource_source.index = 0xFF;
-+      res->data.address64.resource_source.string_length = 0;
-+      res->data.address64.resource_source.string_ptr = NULL;
++/*! \cidoxg_include_ci_ul */
++#ifndef __CI_EF_VI_INTERNAL_H__
++#define __CI_EF_VI_INTERNAL_H__
 +
-+      ptr = (unsigned char *)res;
 +
-+      /* Turn the acpi_resource into an ASCII byte stream */
-+      for (i = 0; i < sizeof(*res); i++) {
-+              snprintf(tmp, sizeof(tmp), "%02x", ptr[i]);
-+              strncat(buf, tmp, 2);
-+      }
++/* These flags share space with enum ef_vi_flags. */
++#define EF_VI_BUG5692_WORKAROUND  0x10000
 +
-+      err = xenbus_printf(XBT_NIL, info->pdev->xdev->nodename,
-+                          str, "%s", buf);
 +
-+      if (!err)
-+              info->resource_count++;
++/* ***********************************************************************
++ * COMPILATION CONTROL FLAGS (see ef_vi.h for "workaround" controls)
++ */
 +
-+      kfree(buf);
++#define EF_VI_DO_MAGIC_CHECKS 1
 +
-+      return AE_OK;
-+}
 +
-+int pciback_publish_pci_roots(struct pciback_device *pdev,
-+                            publish_pci_root_cb publish_root_cb)
-+{
-+      struct controller_dev_data *dev_data = pdev->pci_dev_data;
-+      struct controller_list_entry *cntrl_entry;
-+      int i, root_num, len, err = 0;
-+      unsigned int domain, bus;
-+      char str[64];
-+      struct walk_info info;
++/**********************************************************************
++ * Headers
++ */
 +
-+      spin_lock(&dev_data->lock);
++#include <etherfabric/ef_vi.h>
++#include "sysdep.h"
++#include "ef_vi_falcon.h"
 +
-+      list_for_each_entry(cntrl_entry, &dev_data->list, list) {
-+              /* First publish all the domain:bus info */
-+              err = publish_root_cb(pdev, cntrl_entry->domain,
-+                                    cntrl_entry->bus);
-+              if (err)
-+                      goto out;
 +
-+              /*
-+               * Now figure out which root-%d this belongs to
-+               * so we can associate resources with it.
-+               */
-+              err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
-+                                 "root_num", "%d", &root_num);
++/**********************************************************************
++ * Debugging.
++ */
 +
-+              if (err != 1)
-+                      goto out;
++#ifndef NDEBUG
 +
-+              for (i = 0; i < root_num; i++) {
-+                      len = snprintf(str, sizeof(str), "root-%d", i);
-+                      if (unlikely(len >= (sizeof(str) - 1))) {
-+                              err = -ENOMEM;
-+                              goto out;
-+                      }
++# define _ef_assert(exp, file, line) BUG_ON(!(exp));
 +
-+                      err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
-+                                         str, "%x:%x", &domain, &bus);
-+                      if (err != 2)
-+                              goto out;
++# define _ef_assert2(exp, x, y, file, line)  do {     \
++              if (unlikely(!(exp)))           \
++                      BUG();                          \
++      } while (0)
 +
-+                      /* Is this the one we just published? */
-+                      if (domain == cntrl_entry->domain &&
-+                          bus == cntrl_entry->bus)
-+                              break;
-+              }
++#else
 +
-+              if (i == root_num)
-+                      goto out;
++# define _ef_assert(exp, file, line)
++# define _ef_assert2(e, x, y, file, line)
++
++#endif
++
++#define ef_assert(a)          do{ _ef_assert((a),__FILE__,__LINE__); } while(0)
++#define ef_assert_equal(a,b)  _ef_assert2((a)==(b),(a),(b),__FILE__,__LINE__)
++#define ef_assert_eq          ef_assert_equal
++#define ef_assert_lt(a,b)     _ef_assert2((a)<(b),(a),(b),__FILE__,__LINE__)
++#define ef_assert_le(a,b)     _ef_assert2((a)<=(b),(a),(b),__FILE__,__LINE__)
++#define ef_assert_nequal(a,b) _ef_assert2((a)!=(b),(a),(b),__FILE__,__LINE__)
++#define ef_assert_ne          ef_assert_nequal
++#define ef_assert_ge(a,b)     _ef_assert2((a)>=(b),(a),(b),__FILE__,__LINE__)
++#define ef_assert_gt(a,b)     _ef_assert2((a)>(b),(a),(b),__FILE__,__LINE__)
++
++/**********************************************************************
++ * Debug checks. ******************************************************
++ **********************************************************************/
++
++#ifdef NDEBUG
++# define EF_VI_MAGIC_SET(p, type)
++# define EF_VI_CHECK_VI(p)
++# define EF_VI_CHECK_EVENT_Q(p)
++# define EF_VI_CHECK_IOBUFSET(p)
++# define EF_VI_CHECK_FILTER(p)
++# define EF_VI_CHECK_SHMBUF(p)
++# define EF_VI_CHECK_PT_EP(p)
++#else
++# define EF_VI                    0x3
++# define EF_EPLOCK                0x6
++# define EF_IOBUFSET              0x9
++# define EF_FILTER                0xa
++# define EF_SHMBUF                0x11
++
++# define EF_VI_MAGIC(p, type)                         \
++      (((unsigned)(type) << 28) |                     \
++       (((unsigned)(intptr_t)(p)) & 0x0fffffffu))
++
++# if !EF_VI_DO_MAGIC_CHECKS
++#  define EF_VI_MAGIC_SET(p, type)
++#  define EF_VI_MAGIC_CHECK(p, type)
++# else
++#  define EF_VI_MAGIC_SET(p, type)                    \
++      do {                                            \
++              (p)->magic = EF_VI_MAGIC((p), (type));  \
++      } while (0)
 +
-+              info.pdev = pdev;
-+              info.resource_count = 0;
-+              info.root_num = i;
++# define EF_VI_MAGIC_OKAY(p, type)                      \
++      ((p)->magic == EF_VI_MAGIC((p), (type)))
 +
-+              /* Let ACPI do the heavy lifting on decoding resources */
-+              acpi_walk_resources(cntrl_entry->controller->acpi_handle,
-+                                  METHOD_NAME__CRS, write_xenbus_resource,
-+                                  &info);
++# define EF_VI_MAGIC_CHECK(p, type)                     \
++      ef_assert(EF_VI_MAGIC_OKAY((p), (type)))
 +
-+              /* No resouces.  OK.  On to the next one */
-+              if (!info.resource_count)
-+                      continue;
++#endif /* EF_VI_DO_MAGIC_CHECKS */
 +
-+              /* Store the number of resources we wrote for this root-%d */
-+              len = snprintf(str, sizeof(str), "root-%d-resources", i);
-+              if (unlikely(len >= (sizeof(str) - 1))) {
-+                      err = -ENOMEM;
-+                      goto out;
-+              }
++# define EF_VI_CHECK_VI(p)                    \
++      ef_assert(p);                           \
++      EF_VI_MAGIC_CHECK((p), EF_VI);
 +
-+              err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
-+                                  "%d", info.resource_count);
-+              if (err)
-+                      goto out;
-+      }
++# define EF_VI_CHECK_EVENT_Q(p)                       \
++      ef_assert(p);                           \
++      EF_VI_MAGIC_CHECK((p), EF_VI);          \
++      ef_assert((p)->evq_base);               \
++      ef_assert((p)->evq_mask);
 +
-+      /* Finally, write some magic to synchronize with the guest. */
-+      len = snprintf(str, sizeof(str), "root-resource-magic");
-+      if (unlikely(len >= (sizeof(str) - 1))) {
-+              err = -ENOMEM;
-+              goto out;
-+      }
++# define EF_VI_CHECK_PT_EP(p)                 \
++      ef_assert(p);                           \
++      EF_VI_MAGIC_CHECK((p), EF_VI);          \
++      ef_assert((p)->ep_state);
 +
-+      err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
-+                          "%lx", (sizeof(struct acpi_resource) * 2) + 1);
++# define EF_VI_CHECK_IOBUFSET(p)              \
++      ef_assert(p);                           \
++      EF_VI_MAGIC_CHECK((p), EF_IOBUFSET)
 +
-+out:
-+      spin_unlock(&dev_data->lock);
++# define EF_VI_CHECK_FILTER(p)                        \
++      ef_assert(p);                           \
++      EF_VI_MAGIC_CHECK((p), EF_FILTER);
 +
-+      return err;
-+}
++# define EF_VI_CHECK_SHMBUF(p)                        \
++      ef_assert(p);                           \
++      EF_VI_MAGIC_CHECK((p), EF_SHMBUF);
 +
-+void pciback_release_devices(struct pciback_device *pdev)
-+{
-+      struct controller_dev_data *dev_data = pdev->pci_dev_data;
-+      struct controller_list_entry *cntrl_entry, *c;
-+      struct controller_dev_entry *dev_entry, *d;
++#endif
 +
-+      list_for_each_entry_safe(cntrl_entry, c, &dev_data->list, list) {
-+              list_for_each_entry_safe(dev_entry, d,
-+                                       &cntrl_entry->dev_list, list) {
-+                      list_del(&dev_entry->list);
-+                      pcistub_put_pci_dev(dev_entry->dev);
-+                      kfree(dev_entry);
-+              }
-+              list_del(&cntrl_entry->list);
-+              kfree(cntrl_entry);
-+      }
++#ifndef NDEBUG
++# define EF_DRIVER_MAGIC 0x00f00ba4
++# define EF_ASSERT_THIS_DRIVER_VALID(driver)                          \
++      do{ ef_assert(driver);                                          \
++              EF_VI_MAGIC_CHECK((driver), EF_DRIVER_MAGIC);           \
++              ef_assert((driver)->init);               }while(0)
 +
-+      kfree(dev_data);
-+      pdev->pci_dev_data = NULL;
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/Makefile linux-2.6.18-xen.hg/drivers/xen/pciback/Makefile
---- linux-2.6.18/drivers/xen/pciback/Makefile  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/Makefile   2007-12-23 11:15:34.061269291 +0100
-@@ -0,0 +1,16 @@
-+obj-$(CONFIG_XEN_PCIDEV_BACKEND) += pciback.o
++# define EF_ASSERT_DRIVER_VALID() EF_ASSERT_THIS_DRIVER_VALID(&ci_driver)
++#else
++# define EF_ASSERT_THIS_DRIVER_VALID(driver)
++# define EF_ASSERT_DRIVER_VALID()
++#endif
 +
-+pciback-y := pci_stub.o pciback_ops.o xenbus.o
-+pciback-y += conf_space.o conf_space_header.o \
-+           conf_space_capability.o \
-+           conf_space_capability_vpd.o \
-+           conf_space_capability_pm.o \
-+             conf_space_quirks.o
-+pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o
-+pciback-$(CONFIG_XEN_PCIDEV_BACKEND_SLOT) += slot.o
-+pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o
-+pciback-$(CONFIG_XEN_PCIDEV_BACKEND_CONTROLLER) += controller.o
 +
-+ifeq ($(CONFIG_XEN_PCIDEV_BE_DEBUG),y)
-+EXTRA_CFLAGS += -DDEBUG
-+endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/passthrough.c linux-2.6.18-xen.hg/drivers/xen/pciback/passthrough.c
---- linux-2.6.18/drivers/xen/pciback/passthrough.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/passthrough.c      2007-12-23 11:15:34.064602797 +0100
-@@ -0,0 +1,157 @@
-+/*
-+ * PCI Backend - Provides restricted access to the real PCI bus topology
-+ *               to the frontend
-+ *
-+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++/* *************************************
++ * Power of 2 FIFO
 + */
 +
-+#include <linux/list.h>
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include "pciback.h"
-+
-+struct passthrough_dev_data {
-+      /* Access to dev_list must be protected by lock */
-+      struct list_head dev_list;
-+      spinlock_t lock;
-+};
-+
-+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
-+                                  unsigned int domain, unsigned int bus,
-+                                  unsigned int devfn)
-+{
-+      struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
-+      struct pci_dev_entry *dev_entry;
-+      struct pci_dev *dev = NULL;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&dev_data->lock, flags);
-+
-+      list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
-+              if (domain == (unsigned int)pci_domain_nr(dev_entry->dev->bus)
-+                  && bus == (unsigned int)dev_entry->dev->bus->number
-+                  && devfn == dev_entry->dev->devfn) {
-+                      dev = dev_entry->dev;
-+                      break;
-+              }
-+      }
++#define EF_VI_FIFO2_M(f, x)  ((x) & ((f)->fifo_mask))
++#define ef_vi_fifo2_valid(f) ((f) && (f)->fifo && (f)->fifo_mask > 0 &&       \
++                            (f)->fifo_rd_i <= (f)->fifo_mask       && \
++                            (f)->fifo_wr_i <= (f)->fifo_mask       && \
++                            EF_VI_IS_POW2((f)->fifo_mask+1u))
 +
-+      spin_unlock_irqrestore(&dev_data->lock, flags);
++#define ef_vi_fifo2_init(f, cap)                      \
++      do{ ef_assert(EF_VI_IS_POW2((cap) + 1));        \
++              (f)->fifo_rd_i = (f)->fifo_wr_i = 0u;   \
++              (f)->fifo_mask = (cap);                 \
++      }while(0)
 +
-+      return dev;
-+}
++#define ef_vi_fifo2_is_empty(f) ((f)->fifo_rd_i == (f)->fifo_wr_i)
++#define ef_vi_fifo2_capacity(f) ((f)->fifo_mask)
++#define ef_vi_fifo2_buf_size(f) ((f)->fifo_mask + 1u)
++#define ef_vi_fifo2_end(f)      ((f)->fifo + ef_vi_fifo2_buf_size(f))
++#define ef_vi_fifo2_peek(f)     ((f)->fifo[(f)->fifo_rd_i])
++#define ef_vi_fifo2_poke(f)     ((f)->fifo[(f)->fifo_wr_i])
++#define ef_vi_fifo2_num(f)   EF_VI_FIFO2_M((f),(f)->fifo_wr_i-(f)->fifo_rd_i)
 +
-+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
-+{
-+      struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
-+      struct pci_dev_entry *dev_entry;
-+      unsigned long flags;
++#define ef_vi_fifo2_wr_prev(f)                                                \
++      do{ (f)->fifo_wr_i = EF_VI_FIFO2_M((f), (f)->fifo_wr_i - 1u); }while(0)
++#define ef_vi_fifo2_wr_next(f)                                                \
++      do{ (f)->fifo_wr_i = EF_VI_FIFO2_M((f), (f)->fifo_wr_i + 1u); }while(0)
++#define ef_vi_fifo2_rd_adv(f, n)                                      \
++      do{ (f)->fifo_rd_i = EF_VI_FIFO2_M((f), (f)->fifo_rd_i + (n)); }while(0)
++#define ef_vi_fifo2_rd_prev(f)                                                \
++      do{ (f)->fifo_rd_i = EF_VI_FIFO2_M((f), (f)->fifo_rd_i - 1u); }while(0)
++#define ef_vi_fifo2_rd_next(f)                                                \
++      do{ (f)->fifo_rd_i = EF_VI_FIFO2_M((f), (f)->fifo_rd_i + 1u); }while(0)
 +
-+      dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
-+      if (!dev_entry)
-+              return -ENOMEM;
-+      dev_entry->dev = dev;
++#define ef_vi_fifo2_put(f, v)                                         \
++      do{ ef_vi_fifo2_poke(f) = (v); ef_vi_fifo2_wr_next(f); }while(0)
++#define ef_vi_fifo2_get(f, pv)                                                \
++      do{ *(pv) = ef_vi_fifo2_peek(f); ef_vi_fifo2_rd_next(f); }while(0)
 +
-+      spin_lock_irqsave(&dev_data->lock, flags);
-+      list_add_tail(&dev_entry->list, &dev_data->dev_list);
-+      spin_unlock_irqrestore(&dev_data->lock, flags);
 +
-+      return 0;
-+}
++/* *********************************************************************
++ * Eventq handling
++ */
 +
-+void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
-+{
-+      struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
-+      struct pci_dev_entry *dev_entry, *t;
-+      struct pci_dev *found_dev = NULL;
-+      unsigned long flags;
++typedef union {
++      uint64_t    u64;
++      struct {
++              uint32_t  a;
++              uint32_t  b;
++      } opaque;
++} ef_vi_event;
 +
-+      spin_lock_irqsave(&dev_data->lock, flags);
 +
-+      list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
-+              if (dev_entry->dev == dev) {
-+                      list_del(&dev_entry->list);
-+                      found_dev = dev_entry->dev;
-+                      kfree(dev_entry);
-+              }
-+      }
++#define EF_VI_EVENT_OFFSET(q, i)                                      \
++      (((q)->evq_state->evq_ptr - (i) * sizeof(ef_vi_event)) & (q)->evq_mask)
 +
-+      spin_unlock_irqrestore(&dev_data->lock, flags);
++#define EF_VI_EVENT_PTR(q, i)                                           \
++      ((ef_vi_event*) ((q)->evq_base + EF_VI_EVENT_OFFSET((q), (i))))
 +
-+      if (found_dev)
-+              pcistub_put_pci_dev(found_dev);
-+}
++/* *********************************************************************
++ * Miscellaneous goodies
++ */
++#ifdef NDEBUG
++# define EF_VI_DEBUG(x)
++#else
++# define EF_VI_DEBUG(x)            x
++#endif
 +
-+int pciback_init_devices(struct pciback_device *pdev)
-+{
-+      struct passthrough_dev_data *dev_data;
++#define EF_VI_ROUND_UP(i, align)   (((i)+(align)-1u) & ~((align)-1u))
++#define EF_VI_ALIGN_FWD(p, align)  (((p)+(align)-1u) & ~((align)-1u))
++#define EF_VI_ALIGN_BACK(p, align) ((p) & ~((align)-1u))
++#define EF_VI_PTR_ALIGN_BACK(p, align)                                        \
++      ((char*)EF_VI_ALIGN_BACK(((intptr_t)(p)), ((intptr_t)(align))))
++#define EF_VI_IS_POW2(x)           ((x) && ! ((x) & ((x) - 1)))
 +
-+      dev_data = kmalloc(sizeof(*dev_data), GFP_KERNEL);
-+      if (!dev_data)
-+              return -ENOMEM;
 +
-+      spin_lock_init(&dev_data->lock);
++/* ******************************************************************** 
++ */
 +
-+      INIT_LIST_HEAD(&dev_data->dev_list);
++extern void falcon_vi_init(ef_vi*, void* vvis ) EF_VI_HF;
++extern void ef_eventq_state_init(ef_vi* evq) EF_VI_HF;
++extern void __ef_init(void) EF_VI_HF;
 +
-+      pdev->pci_dev_data = dev_data;
 +
-+      return 0;
-+}
++#endif  /* __CI_EF_VI_INTERNAL_H__ */
 +
-+int pciback_publish_pci_roots(struct pciback_device *pdev,
-+                            publish_pci_root_cb publish_root_cb)
-+{
-+      int err = 0;
-+      struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
-+      struct pci_dev_entry *dev_entry, *e;
-+      struct pci_dev *dev;
-+      int found;
-+      unsigned int domain, bus;
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/etherfabric/ef_vi.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/etherfabric/ef_vi.h   2008-05-19 00:33:48.678952031 +0300
+@@ -0,0 +1,665 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      spin_lock(&dev_data->lock);
++/*
++ *  \brief  Virtual Interface
++ *   \date  2007/05/16
++ */
 +
-+      list_for_each_entry(dev_entry, &dev_data->dev_list, list) {
-+              /* Only publish this device as a root if none of its
-+               * parent bridges are exported
-+               */
-+              found = 0;
-+              dev = dev_entry->dev->bus->self;
-+              for (; !found && dev != NULL; dev = dev->bus->self) {
-+                      list_for_each_entry(e, &dev_data->dev_list, list) {
-+                              if (dev == e->dev) {
-+                                      found = 1;
-+                                      break;
-+                              }
-+                      }
-+              }
++#ifndef __EFAB_EF_VI_H__
++#define __EFAB_EF_VI_H__
 +
-+              domain = (unsigned int)pci_domain_nr(dev_entry->dev->bus);
-+              bus = (unsigned int)dev_entry->dev->bus->number;
 +
-+              if (!found) {
-+                      err = publish_root_cb(pdev, domain, bus);
-+                      if (err)
-+                              break;
-+              }
-+      }
++/**********************************************************************
++ * Primitive types ****************************************************
++ **********************************************************************/
 +
-+      spin_unlock(&dev_data->lock);
++/* We standardise on the types from stdint.h and synthesise these types
++ * for compilers/platforms that don't provide them */
 +
-+      return err;
-+}
++#  include <linux/types.h>
++# define EF_VI_ALIGN(x) __attribute__ ((aligned (x)))
++# define ef_vi_inline static inline
 +
-+void pciback_release_devices(struct pciback_device *pdev)
-+{
-+      struct passthrough_dev_data *dev_data = pdev->pci_dev_data;
-+      struct pci_dev_entry *dev_entry, *t;
 +
-+      list_for_each_entry_safe(dev_entry, t, &dev_data->dev_list, list) {
-+              list_del(&dev_entry->list);
-+              pcistub_put_pci_dev(dev_entry->dev);
-+              kfree(dev_entry);
-+      }
 +
-+      kfree(dev_data);
-+      pdev->pci_dev_data = NULL;
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/pciback.h linux-2.6.18-xen.hg/drivers/xen/pciback/pciback.h
---- linux-2.6.18/drivers/xen/pciback/pciback.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/pciback.h  2007-12-23 11:15:34.067936306 +0100
-@@ -0,0 +1,93 @@
-+/*
-+ * PCI Backend Common Data Structures & Function Declarations
-+ *
-+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ */
-+#ifndef __XEN_PCIBACK_H__
-+#define __XEN_PCIBACK_H__
++/**********************************************************************
++ * Types **************************************************************
++ **********************************************************************/
 +
-+#include <linux/pci.h>
-+#include <linux/interrupt.h>
-+#include <xen/xenbus.h>
-+#include <linux/list.h>
-+#include <linux/spinlock.h>
-+#include <linux/workqueue.h>
-+#include <asm/atomic.h>
-+#include <xen/interface/io/pciif.h>
++typedef uint32_t                ef_eventq_ptr;
 +
-+struct pci_dev_entry {
-+      struct list_head list;
-+      struct pci_dev *dev;
-+};
++typedef uint64_t                ef_addr;
++typedef char*                   ef_vi_ioaddr_t;
 +
-+#define _PDEVF_op_active      (0)
-+#define PDEVF_op_active       (1<<(_PDEVF_op_active))
++/**********************************************************************
++ * ef_event ***********************************************************
++ **********************************************************************/
 +
-+struct pciback_device {
-+      void *pci_dev_data;
-+      spinlock_t dev_lock;
++/*! \i_ef_vi A DMA request identifier.
++**
++** This is an integer token specified by the transport and associated
++** with a DMA request.  It is returned to the VI user with DMA completion
++** events.  It is typically used to identify the buffer associated with
++** the transfer.
++*/
++typedef int                   ef_request_id;
 +
-+      struct xenbus_device *xdev;
++typedef union {
++      uint64_t  u64[1];
++      uint32_t  u32[2];
++} ef_vi_qword;
 +
-+      struct xenbus_watch be_watch;
-+      u8 be_watching;
++typedef ef_vi_qword             ef_hw_event;
 +
-+      int evtchn_irq;
++#define EF_REQUEST_ID_BITS      16u
++#define EF_REQUEST_ID_MASK      ((1u << EF_REQUEST_ID_BITS) - 1u)
 +
-+      struct vm_struct *sh_area;
-+      struct xen_pci_sharedinfo *sh_info;
++/*! \i_ef_event An [ef_event] is a token that identifies something that
++** has happened.  Examples include packets received, packets transmitted
++** and errors.
++*/
++typedef union {
++      struct {
++              ef_hw_event    ev;
++              unsigned       type       :16;
++      } generic;
++      struct {
++              ef_hw_event    ev;
++              unsigned       type       :16;
++              /*ef_request_id  request_id :EF_REQUEST_ID_BITS;*/
++              unsigned       q_id       :16;
++              unsigned       len        :16;
++              unsigned       flags      :16;
++      } rx;
++      struct {  /* This *must* have same layout as [rx]. */
++              ef_hw_event    ev;
++              unsigned       type       :16;
++              /*ef_request_id  request_id :EF_REQUEST_ID_BITS;*/
++              unsigned       q_id       :16;
++              unsigned       len        :16;
++              unsigned       flags      :16;
++              unsigned       subtype    :16;
++      } rx_discard;
++      struct {
++              ef_hw_event    ev;
++              unsigned       type       :16;
++              /*ef_request_id  request_id :EF_REQUEST_ID_BITS;*/
++              unsigned       q_id       :16;
++      } tx;
++      struct {
++              ef_hw_event    ev;
++              unsigned       type       :16;
++              /*ef_request_id  request_id :EF_REQUEST_ID_BITS;*/
++              unsigned       q_id       :16;
++              unsigned       subtype    :16;
++      } tx_error;
++      struct {
++              ef_hw_event    ev;
++              unsigned       type       :16;
++              unsigned       q_id       :16;
++      } rx_no_desc_trunc;
++      struct {
++              ef_hw_event    ev;
++              unsigned       type       :16;
++              unsigned       data;
++      } sw;
++} ef_event;
 +
-+      unsigned long flags;
 +
-+      struct work_struct op_work;
++#define EF_EVENT_TYPE(e)        ((e).generic.type)
++enum {
++      /** Good data was received. */
++      EF_EVENT_TYPE_RX,
++      /** Packets have been sent. */
++      EF_EVENT_TYPE_TX,
++      /** Data received and buffer consumed, but something is wrong. */
++      EF_EVENT_TYPE_RX_DISCARD,
++      /** Transmit of packet failed. */
++      EF_EVENT_TYPE_TX_ERROR,
++      /** Received packet was truncated due to lack of descriptors. */
++      EF_EVENT_TYPE_RX_NO_DESC_TRUNC,
++      /** Software generated event. */
++      EF_EVENT_TYPE_SW,
++      /** Event queue overflow. */
++      EF_EVENT_TYPE_OFLOW,
++};
++
++#define EF_EVENT_RX_BYTES(e)    ((e).rx.len)
++#define EF_EVENT_RX_Q_ID(e)     ((e).rx.q_id)
++#define EF_EVENT_RX_CONT(e)     ((e).rx.flags & EF_EVENT_FLAG_CONT)
++#define EF_EVENT_RX_SOP(e)      ((e).rx.flags & EF_EVENT_FLAG_SOP)
++#define EF_EVENT_RX_ISCSI_OKAY(e) ((e).rx.flags & EF_EVENT_FLAG_ISCSI_OK)
++#define EF_EVENT_FLAG_SOP       0x1
++#define EF_EVENT_FLAG_CONT      0x2
++#define EF_EVENT_FLAG_ISCSI_OK  0x4
++
++#define EF_EVENT_TX_Q_ID(e)     ((e).tx.q_id)
++
++#define EF_EVENT_RX_DISCARD_Q_ID(e)  ((e).rx_discard.q_id)
++#define EF_EVENT_RX_DISCARD_LEN(e)   ((e).rx_discard.len)
++#define EF_EVENT_RX_DISCARD_TYPE(e)  ((e).rx_discard.subtype)
++enum {
++      EF_EVENT_RX_DISCARD_CSUM_BAD,
++      EF_EVENT_RX_DISCARD_CRC_BAD,
++      EF_EVENT_RX_DISCARD_TRUNC,
++      EF_EVENT_RX_DISCARD_RIGHTS,
++      EF_EVENT_RX_DISCARD_OTHER,
 +};
 +
-+struct pciback_dev_data {
-+      struct list_head config_fields;
-+      int permissive;
-+      int warned_on_write;
++#define EF_EVENT_TX_ERROR_Q_ID(e)    ((e).tx_error.q_id)
++#define EF_EVENT_TX_ERROR_TYPE(e)    ((e).tx_error.subtype)
++enum {
++      EF_EVENT_TX_ERROR_RIGHTS,
++      EF_EVENT_TX_ERROR_OFLOW,
++      EF_EVENT_TX_ERROR_2BIG,
++      EF_EVENT_TX_ERROR_BUS,
 +};
 +
-+/* Get/Put PCI Devices that are hidden from the PCI Backend Domain */
-+struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
-+                                          int domain, int bus,
-+                                          int slot, int func);
-+struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
-+                                  struct pci_dev *dev);
-+void pcistub_put_pci_dev(struct pci_dev *dev);
++#define EF_EVENT_RX_NO_DESC_TRUNC_Q_ID(e)  ((e).rx_no_desc_trunc.q_id)
 +
-+/* Ensure a device is turned off or reset */
-+void pciback_reset_device(struct pci_dev *pdev);
++#define EF_EVENT_SW_DATA_MASK   0xffff
++#define EF_EVENT_SW_DATA(e)     ((e).sw.data)
 +
-+/* Access a virtual configuration space for a PCI device */
-+int pciback_config_init(void);
-+int pciback_config_init_dev(struct pci_dev *dev);
-+void pciback_config_free_dyn_fields(struct pci_dev *dev);
-+void pciback_config_reset_dev(struct pci_dev *dev);
-+void pciback_config_free_dev(struct pci_dev *dev);
-+int pciback_config_read(struct pci_dev *dev, int offset, int size,
-+                      u32 * ret_val);
-+int pciback_config_write(struct pci_dev *dev, int offset, int size, u32 value);
++#define EF_EVENT_FMT            "[ev:%x:%08x:%08x]"
++#define EF_EVENT_PRI_ARG(e)     (unsigned) (e).generic.type,    \
++              (unsigned) (e).generic.ev.u32[1],               \
++              (unsigned) (e).generic.ev.u32[0]
 +
-+/* Handle requests for specific devices from the frontend */
-+typedef int (*publish_pci_root_cb) (struct pciback_device * pdev,
-+                                  unsigned int domain, unsigned int bus);
-+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
-+void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev);
-+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
-+                                  unsigned int domain, unsigned int bus,
-+                                  unsigned int devfn);
-+int pciback_init_devices(struct pciback_device *pdev);
-+int pciback_publish_pci_roots(struct pciback_device *pdev,
-+                            publish_pci_root_cb cb);
-+void pciback_release_devices(struct pciback_device *pdev);
++#define EF_GET_HW_EV(e)         ((e).generic.ev)
++#define EF_GET_HW_EV_PTR(e)     (&(e).generic.ev)
++#define EF_GET_HW_EV_U64(e)     ((e).generic.ev.u64[0])
 +
-+/* Handles events from front-end */
-+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs);
-+void pciback_do_op(void *data);
 +
-+int pciback_xenbus_register(void);
-+void pciback_xenbus_unregister(void);
++/* ***************** */
 +
-+extern int verbose_request;
-+#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/pciback_ops.c linux-2.6.18-xen.hg/drivers/xen/pciback/pciback_ops.c
---- linux-2.6.18/drivers/xen/pciback/pciback_ops.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/pciback_ops.c      2007-12-23 11:15:34.067936306 +0100
-@@ -0,0 +1,95 @@
-+/*
-+ * PCI Backend Operations - respond to PCI requests from Frontend
-+ *
-+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ */
-+#include <linux/module.h>
-+#include <asm/bitops.h>
-+#include <xen/evtchn.h>
-+#include "pciback.h"
++/*! Used by netif shared state. Must use types of explicit size. */
++typedef struct {
++      uint16_t              rx_last_desc_ptr;   /* for RX duplicates       */
++      uint8_t               bad_sop;            /* bad SOP detected        */
++      uint8_t               frag_num;           /* next fragment #, 0=>SOP */
++} ef_rx_dup_state_t;
 +
-+int verbose_request = 0;
-+module_param(verbose_request, int, 0644);
 +
-+/* Ensure a device is "turned off" and ready to be exported.
-+ * (Also see pciback_config_reset to ensure virtual configuration space is
-+ * ready to be re-exported)
-+ */
-+void pciback_reset_device(struct pci_dev *dev)
-+{
-+      u16 cmd;
++/* Max number of ports on any SF NIC. */
++#define EFAB_DMAQS_PER_EVQ_MAX 32
 +
-+      /* Disable devices (but not bridges) */
-+      if (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) {
-+              pci_disable_device(dev);
++typedef struct {
++      ef_eventq_ptr           evq_ptr;
++      int32_t               trashed;
++      ef_rx_dup_state_t     rx_dup_state[EFAB_DMAQS_PER_EVQ_MAX];
++} ef_eventq_state;
 +
-+              pci_write_config_word(dev, PCI_COMMAND, 0);
 +
-+              dev->is_enabled = 0;
-+              dev->is_busmaster = 0;
-+      } else {
-+              pci_read_config_word(dev, PCI_COMMAND, &cmd);
-+              if (cmd & (PCI_COMMAND_INVALIDATE)) {
-+                      cmd &= ~(PCI_COMMAND_INVALIDATE);
-+                      pci_write_config_word(dev, PCI_COMMAND, cmd);
++/*! \i_ef_base [ef_iovec] is similar the standard [struct iovec].  An
++** array of these is used to designate a scatter/gather list of I/O
++** buffers.
++*/
++typedef struct {
++      ef_addr                       iov_base EF_VI_ALIGN(8);
++      unsigned                      iov_len;
++} ef_iovec;
 +
-+                      dev->is_busmaster = 0;
-+              }
-+      }
-+}
++/* Falcon constants */
++#define TX_EV_DESC_PTR_LBN 0
 +
-+static inline void test_and_schedule_op(struct pciback_device *pdev)
-+{
-+      /* Check that frontend is requesting an operation and that we are not
-+       * already processing a request */
-+      if (test_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags)
-+          && !test_and_set_bit(_PDEVF_op_active, &pdev->flags))
-+              schedule_work(&pdev->op_work);
-+}
++/**********************************************************************
++ * ef_iobufset ********************************************************
++ **********************************************************************/
 +
-+/* Performing the configuration space reads/writes must not be done in atomic
-+ * context because some of the pci_* functions can sleep (mostly due to ACPI
-+ * use of semaphores). This function is intended to be called from a work
-+ * queue in process context taking a struct pciback_device as a parameter */
-+void pciback_do_op(void *data)
-+{
-+      struct pciback_device *pdev = data;
-+      struct pci_dev *dev;
-+      struct xen_pci_op *op = &pdev->sh_info->op;
++/*! \i_ef_bufs An [ef_iobufset] is a collection of buffers to be used
++** with the NIC.
++*/
++typedef struct ef_iobufset {
++      unsigned                      magic;
++      unsigned                      bufs_mmap_bytes;
++      unsigned                      bufs_handle;
++      int                           bufs_ptr_off;
++      ef_addr                       bufs_addr;
++      unsigned                      bufs_size; /* size rounded to pow2 */
++      int                           bufs_num;
++      int                           faultonaccess;
++} ef_iobufset;
++
++
++/**********************************************************************
++ * ef_vi **************************************************************
++ **********************************************************************/
++
++enum ef_vi_flags {
++      EF_VI_RX_SCATTER        = 0x1,
++      EF_VI_ISCSI_RX_HDIG     = 0x2,
++      EF_VI_ISCSI_TX_HDIG     = 0x4,
++      EF_VI_ISCSI_RX_DDIG     = 0x8,
++      EF_VI_ISCSI_TX_DDIG     = 0x10,
++      EF_VI_TX_PHYS_ADDR      = 0x20,
++      EF_VI_RX_PHYS_ADDR      = 0x40,
++      EF_VI_TX_IP_CSUM_DIS    = 0x80,
++      EF_VI_TX_TCPUDP_CSUM_DIS= 0x100,
++      EF_VI_TX_TCPUDP_ONLY    = 0x200,
++      /* Flags in range 0xXXXX0000 are for internal use. */
++};
 +
-+      dev = pciback_get_pci_dev(pdev, op->domain, op->bus, op->devfn);
++typedef struct {
++      uint32_t  added;
++      uint32_t  removed;
++} ef_vi_txq_state;
 +
-+      if (dev == NULL)
-+              op->err = XEN_PCI_ERR_dev_not_found;
-+      else if (op->cmd == XEN_PCI_OP_conf_read)
-+              op->err = pciback_config_read(dev, op->offset, op->size,
-+                                            &op->value);
-+      else if (op->cmd == XEN_PCI_OP_conf_write)
-+              op->err = pciback_config_write(dev, op->offset, op->size,
-+                                             op->value);
-+      else
-+              op->err = XEN_PCI_ERR_not_implemented;
++typedef struct {
++      uint32_t  added;
++      uint32_t  removed;
++} ef_vi_rxq_state;
 +
-+      /* Tell the driver domain that we're done. */ 
-+      wmb();
-+      clear_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
-+      notify_remote_via_irq(pdev->evtchn_irq);
++typedef struct {
++      uint32_t         mask;
++      void*            doorbell;
++      void*            descriptors;
++      uint16_t*        ids;
++      unsigned         misalign_mask;
++} ef_vi_txq;
 +
-+      /* Mark that we're done. */
-+      smp_mb__before_clear_bit(); /* /after/ clearing PCIF_active */
-+      clear_bit(_PDEVF_op_active, &pdev->flags);
-+      smp_mb__after_clear_bit(); /* /before/ final check for work */
++typedef struct {
++      uint32_t         mask;
++      void*            doorbell;
++      void*            descriptors;
++      uint16_t*        ids;
++} ef_vi_rxq;
 +
-+      /* Check to see if the driver domain tried to start another request in
-+       * between clearing _XEN_PCIF_active and clearing _PDEVF_op_active. */
-+      test_and_schedule_op(pdev);
-+}
++typedef struct {
++      ef_eventq_state  evq;
++      ef_vi_txq_state  txq;
++      ef_vi_rxq_state  rxq;
++      /* Followed by request id fifos. */
++} ef_vi_state;
++
++/*! \i_ef_vi  A virtual interface.
++**
++** An [ef_vi] represents a virtual interface on a specific NIC.  A
++** virtual interface is a collection of an event queue and two DMA queues
++** used to pass Ethernet frames between the transport implementation and
++** the network.
++*/
++typedef struct ef_vi {
++      unsigned                        magic;
 +
-+irqreturn_t pciback_handle_event(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+      struct pciback_device *pdev = dev_id;
++      unsigned                      vi_resource_id;
++      unsigned                      vi_resource_handle_hack;
++      unsigned                      vi_i;
 +
-+      test_and_schedule_op(pdev);
++      char*                           vi_mem_mmap_ptr;
++      int                           vi_mem_mmap_bytes;
++      char*                           vi_io_mmap_ptr;
++      int                           vi_io_mmap_bytes;
 +
-+      return IRQ_HANDLED;
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/pci_stub.c linux-2.6.18-xen.hg/drivers/xen/pciback/pci_stub.c
---- linux-2.6.18/drivers/xen/pciback/pci_stub.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/pci_stub.c 2007-12-23 11:15:34.067936306 +0100
-@@ -0,0 +1,929 @@
-+/*
-+ * PCI Stub Driver - Grabs devices in backend to be exported later
-+ *
-+ * Ryan Wilson <hap9@epoch.ncsc.mil>
-+ * Chris Bookholt <hap10@epoch.ncsc.mil>
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/spinlock.h>
-+#include <linux/kref.h>
-+#include <asm/atomic.h>
-+#include "pciback.h"
-+#include "conf_space.h"
-+#include "conf_space_quirks.h"
++      ef_eventq_state*              evq_state;
++      char*                         evq_base;
++      unsigned                      evq_mask;
++      ef_vi_ioaddr_t                evq_timer_reg;
 +
-+static char *pci_devs_to_hide = NULL;
-+module_param_named(hide, pci_devs_to_hide, charp, 0444);
++      ef_vi_txq                     vi_txq;
++      ef_vi_rxq                     vi_rxq;
++      ef_vi_state*                  ep_state;
++      enum ef_vi_flags              vi_flags;
++} ef_vi;
 +
-+struct pcistub_device_id {
-+      struct list_head slot_list;
-+      int domain;
-+      unsigned char bus;
-+      unsigned int devfn;
++
++enum ef_vi_arch {
++      EF_VI_ARCH_FALCON,
 +};
-+static LIST_HEAD(pcistub_device_ids);
-+static DEFINE_SPINLOCK(device_ids_lock);
 +
-+struct pcistub_device {
-+      struct kref kref;
-+      struct list_head dev_list;
-+      spinlock_t lock;
 +
-+      struct pci_dev *dev;
-+      struct pciback_device *pdev;    /* non-NULL if struct pci_dev is in use */
++struct ef_vi_nic_type {
++      unsigned char  arch;
++      char           variant;
++      unsigned char  revision;
 +};
 +
-+/* Access to pcistub_devices & seized_devices lists and the initialize_devices
-+ * flag must be locked with pcistub_devices_lock
-+ */
-+static DEFINE_SPINLOCK(pcistub_devices_lock);
-+static LIST_HEAD(pcistub_devices);
 +
-+/* wait for device_initcall before initializing our devices
-+ * (see pcistub_init_devices_late)
++/* This structure is opaque to the client & used to pass mapping data
++ * from the resource manager to the ef_vi lib. for ef_vi_init().
 + */
-+static int initialize_devices = 0;
-+static LIST_HEAD(seized_devices);
++struct vi_mappings {
++      uint32_t         signature;
++# define VI_MAPPING_VERSION   0x02  /*Byte: Increment me if struct altered*/
++# define VI_MAPPING_SIGNATURE (0xBA1150 + VI_MAPPING_VERSION)
 +
-+static struct pcistub_device *pcistub_device_alloc(struct pci_dev *dev)
-+{
-+      struct pcistub_device *psdev;
++      struct ef_vi_nic_type nic_type;
 +
-+      dev_dbg(&dev->dev, "pcistub_device_alloc\n");
++      int              vi_instance;
 +
-+      psdev = kzalloc(sizeof(*psdev), GFP_ATOMIC);
-+      if (!psdev)
-+              return NULL;
++      unsigned         evq_bytes;
++      char*            evq_base;
++      ef_vi_ioaddr_t   evq_timer_reg;
 +
-+      psdev->dev = pci_dev_get(dev);
-+      if (!psdev->dev) {
-+              kfree(psdev);
-+              return NULL;
-+      }
++      unsigned         rx_queue_capacity;
++      ef_vi_ioaddr_t   rx_dma_ef1;
++      char*            rx_dma_falcon;
++      ef_vi_ioaddr_t   rx_bell;
 +
-+      kref_init(&psdev->kref);
-+      spin_lock_init(&psdev->lock);
++      unsigned         tx_queue_capacity;
++      ef_vi_ioaddr_t   tx_dma_ef1;
++      char*            tx_dma_falcon;
++      ef_vi_ioaddr_t   tx_bell;
++};
++/* This is used by clients to allocate a suitably sized buffer for the 
++ * resource manager to fill & ef_vi_init() to use. */
++#define VI_MAPPINGS_SIZE (sizeof(struct vi_mappings))
 +
-+      return psdev;
-+}
 +
-+/* Don't call this directly as it's called by pcistub_device_put */
-+static void pcistub_device_release(struct kref *kref)
-+{
-+      struct pcistub_device *psdev;
++/**********************************************************************
++ * ef_config **********************************************************
++ **********************************************************************/
 +
-+      psdev = container_of(kref, struct pcistub_device, kref);
++struct ef_config_t {
++      int   log;                    /* debug logging level          */
++};
 +
-+      dev_dbg(&psdev->dev->dev, "pcistub_device_release\n");
++extern struct ef_config_t  ef_config;
 +
-+      /* Clean-up the device */
-+      pciback_reset_device(psdev->dev);
-+      pciback_config_free_dyn_fields(psdev->dev);
-+      pciback_config_free_dev(psdev->dev);
-+      kfree(pci_get_drvdata(psdev->dev));
-+      pci_set_drvdata(psdev->dev, NULL);
 +
-+      pci_dev_put(psdev->dev);
++/**********************************************************************
++ * ef_vi **************************************************************
++ **********************************************************************/
 +
-+      kfree(psdev);
++/* Initialise [data_area] with information required to initialise an ef_vi.
++ * In the following, an unused param should be set to NULL. Note the case
++ * marked (*) of [iobuf_mmap] for falcon/driver; for normal driver this
++ * must be NULL.
++ *
++ * \param  data_area     [in,out] required, must ref at least VI_MAPPINGS_SIZE 
++ *                                bytes
++ * \param  evq_capacity  [in] number of events in event queue.  Specify 0 for
++ *                            no event queue.
++ * \param  rxq_capacity  [in] number of descriptors in RX DMA queue.  Specify
++ *                            0 for no RX queue.
++ * \param  txq_capacity  [in] number of descriptors in TX DMA queue.  Specify
++ *                            0 for no TX queue.
++ * \param  mmap_info     [in] mem-map info for resource
++ * \param  io_mmap       [in] ef1,    required
++ *                            falcon, required
++ * \param  iobuf_mmap    [in] ef1,    UL: unused
++ *                            falcon, UL: required
++ */
++extern void ef_vi_init_mapping_vi(void* data_area, struct ef_vi_nic_type,
++                                  unsigned rxq_capacity,
++                                  unsigned txq_capacity, int instance,
++                                  void* io_mmap, void* iobuf_mmap_rx,
++                                  void* iobuf_mmap_tx, enum ef_vi_flags);
++
++
++extern void ef_vi_init_mapping_evq(void* data_area, struct ef_vi_nic_type,
++                                   int instance, unsigned evq_bytes,
++                                   void* base, void* timer_reg);
++
++ef_vi_inline unsigned ef_vi_resource_id(ef_vi* vi)
++{ 
++      return vi->vi_resource_id; 
 +}
 +
-+static inline void pcistub_device_get(struct pcistub_device *psdev)
-+{
-+      kref_get(&psdev->kref);
++ef_vi_inline enum ef_vi_flags ef_vi_flags(ef_vi* vi)
++{ 
++      return vi->vi_flags; 
 +}
 +
-+static inline void pcistub_device_put(struct pcistub_device *psdev)
++
++/**********************************************************************
++ * Receive interface **************************************************
++ **********************************************************************/
++
++/*! \i_ef_vi Returns the amount of space in the RX descriptor ring.
++**
++** \return the amount of space in the queue.
++*/
++ef_vi_inline int ef_vi_receive_space(ef_vi* vi) 
 +{
-+      kref_put(&psdev->kref, pcistub_device_release);
++      ef_vi_rxq_state* qs = &vi->ep_state->rxq;
++      return vi->vi_rxq.mask - (qs->added - qs->removed);
 +}
 +
-+static struct pcistub_device *pcistub_device_find(int domain, int bus,
-+                                                int slot, int func)
++
++/*! \i_ef_vi Returns the fill level of the RX descriptor ring.
++**
++** \return the fill level of the queue.
++*/
++ef_vi_inline int ef_vi_receive_fill_level(ef_vi* vi) 
 +{
-+      struct pcistub_device *psdev = NULL;
-+      unsigned long flags;
++      ef_vi_rxq_state* qs = &vi->ep_state->rxq;
++      return qs->added - qs->removed;
++}
 +
-+      spin_lock_irqsave(&pcistub_devices_lock, flags);
 +
-+      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+              if (psdev->dev != NULL
-+                  && domain == pci_domain_nr(psdev->dev->bus)
-+                  && bus == psdev->dev->bus->number
-+                  && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
-+                      pcistub_device_get(psdev);
-+                      goto out;
-+              }
-+      }
++ef_vi_inline int ef_vi_receive_capacity(ef_vi* vi)
++{ 
++      return vi->vi_rxq.mask;
++}
 +
-+      /* didn't find it */
-+      psdev = NULL;
++/*! \i_ef_vi  Complete a receive operation.
++**
++** When a receive completion event is received, it should be passed to
++** this function.  The request-id for the buffer that the packet was
++** delivered to is returned.
++**
++** After this function returns, more space may be available in the
++** receive queue.
++*/
++extern ef_request_id ef_vi_receive_done(const ef_vi*, const ef_event*);
 +
-+      out:
-+      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+      return psdev;
++/*! \i_ef_vi  Return request ID indicated by a receive event
++ */
++ef_vi_inline ef_request_id ef_vi_receive_request_id(const ef_vi* vi,
++                                                    const ef_event* ef_ev)
++{
++      const ef_vi_qword* ev = EF_GET_HW_EV_PTR(*ef_ev);
++      return ev->u32[0] & vi->vi_rxq.mask;
 +}
++  
 +
-+static struct pci_dev *pcistub_device_get_pci_dev(struct pciback_device *pdev,
-+                                                struct pcistub_device *psdev)
-+{
-+      struct pci_dev *pci_dev = NULL;
-+      unsigned long flags;
++/*! \i_ef_vi  Form a receive descriptor.
++**
++** If \c initial_rx_bytes is zero use a reception size at least as large
++** as an MTU.
++*/
++extern int ef_vi_receive_init(ef_vi* vi, ef_addr addr, ef_request_id dma_id,
++                              int intial_rx_bytes);
 +
-+      pcistub_device_get(psdev);
++/*! \i_ef_vi  Submit initialised receive descriptors to the NIC. */
++extern void ef_vi_receive_push(ef_vi* vi);
 +
-+      spin_lock_irqsave(&psdev->lock, flags);
-+      if (!psdev->pdev) {
-+              psdev->pdev = pdev;
-+              pci_dev = psdev->dev;
-+      }
-+      spin_unlock_irqrestore(&psdev->lock, flags);
++/*! \i_ef_vi  Post a buffer on the receive queue.
++**
++**   \return 0 on success, or -EAGAIN if the receive queue is full
++*/
++extern int ef_vi_receive_post(ef_vi*, ef_addr addr,
++                            ef_request_id dma_id);
 +
-+      if (!pci_dev)
-+              pcistub_device_put(psdev);
++/**********************************************************************
++ * Transmit interface *************************************************
++ **********************************************************************/
 +
-+      return pci_dev;
++/*! \i_ef_vi Return the amount of space (in descriptors) in the transmit
++**           queue.
++**
++** \return the amount of space in the queue (in descriptors)
++*/
++ef_vi_inline int ef_vi_transmit_space(ef_vi* vi) 
++{
++      ef_vi_txq_state* qs = &vi->ep_state->txq;
++      return vi->vi_txq.mask - (qs->added - qs->removed);
 +}
 +
-+struct pci_dev *pcistub_get_pci_dev_by_slot(struct pciback_device *pdev,
-+                                          int domain, int bus,
-+                                          int slot, int func)
-+{
-+      struct pcistub_device *psdev;
-+      struct pci_dev *found_dev = NULL;
-+      unsigned long flags;
 +
-+      spin_lock_irqsave(&pcistub_devices_lock, flags);
++/*! \i_ef_vi Returns the fill level of the TX descriptor ring.
++**
++** \return the fill level of the queue.
++*/
++ef_vi_inline int ef_vi_transmit_fill_level(ef_vi* vi)
++{
++      ef_vi_txq_state* qs = &vi->ep_state->txq;
++      return qs->added - qs->removed;
++}
 +
-+      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+              if (psdev->dev != NULL
-+                  && domain == pci_domain_nr(psdev->dev->bus)
-+                  && bus == psdev->dev->bus->number
-+                  && PCI_DEVFN(slot, func) == psdev->dev->devfn) {
-+                      found_dev = pcistub_device_get_pci_dev(pdev, psdev);
-+                      break;
-+              }
-+      }
 +
-+      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+      return found_dev;
++/*! \i_ef_vi Returns the total capacity of the TX descriptor ring.
++**
++** \return the capacity of the queue.
++*/
++ef_vi_inline int ef_vi_transmit_capacity(ef_vi* vi)
++{ 
++      return vi->vi_txq.mask;
 +}
 +
-+struct pci_dev *pcistub_get_pci_dev(struct pciback_device *pdev,
-+                                  struct pci_dev *dev)
-+{
-+      struct pcistub_device *psdev;
-+      struct pci_dev *found_dev = NULL;
-+      unsigned long flags;
 +
-+      spin_lock_irqsave(&pcistub_devices_lock, flags);
++/*! \i_ef_vi  Transmit a packet.
++**
++**   \param bytes must be greater than ETH_ZLEN.
++**   \return -EAGAIN if the transmit queue is full, or 0 on success
++*/
++extern int ef_vi_transmit(ef_vi*, ef_addr, int bytes, ef_request_id dma_id);
++
++/*! \i_ef_vi  Transmit a packet using a gather list.
++**
++**   \param iov_len must be greater than zero
++**   \param iov the first must be non-zero in length (but others need not)
++**
++**   \return -EAGAIN if the queue is full, or 0 on success
++*/
++extern int ef_vi_transmitv(ef_vi*, const ef_iovec* iov, int iov_len,
++                           ef_request_id dma_id);
 +
-+      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+              if (psdev->dev == dev) {
-+                      found_dev = pcistub_device_get_pci_dev(pdev, psdev);
-+                      break;
-+              }
-+      }
++/*! \i_ef_vi  Initialise a DMA request.
++**
++** \return -EAGAIN if the queue is full, or 0 on success
++*/
++extern int ef_vi_transmit_init(ef_vi*, ef_addr, int bytes,
++                               ef_request_id dma_id);
 +
-+      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+      return found_dev;
-+}
++/*! \i_ef_vi  Initialise a DMA request.
++**
++** \return -EAGAIN if the queue is full, or 0 on success
++*/
++extern int ef_vi_transmitv_init(ef_vi*, const ef_iovec*, int iov_len,
++                                ef_request_id dma_id);
 +
-+void pcistub_put_pci_dev(struct pci_dev *dev)
-+{
-+      struct pcistub_device *psdev, *found_psdev = NULL;
-+      unsigned long flags;
++/*! \i_ef_vi  Submit DMA requests to the NIC.
++**
++** The DMA requests must have been initialised using
++** ef_vi_transmit_init() or ef_vi_transmitv_init().
++*/
++extern void ef_vi_transmit_push(ef_vi*);
 +
-+      spin_lock_irqsave(&pcistub_devices_lock, flags);
 +
-+      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+              if (psdev->dev == dev) {
-+                      found_psdev = psdev;
-+                      break;
-+              }
-+      }
++/*! \i_ef_vi Maximum number of transmit completions per transmit event. */
++#define EF_VI_TRANSMIT_BATCH  64
 +
-+      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++/*! \i_ef_vi Determine the set of [ef_request_id]s for each DMA request
++**           which has been completed by a given transmit completion
++**           event.
++**
++** \param ids must point to an array of length EF_VI_TRANSMIT_BATCH
++** \return the number of valid [ef_request_id]s (can be zero)
++*/
++extern int ef_vi_transmit_unbundle(ef_vi* ep, const ef_event*,
++                                   ef_request_id* ids);
 +
-+      /* Cleanup our device
-+       * (so it's ready for the next domain)
-+       */
-+      pciback_reset_device(found_psdev->dev);
-+      pciback_config_free_dyn_fields(found_psdev->dev);
-+      pciback_config_reset_dev(found_psdev->dev);
 +
-+      spin_lock_irqsave(&found_psdev->lock, flags);
-+      found_psdev->pdev = NULL;
-+      spin_unlock_irqrestore(&found_psdev->lock, flags);
++/*! \i_ef_event Returns true if ef_eventq_poll() will return event(s). */
++extern int ef_eventq_has_event(ef_vi* vi);
 +
-+      pcistub_device_put(found_psdev);
-+}
++/*! \i_ef_event Returns true if there are quite a few events in the event
++** queue.
++**
++** This looks ahead in the event queue, so has the property that it will
++** not ping-pong a cache-line when it is called concurrently with events
++** being delivered.
++*/
++extern int ef_eventq_has_many_events(ef_vi* evq, int look_ahead);
 +
-+static int __devinit pcistub_match_one(struct pci_dev *dev,
-+                                     struct pcistub_device_id *pdev_id)
-+{
-+      /* Match the specified device by domain, bus, slot, func and also if
-+       * any of the device's parent bridges match.
-+       */
-+      for (; dev != NULL; dev = dev->bus->self) {
-+              if (pci_domain_nr(dev->bus) == pdev_id->domain
-+                  && dev->bus->number == pdev_id->bus
-+                  && dev->devfn == pdev_id->devfn)
-+                      return 1;
++/*! Type of function to handle unknown events arriving on event queue
++**  Return CI_TRUE iff the event has been handled.
++*/
++typedef int/*bool*/ ef_event_handler_fn(void* priv, ef_vi* evq, ef_event* ev);
 +
-+              /* Sometimes topmost bridge links to itself. */
-+              if (dev == dev->bus->self)
-+                      break;
-+      }
++/*! Standard poll exception routine */
++extern int/*bool*/ ef_eventq_poll_exception(void* priv, ef_vi* evq,
++                                            ef_event* ev);
 +
-+      return 0;
-+}
++/*! \i_ef_event  Retrieve events from the event queue, handle RX/TX events
++**  and pass any others to an exception handler function
++**
++**   \return The number of events retrieved.
++*/
++extern int ef_eventq_poll_evs(ef_vi* evq, ef_event* evs, int evs_len,
++                              ef_event_handler_fn *exception, void *expt_priv);
 +
-+static int __devinit pcistub_match(struct pci_dev *dev)
++/*! \i_ef_event  Retrieve events from the event queue.
++**
++**   \return The number of events retrieved.
++*/
++ef_vi_inline int ef_eventq_poll(ef_vi* evq, ef_event* evs, int evs_len)
 +{
-+      struct pcistub_device_id *pdev_id;
-+      unsigned long flags;
-+      int found = 0;
-+
-+      spin_lock_irqsave(&device_ids_lock, flags);
-+      list_for_each_entry(pdev_id, &pcistub_device_ids, slot_list) {
-+              if (pcistub_match_one(dev, pdev_id)) {
-+                      found = 1;
-+                      break;
-+              }
-+      }
-+      spin_unlock_irqrestore(&device_ids_lock, flags);
-+
-+      return found;
++      return ef_eventq_poll_evs(evq, evs, evs_len,
++                            &ef_eventq_poll_exception, (void*)0);
 +}
 +
-+static int __devinit pcistub_init_device(struct pci_dev *dev)
++/*! \i_ef_event Returns the capacity of an event queue. */
++ef_vi_inline int ef_eventq_capacity(ef_vi* vi) 
 +{
-+      struct pciback_dev_data *dev_data;
-+      int err = 0;
++      return (vi->evq_mask + 1u) / sizeof(ef_hw_event);
++}
 +
-+      dev_dbg(&dev->dev, "initializing...\n");
++/* Returns the instance ID of [vi] */
++ef_vi_inline unsigned ef_vi_instance(ef_vi* vi)
++{ return vi->vi_i; }
 +
-+      /* The PCI backend is not intended to be a module (or to work with
-+       * removable PCI devices (yet). If it were, pciback_config_free()
-+       * would need to be called somewhere to free the memory allocated
-+       * here and then to call kfree(pci_get_drvdata(psdev->dev)).
-+       */
-+      dev_data = kzalloc(sizeof(*dev_data), GFP_ATOMIC);
-+      if (!dev_data) {
-+              err = -ENOMEM;
-+              goto out;
-+      }
-+      pci_set_drvdata(dev, dev_data);
 +
-+      dev_dbg(&dev->dev, "initializing config\n");
-+      err = pciback_config_init_dev(dev);
-+      if (err)
-+              goto out;
++/**********************************************************************
++ * Initialisation *****************************************************
++ **********************************************************************/
 +
-+      /* HACK: Force device (& ACPI) to determine what IRQ it's on - we
-+       * must do this here because pcibios_enable_device may specify
-+       * the pci device's true irq (and possibly its other resources)
-+       * if they differ from what's in the configuration space.
-+       * This makes the assumption that the device's resources won't
-+       * change after this point (otherwise this code may break!)
-+       */
-+      dev_dbg(&dev->dev, "enabling device\n");
-+      err = pci_enable_device(dev);
-+      if (err)
-+              goto config_release;
++/*! Return size of state buffer of an initialised VI. */
++extern int ef_vi_state_bytes(ef_vi*);
 +
-+      /* Now disable the device (this also ensures some private device
-+       * data is setup before we export)
-+       */
-+      dev_dbg(&dev->dev, "reset device\n");
-+      pciback_reset_device(dev);
++/*! Return size of buffer needed for VI state given sizes of RX and TX
++** DMA queues.  Queue sizes must be legal sizes (power of 2), or 0 (no
++** queue).
++*/
++extern int ef_vi_calc_state_bytes(int rxq_size, int txq_size);
 +
-+      return 0;
++/*! Initialise [ef_vi] from the provided resources. [vvis] must have been
++** created by ef_make_vi_data() & remains owned by the caller.
++*/
++extern void ef_vi_init(ef_vi*, void* vi_info, ef_vi_state* state,
++                       ef_eventq_state* evq_state, enum ef_vi_flags);
 +
-+      config_release:
-+      pciback_config_free_dev(dev);
++extern void ef_vi_state_init(ef_vi*);
++extern void ef_eventq_state_init(ef_vi*);
 +
-+      out:
-+      pci_set_drvdata(dev, NULL);
-+      kfree(dev_data);
-+      return err;
-+}
++/*! Convert an efhw device arch to ef_vi_arch, or returns -1 if not
++** recognised.
++*/
++extern int  ef_vi_arch_from_efhw_arch(int efhw_arch);
++
++
++#endif /* __EFAB_EF_VI_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/falcon_event.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/falcon_event.c        2008-05-19 00:33:48.678952031 +0300
+@@ -0,0 +1,346 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
 +/*
-+ * Because some initialization still happens on
-+ * devices during fs_initcall, we need to defer
-+ * full initialization of our devices until
-+ * device_initcall.
++ * \author  djr
++ *  \brief  Routine to poll event queues.
++ *   \date  2003/03/04
 + */
-+static int __init pcistub_init_devices_late(void)
-+{
-+      struct pcistub_device *psdev;
-+      unsigned long flags;
-+      int err = 0;
 +
-+      pr_debug("pciback: pcistub_init_devices_late\n");
++/*! \cidoxg_lib_ef */
++#include "ef_vi_internal.h"
 +
-+      spin_lock_irqsave(&pcistub_devices_lock, flags);
++/* Be worried about this on byteswapped machines */
++/* Due to crazy chipsets, we see the event words being written in
++** arbitrary order (bug4539).  So test for presence of event must ensure
++** that both halves have changed from the null.
++*/
++# define EF_VI_IS_EVENT(evp)                                          \
++      ( (((evp)->opaque.a != (uint32_t)-1) &&                         \
++         ((evp)->opaque.b != (uint32_t)-1)) )
 +
-+      while (!list_empty(&seized_devices)) {
-+              psdev = container_of(seized_devices.next,
-+                                   struct pcistub_device, dev_list);
-+              list_del(&psdev->dev_list);
 +
-+              spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++#ifdef NDEBUG
++# define IS_DEBUG 0
++#else
++# define IS_DEBUG 1
++#endif
 +
-+              err = pcistub_init_device(psdev->dev);
-+              if (err) {
-+                      dev_err(&psdev->dev->dev,
-+                              "error %d initializing device\n", err);
-+                      kfree(psdev);
-+                      psdev = NULL;
-+              }
 +
-+              spin_lock_irqsave(&pcistub_devices_lock, flags);
++/*! Check for RX events with inconsistent SOP/CONT
++**
++** Returns true if this event should be discarded
++*/
++ef_vi_inline int ef_eventq_is_rx_sop_cont_bad_efab(ef_vi* vi,
++                                                 const ef_vi_qword* ev)
++{
++      ef_rx_dup_state_t* rx_dup_state;
++      uint8_t* bad_sop;
 +
-+              if (psdev)
-+                      list_add_tail(&psdev->dev_list, &pcistub_devices);
++      unsigned label = QWORD_GET_U(RX_EV_Q_LABEL, *ev);
++      unsigned sop   = QWORD_TEST_BIT(RX_SOP, *ev);
++  
++      ef_assert(vi);
++      ef_assert_lt(label, EFAB_DMAQS_PER_EVQ_MAX);
++
++      rx_dup_state = &vi->evq_state->rx_dup_state[label];
++      bad_sop = &rx_dup_state->bad_sop;
++
++      if( ! ((vi->vi_flags & EF_VI_BUG5692_WORKAROUND) || IS_DEBUG) ) {
++              *bad_sop = (*bad_sop && !sop);
 +      }
++      else {
++              unsigned cont  = QWORD_TEST_BIT(RX_JUMBO_CONT, *ev);
++              uint8_t *frag_num = &rx_dup_state->frag_num;
 +
-+      initialize_devices = 1;
++              /* bad_sop should latch till the next sop */
++              *bad_sop = (*bad_sop && !sop) || ( !!sop != (*frag_num==0) );
 +
-+      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
++              /* we do not check the number of bytes relative to the
++               * fragment number and size of the user rx buffer here
++               * because we don't know the size of the user rx
++               * buffer - we probably should perform this check in
++               * the nearest code calling this though.
++               */
++              *frag_num = cont ? (*frag_num + 1) : 0;
++      }
 +
-+      return 0;
++      return *bad_sop;
 +}
 +
-+static int __devinit pcistub_seize(struct pci_dev *dev)
++
++ef_vi_inline int falcon_rx_check_dup(ef_vi* evq, ef_event* ev_out,
++                                   const ef_vi_qword* ev)
 +{
-+      struct pcistub_device *psdev;
-+      unsigned long flags;
-+      int err = 0;
++      unsigned q_id = QWORD_GET_U(RX_EV_Q_LABEL, *ev);
++      unsigned desc_ptr = QWORD_GET_U(RX_EV_DESC_PTR, *ev);
++      ef_rx_dup_state_t* rx_dup_state = &evq->evq_state->rx_dup_state[q_id];
 +
-+      psdev = pcistub_device_alloc(dev);
-+      if (!psdev)
-+              return -ENOMEM;
++      if(likely( desc_ptr != rx_dup_state->rx_last_desc_ptr )) {
++              rx_dup_state->rx_last_desc_ptr = desc_ptr;
++              return 0;
++      }
 +
-+      spin_lock_irqsave(&pcistub_devices_lock, flags);
++      rx_dup_state->rx_last_desc_ptr = desc_ptr;
++      rx_dup_state->bad_sop = 1;
++#ifndef NDEBUG
++      rx_dup_state->frag_num = 0;
++#endif
++      BUG_ON(!QWORD_TEST_BIT(RX_EV_FRM_TRUNC, *ev));
++      BUG_ON( QWORD_TEST_BIT(RX_EV_PKT_OK, *ev));
++      BUG_ON(!QWORD_GET_U(RX_EV_BYTE_CNT, *ev) == 0);
++      ev_out->rx_no_desc_trunc.type = EF_EVENT_TYPE_RX_NO_DESC_TRUNC;
++      ev_out->rx_no_desc_trunc.q_id = q_id;
++      return 1;
++}
 +
-+      if (initialize_devices) {
-+              spin_unlock_irqrestore(&pcistub_devices_lock, flags);
 +
-+              /* don't want irqs disabled when calling pcistub_init_device */
-+              err = pcistub_init_device(psdev->dev);
++ef_vi_inline void falcon_rx_event(ef_event* ev_out, const ef_vi_qword* ev)
++{
++      if(likely( QWORD_TEST_BIT(RX_EV_PKT_OK, *ev) )) {
++              ev_out->rx.type = EF_EVENT_TYPE_RX;
++              ev_out->rx.q_id = QWORD_GET_U(RX_EV_Q_LABEL, *ev);
++              ev_out->rx.len  = QWORD_GET_U(RX_EV_BYTE_CNT, *ev);
++              if( QWORD_TEST_BIT(RX_SOP, *ev) )
++                      ev_out->rx.flags = EF_EVENT_FLAG_SOP;
++              else
++                      ev_out->rx.flags = 0;
++              if( QWORD_TEST_BIT(RX_JUMBO_CONT, *ev) )
++                      ev_out->rx.flags |= EF_EVENT_FLAG_CONT;
++              if( QWORD_TEST_BIT(RX_iSCSI_PKT_OK, *ev) )
++                      ev_out->rx.flags |= EF_EVENT_FLAG_ISCSI_OK;
++      }
++      else {
++              ev_out->rx_discard.type = EF_EVENT_TYPE_RX_DISCARD;
++              ev_out->rx_discard.q_id = QWORD_GET_U(RX_EV_Q_LABEL, *ev);
++              ev_out->rx_discard.len  = QWORD_GET_U(RX_EV_BYTE_CNT, *ev);
++#if 1  /* hack for ptloop compatability: ?? TODO purge */
++              if( QWORD_TEST_BIT(RX_SOP, *ev) )
++                      ev_out->rx_discard.flags = EF_EVENT_FLAG_SOP;
++              else
++                      ev_out->rx_discard.flags = 0;
++              if( QWORD_TEST_BIT(RX_JUMBO_CONT, *ev) )
++                      ev_out->rx_discard.flags |= EF_EVENT_FLAG_CONT;
++              if( QWORD_TEST_BIT(RX_iSCSI_PKT_OK, *ev) )
++                      ev_out->rx_discard.flags |= EF_EVENT_FLAG_ISCSI_OK;
++#endif
++              /* Order matters here: more fundamental errors first. */
++              if( QWORD_TEST_BIT(RX_EV_BUF_OWNER_ID_ERR, *ev) )
++                      ev_out->rx_discard.subtype = 
++                              EF_EVENT_RX_DISCARD_RIGHTS;
++              else if( QWORD_TEST_BIT(RX_EV_FRM_TRUNC, *ev) )
++                      ev_out->rx_discard.subtype = 
++                              EF_EVENT_RX_DISCARD_TRUNC;
++              else if( QWORD_TEST_BIT(RX_EV_ETH_CRC_ERR, *ev) )
++                      ev_out->rx_discard.subtype = 
++                              EF_EVENT_RX_DISCARD_CRC_BAD;
++              else if( QWORD_TEST_BIT(RX_EV_IP_HDR_CHKSUM_ERR, *ev) )
++                      ev_out->rx_discard.subtype = 
++                              EF_EVENT_RX_DISCARD_CSUM_BAD;
++              else if( QWORD_TEST_BIT(RX_EV_TCP_UDP_CHKSUM_ERR, *ev) )
++                      ev_out->rx_discard.subtype = 
++                              EF_EVENT_RX_DISCARD_CSUM_BAD;
++              else
++                      ev_out->rx_discard.subtype = 
++                              EF_EVENT_RX_DISCARD_OTHER;
++      }
++}
 +
-+              spin_lock_irqsave(&pcistub_devices_lock, flags);
 +
-+              if (!err)
-+                      list_add(&psdev->dev_list, &pcistub_devices);
-+      } else {
-+              dev_dbg(&dev->dev, "deferring initialization\n");
-+              list_add(&psdev->dev_list, &seized_devices);
++ef_vi_inline void falcon_tx_event(ef_event* ev_out, const ef_vi_qword* ev)
++{
++      /* Danger danger!  No matter what we ask for wrt batching, we
++      ** will get a batched event every 16 descriptors, and we also
++      ** get dma-queue-empty events.  i.e. Duplicates are expected.
++      **
++      ** In addition, if it's been requested in the descriptor, we
++      ** get an event per descriptor.  (We don't currently request
++      ** this).
++      */
++      if(likely( QWORD_TEST_BIT(TX_EV_COMP, *ev) )) {
++              ev_out->tx.type = EF_EVENT_TYPE_TX;
++              ev_out->tx.q_id = QWORD_GET_U(TX_EV_Q_LABEL, *ev);
 +      }
++      else {
++              ev_out->tx_error.type = EF_EVENT_TYPE_TX_ERROR;
++              ev_out->tx_error.q_id = QWORD_GET_U(TX_EV_Q_LABEL, *ev);
++              if(likely( QWORD_TEST_BIT(TX_EV_BUF_OWNER_ID_ERR, *ev) ))
++                      ev_out->tx_error.subtype = EF_EVENT_TX_ERROR_RIGHTS;
++              else if(likely( QWORD_TEST_BIT(TX_EV_WQ_FF_FULL, *ev) ))
++                      ev_out->tx_error.subtype = EF_EVENT_TX_ERROR_OFLOW;
++              else if(likely( QWORD_TEST_BIT(TX_EV_PKT_TOO_BIG, *ev) ))
++                      ev_out->tx_error.subtype = EF_EVENT_TX_ERROR_2BIG;
++              else if(likely( QWORD_TEST_BIT(TX_EV_PKT_ERR, *ev) ))
++                      ev_out->tx_error.subtype = EF_EVENT_TX_ERROR_BUS;
++      }
++}
 +
-+      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+
-+      if (err)
-+              pcistub_device_put(psdev);
 +
-+      return err;
++static void mark_bad(ef_event* ev)
++{
++      ev->generic.ev.u64[0] &=~ ((uint64_t) 1u << RX_EV_PKT_OK_LBN);
 +}
 +
-+static int __devinit pcistub_probe(struct pci_dev *dev,
-+                                 const struct pci_device_id *id)
++
++int ef_eventq_poll_evs(ef_vi* evq, ef_event* evs, int evs_len,
++                     ef_event_handler_fn *exception, void *expt_priv)
 +{
-+      int err = 0;
++      int evs_len_orig = evs_len;
 +
-+      dev_dbg(&dev->dev, "probing...\n");
++      EF_VI_CHECK_EVENT_Q(evq);
++      ef_assert(evs);
++      ef_assert_gt(evs_len, 0);
 +
-+      if (pcistub_match(dev)) {
++      if(unlikely( EF_VI_IS_EVENT(EF_VI_EVENT_PTR(evq, 1)) ))
++              goto overflow;
 +
-+              if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL
-+                  && dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {
-+                      dev_err(&dev->dev, "can't export pci devices that "
-+                              "don't have a normal (0) or bridge (1) "
-+                              "header type!\n");
-+                      err = -ENODEV;
-+                      goto out;
++      do {
++              { /* Read the event out of the ring, then fiddle with
++                 * copied version.  Reason is that the ring is
++                 * likely to get pushed out of cache by another
++                 * event being delivered by hardware. */
++                      ef_vi_event* ev = EF_VI_EVENT_PTR(evq, 0);
++                      if( ! EF_VI_IS_EVENT(ev) )
++                              break;
++                      evs->generic.ev.u64[0] = cpu_to_le64 (ev->u64);
++                      evq->evq_state->evq_ptr += sizeof(ef_vi_event);
++                      ev->u64 = (uint64_t)(int64_t) -1;
++              }
++
++              /* Ugly: Exploit the fact that event code lies in top
++               * bits of event. */
++              ef_assert_ge(EV_CODE_LBN, 32u);
++              switch( evs->generic.ev.u32[1] >> (EV_CODE_LBN - 32u) ) {
++              case RX_IP_EV_DECODE:
++                      /* Look for duplicate desc_ptr: it signals
++                       * that a jumbo frame was truncated because we
++                       * ran out of descriptors. */
++                      if(unlikely( falcon_rx_check_dup
++                                         (evq, evs, &evs->generic.ev) )) {
++                              --evs_len;
++                              ++evs;
++                              break;
++                      }
++                      else {
++                              /* Cope with FalconA1 bugs where RX
++                               * gives inconsistent RX events Mark
++                               * events as bad until SOP becomes
++                               * consistent again
++                               * ef_eventq_is_rx_sop_cont_bad() has
++                               * side effects - order is important
++                               */
++                              if(unlikely
++                                 (ef_eventq_is_rx_sop_cont_bad_efab
++                                  (evq, &evs->generic.ev) )) {
++                                      mark_bad(evs);
++                              }
++                      }
++                      falcon_rx_event(evs, &evs->generic.ev);
++                      --evs_len;      
++                      ++evs;
++                      break;
++
++              case TX_IP_EV_DECODE:
++                      falcon_tx_event(evs, &evs->generic.ev);
++                      --evs_len;
++                      ++evs;
++                      break;
++
++              default:
++                      break;
 +              }
++      } while( evs_len );
 +
-+              dev_info(&dev->dev, "seizing device\n");
-+              err = pcistub_seize(dev);
-+      } else
-+              /* Didn't find the device */
-+              err = -ENODEV;
++      return evs_len_orig - evs_len;
 +
-+      out:
-+      return err;
++
++ overflow:
++      evs->generic.type = EF_EVENT_TYPE_OFLOW;
++      evs->generic.ev.u64[0] = (uint64_t)((int64_t)-1);
++      return 1;
 +}
 +
-+static void pcistub_remove(struct pci_dev *dev)
-+{
-+      struct pcistub_device *psdev, *found_psdev = NULL;
-+      unsigned long flags;
 +
-+      dev_dbg(&dev->dev, "removing\n");
++int/*bool*/ ef_eventq_poll_exception(void* priv, ef_vi* evq, ef_event* ev)
++{
++      int /*bool*/ handled = 0;
++  
++      switch( ev->generic.ev.u32[1] >> (EV_CODE_LBN - 32u) ) {
++      case DRIVER_EV_DECODE:
++              if( QWORD_GET_U(DRIVER_EV_SUB_CODE, ev->generic.ev) ==
++                  EVQ_INIT_DONE_EV_DECODE )
++                      /* EVQ initialised event: ignore. */
++                      handled = 1;
++              break;
++      }
++      return handled;
++}
 +
-+      spin_lock_irqsave(&pcistub_devices_lock, flags);
 +
-+      pciback_config_quirk_release(dev);
++void ef_eventq_iterate(ef_vi* vi,
++                     void (*fn)(void* arg, ef_vi*, int rel_pos,
++                                int abs_pos, void* event),
++                     void* arg, int stop_at_end)
++{
++      int i, size_evs = (vi->evq_mask + 1) / sizeof(ef_vi_event);
 +
-+      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+              if (psdev->dev == dev) {
-+                      found_psdev = psdev;
++      for( i = 0; i < size_evs; ++i ) {
++              ef_vi_event* e = EF_VI_EVENT_PTR(vi, -i);
++              if( EF_VI_IS_EVENT(e) )
++                      fn(arg, vi, i, 
++                         EF_VI_EVENT_OFFSET(vi, -i) / sizeof(ef_vi_event),
++                         e);
++              else if( stop_at_end )
 +                      break;
-+              }
 +      }
++}
 +
-+      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
 +
-+      if (found_psdev) {
-+              dev_dbg(&dev->dev, "found device to remove - in use? %p\n",
-+                      found_psdev->pdev);
++int ef_eventq_has_event(ef_vi* vi)
++{
++      return EF_VI_IS_EVENT(EF_VI_EVENT_PTR(vi, 0));
++}
 +
-+              if (found_psdev->pdev) {
-+                      printk(KERN_WARNING "pciback: ****** removing device "
-+                             "%s while still in-use! ******\n",
-+                             pci_name(found_psdev->dev));
-+                      printk(KERN_WARNING "pciback: ****** driver domain may "
-+                             "still access this device's i/o resources!\n");
-+                      printk(KERN_WARNING "pciback: ****** shutdown driver "
-+                             "domain before binding device\n");
-+                      printk(KERN_WARNING "pciback: ****** to other drivers "
-+                             "or domains\n");
 +
-+                      pciback_release_pci_dev(found_psdev->pdev,
-+                                              found_psdev->dev);
-+              }
++int ef_eventq_has_many_events(ef_vi* vi, int look_ahead)
++{
++      ef_assert_ge(look_ahead, 0);
++      return EF_VI_IS_EVENT(EF_VI_EVENT_PTR(vi, -look_ahead));
++}
 +
-+              spin_lock_irqsave(&pcistub_devices_lock, flags);
-+              list_del(&found_psdev->dev_list);
-+              spin_unlock_irqrestore(&pcistub_devices_lock, flags);
 +
-+              /* the final put for releasing from the list */
-+              pcistub_device_put(found_psdev);
++int ef_eventq_has_rx_event(ef_vi* vi)
++{
++      ef_vi_event* ev;
++      int i, n_evs = 0;
++
++      for( i = 0;  EF_VI_IS_EVENT(EF_VI_EVENT_PTR(vi, i)); --i ) {
++              ev = EF_VI_EVENT_PTR(vi, i);
++              if( EFVI_FALCON_EVENT_CODE(ev) == EF_EVENT_TYPE_RX )  n_evs++;
 +      }
++      return n_evs;
 +}
 +
-+static struct pci_device_id pcistub_ids[] = {
-+      {
-+       .vendor = PCI_ANY_ID,
-+       .device = PCI_ANY_ID,
-+       .subvendor = PCI_ANY_ID,
-+       .subdevice = PCI_ANY_ID,
-+       },
-+      {0,},
-+};
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/falcon_vi.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/falcon_vi.c   2008-05-19 00:33:48.678952031 +0300
+@@ -0,0 +1,465 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
 +/*
-+ * Note: There is no MODULE_DEVICE_TABLE entry here because this isn't
-+ * for a normal device. I don't want it to be loaded automatically.
++ * \author  djr, stg
++ *  \brief  Falcon-specific VI
++ *   \date  2006/11/30
 + */
 +
-+static struct pci_driver pciback_pci_driver = {
-+      .name = "pciback",
-+      .id_table = pcistub_ids,
-+      .probe = pcistub_probe,
-+      .remove = pcistub_remove,
-+};
-+
-+static inline int str_to_slot(const char *buf, int *domain, int *bus,
-+                            int *slot, int *func)
-+{
-+      int err;
-+
-+      err = sscanf(buf, " %x:%x:%x.%x", domain, bus, slot, func);
-+      if (err == 4)
-+              return 0;
-+      else if (err < 0)
-+              return -EINVAL;
++#include "ef_vi_internal.h"
 +
-+      /* try again without domain */
-+      *domain = 0;
-+      err = sscanf(buf, " %x:%x.%x", bus, slot, func);
-+      if (err == 3)
-+              return 0;
 +
-+      return -EINVAL;
-+}
++#define EFVI_FALCON_DMA_TX_FRAG               1
 +
-+static inline int str_to_quirk(const char *buf, int *domain, int *bus, int
-+                             *slot, int *func, int *reg, int *size, int *mask)
-+{
-+      int err;
 +
-+      err =
-+          sscanf(buf, " %04x:%02x:%02x.%1x-%08x:%1x:%08x", domain, bus, slot,
-+                 func, reg, size, mask);
-+      if (err == 7)
-+              return 0;
-+      return -EINVAL;
-+}
++/* TX descriptor for both physical and virtual packet transfers */
++typedef union {
++      uint32_t        dword[2];
++} ef_vi_falcon_dma_tx_buf_desc;
++typedef ef_vi_falcon_dma_tx_buf_desc ef_vi_falcon_dma_tx_phys_desc;
 +
-+static int pcistub_device_id_add(int domain, int bus, int slot, int func)
-+{
-+      struct pcistub_device_id *pci_dev_id;
-+      unsigned long flags;
 +
-+      pci_dev_id = kmalloc(sizeof(*pci_dev_id), GFP_KERNEL);
-+      if (!pci_dev_id)
-+              return -ENOMEM;
++/* RX descriptor for physical addressed transfers */
++typedef union {
++      uint32_t        dword[2];
++} ef_vi_falcon_dma_rx_phys_desc;
 +
-+      pci_dev_id->domain = domain;
-+      pci_dev_id->bus = bus;
-+      pci_dev_id->devfn = PCI_DEVFN(slot, func);
 +
-+      pr_debug("pciback: wants to seize %04x:%02x:%02x.%01x\n",
-+               domain, bus, slot, func);
++/* RX descriptor for virtual packet transfers */
++typedef struct {
++      uint32_t        dword[1];
++} ef_vi_falcon_dma_rx_buf_desc;
 +
-+      spin_lock_irqsave(&device_ids_lock, flags);
-+      list_add_tail(&pci_dev_id->slot_list, &pcistub_device_ids);
-+      spin_unlock_irqrestore(&device_ids_lock, flags);
++/* Buffer table index */
++typedef uint32_t              ef_vi_buffer_addr_t;
 +
-+      return 0;
++ef_vi_inline int64_t dma_addr_to_u46(int64_t src_dma_addr)
++{
++      return (src_dma_addr & __FALCON_MASK(46, int64_t));
 +}
 +
-+static int pcistub_device_id_remove(int domain, int bus, int slot, int func)
++/*! Setup a physical address based descriptor with a specified length */
++ef_vi_inline void
++__falcon_dma_rx_calc_ip_phys(ef_vi_dma_addr_t dest_pa, 
++                           ef_vi_falcon_dma_rx_phys_desc *desc,
++                           int bytes)
 +{
-+      struct pcistub_device_id *pci_dev_id, *t;
-+      int devfn = PCI_DEVFN(slot, func);
-+      int err = -ENOENT;
-+      unsigned long flags;
++      int region = 0;                 /* TODO fixme */
++      int64_t dest    = dma_addr_to_u46(dest_pa); /* lower 46 bits */
 +
-+      spin_lock_irqsave(&device_ids_lock, flags);
-+      list_for_each_entry_safe(pci_dev_id, t, &pcistub_device_ids, slot_list) {
++      DWCHCK(__DW2(RX_KER_BUF_SIZE_LBN),  RX_KER_BUF_SIZE_WIDTH);
++      DWCHCK(__DW2(RX_KER_BUF_REGION_LBN),RX_KER_BUF_REGION_WIDTH);
 +
-+              if (pci_dev_id->domain == domain
-+                  && pci_dev_id->bus == bus && pci_dev_id->devfn == devfn) {
-+                      /* Don't break; here because it's possible the same
-+                       * slot could be in the list more than once
-+                       */
-+                      list_del(&pci_dev_id->slot_list);
-+                      kfree(pci_dev_id);
++      LWCHK(RX_KER_BUF_ADR_LBN, RX_KER_BUF_ADR_WIDTH);
 +
-+                      err = 0;
++      RANGECHCK(bytes,  RX_KER_BUF_SIZE_WIDTH);
++      RANGECHCK(region, RX_KER_BUF_REGION_WIDTH);
 +
-+                      pr_debug("pciback: removed %04x:%02x:%02x.%01x from "
-+                               "seize list\n", domain, bus, slot, func);
-+              }
-+      }
-+      spin_unlock_irqrestore(&device_ids_lock, flags);
++      ef_assert(desc);
 +
-+      return err;
++      desc->dword[1] = ((bytes << __DW2(RX_KER_BUF_SIZE_LBN)) |
++                        (region << __DW2(RX_KER_BUF_REGION_LBN)) |
++                        (HIGH(dest,
++                              RX_KER_BUF_ADR_LBN, 
++                              RX_KER_BUF_ADR_WIDTH)));
++
++      desc->dword[0] = LOW(dest, 
++                           RX_KER_BUF_ADR_LBN, 
++                           RX_KER_BUF_ADR_WIDTH);
 +}
 +
-+static int pcistub_reg_add(int domain, int bus, int slot, int func, int reg,
-+                         int size, int mask)
++/*! Setup a virtual buffer descriptor for an IPMODE transfer */
++ef_vi_inline void
++__falcon_dma_tx_calc_ip_buf(unsigned buf_id, unsigned buf_ofs, unsigned bytes,
++                          int port, int frag, 
++                          ef_vi_falcon_dma_tx_buf_desc *desc)
 +{
-+      int err = 0;
-+      struct pcistub_device *psdev;
-+      struct pci_dev *dev;
-+      struct config_field *field;
++      DWCHCK(__DW2(TX_USR_PORT_LBN), TX_USR_PORT_WIDTH);
++      DWCHCK(__DW2(TX_USR_CONT_LBN), TX_USR_CONT_WIDTH);
++      DWCHCK(__DW2(TX_USR_BYTE_CNT_LBN), TX_USR_BYTE_CNT_WIDTH);
++      LWCHK(RX_KER_BUF_ADR_LBN, RX_KER_BUF_ADR_WIDTH);
++      DWCHCK(TX_USR_BYTE_OFS_LBN, TX_USR_BYTE_OFS_WIDTH);
 +
-+      psdev = pcistub_device_find(domain, bus, slot, func);
-+      if (!psdev || !psdev->dev) {
-+              err = -ENODEV;
-+              goto out;
-+      }
-+      dev = psdev->dev;
++      RANGECHCK(bytes,   TX_USR_BYTE_CNT_WIDTH);
++      RANGECHCK(port,    TX_USR_PORT_WIDTH);
++      RANGECHCK(frag,    TX_USR_CONT_WIDTH);
++      RANGECHCK(buf_id,  TX_USR_BUF_ID_WIDTH);
++      RANGECHCK(buf_ofs, TX_USR_BYTE_OFS_WIDTH);
 +
-+      field = kzalloc(sizeof(*field), GFP_ATOMIC);
-+      if (!field) {
-+              err = -ENOMEM;
-+              goto out;
-+      }
++      ef_assert(desc);
 +
-+      field->offset = reg;
-+      field->size = size;
-+      field->mask = mask;
-+      field->init = NULL;
-+      field->reset = NULL;
-+      field->release = NULL;
-+      field->clean = pciback_config_field_free;
++      desc->dword[1] = ((port   <<  __DW2(TX_USR_PORT_LBN))      | 
++                        (frag   <<  __DW2(TX_USR_CONT_LBN))      | 
++                        (bytes  <<  __DW2(TX_USR_BYTE_CNT_LBN))  |
++                        (HIGH(buf_id, 
++                              TX_USR_BUF_ID_LBN,
++                              TX_USR_BUF_ID_WIDTH)));
 +
-+      err = pciback_config_quirks_add_field(dev, field);
-+      if (err)
-+              kfree(field);
-+      out:
-+      return err;
++      desc->dword[0] =  ((LOW(buf_id,
++                              TX_USR_BUF_ID_LBN,
++                              (TX_USR_BUF_ID_WIDTH))) |
++                         (buf_ofs << TX_USR_BYTE_OFS_LBN));
 +}
 +
-+static ssize_t pcistub_slot_add(struct device_driver *drv, const char *buf,
-+                              size_t count)
++ef_vi_inline void
++falcon_dma_tx_calc_ip_buf_4k(unsigned buf_vaddr, unsigned bytes,
++                           int port, int frag, 
++                           ef_vi_falcon_dma_tx_buf_desc *desc)
 +{
-+      int domain, bus, slot, func;
-+      int err;
-+
-+      err = str_to_slot(buf, &domain, &bus, &slot, &func);
-+      if (err)
-+              goto out;
-+
-+      err = pcistub_device_id_add(domain, bus, slot, func);
++      /* TODO FIXME [buf_vaddr] consists of the buffer index in the
++      ** high bits, and an offset in the low bits. Assumptions
++      ** permate the code that these can be rolled into one 32bit
++      ** value, so this is currently preserved for Falcon. But we
++      ** should change to support 8K pages
++      */
++      unsigned buf_id =  EFVI_FALCON_BUFFER_4K_PAGE(buf_vaddr);
++      unsigned buf_ofs = EFVI_FALCON_BUFFER_4K_OFF(buf_vaddr);
 +
-+      out:
-+      if (!err)
-+              err = count;
-+      return err;
++      __falcon_dma_tx_calc_ip_buf( buf_id, buf_ofs, bytes, port, frag, desc);
 +}
 +
-+DRIVER_ATTR(new_slot, S_IWUSR, NULL, pcistub_slot_add);
-+
-+static ssize_t pcistub_slot_remove(struct device_driver *drv, const char *buf,
-+                                 size_t count)
++ef_vi_inline void
++falcon_dma_tx_calc_ip_buf(unsigned buf_vaddr, unsigned bytes, int port, 
++                        int frag, ef_vi_falcon_dma_tx_buf_desc *desc)
 +{
-+      int domain, bus, slot, func;
-+      int err;
-+
-+      err = str_to_slot(buf, &domain, &bus, &slot, &func);
-+      if (err)
-+              goto out;
-+
-+      err = pcistub_device_id_remove(domain, bus, slot, func);
-+
-+      out:
-+      if (!err)
-+              err = count;
-+      return err;
++      falcon_dma_tx_calc_ip_buf_4k(buf_vaddr, bytes, port, frag, desc);
 +}
 +
-+DRIVER_ATTR(remove_slot, S_IWUSR, NULL, pcistub_slot_remove);
++/*! Setup a virtual buffer based descriptor */
++ef_vi_inline void
++__falcon_dma_rx_calc_ip_buf(unsigned buf_id, unsigned buf_ofs, 
++                          ef_vi_falcon_dma_rx_buf_desc *desc)
++{ 
++      /* check alignment of buffer offset and pack */
++      ef_assert((buf_ofs & 0x1) == 0);
 +
-+static ssize_t pcistub_slot_show(struct device_driver *drv, char *buf)
-+{
-+      struct pcistub_device_id *pci_dev_id;
-+      size_t count = 0;
-+      unsigned long flags;
++      buf_ofs >>= 1;
 +
-+      spin_lock_irqsave(&device_ids_lock, flags);
-+      list_for_each_entry(pci_dev_id, &pcistub_device_ids, slot_list) {
-+              if (count >= PAGE_SIZE)
-+                      break;
++      DWCHCK(RX_USR_2BYTE_OFS_LBN, RX_USR_2BYTE_OFS_WIDTH);
++      DWCHCK(RX_USR_BUF_ID_LBN, RX_USR_BUF_ID_WIDTH);
 +
-+              count += scnprintf(buf + count, PAGE_SIZE - count,
-+                                 "%04x:%02x:%02x.%01x\n",
-+                                 pci_dev_id->domain, pci_dev_id->bus,
-+                                 PCI_SLOT(pci_dev_id->devfn),
-+                                 PCI_FUNC(pci_dev_id->devfn));
-+      }
-+      spin_unlock_irqrestore(&device_ids_lock, flags);
++      RANGECHCK(buf_ofs, RX_USR_2BYTE_OFS_WIDTH);
++      RANGECHCK(buf_id,  RX_USR_BUF_ID_WIDTH);
 +
-+      return count;
++      ef_assert(desc);
++
++      desc->dword[0] = ((buf_ofs << RX_USR_2BYTE_OFS_LBN) | 
++                        (buf_id  << RX_USR_BUF_ID_LBN));
 +}
 +
-+DRIVER_ATTR(slots, S_IRUSR, pcistub_slot_show, NULL);
++ef_vi_inline void
++falcon_dma_rx_calc_ip_buf_4k(unsigned buf_vaddr, 
++                           ef_vi_falcon_dma_rx_buf_desc *desc)
++{ 
++      /* TODO FIXME [buf_vaddr] consists of the buffer index in the
++      ** high bits, and an offset in the low bits. Assumptions
++      ** permeate the code that these can be rolled into one 32bit
++      ** value, so this is currently preserved for Falcon. But we
++      ** should change to support 8K pages
++      */
++      unsigned buf_id =  EFVI_FALCON_BUFFER_4K_PAGE(buf_vaddr);
++      unsigned buf_ofs = EFVI_FALCON_BUFFER_4K_OFF(buf_vaddr);
 +
-+static ssize_t pcistub_quirk_add(struct device_driver *drv, const char *buf,
-+                               size_t count)
-+{
-+      int domain, bus, slot, func, reg, size, mask;
-+      int err;
++      __falcon_dma_rx_calc_ip_buf(buf_id, buf_ofs, desc);
++}
 +
-+      err = str_to_quirk(buf, &domain, &bus, &slot, &func, &reg, &size,
-+                         &mask);
-+      if (err)
-+              goto out;
++ef_vi_inline void
++falcon_dma_rx_calc_ip_buf(unsigned buf_vaddr, 
++                        ef_vi_falcon_dma_rx_buf_desc *desc)
++{ 
++      falcon_dma_rx_calc_ip_buf_4k(buf_vaddr, desc);
++}
 +
-+      err = pcistub_reg_add(domain, bus, slot, func, reg, size, mask);
 +
-+      out:
-+      if (!err)
-+              err = count;
-+      return err;
++ef_vi_inline ef_vi_dma_addr_t ef_physaddr(ef_addr efaddr)
++{
++      return (ef_vi_dma_addr_t) efaddr;
 +}
 +
-+static ssize_t pcistub_quirk_show(struct device_driver *drv, char *buf)
-+{
-+      int count = 0;
-+      unsigned long flags;
-+      extern struct list_head pciback_quirks;
-+      struct pciback_config_quirk *quirk;
-+      struct pciback_dev_data *dev_data;
-+      struct config_field *field;
-+      struct config_field_entry *cfg_entry;
 +
-+      spin_lock_irqsave(&device_ids_lock, flags);
-+      list_for_each_entry(quirk, &pciback_quirks, quirks_list) {
-+              if (count >= PAGE_SIZE)
-+                      goto out;
++/*! Convert between an ef_addr and a buffer table index
++**  Assert that this was not a physical address
++*/
++ef_vi_inline ef_vi_buffer_addr_t ef_bufaddr(ef_addr efaddr)
++{
++      ef_assert(efaddr < ((uint64_t)1 << 32) );
 +
-+              count += scnprintf(buf + count, PAGE_SIZE - count,
-+                                 "%02x:%02x.%01x\n\t%04x:%04x:%04x:%04x\n",
-+                                 quirk->pdev->bus->number,
-+                                 PCI_SLOT(quirk->pdev->devfn),
-+                                 PCI_FUNC(quirk->pdev->devfn),
-+                                 quirk->devid.vendor, quirk->devid.device,
-+                                 quirk->devid.subvendor,
-+                                 quirk->devid.subdevice);
++      return (ef_vi_buffer_addr_t) efaddr;
++}
 +
-+              dev_data = pci_get_drvdata(quirk->pdev);
 +
-+              list_for_each_entry(cfg_entry, &dev_data->config_fields, list) {
-+                      field = cfg_entry->field;
-+                      if (count >= PAGE_SIZE)
-+                              goto out;
++/*! Setup an physical address based descriptor for an IPMODE transfer */
++ef_vi_inline void
++falcon_dma_tx_calc_ip_phys(ef_vi_dma_addr_t src_dma_addr, unsigned bytes, 
++                         int port, int frag,
++                         ef_vi_falcon_dma_tx_phys_desc *desc)
++{
 +
-+                      count += scnprintf(buf + count, PAGE_SIZE - count,
-+                                         "\t\t%08x:%01x:%08x\n",
-+                                         cfg_entry->base_offset + field->offset, 
-+                                         field->size, field->mask);
-+              }
-+      }
++      int region = 0; /* FIXME */
++      int64_t src    = dma_addr_to_u46(src_dma_addr); /* lower 46 bits */
 +
-+      out:
-+      spin_unlock_irqrestore(&device_ids_lock, flags);
++      DWCHCK(__DW2(TX_KER_PORT_LBN),      TX_KER_PORT_WIDTH);
++      DWCHCK(__DW2(TX_KER_CONT_LBN),      TX_KER_CONT_WIDTH);
++      DWCHCK(__DW2(TX_KER_BYTE_CNT_LBN),  TX_KER_BYTE_CNT_WIDTH);
++      DWCHCK(__DW2(TX_KER_BUF_REGION_LBN),TX_KER_BUF_REGION_WIDTH);
 +
-+      return count;
-+}
++      LWCHK(TX_KER_BUF_ADR_LBN, TX_KER_BUF_ADR_WIDTH);
 +
-+DRIVER_ATTR(quirks, S_IRUSR | S_IWUSR, pcistub_quirk_show, pcistub_quirk_add);
++      RANGECHCK(port,   TX_KER_PORT_WIDTH);
++      RANGECHCK(frag,   TX_KER_CONT_WIDTH);
++      RANGECHCK(bytes,  TX_KER_BYTE_CNT_WIDTH);
++      RANGECHCK(region, TX_KER_BUF_REGION_WIDTH);
 +
-+static ssize_t permissive_add(struct device_driver *drv, const char *buf,
-+                            size_t count)
-+{
-+      int domain, bus, slot, func;
-+      int err;
-+      struct pcistub_device *psdev;
-+      struct pciback_dev_data *dev_data;
-+      err = str_to_slot(buf, &domain, &bus, &slot, &func);
-+      if (err)
-+              goto out;
-+      psdev = pcistub_device_find(domain, bus, slot, func);
-+      if (!psdev) {
-+              err = -ENODEV;
-+              goto out;
-+      }
-+      if (!psdev->dev) {
-+              err = -ENODEV;
-+              goto release;
-+      }
-+      dev_data = pci_get_drvdata(psdev->dev);
-+      /* the driver data for a device should never be null at this point */
-+      if (!dev_data) {
-+              err = -ENXIO;
-+              goto release;
-+      }
-+      if (!dev_data->permissive) {
-+              dev_data->permissive = 1;
-+              /* Let user know that what they're doing could be unsafe */
-+              dev_warn(&psdev->dev->dev,
-+                       "enabling permissive mode configuration space accesses!\n");
-+              dev_warn(&psdev->dev->dev,
-+                       "permissive mode is potentially unsafe!\n");
-+      }
-+      release:
-+      pcistub_device_put(psdev);
-+      out:
-+      if (!err)
-+              err = count;
-+      return err;
-+}
++      desc->dword[1] = ((port   <<  __DW2(TX_KER_PORT_LBN))      | 
++                        (frag   <<  __DW2(TX_KER_CONT_LBN))      | 
++                        (bytes  <<  __DW2(TX_KER_BYTE_CNT_LBN))  | 
++                        (region << __DW2(TX_KER_BUF_REGION_LBN)) |
++                        (HIGH(src,
++                              TX_KER_BUF_ADR_LBN, 
++                              TX_KER_BUF_ADR_WIDTH)));
 +
-+static ssize_t permissive_show(struct device_driver *drv, char *buf)
-+{
-+      struct pcistub_device *psdev;
-+      struct pciback_dev_data *dev_data;
-+      size_t count = 0;
-+      unsigned long flags;
-+      spin_lock_irqsave(&pcistub_devices_lock, flags);
-+      list_for_each_entry(psdev, &pcistub_devices, dev_list) {
-+              if (count >= PAGE_SIZE)
-+                      break;
-+              if (!psdev->dev)
-+                      continue;
-+              dev_data = pci_get_drvdata(psdev->dev);
-+              if (!dev_data || !dev_data->permissive)
-+                      continue;
-+              count +=
-+                  scnprintf(buf + count, PAGE_SIZE - count, "%s\n",
-+                            pci_name(psdev->dev));
-+      }
-+      spin_unlock_irqrestore(&pcistub_devices_lock, flags);
-+      return count;
++      ef_assert_equal(TX_KER_BUF_ADR_LBN, 0);
++      desc->dword[0] = (uint32_t) src_dma_addr;
 +}
 +
-+DRIVER_ATTR(permissive, S_IRUSR | S_IWUSR, permissive_show, permissive_add);
 +
-+static void pcistub_exit(void)
++void falcon_vi_init(ef_vi* vi, void* vvis)
 +{
-+      driver_remove_file(&pciback_pci_driver.driver, &driver_attr_new_slot);
-+      driver_remove_file(&pciback_pci_driver.driver,
-+                         &driver_attr_remove_slot);
-+      driver_remove_file(&pciback_pci_driver.driver, &driver_attr_slots);
-+      driver_remove_file(&pciback_pci_driver.driver, &driver_attr_quirks);
-+      driver_remove_file(&pciback_pci_driver.driver, &driver_attr_permissive);
++      struct vi_mappings *vm = (struct vi_mappings*)vvis;
++      uint16_t* ids;
 +
-+      pci_unregister_driver(&pciback_pci_driver);
-+}
++      ef_assert(vi);
++      ef_assert(vvis);
++      ef_assert_equal(vm->signature, VI_MAPPING_SIGNATURE);
++      ef_assert_equal(vm->nic_type.arch, EF_VI_ARCH_FALCON);
 +
-+static int __init pcistub_init(void)
-+{
-+      int pos = 0;
-+      int err = 0;
-+      int domain, bus, slot, func;
-+      int parsed;
++      /* Initialise masks to zero, so that ef_vi_state_init() will
++      ** not do any harm when we don't have DMA queues. */
++      vi->vi_rxq.mask = vi->vi_txq.mask = 0;
 +
-+      if (pci_devs_to_hide && *pci_devs_to_hide) {
-+              do {
-+                      parsed = 0;
++      /* Used for BUG5391_WORKAROUND. */
++      vi->vi_txq.misalign_mask = 0;
 +
-+                      err = sscanf(pci_devs_to_hide + pos,
-+                                   " (%x:%x:%x.%x) %n",
-+                                   &domain, &bus, &slot, &func, &parsed);
-+                      if (err != 4) {
-+                              domain = 0;
-+                              err = sscanf(pci_devs_to_hide + pos,
-+                                           " (%x:%x.%x) %n",
-+                                           &bus, &slot, &func, &parsed);
-+                              if (err != 3)
-+                                      goto parse_error;
-+                      }
++      /* Initialise doorbell addresses to a distinctive small value
++      ** which will cause a segfault, to trap doorbell pushes to VIs
++      ** without DMA queues. */
++      vi->vi_rxq.doorbell = vi->vi_txq.doorbell = (ef_vi_ioaddr_t)0xdb;
 +
-+                      err = pcistub_device_id_add(domain, bus, slot, func);
-+                      if (err)
-+                              goto out;
++      ids = (uint16_t*) (vi->ep_state + 1);
 +
-+                      /* if parsed<=0, we've reached the end of the string */
-+                      pos += parsed;
-+              } while (parsed > 0 && pci_devs_to_hide[pos]);
++      if( vm->tx_queue_capacity ) {
++              vi->vi_txq.mask = vm->tx_queue_capacity - 1;
++              vi->vi_txq.doorbell = vm->tx_bell + 12;
++              vi->vi_txq.descriptors = vm->tx_dma_falcon;
++              vi->vi_txq.ids = ids;
++              ids += vi->vi_txq.mask + 1;
++              /* Check that the id fifo fits in the space allocated. */
++              ef_assert_le((char*) (vi->vi_txq.ids + vm->tx_queue_capacity),
++                           (char*) vi->ep_state
++                           + ef_vi_calc_state_bytes(vm->rx_queue_capacity,
++                                                    vm->tx_queue_capacity));
++      }
++      if( vm->rx_queue_capacity ) {
++              vi->vi_rxq.mask = vm->rx_queue_capacity - 1;
++              vi->vi_rxq.doorbell = vm->rx_bell + 12;
++              vi->vi_rxq.descriptors = vm->rx_dma_falcon;
++              vi->vi_rxq.ids = ids;
++              /* Check that the id fifo fits in the space allocated. */
++              ef_assert_le((char*) (vi->vi_rxq.ids + vm->rx_queue_capacity),
++                           (char*) vi->ep_state
++                           + ef_vi_calc_state_bytes(vm->rx_queue_capacity,
++                                                    vm->tx_queue_capacity));
 +      }
 +
-+      /* If we're the first PCI Device Driver to register, we're the
-+       * first one to get offered PCI devices as they become
-+       * available (and thus we can be the first to grab them)
-+       */
-+      err = pci_register_driver(&pciback_pci_driver);
-+      if (err < 0)
-+              goto out;
-+
-+      err = driver_create_file(&pciback_pci_driver.driver,
-+                               &driver_attr_new_slot);
-+      if (!err)
-+              err = driver_create_file(&pciback_pci_driver.driver,
-+                                       &driver_attr_remove_slot);
-+      if (!err)
-+              err = driver_create_file(&pciback_pci_driver.driver,
-+                                       &driver_attr_slots);
-+      if (!err)
-+              err = driver_create_file(&pciback_pci_driver.driver,
-+                                       &driver_attr_quirks);
-+      if (!err)
-+              err = driver_create_file(&pciback_pci_driver.driver,
-+                                       &driver_attr_permissive);
-+
-+      if (err)
-+              pcistub_exit();
-+
-+      out:
-+      return err;
-+
-+      parse_error:
-+      printk(KERN_ERR "pciback: Error parsing pci_devs_to_hide at \"%s\"\n",
-+             pci_devs_to_hide + pos);
-+      return -EINVAL;
++      if( vm->nic_type.variant == 'A' ) {
++              vi->vi_txq.misalign_mask = 15;    /* BUG5391_WORKAROUND */
++              vi->vi_flags |= EF_VI_BUG5692_WORKAROUND;
++      }
 +}
 +
-+#ifndef MODULE
-+/*
-+ * fs_initcall happens before device_initcall
-+ * so pciback *should* get called first (b/c we 
-+ * want to suck up any device before other drivers
-+ * get a chance by being the first pci device
-+ * driver to register)
-+ */
-+fs_initcall(pcistub_init);
-+#endif
 +
-+static int __init pciback_init(void)
++int ef_vi_transmitv_init(ef_vi* vi, const ef_iovec* iov, int iov_len,
++                       ef_request_id dma_id)
 +{
-+      int err;
-+
-+      err = pciback_config_init();
-+      if (err)
-+              return err;
++      ef_vi_txq* q = &vi->vi_txq;
++      ef_vi_txq_state* qs = &vi->ep_state->txq;
++      ef_vi_falcon_dma_tx_buf_desc* dp;
++      unsigned len, dma_len, di;
++      unsigned added_save = qs->added;
++      ef_addr dma_addr;
++      unsigned last_len = 0;
 +
-+#ifdef MODULE
-+      err = pcistub_init();
-+      if (err < 0)
-+              return err;
-+#endif
++      ef_assert(iov_len > 0);
++      ef_assert(iov);
++      ef_assert_equal((dma_id & EF_REQUEST_ID_MASK), dma_id);
++      ef_assert_nequal(dma_id, 0xffff);
 +
-+      pcistub_init_devices_late();
-+      err = pciback_xenbus_register();
-+      if (err)
-+              pcistub_exit();
++      dma_addr = iov->iov_base;
++      len = iov->iov_len;
 +
-+      return err;
-+}
++      if( vi->vi_flags & EF_VI_ISCSI_TX_DDIG ) {
++              /* Last 4 bytes of placeholder for digest must be
++               * removed for h/w */
++              ef_assert(len > 4);
++              last_len = iov[iov_len - 1].iov_len;
++              if( last_len <= 4 ) {
++                      ef_assert(iov_len > 1);
++                      --iov_len;
++                      last_len = iov[iov_len - 1].iov_len - (4 - last_len);
++              }
++              else {
++                      last_len = iov[iov_len - 1].iov_len - 4;
++              }
++              if( iov_len == 1 )
++                      len = last_len;
++      }
 +
-+static void __exit pciback_cleanup(void)
-+{
-+      pciback_xenbus_unregister();
-+      pcistub_exit();
-+}
++      while( 1 ) {
++              if( qs->added - qs->removed >= q->mask ) {
++                      qs->added = added_save;
++                      return -EAGAIN;
++              }
 +
-+module_init(pciback_init);
-+module_exit(pciback_cleanup);
++              dma_len = (~((unsigned) dma_addr) & 0xfff) + 1;
++              if( dma_len > len )  dma_len = len;
++              { /* BUG5391_WORKAROUND */
++                      unsigned misalign = 
++                              (unsigned) dma_addr & q->misalign_mask;
++                      if( misalign && dma_len + misalign > 512 )
++                              dma_len = 512 - misalign;
++              }
 +
-+MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/slot.c linux-2.6.18-xen.hg/drivers/xen/pciback/slot.c
---- linux-2.6.18/drivers/xen/pciback/slot.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/slot.c     2007-12-23 11:15:34.067936306 +0100
-@@ -0,0 +1,151 @@
-+/*
-+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
-+ *               to the frontend
-+ *
-+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil> (vpci.c)
-+ *   Author: Tristan Gingold <tristan.gingold@bull.net>, from vpci.c
-+ */
++              di = qs->added++ & q->mask;
++              dp = (ef_vi_falcon_dma_tx_buf_desc*) q->descriptors + di;
++              if( vi->vi_flags & EF_VI_TX_PHYS_ADDR )
++                      falcon_dma_tx_calc_ip_phys
++                              (ef_physaddr(dma_addr), dma_len, /*port*/ 0,
++                               (iov_len == 1 && dma_len == len) ? 0 :
++                               EFVI_FALCON_DMA_TX_FRAG, dp);
++              else
++                      falcon_dma_tx_calc_ip_buf
++                              (ef_bufaddr(dma_addr), dma_len, /*port*/ 0,
++                               (iov_len == 1 && dma_len == len) ? 0 :
++                               EFVI_FALCON_DMA_TX_FRAG, dp);
 +
-+#include <linux/list.h>
-+#include <linux/slab.h>
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include "pciback.h"
++              dma_addr += dma_len;
++              len -= dma_len;
 +
-+/* There are at most 32 slots in a pci bus.  */
-+#define PCI_SLOT_MAX 32
++              if( len == 0 ) {
++                      if( --iov_len == 0 )  break;
++                      ++iov;
++                      dma_addr = iov->iov_base;
++                      len = iov->iov_len;
++                      if( (vi->vi_flags & EF_VI_ISCSI_TX_DDIG) &&
++                          (iov_len == 1) )
++                              len = last_len;
++              }
++      }
 +
-+#define PCI_BUS_NBR 2
++      q->ids[di] = (uint16_t) dma_id;
++      return 0;
++}
 +
-+struct slot_dev_data {
-+      /* Access to dev_list must be protected by lock */
-+      struct pci_dev *slots[PCI_BUS_NBR][PCI_SLOT_MAX];
-+      spinlock_t lock;
-+};
 +
-+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
-+                                  unsigned int domain, unsigned int bus,
-+                                  unsigned int devfn)
++void ef_vi_transmit_push(ef_vi* vi)
 +{
-+      struct pci_dev *dev = NULL;
-+      struct slot_dev_data *slot_dev = pdev->pci_dev_data;
-+      unsigned long flags;
-+
-+      if (domain != 0 || PCI_FUNC(devfn) != 0)
-+              return NULL;
++      ef_vi_wiob();
++      writel((vi->ep_state->txq.added & vi->vi_txq.mask) <<
++              __DW4(TX_DESC_WPTR_LBN),
++              vi->vi_txq.doorbell);
++}
 +
-+      if (PCI_SLOT(devfn) >= PCI_SLOT_MAX || bus >= PCI_BUS_NBR)
-+              return NULL;
 +
-+      spin_lock_irqsave(&slot_dev->lock, flags);
-+      dev = slot_dev->slots[bus][PCI_SLOT(devfn)];
-+      spin_unlock_irqrestore(&slot_dev->lock, flags);
++/*! The value of initial_rx_bytes is used to set RX_KER_BUF_SIZE in an initial
++**  receive descriptor here if physical addressing is being used. A value of
++**  zero represents 16384 bytes.  This is okay, because caller must provide a
++**  buffer than is > MTU, and mac should filter anything bigger than that.
++*/
++int ef_vi_receive_init(ef_vi* vi, ef_addr addr, ef_request_id dma_id,
++                     int initial_rx_bytes)
++{
++      ef_vi_rxq* q = &vi->vi_rxq;
++      ef_vi_rxq_state* qs = &vi->ep_state->rxq;
++      unsigned di;
 +
-+      return dev;
-+}
++      if( ef_vi_receive_space(vi) ) {
++              di = qs->added++ & q->mask;
++              ef_assert_equal(q->ids[di], 0xffff);
++              q->ids[di] = (uint16_t) dma_id;
 +
-+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
-+{
-+      int err = 0, slot, bus;
-+      struct slot_dev_data *slot_dev = pdev->pci_dev_data;
-+      unsigned long flags;
++              if( ! (vi->vi_flags & EF_VI_RX_PHYS_ADDR) ) {
++                      ef_vi_falcon_dma_rx_buf_desc* dp;
++                      dp = (ef_vi_falcon_dma_rx_buf_desc*) 
++                              q->descriptors + di;
++                      falcon_dma_rx_calc_ip_buf(ef_bufaddr(addr), dp);
++              }
++              else {
++                      ef_vi_falcon_dma_rx_phys_desc* dp;
++                      dp = (ef_vi_falcon_dma_rx_phys_desc*) 
++                              q->descriptors + di;
++                      __falcon_dma_rx_calc_ip_phys(addr, dp,
++                                                   initial_rx_bytes);
++              }
 +
-+      if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
-+              err = -EFAULT;
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Can't export bridges on the virtual PCI bus");
-+              goto out;
++              return 0;
 +      }
 +
-+      spin_lock_irqsave(&slot_dev->lock, flags);
-+
-+      /* Assign to a new slot on the virtual PCI bus */
-+      for (bus = 0; bus < PCI_BUS_NBR; bus++)
-+              for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+                      if (slot_dev->slots[bus][slot] == NULL) {
-+                              printk(KERN_INFO
-+                                     "pciback: slot: %s: assign to virtual slot %d, bus %d\n",
-+                                     pci_name(dev), slot, bus);
-+                              slot_dev->slots[bus][slot] = dev;
-+                              goto unlock;
-+                      }
-+              }
++      return -EAGAIN;
++}
 +
-+      err = -ENOMEM;
-+      xenbus_dev_fatal(pdev->xdev, err,
-+                       "No more space on root virtual PCI bus");
 +
-+      unlock:
-+      spin_unlock_irqrestore(&slot_dev->lock, flags);
-+      out:
-+      return err;
++void ef_vi_receive_push(ef_vi* vi)
++{
++      ef_vi_wiob();
++      writel ((vi->ep_state->rxq.added & vi->vi_rxq.mask) <<
++              __DW4(RX_DESC_WPTR_LBN),
++              vi->vi_rxq.doorbell);
 +}
 +
-+void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
++
++ef_request_id ef_vi_receive_done(const ef_vi* vi, const ef_event* ef_ev)
 +{
-+      int slot, bus;
-+      struct slot_dev_data *slot_dev = pdev->pci_dev_data;
-+      struct pci_dev *found_dev = NULL;
-+      unsigned long flags;
++      const ef_vi_qword* ev = EF_GET_HW_EV_PTR(*ef_ev);
++      unsigned di = ev->u32[0] & vi->vi_rxq.mask;
++      ef_request_id rq_id;
 +
-+      spin_lock_irqsave(&slot_dev->lock, flags);
++      ef_assert(EF_EVENT_TYPE(*ef_ev) == EF_EVENT_TYPE_RX ||
++                EF_EVENT_TYPE(*ef_ev) == EF_EVENT_TYPE_RX_DISCARD);
 +
-+      for (bus = 0; bus < PCI_BUS_NBR; bus++)
-+              for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+                      if (slot_dev->slots[bus][slot] == dev) {
-+                              slot_dev->slots[bus][slot] = NULL;
-+                              found_dev = dev;
-+                              goto out;
-+                      }
-+              }
++      /* Detect spurious / duplicate RX events.  We may need to modify this
++      ** code so that we are robust if they happen. */
++      ef_assert_equal(di, vi->ep_state->rxq.removed & vi->vi_rxq.mask);
 +
-+      out:
-+      spin_unlock_irqrestore(&slot_dev->lock, flags);
++      /* We only support 1 port: so events should be in order. */
++      ef_assert(vi->vi_rxq.ids[di] != 0xffff);
 +
-+      if (found_dev)
-+              pcistub_put_pci_dev(found_dev);
++      rq_id = vi->vi_rxq.ids[di];
++      vi->vi_rxq.ids[di] = 0xffff;
++      ++vi->ep_state->rxq.removed;
++      return rq_id;
 +}
 +
-+int pciback_init_devices(struct pciback_device *pdev)
-+{
-+      int slot, bus;
-+      struct slot_dev_data *slot_dev;
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/pt_tx.c    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/pt_tx.c       2008-05-19 00:33:48.678952031 +0300
+@@ -0,0 +1,91 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      slot_dev = kmalloc(sizeof(*slot_dev), GFP_KERNEL);
-+      if (!slot_dev)
-+              return -ENOMEM;
++/*
++ * \author  djr
++ *  \brief  Packet-mode transmit interface.
++ *   \date  2003/04/02
++ */
++
++/*! \cidoxg_lib_ef */
++#include "ef_vi_internal.h"
 +
-+      spin_lock_init(&slot_dev->lock);
 +
-+      for (bus = 0; bus < PCI_BUS_NBR; bus++)
-+              for (slot = 0; slot < PCI_SLOT_MAX; slot++)
-+                      slot_dev->slots[bus][slot] = NULL;
++int ef_vi_transmit_init(ef_vi* vi, ef_addr base, int len, ef_request_id dma_id)
++{
++      ef_iovec iov = { base, len };
++      return ef_vi_transmitv_init(vi, &iov, 1, dma_id);
++}
 +
-+      pdev->pci_dev_data = slot_dev;
 +
-+      return 0;
++int ef_vi_transmit(ef_vi* vi, ef_addr base, int len, ef_request_id dma_id)
++{
++      ef_iovec iov = { base, len };
++      int rc = ef_vi_transmitv_init(vi, &iov, 1, dma_id);
++      if( rc == 0 )  ef_vi_transmit_push(vi);
++      return rc;
 +}
 +
-+int pciback_publish_pci_roots(struct pciback_device *pdev,
-+                            publish_pci_root_cb publish_cb)
++
++int ef_vi_transmitv(ef_vi* vi, const ef_iovec* iov, int iov_len,
++                    ef_request_id dma_id)
 +{
-+      /* The Virtual PCI bus has only one root */
-+      return publish_cb(pdev, 0, 0);
++      int rc = ef_vi_transmitv_init(vi, iov, iov_len, dma_id);
++      if( rc == 0 )  ef_vi_transmit_push(vi);
++      return rc;
 +}
 +
-+void pciback_release_devices(struct pciback_device *pdev)
++
++int ef_vi_transmit_unbundle(ef_vi* vi, const ef_event* __ev,
++                          ef_request_id* ids)
 +{
-+      int slot, bus;
-+      struct slot_dev_data *slot_dev = pdev->pci_dev_data;
-+      struct pci_dev *dev;
++      ef_request_id* ids_in = ids;
++      ef_vi_txq* q = &vi->vi_txq;
++      ef_vi_txq_state* qs = &vi->ep_state->txq;
++      const ef_vi_qword* ev = EF_GET_HW_EV_PTR(*__ev);
++      unsigned i, stop = (ev->u32[0] + 1) & q->mask;
 +
-+      for (bus = 0; bus < PCI_BUS_NBR; bus++)
-+              for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+                      dev = slot_dev->slots[bus][slot];
-+                      if (dev != NULL)
-+                              pcistub_put_pci_dev(dev);
++      ef_assert(EF_EVENT_TYPE(*__ev) == EF_EVENT_TYPE_TX ||
++                EF_EVENT_TYPE(*__ev) == EF_EVENT_TYPE_TX_ERROR);
++
++      /* Shouldn't be batching more than 64 descriptors, and should not go
++      ** backwards. */
++      ef_assert_le((((ev->u32[0] + 1) - qs->removed) & q->mask), 64);
++      /* Should not complete more than we've posted. */
++      ef_assert_le((((ev->u32[0] + 1) - qs->removed) & q->mask),
++                   qs->added - qs->removed);
++
++      for( i = qs->removed & q->mask; i != stop; i = ++qs->removed & q->mask )
++              if( q->ids[i] != 0xffff ) {
++                      *ids++ = q->ids[i];
++                      q->ids[i] = 0xffff;
 +              }
 +
-+      kfree(slot_dev);
-+      pdev->pci_dev_data = NULL;
++      ef_assert_le(ids - ids_in, EF_VI_TRANSMIT_BATCH);
++
++      return (int) (ids - ids_in);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/vpci.c linux-2.6.18-xen.hg/drivers/xen/pciback/vpci.c
---- linux-2.6.18/drivers/xen/pciback/vpci.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/vpci.c     2007-12-23 11:15:34.067936306 +0100
-@@ -0,0 +1,204 @@
-+/*
-+ * PCI Backend - Provides a Virtual PCI bus (with real devices)
-+ *               to the frontend
++
++/*! \cidoxg_end */
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/sysdep.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/sysdep.h      2008-05-19 00:33:48.682952261 +0300
+@@ -0,0 +1,184 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
 + *
-+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <linux/list.h>
-+#include <linux/slab.h>
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include "pciback.h"
++/*
++ * \author  stg
++ *  \brief  System dependent support for ef vi lib
++ *   \date  2007/05/10
++ */
 +
-+#define PCI_SLOT_MAX 32
++/*! \cidoxg_include_ci_ul */
++#ifndef __CI_CIUL_SYSDEP_LINUX_H__
++#define __CI_CIUL_SYSDEP_LINUX_H__
 +
-+struct vpci_dev_data {
-+      /* Access to dev_list must be protected by lock */
-+      struct list_head dev_list[PCI_SLOT_MAX];
-+      spinlock_t lock;
-+};
++/**********************************************************************
++ * Kernel version compatability
++ */
 +
-+static inline struct list_head *list_first(struct list_head *head)
-+{
-+      return head->next;
-+}
++#if defined(__GNUC__)
 +
-+struct pci_dev *pciback_get_pci_dev(struct pciback_device *pdev,
-+                                  unsigned int domain, unsigned int bus,
-+                                  unsigned int devfn)
-+{
-+      struct pci_dev_entry *entry;
-+      struct pci_dev *dev = NULL;
-+      struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
-+      unsigned long flags;
++/* Linux kernel doesn't have stdint.h or [u]intptr_t. */
++# if !defined(LINUX_VERSION_CODE)
++#  include <linux/version.h>
++# endif
++# include <asm/io.h>
 +
-+      if (domain != 0 || bus != 0)
-+              return NULL;
++/* In Linux 2.6.24, linux/types.h has uintptr_t */
++# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
++#  if BITS_PER_LONG == 32
++   typedef __u32         uintptr_t;
++#  else
++   typedef __u64         uintptr_t;
++#  endif
++# endif
 +
-+      if (PCI_SLOT(devfn) < PCI_SLOT_MAX) {
-+              spin_lock_irqsave(&vpci_dev->lock, flags);
++/* But even 2.6.24 doesn't define intptr_t */
++# if BITS_PER_LONG == 32
++   typedef __s32         intptr_t;
++# else
++   typedef __s64         intptr_t;
++# endif
 +
-+              list_for_each_entry(entry,
-+                                  &vpci_dev->dev_list[PCI_SLOT(devfn)],
-+                                  list) {
-+                      if (PCI_FUNC(entry->dev->devfn) == PCI_FUNC(devfn)) {
-+                              dev = entry->dev;
-+                              break;
-+                      }
-+              }
++# if defined(__ia64__)
++#  define EF_VI_PRIx64  "lx"
++# else
++#  define EF_VI_PRIx64  "llx"
++# endif
 +
-+              spin_unlock_irqrestore(&vpci_dev->lock, flags);
-+      }
-+      return dev;
-+}
++# define EF_VI_HF __attribute__((visibility("hidden")))
++# define EF_VI_HV __attribute__((visibility("hidden")))
 +
-+static inline int match_slot(struct pci_dev *l, struct pci_dev *r)
-+{
-+      if (pci_domain_nr(l->bus) == pci_domain_nr(r->bus)
-+          && l->bus == r->bus && PCI_SLOT(l->devfn) == PCI_SLOT(r->devfn))
-+              return 1;
++# if defined(__i386__) || defined(__x86_64__)  /* GCC x86/x64 */
++   typedef unsigned long long ef_vi_dma_addr_t; 
++#  if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
++#   define ef_vi_wiob()  __asm__ __volatile__ ("sfence")
++#  else
++#   define ef_vi_wiob()  __asm__ __volatile__ (".byte 0x0F, 0xAE, 0xF8")
++#  endif
 +
-+      return 0;
-+}
++# endif
++#endif
 +
-+int pciback_add_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
-+{
-+      int err = 0, slot;
-+      struct pci_dev_entry *t, *dev_entry;
-+      struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
-+      unsigned long flags;
++#ifdef EFX_NOT_UPSTREAM
++
++/* Stuff for architectures/compilers not officially supported */
++
++#if !defined(__GNUC__)
++# if defined(__PPC__)  /* GCC, PPC */
++   typedef unsigned long     ef_vi_dma_addr_t;
++#  define ef_vi_wiob()  wmb()
++
++#  ifdef __powerpc64__
++#   ifdef CONFIG_SMP
++#    define CI_SMP_SYNC        "\n   eieio     \n"         /* memory cache sync */
++#    define CI_SMP_ISYNC       "\n   isync     \n"         /* instr cache sync */
++#   else
++#    define CI_SMP_SYNC
++#    define CI_SMP_ISYNC
++#   endif
++#  else        /* for ppc32 systems */
++#   ifdef CONFIG_SMP
++#    define CI_SMP_SYNC        "\n   eieio     \n"
++#    define CI_SMP_ISYNC       "\n   sync      \n"
++#   else
++#    define CI_SMP_SYNC
++#    define CI_SMP_ISYNC
++#   endif
++#  endif
 +
-+      if ((dev->class >> 24) == PCI_BASE_CLASS_BRIDGE) {
-+              err = -EFAULT;
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Can't export bridges on the virtual PCI bus");
-+              goto out;
-+      }
++# elif defined(__ia64__)  /* GCC, IA64 */
++   typedef unsigned long     ef_vi_dma_addr_t;
++#  define ef_vi_wiob()  __asm__ __volatile__("mf.a": : :"memory")
 +
-+      dev_entry = kmalloc(sizeof(*dev_entry), GFP_KERNEL);
-+      if (!dev_entry) {
-+              err = -ENOMEM;
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Error adding entry to virtual PCI bus");
-+              goto out;
-+      }
++# else
++#  error Unknown processor - GNU C
++# endif
 +
-+      dev_entry->dev = dev;
++#elif defined(__PGI)
++# error PGI not supported 
 +
-+      spin_lock_irqsave(&vpci_dev->lock, flags);
++#elif defined(__INTEL_COMPILER)
 +
-+      /* Keep multi-function devices together on the virtual PCI bus */
-+      for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+              if (!list_empty(&vpci_dev->dev_list[slot])) {
-+                      t = list_entry(list_first(&vpci_dev->dev_list[slot]),
-+                                     struct pci_dev_entry, list);
++/* Intel compilers v7 claim to be very gcc compatible. */
++# if __INTEL_COMPILER >= 700
++#  if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ > 91)
++#   define EF_VI_LIKELY(t)    __builtin_expect((t), 1)
++#   define EF_VI_UNLIKELY(t)  __builtin_expect((t), 0)
++#  endif
 +
-+                      if (match_slot(dev, t->dev)) {
-+                              pr_info("pciback: vpci: %s: "
-+                                      "assign to virtual slot %d func %d\n",
-+                                      pci_name(dev), slot,
-+                                      PCI_FUNC(dev->devfn));
-+                              list_add_tail(&dev_entry->list,
-+                                            &vpci_dev->dev_list[slot]);
-+                              goto unlock;
-+                      }
-+              }
-+      }
++#  if __GNUC__ >= 3 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
++#   define ef_vi_wiob()  __asm__ __volatile__ ("sfence")
++#  else
++#   define ef_vi_wiob()  __asm__ __volatile__ (".byte 0x0F, 0xAE, 0xF8")
++#  endif
 +
-+      /* Assign to a new slot on the virtual PCI bus */
-+      for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+              if (list_empty(&vpci_dev->dev_list[slot])) {
-+                      printk(KERN_INFO
-+                             "pciback: vpci: %s: assign to virtual slot %d\n",
-+                             pci_name(dev), slot);
-+                      list_add_tail(&dev_entry->list,
-+                                    &vpci_dev->dev_list[slot]);
-+                      goto unlock;
-+              }
-+      }
++# else
++#  error Old Intel compiler not supported.
++# endif
 +
-+      err = -ENOMEM;
-+      xenbus_dev_fatal(pdev->xdev, err,
-+                       "No more space on root virtual PCI bus");
++#else
++# error Unknown compiler.
++#endif
 +
-+      unlock:
-+      spin_unlock_irqrestore(&vpci_dev->lock, flags);
-+      out:
-+      return err;
-+}
++#endif
 +
-+void pciback_release_pci_dev(struct pciback_device *pdev, struct pci_dev *dev)
-+{
-+      int slot;
-+      struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
-+      struct pci_dev *found_dev = NULL;
-+      unsigned long flags;
 +
-+      spin_lock_irqsave(&vpci_dev->lock, flags);
++# include <linux/errno.h>
 +
-+      for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+              struct pci_dev_entry *e, *tmp;
-+              list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
-+                                       list) {
-+                      if (e->dev == dev) {
-+                              list_del(&e->list);
-+                              found_dev = e->dev;
-+                              kfree(e);
-+                              goto out;
-+                      }
-+              }
-+      }
 +
-+      out:
-+      spin_unlock_irqrestore(&vpci_dev->lock, flags);
++/**********************************************************************
++ * Extracting bit fields.
++ */
 +
-+      if (found_dev)
-+              pcistub_put_pci_dev(found_dev);
-+}
++#define _QWORD_GET_LOW(f, v)                                    \
++  (((v).u32[0] >> (f##_LBN)) & ((1u << f##_WIDTH) - 1u))
++#define _QWORD_GET_HIGH(f, v)                                           \
++  (((v).u32[1] >> (f##_LBN - 32u)) & ((1u << f##_WIDTH) - 1u))
++#define _QWORD_GET_ANY(f, v)                                            \
++  (((v).u64[0] >> f##_LBN) & (((uint64_t) 1u << f##_WIDTH) - 1u))
 +
-+int pciback_init_devices(struct pciback_device *pdev)
-+{
-+      int slot;
-+      struct vpci_dev_data *vpci_dev;
++#define QWORD_GET(f, v)                                                     \
++  ((f##_LBN + f##_WIDTH) <= 32u                                             \
++   ? _QWORD_GET_LOW(f, (v))                                                 \
++   : ((f##_LBN >= 32u) ? _QWORD_GET_HIGH(f, (v)) : _QWORD_GET_ANY(f, (v))))
 +
-+      vpci_dev = kmalloc(sizeof(*vpci_dev), GFP_KERNEL);
-+      if (!vpci_dev)
-+              return -ENOMEM;
++#define QWORD_GET_U(f, v)  ((unsigned) QWORD_GET(f, (v)))
 +
-+      spin_lock_init(&vpci_dev->lock);
++#define _QWORD_TEST_BIT_LOW(f, v)   ((v).u32[0] & (1u << (f##_LBN)))
++#define _QWORD_TEST_BIT_HIGH(f, v)  ((v).u32[1] & (1u << (f##_LBN - 32u)))
 +
-+      for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+              INIT_LIST_HEAD(&vpci_dev->dev_list[slot]);
-+      }
++#define QWORD_TEST_BIT(f, v)                                                  \
++  (f##_LBN < 32 ? _QWORD_TEST_BIT_LOW(f, (v)) : _QWORD_TEST_BIT_HIGH(f, (v)))
 +
-+      pdev->pci_dev_data = vpci_dev;
 +
-+      return 0;
-+}
 +
-+int pciback_publish_pci_roots(struct pciback_device *pdev,
-+                            publish_pci_root_cb publish_cb)
-+{
-+      /* The Virtual PCI bus has only one root */
-+      return publish_cb(pdev, 0, 0);
-+}
 +
-+void pciback_release_devices(struct pciback_device *pdev)
-+{
-+      int slot;
-+      struct vpci_dev_data *vpci_dev = pdev->pci_dev_data;
++#ifndef DECLSPEC_NORETURN
++/* normally defined on Windows to expand to a declaration that the
++   function will not return */
++# define DECLSPEC_NORETURN
++#endif
 +
-+      for (slot = 0; slot < PCI_SLOT_MAX; slot++) {
-+              struct pci_dev_entry *e, *tmp;
-+              list_for_each_entry_safe(e, tmp, &vpci_dev->dev_list[slot],
-+                                       list) {
-+                      list_del(&e->list);
-+                      pcistub_put_pci_dev(e->dev);
-+                      kfree(e);
-+              }
-+      }
++#endif  /* __CI_CIUL_SYSDEP_LINUX_H__ */
+--- linux-2.6.18.8/drivers/xen/sfc_netfront/vi_init.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netfront/vi_init.c     2008-05-19 00:33:48.682952261 +0300
+@@ -0,0 +1,183 @@
++/****************************************************************************
++ * Copyright 2002-2005: Level 5 Networks Inc.
++ * Copyright 2005-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications
++ *  <linux-xen-drivers@solarflare.com>
++ *  <onload-dev@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      kfree(vpci_dev);
-+      pdev->pci_dev_data = NULL;
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pciback/xenbus.c linux-2.6.18-xen.hg/drivers/xen/pciback/xenbus.c
---- linux-2.6.18/drivers/xen/pciback/xenbus.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pciback/xenbus.c   2007-12-23 11:15:34.067936306 +0100
-@@ -0,0 +1,454 @@
 +/*
-+ * PCI Backend Xenbus Setup - handles setup with frontend and xend
-+ *
-+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ * \author  djr
++ *  \brief  Initialisation of VIs.
++ *   \date  2007/06/08
 + */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/list.h>
-+#include <linux/vmalloc.h>
-+#include <xen/xenbus.h>
-+#include <xen/evtchn.h>
-+#include "pciback.h"
 +
-+#define INVALID_EVTCHN_IRQ  (-1)
++#include "ef_vi_internal.h"
 +
-+static struct pciback_device *alloc_pdev(struct xenbus_device *xdev)
++#define EF_VI_STATE_BYTES(rxq_sz, txq_sz)                     \
++      (sizeof(ef_vi_state) + (rxq_sz) * sizeof(uint16_t)      \
++       + (txq_sz) * sizeof(uint16_t))
++
++int ef_vi_calc_state_bytes(int rxq_sz, int txq_sz)
 +{
-+      struct pciback_device *pdev;
++      ef_assert(rxq_sz == 0 || EF_VI_IS_POW2(rxq_sz));
++      ef_assert(txq_sz == 0 || EF_VI_IS_POW2(txq_sz));
 +
-+      pdev = kzalloc(sizeof(struct pciback_device), GFP_KERNEL);
-+      if (pdev == NULL)
-+              goto out;
-+      dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev);
++      return EF_VI_STATE_BYTES(rxq_sz, txq_sz);
++}
 +
-+      pdev->xdev = xdev;
-+      xdev->dev.driver_data = pdev;
 +
-+      spin_lock_init(&pdev->dev_lock);
++int ef_vi_state_bytes(ef_vi* vi)
++{
++      int rxq_sz = 0, txq_sz = 0;
++      if( ef_vi_receive_capacity(vi) )
++              rxq_sz = ef_vi_receive_capacity(vi) + 1;
++      if( ef_vi_transmit_capacity(vi) )
++              txq_sz = ef_vi_transmit_capacity(vi) + 1;
 +
-+      pdev->sh_area = NULL;
-+      pdev->sh_info = NULL;
-+      pdev->evtchn_irq = INVALID_EVTCHN_IRQ;
-+      pdev->be_watching = 0;
++      ef_assert(rxq_sz == 0 || EF_VI_IS_POW2(rxq_sz));
++      ef_assert(txq_sz == 0 || EF_VI_IS_POW2(txq_sz));
 +
-+      INIT_WORK(&pdev->op_work, pciback_do_op, pdev);
++      return EF_VI_STATE_BYTES(rxq_sz, txq_sz);
++}
 +
-+      if (pciback_init_devices(pdev)) {
-+              kfree(pdev);
-+              pdev = NULL;
++
++void ef_eventq_state_init(ef_vi* evq)
++{
++      int j;
++
++      for (j = 0; j<EFAB_DMAQS_PER_EVQ_MAX; j++) {
++              ef_rx_dup_state_t *rx_dup_state =
++                      &evq->evq_state->rx_dup_state[j];
++              rx_dup_state->bad_sop = 0;
++              rx_dup_state->rx_last_desc_ptr = -1;
++              rx_dup_state->frag_num = 0;
 +      }
-+      out:
-+      return pdev;
++
++      evq->evq_state->evq_ptr = 0;
 +}
 +
-+static void free_pdev(struct pciback_device *pdev)
-+{
-+      if (pdev->be_watching)
-+              unregister_xenbus_watch(&pdev->be_watch);
 +
-+      /* Ensure the guest can't trigger our handler before removing devices */
-+      if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ)
-+              unbind_from_irqhandler(pdev->evtchn_irq, pdev);
++void ef_vi_state_init(ef_vi* vi)
++{
++      ef_vi_state* state = vi->ep_state;
++      unsigned i;
 +
-+      /* If the driver domain started an op, make sure we complete it or
-+       * delete it before releasing the shared memory */
-+      cancel_delayed_work(&pdev->op_work);
-+      flush_scheduled_work();
++      state->txq.added = state->txq.removed = 0;
++      state->rxq.added = state->rxq.removed = 0;
 +
-+      if (pdev->sh_info)
-+              xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_area);
++      if( vi->vi_rxq.mask )
++              for( i = 0; i <= vi->vi_rxq.mask; ++i )
++                      vi->vi_rxq.ids[i] = (uint16_t) -1;
++      if( vi->vi_txq.mask )
++              for( i = 0; i <= vi->vi_txq.mask; ++i )
++                      vi->vi_txq.ids[i] = (uint16_t) -1;
++}
 +
-+      pciback_release_devices(pdev);
 +
-+      pdev->xdev->dev.driver_data = NULL;
-+      pdev->xdev = NULL;
++void ef_vi_init_mapping_evq(void* data_area, struct ef_vi_nic_type nic_type,
++                            int instance, unsigned evq_bytes, void* base,
++                            void* timer_reg)
++{
++      struct vi_mappings* vm = (struct vi_mappings*) data_area;
 +
-+      kfree(pdev);
++      vm->signature = VI_MAPPING_SIGNATURE;
++      vm->vi_instance = instance;
++      vm->nic_type = nic_type;
++      vm->evq_bytes = evq_bytes;
++      vm->evq_base = base;
++      vm->evq_timer_reg = timer_reg;
 +}
 +
-+static int pciback_do_attach(struct pciback_device *pdev, int gnt_ref,
-+                           int remote_evtchn)
++
++void ef_vi_init(ef_vi* vi, void* vvis, ef_vi_state* state,
++                ef_eventq_state* evq_state, enum ef_vi_flags vi_flags)
 +{
-+      int err = 0;
-+      struct vm_struct *area;
++      struct vi_mappings* vm = (struct vi_mappings*) vvis;
 +
-+      dev_dbg(&pdev->xdev->dev,
-+              "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n",
-+              gnt_ref, remote_evtchn);
++      vi->vi_i = vm->vi_instance;
++      vi->ep_state = state;
++      vi->vi_flags = vi_flags;
 +
-+      area = xenbus_map_ring_valloc(pdev->xdev, gnt_ref);
-+      if (IS_ERR(area)) {
-+              err = PTR_ERR(area);
-+              goto out;
++      switch( vm->nic_type.arch ) {
++      case EF_VI_ARCH_FALCON:
++              falcon_vi_init(vi, vvis);
++              break;
++      default:
++              /* ?? TODO: We should return an error code. */
++              ef_assert(0);
++              break;
 +      }
-+      pdev->sh_area = area;
-+      pdev->sh_info = area->addr;
 +
-+      err = bind_interdomain_evtchn_to_irqhandler(
-+              pdev->xdev->otherend_id, remote_evtchn, pciback_handle_event,
-+              SA_SAMPLE_RANDOM, "pciback", pdev);
-+      if (err < 0) {
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Error binding event channel to IRQ");
-+              goto out;
++      if( vm->evq_bytes ) {
++              vi->evq_state = evq_state;
++              vi->evq_mask = vm->evq_bytes - 1u;
++              vi->evq_base = vm->evq_base;
++              vi->evq_timer_reg = vm->evq_timer_reg;
 +      }
-+      pdev->evtchn_irq = err;
-+      err = 0;
 +
-+      dev_dbg(&pdev->xdev->dev, "Attached!\n");
-+      out:
-+      return err;
++      EF_VI_MAGIC_SET(vi, EF_VI);
 +}
 +
-+static int pciback_attach(struct pciback_device *pdev)
++
++/* Initialise [data_area] with information required to initialise an ef_vi.
++ * In the following, an unused param should be set to NULL. Note the case
++ * marked (*) of [iobuf_mmap] for falcon/driver; for the normal driver this
++ * must be NULL.
++ *
++ * \param  data_area     [in,out] required, must ref at least VI_MAPPING_SIZE 
++ *                                bytes
++ * \param  io_mmap       [in] ef1,    required
++ *                            falcon, required
++ * \param  iobuf_mmap    [in] ef1,    unused
++ *                            falcon, required
++ */
++void ef_vi_init_mapping_vi(void* data_area, struct ef_vi_nic_type nic_type,
++                           unsigned rxq_capacity, unsigned txq_capacity,
++                           int instance, void* io_mmap,
++                           void* iobuf_mmap_rx, void* iobuf_mmap_tx,
++                           enum ef_vi_flags vi_flags)
 +{
-+      int err = 0;
-+      int gnt_ref, remote_evtchn;
-+      char *magic = NULL;
++      struct vi_mappings* vm = (struct vi_mappings*) data_area;
++      int rx_desc_bytes, rxq_bytes;
 +
-+      spin_lock(&pdev->dev_lock);
++      ef_assert(rxq_capacity > 0 || txq_capacity > 0);
++      ef_assert(vm);
++      ef_assert(io_mmap);
++      ef_assert(iobuf_mmap_rx || iobuf_mmap_tx);
 +
-+      /* Make sure we only do this setup once */
-+      if (xenbus_read_driver_state(pdev->xdev->nodename) !=
-+          XenbusStateInitialised)
-+              goto out;
++      vm->signature = VI_MAPPING_SIGNATURE;
++      vm->vi_instance = instance;
++      vm->nic_type = nic_type;
 +
-+      /* Wait for frontend to state that it has published the configuration */
-+      if (xenbus_read_driver_state(pdev->xdev->otherend) !=
-+          XenbusStateInitialised)
-+              goto out;
++      rx_desc_bytes = (vi_flags & EF_VI_RX_PHYS_ADDR) ? 8 : 4;
++      rxq_bytes = rxq_capacity * rx_desc_bytes;
++      rxq_bytes = (rxq_bytes + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1);
 +
-+      dev_dbg(&pdev->xdev->dev, "Reading frontend config\n");
++      if( iobuf_mmap_rx == iobuf_mmap_tx )
++              iobuf_mmap_tx = (char*) iobuf_mmap_rx + rxq_bytes;
 +
-+      err = xenbus_gather(XBT_NIL, pdev->xdev->otherend,
-+                          "pci-op-ref", "%u", &gnt_ref,
-+                          "event-channel", "%u", &remote_evtchn,
-+                          "magic", NULL, &magic, NULL);
-+      if (err) {
-+              /* If configuration didn't get read correctly, wait longer */
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Error reading configuration from frontend");
-+              goto out;
-+      }
++      vm->rx_queue_capacity = rxq_capacity;
++      vm->rx_dma_falcon = iobuf_mmap_rx;
++      vm->rx_bell       = (char*) io_mmap + (RX_DESC_UPD_REG_KER_OFST & 4095);
++      vm->tx_queue_capacity = txq_capacity;
++      vm->tx_dma_falcon = iobuf_mmap_tx;
++      vm->tx_bell       = (char*) io_mmap + (TX_DESC_UPD_REG_KER_OFST & 4095);
++}
+--- linux-2.6.18.8/drivers/xen/sfc_netutil/Makefile    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netutil/Makefile       2008-05-19 00:33:48.682952261 +0300
+@@ -0,0 +1,11 @@
++EXTRA_CFLAGS += -Idrivers/xen/sfc_netutil
++EXTRA_CFLAGS += -Werror
 +
-+      if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) {
-+              xenbus_dev_fatal(pdev->xdev, -EFAULT,
-+                               "version mismatch (%s/%s) with pcifront - "
-+                               "halting pciback",
-+                               magic, XEN_PCI_MAGIC);
-+              goto out;
-+      }
++ifdef GGOV
++EXTRA_CFLAGS += -fprofile-arcs -ftest-coverage -DEFX_GCOV
++endif
 +
-+      err = pciback_do_attach(pdev, gnt_ref, remote_evtchn);
-+      if (err)
-+              goto out;
++obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL) := sfc_netutil.o
 +
-+      dev_dbg(&pdev->xdev->dev, "Connecting...\n");
++sfc_netutil-objs := accel_cuckoo_hash.o accel_msg_iface.o accel_util.o 
 +
-+      err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
-+      if (err)
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Error switching to connected state!");
+--- linux-2.6.18.8/drivers/xen/sfc_netutil/accel_cuckoo_hash.c 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netutil/accel_cuckoo_hash.c    2008-05-19 00:33:48.706953645 +0300
+@@ -0,0 +1,651 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err);
-+      out:
-+      spin_unlock(&pdev->dev_lock);
++#include <linux/types.h> /* needed for linux/random.h */
++#include <linux/random.h>
 +
-+      if (magic)
-+              kfree(magic);
++#include "accel_cuckoo_hash.h"
++#include "accel_util.h"
 +
-+      return err;
++static inline int cuckoo_hash_key_compare(cuckoo_hash_table *hashtab,
++                                        cuckoo_hash_key *key1, 
++                                        cuckoo_hash_key *key2)
++{
++      return !memcmp(key1, key2, hashtab->key_length);
 +}
 +
-+static void pciback_frontend_changed(struct xenbus_device *xdev,
-+                                   enum xenbus_state fe_state)
++
++static inline void cuckoo_hash_key_set(cuckoo_hash_key *key1, 
++                                     cuckoo_hash_key *key2)
 +{
-+      struct pciback_device *pdev = xdev->dev.driver_data;
++      *key1 = *key2;
++}
 +
-+      dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state);
 +
-+      switch (fe_state) {
-+      case XenbusStateInitialised:
-+              pciback_attach(pdev);
-+              break;
++/*
++ * Sets hash function parameters.  Chooses "a" to be odd, 0 < a < 2^w
++ * where w is the length of the key
++ */
++static void set_hash_parameters(cuckoo_hash_table *hashtab)
++{
++ again:
++      hashtab->a0 = hashtab->a1 = 0;
 +
-+      case XenbusStateClosing:
-+              xenbus_switch_state(xdev, XenbusStateClosing);
-+              break;
++      /* Make sure random */
++      get_random_bytes(&hashtab->a0, hashtab->key_length);
++      get_random_bytes(&hashtab->a1, hashtab->key_length);
 +
-+      case XenbusStateUnknown:
-+      case XenbusStateClosed:
-+              dev_dbg(&xdev->dev, "frontend is gone! unregister device\n");
-+              device_unregister(&xdev->dev);
-+              break;
++      /* Make sure odd */
++      hashtab->a0 |= 1;
++      hashtab->a1 |= 1;
 +
-+      default:
-+              break;
-+      }
++      /* Being different is good */
++      if (hashtab->a0 != hashtab->a1)
++              return;
++                     
++      goto again;
 +}
 +
-+static int pciback_publish_pci_root(struct pciback_device *pdev,
-+                                  unsigned int domain, unsigned int bus)
++int cuckoo_hash_init(cuckoo_hash_table *hashtab, unsigned length_bits,
++                   unsigned key_length)
 +{
-+      unsigned int d, b;
-+      int i, root_num, len, err;
-+      char str[64];
-+
-+      dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n");
++      char *table_mem;
++      unsigned length = 1 << length_bits;
 +
-+      err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
-+                         "root_num", "%d", &root_num);
-+      if (err == 0 || err == -ENOENT)
-+              root_num = 0;
-+      else if (err < 0)
-+              goto out;
-+
-+      /* Verify that we haven't already published this pci root */
-+      for (i = 0; i < root_num; i++) {
-+              len = snprintf(str, sizeof(str), "root-%d", i);
-+              if (unlikely(len >= (sizeof(str) - 1))) {
-+                      err = -ENOMEM;
-+                      goto out;
-+              }
++      BUG_ON(length_bits >= sizeof(unsigned) * 8);
++      BUG_ON(key_length > sizeof(cuckoo_hash_key));
 +
-+              err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename,
-+                                 str, "%x:%x", &d, &b);
-+              if (err < 0)
-+                      goto out;
-+              if (err != 2) {
-+                      err = -EINVAL;
-+                      goto out;
-+              }
++      table_mem = kmalloc(sizeof(cuckoo_hash_entry) * 2 * length, GFP_KERNEL);
 +
-+              if (d == domain && b == bus) {
-+                      err = 0;
-+                      goto out;
-+              }
-+      }
++      if (table_mem == NULL)
++              return -ENOMEM;
 +
-+      len = snprintf(str, sizeof(str), "root-%d", root_num);
-+      if (unlikely(len >= (sizeof(str) - 1))) {
-+              err = -ENOMEM;
-+              goto out;
-+      }
++      hashtab->length = length;
++      hashtab->length_bits = length_bits;
++      hashtab->key_length = key_length;
++      hashtab->entries = 0;
 +
-+      dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n",
-+              root_num, domain, bus);
++      hashtab->table0 = (cuckoo_hash_entry *)table_mem;
++      hashtab->table1 = (cuckoo_hash_entry *)
++              (table_mem + length * sizeof(cuckoo_hash_entry));
 +
-+      err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str,
-+                          "%04x:%02x", domain, bus);
-+      if (err)
-+              goto out;
++      set_hash_parameters(hashtab);
 +
-+      err = xenbus_printf(XBT_NIL, pdev->xdev->nodename,
-+                          "root_num", "%d", (root_num + 1));
++      /* Zero the table */
++      memset(hashtab->table0, 0, length * 2 * sizeof(cuckoo_hash_entry));
 +
-+      out:
-+      return err;
++      return 0;
 +}
++EXPORT_SYMBOL_GPL(cuckoo_hash_init);
 +
-+static int pciback_export_device(struct pciback_device *pdev,
-+                               int domain, int bus, int slot, int func)
++void cuckoo_hash_destroy(cuckoo_hash_table *hashtab)
 +{
-+      struct pci_dev *dev;
-+      int err = 0;
-+
-+      dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n",
-+              domain, bus, slot, func);
++      if (hashtab->table0 != NULL)
++              kfree(hashtab->table0);
++}
 +
-+      dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func);
-+      if (!dev) {
-+              err = -EINVAL;
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Couldn't locate PCI device "
-+                               "(%04x:%02x:%02x.%01x)! "
-+                               "perhaps already in-use?",
-+                               domain, bus, slot, func);
-+              goto out;
-+      }
++EXPORT_SYMBOL_GPL(cuckoo_hash_destroy);
 +
-+      err = pciback_add_pci_dev(pdev, dev);
-+      if (err)
-+              goto out;
++/* 
++ * This computes sizeof(cuckoo_hash) bits of hash, not all will be
++ * necessarily used, but the hash function throws away any that
++ * aren't
++ */ 
++static inline void cuckoo_compute_hash_helper(cuckoo_hash_table *hashtab,
++                                            cuckoo_hash_key *a,
++                                            cuckoo_hash_key *x,
++                                            cuckoo_hash *result) 
++{
++      u64 multiply_result = 0, a_temp, x_temp;
++      u32 carry = 0;
++      u32 *a_words;
++      u32 *x_words;
++      int i;
 +
-+      /* TODO: It'd be nice to export a bridge and have all of its children
-+       * get exported with it. This may be best done in xend (which will
-+       * have to calculate resource usage anyway) but we probably want to
-+       * put something in here to ensure that if a bridge gets given to a
-+       * driver domain, that all devices under that bridge are not given
-+       * to other driver domains (as he who controls the bridge can disable
-+       * it and stop the other devices from working).
++      /*
++       * As the mod and div operations in the function effectively
++       * reduce and shift the bits of the product down to just the
++       * third word, we need only compute that and return it as a
++       * result.
++       *
++       * Do enough long multiplication to get the word we need
 +       */
-+      out:
-+      return err;
++
++      /* This assumes things about the sizes of the key and hash */
++      BUG_ON(hashtab->key_length % sizeof(u32) != 0);
++      BUG_ON(sizeof(cuckoo_hash) != sizeof(u32));
++
++      a_words = (u32 *)a;
++      x_words = (u32 *)x;
++
++      for (i = 0; i < hashtab->key_length / sizeof(u32); i++) {
++              a_temp = a_words[i];
++              x_temp = x_words[i];
++              
++              multiply_result = (a_temp * x_temp) + carry;
++              carry = (multiply_result >> 32) & 0xffffffff;
++      }
++      
++      *result = multiply_result & 0xffffffff;
 +}
 +
-+static int pciback_setup_backend(struct pciback_device *pdev)
++
++/*
++ * Want to implement (ax mod 2^w) div 2^(w-q) for odd a, 0 < a < 2^w;
++ * w is the length of the key, q is the length of the hash, I think.
++ * See http://www.it-c.dk/people/pagh/papers/cuckoo-jour.pdf 
++ */
++static cuckoo_hash cuckoo_compute_hash(cuckoo_hash_table *hashtab, 
++                                     cuckoo_hash_key *key, 
++                                     cuckoo_hash_key *a)
 +{
-+      /* Get configuration from xend (if available now) */
-+      int domain, bus, slot, func;
-+      int err = 0;
-+      int i, num_devs;
-+      char dev_str[64];
++      unsigned q = hashtab->length_bits;
++      unsigned shift = 32 - q;
++      unsigned mask = ((1 << q) - 1) << shift;
++      cuckoo_hash hash;
 +
-+      spin_lock(&pdev->dev_lock);
++      cuckoo_compute_hash_helper(hashtab, a, key, &hash);
 +
-+      /* It's possible we could get the call to setup twice, so make sure
-+       * we're not already connected.
++      /* 
++       * Take the top few bits to get the right length for this
++       * hash table 
 +       */
-+      if (xenbus_read_driver_state(pdev->xdev->nodename) !=
-+          XenbusStateInitWait)
-+              goto out;
++      hash = (hash & mask) >> shift;
 +
-+      dev_dbg(&pdev->xdev->dev, "getting be setup\n");
++      BUG_ON(hash >= hashtab->length);
 +
-+      err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d",
-+                         &num_devs);
-+      if (err != 1) {
-+              if (err >= 0)
-+                      err = -EINVAL;
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Error reading number of devices");
-+              goto out;
-+      }
++      return hash;
++}
 +
-+      for (i = 0; i < num_devs; i++) {
-+              int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i);
-+              if (unlikely(l >= (sizeof(dev_str) - 1))) {
-+                      err = -ENOMEM;
-+                      xenbus_dev_fatal(pdev->xdev, err,
-+                                       "String overflow while reading "
-+                                       "configuration");
-+                      goto out;
-+              }
 +
-+              err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str,
-+                                 "%x:%x:%x.%x", &domain, &bus, &slot, &func);
-+              if (err < 0) {
-+                      xenbus_dev_fatal(pdev->xdev, err,
-+                                       "Error reading device configuration");
-+                      goto out;
-+              }
-+              if (err != 4) {
-+                      err = -EINVAL;
-+                      xenbus_dev_fatal(pdev->xdev, err,
-+                                       "Error parsing pci device "
-+                                       "configuration");
-+                      goto out;
-+              }
++static int cuckoo_hash_lookup0(cuckoo_hash_table *hashtab,
++                             cuckoo_hash_key *key,
++                             cuckoo_hash_value *value)
++{
++      cuckoo_hash hash = cuckoo_compute_hash(hashtab, key, &hashtab->a0);
 +
-+              err = pciback_export_device(pdev, domain, bus, slot, func);
-+              if (err)
-+                      goto out;
++      if ((hashtab->table0[hash].state == CUCKOO_HASH_STATE_OCCUPIED)
++          && cuckoo_hash_key_compare(hashtab, &(hashtab->table0[hash].key),
++                                     key)) {
++              *value = hashtab->table0[hash].value;
++              return 1;
 +      }
 +
-+      err = pciback_publish_pci_roots(pdev, pciback_publish_pci_root);
-+      if (err) {
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Error while publish PCI root buses "
-+                               "for frontend");
-+              goto out;
-+      }
++      return 0;
++}
 +
-+      err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
-+      if (err)
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Error switching to initialised state!");
++static int cuckoo_hash_lookup1(cuckoo_hash_table *hashtab,
++                             cuckoo_hash_key *key,
++                             cuckoo_hash_value *value)
++{
++      cuckoo_hash hash = cuckoo_compute_hash(hashtab, key, &hashtab->a1);
 +
-+      out:
-+      spin_unlock(&pdev->dev_lock);
++      if ((hashtab->table1[hash].state == CUCKOO_HASH_STATE_OCCUPIED)
++          && cuckoo_hash_key_compare(hashtab, &(hashtab->table1[hash].key),
++                                     key)) {
++              *value = hashtab->table1[hash].value;
++              return 1;
++      }
 +
-+      if (!err)
-+              /* see if pcifront is already configured (if not, we'll wait) */
-+              pciback_attach(pdev);
++      return 0;
++}
 +
-+      return err;
++
++int cuckoo_hash_lookup(cuckoo_hash_table *hashtab, cuckoo_hash_key *key,
++                     cuckoo_hash_value *value)
++{
++      return cuckoo_hash_lookup0(hashtab, key, value)
++              || cuckoo_hash_lookup1(hashtab, key, value);
 +}
++EXPORT_SYMBOL_GPL(cuckoo_hash_lookup);
 +
-+static void pciback_be_watch(struct xenbus_watch *watch,
-+                           const char **vec, unsigned int len)
++
++/* Transfer any active entries from "old_table" into hashtab */
++static int cuckoo_hash_transfer_entries(cuckoo_hash_table *hashtab,
++                                      cuckoo_hash_entry *old_table,
++                                      unsigned capacity)
 +{
-+      struct pciback_device *pdev =
-+          container_of(watch, struct pciback_device, be_watch);
++      int i, rc;
++      cuckoo_hash_entry *entry;
 +
-+      switch (xenbus_read_driver_state(pdev->xdev->nodename)) {
-+      case XenbusStateInitWait:
-+              pciback_setup_backend(pdev);
-+              break;
++      hashtab->entries = 0;
 +
-+      default:
-+              break;
++      for (i = 0; i < capacity; i++) {
++              entry = &old_table[i];
++              if (entry->state == CUCKOO_HASH_STATE_OCCUPIED) {
++                      rc = cuckoo_hash_add(hashtab, &(entry->key), 
++                                           entry->value, 0);
++                      if (rc != 0) {
++                              return rc;
++                      }
++              }
 +      }
++  
++      return 0;
 +}
 +
-+static int pciback_xenbus_probe(struct xenbus_device *dev,
-+                              const struct xenbus_device_id *id)
++
++int cuckoo_hash_rehash(cuckoo_hash_table *hashtab)
 +{
-+      int err = 0;
-+      struct pciback_device *pdev = alloc_pdev(dev);
++      cuckoo_hash_entry *new_table;
++      cuckoo_hash_table old_hashtab;
++      int resize = 0, rc, rehash_count;
 +
-+      if (pdev == NULL) {
-+              err = -ENOMEM;
-+              xenbus_dev_fatal(dev, err,
-+                               "Error allocating pciback_device struct");
-+              goto out;
++      /*
++       * Store old tables so we can access the existing values and
++       * copy across
++       */
++      memcpy(&old_hashtab, hashtab, sizeof(cuckoo_hash_table));
++
++      /* resize if hashtable is more than half full */
++      if (old_hashtab.entries > old_hashtab.length &&
++          old_hashtab.length_bits < 32)
++              resize = 1;
++
++ resize:
++      if (resize) {
++              new_table = kmalloc(sizeof(cuckoo_hash_entry) * 4 * hashtab->length,
++                                  GFP_ATOMIC);
++              if (new_table == NULL) {
++                      rc = -ENOMEM;
++                      goto err;
++              }
++
++              hashtab->length = 2 * hashtab->length;
++              hashtab->length_bits++;
++      } else {
++              new_table = kmalloc(sizeof(cuckoo_hash_entry) * 2 * hashtab->length,
++                                  GFP_ATOMIC);
++              if (new_table == NULL) {
++                      rc = -ENOMEM;
++                      goto err;
++              }
 +      }
++    
++      /*
++       * Point hashtab to new memory region so we can try to
++       * construct new table
++       */
++      hashtab->table0 = new_table;
++      hashtab->table1 = (cuckoo_hash_entry *)
++              ((char *)new_table + hashtab->length * sizeof(cuckoo_hash_entry));
++  
++      rehash_count = 0;
 +
-+      /* wait for xend to configure us */
-+      err = xenbus_switch_state(dev, XenbusStateInitWait);
-+      if (err)
-+              goto out;
++ again:
++      /* Zero the new tables */
++      memset(new_table, 0, hashtab->length * 2 * sizeof(cuckoo_hash_entry));
 +
-+      /* watch the backend node for backend configuration information */
-+      err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch,
-+                              pciback_be_watch);
-+      if (err)
-+              goto out;
-+      pdev->be_watching = 1;
++      /* Choose new parameters for the hash functions */
++      set_hash_parameters(hashtab);
 +
-+      /* We need to force a call to our callback here in case
-+       * xend already configured us!
-+       */
-+      pciback_be_watch(&pdev->be_watch, NULL, 0);
++      /*
++       * Multiply old_table_length by 2 as the length refers to each
++       * table, and there are two of them.  This assumes that they
++       * are arranged sequentially in memory, so assert it 
++       */
++      BUG_ON(((char *)old_hashtab.table1) != 
++             ((char *)old_hashtab.table0 + old_hashtab.length
++              * sizeof(cuckoo_hash_entry)));
++      rc = cuckoo_hash_transfer_entries(hashtab, old_hashtab.table0, 
++                                        old_hashtab.length * 2);
++      if (rc < 0) {
++              /* Problem */
++              if (rc == -ENOSPC) {
++                      ++rehash_count;
++                      if (rehash_count < CUCKOO_HASH_MAX_LOOP) {
++                              /*
++                               * Wanted to rehash, but rather than
++                               * recurse we can just do it here
++                               */
++                              goto again;
++                      } else {
++                              /*
++                               * Didn't manage to rehash, so let's
++                               * go up a size (if we haven't already
++                               * and there's space)
++                               */
++                              if (!resize && hashtab->length_bits < 32) {
++                                      resize = 1;
++                                      kfree(new_table);
++                                      goto resize;
++                              }
++                              else
++                                      goto err;
++                      }
++              }
++              else
++                      goto err;
++      }
 +
-+      out:
-+      return err;
++      /* Success, I think.  Free up the old table */
++      kfree(old_hashtab.table0);
++  
++      /* We should have put all the entries from old table in the new one */
++      BUG_ON(hashtab->entries != old_hashtab.entries);
++
++      return 0;
++ err:
++      EPRINTK("%s: Rehash failed, giving up\n", __FUNCTION__);
++      /* Some other error, give up, at least restore table to how it was */
++      memcpy(hashtab, &old_hashtab, sizeof(cuckoo_hash_table));
++      if (new_table)
++              kfree(new_table);
++      return rc;
 +}
++EXPORT_SYMBOL_GPL(cuckoo_hash_rehash);
 +
-+static int pciback_xenbus_remove(struct xenbus_device *dev)
++
++static int 
++cuckoo_hash_insert_or_displace(cuckoo_hash_entry *table, unsigned hash,
++                             cuckoo_hash_key *key, 
++                             cuckoo_hash_value value,
++                             cuckoo_hash_key *displaced_key, 
++                             cuckoo_hash_value *displaced_value)
 +{
-+      struct pciback_device *pdev = dev->dev.driver_data;
++      if (table[hash].state == CUCKOO_HASH_STATE_VACANT) {
++              cuckoo_hash_key_set(&(table[hash].key), key);
++              table[hash].value = value;
++              table[hash].state = CUCKOO_HASH_STATE_OCCUPIED;
 +
-+      if (pdev != NULL)
-+              free_pdev(pdev);
++              return 1;
++      } else {
++              cuckoo_hash_key_set(displaced_key, &(table[hash].key));
++              *displaced_value = table[hash].value;
++              cuckoo_hash_key_set(&(table[hash].key), key);
++              table[hash].value = value;
 +
-+      return 0;
++              return 0;
++      }
 +}
 +
-+static struct xenbus_device_id xenpci_ids[] = {
-+      {"pci"},
-+      {{0}},
-+};
-+
-+static struct xenbus_driver xenbus_pciback_driver = {
-+      .name                   = "pciback",
-+      .owner                  = THIS_MODULE,
-+      .ids                    = xenpci_ids,
-+      .probe                  = pciback_xenbus_probe,
-+      .remove                 = pciback_xenbus_remove,
-+      .otherend_changed       = pciback_frontend_changed,
-+};
 +
-+int __init pciback_xenbus_register(void)
++int cuckoo_hash_add(cuckoo_hash_table *hashtab, cuckoo_hash_key *key,
++                   cuckoo_hash_value value, int can_rehash)
 +{
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++      cuckoo_hash hash0, hash1;
++      int i, rc;
++      cuckoo_hash_key key1, key2;
 +
-+      return xenbus_register_backend(&xenbus_pciback_driver);
++      cuckoo_hash_key_set(&key1, key);
++
++ again:
++      i = 0;
++      do {
++              hash0 = cuckoo_compute_hash(hashtab, &key1, &hashtab->a0);
++              if (cuckoo_hash_insert_or_displace(hashtab->table0, hash0, 
++                                                 &key1, value, &key2,
++                                                 &value)) {
++                      /* Success */
++                      hashtab->entries++;
++                      return 0;
++              }
++      
++              hash1 = cuckoo_compute_hash(hashtab, &key2, &hashtab->a1);
++              if (cuckoo_hash_insert_or_displace(hashtab->table1, hash1,
++                                                 &key2, value, &key1,
++                                                 &value)) {
++                      /* Success */
++                      hashtab->entries++;
++                      return 0;
++              }
++      } while (++i < CUCKOO_HASH_MAX_LOOP);
++
++      if (can_rehash) {
++              if ((rc = cuckoo_hash_rehash(hashtab)) < 0) {
++                      /*
++                       * Give up - this will drop whichever
++                       * key/value pair we have currently displaced
++                       * on the floor
++                       */
++                      return rc;
++              }
++              goto again;
++      }
++  
++      EPRINTK("%s: failed hash add\n", __FUNCTION__);
++      /*
++       * Couldn't do it - bad as we've now removed some random thing
++       * from the table, and will just drop it on the floor.  Better
++       * would be to somehow revert the table to the state it was in
++       * at the start
++       */
++      return -ENOSPC;
 +}
++EXPORT_SYMBOL_GPL(cuckoo_hash_add);
 +
-+void __exit pciback_xenbus_unregister(void)
++
++int cuckoo_hash_add_check(cuckoo_hash_table *hashtab,
++                        cuckoo_hash_key *key, cuckoo_hash_value value,
++                        int can_rehash)
 +{
-+      xenbus_unregister_driver(&xenbus_pciback_driver);
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pcifront/Makefile linux-2.6.18-xen.hg/drivers/xen/pcifront/Makefile
---- linux-2.6.18/drivers/xen/pcifront/Makefile 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pcifront/Makefile  2007-12-23 11:15:34.067936306 +0100
-@@ -0,0 +1,7 @@
-+obj-y += pcifront.o
++      int stored_value;
 +
-+pcifront-y := pci_op.o xenbus.o pci.o
++      if (cuckoo_hash_lookup(hashtab, key, &stored_value))
++              return -EBUSY;
 +
-+ifeq ($(CONFIG_XEN_PCIDEV_FE_DEBUG),y)
-+EXTRA_CFLAGS += -DDEBUG
-+endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pcifront/pci.c linux-2.6.18-xen.hg/drivers/xen/pcifront/pci.c
---- linux-2.6.18/drivers/xen/pcifront/pci.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pcifront/pci.c     2007-12-23 11:15:34.067936306 +0100
-@@ -0,0 +1,46 @@
-+/*
-+ * PCI Frontend Operations - ensure only one PCI frontend runs at a time
-+ *
-+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include "pcifront.h"
++      return cuckoo_hash_add(hashtab, key, value, can_rehash);
++}
++EXPORT_SYMBOL_GPL(cuckoo_hash_add_check);
 +
-+DEFINE_SPINLOCK(pcifront_dev_lock);
-+static struct pcifront_device *pcifront_dev = NULL;
 +
-+int pcifront_connect(struct pcifront_device *pdev)
++int cuckoo_hash_remove(cuckoo_hash_table *hashtab, cuckoo_hash_key *key)
 +{
-+      int err = 0;
-+
-+      spin_lock(&pcifront_dev_lock);
++      cuckoo_hash hash;
 +
-+      if (!pcifront_dev) {
-+              dev_info(&pdev->xdev->dev, "Installing PCI frontend\n");
-+              pcifront_dev = pdev;
++      hash = cuckoo_compute_hash(hashtab, key, &hashtab->a0);
++      if ((hashtab->table0[hash].state == CUCKOO_HASH_STATE_OCCUPIED) &&
++          cuckoo_hash_key_compare(hashtab, &(hashtab->table0[hash].key),
++                                  key)) {
++              hashtab->table0[hash].state = CUCKOO_HASH_STATE_VACANT;
++              hashtab->entries--;
++              return 0;
 +      }
-+      else {
-+              dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n");
-+              err = -EEXIST;
++  
++      hash = cuckoo_compute_hash(hashtab, key, &hashtab->a1);
++      if ((hashtab->table1[hash].state == CUCKOO_HASH_STATE_OCCUPIED) &&
++          cuckoo_hash_key_compare(hashtab, &(hashtab->table1[hash].key),
++                                  key)) {
++              hashtab->table1[hash].state = CUCKOO_HASH_STATE_VACANT;
++              hashtab->entries--;
++              return 0;
 +      }
-+
-+      spin_unlock(&pcifront_dev_lock);
-+
-+      return err;
++ 
++      return -EINVAL;
 +}
++EXPORT_SYMBOL_GPL(cuckoo_hash_remove);
 +
-+void pcifront_disconnect(struct pcifront_device *pdev)
++
++int cuckoo_hash_update(cuckoo_hash_table *hashtab, cuckoo_hash_key *key,
++                     cuckoo_hash_value value)
 +{
-+      spin_lock(&pcifront_dev_lock);
++      cuckoo_hash hash;
 +
-+      if (pdev == pcifront_dev) {
-+              dev_info(&pdev->xdev->dev,
-+                       "Disconnecting PCI Frontend Buses\n");
-+              pcifront_dev = NULL;
++      hash = cuckoo_compute_hash(hashtab, key, &hashtab->a0);
++      if ((hashtab->table0[hash].state == CUCKOO_HASH_STATE_OCCUPIED) &&
++          cuckoo_hash_key_compare(hashtab, &(hashtab->table0[hash].key),
++                                  key)) {
++              hashtab->table0[hash].value = value;
++              return 0;
 +      }
 +
-+      spin_unlock(&pcifront_dev_lock);
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pcifront/pcifront.h linux-2.6.18-xen.hg/drivers/xen/pcifront/pcifront.h
---- linux-2.6.18/drivers/xen/pcifront/pcifront.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pcifront/pcifront.h        2007-12-23 11:15:34.071269815 +0100
-@@ -0,0 +1,40 @@
-+/*
-+ * PCI Frontend - Common data structures & function declarations
-+ *
-+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ */
-+#ifndef __XEN_PCIFRONT_H__
-+#define __XEN_PCIFRONT_H__
++      hash = cuckoo_compute_hash(hashtab, key, &hashtab->a1);
++      if ((hashtab->table1[hash].state == CUCKOO_HASH_STATE_OCCUPIED) &&
++          cuckoo_hash_key_compare(hashtab, &(hashtab->table1[hash].key),
++                                  key)) {
++              hashtab->table1[hash].value = value;
++              return 0;
++      }
 +
-+#include <linux/spinlock.h>
-+#include <linux/pci.h>
-+#include <xen/xenbus.h>
-+#include <xen/interface/io/pciif.h>
-+#include <xen/pcifront.h>
++      return -EINVAL;
++}
++EXPORT_SYMBOL_GPL(cuckoo_hash_update);
 +
-+struct pci_bus_entry {
-+      struct list_head list;
-+      struct pci_bus *bus;
-+};
 +
-+struct pcifront_device {
-+      struct xenbus_device *xdev;
-+      struct list_head root_buses;
-+      spinlock_t dev_lock;
++void cuckoo_hash_iterate_reset(cuckoo_hash_table *hashtab)
++{
++      hashtab->iterate_index = 0;
++}
++EXPORT_SYMBOL_GPL(cuckoo_hash_iterate_reset);
 +
-+      int evtchn;
-+      int gnt_ref;
 +
-+      /* Lock this when doing any operations in sh_info */
-+      spinlock_t sh_info_lock;
-+      struct xen_pci_sharedinfo *sh_info;
-+};
++int cuckoo_hash_iterate(cuckoo_hash_table *hashtab,
++                      cuckoo_hash_key *key, cuckoo_hash_value *value)
++{
++      unsigned index;
 +
-+int pcifront_connect(struct pcifront_device *pdev);
-+void pcifront_disconnect(struct pcifront_device *pdev);
++      while (hashtab->iterate_index < hashtab->length) {
++              index = hashtab->iterate_index;
++              ++hashtab->iterate_index;
++              if (hashtab->table0[index].state == CUCKOO_HASH_STATE_OCCUPIED) {
++                      *key = hashtab->table0[index].key;
++                      *value = hashtab->table0[index].value;
++                      return 0;
++              }
++      }
 +
-+int pcifront_scan_root(struct pcifront_device *pdev,
-+                     unsigned int domain, unsigned int bus);
-+void pcifront_free_roots(struct pcifront_device *pdev);
++      while (hashtab->iterate_index >= hashtab->length &&
++             hashtab->iterate_index < hashtab->length * 2) {
++              index = hashtab->iterate_index - hashtab->length;
++              ++hashtab->iterate_index;               
++              if (hashtab->table1[index].state == CUCKOO_HASH_STATE_OCCUPIED) {
++                      *key = hashtab->table1[index].key;
++                      *value = hashtab->table1[index].value;
++                      return 0;
++              }
++      }
 +
-+#endif        /* __XEN_PCIFRONT_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pcifront/pci_op.c linux-2.6.18-xen.hg/drivers/xen/pcifront/pci_op.c
---- linux-2.6.18/drivers/xen/pcifront/pci_op.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pcifront/pci_op.c  2007-12-23 11:15:34.071269815 +0100
-@@ -0,0 +1,386 @@
-+/*
-+ * PCI Frontend Operations - Communicates with frontend
-+ *
-+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
-+ */
-+#include <linux/module.h>
-+#include <linux/version.h>
-+#include <linux/init.h>
-+#include <linux/pci.h>
-+#include <linux/spinlock.h>
-+#include <linux/time.h>
-+#include <xen/evtchn.h>
-+#include "pcifront.h"
++      return -ENOSPC;
++}
++EXPORT_SYMBOL_GPL(cuckoo_hash_iterate);
 +
-+static int verbose_request = 0;
-+module_param(verbose_request, int, 0644);
 +
-+#ifdef __ia64__
-+static void pcifront_init_sd(struct pcifront_sd *sd,
-+                           unsigned int domain, unsigned int bus,
-+                           struct pcifront_device *pdev)
++#if 0
++void cuckoo_hash_valid(cuckoo_hash_table *hashtab)
 +{
-+      int err, i, j, k, len, root_num, res_count;
-+      struct acpi_resource res;
-+      unsigned int d, b, byte;
-+      unsigned long magic;
-+      char str[64], tmp[3];
-+      unsigned char *buf, *bufp;
-+      u8 *ptr;
-+
-+      memset(sd, 0, sizeof(*sd));
-+
-+      sd->segment = domain;
-+      sd->node = -1;  /* Revisit for NUMA */
-+      sd->platform_data = pdev;
++      int i, entry_count = 0;
 +
-+      /* Look for resources for this controller in xenbus. */
-+      err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, "root_num",
-+                         "%d", &root_num);
-+      if (err != 1)
++      for (i=0; i < hashtab->length; i++) {
++              EPRINTK_ON(hashtab->table0[i].state != CUCKOO_HASH_STATE_VACANT &&
++                         hashtab->table0[i].state != CUCKOO_HASH_STATE_OCCUPIED);
++              if (hashtab->table0[i].state == CUCKOO_HASH_STATE_OCCUPIED)
++                      entry_count++;
++              EPRINTK_ON(hashtab->table1[i].state != CUCKOO_HASH_STATE_VACANT &&
++                         hashtab->table1[i].state != CUCKOO_HASH_STATE_OCCUPIED);
++              if (hashtab->table1[i].state == CUCKOO_HASH_STATE_OCCUPIED)
++                      entry_count++;  
++      }
++      
++      if (entry_count != hashtab->entries) {
++              EPRINTK("%s: bad count\n", __FUNCTION__);
++              cuckoo_hash_dump(hashtab);
 +              return;
++      }
 +
-+      for (i = 0; i < root_num; i++) {
-+              len = snprintf(str, sizeof(str), "root-%d", i);
-+              if (unlikely(len >= (sizeof(str) - 1)))
-+                      return;
-+
-+              err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
-+                                 str, "%x:%x", &d, &b);
-+              if (err != 2)
-+                      return;
++      for (i=0; i< hashtab->length; i++) {
++              if (hashtab->table0[i].state == CUCKOO_HASH_STATE_OCCUPIED)
++                      if (i != cuckoo_compute_hash(hashtab, 
++                                                   &hashtab->table0[i].key, 
++                                                   &hashtab->a0)) {
++                              EPRINTK("%s: Bad key table 0 index %d\n",
++                                      __FUNCTION__, i);
++                              cuckoo_hash_dump(hashtab);
++                              return;
++                      }
++              if (hashtab->table1[i].state == CUCKOO_HASH_STATE_OCCUPIED)
++                      if (i != cuckoo_compute_hash(hashtab, 
++                                                   &hashtab->table1[i].key, 
++                                                   &hashtab->a1)) {
++                              EPRINTK("%s: Bad key table 1 index %d\n",
++                                      __FUNCTION__, i);
++                              cuckoo_hash_dump(hashtab);
++                              return;
++                      }
++      }
 +
-+              if (d == domain && b == bus)
-+                      break;
++}
++EXPORT_SYMBOL_GPL(cuckoo_hash_valid);
++
++
++void cuckoo_hash_dump(cuckoo_hash_table *hashtab)
++{
++      int i, entry_count;
++
++      entry_count = 0;
++      for (i=0; i < hashtab->length; i++) {
++              EPRINTK_ON(hashtab->table0[i].state != CUCKOO_HASH_STATE_VACANT &&
++                         hashtab->table0[i].state != CUCKOO_HASH_STATE_OCCUPIED);
++              if (hashtab->table0[i].state == CUCKOO_HASH_STATE_OCCUPIED)
++                      entry_count++;
++              EPRINTK_ON(hashtab->table1[i].state != CUCKOO_HASH_STATE_VACANT &&
++                         hashtab->table1[i].state != CUCKOO_HASH_STATE_OCCUPIED);
++              if (hashtab->table1[i].state == CUCKOO_HASH_STATE_OCCUPIED)
++                      entry_count++;  
++      }
++
++      EPRINTK("======================\n");
++      EPRINTK("Cuckoo hash table dump\n");
++      EPRINTK("======================\n");
++      EPRINTK("length: %d; length_bits: %d; key_length: %d\n", hashtab->length,
++              hashtab->length_bits, hashtab->key_length);
++      EPRINTK("Recorded entries: %d\n", hashtab->entries);
++      EPRINTK("Counted entries: %d\n", entry_count);
++      EPRINTK("a0: %llx; a1: %llx\n", hashtab->a0, hashtab->a1);
++      EPRINTK("-----------------------------------------\n");
++      EPRINTK("Index  Occupied  Key  Value Index0 Index1\n");
++      EPRINTK("-----------------------------------------\n");         
++      for (i=0; i< hashtab->length; i++) {
++              if (hashtab->table0[i].state == CUCKOO_HASH_STATE_OCCUPIED)
++              EPRINTK("%d %d %llx %d %d %d\n", i,
++                      hashtab->table0[i].state == CUCKOO_HASH_STATE_OCCUPIED,
++                      hashtab->table0[i].key, hashtab->table0[i].value,
++                      cuckoo_compute_hash(hashtab, &hashtab->table0[i].key, 
++                                          &hashtab->a0),
++                      cuckoo_compute_hash(hashtab, &hashtab->table0[i].key, 
++                                          &hashtab->a1));
++              else
++              EPRINTK("%d %d - - - -\n", i,
++                      hashtab->table0[i].state == CUCKOO_HASH_STATE_OCCUPIED);
++                      
 +      }
++      EPRINTK("-----------------------------------------\n");
++      EPRINTK("Index  Occupied  Key  Value Index0 Index1\n");
++      EPRINTK("-----------------------------------------\n");
++      for (i=0; i< hashtab->length; i++) {
++              if (hashtab->table1[i].state == CUCKOO_HASH_STATE_OCCUPIED)
++              EPRINTK("%d %d %llx %d %d %d\n", i,
++                      hashtab->table1[i].state == CUCKOO_HASH_STATE_OCCUPIED,
++                      hashtab->table1[i].key, hashtab->table1[i].value,
++                      cuckoo_compute_hash(hashtab, &hashtab->table1[i].key, 
++                                          &hashtab->a0),
++                      cuckoo_compute_hash(hashtab, &hashtab->table1[i].key, 
++                                          &hashtab->a1));
++              else
++              EPRINTK("%d %d - - - -\n", i,
++                      hashtab->table1[i].state == CUCKOO_HASH_STATE_OCCUPIED);
++      } 
++      EPRINTK("======================\n");
++}
++EXPORT_SYMBOL_GPL(cuckoo_hash_dump);
++#endif
+--- linux-2.6.18.8/drivers/xen/sfc_netutil/accel_cuckoo_hash.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netutil/accel_cuckoo_hash.h    2008-05-19 00:33:48.730955028 +0300
+@@ -0,0 +1,227 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      if (i == root_num)
-+              return;
++/*
++ * A cuckoo hash table consists of two sub tables.  Each entry can
++ * hash to a position in each table.  If, on entry, its position is
++ * found to be occupied, the existing element is moved to it's other
++ * location.  This recurses until success or a loop is found.  If a
++ * loop is found the table is rehashed.
++ *
++ *  See http://www.it-c.dk/people/pagh/papers/cuckoo-jour.pdf
++ */
 +
-+      len = snprintf(str, sizeof(str), "root-resource-magic");
++#ifndef NET_ACCEL_CUCKOO_HASH_H
++#define NET_ACCEL_CUCKOO_HASH_H
 +
-+      err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
-+                         str, "%lx", &magic);
++/*! Type used for hash table keys of ip pairs */
++typedef struct {
++      u32 local_ip;
++      //u32 remote_ip;
++      u16 local_port;
++      //u16 remote_port;
++      /* Technically only 1 bit, but use 16 to make key a round
++         number size */
++      u16 proto;
++} cuckoo_hash_ip_key;
 +
-+      if (err != 1)
-+              return; /* No resources, nothing to do */
++/*! Type used for hash table keys of mac addresses */
++typedef u64 cuckoo_hash_mac_key;
 +
-+      if (magic != (sizeof(res) * 2) + 1) {
-+              printk(KERN_WARNING "pcifront: resource magic mismatch\n");
-+              return;
-+      }
++/*! This type is designed to be large enough to hold all supported key
++ *  sizes to avoid having to malloc storage for them.
++ */
++typedef u64 cuckoo_hash_key;
 +
-+      len = snprintf(str, sizeof(str), "root-%d-resources", i);
-+      if (unlikely(len >= (sizeof(str) - 1)))
-+              return;
++/*! Type used for the values stored in the hash table */
++typedef int cuckoo_hash_value;
 +
-+      err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
-+                         str, "%d", &res_count);
++/*! Type used for the hash used to index the table */
++typedef u32 cuckoo_hash;
 +
-+      if (err != 1)
-+              return; /* No resources, nothing to do */
++/*! How long to spend displacing values when adding before giving up
++ *  and rehashing */
++#define CUCKOO_HASH_MAX_LOOP (hashtab->length)
 +
-+      sd->window = kzalloc(sizeof(*sd->window) * res_count, GFP_KERNEL);
-+      if (!sd->window)
-+              return;
++/*! State of hash table entry */
++typedef enum {
++      CUCKOO_HASH_STATE_VACANT = 0,
++      CUCKOO_HASH_STATE_OCCUPIED 
++} cuckoo_hash_state;
 +
-+      /* magic is also the size of the byte stream in xenbus */
-+      buf = kmalloc(magic, GFP_KERNEL);
-+      if (!buf) {
-+              kfree(sd->window);
-+              sd->window = NULL;
-+              return;
-+      }
++/*! An entry in the hash table */
++typedef struct {
++      cuckoo_hash_state state;
++      cuckoo_hash_key key;
++      cuckoo_hash_value value;
++} cuckoo_hash_entry;
 +
-+      /* Read the resources out of xenbus */
-+      for (j = 0; j < res_count; j++) {
-+              memset(&res, 0, sizeof(res));
-+              memset(buf, 0, magic);
++/*! A cuckoo hash table */
++typedef struct {
++      /*! The length of each table (NB. there are two tables of this
++       *  length) */
++      unsigned length; 
++      /*! The length of each table in bits */
++      unsigned length_bits;
++      /*! The length of the key in bytes */ 
++      unsigned key_length; 
++      /*! The number of entries currently stored in the table */
++      unsigned entries;
++      /*! Index into table used by cuckoo_hash_iterate */
++      unsigned iterate_index; 
++
++      /* parameter of hash functions */
++      /*! The "a" parameter of the first hash function */
++      cuckoo_hash_key a0; 
++      /*! The "a" parameter of the second hash function */
++      cuckoo_hash_key a1; 
++
++      /*! The first table */
++      cuckoo_hash_entry *table0; 
++      /*! The second table */
++      cuckoo_hash_entry *table1; 
++} cuckoo_hash_table;
++
++/*! Initialise the cuckoo has table 
++ *
++ * \param hashtab A pointer to an unitialised hash table structure
++ * \param length_bits The number of elements in each table equals
++ * 2**length_bits
++ * \param key_length The length of the key in bytes
++ *
++ * \return 0 on success, -ENOMEM if it couldn't allocate the tables
++ */
++extern
++int cuckoo_hash_init(cuckoo_hash_table *hashtab, unsigned length_bits,
++                   unsigned key_length);
 +
-+              len = snprintf(str, sizeof(str), "root-%d-resource-%d", i, j);
-+              if (unlikely(len >= (sizeof(str) - 1)))
-+                      return;
 +
-+              err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str,
-+                                 "%s", buf);
-+              if (err != 1) {
-+                      printk(KERN_WARNING "pcifront: error reading "
-+                             "resource %d on bus %04x:%02x\n",
-+                             j, domain, bus);
-+                      continue;
-+              }
++/*! Destroy a hash table
++ *
++ * \param hashtab A hash table that has previously been passed to a
++ * successful call of cuckoo_hash_init()
++ */
++extern
++void cuckoo_hash_destroy(cuckoo_hash_table *hashtab);
 +
-+              bufp = buf;
-+              ptr = (u8 *)&res;
-+              memset(tmp, 0, sizeof(tmp));
 +
-+              /* Copy ASCII byte stream into structure */
-+              for (k = 0; k < magic - 1; k += 2) {
-+                      memcpy(tmp, bufp, 2);
-+                      bufp += 2;
++/*! Lookup an entry in the hash table 
++ *
++ * \param hashtab The hash table in which to look.
++ * \param key Pointer to a mac address to use as the key
++ * \param value On exit set to the value stored if key was present
++ *
++ * \return 0 if not present in the table, non-zero if it is (and value
++ * is set accordingly)
++ */
++extern
++int cuckoo_hash_lookup(cuckoo_hash_table *hashtab,
++                     cuckoo_hash_key *key,
++                     cuckoo_hash_value *value);
 +
-+                      sscanf(tmp, "%02x", &byte);
-+                      *ptr = byte;
-+                      ptr++;
-+              }
++/*! Add an entry to the hash table.  Key must not be a duplicate of
++ * anything already in the table.  If this is a risk, see
++ * cuckoo_hash_add_check
++ *
++ * \param hashtab The hash table to add the entry to
++ * \param key Pointer to a mac address to use as a key
++ * \param value The value to store 
++ * \param can_rehash Flag to allow the add function to rehash the
++ * table if necessary
++ *
++ * \return 0 on success, non-zero on failure.  -ENOSPC means it just
++ * couldn't find anywhere to put it - this is bad and probably means
++ * an entry has been dropped on the floor (but the entry you just
++ * tried to add may now be included)
++ */
++extern
++int cuckoo_hash_add(cuckoo_hash_table *hashtab,
++                  cuckoo_hash_key *key, 
++                  cuckoo_hash_value value,
++                  int can_rehash);
 +
-+              xen_add_resource(sd, domain, bus, &res);
-+              sd->windows++;
-+      }
-+      kfree(buf);
-+}
-+#endif
++/*! Same as cuckoo_hash_add but first checks to ensure entry is not
++ * already there
++ * \return -EBUSY if already there
++ */
 +
-+static int errno_to_pcibios_err(int errno)
-+{
-+      switch (errno) {
-+      case XEN_PCI_ERR_success:
-+              return PCIBIOS_SUCCESSFUL;
++extern
++int cuckoo_hash_add_check(cuckoo_hash_table *hashtab,
++                        cuckoo_hash_key *key, 
++                        cuckoo_hash_value value,
++                        int can_rehash);
++/*! Remove an entry from the table 
++ *
++ * \param hashtab The hash table to remove the entry from
++ * \param key The key that was used to previously add the entry
++ *
++ * \return 0 on success, -EINVAL if the entry couldn't be found 
++ */
++extern
++int cuckoo_hash_remove(cuckoo_hash_table *hashtab, cuckoo_hash_key *key);
 +
-+      case XEN_PCI_ERR_dev_not_found:
-+              return PCIBIOS_DEVICE_NOT_FOUND;
 +
-+      case XEN_PCI_ERR_invalid_offset:
-+      case XEN_PCI_ERR_op_failed:
-+              return PCIBIOS_BAD_REGISTER_NUMBER;
++/*! Helper for those using mac addresses to convert to a key for the
++ *  hash table
++ */
++static inline cuckoo_hash_mac_key cuckoo_mac_to_key(const u8 *mac)
++{
++      return (cuckoo_hash_mac_key)(mac[0])
++              | (cuckoo_hash_mac_key)(mac[1]) << 8
++              | (cuckoo_hash_mac_key)(mac[2]) << 16
++              | (cuckoo_hash_mac_key)(mac[3]) << 24
++              | (cuckoo_hash_mac_key)(mac[4]) << 32
++              | (cuckoo_hash_mac_key)(mac[5]) << 40;
++}
 +
-+      case XEN_PCI_ERR_not_implemented:
-+              return PCIBIOS_FUNC_NOT_SUPPORTED;
 +
-+      case XEN_PCI_ERR_access_denied:
-+              return PCIBIOS_SET_FAILED;
-+      }
-+      return errno;
-+}
++/*! Update an entry already in the hash table to take a new value 
++ *
++ * \param hashtab The hash table to add the entry to
++ * \param key Pointer to a mac address to use as a key
++ * \param value The value to store 
++ *
++ * \return 0 on success, non-zero on failure. 
++ */
++int cuckoo_hash_update(cuckoo_hash_table *hashtab, cuckoo_hash_key *key,
++                     cuckoo_hash_value value);
 +
-+static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op)
-+{
-+      int err = 0;
-+      struct xen_pci_op *active_op = &pdev->sh_info->op;
-+      unsigned long irq_flags;
-+      evtchn_port_t port = pdev->evtchn;
-+      s64 ns, ns_timeout;
-+      struct timeval tv;
 +
-+      spin_lock_irqsave(&pdev->sh_info_lock, irq_flags);
++/*! Go through the hash table and return all used entries (one per call)
++ *
++ * \param hashtab The hash table to iterate over 
++ * \param key Pointer to a key to take the returned key
++ * \param value Pointer to a value to take the returned value
++ *
++ * \return 0 on success (key, value set), non-zero on failure.
++ */
++int cuckoo_hash_iterate(cuckoo_hash_table *hashtab,
++                      cuckoo_hash_key *key, cuckoo_hash_value *value);
++void cuckoo_hash_iterate_reset(cuckoo_hash_table *hashtab);
 +
-+      memcpy(active_op, op, sizeof(struct xen_pci_op));
++/* debug, not compiled by default */
++void cuckoo_hash_valid(cuckoo_hash_table *hashtab);
++void cuckoo_hash_dump(cuckoo_hash_table *hashtab);
++
++#endif /* NET_ACCEL_CUCKOO_HASH_H */
+--- linux-2.6.18.8/drivers/xen/sfc_netutil/accel_msg_iface.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netutil/accel_msg_iface.c      2008-05-19 00:33:48.730955028 +0300
+@@ -0,0 +1,301 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      /* Go */
-+      wmb();
-+      set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags);
-+      notify_remote_via_evtchn(port);
++#include <xen/evtchn.h>
 +
-+      /*
-+       * We set a poll timeout of 3 seconds but give up on return after
-+       * 2 seconds. It is better to time out too late rather than too early
-+       * (in the latter case we end up continually re-executing poll() with a
-+       * timeout in the past). 1s difference gives plenty of slack for error.
-+       */
-+      do_gettimeofday(&tv);
-+      ns_timeout = timeval_to_ns(&tv) + 2 * (s64)NSEC_PER_SEC;
++#include "accel_util.h"
++#include "accel_msg_iface.h"
 +
-+      clear_evtchn(port);
++#define NET_ACCEL_MSG_Q_SIZE (1024)
++#define NET_ACCEL_MSG_Q_MASK (NET_ACCEL_MSG_Q_SIZE - 1)
 +
-+      while (test_bit(_XEN_PCIF_active,
-+                      (unsigned long *)&pdev->sh_info->flags)) {
-+              if (HYPERVISOR_poll(&port, 1, jiffies + 3*HZ))
-+                      BUG();
-+              clear_evtchn(port);
-+              do_gettimeofday(&tv);
-+              ns = timeval_to_ns(&tv);
-+              if (ns > ns_timeout) {
-+                      dev_err(&pdev->xdev->dev,
-+                              "pciback not responding!!!\n");
-+                      clear_bit(_XEN_PCIF_active,
-+                                (unsigned long *)&pdev->sh_info->flags);
-+                      err = XEN_PCI_ERR_dev_not_found;
-+                      goto out;
-+              }
++#ifdef NDEBUG
++#define NET_ACCEL_CHECK_MAGIC(_p, _errval)
++#define NET_ACCEL_SHOW_QUEUE(_t, _q, _id)
++#else
++#define NET_ACCEL_CHECK_MAGIC(_p, _errval)                            \
++      if (_p->magic != NET_ACCEL_MSG_MAGIC) {                         \
++              printk(KERN_ERR "%s: passed invalid shared page %p!\n", \
++                     __FUNCTION__, _p);                               \
++              return _errval;                                         \
 +      }
++#define NET_ACCEL_SHOW_QUEUE(_t, _q, _id)                             \
++      printk(_t ": queue %d write %x read %x base %x limit %x\n",     \
++             _id, _q->write, _q->read, _q->base, _q->limit);
++#endif
 +
-+      memcpy(op, active_op, sizeof(struct xen_pci_op));
-+
-+      err = op->err;
-+      out:
-+      spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags);
-+      return err;
-+}
-+
-+/* Access to this function is spinlocked in drivers/pci/access.c */
-+static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn,
-+                           int where, int size, u32 * val)
++/*
++ * We've been passed at least 2 pages. 1 control page and 1 or more
++ * data pages.
++ */
++int net_accel_msg_init_page(void *mem, int len, int up)
 +{
-+      int err = 0;
-+      struct xen_pci_op op = {
-+              .cmd    = XEN_PCI_OP_conf_read,
-+              .domain = pci_domain_nr(bus),
-+              .bus    = bus->number,
-+              .devfn  = devfn,
-+              .offset = where,
-+              .size   = size,
-+      };
-+      struct pcifront_sd *sd = bus->sysdata;
-+      struct pcifront_device *pdev = pcifront_get_pdev(sd);
++      struct net_accel_shared_page *shared_page = 
++              (struct net_accel_shared_page*)mem;
 +
-+      if (verbose_request)
-+              dev_info(&pdev->xdev->dev,
-+                       "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n",
-+                       pci_domain_nr(bus), bus->number, PCI_SLOT(devfn),
-+                       PCI_FUNC(devfn), where, size);
++      if ((unsigned long)shared_page & NET_ACCEL_MSG_Q_MASK)
++              return -EINVAL;
 +
-+      err = do_pci_op(pdev, &op);
++      shared_page->magic = NET_ACCEL_MSG_MAGIC;
 +
-+      if (likely(!err)) {
-+              if (verbose_request)
-+                      dev_info(&pdev->xdev->dev, "read got back value %x\n",
-+                               op.value);
++      shared_page->aflags = 0;
 +
-+              *val = op.value;
-+      } else if (err == -ENODEV) {
-+              /* No device here, pretend that it just returned 0 */
-+              err = 0;
-+              *val = 0;
-+      }
++      shared_page->net_dev_up = up;
 +
-+      return errno_to_pcibios_err(err);
++      return 0;
 +}
++EXPORT_SYMBOL_GPL(net_accel_msg_init_page);
 +
-+/* Access to this function is spinlocked in drivers/pci/access.c */
-+static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn,
-+                            int where, int size, u32 val)
++
++void net_accel_msg_init_queue(sh_msg_fifo2 *queue,
++                            struct net_accel_msg_queue *indices,
++                            struct net_accel_msg *base, int size)
 +{
-+      struct xen_pci_op op = {
-+              .cmd    = XEN_PCI_OP_conf_write,
-+              .domain = pci_domain_nr(bus),
-+              .bus    = bus->number,
-+              .devfn  = devfn,
-+              .offset = where,
-+              .size   = size,
-+              .value  = val,
-+      };
-+      struct pcifront_sd *sd = bus->sysdata;
-+      struct pcifront_device *pdev = pcifront_get_pdev(sd);
++      queue->fifo = base;
++      spin_lock_init(&queue->lock);
++      sh_fifo2_init(queue, size-1, &indices->read, &indices->write);
++}
++EXPORT_SYMBOL_GPL(net_accel_msg_init_queue);
 +
-+      if (verbose_request)
-+              dev_info(&pdev->xdev->dev,
-+                       "write dev=%04x:%02x:%02x.%01x - "
-+                       "offset %x size %d val %x\n",
-+                       pci_domain_nr(bus), bus->number,
-+                       PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val);
 +
-+      return errno_to_pcibios_err(do_pci_op(pdev, &op));
++static inline int _net_accel_msg_send(struct net_accel_shared_page *sp,
++                                    sh_msg_fifo2 *queue,
++                                    struct net_accel_msg *msg,
++                                    int is_reply)
++{
++      int rc = 0;
++      NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
++      rmb();
++      if (is_reply) {
++              EPRINTK_ON(sh_fifo2_is_full(queue));
++              sh_fifo2_put(queue, *msg);
++      } else {
++              if (sh_fifo2_not_half_full(queue)) {
++                      sh_fifo2_put(queue, *msg);
++              } else {
++                      rc = -ENOSPC;
++              }
++      }
++      wmb();
++      return rc;
 +}
 +
-+struct pci_ops pcifront_bus_ops = {
-+      .read = pcifront_bus_read,
-+      .write = pcifront_bus_write,
-+};
++/* Notify after a batch of messages have been sent */
++void net_accel_msg_notify(int irq)
++{
++      notify_remote_via_irq(irq);
++}
++EXPORT_SYMBOL_GPL(net_accel_msg_notify);
 +
-+/* Claim resources for the PCI frontend as-is, backend won't allow changes */
-+static void pcifront_claim_resource(struct pci_dev *dev, void *data)
++/* 
++ * Send a message on the specified FIFO. Returns 0 on success, -errno
++ * on failure. The message in msg is copied to the current slot of the
++ * FIFO.
++ */
++int net_accel_msg_send(struct net_accel_shared_page *sp, sh_msg_fifo2 *q, 
++                     struct net_accel_msg *msg)
 +{
-+      struct pcifront_device *pdev = data;
-+      int i;
-+      struct resource *r;
++      unsigned long flags;
++      int rc;
++      net_accel_msg_lock_queue(q, &flags);
++      rc = _net_accel_msg_send(sp, q, msg, 0);
++      net_accel_msg_unlock_queue(q, &flags);
++      return rc;
++}
++EXPORT_SYMBOL_GPL(net_accel_msg_send);
 +
-+      for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-+              r = &dev->resource[i];
 +
-+              if (!r->parent && r->start && r->flags) {
-+                      dev_dbg(&pdev->xdev->dev, "claiming resource %s/%d\n",
-+                              pci_name(dev), i);
-+                      pci_claim_resource(dev, i);
-+              }
-+      }
++/* As net_accel_msg_send but also posts a notification to the far end. */
++int net_accel_msg_send_notify(struct net_accel_shared_page *sp, int irq, 
++                            sh_msg_fifo2 *q, struct net_accel_msg *msg)
++{
++      unsigned long flags;
++      int rc;
++      net_accel_msg_lock_queue(q, &flags);
++      rc = _net_accel_msg_send(sp, q, msg, 0);
++      net_accel_msg_unlock_queue(q, &flags);
++      if (rc >= 0)
++              notify_remote_via_irq(irq);
++      return rc;
 +}
++EXPORT_SYMBOL_GPL(net_accel_msg_send_notify);
 +
-+int pcifront_scan_root(struct pcifront_device *pdev,
-+                     unsigned int domain, unsigned int bus)
++
++int net_accel_msg_reply(struct net_accel_shared_page *sp, sh_msg_fifo2 *q, 
++                     struct net_accel_msg *msg)
 +{
-+      struct pci_bus *b;
-+      struct pcifront_sd *sd = NULL;
-+      struct pci_bus_entry *bus_entry = NULL;
-+      int err = 0;
++      unsigned long flags;
++      int rc;
++      net_accel_msg_lock_queue(q, &flags);
++      rc = _net_accel_msg_send(sp, q, msg, 1);
++      net_accel_msg_unlock_queue(q, &flags);
++      return rc;
++}
++EXPORT_SYMBOL_GPL(net_accel_msg_reply);
 +
-+#ifndef CONFIG_PCI_DOMAINS
-+      if (domain != 0) {
-+              dev_err(&pdev->xdev->dev,
-+                      "PCI Root in non-zero PCI Domain! domain=%d\n", domain);
-+              dev_err(&pdev->xdev->dev,
-+                      "Please compile with CONFIG_PCI_DOMAINS\n");
-+              err = -EINVAL;
-+              goto err_out;
-+      }
-+#endif
 +
-+      dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n",
-+               domain, bus);
++/* As net_accel_msg_send but also posts a notification to the far end. */
++int net_accel_msg_reply_notify(struct net_accel_shared_page *sp, int irq, 
++                            sh_msg_fifo2 *q, struct net_accel_msg *msg)
++{
++      unsigned long flags;
++      int rc;
++      net_accel_msg_lock_queue(q, &flags);
++      rc = _net_accel_msg_send(sp, q, msg, 1);
++      net_accel_msg_unlock_queue(q, &flags);
++      if (rc >= 0)
++              notify_remote_via_irq(irq);
++      return rc;
++}
++EXPORT_SYMBOL_GPL(net_accel_msg_reply_notify);
 +
-+      bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL);
-+      sd = kmalloc(sizeof(*sd), GFP_KERNEL);
-+      if (!bus_entry || !sd) {
-+              err = -ENOMEM;
-+              goto err_out;
-+      }
-+      pcifront_init_sd(sd, domain, bus, pdev);
 +
-+      b = pci_scan_bus_parented(&pdev->xdev->dev, bus,
-+                                &pcifront_bus_ops, sd);
-+      if (!b) {
-+              dev_err(&pdev->xdev->dev,
-+                      "Error creating PCI Frontend Bus!\n");
-+              err = -ENOMEM;
-+              goto err_out;
++/*
++ * Look at a received message, if any, so a decision can be made about
++ * whether to read it now or not.  Cookie is a bit of debug which is
++ * set here and checked when passed to net_accel_msg_recv_next()
++ */
++int net_accel_msg_peek(struct net_accel_shared_page *sp, 
++                     sh_msg_fifo2 *queue, 
++                     struct net_accel_msg *msg, int *cookie)
++{
++      unsigned long flags;
++      int rc = 0;
++      NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
++      net_accel_msg_lock_queue(queue, &flags);
++      rmb();
++      if (sh_fifo2_is_empty(queue)) {
++              rc = -ENOENT;
++      } else {
++              *msg = sh_fifo2_peek(queue);
++              *cookie = *(queue->fifo_rd_i);
 +      }
++      net_accel_msg_unlock_queue(queue, &flags);
++      return rc;
++}
++EXPORT_SYMBOL_GPL(net_accel_msg_peek);
 +
-+      pcifront_setup_root_resources(b, sd);
-+      bus_entry->bus = b;
-+
-+      list_add(&bus_entry->list, &pdev->root_buses);
 +
-+      /* Claim resources before going "live" with our devices */
-+      pci_walk_bus(b, pcifront_claim_resource, pdev);
++/*
++ * Move the queue onto the next element, used after finished with a
++ * peeked msg 
++ */
++int net_accel_msg_recv_next(struct net_accel_shared_page *sp, 
++                          sh_msg_fifo2 *queue, int cookie)
++{
++      unsigned long flags;
++      NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
++      net_accel_msg_lock_queue(queue, &flags);
++      rmb();
++      /* Mustn't be empty */
++      BUG_ON(sh_fifo2_is_empty(queue));
++      /* 
++       * Check cookie matches, i.e. we're advancing over the same message
++       * as was got using peek 
++       */
++      BUG_ON(cookie != *(queue->fifo_rd_i));
++      sh_fifo2_rd_next(queue);
++      wmb();
++      net_accel_msg_unlock_queue(queue, &flags);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(net_accel_msg_recv_next);
 +
-+      pci_bus_add_devices(b);
 +
-+      return 0;
++/* 
++ * Receive a message on the specified FIFO. Returns 0 on success,
++ * -errno on failure.
++ */
++int net_accel_msg_recv(struct net_accel_shared_page *sp, sh_msg_fifo2 *queue, 
++                     struct net_accel_msg *msg)
++{
++      unsigned long flags;
++      int rc = 0;
++      NET_ACCEL_CHECK_MAGIC(sp, -EINVAL);
++      net_accel_msg_lock_queue(queue, &flags);
++      rmb();
++      if (sh_fifo2_is_empty(queue)) {
++              rc = -ENOENT;
++      } else {
++              sh_fifo2_get(queue, msg);
++      }
++      wmb();
++      net_accel_msg_unlock_queue(queue, &flags);
++      return rc;
++}
++EXPORT_SYMBOL_GPL(net_accel_msg_recv);
 +
-+      err_out:
-+      kfree(bus_entry);
-+      kfree(sd);
 +
-+      return err;
++/* 
++ * Start sending a message without copying. returns a pointer to a message
++ * that will be filled out in place. The queue is locked until the message 
++ * is sent.
++ */
++struct net_accel_msg *net_accel_msg_start_send(struct net_accel_shared_page *sp,
++                                             sh_msg_fifo2 *queue, unsigned long *flags)
++{
++      struct net_accel_msg *msg;
++      NET_ACCEL_CHECK_MAGIC(sp, NULL);
++      net_accel_msg_lock_queue(queue, flags);
++      rmb();
++      if (sh_fifo2_not_half_full(queue)) {
++              msg = sh_fifo2_pokep(queue);
++      } else {
++              net_accel_msg_unlock_queue(queue, flags);
++              msg = NULL;
++      }
++      return msg;
 +}
++EXPORT_SYMBOL_GPL(net_accel_msg_start_send);
 +
-+static void free_root_bus_devs(struct pci_bus *bus)
++
++static inline void _msg_complete(struct net_accel_shared_page *sp,
++                               sh_msg_fifo2 *queue,
++                               unsigned long *flags)
 +{
-+      struct pci_dev *dev;
++      sh_fifo2_wr_next(queue);
++      net_accel_msg_unlock_queue(queue, flags);
++}
 +
-+      while (!list_empty(&bus->devices)) {
-+              dev = container_of(bus->devices.next, struct pci_dev,
-+                                 bus_list);
-+              dev_dbg(&dev->dev, "removing device\n");
-+              pci_remove_bus_device(dev);
-+      }
++/*
++ * Complete the sending of a message started with net_accel_msg_start_send. The 
++ * message is implicit since the queue was locked by _start
++ */
++void net_accel_msg_complete_send(struct net_accel_shared_page *sp,
++                               sh_msg_fifo2 *queue,
++                               unsigned long *flags)
++{
++      _msg_complete(sp, queue, flags);
 +}
++EXPORT_SYMBOL_GPL(net_accel_msg_complete_send);
 +
-+void pcifront_free_roots(struct pcifront_device *pdev)
++/* As net_accel_msg_complete_send but does the notify. */
++void net_accel_msg_complete_send_notify(struct net_accel_shared_page *sp, 
++                                      sh_msg_fifo2 *queue, 
++                                      unsigned long *flags, int irq)
 +{
-+      struct pci_bus_entry *bus_entry, *t;
++      _msg_complete(sp, queue, flags);
++      notify_remote_via_irq(irq);
++}
++EXPORT_SYMBOL_GPL(net_accel_msg_complete_send_notify);
+--- linux-2.6.18.8/drivers/xen/sfc_netutil/accel_msg_iface.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netutil/accel_msg_iface.h      2008-05-19 00:33:48.742955720 +0300
+@@ -0,0 +1,414 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n");
++#ifndef NET_ACCEL_MSG_IFACE_H
++#define NET_ACCEL_MSG_IFACE_H
 +
-+      list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) {
-+              list_del(&bus_entry->list);
++#include <linux/ip.h>
++#include <linux/tcp.h>
++#include <linux/udp.h>
++#include <linux/in.h>
++#include <linux/netdevice.h>
++#include <linux/etherdevice.h>
 +
-+              free_root_bus_devs(bus_entry->bus);
++#include "accel_shared_fifo.h"
 +
-+              kfree(bus_entry->bus->sysdata);
++#define NET_ACCEL_MSG_MAGIC (0x85465479)
++
++/*! We talk version 0.010 of the interdomain protocol */
++#define NET_ACCEL_MSG_VERSION (0x00001000)
++
++/*! Shared memory portion of inter-domain FIFO */
++struct net_accel_msg_queue {
++      u32 read;
++      u32 write;
++};
 +
-+              device_unregister(bus_entry->bus->bridge);
-+              pci_remove_bus(bus_entry->bus);
 +
-+              kfree(bus_entry);
-+      }
-+}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/pcifront/xenbus.c linux-2.6.18-xen.hg/drivers/xen/pcifront/xenbus.c
---- linux-2.6.18/drivers/xen/pcifront/xenbus.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/pcifront/xenbus.c  2007-12-23 11:15:34.071269815 +0100
-@@ -0,0 +1,296 @@
 +/*
-+ * PCI Frontend Xenbus Setup - handles setup with backend (imports page/evtchn)
++ * The aflags in the following structure is used as follows:
 + *
-+ *   Author: Ryan Wilson <hap9@epoch.ncsc.mil>
++ *  - each bit is set when one of the corresponding variables is
++ *  changed by either end.
++ *
++ *  - the end that has made the change then forwards an IRQ to the
++ *  other
++ *
++ *  - the IRQ handler deals with these bits either on the fast path, or
++ *  for less common changes, by jumping onto the slow path.
++ *
++ *  - once it has seen a change, it clears the relevant bit.
++ *
++ * aflags is accessed atomically using clear_bit, test_bit,
++ * test_and_set_bit etc
 + */
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/mm.h>
-+#include <xen/xenbus.h>
-+#include <xen/gnttab.h>
-+#include "pcifront.h"
-+
-+#define INVALID_GRANT_REF (0)
-+#define INVALID_EVTCHN    (-1)
 +
-+static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev)
-+{
-+      struct pcifront_device *pdev;
++/*
++ * The following used to signify to the other domain when the queue
++ * they want to use is full, and when it is no longer full.  Could be
++ * compressed to use fewer bits but done this way for simplicity and
++ * clarity
++ */
 +
-+      pdev = kmalloc(sizeof(struct pcifront_device), GFP_KERNEL);
-+      if (pdev == NULL)
-+              goto out;
++/* "dom0->domU queue" is full */
++#define NET_ACCEL_MSG_AFLAGS_QUEUE0FULL      0x1 
++#define NET_ACCEL_MSG_AFLAGS_QUEUE0FULL_B    0
++/* "dom0->domU queue" is not full */
++#define NET_ACCEL_MSG_AFLAGS_QUEUE0NOTFULL   0x2 
++#define NET_ACCEL_MSG_AFLAGS_QUEUE0NOTFULL_B 1
++/* "domU->dom0 queue" is full */
++#define NET_ACCEL_MSG_AFLAGS_QUEUEUFULL      0x4 
++#define NET_ACCEL_MSG_AFLAGS_QUEUEUFULL_B    2
++/* "domU->dom0 queue" is not full */
++#define NET_ACCEL_MSG_AFLAGS_QUEUEUNOTFULL   0x8
++#define NET_ACCEL_MSG_AFLAGS_QUEUEUNOTFULL_B 3
++/* dom0 -> domU net_dev up/down events */
++#define NET_ACCEL_MSG_AFLAGS_NETUPDOWN         0x10
++#define NET_ACCEL_MSG_AFLAGS_NETUPDOWN_B       4
 +
-+      pdev->sh_info =
-+          (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL);
-+      if (pdev->sh_info == NULL) {
-+              kfree(pdev);
-+              pdev = NULL;
-+              goto out;
-+      }
-+      pdev->sh_info->flags = 0;
++/*
++ * Masks used to test if there are any messages for domU and dom0
++ * respectively
++ */
++#define NET_ACCEL_MSG_AFLAGS_TO_DOMU_MASK     \
++      (NET_ACCEL_MSG_AFLAGS_QUEUE0FULL    |   \
++       NET_ACCEL_MSG_AFLAGS_QUEUEUNOTFULL |   \
++       NET_ACCEL_MSG_AFLAGS_NETUPDOWN)
++#define NET_ACCEL_MSG_AFLAGS_TO_DOM0_MASK     \
++      (NET_ACCEL_MSG_AFLAGS_QUEUE0NOTFULL |   \
++       NET_ACCEL_MSG_AFLAGS_QUEUEUFULL)
 +
-+      xdev->dev.driver_data = pdev;
-+      pdev->xdev = xdev;
++/*! The shared data structure used for inter-VM communication. */
++struct net_accel_shared_page {
++      /*! Sanity check */
++      u32 magic;          
++      /*! Used by host/Dom0 */
++      struct net_accel_msg_queue queue0;
++      /*! Used by guest/DomU */
++      struct net_accel_msg_queue queue1;
++      /*! Atomic flags, used to communicate simple state changes */
++      u32 aflags;     
++      /*! State of net_dev used for acceleration */     
++      u32 net_dev_up; 
++};
 +
-+      INIT_LIST_HEAD(&pdev->root_buses);
 +
-+      spin_lock_init(&pdev->dev_lock);
-+      spin_lock_init(&pdev->sh_info_lock);
++enum net_accel_hw_type {
++      /*! Not a virtualisable NIC: use slow path. */
++      NET_ACCEL_MSG_HWTYPE_NONE = 0,
++      /*! NIC is Falcon-based */
++      NET_ACCEL_MSG_HWTYPE_FALCON_A = 1,
++      NET_ACCEL_MSG_HWTYPE_FALCON_B = 2,
++};
 +
-+      pdev->evtchn = INVALID_EVTCHN;
-+      pdev->gnt_ref = INVALID_GRANT_REF;
++/*! The maximum number of pages used by an event queue. */
++#define EF_HW_FALCON_EVQ_PAGES 8
 +
-+      dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n",
-+              pdev, pdev->sh_info);
-+      out:
-+      return pdev;
-+}
++struct net_accel_hw_falcon_b {
++      /* VI */
++      /*! Grant for Tx DMA Q */
++      u32 txdmaq_gnt;   
++      /*! Grant for Rx DMA Q */
++      u32 rxdmaq_gnt;   
++      /*! Machine frame number for Tx/Rx doorbell page */
++      u32 doorbell_mfn; 
++      /*! Grant for Tx/Rx doorbell page */
++      u32 doorbell_gnt;
 +
-+static void free_pdev(struct pcifront_device *pdev)
-+{
-+      dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev);
++      /* Event Q */
++      /*! Grants for the pages of the EVQ */
++      u32 evq_mem_gnts[EF_HW_FALCON_EVQ_PAGES]; 
++      u32 evq_offs;
++      /*! log2(pages in event Q) */
++      u32 evq_order;    
++      /*! Capacity in events */
++      u32 evq_capacity; 
++      /*! Eventq pointer register physical address */
++      u32 evq_rptr; 
++      /*! Interface instance */
++      u32 instance; 
++      /*! Capacity of RX queue */
++      u32 rx_capacity;
++      /*! Capacity of TX queue */
++      u32 tx_capacity;
++
++      /* NIC */
++      s32 nic_arch;
++      s32 nic_revision;
++      u8 nic_variant;
++};
++
++struct net_accel_hw_falcon_a {
++      struct net_accel_hw_falcon_b common;
++      u32 evq_rptr_gnt;
++};
++
++
++/*! Description of the hardware that the DomU is being given. */
++struct net_accel_msg_hw {
++      u32 type;               /*!< Hardware type */
++      union {
++              struct net_accel_hw_falcon_a falcon_a;
++              struct net_accel_hw_falcon_b falcon_b;
++      } resources;
++};
 +
-+      pcifront_free_roots(pdev);
++/*! Start-of-day handshake message. Dom0 fills in its version and
++ * sends, DomU checks, inserts its version and replies
++ */
++struct net_accel_msg_hello {
++      /*! Sender's version (set by each side in turn) */
++      u32 version;    
++      /*! max pages allocated/allowed for buffers */
++      u32 max_pages;      
++};
 +
-+      if (pdev->evtchn != INVALID_EVTCHN)
-+              xenbus_free_evtchn(pdev->xdev, pdev->evtchn);
++/*! Maximum number of page requests that can fit in a message. */
++#define NET_ACCEL_MSG_MAX_PAGE_REQ (8)
 +
-+      if (pdev->gnt_ref != INVALID_GRANT_REF)
-+              gnttab_end_foreign_access(pdev->gnt_ref,
-+                                        (unsigned long)pdev->sh_info);
++/*! Request for NIC buffers. DomU fils out pages and grants (and
++ *  optionally) reqid, dom0 fills out buf and sends reply 
++ */
++struct net_accel_msg_map_buffers {
++      u32 reqid;      /*!< Optional request ID */
++      u32 pages;      /*!< Number of pages to map */
++      u32 grants[NET_ACCEL_MSG_MAX_PAGE_REQ];  /*!< Grant ids to map */ 
++      u32 buf;          /*!< NIC buffer address of pages obtained */
++};
 +
-+      pdev->xdev->dev.driver_data = NULL;
++/*! Notification of a change to local mac address, used to filter
++  locally destined packets off the fast path */
++struct net_accel_msg_localmac {
++      u32 flags;      /*!< Should this be added or removed? */
++      u8 mac[ETH_ALEN]; /*!< The mac address to filter onto slow path */
++};
 +
-+      kfree(pdev);
-+}
++struct net_accel_msg_fastpath {
++      u32 flags;      /*!< Should this be added or removed? */
++      u8  mac[ETH_ALEN];/*!< The mac address to filter onto fast path */
++      u16 port;        /*!< The port of the connection */
++      u32 ip;    /*!< The IP address of the connection */
++      u8  proto;      /*!< The protocol of connection (TCP/UDP) */
++};
 +
-+static int pcifront_publish_info(struct pcifront_device *pdev)
-+{
-+      int err = 0;
-+      struct xenbus_transaction trans;
++/*! Values for struct ef_msg_localmac/fastpath.flags */
++#define NET_ACCEL_MSG_ADD    0x1
++#define NET_ACCEL_MSG_REMOVE 0x2
 +
-+      err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info));
-+      if (err < 0)
-+              goto out;
++/*! Overall message structure */
++struct net_accel_msg {
++      /*! ID specifying type of messge */
++      u32 id;              
++      union {
++              /*! handshake */
++              struct net_accel_msg_hello hello;  
++              /*! hardware description */
++              struct net_accel_msg_hw hw;     
++              /*! buffer map request */
++              struct net_accel_msg_map_buffers mapbufs; 
++              /*! mac address of a local interface */
++              struct net_accel_msg_localmac localmac; 
++              /*! address of a new fastpath connection */
++              struct net_accel_msg_fastpath fastpath; 
++              /*! make the message a fixed size */
++              u8 pad[128 - sizeof(u32)]; 
++      }  u;
++};
 +
-+      pdev->gnt_ref = err;
 +
-+      err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn);
-+      if (err)
-+              goto out;
++#define NET_ACCEL_MSG_HW_TO_MSG(_u) container_of(_u, struct net_accel_msg, u.hw)
 +
-+      do_publish:
-+      err = xenbus_transaction_start(&trans);
-+      if (err) {
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Error writing configuration for backend "
-+                               "(start transaction)");
-+              goto out;
-+      }
++/*! Inter-domain message FIFO */
++typedef struct {
++      struct net_accel_msg *fifo;
++      u32 fifo_mask;
++      u32 *fifo_rd_i;
++      u32 *fifo_wr_i;
++      spinlock_t lock;
++      u32 is_locked; /* Debug flag */
++} sh_msg_fifo2;
 +
-+      err = xenbus_printf(trans, pdev->xdev->nodename,
-+                          "pci-op-ref", "%u", pdev->gnt_ref);
-+      if (!err)
-+              err = xenbus_printf(trans, pdev->xdev->nodename,
-+                                  "event-channel", "%u", pdev->evtchn);
-+      if (!err)
-+              err = xenbus_printf(trans, pdev->xdev->nodename,
-+                                  "magic", XEN_PCI_MAGIC);
 +
-+      if (err) {
-+              xenbus_transaction_end(trans, 1);
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Error writing configuration for backend");
-+              goto out;
-+      } else {
-+              err = xenbus_transaction_end(trans, 0);
-+              if (err == -EAGAIN)
-+                      goto do_publish;
-+              else if (err) {
-+                      xenbus_dev_fatal(pdev->xdev, err,
-+                                       "Error completing transaction "
-+                                       "for backend");
-+                      goto out;
-+              }
-+      }
++#define NET_ACCEL_MSG_OFFSET_MASK PAGE_MASK
 +
-+      xenbus_switch_state(pdev->xdev, XenbusStateInitialised);
++/* Modifiers */
++#define NET_ACCEL_MSG_REPLY    (0x80000000)
++#define NET_ACCEL_MSG_ERROR    (0x40000000)
 +
-+      dev_dbg(&pdev->xdev->dev, "publishing successful!\n");
++/* Dom0 -> DomU and reply. Handshake/version check. */
++#define NET_ACCEL_MSG_HELLO    (0x00000001)
++/* Dom0 -> DomU : hardware setup (VI info.) */
++#define NET_ACCEL_MSG_SETHW    (0x00000002)
++/*
++ * Dom0 -> DomU. Notification of a local mac to add/remove from slow
++ * path filter
++ */
++#define NET_ACCEL_MSG_LOCALMAC (0x00000003)
++/* 
++ * DomU -> Dom0 and reply. Request for buffer table entries for
++ * preallocated pages.
++ */
++#define NET_ACCEL_MSG_MAPBUF   (0x00000004)
++/* 
++ * Dom0 -> DomU. Notification of a local mac to add/remove from fast
++ * path filter
++ */
++#define NET_ACCEL_MSG_FASTPATH (0x00000005)
 +
-+      out:
-+      return err;
++/*! Initialise a message and set the type
++ * \param message : the message
++ * \param code : the message type 
++ */
++static inline void net_accel_msg_init(struct net_accel_msg *msg, int code) {
++      msg->id = (u32)code;
 +}
 +
-+static int pcifront_try_connect(struct pcifront_device *pdev)
-+{
-+      int err = -EFAULT;
-+      int i, num_roots, len;
-+      char str[64];
-+      unsigned int domain, bus;
++/*! initialise a shared page structure
++ * \param shared_page : mapped memory in which the structure resides
++ * \param len : size of the message FIFO area that follows
++ * \param up : initial up/down state of netdev 
++ * \return 0 or an error code
++ */
++extern int net_accel_msg_init_page(void *shared_page, int len, int up);
 +
-+      spin_lock(&pdev->dev_lock);
++/*! initialise a message queue 
++ * \param queue : the message FIFO to initialise 
++ * \param indices : the read and write indices in shared memory
++ * \param base : the start of the memory area for the FIFO
++ * \param size : the size of the FIFO in bytes
++ */
++extern void net_accel_msg_init_queue(sh_msg_fifo2 *queue,
++                                   struct net_accel_msg_queue *indices,
++                                   struct net_accel_msg *base, int size);
 +
-+      /* Only connect once */
-+      if (xenbus_read_driver_state(pdev->xdev->nodename) !=
-+          XenbusStateInitialised)
-+              goto out;
++/* Notify after a batch of messages have been sent */
++extern void net_accel_msg_notify(int irq);
 +
-+      err = pcifront_connect(pdev);
-+      if (err) {
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Error connecting PCI Frontend");
-+              goto out;
-+      }
++/*! Send a message on the specified FIFO. The message is copied to the 
++ *  current slot of the FIFO.
++ * \param sp : pointer to shared page
++ * \param q : pointer to message FIFO to use
++ * \param msg : pointer to message 
++ * \return 0 on success, -errno on
++ */ 
++extern int net_accel_msg_send(struct net_accel_shared_page *sp,
++                            sh_msg_fifo2 *q, 
++                            struct net_accel_msg *msg);
++extern int net_accel_msg_reply(struct net_accel_shared_page *sp,
++                            sh_msg_fifo2 *q, 
++                            struct net_accel_msg *msg);
++
++/*! As net_accel_msg_send but also posts a notification to the far end. */
++extern int net_accel_msg_send_notify(struct net_accel_shared_page *sp, 
++                                   int irq, sh_msg_fifo2 *q, 
++                                   struct net_accel_msg *msg);
++/*! As net_accel_msg_send but also posts a notification to the far end. */
++extern int net_accel_msg_reply_notify(struct net_accel_shared_page *sp, 
++                                    int irq, sh_msg_fifo2 *q, 
++                                    struct net_accel_msg *msg);
++
++/*! Receive a message on the specified FIFO. Returns 0 on success,
++ *  -errno on failure.
++ */
++extern int net_accel_msg_recv(struct net_accel_shared_page *sp,
++                            sh_msg_fifo2 *q,
++                            struct net_accel_msg *msg);
++
++/*! Look at a received message, if any, so a decision can be made
++ *  about whether to read it now or not.  Cookie is a bit of debug
++ *  which is set here and checked when passed to
++ *  net_accel_msg_recv_next()
++ */
++extern int net_accel_msg_peek(struct net_accel_shared_page *sp,
++                            sh_msg_fifo2 *queue, 
++                            struct net_accel_msg *msg, int *cookie);
++/*! Move the queue onto the next element, used after finished with a
++ *  peeked msg 
++ */
++extern int net_accel_msg_recv_next(struct net_accel_shared_page *sp,
++                                 sh_msg_fifo2 *queue, int cookie);
++
++/*! Start sending a message without copying. returns a pointer to a
++ *  message that will be filled out in place. The queue is locked
++ *  until the message is sent.
++ */
++extern 
++struct net_accel_msg *net_accel_msg_start_send(struct net_accel_shared_page *sp,
++                                             sh_msg_fifo2 *queue,
++                                             unsigned long *flags);
 +
-+      err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend,
-+                         "root_num", "%d", &num_roots);
-+      if (err == -ENOENT) {
-+              xenbus_dev_error(pdev->xdev, err,
-+                               "No PCI Roots found, trying 0000:00");
-+              err = pcifront_scan_root(pdev, 0, 0);
-+              num_roots = 0;
-+      } else if (err != 1) {
-+              if (err == 0)
-+                      err = -EINVAL;
-+              xenbus_dev_fatal(pdev->xdev, err,
-+                               "Error reading number of PCI roots");
-+              goto out;
-+      }
 +
-+      for (i = 0; i < num_roots; i++) {
-+              len = snprintf(str, sizeof(str), "root-%d", i);
-+              if (unlikely(len >= (sizeof(str) - 1))) {
-+                      err = -ENOMEM;
-+                      goto out;
-+              }
++/*! Complete the sending of a message started with
++ *  net_accel_msg_start_send. The message is implicit since the queue
++ *  was locked by _start 
++ */
++extern void net_accel_msg_complete_send(struct net_accel_shared_page *sp,
++                                      sh_msg_fifo2 *queue,
++                                      unsigned long *flags);
 +
-+              err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str,
-+                                 "%x:%x", &domain, &bus);
-+              if (err != 2) {
-+                      if (err >= 0)
-+                              err = -EINVAL;
-+                      xenbus_dev_fatal(pdev->xdev, err,
-+                                       "Error reading PCI root %d", i);
-+                      goto out;
-+              }
++/*! As net_accel_msg_complete_send but does the notify. */
++extern void net_accel_msg_complete_send_notify(struct net_accel_shared_page *sp, 
++                                             sh_msg_fifo2 *queue,
++                                             unsigned long *flags, int irq);
 +
-+              err = pcifront_scan_root(pdev, domain, bus);
-+              if (err) {
-+                      xenbus_dev_fatal(pdev->xdev, err,
-+                                       "Error scanning PCI root %04x:%02x",
-+                                       domain, bus);
-+                      goto out;
-+              }
-+      }
++/*! Lock the queue so that multiple "_locked" functions can be called
++ *  without the queue being modified by others 
++ */
++static inline
++void net_accel_msg_lock_queue(sh_msg_fifo2 *queue, unsigned long *flags)
++{
++      spin_lock_irqsave(&queue->lock, (*flags));
++      rmb();
++      BUG_ON(queue->is_locked);
++      queue->is_locked = 1;
++}
 +
-+      err = xenbus_switch_state(pdev->xdev, XenbusStateConnected);
-+      if (err)
-+              goto out;
++/*! Unlock the queue */
++static inline
++void net_accel_msg_unlock_queue(sh_msg_fifo2 *queue, unsigned long *flags)
++{
++      BUG_ON(!queue->is_locked);
++      queue->is_locked = 0;
++      wmb();
++      spin_unlock_irqrestore(&queue->lock, (*flags));
++}
 +
-+      out:
-+      spin_unlock(&pdev->dev_lock);
-+      return err;
++/*! Give up without sending a message that was started with
++ *  net_accel_msg_start_send() 
++ */
++static inline 
++void net_accel_msg_abort_send(struct net_accel_shared_page *sp,
++                            sh_msg_fifo2 *queue, unsigned long *flags)
++{
++      net_accel_msg_unlock_queue(queue, flags);
 +}
 +
-+static int pcifront_try_disconnect(struct pcifront_device *pdev)
++/*! Test the queue to ensure there is sufficient space */
++static inline
++int net_accel_msg_check_space(sh_msg_fifo2 *queue, unsigned space)
 +{
-+      int err = 0;
-+      enum xenbus_state prev_state;
++      return sh_fifo2_space(queue) >= space;
++}
 +
-+      spin_lock(&pdev->dev_lock);
++#endif /* NET_ACCEL_MSG_IFACE_H */
+--- linux-2.6.18.8/drivers/xen/sfc_netutil/accel_shared_fifo.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netutil/accel_shared_fifo.h    2008-05-19 00:33:48.742955720 +0300
+@@ -0,0 +1,127 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
 +
-+      prev_state = xenbus_read_driver_state(pdev->xdev->nodename);
++#ifndef NET_ACCEL_SHARED_FIFO_H
++#define NET_ACCEL_SHARED_FIFO_H
 +
-+      if (prev_state < XenbusStateClosing)
-+              err = xenbus_switch_state(pdev->xdev, XenbusStateClosing);
++/*
++ * This is based on fifo.h, but handles sharing between address spaces
++ * that don't trust each other, by splitting out the read and write
++ * indices. This costs at least one pointer indirection more than the
++ * vanilla version per access.
++ */
 +
-+      if (!err && prev_state == XenbusStateConnected)
-+              pcifront_disconnect(pdev);
++typedef struct {
++      char*    fifo;
++      unsigned      fifo_mask;
++      unsigned      *fifo_rd_i;
++      unsigned      *fifo_wr_i;
++} sh_byte_fifo2;
 +
-+      spin_unlock(&pdev->dev_lock);
++#define SH_FIFO2_M(f, x)     ((x) & ((f)->fifo_mask))
 +
-+      return err;
++static inline unsigned log2_ge(unsigned long n, unsigned min_order) {
++      unsigned order = min_order;
++      while((1ul << order) < n) ++order;
++      return order;
 +}
 +
-+static void pcifront_backend_changed(struct xenbus_device *xdev,
-+                                   enum xenbus_state be_state)
-+{
-+      struct pcifront_device *pdev = xdev->dev.driver_data;
-+
-+      switch (be_state) {
-+      case XenbusStateClosing:
-+              dev_warn(&xdev->dev, "backend going away!\n");
-+              pcifront_try_disconnect(pdev);
-+              break;
++static inline unsigned long pow2(unsigned order) {
++      return (1ul << order);
++}
 +
-+      case XenbusStateUnknown:
-+      case XenbusStateClosed:
-+              dev_warn(&xdev->dev, "backend went away!\n");
-+              pcifront_try_disconnect(pdev);
++#define is_pow2(x)  (pow2(log2_ge((x), 0)) == (x))
 +
-+              device_unregister(&pdev->xdev->dev);
-+              break;
++#define sh_fifo2_valid(f)  ((f) && (f)->fifo && (f)->fifo_mask > 0 &&   \
++                          is_pow2((f)->fifo_mask+1u))
 +
-+      case XenbusStateConnected:
-+              pcifront_try_connect(pdev);
-+              break;
++#define sh_fifo2_init(f, cap, _rptr, _wptr)           \
++      do {                                            \
++              BUG_ON(!is_pow2((cap) + 1));            \
++              (f)->fifo_rd_i = _rptr;                 \
++              (f)->fifo_wr_i = _wptr;                 \
++              *(f)->fifo_rd_i = *(f)->fifo_wr_i = 0u; \
++              (f)->fifo_mask = (cap);                 \
++      } while(0)
 +
-+      default:
-+              break;
-+      }
-+}
++#define sh_fifo2_num(f)      SH_FIFO2_M((f),*(f)->fifo_wr_i - *(f)->fifo_rd_i)
++#define sh_fifo2_space(f)    SH_FIFO2_M((f),*(f)->fifo_rd_i - *(f)->fifo_wr_i-1u)
++#define sh_fifo2_is_empty(f)  (sh_fifo2_num(f)==0)
++#define sh_fifo2_not_empty(f) (sh_fifo2_num(f)!=0)
++#define sh_fifo2_is_full(f)   (sh_fifo2_space(f)==0u)
++#define sh_fifo2_not_full(f)  (sh_fifo2_space(f)!=0u)
++#define sh_fifo2_buf_size(f) ((f)->fifo_mask + 1u)
++#define sh_fifo2_capacity(f) ((f)->fifo_mask)
++#define sh_fifo2_end(f)      ((f)->fifo + sh_fifo2_buf_size(f))
++#define sh_fifo2_not_half_full(f) (sh_fifo2_space(f) > (sh_fifo2_capacity(f) >> 1))
 +
-+static int pcifront_xenbus_probe(struct xenbus_device *xdev,
-+                               const struct xenbus_device_id *id)
-+{
-+      int err = 0;
-+      struct pcifront_device *pdev = alloc_pdev(xdev);
++#define sh_fifo2_peek(f)     ((f)->fifo[SH_FIFO2_M((f), *(f)->fifo_rd_i)])
++#define sh_fifo2_peekp(f)    ((f)->fifo + SH_FIFO2_M((f), *(f)->fifo_rd_i))
++#define sh_fifo2_poke(f)     ((f)->fifo[SH_FIFO2_M((f), *(f)->fifo_wr_i)])
++#define sh_fifo2_pokep(f)    ((f)->fifo + SH_FIFO2_M((f), *(f)->fifo_wr_i))
++#define sh_fifo2_peek_i(f,i) ((f)->fifo[SH_FIFO2_M((f), *(f)->fifo_rd_i+(i))])
++#define sh_fifo2_poke_i(f,i) ((f)->fifo[SH_FIFO2_M((f), *(f)->fifo_wr_i+(i))])
 +
-+      if (pdev == NULL) {
-+              err = -ENOMEM;
-+              xenbus_dev_fatal(xdev, err,
-+                               "Error allocating pcifront_device struct");
-+              goto out;
-+      }
++#define sh_fifo2_rd_next(f)                                   \
++      do {*(f)->fifo_rd_i = *(f)->fifo_rd_i + 1u;} while(0)
++#define sh_fifo2_wr_next(f)                                   \
++      do {*(f)->fifo_wr_i = *(f)->fifo_wr_i + 1u;} while(0)
++#define sh_fifo2_rd_adv(f, n)                                 \
++      do {*(f)->fifo_rd_i = *(f)->fifo_rd_i + (n);} while(0)
++#define sh_fifo2_wr_adv(f, n)                                 \
++      do {*(f)->fifo_wr_i = *(f)->fifo_wr_i + (n);} while(0)
 +
-+      err = pcifront_publish_info(pdev);
++#define sh_fifo2_put(f, v)                                            \
++      do {sh_fifo2_poke(f) = (v); wmb(); sh_fifo2_wr_next(f);} while(0)
 +
-+      out:
-+      return err;
-+}
++#define sh_fifo2_get(f, pv)                                           \
++      do {*(pv) = sh_fifo2_peek(f); mb(); sh_fifo2_rd_next(f);} while(0)
 +
-+static int pcifront_xenbus_remove(struct xenbus_device *xdev)
++static inline unsigned sh_fifo2_contig_num(sh_byte_fifo2 *f)
 +{
-+      if (xdev->dev.driver_data)
-+              free_pdev(xdev->dev.driver_data);
++      unsigned fifo_wr_i = SH_FIFO2_M(f, *f->fifo_wr_i);
++      unsigned fifo_rd_i = SH_FIFO2_M(f, *f->fifo_rd_i);
 +
-+      return 0;
++      return (fifo_wr_i >= fifo_rd_i)
++              ? fifo_wr_i - fifo_rd_i
++              : f->fifo_mask + 1u - *(f)->fifo_rd_i;
 +}
 +
-+static struct xenbus_device_id xenpci_ids[] = {
-+      {"pci"},
-+      {{0}},
-+};
-+MODULE_ALIAS("xen:pci");
-+
-+static struct xenbus_driver xenbus_pcifront_driver = {
-+      .name                   = "pcifront",
-+      .owner                  = THIS_MODULE,
-+      .ids                    = xenpci_ids,
-+      .probe                  = pcifront_xenbus_probe,
-+      .remove                 = pcifront_xenbus_remove,
-+      .otherend_changed       = pcifront_backend_changed,
-+};
-+
-+static int __init pcifront_init(void)
++static inline unsigned sh_fifo2_contig_space(sh_byte_fifo2 *f)
 +{
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++      unsigned fifo_wr_i = SH_FIFO2_M(f, *f->fifo_wr_i);
++      unsigned fifo_rd_i = SH_FIFO2_M(f, *f->fifo_rd_i);
 +
-+      return xenbus_register_frontend(&xenbus_pcifront_driver);
++      return (fifo_rd_i > fifo_wr_i)
++              ? fifo_rd_i - fifo_wr_i - 1
++              : (f->fifo_mask + 1u - fifo_wr_i
++                 /*
++                  * The last byte can't be used if the read pointer
++                  * is at zero.
++                  */
++                 - (fifo_rd_i==0));
 +}
 +
-+/* Initialize after the Xen PCI Frontend Stub is initialized */
-+subsys_initcall(pcifront_init);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/privcmd/compat_privcmd.c linux-2.6.18-xen.hg/drivers/xen/privcmd/compat_privcmd.c
---- linux-2.6.18/drivers/xen/privcmd/compat_privcmd.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/privcmd/compat_privcmd.c   2007-12-23 11:15:34.071269815 +0100
-@@ -0,0 +1,73 @@
-+/*
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License as published by
-+ * the Free Software Foundation; either version 2 of the License, or
-+ * (at your option) any later version.
++
++#endif /* NET_ACCEL_SHARED_FIFO_H */
+--- linux-2.6.18.8/drivers/xen/sfc_netutil/accel_util.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netutil/accel_util.c   2008-05-19 00:33:48.746955951 +0300
+@@ -0,0 +1,333 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -102151,366 +166624,458 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/privcmd/comp
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software
-+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
-+ *
-+ * Copyright (C) IBM Corp. 2006
-+ *
-+ * Authors: Jimi Xenidis <jimix@watson.ibm.com>
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
 + */
 +
-+#include <linux/config.h>
-+#include <linux/compat.h>
-+#include <linux/ioctl.h>
-+#include <linux/syscalls.h>
-+#include <asm/hypervisor.h>
-+#include <asm/uaccess.h>
-+#include <xen/public/privcmd.h>
-+#include <xen/compat_ioctl.h>
-+
-+int privcmd_ioctl_32(int fd, unsigned int cmd, unsigned long arg)
-+{
-+      int ret;
++#include <linux/if_ether.h>
++#include <asm/io.h>
++#include <asm/pgtable.h>
++#include <asm/hypercall.h>
++#include <xen/xenbus.h>
++#include <xen/driver_util.h>
++#include <xen/gnttab.h>
 +
-+      switch (cmd) {
-+      case IOCTL_PRIVCMD_MMAP_32: {
-+              struct privcmd_mmap *p;
-+              struct privcmd_mmap_32 *p32;
-+              struct privcmd_mmap_32 n32;
++#include "accel_util.h"
 +
-+              p32 = compat_ptr(arg);
-+              p = compat_alloc_user_space(sizeof(*p));
-+              if (copy_from_user(&n32, p32, sizeof(n32)) ||
-+                  put_user(n32.num, &p->num) ||
-+                  put_user(n32.dom, &p->dom) ||
-+                  put_user(compat_ptr(n32.entry), &p->entry))
-+                      return -EFAULT;
-+              
-+              ret = sys_ioctl(fd, IOCTL_PRIVCMD_MMAP, (unsigned long)p);
-+      }
-+              break;
-+      case IOCTL_PRIVCMD_MMAPBATCH_32: {
-+              struct privcmd_mmapbatch *p;
-+              struct privcmd_mmapbatch_32 *p32;
-+              struct privcmd_mmapbatch_32 n32;
++#ifdef EFX_GCOV
++#include "gcov.h"
 +
-+              p32 = compat_ptr(arg);
-+              p = compat_alloc_user_space(sizeof(*p));
-+              if (copy_from_user(&n32, p32, sizeof(n32)) ||
-+                  put_user(n32.num, &p->num) ||
-+                  put_user(n32.dom, &p->dom) ||
-+                  put_user(n32.addr, &p->addr) ||
-+                  put_user(compat_ptr(n32.arr), &p->arr))
-+                      return -EFAULT;
-+              
-+              ret = sys_ioctl(fd, IOCTL_PRIVCMD_MMAPBATCH, (unsigned long)p);
-+      }
-+              break;
-+      default:
-+              ret = -EINVAL;
-+              break;
-+      }
-+      return ret;
++static int __init net_accel_init(void)
++{
++      gcov_provider_init(THIS_MODULE);
++      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/privcmd/Makefile linux-2.6.18-xen.hg/drivers/xen/privcmd/Makefile
---- linux-2.6.18/drivers/xen/privcmd/Makefile  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/privcmd/Makefile   2007-12-23 11:15:34.071269815 +0100
-@@ -0,0 +1,3 @@
++module_init(net_accel_init);
 +
-+obj-y += privcmd.o
-+obj-$(CONFIG_COMPAT)  += compat_privcmd.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/privcmd/privcmd.c linux-2.6.18-xen.hg/drivers/xen/privcmd/privcmd.c
---- linux-2.6.18/drivers/xen/privcmd/privcmd.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/privcmd/privcmd.c  2007-12-23 11:15:34.071269815 +0100
-@@ -0,0 +1,286 @@
-+/******************************************************************************
-+ * privcmd.c
-+ * 
-+ * Interface to privileged domain-0 commands.
-+ * 
-+ * Copyright (c) 2002-2004, K A Fraser, B Dragovic
-+ */
++static void __exit net_accel_exit(void)
++{
++      gcov_provider_fini(THIS_MODULE);
++}
++module_exit(net_accel_exit);
++#endif
 +
-+#include <linux/kernel.h>
-+#include <linux/sched.h>
-+#include <linux/slab.h>
-+#include <linux/string.h>
-+#include <linux/errno.h>
-+#include <linux/mm.h>
-+#include <linux/mman.h>
-+#include <linux/swap.h>
-+#include <linux/smp_lock.h>
-+#include <linux/highmem.h>
-+#include <linux/pagemap.h>
-+#include <linux/seq_file.h>
-+#include <asm/hypervisor.h>
++/* Shutdown remote domain that is misbehaving */
++int net_accel_shutdown_remote(int domain)
++{
++      struct sched_remote_shutdown sched_shutdown = {
++              .domain_id = domain,
++              .reason = SHUTDOWN_crash
++      };
 +
-+#include <asm/pgalloc.h>
-+#include <asm/pgtable.h>
-+#include <asm/uaccess.h>
-+#include <asm/tlb.h>
-+#include <asm/hypervisor.h>
-+#include <xen/public/privcmd.h>
-+#include <xen/interface/xen.h>
-+#include <xen/xen_proc.h>
-+#include <xen/features.h>
++      EPRINTK("Crashing domain %d\n", domain);
 +
-+static struct proc_dir_entry *privcmd_intf;
-+static struct proc_dir_entry *capabilities_intf;
++      return HYPERVISOR_sched_op(SCHEDOP_remote_shutdown, &sched_shutdown);
++}
++EXPORT_SYMBOL(net_accel_shutdown_remote);
 +
-+#ifndef HAVE_ARCH_PRIVCMD_MMAP
-+static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma);
-+#endif
 +
-+static long privcmd_ioctl(struct file *file,
-+                        unsigned int cmd, unsigned long data)
++/* Based on xenbus_backend_client.c:xenbus_map_ring() */
++static int net_accel_map_grant(struct xenbus_device *dev, int gnt_ref,
++                             grant_handle_t *handle, void *vaddr, 
++                             u64 *dev_bus_addr, unsigned flags)
 +{
-+      int ret = -ENOSYS;
-+      void __user *udata = (void __user *) data;
++      struct gnttab_map_grant_ref op;
++      
++      gnttab_set_map_op(&op, (unsigned long)vaddr, flags,
++                        gnt_ref, dev->otherend_id);
 +
-+      switch (cmd) {
-+      case IOCTL_PRIVCMD_HYPERCALL: {
-+              privcmd_hypercall_t hypercall;
-+  
-+              if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
-+                      return -EFAULT;
++      BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, &op, 1));
 +
-+#if defined(__i386__)
-+              if (hypercall.op >= (PAGE_SIZE >> 5))
-+                      break;
-+              __asm__ __volatile__ (
-+                      "pushl %%ebx; pushl %%ecx; pushl %%edx; "
-+                      "pushl %%esi; pushl %%edi; "
-+                      "movl  8(%%eax),%%ebx ;"
-+                      "movl 16(%%eax),%%ecx ;"
-+                      "movl 24(%%eax),%%edx ;"
-+                      "movl 32(%%eax),%%esi ;"
-+                      "movl 40(%%eax),%%edi ;"
-+                      "movl   (%%eax),%%eax ;"
-+                      "shll $5,%%eax ;"
-+                      "addl $hypercall_page,%%eax ;"
-+                      "call *%%eax ;"
-+                      "popl %%edi; popl %%esi; popl %%edx; "
-+                      "popl %%ecx; popl %%ebx"
-+                      : "=a" (ret) : "0" (&hypercall) : "memory" );
-+#elif defined (__x86_64__)
-+              if (hypercall.op < (PAGE_SIZE >> 5)) {
-+                      long ign1, ign2, ign3;
-+                      __asm__ __volatile__ (
-+                              "movq %8,%%r10; movq %9,%%r8;"
-+                              "shll $5,%%eax ;"
-+                              "addq $hypercall_page,%%rax ;"
-+                              "call *%%rax"
-+                              : "=a" (ret), "=D" (ign1),
-+                                "=S" (ign2), "=d" (ign3)
-+                              : "0" ((unsigned int)hypercall.op),
-+                              "1" (hypercall.arg[0]),
-+                              "2" (hypercall.arg[1]),
-+                              "3" (hypercall.arg[2]),
-+                              "g" (hypercall.arg[3]),
-+                              "g" (hypercall.arg[4])
-+                              : "r8", "r10", "memory" );
-+              }
-+#else
-+              ret = privcmd_hypercall(&hypercall);
-+#endif
++      if (op.status != GNTST_okay) {
++              xenbus_dev_error
++                      (dev, op.status,
++                       "failed mapping in shared page %d from domain %d\n",
++                       gnt_ref, dev->otherend_id);
++      } else {
++              *handle = op.handle;
++              if (dev_bus_addr)
++                      *dev_bus_addr = op.dev_bus_addr;
 +      }
-+      break;
 +
-+      case IOCTL_PRIVCMD_MMAP: {
-+              privcmd_mmap_t mmapcmd;
-+              privcmd_mmap_entry_t msg;
-+              privcmd_mmap_entry_t __user *p;
-+              struct mm_struct *mm = current->mm;
-+              struct vm_area_struct *vma;
-+              unsigned long va;
-+              int i, rc;
++      return op.status;
++}
 +
-+              if (!is_initial_xendomain())
-+                      return -EPERM;
 +
-+              if (copy_from_user(&mmapcmd, udata, sizeof(mmapcmd)))
-+                      return -EFAULT;
++/* Based on xenbus_backend_client.c:xenbus_unmap_ring() */
++static int net_accel_unmap_grant(struct xenbus_device *dev, 
++                               grant_handle_t handle,
++                               void *vaddr, u64 dev_bus_addr,
++                               unsigned flags)
++{
++      struct gnttab_unmap_grant_ref op;
 +
-+              p = mmapcmd.entry;
-+              if (copy_from_user(&msg, p, sizeof(msg)))
-+                      return -EFAULT;
++      gnttab_set_unmap_op(&op, (unsigned long)vaddr, flags, handle);
++      
++      if (dev_bus_addr)
++              op.dev_bus_addr = dev_bus_addr;
 +
-+              down_write(&mm->mmap_sem);
++      BUG_ON(HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, &op, 1));
 +
-+              vma = find_vma(mm, msg.va);
-+              rc = -EINVAL;
-+              if (!vma || (msg.va != vma->vm_start) ||
-+                  !privcmd_enforce_singleshot_mapping(vma))
-+                      goto mmap_out;
++      if (op.status != GNTST_okay)
++              xenbus_dev_error(dev, op.status,
++                               "failed unmapping page at handle %d error %d\n",
++                               handle, op.status);
 +
-+              va = vma->vm_start;
++      return op.status;
++}
 +
-+              for (i = 0; i < mmapcmd.num; i++) {
-+                      rc = -EFAULT;
-+                      if (copy_from_user(&msg, p, sizeof(msg)))
-+                              goto mmap_out;
 +
-+                      /* Do not allow range to wrap the address space. */
-+                      rc = -EINVAL;
-+                      if ((msg.npages > (LONG_MAX >> PAGE_SHIFT)) ||
-+                          ((unsigned long)(msg.npages << PAGE_SHIFT) >= -va))
-+                              goto mmap_out;
++int net_accel_map_device_page(struct xenbus_device *dev,  
++                            int gnt_ref, grant_handle_t *handle,
++                            u64 *dev_bus_addr)
++{
++      return net_accel_map_grant(dev, gnt_ref, handle, 0, dev_bus_addr,
++                                 GNTMAP_device_map);
++}
++EXPORT_SYMBOL_GPL(net_accel_map_device_page);
 +
-+                      /* Range chunks must be contiguous in va space. */
-+                      if ((msg.va != va) ||
-+                          ((msg.va+(msg.npages<<PAGE_SHIFT)) > vma->vm_end))
-+                              goto mmap_out;
++ 
++int net_accel_unmap_device_page(struct xenbus_device *dev,
++                              grant_handle_t handle, u64 dev_bus_addr)
++{
++      return net_accel_unmap_grant(dev, handle, 0, dev_bus_addr, 
++                                   GNTMAP_device_map);
++}
++EXPORT_SYMBOL_GPL(net_accel_unmap_device_page);
 +
-+                      if ((rc = direct_remap_pfn_range(
-+                              vma,
-+                              msg.va & PAGE_MASK, 
-+                              msg.mfn, 
-+                              msg.npages << PAGE_SHIFT, 
-+                              vma->vm_page_prot,
-+                              mmapcmd.dom)) < 0)
-+                              goto mmap_out;
 +
-+                      p++;
-+                      va += msg.npages << PAGE_SHIFT;
-+              }
++struct net_accel_valloc_grant_mapping {
++      struct vm_struct *vm;
++      int pages;
++      grant_handle_t grant_handles[0];
++};
 +
-+              rc = 0;
++/* Map a series of grants into a contiguous virtual area */
++static void *net_accel_map_grants_valloc(struct xenbus_device *dev, 
++                                       unsigned *grants, int npages, 
++                                       unsigned flags, void **priv)
++{
++      struct net_accel_valloc_grant_mapping *map;
++      struct vm_struct *vm;
++      void *addr;
++      int i, j, rc;
 +
-+      mmap_out:
-+              up_write(&mm->mmap_sem);
-+              ret = rc;
++      vm  = alloc_vm_area(PAGE_SIZE * npages);
++      if (vm == NULL) {
++              EPRINTK("No memory from alloc_vm_area.\n");
++              return NULL;
 +      }
-+      break;
-+
-+      case IOCTL_PRIVCMD_MMAPBATCH: {
-+              privcmd_mmapbatch_t m;
-+              struct mm_struct *mm = current->mm;
-+              struct vm_area_struct *vma;
-+              xen_pfn_t __user *p;
-+              unsigned long addr, mfn, nr_pages;
-+              int i;
-+
-+              if (!is_initial_xendomain())
-+                      return -EPERM;
++      /* 
++       * Get a structure in which we will record all the info needed
++       * to undo the mapping.
++       */
++      map = kzalloc(sizeof(struct net_accel_valloc_grant_mapping)  + 
++                    npages * sizeof(grant_handle_t), GFP_KERNEL);
++      if (map == NULL) {
++              EPRINTK("No memory for net_accel_valloc_grant_mapping\n");
++              free_vm_area(vm);
++              return NULL;
++      }
++      map->vm = vm;
++      map->pages = npages;
 +
-+              if (copy_from_user(&m, udata, sizeof(m)))
-+                      return -EFAULT;
++      /* Do the actual mapping */
++      addr = vm->addr;
++      for (i = 0; i < npages; i++) {
++              rc = net_accel_map_grant(dev, grants[i], map->grant_handles + i, 
++                                       addr, NULL, flags);
++              if (rc != 0)
++                      goto undo;
++              addr = (void*)((unsigned long)addr + PAGE_SIZE);
++      }
 +
-+              nr_pages = m.num;
-+              if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
-+                      return -EINVAL;
++      if (priv)
++              *priv = (void *)map;
++      else
++              kfree(map);
 +
-+              down_write(&mm->mmap_sem);
++      return vm->addr;
 +
-+              vma = find_vma(mm, m.addr);
-+              if (!vma ||
-+                  (m.addr != vma->vm_start) ||
-+                  ((m.addr + (nr_pages << PAGE_SHIFT)) != vma->vm_end) ||
-+                  !privcmd_enforce_singleshot_mapping(vma)) {
-+                      up_write(&mm->mmap_sem);
-+                      return -EINVAL;
-+              }
++ undo:
++      EPRINTK("Aborting contig map due to single map failure %d (%d of %d)\n",
++              rc, i+1, npages);
++      for (j = 0; j < i; j++) {
++              addr = (void*)((unsigned long)vm->addr + (j * PAGE_SIZE));
++              net_accel_unmap_grant(dev, map->grant_handles[j], addr, 0,
++                                    flags);
++      }
++      free_vm_area(vm);
++      kfree(map);
++      return NULL;
++}
 +
-+              p = m.arr;
-+              addr = m.addr;
-+              for (i = 0; i < nr_pages; i++, addr += PAGE_SIZE, p++) {
-+                      if (get_user(mfn, p)) {
-+                              up_write(&mm->mmap_sem);
-+                              return -EFAULT;
-+                      }
++/* Undo the result of the mapping */
++static void net_accel_unmap_grants_vfree(struct xenbus_device *dev, 
++                                       unsigned flags, void *priv)
++{
++      struct net_accel_valloc_grant_mapping *map = 
++              (struct net_accel_valloc_grant_mapping *)priv;
 +
-+                      ret = direct_remap_pfn_range(vma, addr & PAGE_MASK,
-+                                                   mfn, PAGE_SIZE,
-+                                                   vma->vm_page_prot, m.dom);
-+                      if (ret < 0)
-+                              put_user(0xF0000000 | mfn, p);
-+              }
++      void *addr = map->vm->addr;
++      int npages = map->pages;
++      int i;
 +
-+              up_write(&mm->mmap_sem);
-+              ret = 0;
++      for (i = 0; i < npages; i++) {
++              net_accel_unmap_grant(dev, map->grant_handles[i], addr, 0,
++                                    flags);
++              addr = (void*)((unsigned long)addr + PAGE_SIZE);
 +      }
-+      break;
++      free_vm_area(map->vm);
++      kfree(map);
++}
 +
-+      default:
-+              ret = -EINVAL;
-+              break;
-+      }
 +
-+      return ret;
++void *net_accel_map_grants_contig(struct xenbus_device *dev,
++                              unsigned *grants, int npages, 
++                              void **priv)
++{
++      return net_accel_map_grants_valloc(dev, grants, npages,
++                                         GNTMAP_host_map, priv);
 +}
++EXPORT_SYMBOL(net_accel_map_grants_contig);
 +
-+#ifndef HAVE_ARCH_PRIVCMD_MMAP
-+static struct page *privcmd_nopage(struct vm_area_struct *vma,
-+                                 unsigned long address,
-+                                 int *type)
++
++void net_accel_unmap_grants_contig(struct xenbus_device *dev,
++                                 void *priv)
 +{
-+      return NOPAGE_SIGBUS;
++      net_accel_unmap_grants_vfree(dev, GNTMAP_host_map, priv);
 +}
++EXPORT_SYMBOL(net_accel_unmap_grants_contig);
 +
-+static struct vm_operations_struct privcmd_vm_ops = {
-+      .nopage = privcmd_nopage
-+};
 +
-+static int privcmd_mmap(struct file * file, struct vm_area_struct * vma)
++void *net_accel_map_iomem_page(struct xenbus_device *dev, int gnt_ref,
++                           void **priv)
 +{
-+#ifndef __powerpc__ /* PowerPC has a trick to safely do this. */
-+      /* Unsupported for auto-translate guests. */
-+      if (xen_feature(XENFEAT_auto_translated_physmap))
-+              return -ENOSYS;
-+#endif
++      return net_accel_map_grants_valloc(dev, &gnt_ref, 1, 
++                                         GNTMAP_host_map, priv);
++}
++EXPORT_SYMBOL(net_accel_map_iomem_page);
 +
-+      /* DONTCOPY is essential for Xen as copy_page_range is broken. */
-+      vma->vm_flags |= VM_RESERVED | VM_IO | VM_DONTCOPY;
-+      vma->vm_ops = &privcmd_vm_ops;
-+      vma->vm_private_data = NULL;
 +
-+      return 0;
++void net_accel_unmap_iomem_page(struct xenbus_device *dev, void *priv)
++{
++      net_accel_unmap_grants_vfree(dev, GNTMAP_host_map, priv);
 +}
++EXPORT_SYMBOL(net_accel_unmap_iomem_page);
 +
-+static int privcmd_enforce_singleshot_mapping(struct vm_area_struct *vma)
++
++int net_accel_grant_page(struct xenbus_device *dev, unsigned long mfn, 
++                       int is_iomem)
 +{
-+      return (xchg(&vma->vm_private_data, (void *)1) == NULL);
++      int err = gnttab_grant_foreign_access(dev->otherend_id, mfn,
++                                            is_iomem ? GTF_PCD : 0);
++      if (err < 0)
++              xenbus_dev_error(dev, err, "failed granting access to page\n");
++      return err;
 +}
-+#endif
++EXPORT_SYMBOL_GPL(net_accel_grant_page);
 +
-+static const struct file_operations privcmd_file_ops = {
-+      .unlocked_ioctl = privcmd_ioctl,
-+      .mmap = privcmd_mmap,
-+};
 +
-+static int capabilities_read(char *page, char **start, off_t off,
-+                           int count, int *eof, void *data)
++int net_accel_ungrant_page(grant_ref_t gntref)
 +{
-+      int len = 0;
-+      *page = 0;
-+
-+      if (is_initial_xendomain())
-+              len = sprintf( page, "control_d\n" );
++      if (unlikely(gnttab_query_foreign_access(gntref) != 0)) {
++              EPRINTK("%s: remote domain still using grant %d\n", __FUNCTION__, 
++                      gntref);
++              return -EBUSY;
++      }
 +
-+      *eof = 1;
-+      return len;
++      gnttab_end_foreign_access(gntref, 0);
++      return 0;
 +}
++EXPORT_SYMBOL_GPL(net_accel_ungrant_page);
 +
-+static int __init privcmd_init(void)
++
++int net_accel_xen_net_read_mac(struct xenbus_device *dev, u8 mac[])
 +{
-+      if (!is_running_on_xen())
-+              return -ENODEV;
++      char *s, *e, *macstr;
++      int i;
 +
-+      privcmd_intf = create_xen_proc_entry("privcmd", 0400);
-+      if (privcmd_intf != NULL)
-+              privcmd_intf->proc_fops = &privcmd_file_ops;
++      macstr = s = xenbus_read(XBT_NIL, dev->nodename, "mac", NULL);
++      if (IS_ERR(macstr))
++              return PTR_ERR(macstr);
 +
-+      capabilities_intf = create_xen_proc_entry("capabilities", 0400 );
-+      if (capabilities_intf != NULL)
-+              capabilities_intf->read_proc = capabilities_read;
++      for (i = 0; i < ETH_ALEN; i++) {
++              mac[i] = simple_strtoul(s, &e, 16);
++              if ((s == e) || (*e != ((i == ETH_ALEN-1) ? '\0' : ':'))) {
++                      kfree(macstr);
++                      return -ENOENT;
++              }
++              s = e+1;
++      }
 +
++      kfree(macstr);
 +      return 0;
 +}
++EXPORT_SYMBOL_GPL(net_accel_xen_net_read_mac);
 +
-+__initcall(privcmd_init);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/tpmback/common.h linux-2.6.18-xen.hg/drivers/xen/tpmback/common.h
---- linux-2.6.18/drivers/xen/tpmback/common.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/tpmback/common.h   2007-12-23 11:15:34.247945758 +0100
++
++void net_accel_update_state(struct xenbus_device *dev, int state)
++{
++      struct xenbus_transaction tr;
++      int err;
++
++      DPRINTK("%s: setting accelstate to %s\n", __FUNCTION__,
++              xenbus_strstate(state));
++
++      if (xenbus_exists(XBT_NIL, dev->nodename, "")) {
++              VPRINTK("%s: nodename %s\n", __FUNCTION__, dev->nodename);
++      again:
++              err = xenbus_transaction_start(&tr);
++              if (err == 0)
++                      err = xenbus_printf(tr, dev->nodename, "accelstate",
++                                          "%d", state);
++              if (err != 0) {
++                      xenbus_transaction_end(tr, 1);
++              } else {
++                      err = xenbus_transaction_end(tr, 0);
++                      if (err == -EAGAIN)
++                              goto again;
++              }
++      }
++}
++EXPORT_SYMBOL_GPL(net_accel_update_state);
++
++MODULE_LICENSE("GPL");
+--- linux-2.6.18.8/drivers/xen/sfc_netutil/accel_util.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/sfc_netutil/accel_util.h   2008-05-19 00:33:48.746955951 +0300
+@@ -0,0 +1,127 @@
++/****************************************************************************
++ * Solarflare driver for Xen network acceleration
++ *
++ * Copyright 2006-2008: Solarflare Communications Inc,
++ *                      9501 Jeronimo Road, Suite 250,
++ *                      Irvine, CA 92618, USA
++ *
++ * Maintained by Solarflare Communications <linux-xen-drivers@solarflare.com>
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License version 2 as published
++ * by the Free Software Foundation, incorporated herein by reference.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
++ ****************************************************************************
++ */
++
++#ifndef NETBACK_ACCEL_UTIL_H
++#define NETBACK_ACCEL_UTIL_H
++
++#ifdef DPRINTK
++#undef DPRINTK
++#endif
++
++#define FILE_LEAF strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__
++
++#if 1
++#define VPRINTK(_f, _a...) 
++#else
++#define VPRINTK(_f, _a...)                    \
++      printk("(file=%s, line=%d) " _f,        \
++             FILE_LEAF , __LINE__ , ## _a )
++#endif
++
++#if 1
++#define DPRINTK(_f, _a...) 
++#else
++#define DPRINTK(_f, _a...)                    \
++      printk("(file=%s, line=%d) " _f,        \
++             FILE_LEAF , __LINE__ , ## _a )
++#endif
++
++#define EPRINTK(_f, _a...)                    \
++      printk("(file=%s, line=%d) " _f,        \
++             FILE_LEAF , __LINE__ , ## _a )
++
++#define EPRINTK_ON(exp)                                                       \
++      do {                                                            \
++              if (exp)                                                \
++                      EPRINTK("%s at %s:%d\n", #exp, __FILE__, __LINE__); \
++      } while(0)
++
++#define DPRINTK_ON(exp)                                                       \
++      do {                                                            \
++              if (exp)                                                \
++                      DPRINTK("%s at %s:%d\n", #exp, __FILE__, __LINE__); \
++      } while(0)
++
++#define MAC_FMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
++#define MAC_ARG(_mac) (_mac)[0], (_mac)[1], (_mac)[2], (_mac)[3], (_mac)[4], (_mac)[5]
++
++#include <xen/xenbus.h>
++
++/*! Map a set of pages from another domain
++ * \param dev The xenbus device context
++ * \param priv The private data returned by the mapping function 
++ */
++extern 
++void *net_accel_map_grants_contig(struct xenbus_device *dev, 
++                                unsigned *grants, int npages, 
++                                void **priv);
++
++/*! Unmap a set of pages mapped using net_accel_map_grants_contig.
++ * \param dev The xenbus device context
++ * \param priv The private data returned by the mapping function 
++ */
++extern 
++void net_accel_unmap_grants_contig(struct xenbus_device *dev, void *priv);
++
++/*! Read the MAC address of a device from xenstore */
++extern
++int net_accel_xen_net_read_mac(struct xenbus_device *dev, u8 mac[]);
++
++/*! Update the accelstate field for a device in xenstore */
++extern
++void net_accel_update_state(struct xenbus_device *dev, int state);
++
++/* These four map/unmap functions are based on
++ * xenbus_backend_client.c:xenbus_map_ring().  However, they are not
++ * used for ring buffers, instead just to map pages between domains,
++ * or to map a page so that it is accessible by a device
++ */
++extern
++int net_accel_map_device_page(struct xenbus_device *dev,  
++                            int gnt_ref, grant_handle_t *handle,
++                            u64 *dev_bus_addr);
++extern
++int net_accel_unmap_device_page(struct xenbus_device *dev,
++                              grant_handle_t handle, u64 dev_bus_addr);
++extern
++void *net_accel_map_iomem_page(struct xenbus_device *dev, int gnt_ref,
++                           void **priv);
++extern
++void net_accel_unmap_iomem_page(struct xenbus_device *dev, void *priv);
++
++/*! Grrant a page to remote domain */
++extern
++int net_accel_grant_page(struct xenbus_device *dev, unsigned long mfn, 
++                       int is_iomem);
++/*! Undo a net_accel_grant_page */
++extern
++int net_accel_ungrant_page(grant_ref_t gntref);
++
++
++/*! Shutdown remote domain that is misbehaving */
++extern
++int net_accel_shutdown_remote(int domain);
++
++
++#endif
+--- linux-2.6.18.8/drivers/xen/tpmback/Makefile        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/tpmback/Makefile   2008-05-19 00:33:48.746955951 +0300
+@@ -0,0 +1,4 @@
++
++obj-$(CONFIG_XEN_TPMDEV_BACKEND)      += tpmbk.o
++
++tpmbk-y += tpmback.o interface.o xenbus.o
+--- linux-2.6.18.8/drivers/xen/tpmback/common.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/tpmback/common.h   2008-05-19 00:33:48.746955951 +0300
 @@ -0,0 +1,85 @@
 +/******************************************************************************
 + * drivers/xen/tpmback/common.h
@@ -102597,10 +167162,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/tpmback/comm
 +}
 +
 +#endif /* __TPMIF__BACKEND__COMMON_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/tpmback/interface.c linux-2.6.18-xen.hg/drivers/xen/tpmback/interface.c
---- linux-2.6.18/drivers/xen/tpmback/interface.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/tpmback/interface.c        2007-12-23 11:15:34.247945758 +0100
-@@ -0,0 +1,167 @@
+--- linux-2.6.18.8/drivers/xen/tpmback/interface.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/tpmback/interface.c        2008-05-19 00:33:48.746955951 +0300
+@@ -0,0 +1,168 @@
 + /*****************************************************************************
 + * drivers/xen/tpmback/interface.c
 + *
@@ -102729,6 +167293,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/tpmback/inte
 +      }
 +
 +      tpmif->tx = (tpmif_tx_interface_t *)tpmif->tx_area->addr;
++      memset(tpmif->tx, 0, PAGE_SIZE);
 +
 +      err = bind_interdomain_evtchn_to_irqhandler(
 +              tpmif->domid, evtchn, tpmif_be_int, 0, tpmif->devname, tpmif);
@@ -102768,17 +167333,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/tpmback/inte
 +{
 +      kmem_cache_destroy(tpmif_cachep);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/tpmback/Makefile linux-2.6.18-xen.hg/drivers/xen/tpmback/Makefile
---- linux-2.6.18/drivers/xen/tpmback/Makefile  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/tpmback/Makefile   2007-12-23 11:15:34.247945758 +0100
-@@ -0,0 +1,4 @@
-+
-+obj-$(CONFIG_XEN_TPMDEV_BACKEND)      += tpmbk.o
-+
-+tpmbk-y += tpmback.o interface.o xenbus.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/tpmback/tpmback.c linux-2.6.18-xen.hg/drivers/xen/tpmback/tpmback.c
---- linux-2.6.18/drivers/xen/tpmback/tpmback.c 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/tpmback/tpmback.c  2007-12-23 11:15:34.247945758 +0100
+--- linux-2.6.18.8/drivers/xen/tpmback/tpmback.c       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/tpmback/tpmback.c  2008-05-19 00:33:48.750956181 +0300
 @@ -0,0 +1,944 @@
 +/******************************************************************************
 + * drivers/xen/tpmback/tpmback.c
@@ -103724,9 +168280,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/tpmback/tpmb
 +}
 +
 +MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/tpmback/xenbus.c linux-2.6.18-xen.hg/drivers/xen/tpmback/xenbus.c
---- linux-2.6.18/drivers/xen/tpmback/xenbus.c  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/tpmback/xenbus.c   2007-12-23 11:15:34.247945758 +0100
+--- linux-2.6.18.8/drivers/xen/tpmback/xenbus.c        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/tpmback/xenbus.c   2008-05-19 00:33:48.750956181 +0300
 @@ -0,0 +1,289 @@
 +/*  Xenbus code for tpmif backend
 +    Copyright (C) 2005 IBM Corporation
@@ -103992,7 +168547,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/tpmback/xenb
 +}
 +
 +
-+static struct xenbus_device_id tpmback_ids[] = {
++static const struct xenbus_device_id tpmback_ids[] = {
 +      { "vtpm" },
 +      { "" }
 +};
@@ -104017,9 +168572,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/tpmback/xenb
 +{
 +      xenbus_unregister_driver(&tpmback);
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/util.c linux-2.6.18-xen.hg/drivers/xen/util.c
---- linux-2.6.18/drivers/xen/util.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/util.c     2007-12-23 11:15:34.247945758 +0100
+--- linux-2.6.18.8/drivers/xen/util.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/util.c     2008-05-19 00:33:48.750956181 +0300
 @@ -0,0 +1,65 @@
 +#include <linux/mm.h>
 +#include <linux/module.h>
@@ -104086,9 +168640,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/util.c linux
 +}
 +EXPORT_SYMBOL_GPL(free_vm_area);
 +#endif /* CONFIG_X86 */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/Makefile linux-2.6.18-xen.hg/drivers/xen/xenbus/Makefile
---- linux-2.6.18/drivers/xen/xenbus/Makefile   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/xenbus/Makefile    2007-12-23 11:15:34.251279267 +0100
+--- linux-2.6.18.8/drivers/xen/xenbus/Makefile 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/xenbus/Makefile    2008-05-19 00:33:48.750956181 +0300
 @@ -0,0 +1,9 @@
 +obj-y += xenbus_client.o xenbus_comms.o xenbus_xs.o xenbus_probe.o
 +obj-$(CONFIG_XEN_BACKEND) += xenbus_be.o
@@ -104099,9 +168652,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/Makef
 +xenbus-$(CONFIG_XEN_BACKEND) += xenbus_probe_backend.o
 +obj-y += $(xenbus-y) $(xenbus-m)
 +obj-$(CONFIG_XEN_XENBUS_DEV) += xenbus_dev.o
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbus_backend_client.c linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_backend_client.c
---- linux-2.6.18/drivers/xen/xenbus/xenbus_backend_client.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_backend_client.c     2007-12-23 11:15:34.251279267 +0100
+--- linux-2.6.18.8/drivers/xen/xenbus/xenbus_backend_client.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_backend_client.c     2008-05-19 00:33:48.754956412 +0300
 @@ -0,0 +1,147 @@
 +/******************************************************************************
 + * Backend-client-facing interface for the Xenbus driver.  In other words, the
@@ -104250,9 +168802,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +EXPORT_SYMBOL_GPL(xenbus_dev_is_online);
 +
 +MODULE_LICENSE("Dual BSD/GPL");
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbus_client.c linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_client.c
---- linux-2.6.18/drivers/xen/xenbus/xenbus_client.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_client.c     2007-12-23 11:15:34.251279267 +0100
+--- linux-2.6.18.8/drivers/xen/xenbus/xenbus_client.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_client.c     2008-05-19 00:33:48.754956412 +0300
 @@ -0,0 +1,284 @@
 +/******************************************************************************
 + * Client-facing interface for the Xenbus driver.  In other words, the
@@ -104343,7 +168894,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +                                      const char **, unsigned int))
 +{
 +      int err;
-+      char *state = kasprintf(GFP_KERNEL, "%s/%s", path, path2);
++      char *state = kasprintf(GFP_KERNEL|__GFP_HIGH, "%s/%s", path, path2);
 +      if (!state) {
 +              xenbus_dev_fatal(dev, -ENOMEM, "allocating path for watch");
 +              return -ENOMEM;
@@ -104538,9 +169089,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +      return result;
 +}
 +EXPORT_SYMBOL_GPL(xenbus_read_driver_state);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbus_comms.c linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_comms.c
---- linux-2.6.18/drivers/xen/xenbus/xenbus_comms.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_comms.c      2007-12-23 11:15:34.251279267 +0100
+--- linux-2.6.18.8/drivers/xen/xenbus/xenbus_comms.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_comms.c      2008-05-19 00:33:48.754956412 +0300
 @@ -0,0 +1,233 @@
 +/******************************************************************************
 + * xenbus_comms.c
@@ -104775,9 +169325,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +
 +      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbus_comms.h linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_comms.h
---- linux-2.6.18/drivers/xen/xenbus/xenbus_comms.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_comms.h      2007-12-23 11:15:34.251279267 +0100
+--- linux-2.6.18.8/drivers/xen/xenbus/xenbus_comms.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_comms.h      2008-05-19 00:33:48.754956412 +0300
 @@ -0,0 +1,46 @@
 +/*
 + * Private include for xenbus communications.
@@ -104825,9 +169374,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +extern int xen_store_evtchn;
 +
 +#endif /* _XENBUS_COMMS_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbus_dev.c linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_dev.c
---- linux-2.6.18/drivers/xen/xenbus/xenbus_dev.c       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_dev.c        2007-12-23 11:15:34.251279267 +0100
+--- linux-2.6.18.8/drivers/xen/xenbus/xenbus_dev.c     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_dev.c        2008-05-19 00:33:48.758956642 +0300
 @@ -0,0 +1,404 @@
 +/*
 + * xenbus_dev.c
@@ -105109,7 +169657,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +              token++;
 +
 +              if (msg_type == XS_WATCH) {
-+                      watch = kmalloc(sizeof(*watch), GFP_KERNEL);
++                      watch = kzalloc(sizeof(*watch), GFP_KERNEL);
 +                      watch->watch.node = kmalloc(strlen(path)+1,
 +                                                    GFP_KERNEL);
 +                      strcpy((char *)watch->watch.node, path);
@@ -105233,307 +169781,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +
 +      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbus_probe_backend.c linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_probe_backend.c
---- linux-2.6.18/drivers/xen/xenbus/xenbus_probe_backend.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_probe_backend.c      2007-12-23 11:15:34.254612776 +0100
-@@ -0,0 +1,293 @@
-+/******************************************************************************
-+ * Talks to Xen Store to figure out what devices we have (backend half).
-+ *
-+ * Copyright (C) 2005 Rusty Russell, IBM Corporation
-+ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
-+ * Copyright (C) 2005, 2006 XenSource Ltd
-+ * Copyright (C) 2007 Solarflare Communications, Inc.
-+ * 
-+ * This program is free software; you can redistribute it and/or
-+ * modify it under the terms of the GNU General Public License version 2
-+ * as published by the Free Software Foundation; or, when distributed
-+ * separately from the Linux kernel or incorporated into other
-+ * software packages, subject to the following license:
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this source file (the "Software"), to deal in the Software without
-+ * restriction, including without limitation the rights to use, copy, modify,
-+ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
-+ * and to permit persons to whom the Software is furnished to do so, subject to
-+ * the following conditions:
-+ * 
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ * 
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-+ * IN THE SOFTWARE.
-+ */
-+
-+#define DPRINTK(fmt, args...)                         \
-+      pr_debug("xenbus_probe (%s:%d) " fmt ".\n",     \
-+               __FUNCTION__, __LINE__, ##args)
-+
-+#include <linux/kernel.h>
-+#include <linux/err.h>
-+#include <linux/string.h>
-+#include <linux/ctype.h>
-+#include <linux/fcntl.h>
-+#include <linux/mm.h>
-+#include <linux/notifier.h>
-+
-+#include <asm/io.h>
-+#include <asm/page.h>
-+#include <asm/maddr.h>
-+#include <asm/pgtable.h>
-+#include <asm/hypervisor.h>
-+#include <xen/xenbus.h>
-+#include <xen/xen_proc.h>
-+#include <xen/evtchn.h>
-+#include <xen/features.h>
-+#include <xen/hvm.h>
-+
-+#include "xenbus_comms.h"
-+#include "xenbus_probe.h"
-+
-+#ifdef HAVE_XEN_PLATFORM_COMPAT_H
-+#include <xen/platform-compat.h>
-+#endif
-+
-+static int xenbus_uevent_backend(struct device *dev, char **envp,
-+                               int num_envp, char *buffer, int buffer_size);
-+static int xenbus_probe_backend(const char *type, const char *domid);
-+
-+extern int read_otherend_details(struct xenbus_device *xendev,
-+                               char *id_node, char *path_node);
-+
-+static int read_frontend_details(struct xenbus_device *xendev)
-+{
-+      return read_otherend_details(xendev, "frontend-id", "frontend");
-+}
-+
-+/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
-+static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
-+{
-+      int domid, err;
-+      const char *devid, *type, *frontend;
-+      unsigned int typelen;
-+
-+      type = strchr(nodename, '/');
-+      if (!type)
-+              return -EINVAL;
-+      type++;
-+      typelen = strcspn(type, "/");
-+      if (!typelen || type[typelen] != '/')
-+              return -EINVAL;
-+
-+      devid = strrchr(nodename, '/') + 1;
-+
-+      err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
-+                          "frontend", NULL, &frontend,
-+                          NULL);
-+      if (err)
-+              return err;
-+      if (strlen(frontend) == 0)
-+              err = -ERANGE;
-+      if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
-+              err = -ENOENT;
-+      kfree(frontend);
-+
-+      if (err)
-+              return err;
-+
-+      if (snprintf(bus_id, BUS_ID_SIZE,
-+                   "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
-+              return -ENOSPC;
-+      return 0;
-+}
-+
-+static struct xen_bus_type xenbus_backend = {
-+      .root = "backend",
-+      .levels = 3,            /* backend/type/<frontend>/<id> */
-+      .get_bus_id = backend_bus_id,
-+      .probe = xenbus_probe_backend,
-+      .error = -ENODEV,
-+      .bus = {
-+              .name     = "xen-backend",
-+              .match    = xenbus_match,
-+              .probe    = xenbus_dev_probe,
-+              .remove   = xenbus_dev_remove,
-+//            .shutdown = xenbus_dev_shutdown,
-+              .uevent   = xenbus_uevent_backend,
-+      },
-+      .dev = {
-+              .bus_id = "xen-backend",
-+      },
-+};
-+
-+static int xenbus_uevent_backend(struct device *dev, char **envp,
-+                               int num_envp, char *buffer, int buffer_size)
-+{
-+      struct xenbus_device *xdev;
-+      struct xenbus_driver *drv;
-+      int i = 0;
-+      int length = 0;
-+
-+      DPRINTK("");
-+
-+      if (dev == NULL)
-+              return -ENODEV;
-+
-+      xdev = to_xenbus_device(dev);
-+      if (xdev == NULL)
-+              return -ENODEV;
-+
-+      /* stuff we want to pass to /sbin/hotplug */
-+      add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-+                     "XENBUS_TYPE=%s", xdev->devicetype);
-+
-+      add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-+                     "XENBUS_PATH=%s", xdev->nodename);
-+
-+      add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
-+                     "XENBUS_BASE_PATH=%s", xenbus_backend.root);
-+
-+      /* terminate, set to next free slot, shrink available space */
-+      envp[i] = NULL;
-+      envp = &envp[i];
-+      num_envp -= i;
-+      buffer = &buffer[length];
-+      buffer_size -= length;
-+
-+      if (dev->driver) {
-+              drv = to_xenbus_driver(dev->driver);
-+              if (drv && drv->uevent)
-+                      return drv->uevent(xdev, envp, num_envp, buffer,
-+                                         buffer_size);
-+      }
-+
-+      return 0;
-+}
-+
-+int xenbus_register_backend(struct xenbus_driver *drv)
-+{
-+      drv->read_otherend_details = read_frontend_details;
-+
-+      return xenbus_register_driver_common(drv, &xenbus_backend);
-+}
-+EXPORT_SYMBOL_GPL(xenbus_register_backend);
-+
-+/* backend/<typename>/<frontend-uuid>/<name> */
-+static int xenbus_probe_backend_unit(const char *dir,
-+                                   const char *type,
-+                                   const char *name)
-+{
-+      char *nodename;
-+      int err;
-+
-+      nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
-+      if (!nodename)
-+              return -ENOMEM;
-+
-+      DPRINTK("%s\n", nodename);
-+
-+      err = xenbus_probe_node(&xenbus_backend, type, nodename);
-+      kfree(nodename);
-+      return err;
-+}
-+
-+/* backend/<typename>/<frontend-domid> */
-+static int xenbus_probe_backend(const char *type, const char *domid)
-+{
-+      char *nodename;
-+      int err = 0;
-+      char **dir;
-+      unsigned int i, dir_n = 0;
-+
-+      DPRINTK("");
-+
-+      nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_backend.root, type, domid);
-+      if (!nodename)
-+              return -ENOMEM;
-+
-+      dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
-+      if (IS_ERR(dir)) {
-+              kfree(nodename);
-+              return PTR_ERR(dir);
-+      }
-+
-+      for (i = 0; i < dir_n; i++) {
-+              err = xenbus_probe_backend_unit(nodename, type, dir[i]);
-+              if (err)
-+                      break;
-+      }
-+      kfree(dir);
-+      kfree(nodename);
-+      return err;
-+}
-+
-+static void backend_changed(struct xenbus_watch *watch,
-+                          const char **vec, unsigned int len)
-+{
-+      DPRINTK("");
-+
-+      dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
-+}
-+
-+static struct xenbus_watch be_watch = {
-+      .node = "backend",
-+      .callback = backend_changed,
-+};
-+
-+void xenbus_backend_suspend(int (*fn)(struct device *, void *))
-+{
-+      DPRINTK("");
-+      if (!xenbus_backend.error)
-+              bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
-+}
-+
-+void xenbus_backend_resume(int (*fn)(struct device *, void *))
-+{
-+      DPRINTK("");
-+      if (!xenbus_backend.error)
-+              bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
-+}
-+
-+void xenbus_backend_probe_and_watch(void)
-+{
-+      xenbus_probe_devices(&xenbus_backend);
-+      register_xenbus_watch(&be_watch);
-+}
-+
-+void xenbus_backend_bus_register(void)
-+{
-+      xenbus_backend.error = bus_register(&xenbus_backend.bus);
-+      if (xenbus_backend.error)
-+              printk(KERN_WARNING
-+                     "XENBUS: Error registering backend bus: %i\n",
-+                     xenbus_backend.error);
-+}
-+
-+void xenbus_backend_device_register(void)
-+{
-+      if (xenbus_backend.error)
-+              return;
-+
-+      xenbus_backend.error = device_register(&xenbus_backend.dev);
-+      if (xenbus_backend.error) {
-+              bus_unregister(&xenbus_backend.bus);
-+              printk(KERN_WARNING
-+                     "XENBUS: Error registering backend device: %i\n",
-+                     xenbus_backend.error);
-+      }
-+}
-+
-+int xenbus_for_each_backend(void *arg, int (*fn)(struct device *, void *))
-+{
-+      return bus_for_each_dev(&xenbus_backend.bus, NULL, arg, fn);
-+}
-+EXPORT_SYMBOL_GPL(xenbus_for_each_backend);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbus_probe.c linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_probe.c
---- linux-2.6.18/drivers/xen/xenbus/xenbus_probe.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_probe.c      2007-12-23 11:15:34.254612776 +0100
-@@ -0,0 +1,1148 @@
+--- linux-2.6.18.8/drivers/xen/xenbus/xenbus_probe.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_probe.c      2008-05-19 00:33:48.758956642 +0300
+@@ -0,0 +1,1153 @@
 +/******************************************************************************
 + * Talks to Xen Store to figure out what devices we have.
 + *
@@ -105590,7 +169840,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +#include <xen/xen_proc.h>
 +#include <xen/evtchn.h>
 +#include <xen/features.h>
++#ifdef MODULE
 +#include <xen/hvm.h>
++#endif
 +
 +#include "xenbus_comms.h"
 +#include "xenbus_probe.h"
@@ -105881,6 +170133,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +
 +      DPRINTK("%s", dev->nodename);
 +
++      if (is_initial_xendomain())
++              return;
++
 +      get_device(&dev->dev);
 +      if (dev->state != XenbusStateConnected) {
 +              printk("%s: %s: %s != Connected, skipping\n", __FUNCTION__,
@@ -106682,9 +170937,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +      return bus_for_each_dev(&xenbus_frontend.bus, NULL, arg, fn);
 +}
 +EXPORT_SYMBOL_GPL(xenbus_for_each_frontend);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbus_probe.h linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_probe.h
---- linux-2.6.18/drivers/xen/xenbus/xenbus_probe.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_probe.h      2007-12-23 11:15:34.254612776 +0100
+--- linux-2.6.18.8/drivers/xen/xenbus/xenbus_probe.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_probe.h      2008-05-19 00:33:48.758956642 +0300
 @@ -0,0 +1,75 @@
 +/******************************************************************************
 + * xenbus_probe.h
@@ -106719,52 +170973,346 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 + * IN THE SOFTWARE.
 + */
 +
-+#ifndef _XENBUS_PROBE_H
-+#define _XENBUS_PROBE_H
++#ifndef _XENBUS_PROBE_H
++#define _XENBUS_PROBE_H
++
++#if defined(CONFIG_XEN_BACKEND) || defined(CONFIG_XEN_BACKEND_MODULE)
++extern void xenbus_backend_suspend(int (*fn)(struct device *, void *));
++extern void xenbus_backend_resume(int (*fn)(struct device *, void *));
++extern void xenbus_backend_probe_and_watch(void);
++extern void xenbus_backend_bus_register(void);
++extern void xenbus_backend_device_register(void);
++#else
++static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {}
++static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {}
++static inline void xenbus_backend_probe_and_watch(void) {}
++static inline void xenbus_backend_bus_register(void) {}
++static inline void xenbus_backend_device_register(void) {}
++#endif
++
++struct xen_bus_type
++{
++      char *root;
++      int error;
++      unsigned int levels;
++      int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
++      int (*probe)(const char *type, const char *dir);
++      struct bus_type bus;
++      struct device dev;
++};
++
++extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
++extern int xenbus_dev_probe(struct device *_dev);
++extern int xenbus_dev_remove(struct device *_dev);
++extern int xenbus_register_driver_common(struct xenbus_driver *drv,
++                                       struct xen_bus_type *bus);
++extern int xenbus_probe_node(struct xen_bus_type *bus,
++                           const char *type,
++                           const char *nodename);
++extern int xenbus_probe_devices(struct xen_bus_type *bus);
++
++extern void dev_changed(const char *node, struct xen_bus_type *bus);
++
++#endif
++
+--- linux-2.6.18.8/drivers/xen/xenbus/xenbus_probe_backend.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_probe_backend.c      2008-05-19 00:33:48.762956873 +0300
+@@ -0,0 +1,292 @@
++/******************************************************************************
++ * Talks to Xen Store to figure out what devices we have (backend half).
++ *
++ * Copyright (C) 2005 Rusty Russell, IBM Corporation
++ * Copyright (C) 2005 Mike Wray, Hewlett-Packard
++ * Copyright (C) 2005, 2006 XenSource Ltd
++ * Copyright (C) 2007 Solarflare Communications, Inc.
++ * 
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License version 2
++ * as published by the Free Software Foundation; or, when distributed
++ * separately from the Linux kernel or incorporated into other
++ * software packages, subject to the following license:
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this source file (the "Software"), to deal in the Software without
++ * restriction, including without limitation the rights to use, copy, modify,
++ * merge, publish, distribute, sublicense, and/or sell copies of the Software,
++ * and to permit persons to whom the Software is furnished to do so, subject to
++ * the following conditions:
++ * 
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ * 
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
++ * IN THE SOFTWARE.
++ */
++
++#define DPRINTK(fmt, args...)                         \
++      pr_debug("xenbus_probe (%s:%d) " fmt ".\n",     \
++               __FUNCTION__, __LINE__, ##args)
 +
-+#if defined(CONFIG_XEN_BACKEND) || defined(CONFIG_XEN_BACKEND_MODULE)
-+extern void xenbus_backend_suspend(int (*fn)(struct device *, void *));
-+extern void xenbus_backend_resume(int (*fn)(struct device *, void *));
-+extern void xenbus_backend_probe_and_watch(void);
-+extern void xenbus_backend_bus_register(void);
-+extern void xenbus_backend_device_register(void);
-+#else
-+static inline void xenbus_backend_suspend(int (*fn)(struct device *, void *)) {}
-+static inline void xenbus_backend_resume(int (*fn)(struct device *, void *)) {}
-+static inline void xenbus_backend_probe_and_watch(void) {}
-+static inline void xenbus_backend_bus_register(void) {}
-+static inline void xenbus_backend_device_register(void) {}
++#include <linux/kernel.h>
++#include <linux/err.h>
++#include <linux/string.h>
++#include <linux/ctype.h>
++#include <linux/fcntl.h>
++#include <linux/mm.h>
++#include <linux/notifier.h>
++
++#include <asm/io.h>
++#include <asm/page.h>
++#include <asm/maddr.h>
++#include <asm/pgtable.h>
++#include <asm/hypervisor.h>
++#include <xen/xenbus.h>
++#include <xen/xen_proc.h>
++#include <xen/evtchn.h>
++#include <xen/features.h>
++
++#include "xenbus_comms.h"
++#include "xenbus_probe.h"
++
++#ifdef HAVE_XEN_PLATFORM_COMPAT_H
++#include <xen/platform-compat.h>
 +#endif
 +
-+struct xen_bus_type
++static int xenbus_uevent_backend(struct device *dev, char **envp,
++                               int num_envp, char *buffer, int buffer_size);
++static int xenbus_probe_backend(const char *type, const char *domid);
++
++extern int read_otherend_details(struct xenbus_device *xendev,
++                               char *id_node, char *path_node);
++
++static int read_frontend_details(struct xenbus_device *xendev)
 +{
-+      char *root;
-+      int error;
-+      unsigned int levels;
-+      int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
-+      int (*probe)(const char *type, const char *dir);
-+      struct bus_type bus;
-+      struct device dev;
++      return read_otherend_details(xendev, "frontend-id", "frontend");
++}
++
++/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
++static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
++{
++      int domid, err;
++      const char *devid, *type, *frontend;
++      unsigned int typelen;
++
++      type = strchr(nodename, '/');
++      if (!type)
++              return -EINVAL;
++      type++;
++      typelen = strcspn(type, "/");
++      if (!typelen || type[typelen] != '/')
++              return -EINVAL;
++
++      devid = strrchr(nodename, '/') + 1;
++
++      err = xenbus_gather(XBT_NIL, nodename, "frontend-id", "%i", &domid,
++                          "frontend", NULL, &frontend,
++                          NULL);
++      if (err)
++              return err;
++      if (strlen(frontend) == 0)
++              err = -ERANGE;
++      if (!err && !xenbus_exists(XBT_NIL, frontend, ""))
++              err = -ENOENT;
++      kfree(frontend);
++
++      if (err)
++              return err;
++
++      if (snprintf(bus_id, BUS_ID_SIZE,
++                   "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
++              return -ENOSPC;
++      return 0;
++}
++
++static struct xen_bus_type xenbus_backend = {
++      .root = "backend",
++      .levels = 3,            /* backend/type/<frontend>/<id> */
++      .get_bus_id = backend_bus_id,
++      .probe = xenbus_probe_backend,
++      .error = -ENODEV,
++      .bus = {
++              .name     = "xen-backend",
++              .match    = xenbus_match,
++              .probe    = xenbus_dev_probe,
++              .remove   = xenbus_dev_remove,
++//            .shutdown = xenbus_dev_shutdown,
++              .uevent   = xenbus_uevent_backend,
++      },
++      .dev = {
++              .bus_id = "xen-backend",
++      },
 +};
 +
-+extern int xenbus_match(struct device *_dev, struct device_driver *_drv);
-+extern int xenbus_dev_probe(struct device *_dev);
-+extern int xenbus_dev_remove(struct device *_dev);
-+extern int xenbus_register_driver_common(struct xenbus_driver *drv,
-+                                       struct xen_bus_type *bus);
-+extern int xenbus_probe_node(struct xen_bus_type *bus,
-+                           const char *type,
-+                           const char *nodename);
-+extern int xenbus_probe_devices(struct xen_bus_type *bus);
++static int xenbus_uevent_backend(struct device *dev, char **envp,
++                               int num_envp, char *buffer, int buffer_size)
++{
++      struct xenbus_device *xdev;
++      struct xenbus_driver *drv;
++      int i = 0;
++      int length = 0;
 +
-+extern void dev_changed(const char *node, struct xen_bus_type *bus);
++      DPRINTK("");
 +
-+#endif
++      if (dev == NULL)
++              return -ENODEV;
++
++      xdev = to_xenbus_device(dev);
++      if (xdev == NULL)
++              return -ENODEV;
++
++      /* stuff we want to pass to /sbin/hotplug */
++      add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++                     "XENBUS_TYPE=%s", xdev->devicetype);
++
++      add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++                     "XENBUS_PATH=%s", xdev->nodename);
++
++      add_uevent_var(envp, num_envp, &i, buffer, buffer_size, &length,
++                     "XENBUS_BASE_PATH=%s", xenbus_backend.root);
++
++      /* terminate, set to next free slot, shrink available space */
++      envp[i] = NULL;
++      envp = &envp[i];
++      num_envp -= i;
++      buffer = &buffer[length];
++      buffer_size -= length;
++
++      if (dev->driver) {
++              drv = to_xenbus_driver(dev->driver);
++              if (drv && drv->uevent)
++                      return drv->uevent(xdev, envp, num_envp, buffer,
++                                         buffer_size);
++      }
++
++      return 0;
++}
++
++int xenbus_register_backend(struct xenbus_driver *drv)
++{
++      drv->read_otherend_details = read_frontend_details;
++
++      return xenbus_register_driver_common(drv, &xenbus_backend);
++}
++EXPORT_SYMBOL_GPL(xenbus_register_backend);
++
++/* backend/<typename>/<frontend-uuid>/<name> */
++static int xenbus_probe_backend_unit(const char *dir,
++                                   const char *type,
++                                   const char *name)
++{
++      char *nodename;
++      int err;
++
++      nodename = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
++      if (!nodename)
++              return -ENOMEM;
++
++      DPRINTK("%s\n", nodename);
++
++      err = xenbus_probe_node(&xenbus_backend, type, nodename);
++      kfree(nodename);
++      return err;
++}
++
++/* backend/<typename>/<frontend-domid> */
++static int xenbus_probe_backend(const char *type, const char *domid)
++{
++      char *nodename;
++      int err = 0;
++      char **dir;
++      unsigned int i, dir_n = 0;
++
++      DPRINTK("");
++
++      nodename = kasprintf(GFP_KERNEL, "%s/%s/%s", xenbus_backend.root, type, domid);
++      if (!nodename)
++              return -ENOMEM;
++
++      dir = xenbus_directory(XBT_NIL, nodename, "", &dir_n);
++      if (IS_ERR(dir)) {
++              kfree(nodename);
++              return PTR_ERR(dir);
++      }
++
++      for (i = 0; i < dir_n; i++) {
++              err = xenbus_probe_backend_unit(nodename, type, dir[i]);
++              if (err)
++                      break;
++      }
++      kfree(dir);
++      kfree(nodename);
++      return err;
++}
++
++static void backend_changed(struct xenbus_watch *watch,
++                          const char **vec, unsigned int len)
++{
++      DPRINTK("");
++
++      dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
++}
++
++static struct xenbus_watch be_watch = {
++      .node = "backend",
++      .callback = backend_changed,
++};
++
++void xenbus_backend_suspend(int (*fn)(struct device *, void *))
++{
++      DPRINTK("");
++      if (!xenbus_backend.error)
++              bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
++}
++
++void xenbus_backend_resume(int (*fn)(struct device *, void *))
++{
++      DPRINTK("");
++      if (!xenbus_backend.error)
++              bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, fn);
++}
++
++void xenbus_backend_probe_and_watch(void)
++{
++      xenbus_probe_devices(&xenbus_backend);
++      register_xenbus_watch(&be_watch);
++}
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbus_xs.c linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_xs.c
---- linux-2.6.18/drivers/xen/xenbus/xenbus_xs.c        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_xs.c 2007-12-23 11:15:34.254612776 +0100
-@@ -0,0 +1,886 @@
++void xenbus_backend_bus_register(void)
++{
++      xenbus_backend.error = bus_register(&xenbus_backend.bus);
++      if (xenbus_backend.error)
++              printk(KERN_WARNING
++                     "XENBUS: Error registering backend bus: %i\n",
++                     xenbus_backend.error);
++}
++
++void xenbus_backend_device_register(void)
++{
++      if (xenbus_backend.error)
++              return;
++
++      xenbus_backend.error = device_register(&xenbus_backend.dev);
++      if (xenbus_backend.error) {
++              bus_unregister(&xenbus_backend.bus);
++              printk(KERN_WARNING
++                     "XENBUS: Error registering backend device: %i\n",
++                     xenbus_backend.error);
++      }
++}
++
++int xenbus_for_each_backend(void *arg, int (*fn)(struct device *, void *))
++{
++      return bus_for_each_dev(&xenbus_backend.bus, NULL, arg, fn);
++}
++EXPORT_SYMBOL_GPL(xenbus_for_each_backend);
+--- linux-2.6.18.8/drivers/xen/xenbus/xenbus_xs.c      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/xenbus/xenbus_xs.c 2008-05-19 00:33:48.782958026 +0300
+@@ -0,0 +1,901 @@
 +/******************************************************************************
 + * xenbus_xs.c
 + *
@@ -107058,9 +171606,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +      char *buffer;
 +
 +      if (strlen(name) == 0)
-+              buffer = kasprintf(GFP_KERNEL, "%s", dir);
++              buffer = kasprintf(GFP_KERNEL|__GFP_HIGH, "%s", dir);
 +      else
-+              buffer = kasprintf(GFP_KERNEL, "%s/%s", dir, name);
++              buffer = kasprintf(GFP_KERNEL|__GFP_HIGH, "%s/%s", dir, name);
 +      return (!buffer) ? ERR_PTR(-ENOMEM) : buffer;
 +}
 +
@@ -107072,7 +171620,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +      *num = count_strings(strings, len);
 +
 +      /* Transfer to one big alloc for easy freeing. */
-+      ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL);
++      ret = kmalloc(*num * sizeof(char *) + len, GFP_KERNEL|__GFP_HIGH);
 +      if (!ret) {
 +              kfree(strings);
 +              return ERR_PTR(-ENOMEM);
@@ -107273,7 +171821,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +#define PRINTF_BUFFER_SIZE 4096
 +      char *printf_buffer;
 +
-+      printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL);
++      printf_buffer = kmalloc(PRINTF_BUFFER_SIZE, GFP_KERNEL|__GFP_HIGH);
 +      if (printf_buffer == NULL)
 +              return -ENOMEM;
 +
@@ -107396,6 +171944,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +      char token[sizeof(watch) * 2 + 1];
 +      int err;
 +
++      BUG_ON(watch->flags & XBWF_new_thread);
++
 +      sprintf(token, "%lX", (long)watch);
 +
 +      down_read(&xs_state.watch_mutex);
@@ -107505,16 +172055,29 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +                      list_del(ent);
 +              spin_unlock(&watch_events_lock);
 +
-+              if (ent != &watch_events) {
-+                      msg = list_entry(ent, struct xs_stored_msg, list);
-+                      if (msg->u.watch.handle->flags & XBWF_new_thread)
-+                              kthread_run(xenwatch_handle_callback,
-+                                          msg, "xenwatch_cb");
-+                      else
-+                              xenwatch_handle_callback(msg);
++              if (ent == &watch_events) {
++                      mutex_unlock(&xenwatch_mutex);
++                      continue;
 +              }
 +
-+              mutex_unlock(&xenwatch_mutex);
++              msg = list_entry(ent, struct xs_stored_msg, list);
++
++              /*
++               * Unlock the mutex before running an XBWF_new_thread
++               * handler. kthread_run can block which can deadlock
++               * against unregister_xenbus_watch() if we need to
++               * unregister other watches in order to make
++               * progress. This can occur on resume before the swap
++               * device is attached.
++               */
++              if (msg->u.watch.handle->flags & XBWF_new_thread) {
++                      mutex_unlock(&xenwatch_mutex);
++                      kthread_run(xenwatch_handle_callback,
++                                  msg, "xenwatch_cb");
++              } else {
++                      xenwatch_handle_callback(msg);
++                      mutex_unlock(&xenwatch_mutex);
++              }
 +      }
 +
 +      return 0;
@@ -107542,7 +172105,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +      }
 +
 +
-+      msg = kmalloc(sizeof(*msg), GFP_KERNEL);
++      msg = kmalloc(sizeof(*msg), GFP_KERNEL|__GFP_HIGH);
 +      if (msg == NULL) {
 +              err = -ENOMEM;
 +              goto out;
@@ -107554,7 +172117,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +              goto out;
 +      }
 +
-+      body = kmalloc(msg->hdr.len + 1, GFP_KERNEL);
++      body = kmalloc(msg->hdr.len + 1, GFP_KERNEL|__GFP_HIGH);
 +      if (body == NULL) {
 +              kfree(msg);
 +              err = -ENOMEM;
@@ -107651,10 +172214,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenbus/xenbu
 +
 +      return 0;
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenoprof/xenoprofile.c linux-2.6.18-xen.hg/drivers/xen/xenoprof/xenoprofile.c
---- linux-2.6.18/drivers/xen/xenoprof/xenoprofile.c    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/drivers/xen/xenoprof/xenoprofile.c     2007-12-23 11:15:34.254612776 +0100
-@@ -0,0 +1,544 @@
+--- linux-2.6.18.8/drivers/xen/xenoprof/xenoprofile.c  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/drivers/xen/xenoprof/xenoprofile.c     2008-05-19 00:33:48.782958026 +0300
+@@ -0,0 +1,546 @@
 +/**
 + * @file xenoprofile.c
 + *
@@ -107855,11 +172417,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenoprof/xen
 +xenoprof_ovf_interrupt(int irq, void * dev_id, struct pt_regs * regs)
 +{
 +      struct xenoprof_buf * buf;
-+      int cpu;
 +      static unsigned long flag;
 +
-+      cpu = smp_processor_id();
-+      buf = xenoprof_buf[cpu];
++      buf = xenoprof_buf[smp_processor_id()];
 +
 +      xenoprof_add_pc(buf, 0);
 +
@@ -107875,7 +172435,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenoprof/xen
 +
 +static void unbind_virq(void)
 +{
-+      int i;
++      unsigned int i;
 +
 +      for_each_online_cpu(i) {
 +              if (ovf_irq[i] >= 0) {
@@ -107888,7 +172448,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenoprof/xen
 +
 +static int bind_virq(void)
 +{
-+      int i, result;
++      unsigned int i;
++      int result;
 +
 +      for_each_online_cpu(i) {
 +              result = bind_virq_to_irqhandler(VIRQ_XENOPROF,
@@ -108004,10 +172565,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenoprof/xen
 +{
 +      xenoprof_enabled = 0;
 +
-+      HYPERVISOR_xenoprof_op(XENOPROF_disable_virq, NULL);
++      WARN_ON(HYPERVISOR_xenoprof_op(XENOPROF_disable_virq, NULL));
 +
 +      if (xenoprof_is_primary) {
-+              HYPERVISOR_xenoprof_op(XENOPROF_release_counters, NULL);
++              WARN_ON(HYPERVISOR_xenoprof_op(XENOPROF_release_counters,
++                                             NULL));
 +              active_defined = 0;
 +      }
 +
@@ -108034,7 +172596,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenoprof/xen
 +static void xenoprof_stop(void)
 +{
 +      if (xenoprof_is_primary)
-+              HYPERVISOR_xenoprof_op(XENOPROF_stop, NULL);
++              WARN_ON(HYPERVISOR_xenoprof_op(XENOPROF_stop, NULL));
 +      xenoprof_arch_stop();
 +}
 +
@@ -108077,7 +172639,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenoprof/xen
 +
 +out:
 +      if (ret)
-+              HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list, NULL);
++              WARN_ON(HYPERVISOR_xenoprof_op(XENOPROF_reset_active_list,
++                                             NULL));
 +      active_defined = !ret;
 +      return ret;
 +}
@@ -108086,7 +172649,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenoprof/xen
 +                                unsigned int pdoms)
 +{
 +      int ret;
-+      int i, j;
++      unsigned int i, j;
 +      struct xenoprof_buf *buf;
 +
 +      if (!xenoprof_is_primary)
@@ -108160,7 +172723,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenoprof/xen
 +int __init xenoprofile_init(struct oprofile_operations * ops)
 +{
 +      struct xenoprof_init init;
-+      int ret, i;
++      unsigned int i;
++      int ret;
 +
 +      ret = HYPERVISOR_xenoprof_op(XENOPROF_init, &init);
 +      if (!ret) {
@@ -108196,12 +172760,33 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/drivers/xen/xenoprof/xen
 +      xenoprof_arch_unmap_shared_buffer(&shared_buffer);
 +      if (xenoprof_is_primary) {
 +              unmap_passive_list();
-+              HYPERVISOR_xenoprof_op(XENOPROF_shutdown, NULL);
++              WARN_ON(HYPERVISOR_xenoprof_op(XENOPROF_shutdown, NULL));
 +        }
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/aio.c linux-2.6.18-xen.hg/fs/aio.c
---- linux-2.6.18/fs/aio.c      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/fs/aio.c       2007-12-23 11:15:34.304615402 +0100
+--- linux-2.6.18.8/fs/Kconfig  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/Kconfig     2008-05-19 00:33:48.982969555 +0300
+@@ -826,6 +826,11 @@
+         help
+         Exports the dump image of crashed kernel in ELF format.
++config PROC_IOMEM_MACHINE
++      bool
++      depends on PROC_FS && EXPERIMENTAL && KEXEC && XEN && IA64
++      default y
++
+ config SYSFS
+       bool "sysfs file system support" if EMBEDDED
+       default y
+@@ -865,6 +870,7 @@
+ config HUGETLBFS
+       bool "HugeTLB file system support"
+       depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN
++      depends on !XEN
+       help
+         hugetlbfs is a filesystem backing for HugeTLB pages, based on
+         ramfs. For architectures that support it, say Y here and read
+--- linux-2.6.18.8/fs/aio.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/aio.c       2008-05-19 00:33:49.282986848 +0300
 @@ -34,6 +34,11 @@
  #include <asm/uaccess.h>
  #include <asm/mmu_context.h>
@@ -108380,22 +172965,46 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/aio.c linux-2.6.18-xe
  
                get_ioctx(ioctx); /* io_destroy() expects us to hold a ref */
                io_destroy(ioctx);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/compat_ioctl.c linux-2.6.18-xen.hg/fs/compat_ioctl.c
---- linux-2.6.18/fs/compat_ioctl.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/fs/compat_ioctl.c      2007-12-23 11:15:34.384619602 +0100
-@@ -124,6 +124,11 @@
+--- linux-2.6.18.8/fs/binfmt_elf.c     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/binfmt_elf.c        2008-05-19 00:33:49.506999760 +0300
+@@ -1170,6 +1170,10 @@
+  */
+ static int maydump(struct vm_area_struct *vma)
+ {
++      /* The vma can be set up to tell us the answer directly.  */
++      if (vma->vm_flags & VM_ALWAYSDUMP)
++              return 1;
++
+       /* Do not dump I/O mapped devices or special mappings */
+       if (vma->vm_flags & (VM_IO | VM_RESERVED))
+               return 0;
+--- linux-2.6.18.8/fs/bio.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/bio.c       2008-05-19 00:33:49.551002297 +0300
+@@ -112,6 +112,7 @@
+       BIO_BUG_ON(pool_idx >= BIOVEC_NR_POOLS);
++      if (bio->bi_io_vec)
+       mempool_free(bio->bi_io_vec, bio_set->bvec_pools[pool_idx]);
+       mempool_free(bio, bio_set->bio_pool);
+ }
+--- linux-2.6.18.8/fs/compat_ioctl.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/compat_ioctl.c      2008-05-19 00:33:49.735012903 +0300
+@@ -124,6 +124,13 @@
  #include <linux/dvb/video.h>
  #include <linux/lp.h>
  
++#ifdef CONFIG_XEN
 +#include <xen/interface/xen.h>
 +#include <xen/public/evtchn.h>
 +#include <xen/public/privcmd.h>
 +#include <xen/compat_ioctl.h>
++#endif
 +
  /* Aiee. Someone does not find a difference between int and long */
  #define EXT2_IOC32_GETFLAGS               _IOR('f', 1, int)
  #define EXT2_IOC32_SETFLAGS               _IOW('f', 2, int)
-@@ -2948,6 +2953,18 @@
+@@ -2948,6 +2955,18 @@
  /*LPGETSTATS not implemented, but no kernels seem to compile it in anyways*/
  COMPATIBLE_IOCTL(LPGETFLAGS)
  HANDLE_IOCTL(LPSETTIMEOUT, lp_timeout_trans)
@@ -108414,9 +173023,62 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/compat_ioctl.c linux-
  };
  
  int ioctl_table_size = ARRAY_SIZE(ioctl_start);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/eventpoll.c linux-2.6.18-xen.hg/fs/eventpoll.c
---- linux-2.6.18/fs/eventpoll.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/fs/eventpoll.c 2007-12-23 11:15:34.401287149 +0100
+--- linux-2.6.18.8/fs/debugfs/file.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/debugfs/file.c      2008-05-19 00:33:49.819017745 +0300
+@@ -170,6 +170,51 @@
+ }
+ EXPORT_SYMBOL_GPL(debugfs_create_u32);
++
++static void debugfs_u64_set(void *data, u64 val)
++{
++      *(u64 *)data = val;
++}
++
++static u64 debugfs_u64_get(void *data)
++{
++      return *(u64 *)data;
++}
++DEFINE_SIMPLE_ATTRIBUTE(fops_u64, debugfs_u64_get, debugfs_u64_set, "%llu\n");
++
++/**
++ * debugfs_create_u64 - create a file in the debugfs filesystem that is used to read and write an unsigned 64 bit value.
++ *
++ * @name: a pointer to a string containing the name of the file to create.
++ * @mode: the permission that the file should have
++ * @parent: a pointer to the parent dentry for this file.  This should be a
++ *          directory dentry if set.  If this paramater is NULL, then the
++ *          file will be created in the root of the debugfs filesystem.
++ * @value: a pointer to the variable that the file should read to and write
++ *         from.
++ *
++ * This function creates a file in debugfs with the given name that
++ * contains the value of the variable @value.  If the @mode variable is so
++ * set, it can be read from, and written to.
++ *
++ * This function will return a pointer to a dentry if it succeeds.  This
++ * pointer must be passed to the debugfs_remove() function when the file is
++ * to be removed (no automatic cleanup happens if your module is unloaded,
++ * you are responsible here.)  If an error occurs, NULL will be returned.
++ *
++ * If debugfs is not enabled in the kernel, the value -ENODEV will be
++ * returned.  It is not wise to check for this value, but rather, check for
++ * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
++ * code.
++ */
++struct dentry *debugfs_create_u64(const char *name, mode_t mode,
++                                struct dentry *parent, u64 *value)
++{
++      return debugfs_create_file(name, mode, parent, value, &fops_u64);
++}
++EXPORT_SYMBOL_GPL(debugfs_create_u64);
++
++
+ static ssize_t read_file_bool(struct file *file, char __user *user_buf,
+                             size_t count, loff_t *ppos)
+ {
+--- linux-2.6.18.8/fs/eventpoll.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/eventpoll.c 2008-05-19 00:33:49.903022587 +0300
 @@ -236,8 +236,6 @@
  
  static void ep_poll_safewake_init(struct poll_safewake *psw);
@@ -108491,32 +173153,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/eventpoll.c linux-2.6
  
        /*
         * Mark the inode dirty from the very beginning,
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/Kconfig linux-2.6.18-xen.hg/fs/Kconfig
---- linux-2.6.18/fs/Kconfig    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/fs/Kconfig     2007-12-23 11:15:34.274613828 +0100
-@@ -826,6 +826,11 @@
-         help
-         Exports the dump image of crashed kernel in ELF format.
-+config PROC_IOMEM_MACHINE
-+      bool
-+      depends on PROC_FS && EXPERIMENTAL && KEXEC && XEN && IA64
-+      default y
-+
- config SYSFS
-       bool "sysfs file system support" if EMBEDDED
-       default y
-@@ -865,6 +870,7 @@
- config HUGETLBFS
-       bool "HugeTLB file system support"
-       depends X86 || IA64 || PPC64 || SPARC64 || SUPERH || BROKEN
-+      depends on !XEN
-       help
-         hugetlbfs is a filesystem backing for HugeTLB pages, based on
-         ramfs. For architectures that support it, say Y here and read
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/lockd/svc.c linux-2.6.18-xen.hg/fs/lockd/svc.c
---- linux-2.6.18/fs/lockd/svc.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/fs/lockd/svc.c 2007-12-23 11:15:35.277999847 +0100
+--- linux-2.6.18.8/fs/lockd/svc.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/lockd/svc.c 2008-05-19 00:33:53.823248553 +0300
 @@ -323,9 +323,6 @@
   * Sysctl parameters (same as module parameters, different interface).
   */
@@ -108527,9 +173165,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/lockd/svc.c linux-2.6
  static ctl_table nlm_sysctls[] = {
        {
                .ctl_name       = CTL_UNNUMBERED,
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/nfs/sysctl.c linux-2.6.18-xen.hg/fs/nfs/sysctl.c
---- linux-2.6.18/fs/nfs/sysctl.c       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/fs/nfs/sysctl.c        2007-12-23 11:15:35.324668967 +0100
+--- linux-2.6.18.8/fs/nfs/sysctl.c     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/nfs/sysctl.c        2008-05-19 00:33:54.179269075 +0300
 @@ -18,11 +18,6 @@
  static const int nfs_set_port_min = 0;
  static const int nfs_set_port_max = 65535;
@@ -108542,9 +173179,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/nfs/sysctl.c linux-2.
  
  static ctl_table nfs_cb_sysctls[] = {
  #ifdef CONFIG_NFS_V4
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/proc/proc_misc.c linux-2.6.18-xen.hg/fs/proc/proc_misc.c
---- linux-2.6.18/fs/proc/proc_misc.c   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/fs/proc/proc_misc.c    2007-12-23 11:15:36.721408978 +0100
+--- linux-2.6.18.8/fs/proc/proc_misc.c 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/proc/proc_misc.c    2008-05-19 00:33:55.683355772 +0300
 @@ -471,7 +471,7 @@
                (unsigned long long)cputime64_to_clock_t(irq),
                (unsigned long long)cputime64_to_clock_t(softirq),
@@ -108554,9 +173190,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/proc/proc_misc.c linu
  
                /* Copy values here to work around gcc-2.95.3, gcc-2.96 */
                user = kstat_cpu(i).cpustat.user;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/proc/vmcore.c linux-2.6.18-xen.hg/fs/proc/vmcore.c
---- linux-2.6.18/fs/proc/vmcore.c      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/fs/proc/vmcore.c       2007-12-23 11:15:36.724742484 +0100
+--- linux-2.6.18.8/fs/proc/vmcore.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/proc/vmcore.c       2008-05-19 00:33:55.687356003 +0300
 @@ -514,7 +514,7 @@
        /* Do some basic Verification. */
        if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG) != 0 ||
@@ -108566,9 +173201,20 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/proc/vmcore.c linux-2
                ehdr.e_ident[EI_CLASS] != ELFCLASS64 ||
                ehdr.e_ident[EI_VERSION] != EV_CURRENT ||
                ehdr.e_version != EV_CURRENT ||
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/xfs/linux-2.6/xfs_buf.c linux-2.6.18-xen.hg/fs/xfs/linux-2.6/xfs_buf.c
---- linux-2.6.18/fs/xfs/linux-2.6/xfs_buf.c    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/fs/xfs/linux-2.6/xfs_buf.c     2007-12-23 11:15:37.398111178 +0100
+--- linux-2.6.18.8/fs/splice.c 2008-05-19 00:42:34.129243112 +0300
++++ linux-2.6.18-xen.hg/fs/splice.c    2008-05-19 00:33:55.971372374 +0300
+@@ -1141,6 +1141,9 @@
+               if (unlikely(!base))
+                       break;
++              if (unlikely(!access_ok(VERIFY_READ, base, len)))
++                      break;
++
+               /*
+                * Get this base offset and number of pages, then map
+                * in the user pages.
+--- linux-2.6.18.8/fs/xfs/linux-2.6/xfs_buf.c  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/fs/xfs/linux-2.6/xfs_buf.c     2008-05-19 00:33:58.495517869 +0300
 @@ -182,6 +182,19 @@
  {
        a_list_t        *aentry;
@@ -108589,9 +173235,133 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/fs/xfs/linux-2.6/xfs_buf
        aentry = kmalloc(sizeof(a_list_t), GFP_NOWAIT);
        if (likely(aentry)) {
                spin_lock(&as_lock);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-generic/pci.h linux-2.6.18-xen.hg/include/asm-generic/pci.h
---- linux-2.6.18/include/asm-generic/pci.h     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-generic/pci.h      2007-12-23 11:15:40.078251913 +0100
+--- linux-2.6.18.8/include/acpi/processor.h    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/acpi/processor.h       2008-05-19 00:33:59.571579895 +0300
+@@ -21,6 +21,10 @@
+ #define ACPI_PSD_REV0_REVISION                0 /* Support for _PSD as in ACPI 3.0 */
+ #define ACPI_PSD_REV0_ENTRIES         5
++#ifdef CONFIG_XEN
++#define NR_ACPI_CPUS                  256
++#endif /* CONFIG_XEN */
++
+ /*
+  * Types of coordination defined in ACPI 3.0. Same macros can be used across
+  * P, C and T states
+@@ -33,6 +37,17 @@
+ struct acpi_processor_cx;
++#ifdef CONFIG_PROCESSOR_EXTERNAL_CONTROL
++struct acpi_csd_package {
++      acpi_integer num_entries;
++      acpi_integer revision;
++      acpi_integer domain;
++      acpi_integer coord_type;
++      acpi_integer num_processors;
++      acpi_integer index;
++} __attribute__ ((packed));
++#endif
++
+ struct acpi_power_register {
+       u8 descriptor;
+       u16 length;
+@@ -63,6 +78,12 @@
+       u32 power;
+       u32 usage;
+       u64 time;
++#ifdef CONFIG_PROCESSOR_EXTERNAL_CONTROL
++      /* Require raw information for external control logic */
++      struct acpi_power_register reg;
++      u32 csd_count;
++      struct acpi_csd_package *domain_info;
++#endif
+       struct acpi_processor_cx_policy promotion;
+       struct acpi_processor_cx_policy demotion;
+ };
+@@ -275,4 +296,80 @@
+ }
+ #endif
++#ifdef CONFIG_XEN
++/* 
++ * Following are interfaces geared to external processor PM control
++ * logic like a VMM
++ */
++/* Events notified to external control logic */
++#define PROCESSOR_PM_INIT     1
++#define PROCESSOR_PM_CHANGE   2
++#define PROCESSOR_HOTPLUG     3
++
++/* Objects for the PM envents */
++#define PM_TYPE_IDLE          0
++#define PM_TYPE_PERF          1
++#define PM_TYPE_THR           2
++#define PM_TYPE_MAX           3
++
++/* Processor hotplug events */
++#define HOTPLUG_TYPE_ADD      0
++#define HOTPLUG_TYPE_REMOVE   1
++
++#ifdef CONFIG_PROCESSOR_EXTERNAL_CONTROL
++struct processor_extcntl_ops {
++      /* Transfer processor PM events to external control logic */
++      int (*pm_ops[PM_TYPE_MAX])(struct acpi_processor *pr, int event);
++      /* Notify physical processor status to external control logic */
++      int (*hotplug)(struct acpi_processor *pr, int event);
++};
++extern struct processor_extcntl_ops *processor_extcntl_ops;
++
++static inline int processor_cntl_external(void)
++{
++      return (processor_extcntl_ops != NULL);
++}
++
++static inline int processor_pm_external(void)
++{
++      return processor_cntl_external() &&
++              (processor_extcntl_ops->pm_ops[PM_TYPE_IDLE] != NULL);
++}
++
++static inline int processor_pmperf_external(void)
++{
++      return processor_cntl_external() &&
++              (processor_extcntl_ops->pm_ops[PM_TYPE_PERF] != NULL);
++}
++
++static inline int processor_pmthr_external(void)
++{
++      return processor_cntl_external() &&
++              (processor_extcntl_ops->pm_ops[PM_TYPE_THR] != NULL);
++}
++
++extern int processor_notify_external(struct acpi_processor *pr,
++                      int event, int type);
++extern int processor_register_extcntl(struct processor_extcntl_ops *ops);
++extern int processor_unregister_extcntl(struct processor_extcntl_ops *ops);
++extern int processor_extcntl_init(struct acpi_processor *pr);
++extern int acpi_processor_get_performance_info(struct acpi_processor *pr);
++extern int acpi_processor_get_psd(struct acpi_processor *pr);
++#else
++static inline int processor_cntl_external(void) {return 0;}
++static inline int processor_pm_external(void) {return 0;}
++static inline int processor_pmperf_external(void) {return 0;}
++static inline int processor_pmthr_external(void) {return 0;}
++static inline int processor_notify_external(struct acpi_processor *pr,
++                      int event, int type)
++{
++      return -EINVAL;
++}
++static inline int processor_extcntl_init(struct acpi_processor *pr)
++{
++      return -EINVAL;
++}
++#endif /* CONFIG_PROCESSOR_EXTERNAL_CONTROL */
++#endif /* CONFIG_XEN */
++
+ #endif
+--- linux-2.6.18.8/include/asm-generic/pci.h   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-generic/pci.h      2008-05-19 00:34:06.095955969 +0300
 @@ -43,7 +43,9 @@
        return root;
  }
@@ -108602,9 +173372,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-generic/pci.
  
  #ifndef HAVE_ARCH_PCI_GET_LEGACY_IDE_IRQ
  static inline int pci_get_legacy_ide_irq(struct pci_dev *dev, int channel)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-generic/vmlinux.lds.h linux-2.6.18-xen.hg/include/asm-generic/vmlinux.lds.h
---- linux-2.6.18/include/asm-generic/vmlinux.lds.h     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-generic/vmlinux.lds.h      2007-12-23 11:15:40.084918931 +0100
+--- linux-2.6.18.8/include/asm-generic/pgtable.h       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-generic/pgtable.h  2008-05-19 00:34:06.499979257 +0300
+@@ -188,6 +188,10 @@
+ })
+ #endif
++#ifndef arch_change_pte_range
++#define arch_change_pte_range(mm, pmd, addr, end, newprot) 0
++#endif
++
+ #ifndef __ASSEMBLY__
+ /*
+  * When walking page tables, we usually want to skip any p?d_none entries;
+--- linux-2.6.18.8/include/asm-generic/vmlinux.lds.h   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-generic/vmlinux.lds.h      2008-05-19 00:34:06.607985483 +0300
 @@ -194,3 +194,6 @@
                .stab.index 0 : { *(.stab.index) }                      \
                .stab.indexstr 0 : { *(.stab.indexstr) }                \
@@ -108612,18 +173394,47 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-generic/vmli
 +
 +#define NOTES                                                         \
 +              .notes : { *(.note.*) } :note
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/acpi.h linux-2.6.18-xen.hg/include/asm-i386/acpi.h
---- linux-2.6.18/include/asm-i386/acpi.h       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-i386/acpi.h        2007-12-23 11:15:40.131588046 +0100
-@@ -177,11 +177,17 @@
- /* early initialization routine */
- extern void acpi_reserve_bootmem(void);
+--- linux-2.6.18.8/include/asm-i386/acpi.h     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/acpi.h        2008-05-19 00:34:07.420032291 +0300
+@@ -31,6 +31,9 @@
+ #include <acpi/pdc_intel.h>
  
-+#ifdef CONFIG_ACPI_PV_SLEEP
-+extern int acpi_notify_hypervisor_state(u8 sleep_state,
-+      u32 pm1a_cnt, u32 pm1b_cnt);
-+#endif /* CONFIG_ACPI_PV_SLEEP */
- #endif /*CONFIG_ACPI_SLEEP*/
+ #include <asm/system.h>               /* defines cmpxchg */
++#ifdef CONFIG_XEN
++#include <xen/interface/platform.h>
++#endif
+ #define COMPILER_DEPENDENT_INT64   long long
+ #define COMPILER_DEPENDENT_UINT64  unsigned long long
+@@ -156,6 +159,27 @@
+ }
+ extern int acpi_irq_balance_set(char *str);
++#ifdef CONFIG_XEN
++static inline int acpi_notify_hypervisor_state(u8 sleep_state,
++                                             u32 pm1a_cnt_val,
++                                             u32 pm1b_cnt_val)
++{
++      struct xen_platform_op op = {
++              .cmd = XENPF_enter_acpi_sleep,
++              .interface_version = XENPF_INTERFACE_VERSION,
++              .u = {
++                      .enter_acpi_sleep = {
++                              .pm1a_cnt_val = pm1a_cnt_val,
++                              .pm1b_cnt_val = pm1b_cnt_val,
++                              .sleep_state = sleep_state,
++                      },
++              },
++      };
++
++      return HYPERVISOR_platform_op(&op);
++}
++#endif /* CONFIG_XEN */
++
+ #else /* !CONFIG_ACPI */
+ #define acpi_lapic 0
+@@ -181,7 +205,9 @@
  
  extern u8 x86_acpiid_to_apicid[];
  
@@ -108633,9 +173444,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/acpi.h
  
  #endif /*__KERNEL__*/
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/agp.h linux-2.6.18-xen.hg/include/asm-i386/agp.h
---- linux-2.6.18/include/asm-i386/agp.h        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-i386/agp.h 2007-12-23 11:15:40.134921557 +0100
+--- linux-2.6.18.8/include/asm-i386/agp.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/agp.h 2008-05-19 00:34:07.420032291 +0300
 @@ -12,8 +12,10 @@
   * data corruption on some CPUs.
   */
@@ -108649,9 +173459,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/agp.h l
  #define flush_agp_mappings() global_flush_tlb()
  
  /* Could use CLFLUSH here if the cpu supports it. But then it would
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/apic.h linux-2.6.18-xen.hg/include/asm-i386/apic.h
---- linux-2.6.18/include/asm-i386/apic.h       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-i386/apic.h        2007-12-23 11:15:40.134921557 +0100
+--- linux-2.6.18.8/include/asm-i386/apic.h     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/apic.h        2008-05-19 00:34:07.424032521 +0300
 @@ -119,10 +119,12 @@
  
  extern int disable_timer_pin_1;
@@ -108665,9 +173474,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/apic.h
  
  extern int timer_over_8254;
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/e820.h linux-2.6.18-xen.hg/include/asm-i386/e820.h
---- linux-2.6.18/include/asm-i386/e820.h       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-i386/e820.h        2007-12-23 11:15:40.144922089 +0100
+--- linux-2.6.18.8/include/asm-i386/e820.h     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/e820.h        2008-05-19 00:34:07.464034827 +0300
 @@ -38,6 +38,7 @@
  
  extern int e820_all_mapped(unsigned long start, unsigned long end,
@@ -108676,9 +173484,61 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/e820.h
  
  #endif/*!__ASSEMBLY__*/
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/fixmap.h linux-2.6.18-xen.hg/include/asm-i386/fixmap.h
---- linux-2.6.18/include/asm-i386/fixmap.h     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-i386/fixmap.h      2007-12-23 11:15:40.148255594 +0100
+--- linux-2.6.18.8/include/asm-i386/elf.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/elf.h 2008-05-19 00:34:07.476035519 +0300
+@@ -169,50 +169,6 @@
+               NEW_AUX_ENT(AT_SYSINFO_EHDR, VDSO_COMPAT_BASE); \
+ } while (0)
+-/*
+- * These macros parameterize elf_core_dump in fs/binfmt_elf.c to write out
+- * extra segments containing the vsyscall DSO contents.  Dumping its
+- * contents makes post-mortem fully interpretable later without matching up
+- * the same kernel and hardware config to see what PC values meant.
+- * Dumping its extra ELF program headers includes all the other information
+- * a debugger needs to easily find how the vsyscall DSO was being used.
+- */
+-#define ELF_CORE_EXTRA_PHDRS          (VDSO_HIGH_EHDR->e_phnum)
+-#define ELF_CORE_WRITE_EXTRA_PHDRS                                          \
+-do {                                                                        \
+-      const struct elf_phdr *const vsyscall_phdrs =                         \
+-              (const struct elf_phdr *) (VDSO_HIGH_BASE                     \
+-                                         + VDSO_HIGH_EHDR->e_phoff);    \
+-      int i;                                                                \
+-      Elf32_Off ofs = 0;                                                    \
+-      for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) {               \
+-              struct elf_phdr phdr = vsyscall_phdrs[i];                     \
+-              if (phdr.p_type == PT_LOAD) {                                 \
+-                      BUG_ON(ofs != 0);                                     \
+-                      ofs = phdr.p_offset = offset;                         \
+-                      phdr.p_memsz = PAGE_ALIGN(phdr.p_memsz);              \
+-                      phdr.p_filesz = phdr.p_memsz;                         \
+-                      offset += phdr.p_filesz;                              \
+-              }                                                             \
+-              else                                                          \
+-                      phdr.p_offset += ofs;                                 \
+-              phdr.p_paddr = 0; /* match other core phdrs */                \
+-              DUMP_WRITE(&phdr, sizeof(phdr));                              \
+-      }                                                                     \
+-} while (0)
+-#define ELF_CORE_WRITE_EXTRA_DATA                                           \
+-do {                                                                        \
+-      const struct elf_phdr *const vsyscall_phdrs =                         \
+-              (const struct elf_phdr *) (VDSO_HIGH_BASE                     \
+-                                         + VDSO_HIGH_EHDR->e_phoff);    \
+-      int i;                                                                \
+-      for (i = 0; i < VDSO_HIGH_EHDR->e_phnum; ++i) {               \
+-              if (vsyscall_phdrs[i].p_type == PT_LOAD)                      \
+-                      DUMP_WRITE((void *) vsyscall_phdrs[i].p_vaddr,        \
+-                                 PAGE_ALIGN(vsyscall_phdrs[i].p_memsz));    \
+-      }                                                                     \
+-} while (0)
+-
+ #endif
+ #endif
+--- linux-2.6.18.8/include/asm-i386/fixmap.h   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/fixmap.h      2008-05-19 00:34:07.480035749 +0300
 @@ -19,7 +19,7 @@
   * Leave one empty page between vmalloc'ed areas and
   * the start of the fixmap.
@@ -108697,9 +173557,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/fixmap.
  #define set_fixmap(idx, phys) \
                __set_fixmap(idx, phys, PAGE_KERNEL)
  /*
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/kexec.h linux-2.6.18-xen.hg/include/asm-i386/kexec.h
---- linux-2.6.18/include/asm-i386/kexec.h      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-i386/kexec.h       2007-12-23 11:15:40.194924713 +0100
+--- linux-2.6.18.8/include/asm-i386/io_apic.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/io_apic.h     2008-05-19 00:34:07.492036441 +0300
+@@ -12,7 +12,7 @@
+ #ifdef CONFIG_X86_IO_APIC
+-#ifdef CONFIG_PCI_MSI
++#if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN)
+ static inline int use_pci_vector(void)        {return 1;}
+ static inline void disable_edge_ioapic_vector(unsigned int vector) { }
+ static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
+--- linux-2.6.18.8/include/asm-i386/kexec.h    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/kexec.h       2008-05-19 00:34:07.512037594 +0300
 @@ -1,6 +1,26 @@
  #ifndef _I386_KEXEC_H
  #define _I386_KEXEC_H
@@ -108764,9 +173634,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/kexec.h
 +#endif /* __ASSEMBLY__ */
  
  #endif /* _I386_KEXEC_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-default/mach_traps.h linux-2.6.18-xen.hg/include/asm-i386/mach-default/mach_traps.h
---- linux-2.6.18/include/asm-i386/mach-default/mach_traps.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-default/mach_traps.h     2007-12-23 11:15:40.208258741 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-default/mach_traps.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-default/mach_traps.h     2008-05-19 00:34:07.532038747 +0300
 @@ -15,6 +15,18 @@
        outb(reason, 0x61);
  }
@@ -108786,9 +173655,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-de
  static inline unsigned char get_nmi_reason(void)
  {
        return inb(0x61);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/agp.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/agp.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/agp.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/agp.h    2007-12-23 11:15:40.228259789 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/agp.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/agp.h    2008-05-19 00:34:07.692047970 +0300
 @@ -0,0 +1,44 @@
 +#ifndef AGP_H
 +#define AGP_H 1
@@ -108834,10 +173702,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      dma_free_coherent(NULL,PAGE_SIZE<<(order),(table),virt_to_bus(table))
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/desc.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/desc.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/desc.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/desc.h   2007-12-23 11:15:40.228259789 +0100
-@@ -0,0 +1,164 @@
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/desc.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/desc.h   2008-05-19 00:34:07.692047970 +0300
+@@ -0,0 +1,166 @@
 +#ifndef __ARCH_DESC_H
 +#define __ARCH_DESC_H
 +
@@ -108951,7 +173818,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +
 +static inline void load_TLS(struct thread_struct *t, unsigned int cpu)
 +{
-+#define C(i) HYPERVISOR_update_descriptor(virt_to_machine(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]), *(u64 *)&t->tls_array[i])
++#define C(i) if (HYPERVISOR_update_descriptor(virt_to_machine(&get_cpu_gdt_table(cpu)[GDT_ENTRY_TLS_MIN + i]), \
++                                             *(u64 *)&t->tls_array[i])) \
++              BUG();
 +      C(0); C(1); C(2);
 +#undef C
 +}
@@ -108965,7 +173834,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +       * it slows down context switching. Noone uses it anyway.
 +       */
 +      cpu = cpu;              /* XXX avoid compiler warning */
-+      xen_set_ldt(0UL, 0);
++      xen_set_ldt(NULL, 0);
 +      put_cpu();
 +}
 +
@@ -108980,7 +173849,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      if (likely(!count))
 +              segments = NULL;
 +
-+      xen_set_ldt((unsigned long)segments, count);
++      xen_set_ldt(segments, count);
 +}
 +
 +static inline void load_LDT(mm_context_t *pc)
@@ -109002,10 +173871,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#endif /* !__ASSEMBLY__ */
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/dma-mapping.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/dma-mapping.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/dma-mapping.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/dma-mapping.h    2007-12-23 11:15:40.228259789 +0100
-@@ -0,0 +1,157 @@
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/dma-mapping.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/dma-mapping.h    2008-05-19 00:34:07.692047970 +0300
+@@ -0,0 +1,151 @@
 +#ifndef _ASM_I386_DMA_MAPPING_H
 +#define _ASM_I386_DMA_MAPPING_H
 +
@@ -109030,13 +173898,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      return (addr & ~mask) != 0;
 +}
 +
-+static inline int
-+range_straddles_page_boundary(paddr_t p, size_t size)
-+{
-+      extern unsigned long *contiguous_bitmap;
-+      return ((((p & ~PAGE_MASK) + size) > PAGE_SIZE) &&
-+              !test_bit(p >> PAGE_SHIFT, contiguous_bitmap));
-+}
++extern int range_straddles_page_boundary(paddr_t p, size_t size);
 +
 +#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
 +#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
@@ -109163,9 +174025,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +                                dma_addr_t device_addr, size_t size);
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/fixmap.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/fixmap.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/fixmap.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/fixmap.h 2007-12-23 11:15:40.228259789 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/fixmap.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/fixmap.h 2008-05-19 00:34:07.764052120 +0300
 @@ -0,0 +1,155 @@
 +/*
 + * fixmap.h: compile-time virtual memory allocation
@@ -109322,9 +174183,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +
 +#endif /* !__ASSEMBLY__ */
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/gnttab_dma.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/gnttab_dma.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/gnttab_dma.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/gnttab_dma.h     2007-12-23 11:15:40.231593300 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/gnttab_dma.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/gnttab_dma.h     2008-05-19 00:34:07.764052120 +0300
 @@ -0,0 +1,41 @@
 +/*
 + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
@@ -109367,9 +174227,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +}
 +
 +#endif /* _ASM_I386_GNTTAB_DMA_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/highmem.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/highmem.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/highmem.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/highmem.h        2007-12-23 11:15:40.231593300 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/highmem.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/highmem.h        2008-05-19 00:34:07.812054887 +0300
 @@ -0,0 +1,80 @@
 +/*
 + * highmem.h: virtual kernel memory mappings for high memory
@@ -109451,9 +174310,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#endif /* __KERNEL__ */
 +
 +#endif /* _ASM_HIGHMEM_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/hw_irq.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/hw_irq.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/hw_irq.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/hw_irq.h 2007-12-23 11:15:40.231593300 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/hw_irq.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/hw_irq.h 2008-05-19 00:34:07.812054887 +0300
 @@ -0,0 +1,72 @@
 +#ifndef _ASM_HW_IRQ_H
 +#define _ASM_HW_IRQ_H
@@ -109527,10 +174385,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define IO_APIC_IRQ(x) (((x) >= 16) || ((1<<(x)) & io_apic_irqs))
 +
 +#endif /* _ASM_HW_IRQ_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/hypercall.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/hypercall.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/hypercall.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/hypercall.h      2007-12-23 11:15:40.231593300 +0100
-@@ -0,0 +1,408 @@
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/hypercall.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/hypercall.h      2008-05-19 00:34:07.812054887 +0300
+@@ -0,0 +1,416 @@
 +/******************************************************************************
 + * hypercall.h
 + * 
@@ -109573,55 +174430,55 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +# error "please don't include this file directly"
 +#endif
 +
-+#define __STR(x) #x
-+#define STR(x) __STR(x)
-+
 +#ifdef CONFIG_XEN
 +#define HYPERCALL_STR(name)                                   \
-+      "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"
++      "call hypercall_page + ("__stringify(__HYPERVISOR_##name)" * 32)"
 +#else
 +#define HYPERCALL_STR(name)                                   \
-+      "mov "__stringify(hypercall_stubs)",%%eax; "            \
-+      "add $("STR(__HYPERVISOR_##name)" * 32),%%eax; "        \
++      "mov hypercall_stubs,%%eax; "                           \
++      "add $("__stringify(__HYPERVISOR_##name)" * 32),%%eax; "\
 +      "call *%%eax"
 +#endif
 +
 +#define _hypercall0(type, name)                       \
 +({                                            \
-+      long __res;                             \
++      type __res;                             \
 +      asm volatile (                          \
 +              HYPERCALL_STR(name)             \
 +              : "=a" (__res)                  \
 +              :                               \
 +              : "memory" );                   \
-+      (type)__res;                            \
++      __res;                                  \
 +})
 +
 +#define _hypercall1(type, name, a1)                           \
 +({                                                            \
-+      long __res, __ign1;                                     \
++      type __res;                                             \
++      long __ign1;                                            \
 +      asm volatile (                                          \
 +              HYPERCALL_STR(name)                             \
 +              : "=a" (__res), "=b" (__ign1)                   \
 +              : "1" ((long)(a1))                              \
 +              : "memory" );                                   \
-+      (type)__res;                                            \
++      __res;                                                  \
 +})
 +
 +#define _hypercall2(type, name, a1, a2)                               \
 +({                                                            \
-+      long __res, __ign1, __ign2;                             \
++      type __res;                                             \
++      long __ign1, __ign2;                                    \
 +      asm volatile (                                          \
 +              HYPERCALL_STR(name)                             \
 +              : "=a" (__res), "=b" (__ign1), "=c" (__ign2)    \
 +              : "1" ((long)(a1)), "2" ((long)(a2))            \
 +              : "memory" );                                   \
-+      (type)__res;                                            \
++      __res;                                                  \
 +})
 +
 +#define _hypercall3(type, name, a1, a2, a3)                   \
 +({                                                            \
-+      long __res, __ign1, __ign2, __ign3;                     \
++      type __res;                                             \
++      long __ign1, __ign2, __ign3;                            \
 +      asm volatile (                                          \
 +              HYPERCALL_STR(name)                             \
 +              : "=a" (__res), "=b" (__ign1), "=c" (__ign2),   \
@@ -109629,12 +174486,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +              : "1" ((long)(a1)), "2" ((long)(a2)),           \
 +              "3" ((long)(a3))                                \
 +              : "memory" );                                   \
-+      (type)__res;                                            \
++      __res;                                                  \
 +})
 +
 +#define _hypercall4(type, name, a1, a2, a3, a4)                       \
 +({                                                            \
-+      long __res, __ign1, __ign2, __ign3, __ign4;             \
++      type __res;                                             \
++      long __ign1, __ign2, __ign3, __ign4;                    \
 +      asm volatile (                                          \
 +              HYPERCALL_STR(name)                             \
 +              : "=a" (__res), "=b" (__ign1), "=c" (__ign2),   \
@@ -109642,12 +174500,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +              : "1" ((long)(a1)), "2" ((long)(a2)),           \
 +              "3" ((long)(a3)), "4" ((long)(a4))              \
 +              : "memory" );                                   \
-+      (type)__res;                                            \
++      __res;                                                  \
 +})
 +
 +#define _hypercall5(type, name, a1, a2, a3, a4, a5)           \
 +({                                                            \
-+      long __res, __ign1, __ign2, __ign3, __ign4, __ign5;     \
++      type __res;                                             \
++      long __ign1, __ign2, __ign3, __ign4, __ign5;            \
 +      asm volatile (                                          \
 +              HYPERCALL_STR(name)                             \
 +              : "=a" (__res), "=b" (__ign1), "=c" (__ign2),   \
@@ -109656,45 +174515,47 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +              "3" ((long)(a3)), "4" ((long)(a4)),             \
 +              "5" ((long)(a5))                                \
 +              : "memory" );                                   \
-+      (type)__res;                                            \
++      __res;                                                  \
 +})
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_set_trap_table(
-+      trap_info_t *table)
++      const trap_info_t *table)
 +{
 +      return _hypercall1(int, set_trap_table, table);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_mmu_update(
-+      mmu_update_t *req, int count, int *success_count, domid_t domid)
++      mmu_update_t *req, unsigned int count, unsigned int *success_count,
++      domid_t domid)
 +{
 +      return _hypercall4(int, mmu_update, req, count, success_count, domid);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_mmuext_op(
-+      struct mmuext_op *op, int count, int *success_count, domid_t domid)
++      struct mmuext_op *op, unsigned int count, unsigned int *success_count,
++      domid_t domid)
 +{
 +      return _hypercall4(int, mmuext_op, op, count, success_count, domid);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_set_gdt(
-+      unsigned long *frame_list, int entries)
++      unsigned long *frame_list, unsigned int entries)
 +{
 +      return _hypercall2(int, set_gdt, frame_list, entries);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_stack_switch(
 +      unsigned long ss, unsigned long esp)
 +{
 +      return _hypercall2(int, stack_switch, ss, esp);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_set_callbacks(
 +      unsigned long event_selector, unsigned long event_address,
 +      unsigned long failsafe_selector, unsigned long failsafe_address)
@@ -109711,21 +174572,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      return _hypercall1(int, fpu_taskswitch, set);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_sched_op_compat(
 +      int cmd, unsigned long arg)
 +{
 +      return _hypercall2(int, sched_op_compat, cmd, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_sched_op(
 +      int cmd, void *arg)
 +{
 +      return _hypercall2(int, sched_op, cmd, arg);
 +}
 +
-+static inline long
++static inline long __must_check
 +HYPERVISOR_set_timer_op(
 +      u64 timeout)
 +{
@@ -109734,7 +174595,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      return _hypercall2(long, set_timer_op, timeout_lo, timeout_hi);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_platform_op(
 +      struct xen_platform_op *platform_op)
 +{
@@ -109742,42 +174603,42 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      return _hypercall1(int, platform_op, platform_op);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_set_debugreg(
-+      int reg, unsigned long value)
++      unsigned int reg, unsigned long value)
 +{
 +      return _hypercall2(int, set_debugreg, reg, value);
 +}
 +
-+static inline unsigned long
++static inline unsigned long __must_check
 +HYPERVISOR_get_debugreg(
-+      int reg)
++      unsigned int reg)
 +{
 +      return _hypercall1(unsigned long, get_debugreg, reg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_update_descriptor(
 +      u64 ma, u64 desc)
 +{
 +      return _hypercall4(int, update_descriptor, ma, ma>>32, desc, desc>>32);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_memory_op(
 +      unsigned int cmd, void *arg)
 +{
 +      return _hypercall2(int, memory_op, cmd, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_multicall(
-+      multicall_entry_t *call_list, int nr_calls)
++      multicall_entry_t *call_list, unsigned int nr_calls)
 +{
 +      return _hypercall2(int, multicall, call_list, nr_calls);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_update_va_mapping(
 +      unsigned long va, pte_t new_val, unsigned long flags)
 +{
@@ -109789,7 +174650,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +                         new_val.pte_low, pte_hi, flags);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_event_channel_op(
 +      int cmd, void *arg)
 +{
@@ -109808,28 +174669,28 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      return rc;
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_acm_op(
 +      int cmd, void *arg)
 +{
 +      return _hypercall2(int, acm_op, cmd, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_xen_version(
 +      int cmd, void *arg)
 +{
 +      return _hypercall2(int, xen_version, cmd, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_console_io(
-+      int cmd, int count, char *str)
++      int cmd, unsigned int count, char *str)
 +{
 +      return _hypercall3(int, console_io, cmd, count, str);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_physdev_op(
 +      int cmd, void *arg)
 +{
@@ -109848,14 +174709,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      return rc;
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_grant_table_op(
 +      unsigned int cmd, void *uop, unsigned int count)
 +{
 +      return _hypercall3(int, grant_table_op, cmd, uop, count);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_update_va_mapping_otherdomain(
 +      unsigned long va, pte_t new_val, unsigned long flags, domid_t domid)
 +{
@@ -109867,21 +174728,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +                         new_val.pte_low, pte_hi, flags, domid);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_vm_assist(
 +      unsigned int cmd, unsigned int type)
 +{
 +      return _hypercall2(int, vm_assist, cmd, type);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_vcpu_op(
-+      int cmd, int vcpuid, void *extra_args)
++      int cmd, unsigned int vcpuid, void *extra_args)
 +{
 +      return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_suspend(
 +      unsigned long srec)
 +{
@@ -109901,35 +174762,39 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      return rc;
 +}
 +
++#if CONFIG_XEN_COMPAT <= 0x030002
 +static inline int
 +HYPERVISOR_nmi_op(
 +      unsigned long op, void *arg)
 +{
 +      return _hypercall2(int, nmi_op, op, arg);
 +}
++#endif
 +
-+static inline unsigned long
++#ifndef CONFIG_XEN
++static inline unsigned long __must_check
 +HYPERVISOR_hvm_op(
 +    int op, void *arg)
 +{
 +    return _hypercall2(unsigned long, hvm_op, op, arg);
 +}
++#endif
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_callback_op(
-+      int cmd, void *arg)
++      int cmd, const void *arg)
 +{
 +      return _hypercall2(int, callback_op, cmd, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_xenoprof_op(
 +      int op, void *arg)
 +{
 +      return _hypercall2(int, xenoprof_op, op, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_kexec_op(
 +      unsigned long op, void *args)
 +{
@@ -109939,10 +174804,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +
 +
 +#endif /* __HYPERCALL_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/hypervisor.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/hypervisor.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/hypervisor.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/hypervisor.h     2007-12-23 11:15:40.231593300 +0100
-@@ -0,0 +1,255 @@
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/hypervisor.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/hypervisor.h     2008-05-19 00:34:07.816055118 +0300
+@@ -0,0 +1,259 @@
 +/******************************************************************************
 + * hypervisor.h
 + * 
@@ -110050,7 +174914,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +void xen_pgd_pin(unsigned long ptr);
 +void xen_pgd_unpin(unsigned long ptr);
 +
-+void xen_set_ldt(unsigned long ptr, unsigned long bytes);
++void xen_set_ldt(const void *ptr, unsigned int ents);
 +
 +#ifdef CONFIG_SMP
 +#include <linux/cpumask.h>
@@ -110075,7 +174939,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +u64 jiffies_to_st(unsigned long jiffies);
 +
 +#ifdef CONFIG_XEN_SCRUB_PAGES
-+#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT)
++void scrub_pages(void *, unsigned int);
 +#else
 +#define scrub_pages(_p,_n) ((void)0)
 +#endif
@@ -110090,7 +174954,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define MULTI_UVMDOMID_INDEX 4
 +#endif
 +
++#ifdef CONFIG_XEN
 +#define is_running_on_xen() 1
++#else
++extern char *hypercall_stubs;
++#define is_running_on_xen() (!!hypercall_stubs)
++#endif
 +
 +static inline int
 +HYPERVISOR_yield(
@@ -110120,7 +174989,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      return rc;
 +}
 +
-+static inline int
++static inline void /*__noreturn*/
 +HYPERVISOR_shutdown(
 +      unsigned int reason)
 +{
@@ -110128,17 +174997,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +              .reason = reason
 +      };
 +
-+      int rc = HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown);
-+
++      VOID(HYPERVISOR_sched_op(SCHEDOP_shutdown, &sched_shutdown));
 +#if CONFIG_XEN_COMPAT <= 0x030002
-+      if (rc == -ENOSYS)
-+              rc = HYPERVISOR_sched_op_compat(SCHEDOP_shutdown, reason);
++      VOID(HYPERVISOR_sched_op_compat(SCHEDOP_shutdown, reason));
 +#endif
-+
-+      return rc;
++      /* Don't recurse needlessly. */
++      BUG_ON(reason != SHUTDOWN_crash);
++      for(;;);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_poll(
 +      evtchn_port_t *ports, unsigned int nr_ports, u64 timeout)
 +{
@@ -110198,9 +175066,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#endif
 +
 +#endif /* __HYPERVISOR_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/io.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/io.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/io.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/io.h     2007-12-23 11:15:40.231593300 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/io.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/io.h     2008-05-19 00:34:07.816055118 +0300
 @@ -0,0 +1,389 @@
 +#ifndef _ASM_IO_H
 +#define _ASM_IO_H
@@ -110591,9 +175458,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define ARCH_HAS_DEV_MEM
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/irqflags.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/irqflags.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/irqflags.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/irqflags.h       2007-12-23 11:15:40.231593300 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/irqflags.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/irqflags.h       2008-05-19 00:34:07.816055118 +0300
 @@ -0,0 +1,127 @@
 +/*
 + * include/asm-i386/irqflags.h
@@ -110722,9 +175588,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#endif
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/maddr.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/maddr.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/maddr.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/maddr.h  2007-12-23 11:15:40.234926812 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/maddr.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/maddr.h  2008-05-19 00:34:07.816055118 +0300
 @@ -0,0 +1,193 @@
 +#ifndef _I386_MADDR_H
 +#define _I386_MADDR_H
@@ -110882,6 +175747,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#endif
 +
 +#ifdef CONFIG_X86_PAE
++#define __pte_ma(x)   ((pte_t) { (x), (maddr_t)(x) >> 32 } )
 +static inline pte_t pfn_pte_ma(unsigned long page_nr, pgprot_t pgprot)
 +{
 +      pte_t pte;
@@ -110894,11 +175760,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      return pte;
 +}
 +#else
++#define __pte_ma(x)   ((pte_t) { (x) } )
 +#define pfn_pte_ma(pfn, prot) __pte_ma(((pfn) << PAGE_SHIFT) | pgprot_val(prot))
 +#endif
 +
-+#define __pte_ma(x)   ((pte_t) { (x) } )
-+
 +#else /* !CONFIG_XEN */
 +
 +#define pfn_to_mfn(pfn) (pfn)
@@ -110919,9 +175784,40 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define mfn_to_virt(m)                (__va(mfn_to_pfn(m) << PAGE_SHIFT))
 +
 +#endif /* _I386_MADDR_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/mmu_context.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/mmu_context.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/mmu_context.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/mmu_context.h    2007-12-23 11:15:40.234926812 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/mmu.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/mmu.h    2008-05-19 00:34:07.820055349 +0300
+@@ -0,0 +1,29 @@
++#ifndef __i386_MMU_H
++#define __i386_MMU_H
++
++#include <asm/semaphore.h>
++/*
++ * The i386 doesn't have a mmu context, but
++ * we put the segment information here.
++ *
++ * cpu_vm_mask is used to optimize ldt flushing.
++ */
++typedef struct { 
++      int size;
++      struct semaphore sem;
++      void *ldt;
++      void *vdso;
++#ifdef CONFIG_XEN
++      int has_foreign_mappings;
++#endif
++} mm_context_t;
++
++/* mm/memory.c:exit_mmap hook */
++extern void _arch_exit_mmap(struct mm_struct *mm);
++#define arch_exit_mmap(_mm) _arch_exit_mmap(_mm)
++
++/* kernel/fork.c:dup_mmap hook */
++extern void _arch_dup_mmap(struct mm_struct *mm);
++#define arch_dup_mmap(mm, oldmm) ((void)(oldmm), _arch_dup_mmap(mm))
++
++#endif
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/mmu_context.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/mmu_context.h    2008-05-19 00:34:07.820055349 +0300
 @@ -0,0 +1,108 @@
 +#ifndef __I386_SCHED_H
 +#define __I386_SCHED_H
@@ -111031,43 +175927,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +}
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/mmu.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/mmu.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/mmu.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/mmu.h    2007-12-23 11:15:40.234926812 +0100
-@@ -0,0 +1,29 @@
-+#ifndef __i386_MMU_H
-+#define __i386_MMU_H
-+
-+#include <asm/semaphore.h>
-+/*
-+ * The i386 doesn't have a mmu context, but
-+ * we put the segment information here.
-+ *
-+ * cpu_vm_mask is used to optimize ldt flushing.
-+ */
-+typedef struct { 
-+      int size;
-+      struct semaphore sem;
-+      void *ldt;
-+      void *vdso;
-+#ifdef CONFIG_XEN
-+      int has_foreign_mappings;
-+#endif
-+} mm_context_t;
-+
-+/* mm/memory.c:exit_mmap hook */
-+extern void _arch_exit_mmap(struct mm_struct *mm);
-+#define arch_exit_mmap(_mm) _arch_exit_mmap(_mm)
-+
-+/* kernel/fork.c:dup_mmap hook */
-+extern void _arch_dup_mmap(struct mm_struct *mm);
-+#define arch_dup_mmap(mm, oldmm) ((void)(oldmm), _arch_dup_mmap(mm))
-+
-+#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/page.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/page.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/page.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/page.h   2007-12-23 11:15:40.234926812 +0100
-@@ -0,0 +1,227 @@
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/page.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/page.h   2008-05-19 00:34:07.820055349 +0300
+@@ -0,0 +1,233 @@
 +#ifndef _I386_PAGE_H
 +#define _I386_PAGE_H
 +
@@ -111097,6 +175959,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 + * below. The preprocessor will warn if the two definitions aren't identical.
 + */
 +#define _PAGE_PRESENT 0x001
++#define _PAGE_IO      0x200
 +
 +#ifndef __ASSEMBLY__
 +
@@ -111144,8 +176007,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +typedef struct { unsigned long long pgprot; } pgprot_t;
 +#define pgprot_val(x) ((x).pgprot)
 +#include <asm/maddr.h>
-+#define __pte(x) ({ unsigned long long _x = (x);        \
-+    if (_x & _PAGE_PRESENT) _x = pte_phys_to_machine(_x);   \
++#define __pte(x) ({ unsigned long long _x = (x);                      \
++    if ((_x & (_PAGE_PRESENT|_PAGE_IO)) == _PAGE_PRESENT)             \
++        _x = pte_phys_to_machine(_x);                                 \
 +    ((pte_t) {(unsigned long)(_x), (unsigned long)(_x>>32)}); })
 +#define __pgd(x) ({ unsigned long long _x = (x); \
 +    (pgd_t) {((_x) & _PAGE_PRESENT) ? pte_phys_to_machine(_x) : (_x)}; })
@@ -111158,7 +176022,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +static inline unsigned long long pte_val(pte_t x)
 +{
 +      unsigned long long ret = __pte_val(x);
-+      if (x.pte_low & _PAGE_PRESENT) ret = pte_machine_to_phys(ret);
++      if ((x.pte_low & (_PAGE_PRESENT|_PAGE_IO)) == _PAGE_PRESENT)
++              ret = pte_machine_to_phys(ret);
 +      return ret;
 +}
 +#define __pmd_val(x) ((x).pmd)
@@ -111189,11 +176054,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#include <asm/maddr.h>
 +#define boot_pte_t pte_t /* or would you rather have a typedef */
 +#define __pte_val(x) ((x).pte_low)
-+#define pte_val(x) (__pte_val(x) & _PAGE_PRESENT ? \
-+                    machine_to_phys(__pte_val(x)) : \
-+                    __pte_val(x))
-+#define __pte(x) ({ unsigned long _x = (x); \
-+    (pte_t) {((_x) & _PAGE_PRESENT) ? phys_to_machine(_x) : (_x)}; })
++#define pte_val(x) ((__pte_val(x) & (_PAGE_PRESENT|_PAGE_IO)) \
++                  == _PAGE_PRESENT ?                          \
++                  machine_to_phys(__pte_val(x)) :             \
++                  __pte_val(x))
++#define __pte(x) ({ unsigned long _x = (x);                   \
++    if ((_x & (_PAGE_PRESENT|_PAGE_IO)) == _PAGE_PRESENT)     \
++        _x = phys_to_machine(_x);                             \
++    ((pte_t) { _x }); })
 +#define __pmd_val(x) __pud_val((x).pud)
 +#define __pud_val(x) __pgd_val((x).pgd)
 +#define __pgd(x) ({ unsigned long _x = (x); \
@@ -111295,9 +176163,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#endif /* __KERNEL__ */
 +
 +#endif /* _I386_PAGE_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/pci.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pci.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/pci.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pci.h    2007-12-23 11:15:40.234926812 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/pci.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pci.h    2008-05-19 00:34:07.820055349 +0300
 @@ -0,0 +1,148 @@
 +#ifndef __i386_PCI_H
 +#define __i386_PCI_H
@@ -111447,9 +176314,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#include <asm-generic/pci.h>
 +
 +#endif /* __i386_PCI_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/pgalloc.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgalloc.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/pgalloc.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgalloc.h        2007-12-23 11:15:40.234926812 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/pgalloc.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgalloc.h        2008-05-19 00:34:07.820055349 +0300
 @@ -0,0 +1,59 @@
 +#ifndef _I386_PGALLOC_H
 +#define _I386_PGALLOC_H
@@ -111510,9 +176376,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define check_pgt_cache()     do { } while (0)
 +
 +#endif /* _I386_PGALLOC_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h    2007-12-23 11:15:40.238260322 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-2level-defs.h    2008-05-19 00:34:07.824055579 +0300
 @@ -0,0 +1,20 @@
 +#ifndef _I386_PGTABLE_2LEVEL_DEFS_H
 +#define _I386_PGTABLE_2LEVEL_DEFS_H
@@ -111534,10 +176399,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define PTRS_PER_PTE  1024
 +
 +#endif /* _I386_PGTABLE_2LEVEL_DEFS_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/pgtable-2level.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-2level.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/pgtable-2level.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-2level.h 2007-12-23 11:15:40.238260322 +0100
-@@ -0,0 +1,119 @@
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/pgtable-2level.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-2level.h 2008-05-19 00:34:07.824055579 +0300
+@@ -0,0 +1,121 @@
 +#ifndef _I386_PGTABLE_2LEVEL_H
 +#define _I386_PGTABLE_2LEVEL_H
 +
@@ -111611,8 +176475,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define __pte_mfn(_pte) ((_pte).pte_low >> PAGE_SHIFT)
 +#define pte_mfn(_pte) ((_pte).pte_low & _PAGE_PRESENT ? \
 +      __pte_mfn(_pte) : pfn_to_mfn(__pte_mfn(_pte)))
-+#define pte_pfn(_pte) ((_pte).pte_low & _PAGE_PRESENT ? \
-+      mfn_to_local_pfn(__pte_mfn(_pte)) : __pte_mfn(_pte))
++#define pte_pfn(_pte) ((_pte).pte_low & _PAGE_IO ? max_mapnr :        \
++                     (_pte).pte_low & _PAGE_PRESENT ?         \
++                     mfn_to_local_pfn(__pte_mfn(_pte)) :      \
++                     __pte_mfn(_pte))
 +
 +#define pte_page(_pte) pfn_to_page(pte_pfn(_pte))
 +
@@ -111657,9 +176523,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +void vmalloc_sync_all(void);
 +
 +#endif /* _I386_PGTABLE_2LEVEL_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h    2007-12-23 11:15:40.238260322 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-3level-defs.h    2008-05-19 00:34:07.824055579 +0300
 @@ -0,0 +1,24 @@
 +#ifndef _I386_PGTABLE_3LEVEL_DEFS_H
 +#define _I386_PGTABLE_3LEVEL_DEFS_H
@@ -111685,10 +176550,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define PTRS_PER_PTE  512
 +
 +#endif /* _I386_PGTABLE_3LEVEL_DEFS_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/pgtable-3level.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-3level.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/pgtable-3level.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-3level.h 2007-12-23 11:15:40.238260322 +0100
-@@ -0,0 +1,209 @@
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/pgtable-3level.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable-3level.h 2008-05-19 00:34:07.824055579 +0300
+@@ -0,0 +1,211 @@
 +#ifndef _I386_PGTABLE_3LEVEL_H
 +#define _I386_PGTABLE_3LEVEL_H
 +
@@ -111861,8 +176725,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +                       ((_pte).pte_high << (32-PAGE_SHIFT)))
 +#define pte_mfn(_pte) ((_pte).pte_low & _PAGE_PRESENT ? \
 +      __pte_mfn(_pte) : pfn_to_mfn(__pte_mfn(_pte)))
-+#define pte_pfn(_pte) ((_pte).pte_low & _PAGE_PRESENT ? \
-+      mfn_to_local_pfn(__pte_mfn(_pte)) : __pte_mfn(_pte))
++#define pte_pfn(_pte) ((_pte).pte_low & _PAGE_IO ? max_mapnr :        \
++                     (_pte).pte_low & _PAGE_PRESENT ?         \
++                     mfn_to_local_pfn(__pte_mfn(_pte)) :      \
++                     __pte_mfn(_pte))
 +
 +extern unsigned long long __supported_pte_mask;
 +
@@ -111898,10 +176764,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +void vmalloc_sync_all(void);
 +
 +#endif /* _I386_PGTABLE_3LEVEL_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/pgtable.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/pgtable.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable.h        2007-12-23 11:15:40.238260322 +0100
-@@ -0,0 +1,531 @@
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/pgtable.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/pgtable.h        2008-05-19 00:34:07.828055810 +0300
+@@ -0,0 +1,537 @@
 +#ifndef _I386_PGTABLE_H
 +#define _I386_PGTABLE_H
 +
@@ -112009,7 +176874,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define _PAGE_BIT_DIRTY               6
 +#define _PAGE_BIT_PSE         7       /* 4 MB (or 2MB) page, Pentium+, if present.. */
 +#define _PAGE_BIT_GLOBAL      8       /* Global TLB entry PPro+ */
-+#define _PAGE_BIT_UNUSED1     9       /* available for programmer */
++/*#define _PAGE_BIT_UNUSED1   9*/     /* available for programmer */
 +#define _PAGE_BIT_UNUSED2     10
 +#define _PAGE_BIT_UNUSED3     11
 +#define _PAGE_BIT_NX          63
@@ -112023,7 +176888,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define _PAGE_DIRTY   0x040
 +#define _PAGE_PSE     0x080   /* 4 MB (or 2MB) page, Pentium+, if present.. */
 +#define _PAGE_GLOBAL  0x100   /* Global TLB entry PPro+ */
-+#define _PAGE_UNUSED1 0x200   /* available for programmer */
++/*#define _PAGE_UNUSED1       0x200*/ /* available for programmer */
 +#define _PAGE_UNUSED2 0x400
 +#define _PAGE_UNUSED3 0x800
 +
@@ -112037,9 +176902,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define _PAGE_NX      0
 +#endif
 +
++/* Mapped page is I/O or foreign and has no associated page struct. */
++#define _PAGE_IO      0x200
++
 +#define _PAGE_TABLE   (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 +#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY)
-+#define _PAGE_CHG_MASK        (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
++#define _PAGE_CHG_MASK        (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_IO)
 +
 +#define PAGE_NONE \
 +      __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
@@ -112378,19 +177246,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +void make_pages_readonly(void *va, unsigned int nr, unsigned int feature);
 +void make_pages_writable(void *va, unsigned int nr, unsigned int feature);
 +
-+#define virt_to_ptep(__va)                                            \
++#define virt_to_ptep(va)                                              \
 +({                                                                    \
-+      pgd_t *__pgd = pgd_offset_k((unsigned long)(__va));             \
-+      pud_t *__pud = pud_offset(__pgd, (unsigned long)(__va));        \
-+      pmd_t *__pmd = pmd_offset(__pud, (unsigned long)(__va));        \
-+      pte_offset_kernel(__pmd, (unsigned long)(__va));                \
++      pte_t *__ptep = lookup_address((unsigned long)(va));            \
++      BUG_ON(!__ptep || !pte_present(*__ptep));                       \
++      __ptep;                                                         \
 +})
 +
-+#define arbitrary_virt_to_machine(__va)                                       \
-+({                                                                    \
-+      maddr_t m = (maddr_t)pte_mfn(*virt_to_ptep(__va)) << PAGE_SHIFT;\
-+      m | ((unsigned long)(__va) & (PAGE_SIZE-1));                    \
-+})
++#define arbitrary_virt_to_machine(va)                                 \
++      (((maddr_t)pte_mfn(*virt_to_ptep(va)) << PAGE_SHIFT)            \
++       | ((unsigned long)(va) & (PAGE_SIZE - 1)))
 +
 +#endif /* !__ASSEMBLY__ */
 +
@@ -112416,6 +177281,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +                    unsigned long address,
 +                    unsigned long size);
 +
++int xen_change_pte_range(struct mm_struct *mm, pmd_t *pmd,
++              unsigned long addr, unsigned long end, pgprot_t newprot);
++
++#define arch_change_pte_range(mm, pmd, addr, end, newprot)    \
++              xen_change_pte_range(mm, pmd, addr, end, newprot)
++
 +#define io_remap_pfn_range(vma,from,pfn,size,prot) \
 +direct_remap_pfn_range(vma,from,pfn,size,prot,DOMID_IO)
 +
@@ -112433,10 +177304,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#include <asm-generic/pgtable.h>
 +
 +#endif /* _I386_PGTABLE_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/processor.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/processor.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/processor.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/processor.h      2007-12-23 11:15:40.238260322 +0100
-@@ -0,0 +1,741 @@
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/processor.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/processor.h      2008-05-19 00:34:07.828055810 +0300
+@@ -0,0 +1,743 @@
 +/*
 + * include/asm-i386/processor.h
 + *
@@ -112952,8 +177822,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define load_esp0(tss, thread) \
 +      __load_esp0(tss, thread)
 +#else
-+#define load_esp0(tss, thread) \
-+      HYPERVISOR_stack_switch(__KERNEL_DS, (thread)->esp0)
++#define load_esp0(tss, thread) do { \
++      if (HYPERVISOR_stack_switch(__KERNEL_DS, (thread)->esp0)) \
++              BUG(); \
++} while (0)
 +#endif
 +
 +#define start_thread(regs, new_eip, new_esp) do {             \
@@ -112973,7 +177845,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define get_debugreg(var, register)                           \
 +              (var) = HYPERVISOR_get_debugreg((register))
 +#define set_debugreg(value, register)                 \
-+              HYPERVISOR_set_debugreg((register), (value))
++              WARN_ON(HYPERVISOR_set_debugreg((register), (value)))
 +
 +/*
 + * Set IOPL bits in EFLAGS from given mask
@@ -112984,7 +177856,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +
 +      /* Force the change at ring 0. */
 +      set_iopl.iopl = (mask == 0) ? 1 : (mask >> 12) & 3;
-+      HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl);
++      WARN_ON(HYPERVISOR_physdev_op(PHYSDEVOP_set_iopl, &set_iopl));
 +}
 +
 +/* Forward declaration, a strange C thing */
@@ -113178,9 +178050,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +extern int sysenter_setup(void);
 +
 +#endif /* __ASM_I386_PROCESSOR_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/ptrace.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/ptrace.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/ptrace.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/ptrace.h 2007-12-23 11:15:40.238260322 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/ptrace.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/ptrace.h 2008-05-19 00:34:07.828055810 +0300
 @@ -0,0 +1,90 @@
 +#ifndef _I386_PTRACE_H
 +#define _I386_PTRACE_H
@@ -113272,9 +178143,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#endif /* __KERNEL__ */
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/scatterlist.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/scatterlist.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/scatterlist.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/scatterlist.h    2007-12-23 11:15:40.241593831 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/scatterlist.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/scatterlist.h    2008-05-19 00:34:07.832056040 +0300
 @@ -0,0 +1,22 @@
 +#ifndef _I386_SCATTERLIST_H
 +#define _I386_SCATTERLIST_H
@@ -113298,9 +178168,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define ISA_DMA_THRESHOLD (0x00ffffff)
 +
 +#endif /* !(_I386_SCATTERLIST_H) */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/segment.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/segment.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/segment.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/segment.h        2007-12-23 11:15:40.241593831 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/segment.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/segment.h        2008-05-19 00:34:07.832056040 +0300
 @@ -0,0 +1,117 @@
 +#ifndef _ASM_SEGMENT_H
 +#define _ASM_SEGMENT_H
@@ -113419,9 +178288,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define IDT_ENTRIES 256
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/setup.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/setup.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/setup.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/setup.h  2007-12-23 11:15:40.241593831 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/setup.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/setup.h  2008-05-19 00:34:07.832056040 +0300
 @@ -0,0 +1,81 @@
 +/*
 + *    Just a place holder. We don't want to have to test x86 before
@@ -113504,9 +178372,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#endif /* __ASSEMBLY__ */
 +
 +#endif /* _i386_SETUP_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/smp.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/smp.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/smp.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/smp.h    2007-12-23 11:15:40.241593831 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/smp.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/smp.h    2008-05-19 00:34:07.832056040 +0300
 @@ -0,0 +1,103 @@
 +#ifndef __ASM_SMP_H
 +#define __ASM_SMP_H
@@ -113611,9 +178478,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +
 +#endif
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/spinlock.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/spinlock.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/spinlock.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/spinlock.h       2007-12-23 11:15:40.241593831 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/spinlock.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/spinlock.h       2008-05-19 00:34:07.836056271 +0300
 @@ -0,0 +1,202 @@
 +#ifndef __ASM_SPINLOCK_H
 +#define __ASM_SPINLOCK_H
@@ -113817,9 +178683,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +}
 +
 +#endif /* __ASM_SPINLOCK_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/swiotlb.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/swiotlb.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/swiotlb.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/swiotlb.h        2007-12-23 11:15:40.241593831 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/swiotlb.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/swiotlb.h        2008-05-19 00:34:07.836056271 +0300
 @@ -0,0 +1,43 @@
 +#ifndef _ASM_SWIOTLB_H
 +#define _ASM_SWIOTLB_H 1
@@ -113864,10 +178729,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#endif
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/synch_bitops.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/synch_bitops.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/synch_bitops.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/synch_bitops.h   2007-12-23 11:15:40.244927335 +0100
-@@ -0,0 +1,145 @@
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/synch_bitops.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/synch_bitops.h   2008-05-19 00:34:07.836056271 +0300
+@@ -0,0 +1,126 @@
 +#ifndef __XEN_SYNCH_BITOPS_H__
 +#define __XEN_SYNCH_BITOPS_H__
 +
@@ -113989,33 +178853,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +      return old;
 +}
 +
-+static __always_inline int synch_const_test_bit(int nr,
-+                                              const volatile void * addr)
-+{
-+    return ((1UL << (nr & 31)) & 
-+            (((const volatile unsigned int *) addr)[nr >> 5])) != 0;
-+}
-+
-+static __inline__ int synch_var_test_bit(int nr, volatile void * addr)
-+{
-+    int oldbit;
-+    __asm__ __volatile__ (
-+        "btl %2,%1\n\tsbbl %0,%0"
-+        : "=r" (oldbit) : "m" (ADDR), "Ir" (nr) );
-+    return oldbit;
-+}
-+
-+#define synch_test_bit(nr,addr) \
-+(__builtin_constant_p(nr) ? \
-+ synch_const_test_bit((nr),(addr)) : \
-+ synch_var_test_bit((nr),(addr)))
++#define synch_test_bit test_bit
 +
 +#define synch_cmpxchg_subword synch_cmpxchg
 +
 +#endif /* __XEN_SYNCH_BITOPS_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/system.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/system.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/system.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/system.h 2007-12-23 11:15:40.244927335 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/system.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/system.h 2008-05-19 00:34:07.836056271 +0300
 @@ -0,0 +1,488 @@
 +#ifndef __ASM_SYSTEM_H
 +#define __ASM_SYSTEM_H
@@ -114505,9 +179349,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +void default_idle(void);
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/tlbflush.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/tlbflush.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/tlbflush.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/tlbflush.h       2007-12-23 11:15:40.244927335 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/tlbflush.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/tlbflush.h       2008-05-19 00:34:07.840056501 +0300
 @@ -0,0 +1,101 @@
 +#ifndef _I386_TLBFLUSH_H
 +#define _I386_TLBFLUSH_H
@@ -114610,9 +179453,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +}
 +
 +#endif /* _I386_TLBFLUSH_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/vga.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/vga.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/vga.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/vga.h    2007-12-23 11:15:40.244927335 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/vga.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/vga.h    2008-05-19 00:34:07.840056501 +0300
 @@ -0,0 +1,20 @@
 +/*
 + *    Access to VGA videoram
@@ -114634,9 +179476,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define vga_writeb(x,y) (*(y) = (x))
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/asm/xenoprof.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/xenoprof.h
---- linux-2.6.18/include/asm-i386/mach-xen/asm/xenoprof.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/xenoprof.h       2007-12-23 11:15:40.244927335 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/asm/xenoprof.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/asm/xenoprof.h       2008-05-19 00:34:07.840056501 +0300
 @@ -0,0 +1,48 @@
 +/******************************************************************************
 + * asm-i386/mach-xen/asm/xenoprof.h
@@ -114686,9 +179527,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +
 +#endif /* CONFIG_XEN */
 +#endif /* __ASM_XENOPROF_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/irq_vectors.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/irq_vectors.h
---- linux-2.6.18/include/asm-i386/mach-xen/irq_vectors.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/irq_vectors.h        2007-12-23 11:15:40.244927335 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/irq_vectors.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/irq_vectors.h        2008-05-19 00:34:07.840056501 +0300
 @@ -0,0 +1,125 @@
 +/*
 + * This file should contain #defines for all of the interrupt vector
@@ -114815,9 +179655,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +#define irq_to_dynirq(_x)     ((_x) - DYNIRQ_BASE)
 +
 +#endif /* _ASM_IRQ_VECTORS_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/mach_traps.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/mach_traps.h
---- linux-2.6.18/include/asm-i386/mach-xen/mach_traps.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/mach_traps.h 2007-12-23 11:15:40.244927335 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/mach_traps.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/mach_traps.h 2008-05-19 00:34:07.844056732 +0300
 @@ -0,0 +1,33 @@
 +/*
 + *  include/asm-xen/asm-i386/mach-xen/mach_traps.h
@@ -114852,18 +179691,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xe
 +static inline void reassert_nmi(void) {}
 +
 +#endif /* !_MACH_TRAPS_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/mach-xen/setup_arch.h linux-2.6.18-xen.hg/include/asm-i386/mach-xen/setup_arch.h
---- linux-2.6.18/include/asm-i386/mach-xen/setup_arch.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/setup_arch.h 2007-12-23 11:15:40.248260841 +0100
+--- linux-2.6.18.8/include/asm-i386/mach-xen/setup_arch.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/mach-xen/setup_arch.h 2008-05-19 00:34:07.844056732 +0300
 @@ -0,0 +1,5 @@
 +/* Hook to call BIOS initialisation function */
 +
 +#define ARCH_SETUP machine_specific_arch_setup();
 +
 +void __init machine_specific_arch_setup(void);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/page.h linux-2.6.18-xen.hg/include/asm-i386/page.h
---- linux-2.6.18/include/asm-i386/page.h       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-i386/page.h        2007-12-23 11:15:40.258261372 +0100
+--- linux-2.6.18.8/include/asm-i386/page.h     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/page.h        2008-05-19 00:34:07.864057885 +0300
 @@ -122,7 +122,7 @@
  
  #define PAGE_OFFSET           ((unsigned long)__PAGE_OFFSET)
@@ -114873,9 +179710,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/page.h
  #define __pa(x)                       ((unsigned long)(x)-PAGE_OFFSET)
  #define __va(x)                       ((void *)((unsigned long)(x)+PAGE_OFFSET))
  #define pfn_to_kaddr(pfn)      __va((pfn) << PAGE_SHIFT)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/pgtable-2level-defs.h linux-2.6.18-xen.hg/include/asm-i386/pgtable-2level-defs.h
---- linux-2.6.18/include/asm-i386/pgtable-2level-defs.h        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-i386/pgtable-2level-defs.h 2007-12-23 11:15:40.261594879 +0100
+--- linux-2.6.18.8/include/asm-i386/pgtable-2level-defs.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/pgtable-2level-defs.h 2008-05-19 00:34:07.964063649 +0300
 @@ -1,6 +1,8 @@
  #ifndef _I386_PGTABLE_2LEVEL_DEFS_H
  #define _I386_PGTABLE_2LEVEL_DEFS_H
@@ -114885,9 +179721,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/pgtable
  /*
   * traditional i386 two-level paging structure:
   */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/pgtable-3level-defs.h linux-2.6.18-xen.hg/include/asm-i386/pgtable-3level-defs.h
---- linux-2.6.18/include/asm-i386/pgtable-3level-defs.h        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-i386/pgtable-3level-defs.h 2007-12-23 11:15:40.261594879 +0100
+--- linux-2.6.18.8/include/asm-i386/pgtable-3level-defs.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-i386/pgtable-3level-defs.h 2008-05-19 00:34:07.968063880 +0300
 @@ -1,6 +1,8 @@
  #ifndef _I386_PGTABLE_3LEVEL_DEFS_H
  #define _I386_PGTABLE_3LEVEL_DEFS_H
@@ -114897,9 +179732,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-i386/pgtable
  /*
   * PGDIR_SHIFT determines what a top-level page table entry can map
   */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/agp.h linux-2.6.18-xen.hg/include/asm-ia64/agp.h
---- linux-2.6.18/include/asm-ia64/agp.h        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/agp.h 2007-12-23 11:15:40.298263470 +0100
+--- linux-2.6.18.8/include/asm-ia64/agp.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/agp.h 2008-05-19 00:34:08.200077254 +0300
 @@ -19,13 +19,44 @@
  #define flush_agp_cache()             mb()
  
@@ -114945,9 +179779,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/agp.h l
 +#endif /* CONFIG_XEN */
  
  #endif /* _ASM_IA64_AGP_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/gcc_intrin.h linux-2.6.18-xen.hg/include/asm-ia64/gcc_intrin.h
---- linux-2.6.18/include/asm-ia64/gcc_intrin.h 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/gcc_intrin.h  2007-12-23 11:15:40.311597505 +0100
+--- linux-2.6.18.8/include/asm-ia64/gcc_intrin.h       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/gcc_intrin.h  2008-05-19 00:34:08.652103309 +0300
 @@ -26,7 +26,7 @@
  
  register unsigned long ia64_r13 asm ("r13") __attribute_used__;
@@ -115137,9 +179970,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/gcc_int
 +#define __ia64_get_psr_i()    (__ia64_getreg(_IA64_REG_PSR) & 0x4000UL)
 +
  #endif /* _ASM_IA64_GCC_INTRIN_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/gnttab_dma.h linux-2.6.18-xen.hg/include/asm-ia64/gnttab_dma.h
---- linux-2.6.18/include/asm-ia64/gnttab_dma.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/gnttab_dma.h  2007-12-23 11:15:40.311597505 +0100
+--- linux-2.6.18.8/include/asm-ia64/gnttab_dma.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/gnttab_dma.h  2008-05-19 00:34:08.652103309 +0300
 @@ -0,0 +1,51 @@
 +/*
 + * Copyright (c) 2007 Herbert Xu <herbert@gondor.apana.org.au>
@@ -115192,9 +180024,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/gnttab_
 +}
 +
 +#endif /* _ASM_IA64_GNTTAB_DMA_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/hw_irq.h linux-2.6.18-xen.hg/include/asm-ia64/hw_irq.h
---- linux-2.6.18/include/asm-ia64/hw_irq.h     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/hw_irq.h      2007-12-23 11:15:40.314931012 +0100
+--- linux-2.6.18.8/include/asm-ia64/hw_irq.h   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/hw_irq.h      2008-05-19 00:34:08.652103309 +0300
 @@ -15,7 +15,11 @@
  #include <asm/ptrace.h>
  #include <asm/smp.h>
@@ -115220,9 +180051,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/hw_irq.
        platform_send_ipi(smp_processor_id(), vector, IA64_IPI_DM_INT, 0);
  }
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/hypercall.h linux-2.6.18-xen.hg/include/asm-ia64/hypercall.h
---- linux-2.6.18/include/asm-ia64/hypercall.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/hypercall.h   2007-12-23 11:15:40.314931012 +0100
+--- linux-2.6.18.8/include/asm-ia64/hypercall.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/hypercall.h   2008-05-19 00:34:08.656103540 +0300
 @@ -0,0 +1,458 @@
 +/******************************************************************************
 + * hypercall.h
@@ -115682,9 +180512,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/hyperca
 +#define HYPERVISOR_mmu_update(req, count, success_count, domid) ({BUG();0;})
 +
 +#endif /* __HYPERCALL_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/hypervisor.h linux-2.6.18-xen.hg/include/asm-ia64/hypervisor.h
---- linux-2.6.18/include/asm-ia64/hypervisor.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/hypervisor.h  2007-12-23 11:15:40.314931012 +0100
+--- linux-2.6.18.8/include/asm-ia64/hypervisor.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/hypervisor.h  2008-05-19 00:34:08.656103540 +0300
 @@ -0,0 +1,233 @@
 +/******************************************************************************
 + * hypervisor.h
@@ -115805,7 +180634,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/hypervi
 +}
 +
 +#ifndef CONFIG_VMX_GUEST
-+// for drivers/xen/privcmd/privcmd.c
++/* for drivers/xen/privcmd/privcmd.c */
 +#define machine_to_phys_mapping 0
 +struct vm_area_struct;
 +int direct_remap_pfn_range(struct vm_area_struct *vma,
@@ -115819,7 +180648,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/hypervi
 +int privcmd_mmap(struct file * file, struct vm_area_struct * vma);
 +#define HAVE_ARCH_PRIVCMD_MMAP
 +
-+// for drivers/xen/balloon/balloon.c
++/* for drivers/xen/balloon/balloon.c */
 +#ifdef CONFIG_XEN_SCRUB_PAGES
 +#define scrub_pages(_p,_n) memset((void *)(_p), 0, (_n) << PAGE_SHIFT)
 +#else
@@ -115866,8 +180695,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/hypervi
 +#define __pte_ma(_x)  ((pte_t) {(_x)})        /* unmodified use */
 +#define pfn_pte_ma(_x,_y)     __pte_ma(0)     /* unmodified use */
 +
-+// for netfront.c, netback.c
-+#define MULTI_UVMFLAGS_INDEX 0 //XXX any value
++/* for netfront.c, netback.c */
++#define MULTI_UVMFLAGS_INDEX 0 /* XXX any value */
 +
 +static inline void
 +MULTI_update_va_mapping(
@@ -115904,7 +180733,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/hypervi
 +              (-ENOSYS);                                              \
 +      })
 +
-+// for debug
++/* for debug */
 +asmlinkage int xprintk(const char *fmt, ...);
 +#define xprintd(fmt, ...)     xprintk("%s:%d " fmt, __func__, __LINE__, \
 +                                      ##__VA_ARGS__)
@@ -115919,9 +180748,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/hypervi
 +#endif
 +
 +#endif /* __HYPERVISOR_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/intel_intrin.h linux-2.6.18-xen.hg/include/asm-ia64/intel_intrin.h
---- linux-2.6.18/include/asm-ia64/intel_intrin.h       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/intel_intrin.h        2007-12-23 11:15:40.314931012 +0100
+--- linux-2.6.18.8/include/asm-ia64/intel_intrin.h     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/intel_intrin.h        2008-05-19 00:34:08.660103770 +0300
 @@ -16,8 +16,8 @@
                         * intrinsic
                         */
@@ -116043,9 +180871,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/intel_i
  #define __builtin_trap()      __break(0);
  
  #endif /* _ASM_IA64_INTEL_INTRIN_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/intrinsics.h linux-2.6.18-xen.hg/include/asm-ia64/intrinsics.h
---- linux-2.6.18/include/asm-ia64/intrinsics.h 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/intrinsics.h  2007-12-23 11:15:40.318264518 +0100
+--- linux-2.6.18.8/include/asm-ia64/intrinsics.h       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/intrinsics.h  2008-05-19 00:34:08.660103770 +0300
 @@ -18,6 +18,15 @@
  # include <asm/gcc_intrin.h>
  #endif
@@ -116068,9 +180895,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/intrins
  #endif
 +#include <asm/privop.h>
  #endif /* _ASM_IA64_INTRINSICS_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/io.h linux-2.6.18-xen.hg/include/asm-ia64/io.h
---- linux-2.6.18/include/asm-ia64/io.h 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/io.h  2007-12-23 11:15:40.318264518 +0100
+--- linux-2.6.18.8/include/asm-ia64/io.h       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/io.h  2008-05-19 00:34:08.664104001 +0300
 @@ -96,9 +96,39 @@
   * The following two macros are deprecated and scheduled for removal.
   * Please use the PCI-DMA interface defined in <asm/pci.h> instead.
@@ -116111,9 +180937,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/io.h li
  
  # endif /* KERNEL */
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/iosapic.h linux-2.6.18-xen.hg/include/asm-ia64/iosapic.h
---- linux-2.6.18/include/asm-ia64/iosapic.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/iosapic.h     2007-12-23 11:15:40.318264518 +0100
+--- linux-2.6.18.8/include/asm-ia64/iosapic.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/iosapic.h     2008-05-19 00:34:08.664104001 +0300
 @@ -53,6 +53,7 @@
  
  #define NR_IOSAPICS                   256
@@ -116130,9 +180955,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/iosapic
  
  static inline void iosapic_eoi(char __iomem *iosapic, u32 vector)
  {
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/irq.h linux-2.6.18-xen.hg/include/asm-ia64/irq.h
---- linux-2.6.18/include/asm-ia64/irq.h        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/irq.h 2007-12-23 11:15:40.318264518 +0100
+--- linux-2.6.18.8/include/asm-ia64/irq.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/irq.h 2008-05-19 00:34:08.668104231 +0300
 @@ -11,8 +11,41 @@
   * 02/29/00     D.Mosberger   moved most things into hw_irq.h
   */
@@ -116175,9 +180999,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/irq.h l
  
  static __inline__ int
  irq_canonicalize (int irq)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/kexec.h linux-2.6.18-xen.hg/include/asm-ia64/kexec.h
---- linux-2.6.18/include/asm-ia64/kexec.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/kexec.h       2007-12-23 11:15:40.321598027 +0100
+--- linux-2.6.18.8/include/asm-ia64/kexec.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/kexec.h       2008-05-19 00:34:08.668104231 +0300
 @@ -0,0 +1,58 @@
 +#ifndef _ASM_IA64_KEXEC_H
 +#define _ASM_IA64_KEXEC_H
@@ -116237,9 +181060,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/kexec.h
 +#endif
 +
 +#endif /* _ASM_IA64_KEXEC_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/machvec.h linux-2.6.18-xen.hg/include/asm-ia64/machvec.h
---- linux-2.6.18/include/asm-ia64/machvec.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/machvec.h     2007-12-23 11:15:40.324931536 +0100
+--- linux-2.6.18.8/include/asm-ia64/machvec.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/machvec.h     2008-05-19 00:34:08.676104693 +0300
 @@ -35,6 +35,7 @@
  typedef int ia64_mv_pci_legacy_write_t (struct pci_bus *, u16 port, u32 val,
                                        u8 size);
@@ -116275,9 +181097,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/machvec
  #ifndef platform_dma_init
  # define platform_dma_init            swiotlb_init
  #endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/machvec_sn2.h linux-2.6.18-xen.hg/include/asm-ia64/machvec_sn2.h
---- linux-2.6.18/include/asm-ia64/machvec_sn2.h        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/machvec_sn2.h 2007-12-23 11:15:40.324931536 +0100
+--- linux-2.6.18.8/include/asm-ia64/machvec_sn2.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/machvec_sn2.h 2008-05-19 00:34:08.700106076 +0300
 @@ -67,6 +67,7 @@
  extern ia64_mv_dma_mapping_error      sn_dma_mapping_error;
  extern ia64_mv_dma_supported          sn_dma_supported;
@@ -116294,9 +181115,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/machvec
  #ifdef CONFIG_PCI_MSI
  #define platform_msi_init             sn_msi_init
  #else
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/machvec_xen.h linux-2.6.18-xen.hg/include/asm-ia64/machvec_xen.h
---- linux-2.6.18/include/asm-ia64/machvec_xen.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/machvec_xen.h 2007-12-23 11:15:40.328265047 +0100
+--- linux-2.6.18.8/include/asm-ia64/machvec_xen.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/machvec_xen.h 2008-05-19 00:34:08.704106307 +0300
 @@ -0,0 +1,43 @@
 +#ifndef _ASM_IA64_MACHVEC_XEN_h
 +#define _ASM_IA64_MACHVEC_XEN_h
@@ -116341,9 +181161,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/machvec
 +#define platform_dma_mapping_error            xen_dma_mapping_error
 +
 +#endif /* _ASM_IA64_MACHVEC_XEN_h */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/maddr.h linux-2.6.18-xen.hg/include/asm-ia64/maddr.h
---- linux-2.6.18/include/asm-ia64/maddr.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/maddr.h       2007-12-23 11:15:40.328265047 +0100
+--- linux-2.6.18.8/include/asm-ia64/maddr.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/maddr.h       2008-05-19 00:34:08.704106307 +0300
 @@ -0,0 +1,126 @@
 +#ifndef _ASM_IA64_MADDR_H
 +#define _ASM_IA64_MADDR_H
@@ -116378,8 +181197,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/maddr.h
 +      if (p2m_initialized)
 +              return p2m_phystomach(pfn);
 +      mfn = HYPERVISOR_phystomach(pfn);
-+      BUG_ON(mfn == 0); // XXX
-+      BUG_ON(mfn == INVALID_P2M_ENTRY); // XXX
++      BUG_ON(mfn == 0); /* XXX */
++      BUG_ON(mfn == INVALID_P2M_ENTRY); /* XXX */
 +      BUG_ON(mfn == INVALID_MFN);
 +      return mfn;
 +}
@@ -116399,7 +181218,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/maddr.h
 +      unsigned long pfn;
 +      pfn = HYPERVISOR_machtophys(mfn);
 +      BUG_ON(pfn == 0);
-+      //BUG_ON(pfn == INVALID_M2P_ENTRY);
++      /* BUG_ON(pfn == INVALID_M2P_ENTRY); */
 +      return pfn;
 +}
 +
@@ -116445,11 +181264,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/maddr.h
 +
 +#define mfn_to_virt(mfn) (__va((mfn) << PAGE_SHIFT))
 +#define virt_to_mfn(virt) (__pa(virt) >> PAGE_SHIFT)
-+#define virt_to_machine(virt) __pa(virt) // for tpmfront.c
++#define virt_to_machine(virt) __pa(virt) /* for tpmfront.c */
 +
 +#define set_phys_to_machine(pfn, mfn) do { } while (0)
 +
-+typedef unsigned long maddr_t;        // to compile netback, netfront
++typedef unsigned long maddr_t;        /* to compile netback, netfront */
 +#ifndef _ASM_IA64_SN_TYPES_H /* paddr_t is defined in asm-ia64/sn/types.h */
 +typedef unsigned long paddr_t;
 +#endif
@@ -116471,9 +181290,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/maddr.h
 +#endif
 +
 +#endif /* _ASM_IA64_MADDR_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/meminit.h linux-2.6.18-xen.hg/include/asm-ia64/meminit.h
---- linux-2.6.18/include/asm-ia64/meminit.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/meminit.h     2007-12-23 11:15:40.328265047 +0100
+--- linux-2.6.18.8/include/asm-ia64/meminit.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/meminit.h     2008-05-19 00:34:08.708106537 +0300
 @@ -15,11 +15,17 @@
   *    - initrd (optional)
   *    - command line string
@@ -116493,9 +181311,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/meminit
  
  struct rsvd_region {
        unsigned long start;    /* virtual address of beginning of element */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/mmu_context.h linux-2.6.18-xen.hg/include/asm-ia64/mmu_context.h
---- linux-2.6.18/include/asm-ia64/mmu_context.h        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/mmu_context.h 2007-12-23 11:15:40.331598554 +0100
+--- linux-2.6.18.8/include/asm-ia64/mmu_context.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/mmu_context.h 2008-05-19 00:34:08.712106768 +0300
 @@ -151,11 +151,7 @@
  #  endif
  #endif
@@ -116509,9 +181326,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/mmu_con
        ia64_srlz_i();                  /* srlz.i implies srlz.d */
  }
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/page.h linux-2.6.18-xen.hg/include/asm-ia64/page.h
---- linux-2.6.18/include/asm-ia64/page.h       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/page.h        2007-12-23 11:15:40.334932060 +0100
+--- linux-2.6.18.8/include/asm-ia64/page.h     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/page.h        2008-05-19 00:34:08.720107229 +0300
 @@ -119,6 +119,7 @@
  #endif
  
@@ -116548,9 +181364,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/page.h
 +
  # endif /* __KERNEL__ */
  #endif /* _ASM_IA64_PAGE_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/pgalloc.h linux-2.6.18-xen.hg/include/asm-ia64/pgalloc.h
---- linux-2.6.18/include/asm-ia64/pgalloc.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/pgalloc.h     2007-12-23 11:15:40.338265569 +0100
+--- linux-2.6.18.8/include/asm-ia64/pgalloc.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/pgalloc.h     2008-05-19 00:34:08.740108382 +0300
 @@ -125,7 +125,11 @@
  static inline void
  pmd_populate(struct mm_struct *mm, pmd_t * pmd_entry, struct page *pte)
@@ -116563,9 +181378,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/pgalloc
  }
  
  static inline void
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/privop.h linux-2.6.18-xen.hg/include/asm-ia64/privop.h
---- linux-2.6.18/include/asm-ia64/privop.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/privop.h      2007-12-23 11:15:40.341599078 +0100
+--- linux-2.6.18.8/include/asm-ia64/privop.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/privop.h      2008-05-19 00:34:08.748108843 +0300
 @@ -0,0 +1,63 @@
 +#ifndef _ASM_IA64_PRIVOP_H
 +#define _ASM_IA64_PRIVOP_H
@@ -116630,9 +181444,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/privop.
 +#endif /* !__ASSEMBLY */
 +
 +#endif /* _ASM_IA64_PRIVOP_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/sal.h linux-2.6.18-xen.hg/include/asm-ia64/sal.h
---- linux-2.6.18/include/asm-ia64/sal.h        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/sal.h 2007-12-23 11:15:40.344932588 +0100
+--- linux-2.6.18.8/include/asm-ia64/sal.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/sal.h 2008-05-19 00:34:08.760109535 +0300
 @@ -42,6 +42,9 @@
  #include <asm/pal.h>
  #include <asm/system.h>
@@ -116687,9 +181500,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/sal.h l
        SAL_CALL_REENTRANT(isrv, SAL_GET_STATE_INFO, sal_info_type, 0,
                      sal_info, 0, 0, 0, 0);
        if (isrv.status)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/sn/sn_sal.h linux-2.6.18-xen.hg/include/asm-ia64/sn/sn_sal.h
---- linux-2.6.18/include/asm-ia64/sn/sn_sal.h  2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/sn/sn_sal.h   2007-12-23 11:15:40.364933638 +0100
+--- linux-2.6.18.8/include/asm-ia64/sn/sn_sal.h        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/sn/sn_sal.h   2008-05-19 00:34:09.080127981 +0300
 @@ -87,6 +87,8 @@
  #define  SN_SAL_INJECT_ERROR                     0x02000067
  #define  SN_SAL_SET_CPU_NUMBER                           0x02000068
@@ -116711,9 +181523,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/sn/sn_s
 +      return rv.status;
 +}
  #endif /* _ASM_IA64_SN_SN_SAL_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/sn/types.h linux-2.6.18-xen.hg/include/asm-ia64/sn/types.h
---- linux-2.6.18/include/asm-ia64/sn/types.h   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/sn/types.h    2007-12-23 11:15:40.371600653 +0100
+--- linux-2.6.18.8/include/asm-ia64/sn/types.h 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/sn/types.h    2008-05-19 00:34:09.096128903 +0300
 @@ -20,7 +20,9 @@
  typedef unsigned char slabid_t;       /* slab (asic) within slot */
  typedef u64 nic_t;
@@ -116724,9 +181535,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/sn/type
  typedef short cnodeid_t;
  
  #endif /* _ASM_IA64_SN_TYPES_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/swiotlb.h linux-2.6.18-xen.hg/include/asm-ia64/swiotlb.h
---- linux-2.6.18/include/asm-ia64/swiotlb.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/swiotlb.h     2007-12-23 11:15:40.374934162 +0100
+--- linux-2.6.18.8/include/asm-ia64/swiotlb.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/swiotlb.h     2008-05-19 00:34:09.188134207 +0300
 @@ -0,0 +1,41 @@
 +#ifndef _ASM_SWIOTLB_H
 +#define _ASM_SWIOTLB_H 1
@@ -116769,9 +181579,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/swiotlb
 +#endif
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/synch_bitops.h linux-2.6.18-xen.hg/include/asm-ia64/synch_bitops.h
---- linux-2.6.18/include/asm-ia64/synch_bitops.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/synch_bitops.h        2007-12-23 11:15:40.374934162 +0100
+--- linux-2.6.18.8/include/asm-ia64/synch_bitops.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/synch_bitops.h        2008-05-19 00:34:09.192134437 +0300
 @@ -0,0 +1,61 @@
 +#ifndef __XEN_SYNCH_BITOPS_H__
 +#define __XEN_SYNCH_BITOPS_H__
@@ -116834,9 +181643,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/synch_b
 +#define synch_cmpxchg_subword synch_cmpxchg
 +
 +#endif /* __XEN_SYNCH_BITOPS_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/system.h linux-2.6.18-xen.hg/include/asm-ia64/system.h
---- linux-2.6.18/include/asm-ia64/system.h     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-ia64/system.h      2007-12-23 11:15:40.378267672 +0100
+--- linux-2.6.18.8/include/asm-ia64/system.h   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/system.h      2008-05-19 00:34:09.192134437 +0300
 @@ -123,7 +123,7 @@
  #define __local_irq_save(x)                   \
  do {                                          \
@@ -116855,9 +181663,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/system.
  
  #define irqs_disabled()                               \
  ({                                            \
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/xen/privop.h linux-2.6.18-xen.hg/include/asm-ia64/xen/privop.h
---- linux-2.6.18/include/asm-ia64/xen/privop.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/xen/privop.h  2007-12-23 11:15:40.384934686 +0100
+--- linux-2.6.18.8/include/asm-ia64/xen/privop.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/xen/privop.h  2008-05-19 00:34:09.236136974 +0300
 @@ -0,0 +1,551 @@
 +#ifndef _ASM_IA64_XEN_PRIVOP_H
 +#define _ASM_IA64_XEN_PRIVOP_H
@@ -117410,9 +182217,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/xen/pri
 +#define       ia64_pal_call_static            xen_pal_call_static
 +
 +#endif /* _ASM_IA64_XEN_PRIVOP_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/xen/xcom_hcall.h linux-2.6.18-xen.hg/include/asm-ia64/xen/xcom_hcall.h
---- linux-2.6.18/include/asm-ia64/xen/xcom_hcall.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/xen/xcom_hcall.h      2007-12-23 11:15:40.388268195 +0100
+--- linux-2.6.18.8/include/asm-ia64/xen/xcom_hcall.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/xen/xcom_hcall.h      2008-05-19 00:34:09.236136974 +0300
 @@ -0,0 +1,67 @@
 +/*
 + * Copyright (C) 2006 Tristan Gingold <tristan.gingold@bull.net>, Bull SAS
@@ -117481,9 +182287,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/xen/xco
 +extern int xencomm_hypercall_kexec_op(int cmd, void *arg);
 +
 +#endif /* _LINUX_XENCOMM_HCALL_H_ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/xen/xencomm.h linux-2.6.18-xen.hg/include/asm-ia64/xen/xencomm.h
---- linux-2.6.18/include/asm-ia64/xen/xencomm.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/xen/xencomm.h 2007-12-23 11:15:40.388268195 +0100
+--- linux-2.6.18.8/include/asm-ia64/xen/xencomm.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/xen/xencomm.h 2008-05-19 00:34:09.240137204 +0300
 @@ -0,0 +1,33 @@
 +/*
 + * Copyright (C) 2006 Hollis Blanchard <hollisb@us.ibm.com>, IBM Corporation
@@ -117518,9 +182323,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/xen/xen
 +#include <xen/xencomm.h>
 +
 +#endif /* _ASM_IA64_XENCOMM_H_ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/xenoprof.h linux-2.6.18-xen.hg/include/asm-ia64/xenoprof.h
---- linux-2.6.18/include/asm-ia64/xenoprof.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-ia64/xenoprof.h    2007-12-23 11:15:40.388268195 +0100
+--- linux-2.6.18.8/include/asm-ia64/xenoprof.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-ia64/xenoprof.h    2008-05-19 00:34:09.240137204 +0300
 @@ -0,0 +1,48 @@
 +/******************************************************************************
 + * asm-ia64/xenoprof.h
@@ -117560,19 +182364,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-ia64/xenopro
 +};
 +
 +struct xenoprof_shared_buffer;
-+void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffersbuf);
++void xenoprof_arch_unmap_shared_buffer(struct xenoprof_shared_buffer *sbuf);
 +struct xenoprof_get_buffer;
-+int xenoprof_arch_map_shared_buffer(struct xenoprof_get_bufferget_buffer,
-+                                    struct xenoprof_shared_buffersbuf);
++int xenoprof_arch_map_shared_buffer(struct xenoprof_get_buffer *get_buffer,
++                                    struct xenoprof_shared_buffer *sbuf);
 +struct xenoprof_passive;
-+int xenoprof_arch_set_passive(struct xenoprof_passivepdomain,
-+                              struct xenoprof_shared_buffersbuf);
++int xenoprof_arch_set_passive(struct xenoprof_passive *pdomain,
++                              struct xenoprof_shared_buffer *sbuf);
 +
 +#endif /* CONFIG_XEN */
 +#endif /* __ASM_XENOPROF_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/mpic.h linux-2.6.18-xen.hg/include/asm-powerpc/mpic.h
---- linux-2.6.18/include/asm-powerpc/mpic.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-powerpc/mpic.h     2007-12-23 11:15:41.931682576 +0100
+--- linux-2.6.18.8/include/asm-powerpc/mpic.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-powerpc/mpic.h     2008-05-19 00:34:13.772398451 +0300
 @@ -305,6 +305,8 @@
  #define MPIC_SPV_EOI                  0x00000020
  /* No passthrough disable */
@@ -117582,9 +182385,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/mpic
  
  /* MPIC HW modification ID */
  #define MPIC_REGSET_MASK              0xf0000000
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/udbg.h linux-2.6.18-xen.hg/include/asm-powerpc/udbg.h
---- linux-2.6.18/include/asm-powerpc/udbg.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-powerpc/udbg.h     2007-12-23 11:15:41.998352740 +0100
+--- linux-2.6.18.8/include/asm-powerpc/udbg.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-powerpc/udbg.h     2008-05-19 00:34:13.988410903 +0300
 @@ -42,6 +42,7 @@
  extern void __init udbg_init_pmac_realmode(void);
  extern void __init udbg_init_maple_realmode(void);
@@ -117593,9 +182395,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/udbg
  extern void __init udbg_init_rtas_panel(void);
  extern void __init udbg_init_rtas_console(void);
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/xen/asm/gnttab_dma.h linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/gnttab_dma.h
---- linux-2.6.18/include/asm-powerpc/xen/asm/gnttab_dma.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/gnttab_dma.h       2007-12-23 11:15:42.005019763 +0100
+--- linux-2.6.18.8/include/asm-powerpc/xen/asm/gnttab_dma.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/gnttab_dma.h       2008-05-19 00:34:14.016412517 +0300
 @@ -0,0 +1,29 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -117626,9 +182427,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/xen/
 +}
 +
 +#endif /* _ASM_PPC_GNTTAB_DMA_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/xen/asm/hypercall.h linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/hypercall.h
---- linux-2.6.18/include/asm-powerpc/xen/asm/hypercall.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/hypercall.h        2007-12-23 11:15:42.005019763 +0100
+--- linux-2.6.18.8/include/asm-powerpc/xen/asm/hypercall.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/hypercall.h        2008-05-19 00:34:14.020412747 +0300
 @@ -0,0 +1,90 @@
 +/******************************************************************************
 + * hypercall.h
@@ -117720,9 +182520,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/xen/
 +extern int privcmd_hypercall(struct privcmd_hypercall *hypercall);
 +
 +#endif        /*  __HYPERCALL_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/xen/asm/hypervisor.h linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/hypervisor.h
---- linux-2.6.18/include/asm-powerpc/xen/asm/hypervisor.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/hypervisor.h       2007-12-23 11:15:42.005019763 +0100
+--- linux-2.6.18.8/include/asm-powerpc/xen/asm/hypervisor.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/hypervisor.h       2008-05-19 00:34:14.020412747 +0300
 @@ -0,0 +1,276 @@
 +/******************************************************************************
 + * hypervisor.h
@@ -118000,9 +182799,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/xen/
 +      })
 +
 +#endif /* __HYPERVISOR_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/xen/asm/maddr.h linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/maddr.h
---- linux-2.6.18/include/asm-powerpc/xen/asm/maddr.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/maddr.h    2007-12-23 11:15:42.005019763 +0100
+--- linux-2.6.18.8/include/asm-powerpc/xen/asm/maddr.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/maddr.h    2008-05-19 00:34:14.020412747 +0300
 @@ -0,0 +1,7 @@
 +#ifndef _POWERPC_MADDR_H
 +#define _POWERPC_MADDR_H
@@ -118011,9 +182809,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/xen/
 +#include <xen/interface/xen.h>
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/xen/asm/synch_bitops.h linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/synch_bitops.h
---- linux-2.6.18/include/asm-powerpc/xen/asm/synch_bitops.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/synch_bitops.h     2007-12-23 11:15:42.005019763 +0100
+--- linux-2.6.18.8/include/asm-powerpc/xen/asm/synch_bitops.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-powerpc/xen/asm/synch_bitops.h     2008-05-19 00:34:14.020412747 +0300
 @@ -0,0 +1,100 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -118115,21 +182912,55 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-powerpc/xen/
 +#endif
 +
 +#endif /* __SYNCH_BITOPS_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/acpi.h linux-2.6.18-xen.hg/include/asm-x86_64/acpi.h
---- linux-2.6.18/include/asm-x86_64/acpi.h     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/acpi.h      2007-12-23 11:15:43.691775003 +0100
-@@ -153,6 +153,10 @@
+--- linux-2.6.18.8/include/asm-x86_64/acpi.h   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/acpi.h      2008-05-19 00:34:21.360835862 +0300
+@@ -28,6 +28,9 @@
+ #ifdef __KERNEL__
++#ifdef CONFIG_XEN
++#include <xen/interface/platform.h>
++#endif
+ #include <acpi/pdc_intel.h>
+ #define COMPILER_DEPENDENT_INT64   long long
+@@ -129,6 +132,27 @@
+ }
+ extern int acpi_irq_balance_set(char *str);
++#ifdef CONFIG_XEN
++static inline int acpi_notify_hypervisor_state(u8 sleep_state,
++                                             u32 pm1a_cnt_val,
++                                             u32 pm1b_cnt_val)
++{
++      struct xen_platform_op op = {
++              .cmd = XENPF_enter_acpi_sleep,
++              .interface_version = XENPF_INTERFACE_VERSION,
++              .u = {
++                      .enter_acpi_sleep = {
++                              .pm1a_cnt_val = pm1a_cnt_val,
++                              .pm1b_cnt_val = pm1b_cnt_val,
++                              .sleep_state = sleep_state,
++                      },
++              },
++      };
++
++      return HYPERVISOR_platform_op(&op);
++}
++#endif /* CONFIG_XEN */
++
+ #else /* !CONFIG_ACPI */
+ #define acpi_lapic 0
+@@ -152,7 +176,6 @@
  /* early initialization routine */
  extern void acpi_reserve_bootmem(void);
-+#ifdef CONFIG_ACPI_PV_SLEEP
-+extern int acpi_notify_hypervisor_state(u8 sleep_state,
-+      u32 pm1a_cnt, u32 pm1b_cnt);
-+#endif /* CONFIG_ACPI_PV_SLEEP */
+-
  #endif /*CONFIG_ACPI_SLEEP*/
  
  #define boot_cpu_physical_apicid boot_cpu_id
-@@ -162,7 +166,9 @@
+@@ -162,7 +185,9 @@
  
  extern u8 x86_acpiid_to_apicid[];
  
@@ -118139,9 +182970,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/acpi.
  
  extern int acpi_skip_timer_override;
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/agp.h linux-2.6.18-xen.hg/include/asm-x86_64/agp.h
---- linux-2.6.18/include/asm-x86_64/agp.h      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/agp.h       2007-12-23 11:15:43.691775003 +0100
+--- linux-2.6.18.8/include/asm-x86_64/agp.h    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/agp.h       2008-05-19 00:34:21.360835862 +0300
 @@ -10,8 +10,10 @@
   * with different cachability attributes for the same page.
   */
@@ -118155,9 +182985,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/agp.h
  #define flush_agp_mappings() global_flush_tlb()
  
  /* Could use CLFLUSH here if the cpu supports it. But then it would
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/apic.h linux-2.6.18-xen.hg/include/asm-x86_64/apic.h
---- linux-2.6.18/include/asm-x86_64/apic.h     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/apic.h      2007-12-23 11:15:43.691775003 +0100
+--- linux-2.6.18.8/include/asm-x86_64/apic.h   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/apic.h      2008-05-19 00:34:21.364836093 +0300
 @@ -98,11 +98,13 @@
  extern int disable_timer_pin_1;
  
@@ -118172,9 +183001,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/apic.
  
  #endif /* CONFIG_X86_LOCAL_APIC */
  
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/kexec.h linux-2.6.18-xen.hg/include/asm-x86_64/kexec.h
---- linux-2.6.18/include/asm-x86_64/kexec.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/kexec.h     2007-12-23 11:15:43.721776570 +0100
+--- linux-2.6.18.8/include/asm-x86_64/io_apic.h        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/io_apic.h   2008-05-19 00:34:21.700855462 +0300
+@@ -12,7 +12,7 @@
+ #ifdef CONFIG_X86_IO_APIC
+-#ifdef CONFIG_PCI_MSI
++#if defined(CONFIG_PCI_MSI) && !defined(CONFIG_XEN)
+ static inline int use_pci_vector(void)        {return 1;}
+ static inline void disable_edge_ioapic_vector(unsigned int vector) { }
+ static inline void mask_and_ack_level_ioapic_vector(unsigned int vector) { }
+--- linux-2.6.18.8/include/asm-x86_64/kexec.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/kexec.h     2008-05-19 00:34:21.708855923 +0300
 @@ -1,6 +1,27 @@
  #ifndef _X86_64_KEXEC_H
  #define _X86_64_KEXEC_H
@@ -118229,9 +183068,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/kexec
 +#endif /* __ASSEMBLY__ */
 +
  #endif /* _X86_64_KEXEC_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/agp.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/agp.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/agp.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/agp.h  2007-12-23 11:15:43.725110079 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/agp.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/agp.h  2008-05-19 00:34:21.728857076 +0300
 @@ -0,0 +1,40 @@
 +#ifndef AGP_H
 +#define AGP_H 1
@@ -118273,9 +183111,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +      dma_free_coherent(NULL,PAGE_SIZE<<(order),(table),virt_to_bus(table))
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/arch_hooks.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/arch_hooks.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/arch_hooks.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/arch_hooks.h   2007-12-23 11:15:43.725110079 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/arch_hooks.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/arch_hooks.h   2008-05-19 00:34:21.728857076 +0300
 @@ -0,0 +1,27 @@
 +#ifndef _ASM_ARCH_HOOKS_H
 +#define _ASM_ARCH_HOOKS_H
@@ -118304,9 +183141,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +extern void mca_nmi_hook(void);
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/bootsetup.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/bootsetup.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/bootsetup.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/bootsetup.h    2007-12-23 11:15:43.725110079 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/bootsetup.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/bootsetup.h    2008-05-19 00:34:21.732857306 +0300
 @@ -0,0 +1,42 @@
 +
 +#ifndef _X86_64_BOOTSETUP_H
@@ -118350,10 +183186,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#define RAMDISK_LOAD_FLAG             0x4000  
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/desc.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/desc.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/desc.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/desc.h 2007-12-23 11:15:43.725110079 +0100
-@@ -0,0 +1,263 @@
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/desc.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/desc.h 2008-05-19 00:34:21.732857306 +0300
+@@ -0,0 +1,265 @@
 +/* Written 2000 by Andi Kleen */ 
 +#ifndef __ARCH_DESC_H
 +#define __ARCH_DESC_H
@@ -118437,7 +183272,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +       * it slows down context switching. Noone uses it anyway.
 +       */
 +      cpu = cpu;              /* XXX avoid compiler warning */
-+      xen_set_ldt(0UL, 0);
++      xen_set_ldt(NULL, 0);
 +      put_cpu();
 +}
 +
@@ -118585,7 +183420,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +      gdt[2] = t->tls_array[2];
 +#endif
 +#define C(i) \
-+      HYPERVISOR_update_descriptor(virt_to_machine(&cpu_gdt(cpu)[GDT_ENTRY_TLS_MIN + i]), t->tls_array[i])
++      if (HYPERVISOR_update_descriptor(virt_to_machine(&cpu_gdt(cpu)[GDT_ENTRY_TLS_MIN + i]), \
++                                               t->tls_array[i])) \
++              BUG();
 +
 +      C(0); C(1); C(2);
 +#undef C
@@ -118602,7 +183439,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +      if (likely(!count))
 +              segments = NULL;
 +
-+      xen_set_ldt((unsigned long)segments, count);
++      xen_set_ldt(segments, count);
 +}
 +
 +static inline void load_LDT(mm_context_t *pc)
@@ -118617,9 +183454,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#endif /* !__ASSEMBLY__ */
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/dma-mapping.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/dma-mapping.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/dma-mapping.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/dma-mapping.h  2007-12-23 11:15:43.725110079 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/dma-mapping.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/dma-mapping.h  2008-05-19 00:34:21.732857306 +0300
 @@ -0,0 +1,207 @@
 +#ifndef _X8664_DMA_MAPPING_H
 +#define _X8664_DMA_MAPPING_H 1
@@ -118828,9 +183664,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#endif /* _X8664_DMA_MAPPING_H */
 +
 +#include <asm-i386/mach-xen/asm/dma-mapping.h>
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/e820.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/e820.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/e820.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/e820.h 2007-12-23 11:15:43.725110079 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/e820.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/e820.h 2008-05-19 00:34:21.732857306 +0300
 @@ -0,0 +1,66 @@
 +/*
 + * structures and definitions for the int 15, ax=e820 memory map
@@ -118898,9 +183733,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#endif/*!__ASSEMBLY__*/
 +
 +#endif/*__E820_HEADER*/
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/fixmap.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/fixmap.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/fixmap.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/fixmap.h       2007-12-23 11:15:43.728443593 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/fixmap.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/fixmap.h       2008-05-19 00:34:21.736857537 +0300
 @@ -0,0 +1,112 @@
 +/*
 + * fixmap.h: compile-time virtual memory allocation
@@ -119014,14 +183848,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +}
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/gnttab_dma.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/gnttab_dma.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/gnttab_dma.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/gnttab_dma.h   2007-12-23 11:15:43.728443593 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/gnttab_dma.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/gnttab_dma.h   2008-05-19 00:34:21.736857537 +0300
 @@ -0,0 +1 @@
 +#include <asm-i386/mach-xen/asm/gnttab_dma.h>
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/hw_irq.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/hw_irq.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/hw_irq.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/hw_irq.h       2007-12-23 11:15:43.728443593 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/hw_irq.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/hw_irq.h       2008-05-19 00:34:21.736857537 +0300
 @@ -0,0 +1,136 @@
 +#ifndef _ASM_HW_IRQ_H
 +#define _ASM_HW_IRQ_H
@@ -119159,10 +183991,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#endif
 +
 +#endif /* _ASM_HW_IRQ_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/hypercall.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/hypercall.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/hypercall.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/hypercall.h    2007-12-23 11:15:43.728443593 +0100
-@@ -0,0 +1,407 @@
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/hypercall.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/hypercall.h    2008-05-19 00:34:21.736857537 +0300
+@@ -0,0 +1,415 @@
 +/******************************************************************************
 + * hypercall.h
 + * 
@@ -119209,55 +184040,55 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +# error "please don't include this file directly"
 +#endif
 +
-+#define __STR(x) #x
-+#define STR(x) __STR(x)
-+
 +#ifdef CONFIG_XEN
 +#define HYPERCALL_STR(name)                                   \
-+      "call hypercall_page + ("STR(__HYPERVISOR_##name)" * 32)"
++      "call hypercall_page + ("__stringify(__HYPERVISOR_##name)" * 32)"
 +#else
 +#define HYPERCALL_STR(name)                                   \
-+      "mov "__stringify(hypercall_stubs)",%%rax; "            \
-+      "add $("STR(__HYPERVISOR_##name)" * 32),%%rax; "        \
++      "mov $("__stringify(__HYPERVISOR_##name)" * 32),%%eax; "\
++      "add hypercall_stubs(%%rip),%%rax; "                    \
 +      "call *%%rax"
 +#endif
 +
 +#define _hypercall0(type, name)                       \
 +({                                            \
-+      long __res;                             \
++      type __res;                             \
 +      asm volatile (                          \
 +              HYPERCALL_STR(name)             \
 +              : "=a" (__res)                  \
 +              :                               \
 +              : "memory" );                   \
-+      (type)__res;                            \
++      __res;                                  \
 +})
 +
 +#define _hypercall1(type, name, a1)                           \
 +({                                                            \
-+      long __res, __ign1;                                     \
++      type __res;                                             \
++      long __ign1;                                            \
 +      asm volatile (                                          \
 +              HYPERCALL_STR(name)                             \
 +              : "=a" (__res), "=D" (__ign1)                   \
 +              : "1" ((long)(a1))                              \
 +              : "memory" );                                   \
-+      (type)__res;                                            \
++      __res;                                                  \
 +})
 +
 +#define _hypercall2(type, name, a1, a2)                               \
 +({                                                            \
-+      long __res, __ign1, __ign2;                             \
++      type __res;                                             \
++      long __ign1, __ign2;                                    \
 +      asm volatile (                                          \
 +              HYPERCALL_STR(name)                             \
 +              : "=a" (__res), "=D" (__ign1), "=S" (__ign2)    \
 +              : "1" ((long)(a1)), "2" ((long)(a2))            \
 +              : "memory" );                                   \
-+      (type)__res;                                            \
++      __res;                                                  \
 +})
 +
 +#define _hypercall3(type, name, a1, a2, a3)                   \
 +({                                                            \
-+      long __res, __ign1, __ign2, __ign3;                     \
++      type __res;                                             \
++      long __ign1, __ign2, __ign3;                            \
 +      asm volatile (                                          \
 +              HYPERCALL_STR(name)                             \
 +              : "=a" (__res), "=D" (__ign1), "=S" (__ign2),   \
@@ -119265,74 +184096,78 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +              : "1" ((long)(a1)), "2" ((long)(a2)),           \
 +              "3" ((long)(a3))                                \
 +              : "memory" );                                   \
-+      (type)__res;                                            \
++      __res;                                                  \
 +})
 +
 +#define _hypercall4(type, name, a1, a2, a3, a4)                       \
 +({                                                            \
-+      long __res, __ign1, __ign2, __ign3;                     \
++      type __res;                                             \
++      long __ign1, __ign2, __ign3;                            \
++      register long __arg4 asm("r10") = (long)(a4);           \
 +      asm volatile (                                          \
-+              "movq %7,%%r10; "                               \
 +              HYPERCALL_STR(name)                             \
 +              : "=a" (__res), "=D" (__ign1), "=S" (__ign2),   \
-+              "=d" (__ign3)                                   \
++                "=d" (__ign3), "+r" (__arg4)                  \
 +              : "1" ((long)(a1)), "2" ((long)(a2)),           \
-+              "3" ((long)(a3)), "g" ((long)(a4))              \
-+              : "memory", "r10" );                            \
-+      (type)__res;                                            \
++                "3" ((long)(a3))                              \
++              : "memory" );                                   \
++      __res;                                                  \
 +})
 +
 +#define _hypercall5(type, name, a1, a2, a3, a4, a5)           \
 +({                                                            \
-+      long __res, __ign1, __ign2, __ign3;                     \
++      type __res;                                             \
++      long __ign1, __ign2, __ign3;                            \
++      register long __arg4 asm("r10") = (long)(a4);           \
++      register long __arg5 asm("r8") = (long)(a5);            \
 +      asm volatile (                                          \
-+              "movq %7,%%r10; movq %8,%%r8; "                 \
 +              HYPERCALL_STR(name)                             \
 +              : "=a" (__res), "=D" (__ign1), "=S" (__ign2),   \
-+              "=d" (__ign3)                                   \
++                "=d" (__ign3), "+r" (__arg4), "+r" (__arg5)   \
 +              : "1" ((long)(a1)), "2" ((long)(a2)),           \
-+              "3" ((long)(a3)), "g" ((long)(a4)),             \
-+              "g" ((long)(a5))                                \
-+              : "memory", "r10", "r8" );                      \
-+      (type)__res;                                            \
++                "3" ((long)(a3))                              \
++              : "memory" );                                   \
++      __res;                                                  \
 +})
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_set_trap_table(
-+      trap_info_t *table)
++      const trap_info_t *table)
 +{
 +      return _hypercall1(int, set_trap_table, table);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_mmu_update(
-+      mmu_update_t *req, int count, int *success_count, domid_t domid)
++      mmu_update_t *req, unsigned int count, unsigned int *success_count,
++      domid_t domid)
 +{
 +      return _hypercall4(int, mmu_update, req, count, success_count, domid);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_mmuext_op(
-+      struct mmuext_op *op, int count, int *success_count, domid_t domid)
++      struct mmuext_op *op, unsigned int count, unsigned int *success_count,
++      domid_t domid)
 +{
 +      return _hypercall4(int, mmuext_op, op, count, success_count, domid);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_set_gdt(
-+      unsigned long *frame_list, int entries)
++      unsigned long *frame_list, unsigned int entries)
 +{
 +      return _hypercall2(int, set_gdt, frame_list, entries);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_stack_switch(
 +      unsigned long ss, unsigned long esp)
 +{
 +      return _hypercall2(int, stack_switch, ss, esp);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_set_callbacks(
 +      unsigned long event_address, unsigned long failsafe_address, 
 +      unsigned long syscall_address)
@@ -119348,28 +184183,28 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +      return _hypercall1(int, fpu_taskswitch, set);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_sched_op_compat(
 +      int cmd, unsigned long arg)
 +{
 +      return _hypercall2(int, sched_op_compat, cmd, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_sched_op(
 +      int cmd, void *arg)
 +{
 +      return _hypercall2(int, sched_op, cmd, arg);
 +}
 +
-+static inline long
++static inline long __must_check
 +HYPERVISOR_set_timer_op(
 +      u64 timeout)
 +{
 +      return _hypercall1(long, set_timer_op, timeout);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_platform_op(
 +      struct xen_platform_op *platform_op)
 +{
@@ -119377,49 +184212,49 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +      return _hypercall1(int, platform_op, platform_op);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_set_debugreg(
-+      int reg, unsigned long value)
++      unsigned int reg, unsigned long value)
 +{
 +      return _hypercall2(int, set_debugreg, reg, value);
 +}
 +
-+static inline unsigned long
++static inline unsigned long __must_check
 +HYPERVISOR_get_debugreg(
-+      int reg)
++      unsigned int reg)
 +{
 +      return _hypercall1(unsigned long, get_debugreg, reg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_update_descriptor(
 +      unsigned long ma, unsigned long word)
 +{
 +      return _hypercall2(int, update_descriptor, ma, word);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_memory_op(
 +      unsigned int cmd, void *arg)
 +{
 +      return _hypercall2(int, memory_op, cmd, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_multicall(
-+      multicall_entry_t *call_list, int nr_calls)
++      multicall_entry_t *call_list, unsigned int nr_calls)
 +{
 +      return _hypercall2(int, multicall, call_list, nr_calls);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_update_va_mapping(
 +      unsigned long va, pte_t new_val, unsigned long flags)
 +{
 +      return _hypercall3(int, update_va_mapping, va, new_val.pte, flags);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_event_channel_op(
 +      int cmd, void *arg)
 +{
@@ -119438,28 +184273,28 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +      return rc;
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_acm_op(
 +      int cmd, void *arg)
 +{
 +      return _hypercall2(int, acm_op, cmd, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_xen_version(
 +      int cmd, void *arg)
 +{
 +      return _hypercall2(int, xen_version, cmd, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_console_io(
-+      int cmd, int count, char *str)
++      int cmd, unsigned int count, char *str)
 +{
 +      return _hypercall3(int, console_io, cmd, count, str);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_physdev_op(
 +      int cmd, void *arg)
 +{
@@ -119478,14 +184313,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +      return rc;
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_grant_table_op(
 +      unsigned int cmd, void *uop, unsigned int count)
 +{
 +      return _hypercall3(int, grant_table_op, cmd, uop, count);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_update_va_mapping_otherdomain(
 +      unsigned long va, pte_t new_val, unsigned long flags, domid_t domid)
 +{
@@ -119493,28 +184328,28 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +                         new_val.pte, flags, domid);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_vm_assist(
 +      unsigned int cmd, unsigned int type)
 +{
 +      return _hypercall2(int, vm_assist, cmd, type);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_vcpu_op(
-+      int cmd, int vcpuid, void *extra_args)
++      int cmd, unsigned int vcpuid, void *extra_args)
 +{
 +      return _hypercall3(int, vcpu_op, cmd, vcpuid, extra_args);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_set_segment_base(
 +      int reg, unsigned long value)
 +{
 +      return _hypercall2(int, set_segment_base, reg, value);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_suspend(
 +      unsigned long srec)
 +{
@@ -119534,35 +184369,39 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +      return rc;
 +}
 +
++#if CONFIG_XEN_COMPAT <= 0x030002
 +static inline int
 +HYPERVISOR_nmi_op(
 +      unsigned long op, void *arg)
 +{
 +      return _hypercall2(int, nmi_op, op, arg);
 +}
++#endif
 +
-+static inline unsigned long
++#ifndef CONFIG_XEN
++static inline unsigned long __must_check
 +HYPERVISOR_hvm_op(
 +    int op, void *arg)
 +{
 +    return _hypercall2(unsigned long, hvm_op, op, arg);
 +}
++#endif
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_callback_op(
-+      int cmd, void *arg)
++      int cmd, const void *arg)
 +{
 +      return _hypercall2(int, callback_op, cmd, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_xenoprof_op(
 +      int op, void *arg)
 +{
 +      return _hypercall2(int, xenoprof_op, op, arg);
 +}
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_kexec_op(
 +      unsigned long op, void *args)
 +{
@@ -119570,15 +184409,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +}
 +
 +#endif /* __HYPERCALL_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/hypervisor.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/hypervisor.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/hypervisor.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/hypervisor.h   2007-12-23 11:15:43.728443593 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/hypervisor.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/hypervisor.h   2008-05-19 00:34:21.740857768 +0300
 @@ -0,0 +1,2 @@
 +
 +#include <asm-i386/mach-xen/asm/hypervisor.h>
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/io.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/io.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/io.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/io.h   2007-12-23 11:15:43.728443593 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/io.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/io.h   2008-05-19 00:34:21.740857768 +0300
 @@ -0,0 +1,329 @@
 +#ifndef _ASM_IO_H
 +#define _ASM_IO_H
@@ -119909,9 +184746,49 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#define ARCH_HAS_DEV_MEM
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/irqflags.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/irqflags.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/irqflags.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/irqflags.h     2007-12-23 11:15:43.731777107 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/irq.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/irq.h  2008-05-19 00:34:21.740857768 +0300
+@@ -0,0 +1,38 @@
++#ifndef _ASM_IRQ_H
++#define _ASM_IRQ_H
++
++/*
++ *    linux/include/asm/irq.h
++ *
++ *    (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
++ *
++ *    IRQ/IPI changes taken from work by Thomas Radke
++ *    <tomsoft@informatik.tu-chemnitz.de>
++ */
++
++#include <linux/sched.h>
++/* include comes from machine specific directory */
++#include "irq_vectors.h"
++#include <asm/thread_info.h>
++
++static __inline__ int irq_canonicalize(int irq)
++{
++      return ((irq == 2) ? 9 : irq);
++}
++
++#ifdef CONFIG_X86_LOCAL_APIC
++#define ARCH_HAS_NMI_WATCHDOG         /* See include/linux/nmi.h */
++#endif
++
++#define KDB_VECTOR    0xf9
++
++# define irq_ctx_init(cpu) do { } while (0)
++
++#ifdef CONFIG_HOTPLUG_CPU
++#include <linux/cpumask.h>
++extern void fixup_irqs(cpumask_t map);
++#endif
++
++#define __ARCH_HAS_DO_SOFTIRQ 1
++
++#endif /* _ASM_IRQ_H */
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/irqflags.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/irqflags.h     2008-05-19 00:34:21.740857768 +0300
 @@ -0,0 +1,139 @@
 +/*
 + * include/asm-x86_64/irqflags.h
@@ -120052,51 +184929,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#endif
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/irq.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/irq.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/irq.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/irq.h  2007-12-23 11:15:43.728443593 +0100
-@@ -0,0 +1,38 @@
-+#ifndef _ASM_IRQ_H
-+#define _ASM_IRQ_H
-+
-+/*
-+ *    linux/include/asm/irq.h
-+ *
-+ *    (C) 1992, 1993 Linus Torvalds, (C) 1997 Ingo Molnar
-+ *
-+ *    IRQ/IPI changes taken from work by Thomas Radke
-+ *    <tomsoft@informatik.tu-chemnitz.de>
-+ */
-+
-+#include <linux/sched.h>
-+/* include comes from machine specific directory */
-+#include "irq_vectors.h"
-+#include <asm/thread_info.h>
-+
-+static __inline__ int irq_canonicalize(int irq)
-+{
-+      return ((irq == 2) ? 9 : irq);
-+}
-+
-+#ifdef CONFIG_X86_LOCAL_APIC
-+#define ARCH_HAS_NMI_WATCHDOG         /* See include/linux/nmi.h */
-+#endif
-+
-+#define KDB_VECTOR    0xf9
-+
-+# define irq_ctx_init(cpu) do { } while (0)
-+
-+#ifdef CONFIG_HOTPLUG_CPU
-+#include <linux/cpumask.h>
-+extern void fixup_irqs(cpumask_t map);
-+#endif
-+
-+#define __ARCH_HAS_DO_SOFTIRQ 1
-+
-+#endif /* _ASM_IRQ_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/maddr.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/maddr.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/maddr.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/maddr.h        2007-12-23 11:15:43.731777107 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/maddr.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/maddr.h        2008-05-19 00:34:21.744857998 +0300
 @@ -0,0 +1,161 @@
 +#ifndef _X86_64_MADDR_H
 +#define _X86_64_MADDR_H
@@ -120259,9 +185093,49 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +
 +#endif /* _X86_64_MADDR_H */
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/mmu_context.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/mmu_context.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/mmu_context.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/mmu_context.h  2007-12-23 11:15:43.731777107 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/mmu.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/mmu.h  2008-05-19 00:34:21.744857998 +0300
+@@ -0,0 +1,38 @@
++#ifndef __x86_64_MMU_H
++#define __x86_64_MMU_H
++
++#include <linux/spinlock.h>
++#include <asm/semaphore.h>
++
++/*
++ * The x86_64 doesn't have a mmu context, but
++ * we put the segment information here.
++ *
++ * cpu_vm_mask is used to optimize ldt flushing.
++ */
++typedef struct { 
++      void *ldt;
++      rwlock_t ldtlock; 
++      int size;
++      struct semaphore sem; 
++#ifdef CONFIG_XEN
++      unsigned pinned:1;
++      unsigned has_foreign_mappings:1;
++      struct list_head unpinned;
++#endif
++} mm_context_t;
++
++#ifdef CONFIG_XEN
++extern struct list_head mm_unpinned;
++extern spinlock_t mm_unpinned_lock;
++
++/* mm/memory.c:exit_mmap hook */
++extern void _arch_exit_mmap(struct mm_struct *mm);
++#define arch_exit_mmap(_mm) _arch_exit_mmap(_mm)
++
++/* kernel/fork.c:dup_mmap hook */
++extern void _arch_dup_mmap(struct mm_struct *mm);
++#define arch_dup_mmap(mm, oldmm) ((void)(oldmm), _arch_dup_mmap(mm))
++#endif
++
++#endif
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/mmu_context.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/mmu_context.h  2008-05-19 00:34:21.744857998 +0300
 @@ -0,0 +1,136 @@
 +#ifndef __X86_64_MMU_CONTEXT_H
 +#define __X86_64_MMU_CONTEXT_H
@@ -120399,51 +185273,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +}
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/mmu.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/mmu.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/mmu.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/mmu.h  2007-12-23 11:15:43.731777107 +0100
-@@ -0,0 +1,38 @@
-+#ifndef __x86_64_MMU_H
-+#define __x86_64_MMU_H
-+
-+#include <linux/spinlock.h>
-+#include <asm/semaphore.h>
-+
-+/*
-+ * The x86_64 doesn't have a mmu context, but
-+ * we put the segment information here.
-+ *
-+ * cpu_vm_mask is used to optimize ldt flushing.
-+ */
-+typedef struct { 
-+      void *ldt;
-+      rwlock_t ldtlock; 
-+      int size;
-+      struct semaphore sem; 
-+#ifdef CONFIG_XEN
-+      unsigned pinned:1;
-+      unsigned has_foreign_mappings:1;
-+      struct list_head unpinned;
-+#endif
-+} mm_context_t;
-+
-+#ifdef CONFIG_XEN
-+extern struct list_head mm_unpinned;
-+extern spinlock_t mm_unpinned_lock;
-+
-+/* mm/memory.c:exit_mmap hook */
-+extern void _arch_exit_mmap(struct mm_struct *mm);
-+#define arch_exit_mmap(_mm) _arch_exit_mmap(_mm)
-+
-+/* kernel/fork.c:dup_mmap hook */
-+extern void _arch_dup_mmap(struct mm_struct *mm);
-+#define arch_dup_mmap(mm, oldmm) ((void)(oldmm), _arch_dup_mmap(mm))
-+#endif
-+
-+#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/msr.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/msr.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/msr.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/msr.h  2007-12-23 11:15:43.731777107 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/msr.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/msr.h  2008-05-19 00:34:21.744857998 +0300
 @@ -0,0 +1,399 @@
 +#ifndef X86_64_MSR_H
 +#define X86_64_MSR_H 1
@@ -120844,9 +185675,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#define MSR_P4_U2L_ESCR1              0x3b1
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/nmi.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/nmi.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/nmi.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/nmi.h  2007-12-23 11:15:43.731777107 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/nmi.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/nmi.h  2008-05-19 00:34:21.744857998 +0300
 @@ -0,0 +1,93 @@
 +/*
 + *  linux/include/asm-i386/nmi.h
@@ -120941,10 +185771,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#define NMI_INVALID   3
 +
 +#endif /* ASM_NMI_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/page.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/page.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/page.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/page.h 2007-12-23 11:15:43.731777107 +0100
-@@ -0,0 +1,209 @@
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/page.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/page.h 2008-05-19 00:34:21.748858229 +0300
+@@ -0,0 +1,212 @@
 +#ifndef _X86_64_PAGE_H
 +#define _X86_64_PAGE_H
 +
@@ -120962,6 +185791,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 + * below. The preprocessor will warn if the two definitions aren't identical.
 + */
 +#define _PAGE_PRESENT 0x001
++#define _PAGE_IO      0x200
 +
 +/* PAGE_SHIFT determines the page size */
 +#define PAGE_SHIFT    12
@@ -121036,9 +185866,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +typedef struct { unsigned long pgprot; } pgprot_t;
 +
 +#define __pte_val(x) ((x).pte)
-+#define pte_val(x) ((__pte_val(x) & _PAGE_PRESENT) ? \
-+                    pte_machine_to_phys(__pte_val(x)) : \
-+                    __pte_val(x))
++#define pte_val(x) ((__pte_val(x) & (_PAGE_PRESENT|_PAGE_IO)) \
++                  == _PAGE_PRESENT ?                          \
++                  pte_machine_to_phys(__pte_val(x)) :         \
++                  __pte_val(x))
 +
 +#define __pmd_val(x) ((x).pmd)
 +static inline unsigned long pmd_val(pmd_t x)
@@ -121072,7 +185903,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +
 +static inline pte_t __pte(unsigned long x)
 +{
-+      if (x & _PAGE_PRESENT) x = pte_phys_to_machine(x);
++      if ((x & (_PAGE_PRESENT|_PAGE_IO)) == _PAGE_PRESENT)
++              x = pte_phys_to_machine(x);
 +      return ((pte_t) { (x) });
 +}
 +
@@ -121154,9 +185986,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#endif /* __KERNEL__ */
 +
 +#endif /* _X86_64_PAGE_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/pci.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/pci.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/pci.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/pci.h  2007-12-23 11:15:43.735110615 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/pci.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/pci.h  2008-05-19 00:34:21.748858229 +0300
 @@ -0,0 +1,168 @@
 +#ifndef __x8664_PCI_H
 +#define __x8664_PCI_H
@@ -121326,9 +186157,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#endif
 +
 +#endif /* __x8664_PCI_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/pgalloc.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/pgalloc.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/pgalloc.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/pgalloc.h      2007-12-23 11:15:43.735110615 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/pgalloc.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/pgalloc.h      2008-05-19 00:34:21.748858229 +0300
 @@ -0,0 +1,204 @@
 +#ifndef _X86_64_PGALLOC_H
 +#define _X86_64_PGALLOC_H
@@ -121534,10 +186364,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#define __pud_free_tlb(tlb,x)   tlb_remove_page((tlb),virt_to_page(x))
 +
 +#endif /* _X86_64_PGALLOC_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/pgtable.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/pgtable.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/pgtable.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/pgtable.h      2007-12-23 11:15:43.735110615 +0100
-@@ -0,0 +1,573 @@
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/pgtable.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/pgtable.h      2008-05-19 00:34:21.748858229 +0300
+@@ -0,0 +1,583 @@
 +#ifndef _X86_64_PGTABLE_H
 +#define _X86_64_PGTABLE_H
 +
@@ -121558,19 +186387,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +
 +extern void xen_init_pt(void);
 +
-+#define virt_to_ptep(__va)                                            \
-+({                                                                    \
-+      pgd_t *__pgd = pgd_offset_k((unsigned long)(__va));             \
-+      pud_t *__pud = pud_offset(__pgd, (unsigned long)(__va));        \
-+      pmd_t *__pmd = pmd_offset(__pud, (unsigned long)(__va));        \
-+      pte_offset_kernel(__pmd, (unsigned long)(__va));                \
-+})
++extern pte_t *lookup_address(unsigned long address);
 +
-+#define arbitrary_virt_to_machine(__va)                                       \
++#define virt_to_ptep(va)                                              \
 +({                                                                    \
-+      maddr_t m = (maddr_t)pte_mfn(*virt_to_ptep(__va)) << PAGE_SHIFT;\
-+      m | ((unsigned long)(__va) & (PAGE_SIZE-1));                    \
++      pte_t *__ptep = lookup_address((unsigned long)(va));            \
++      BUG_ON(!__ptep || !pte_present(*__ptep));                       \
++      __ptep;                                                         \
 +})
++
++#define arbitrary_virt_to_machine(va)                                 \
++      (((maddr_t)pte_mfn(*virt_to_ptep(va)) << PAGE_SHIFT)            \
++       | ((unsigned long)(va) & (PAGE_SIZE - 1)))
 +#endif
 +
 +extern pud_t level3_kernel_pgt[512];
@@ -121708,6 +186536,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#define _PAGE_PROTNONE        0x080   /* If not present */
 +#define _PAGE_NX        (1UL<<_PAGE_BIT_NX)
 +
++/* Mapped page is I/O or foreign and has no associated page struct. */
++#define _PAGE_IO      0x200
++
 +#if CONFIG_XEN_COMPAT <= 0x030002
 +extern unsigned int __kernel_page_user;
 +#else
@@ -121717,7 +186548,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#define _PAGE_TABLE   (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY)
 +#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY | __kernel_page_user)
 +
-+#define _PAGE_CHG_MASK        (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
++#define _PAGE_CHG_MASK        (PTE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_IO)
 +
 +#define PAGE_NONE     __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
 +#define PAGE_SHARED   __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_NX)
@@ -121808,8 +186639,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#define __pte_mfn(_pte) (((_pte).pte & PTE_MASK) >> PAGE_SHIFT)
 +#define pte_mfn(_pte) ((_pte).pte & _PAGE_PRESENT ? \
 +      __pte_mfn(_pte) : pfn_to_mfn(__pte_mfn(_pte)))
-+#define pte_pfn(_pte) ((_pte).pte & _PAGE_PRESENT ? \
-+      mfn_to_local_pfn(__pte_mfn(_pte)) : __pte_mfn(_pte))
++#define pte_pfn(_pte) ((_pte).pte & _PAGE_IO ? end_pfn :      \
++                     (_pte).pte & _PAGE_PRESENT ?             \
++                     mfn_to_local_pfn(__pte_mfn(_pte)) :      \
++                     __pte_mfn(_pte))
 +
 +#define pte_page(x)   pfn_to_page(pte_pfn(x))
 +
@@ -122081,6 +186914,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +                    unsigned long address,
 +                    unsigned long size);
 +
++int xen_change_pte_range(struct mm_struct *mm, pmd_t *pmd,
++              unsigned long addr, unsigned long end, pgprot_t newprot);
++
++#define arch_change_pte_range(mm, pmd, addr, end, newprot)    \
++              xen_change_pte_range(mm, pmd, addr, end, newprot)
++
 +#define io_remap_pfn_range(vma, vaddr, pfn, size, prot)               \
 +              direct_remap_pfn_range(vma,vaddr,pfn,size,prot,DOMID_IO)
 +
@@ -122111,10 +186950,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#include <asm-generic/pgtable.h>
 +
 +#endif /* _X86_64_PGTABLE_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/processor.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/processor.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/processor.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/processor.h    2007-12-23 11:15:43.735110615 +0100
-@@ -0,0 +1,506 @@
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/processor.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/processor.h    2008-05-19 00:34:21.752858459 +0300
+@@ -0,0 +1,502 @@
 +/*
 + * include/asm-x86_64/processor.h
 + *
@@ -122285,12 +187123,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +
 +
 +/*
-+ * Bus types
-+ */
-+#define MCA_bus 0
-+#define MCA_bus__is_a_macro
-+
-+/*
 + * User space process size. 47bits minus one guard page.
 + */
 +#define TASK_SIZE64   (0x800000000000UL - 4096)
@@ -122434,8 +187266,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +
 +#define get_debugreg(var, register)                           \
 +      var = HYPERVISOR_get_debugreg(register)
-+#define set_debugreg(value, register)                 \
-+      HYPERVISOR_set_debugreg(register, value)
++#define set_debugreg(value, register) do {                    \
++      if (HYPERVISOR_set_debugreg(register, value))           \
++              BUG();                                          \
++} while (0)
 +
 +struct task_struct;
 +struct mm_struct;
@@ -122621,9 +187455,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#define HAVE_ARCH_PICK_MMAP_LAYOUT 1
 +
 +#endif /* __ASM_X86_64_PROCESSOR_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/ptrace.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/ptrace.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/ptrace.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/ptrace.h       2007-12-23 11:15:43.735110615 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/ptrace.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/ptrace.h       2008-05-19 00:34:21.752858459 +0300
 @@ -0,0 +1,127 @@
 +#ifndef _X86_64_PTRACE_H
 +#define _X86_64_PTRACE_H
@@ -122752,9 +187585,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#endif
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/smp.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/smp.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/smp.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/smp.h  2007-12-23 11:15:43.735110615 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/smp.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/smp.h  2008-05-19 00:34:21.752858459 +0300
 @@ -0,0 +1,150 @@
 +#ifndef __ASM_SMP_H
 +#define __ASM_SMP_H
@@ -122906,15 +187738,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +
 +#endif
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/synch_bitops.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/synch_bitops.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/synch_bitops.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/synch_bitops.h 2007-12-23 11:15:43.735110615 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/synch_bitops.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/synch_bitops.h 2008-05-19 00:34:21.756858690 +0300
 @@ -0,0 +1,2 @@
 +
 +#include <asm-i386/mach-xen/asm/synch_bitops.h>
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/system.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/system.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/system.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/system.h       2007-12-23 11:15:43.738444121 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/system.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/system.h       2008-05-19 00:34:21.756858690 +0300
 @@ -0,0 +1,256 @@
 +#ifndef __ASM_SYSTEM_H
 +#define __ASM_SYSTEM_H
@@ -123172,9 +188002,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +extern void free_init_pages(char *what, unsigned long begin, unsigned long end);
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/timer.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/timer.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/timer.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/timer.h        2007-12-23 11:15:43.738444121 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/timer.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/timer.h        2008-05-19 00:34:21.756858690 +0300
 @@ -0,0 +1,67 @@
 +#ifndef _ASMi386_TIMER_H
 +#define _ASMi386_TIMER_H
@@ -123243,9 +188072,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +extern struct init_timer_opts timer_pmtmr_init;
 +#endif
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/tlbflush.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/tlbflush.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/tlbflush.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/tlbflush.h     2007-12-23 11:15:43.738444121 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/tlbflush.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/tlbflush.h     2008-05-19 00:34:21.756858690 +0300
 @@ -0,0 +1,103 @@
 +#ifndef _X8664_TLBFLUSH_H
 +#define _X8664_TLBFLUSH_H
@@ -123350,9 +188178,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +}
 +
 +#endif /* _X8664_TLBFLUSH_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/vga.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/vga.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/vga.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/vga.h  2007-12-23 11:15:43.738444121 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/vga.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/vga.h  2008-05-19 00:34:21.760858920 +0300
 @@ -0,0 +1,20 @@
 +/*
 + *    Access to VGA videoram
@@ -123374,14 +188201,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#define vga_writeb(x,y) (*(y) = (x))
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/xenoprof.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/xenoprof.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/xenoprof.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/xenoprof.h     2007-12-23 11:15:43.738444121 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/xenoprof.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/xenoprof.h     2008-05-19 00:34:21.760858920 +0300
 @@ -0,0 +1 @@
 +#include <asm-i386/mach-xen/asm/xenoprof.h>
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/asm/xor.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/xor.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/asm/xor.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/xor.h  2007-12-23 11:15:43.738444121 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/asm/xor.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/asm/xor.h  2008-05-19 00:34:21.760858920 +0300
 @@ -0,0 +1,328 @@
 +/*
 + * x86-64 changes / gcc fixes from Andi Kleen. 
@@ -123711,9 +188536,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +   We may also be able to load into the L1 only depending on how the cpu
 +   deals with a load to a line that is being prefetched.  */
 +#define XOR_SELECT_TEMPLATE(FASTEST) (&xor_block_sse)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/irq_vectors.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/irq_vectors.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/irq_vectors.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/irq_vectors.h      2007-12-23 11:15:43.741777625 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/irq_vectors.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/irq_vectors.h      2008-05-19 00:34:21.760858920 +0300
 @@ -0,0 +1,123 @@
 +/*
 + * This file should contain #defines for all of the interrupt vector
@@ -123838,9 +188662,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#define irq_to_dynirq(_x)     ((_x) - DYNIRQ_BASE)
 +
 +#endif /* _ASM_IRQ_VECTORS_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/mach_time.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/mach_time.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/mach_time.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/mach_time.h        2007-12-23 11:15:43.741777625 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/mach_time.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/mach_time.h        2008-05-19 00:34:21.764859151 +0300
 @@ -0,0 +1,111 @@
 +/*
 + *  include/asm-i386/mach-default/mach_time.h
@@ -123953,9 +188776,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +}
 +
 +#endif /* !_MACH_TIME_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/mach_timer.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/mach_timer.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/mach_timer.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/mach_timer.h       2007-12-23 11:15:43.741777625 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/mach_timer.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/mach_timer.h       2008-05-19 00:34:21.764859151 +0300
 @@ -0,0 +1,50 @@
 +/*
 + *  include/asm-i386/mach-default/mach_timer.h
@@ -124007,9 +188829,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +}
 +
 +#endif /* !_MACH_TIMER_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/setup_arch_post.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/setup_arch_post.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/setup_arch_post.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/setup_arch_post.h  2007-12-23 11:15:43.741777625 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/setup_arch_post.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/setup_arch_post.h  2008-05-19 00:34:21.764859151 +0300
 @@ -0,0 +1,63 @@
 +/**
 + * machine_specific_* - Hooks for machine specific setup.
@@ -124074,18 +188895,94 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-
 +#endif
 +#endif
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/asm-x86_64/mach-xen/setup_arch_pre.h linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/setup_arch_pre.h
---- linux-2.6.18/include/asm-x86_64/mach-xen/setup_arch_pre.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/setup_arch_pre.h   2007-12-23 11:15:43.741777625 +0100
+--- linux-2.6.18.8/include/asm-x86_64/mach-xen/setup_arch_pre.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/mach-xen/setup_arch_pre.h   2008-05-19 00:34:21.764859151 +0300
 @@ -0,0 +1,5 @@
 +/* Hook to call BIOS initialisation function */
 +
 +#define ARCH_SETUP machine_specific_arch_setup();
 +
 +static void __init machine_specific_arch_setup(void);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/aio.h linux-2.6.18-xen.hg/include/linux/aio.h
---- linux-2.6.18/include/linux/aio.h   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/aio.h    2007-12-23 11:15:43.865117435 +0100
+--- linux-2.6.18.8/include/asm-x86_64/msi.h    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/msi.h       2008-05-19 00:34:21.776859843 +0300
+@@ -7,14 +7,21 @@
+ #define ASM_MSI_H
+ #include <asm/desc.h>
++#ifndef CONFIG_XEN
+ #include <asm/mach_apic.h>
++#endif
+ #include <asm/smp.h>
++#ifndef CONFIG_XEN
+ #define LAST_DEVICE_VECTOR    (FIRST_SYSTEM_VECTOR - 1)
++#else
++#define LAST_DYNAMIC_VECTOR 0xdf
++#define LAST_DEVICE_VECTOR    (LAST_DYNAMIC_VECTOR)
++#endif
++
+ #define MSI_TARGET_CPU_SHIFT  12
+ extern struct msi_ops msi_apic_ops;
+-
+ static inline int msi_arch_init(void)
+ {
+       msi_register(&msi_apic_ops);
+--- linux-2.6.18.8/include/asm-x86_64/signal.h 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/signal.h    2008-05-19 00:34:21.836863301 +0300
+@@ -24,10 +24,6 @@
+ } sigset_t;
+-struct pt_regs; 
+-asmlinkage int do_signal(struct pt_regs *regs, sigset_t *oldset);
+-
+-
+ #else
+ /* Here we must cater to libcs that poke about in kernel headers.  */
+--- linux-2.6.18.8/include/asm-x86_64/thread_info.h    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/thread_info.h       2008-05-19 00:34:21.872865377 +0300
+@@ -114,6 +114,7 @@
+ #define TIF_IRET              5       /* force IRET */
+ #define TIF_SYSCALL_AUDIT     7       /* syscall auditing active */
+ #define TIF_SECCOMP           8       /* secure computing */
++#define TIF_RESTORE_SIGMASK   9       /* restore signal mask in do_signal */
+ /* 16 free */
+ #define TIF_IA32              17      /* 32bit process */ 
+ #define TIF_FORK              18      /* ret_from_fork */
+@@ -128,6 +129,7 @@
+ #define _TIF_IRET             (1<<TIF_IRET)
+ #define _TIF_SYSCALL_AUDIT    (1<<TIF_SYSCALL_AUDIT)
+ #define _TIF_SECCOMP          (1<<TIF_SECCOMP)
++#define _TIF_RESTORE_SIGMASK  (1<<TIF_RESTORE_SIGMASK)
+ #define _TIF_IA32             (1<<TIF_IA32)
+ #define _TIF_FORK             (1<<TIF_FORK)
+ #define _TIF_ABI_PENDING      (1<<TIF_ABI_PENDING)
+--- linux-2.6.18.8/include/asm-x86_64/unistd.h 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/asm-x86_64/unistd.h    2008-05-19 00:34:21.880865838 +0300
+@@ -600,9 +600,9 @@
+ #define __NR_faccessat                269
+ __SYSCALL(__NR_faccessat, sys_faccessat)
+ #define __NR_pselect6         270
+-__SYSCALL(__NR_pselect6, sys_ni_syscall)      /* for now */
++__SYSCALL(__NR_pselect6, sys_pselect6)
+ #define __NR_ppoll            271
+-__SYSCALL(__NR_ppoll, sys_ni_syscall)         /* for now */
++__SYSCALL(__NR_ppoll, sys_ppoll)
+ #define __NR_unshare          272
+ __SYSCALL(__NR_unshare,       sys_unshare)
+ #define __NR_set_robust_list  273
+@@ -658,6 +658,7 @@
+ #define __ARCH_WANT_SYS_SIGPENDING
+ #define __ARCH_WANT_SYS_SIGPROCMASK
+ #define __ARCH_WANT_SYS_RT_SIGACTION
++#define __ARCH_WANT_SYS_RT_SIGSUSPEND
+ #define __ARCH_WANT_SYS_TIME
+ #define __ARCH_WANT_COMPAT_SYS_TIME
+--- linux-2.6.18.8/include/linux/aio.h 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/aio.h    2008-05-19 00:34:23.376952075 +0300
 @@ -191,6 +191,11 @@
        struct aio_ring_info    ring_info;
  
@@ -124098,9 +188995,51 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/aio.h linu
  };
  
  /* prototypes */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/crash_dump.h linux-2.6.18-xen.hg/include/linux/crash_dump.h
---- linux-2.6.18/include/linux/crash_dump.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/crash_dump.h     2007-12-23 11:15:43.918453570 +0100
+--- linux-2.6.18.8/include/linux/bio.h 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/bio.h    2008-05-19 00:34:23.592964527 +0300
+@@ -172,12 +172,27 @@
+ #define bio_offset(bio)               bio_iovec((bio))->bv_offset
+ #define bio_segments(bio)     ((bio)->bi_vcnt - (bio)->bi_idx)
+ #define bio_sectors(bio)      ((bio)->bi_size >> 9)
+-#define bio_cur_sectors(bio)  (bio_iovec(bio)->bv_len >> 9)
+-#define bio_data(bio)         (page_address(bio_page((bio))) + bio_offset((bio)))
+ #define bio_barrier(bio)      ((bio)->bi_rw & (1 << BIO_RW_BARRIER))
+ #define bio_sync(bio)         ((bio)->bi_rw & (1 << BIO_RW_SYNC))
+ #define bio_failfast(bio)     ((bio)->bi_rw & (1 << BIO_RW_FAILFAST))
+ #define bio_rw_ahead(bio)     ((bio)->bi_rw & (1 << BIO_RW_AHEAD))
++#define bio_empty_barrier(bio)        (bio_barrier(bio) && !(bio)->bi_size)
++
++static inline unsigned int bio_cur_sectors(struct bio *bio)
++{
++      if (bio->bi_vcnt)
++              return bio_iovec(bio)->bv_len >> 9;
++
++      return 0;
++}
++
++static inline void *bio_data(struct bio *bio)
++{
++      if (bio->bi_vcnt)
++              return page_address(bio_page(bio)) + bio_offset(bio);
++
++      return NULL;
++}
+ /*
+  * will die
+--- linux-2.6.18.8/include/linux/blkdev.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/blkdev.h 2008-05-19 00:34:23.596964757 +0300
+@@ -506,6 +506,8 @@
+ #define blk_barrier_rq(rq)    ((rq)->flags & REQ_HARDBARRIER)
+ #define blk_fua_rq(rq)                ((rq)->flags & REQ_FUA)
++#define blk_empty_barrier(rq)   (blk_barrier_rq(rq) && blk_fs_request(rq) && !(rq)->hard_nr_sectors)
++
+ #define list_entry_rq(ptr)    list_entry((ptr), struct request, queuelist)
+ #define rq_data_dir(rq)               ((rq)->flags & 1)
+--- linux-2.6.18.8/include/linux/crash_dump.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/crash_dump.h     2008-05-19 00:34:24.092993349 +0300
 @@ -14,5 +14,13 @@
  extern const struct file_operations proc_vmcore_operations;
  extern struct proc_dir_entry *proc_vmcore;
@@ -124115,9 +189054,33 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/crash_dump
 +
  #endif /* CONFIG_CRASH_DUMP */
  #endif /* LINUX_CRASHDUMP_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/elfnote.h linux-2.6.18-xen.hg/include/linux/elfnote.h
---- linux-2.6.18/include/linux/elfnote.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/linux/elfnote.h        2007-12-23 11:15:43.981790229 +0100
+--- linux-2.6.18.8/include/linux/debugfs.h     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/debugfs.h        2008-05-19 00:34:24.132995655 +0300
+@@ -41,6 +41,8 @@
+                                 struct dentry *parent, u16 *value);
+ struct dentry *debugfs_create_u32(const char *name, mode_t mode,
+                                 struct dentry *parent, u32 *value);
++struct dentry *debugfs_create_u64(const char *name, mode_t mode,
++                                struct dentry *parent, u64 *value);
+ struct dentry *debugfs_create_bool(const char *name, mode_t mode,
+                                 struct dentry *parent, u32 *value);
+@@ -94,6 +96,13 @@
+       return ERR_PTR(-ENODEV);
+ }
++static inline struct dentry *debugfs_create_u64(const char *name, mode_t mode,
++                                              struct dentry *parent,
++                                              u64 *value)
++{
++      return ERR_PTR(-ENODEV);
++}
++
+ static inline struct dentry *debugfs_create_bool(const char *name, mode_t mode,
+                                                struct dentry *parent,
+                                                u32 *value)
+--- linux-2.6.18.8/include/linux/elfnote.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/elfnote.h        2008-05-19 00:34:24.285004417 +0300
 @@ -0,0 +1,104 @@
 +#ifndef _LINUX_ELFNOTE_H
 +#define _LINUX_ELFNOTE_H
@@ -124223,9 +189186,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/elfnote.h
 +#endif        /* __ASSEMBLER__ */
 +
 +#endif /* _LINUX_ELFNOTE_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/eventpoll.h linux-2.6.18-xen.hg/include/linux/eventpoll.h
---- linux-2.6.18/include/linux/eventpoll.h     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/eventpoll.h      2007-12-23 11:15:43.981790229 +0100
+--- linux-2.6.18.8/include/linux/eventpoll.h   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/eventpoll.h      2008-05-19 00:34:24.289004648 +0300
 @@ -90,6 +90,12 @@
        eventpoll_release_file(file);
  }
@@ -124239,9 +189201,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/eventpoll.
  #else
  
  static inline void eventpoll_init_file(struct file *file) {}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/highmem.h linux-2.6.18-xen.hg/include/linux/highmem.h
---- linux-2.6.18/include/linux/highmem.h       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/highmem.h        2007-12-23 11:15:44.051793905 +0100
+--- linux-2.6.18.8/include/linux/highmem.h     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/highmem.h        2008-05-19 00:34:24.737030473 +0300
 @@ -24,10 +24,16 @@
  
  /* declarations for linux/mm/highmem.c */
@@ -124259,9 +189220,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/highmem.h
  
  static inline void *kmap(struct page *page)
  {
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/interrupt.h linux-2.6.18-xen.hg/include/linux/interrupt.h
---- linux-2.6.18/include/linux/interrupt.h     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/interrupt.h      2007-12-23 11:15:44.531819112 +0100
+--- linux-2.6.18.8/include/linux/interrupt.h   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/interrupt.h      2008-05-19 00:34:25.057048919 +0300
 @@ -166,6 +166,12 @@
  
  #endif /* CONFIG_GENERIC_HARDIRQS */
@@ -124275,22 +189235,20 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/interrupt.
  #ifndef __ARCH_SET_SOFTIRQ_PENDING
  #define set_softirq_pending(x) (local_softirq_pending() = (x))
  #define or_softirq_pending(x)  (local_softirq_pending() |= (x))
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/ioport.h linux-2.6.18-xen.hg/include/linux/ioport.h
---- linux-2.6.18/include/linux/ioport.h        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/ioport.h 2007-12-23 11:15:44.535152621 +0100
+--- linux-2.6.18.8/include/linux/ioport.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/ioport.h 2008-05-19 00:34:25.073049842 +0300
 @@ -93,6 +93,9 @@
  /* PC/ISA/whatever - the normal PC address spaces: IO and memory */
  extern struct resource ioport_resource;
  extern struct resource iomem_resource;
-+#ifdef CONFIG_XEN
++#ifdef CONFIG_PROC_IOMEM_MACHINE
 +extern struct resource iomem_machine_resource;
 +#endif
  
  extern int request_resource(struct resource *root, struct resource *new);
  extern struct resource * ____request_resource(struct resource *root, struct resource *new);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/kexec.h linux-2.6.18-xen.hg/include/linux/kexec.h
---- linux-2.6.18/include/linux/kexec.h 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/kexec.h  2007-12-23 11:15:44.931840116 +0100
+--- linux-2.6.18.8/include/linux/kexec.h       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/kexec.h  2008-05-19 00:34:25.305063215 +0300
 @@ -31,6 +31,13 @@
  #error KEXEC_ARCH not defined
  #endif
@@ -124337,20 +189295,20 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/kexec.h li
  #else /* !CONFIG_KEXEC */
  struct pt_regs;
  struct task_struct;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/mm.h linux-2.6.18-xen.hg/include/linux/mm.h
---- linux-2.6.18/include/linux/mm.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/mm.h     2007-12-23 11:15:44.965175206 +0100
-@@ -164,6 +164,9 @@
+--- linux-2.6.18.8/include/linux/mm.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/mm.h     2008-05-19 00:34:25.417069672 +0300
+@@ -164,6 +164,10 @@
  #define VM_NONLINEAR  0x00800000      /* Is non-linear (remap_file_pages) */
  #define VM_MAPPED_COPY        0x01000000      /* T if mapped copy of data (nommu mmap) */
  #define VM_INSERTPAGE 0x02000000      /* The vma has had "vm_insert_page()" done on it */
 +#ifdef CONFIG_XEN
 +#define VM_FOREIGN    0x04000000      /* Has pages belonging to another VM */
 +#endif
++#define VM_ALWAYSDUMP 0x08000000      /* Always include in core dumps */
  
  #ifndef VM_STACK_DEFAULT_FLAGS                /* arch can override this */
  #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS
-@@ -202,6 +205,10 @@
+@@ -202,6 +206,10 @@
        /* notification that a previously read-only page is about to become
         * writable, if an error is returned it will cause a SIGBUS */
        int (*page_mkwrite)(struct vm_area_struct *vma, struct page *page);
@@ -124361,7 +189319,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/mm.h linux
  #ifdef CONFIG_NUMA
        int (*set_policy)(struct vm_area_struct *vma, struct mempolicy *new);
        struct mempolicy *(*get_policy)(struct vm_area_struct *vma,
-@@ -1027,6 +1034,13 @@
+@@ -1027,6 +1035,13 @@
  #define FOLL_GET      0x04    /* do get_page on page */
  #define FOLL_ANON     0x08    /* give ZERO_PAGE if no pgtable */
  
@@ -124375,9 +189333,35 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/mm.h linux
  #ifdef CONFIG_PROC_FS
  void vm_stat_account(struct mm_struct *, unsigned long, struct file *, long);
  #else
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/netfilter_bridge.h linux-2.6.18-xen.hg/include/linux/netfilter_bridge.h
---- linux-2.6.18/include/linux/netfilter_bridge.h      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/netfilter_bridge.h       2007-12-23 11:15:45.015177827 +0100
+--- linux-2.6.18.8/include/linux/moduleparam.h 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/moduleparam.h    2008-05-19 00:34:25.449071516 +0300
+@@ -58,13 +58,23 @@
+       void *elem;
+ };
++/* On alpha, ia64 and ppc64 relocations to global data cannot go into
++   read-only sections (which is part of respective UNIX ABI on these
++   platforms). So 'const' makes no sense and even causes compile failures
++   with some compilers. */
++#if defined(CONFIG_ALPHA) || defined(CONFIG_IA64) || defined(CONFIG_PPC64)
++#define __moduleparam_const
++#else
++#define __moduleparam_const const
++#endif
++
+ /* This is the fundamental function for registering boot/module
+    parameters.  perm sets the visibility in driverfs: 000 means it's
+    not there, read bits mean it's readable, write bits mean it's
+    writable. */
+ #define __module_param_call(prefix, name, set, get, arg, perm)                \
+       static char __param_str_##name[] = prefix #name;                \
+-      static struct kernel_param const __param_##name                 \
++      static struct kernel_param __moduleparam_const __param_##name   \
+       __attribute_used__                                              \
+     __attribute__ ((unused,__section__ ("__param"),aligned(sizeof(void *)))) \
+       = { __param_str_##name, perm, set, get, arg }
+--- linux-2.6.18.8/include/linux/netfilter_bridge.h    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/netfilter_bridge.h       2008-05-19 00:34:25.837093883 +0300
 @@ -7,6 +7,7 @@
  #include <linux/netfilter.h>
  #if defined(__KERNEL__) && defined(CONFIG_BRIDGE_NETFILTER)
@@ -124411,9 +189395,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/netfilter_
                }
        }
        return 0;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/oprofile.h linux-2.6.18-xen.hg/include/linux/oprofile.h
---- linux-2.6.18/include/linux/oprofile.h      2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/oprofile.h       2007-12-23 11:15:45.098515532 +0100
+--- linux-2.6.18.8/include/linux/oprofile.h    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/oprofile.h       2008-05-19 00:34:26.497131929 +0300
 @@ -17,6 +17,8 @@
  #include <linux/spinlock.h>
  #include <asm/atomic.h>
@@ -124444,9 +189427,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/oprofile.h
  
  /**
   * Create a file of the given name as a child of the given root, with
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/page-flags.h linux-2.6.18-xen.hg/include/linux/page-flags.h
---- linux-2.6.18/include/linux/page-flags.h    2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/page-flags.h     2007-12-23 11:15:45.098515532 +0100
+--- linux-2.6.18.8/include/linux/page-flags.h  2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/page-flags.h     2008-05-19 00:34:26.501132159 +0300
 @@ -98,6 +98,8 @@
  #define PG_uncached           31      /* Page has been mapped as uncached */
  #endif
@@ -124456,28 +189438,40 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/page-flags
  /*
   * Manipulation of page state flags
   */
-@@ -247,6 +249,18 @@
+@@ -247,6 +249,19 @@
  #define SetPageUncached(page) set_bit(PG_uncached, &(page)->flags)
  #define ClearPageUncached(page)       clear_bit(PG_uncached, &(page)->flags)
  
 +#define PageForeign(page)     test_bit(PG_foreign, &(page)->flags)
-+#define SetPageForeign(page, dtor) do {               \
-+      set_bit(PG_foreign, &(page)->flags);    \
-+      (page)->index = (long)(dtor);           \
++#define SetPageForeign(_page, dtor) do {              \
++      set_bit(PG_foreign, &(_page)->flags);           \
++      BUG_ON((dtor) == (void (*)(struct page *))0);   \
++      (_page)->index = (long)(dtor);                  \
 +} while (0)
-+#define ClearPageForeign(page) do {           \
-+      clear_bit(PG_foreign, &(page)->flags);  \
-+      (page)->index = 0;                      \
++#define ClearPageForeign(page) do {                   \
++      clear_bit(PG_foreign, &(page)->flags);          \
++      (page)->index = 0;                              \
 +} while (0)
-+#define PageForeignDestructor(page)           \
-+      ( (void (*) (struct page *)) (page)->index )(page)
++#define PageForeignDestructor(_page)                  \
++      ((void (*)(struct page *))(_page)->index)(_page)
 +
  struct page;  /* forward declaration */
  
  int test_clear_page_dirty(struct page *page);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/pci_ids.h linux-2.6.18-xen.hg/include/linux/pci_ids.h
---- linux-2.6.18/include/linux/pci_ids.h       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/pci_ids.h        2007-12-23 11:15:45.105182559 +0100
+--- linux-2.6.18.8/include/linux/pci.h 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/pci.h    2008-05-19 00:34:26.509132620 +0300
+@@ -152,6 +152,9 @@
+        * directly, use the values stored here. They might be different!
+        */
+       unsigned int    irq;
++#ifdef CONFIG_XEN
++      unsigned int    irq_old;
++#endif
+       struct resource resource[DEVICE_COUNT_RESOURCE]; /* I/O and memory regions + expansion ROMs */
+       /* These fields are used by common fixups */
+--- linux-2.6.18.8/include/linux/pci_ids.h     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/pci_ids.h        2008-05-19 00:34:26.509132620 +0300
 @@ -2188,6 +2188,13 @@
  #define PCI_DEVICE_ID_INTEL_ICH8_4    0x2815
  #define PCI_DEVICE_ID_INTEL_ICH8_5    0x283e
@@ -124492,9 +189486,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/pci_ids.h
  #define PCI_DEVICE_ID_INTEL_82855PM_HB        0x3340
  #define PCI_DEVICE_ID_INTEL_82830_HB  0x3575
  #define PCI_DEVICE_ID_INTEL_82830_CGC 0x3577
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/sched.h linux-2.6.18-xen.hg/include/linux/sched.h
---- linux-2.6.18/include/linux/sched.h 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/sched.h  2007-12-23 11:15:45.168519210 +0100
+@@ -2202,6 +2209,12 @@
+ #define PCI_DEVICE_ID_INTEL_MCH_PC    0x3599
+ #define PCI_DEVICE_ID_INTEL_MCH_PC1   0x359a
+ #define PCI_DEVICE_ID_INTEL_E7525_MCH 0x359e
++#define PCI_DEVICE_ID_INTEL_ICH10_0   0x3a14
++#define PCI_DEVICE_ID_INTEL_ICH10_1   0x3a16
++#define PCI_DEVICE_ID_INTEL_ICH10_2   0x3a18
++#define PCI_DEVICE_ID_INTEL_ICH10_3   0x3a1a
++#define PCI_DEVICE_ID_INTEL_ICH10_4   0x3a30
++#define PCI_DEVICE_ID_INTEL_ICH10_5   0x3a60
+ #define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
+ #define PCI_DEVICE_ID_INTEL_82371SB_1 0x7010
+ #define PCI_DEVICE_ID_INTEL_82371SB_2 0x7020
+--- linux-2.6.18.8/include/linux/sched.h       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/sched.h  2008-05-19 00:34:26.605138154 +0300
 @@ -211,10 +211,15 @@
  extern void scheduler_tick(void);
  
@@ -124511,9 +189517,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/sched.h li
  static inline void softlockup_tick(void)
  {
  }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/skbuff.h linux-2.6.18-xen.hg/include/linux/skbuff.h
---- linux-2.6.18/include/linux/skbuff.h        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/include/linux/skbuff.h 2007-12-23 11:15:45.181853251 +0100
+--- linux-2.6.18.8/include/linux/skbuff.h      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/skbuff.h 2008-05-19 00:34:26.633139768 +0300
 @@ -203,6 +203,8 @@
   *    @local_df: allow local fragmentation
   *    @cloned: Head may be cloned (check refcnt to be sure)
@@ -124537,9 +189542,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/skbuff.h l
        __be16                  protocol;
  
        void                    (*destructor)(struct sk_buff *skb);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/sysctl.h linux-2.6.18-xen.hg/include/linux/sysctl.h
---- linux-2.6.18/include/linux/sysctl.h        2007-12-23 11:26:51.286801791 +0100
-+++ linux-2.6.18-xen.hg/include/linux/sysctl.h 2007-12-23 11:15:45.848554922 +0100
+--- linux-2.6.18.8/include/linux/sysctl.h      2008-05-19 00:42:34.397258564 +0300
++++ linux-2.6.18-xen.hg/include/linux/sysctl.h 2008-05-19 00:34:26.689142997 +0300
 @@ -6,10 +6,17 @@
   ****************************************************************
   ****************************************************************
@@ -124569,9 +189573,30 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/linux/sysctl.h l
  #endif
  
  enum
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/balloon.h linux-2.6.18-xen.hg/include/xen/balloon.h
---- linux-2.6.18/include/xen/balloon.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/balloon.h  2007-12-23 11:15:46.468587483 +0100
+--- linux-2.6.18.8/include/linux/vermagic.h    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/include/linux/vermagic.h       2008-05-19 00:34:26.765147378 +0300
+@@ -17,6 +17,11 @@
+ #else
+ #define MODULE_VERMAGIC_MODULE_UNLOAD ""
+ #endif
++#ifdef CONFIG_XEN
++#define MODULE_VERMAGIC_XEN "Xen "
++#else
++#define MODULE_VERMAGIC_XEN
++#endif
+ #ifndef MODULE_ARCH_VERMAGIC
+ #define MODULE_ARCH_VERMAGIC ""
+ #endif
+@@ -24,5 +29,6 @@
+ #define VERMAGIC_STRING                                               \
+       UTS_RELEASE " "                                                 \
+       MODULE_VERMAGIC_SMP MODULE_VERMAGIC_PREEMPT                     \
+-      MODULE_VERMAGIC_MODULE_UNLOAD MODULE_ARCH_VERMAGIC              \
++      MODULE_VERMAGIC_MODULE_UNLOAD MODULE_VERMAGIC_XEN               \
++      MODULE_ARCH_VERMAGIC                                            \
+       "gcc-" __stringify(__GNUC__) "." __stringify(__GNUC_MINOR__)
+--- linux-2.6.18.8/include/xen/balloon.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/balloon.h  2008-05-19 00:34:28.317236843 +0300
 @@ -0,0 +1,57 @@
 +/******************************************************************************
 + * balloon.h
@@ -124630,10 +189655,29 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/balloon.h li
 +#define balloon_unlock(__flags) spin_unlock_irqrestore(&balloon_lock, __flags)
 +
 +#endif /* __ASM_BALLOON_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/blkif.h linux-2.6.18-xen.hg/include/xen/blkif.h
---- linux-2.6.18/include/xen/blkif.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/blkif.h    2007-12-23 11:15:46.468587483 +0100
-@@ -0,0 +1,101 @@
+--- linux-2.6.18.8/include/xen/blkif.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/blkif.h    2008-05-19 00:34:28.317236843 +0300
+@@ -0,0 +1,123 @@
++/* 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ */
++
 +#ifndef __XEN_BLKIF_H__
 +#define __XEN_BLKIF_H__
 +
@@ -124714,8 +189758,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/blkif.h linu
 +      dst->handle = src->handle;
 +      dst->id = src->id;
 +      dst->sector_number = src->sector_number;
-+      if (n > src->nr_segments)
-+              n = src->nr_segments;
++      barrier();
++      if (n > dst->nr_segments)
++              n = dst->nr_segments;
 +      for (i = 0; i < n; i++)
 +              dst->seg[i] = src->seg[i];
 +}
@@ -124728,16 +189773,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/blkif.h linu
 +      dst->handle = src->handle;
 +      dst->id = src->id;
 +      dst->sector_number = src->sector_number;
-+      if (n > src->nr_segments)
-+              n = src->nr_segments;
++      barrier();
++      if (n > dst->nr_segments)
++              n = dst->nr_segments;
 +      for (i = 0; i < n; i++)
 +              dst->seg[i] = src->seg[i];
 +}
 +
 +#endif /* __XEN_BLKIF_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/compat_ioctl.h linux-2.6.18-xen.hg/include/xen/compat_ioctl.h
---- linux-2.6.18/include/xen/compat_ioctl.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/compat_ioctl.h     2007-12-23 11:15:46.468587483 +0100
+--- linux-2.6.18.8/include/xen/compat_ioctl.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/compat_ioctl.h     2008-05-19 00:34:28.321237074 +0300
 @@ -0,0 +1,45 @@
 +/*
 + * This program is free software; you can redistribute it and/or
@@ -124784,9 +189829,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/compat_ioctl
 +      _IOC(_IOC_NONE, 'P', 3, sizeof(struct privcmd_mmapbatch_32))
 +
 +#endif /* __LINUX_XEN_COMPAT_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/cpu_hotplug.h linux-2.6.18-xen.hg/include/xen/cpu_hotplug.h
---- linux-2.6.18/include/xen/cpu_hotplug.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/cpu_hotplug.h      2007-12-23 11:15:46.468587483 +0100
+--- linux-2.6.18.8/include/xen/cpu_hotplug.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/cpu_hotplug.h      2008-05-19 00:34:28.321237074 +0300
 @@ -0,0 +1,41 @@
 +#ifndef __XEN_CPU_HOTPLUG_H__
 +#define __XEN_CPU_HOTPLUG_H__
@@ -124829,9 +189873,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/cpu_hotplug.
 +#endif /* !defined(CONFIG_HOTPLUG_CPU) */
 +
 +#endif /* __XEN_CPU_HOTPLUG_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/driver_util.h linux-2.6.18-xen.hg/include/xen/driver_util.h
---- linux-2.6.18/include/xen/driver_util.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/driver_util.h      2007-12-23 11:15:46.468587483 +0100
+--- linux-2.6.18.8/include/xen/driver_util.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/driver_util.h      2008-05-19 00:34:28.321237074 +0300
 @@ -0,0 +1,14 @@
 +
 +#ifndef __ASM_XEN_DRIVER_UTIL_H__
@@ -124847,10 +189890,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/driver_util.
 +extern struct class *get_xen_class(void);
 +
 +#endif /* __ASM_XEN_DRIVER_UTIL_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/evtchn.h linux-2.6.18-xen.hg/include/xen/evtchn.h
---- linux-2.6.18/include/xen/evtchn.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/evtchn.h   2007-12-23 11:15:46.468587483 +0100
-@@ -0,0 +1,139 @@
+--- linux-2.6.18.8/include/xen/evtchn.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/evtchn.h   2008-05-19 00:34:28.321237074 +0300
+@@ -0,0 +1,153 @@
 +/******************************************************************************
 + * evtchn.h
 + * 
@@ -124979,7 +190021,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/evtchn.h lin
 +static inline void notify_remote_via_evtchn(int port)
 +{
 +      struct evtchn_send send = { .port = port };
-+      (void)HYPERVISOR_event_channel_op(EVTCHNOP_send, &send);
++      VOID(HYPERVISOR_event_channel_op(EVTCHNOP_send, &send));
 +}
 +
 +/*
@@ -124989,10 +190031,23 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/evtchn.h lin
 +void notify_remote_via_irq(int irq);
 +int irq_to_evtchn_port(int irq);
 +
++#define PIRQ_SET_MAPPING 0x0
++#define PIRQ_CLEAR_MAPPING 0x1
++#define PIRQ_GET_MAPPING 0x3
++int pirq_mapstatus(int pirq, int action);
++int set_pirq_hw_action(int pirq, int (*action)(int pirq, int action));
++int clear_pirq_hw_action(int pirq);
++
++#define PIRQ_STARTUP 1
++#define PIRQ_SHUTDOWN 2
++#define PIRQ_ENABLE 3
++#define PIRQ_DISABLE 4
++#define PIRQ_END 5
++#define PIRQ_ACK 6
++
 +#endif /* __ASM_EVTCHN_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/features.h linux-2.6.18-xen.hg/include/xen/features.h
---- linux-2.6.18/include/xen/features.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/features.h 2007-12-23 11:15:46.471920991 +0100
+--- linux-2.6.18.8/include/xen/features.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/features.h 2008-05-19 00:34:28.321237074 +0300
 @@ -0,0 +1,20 @@
 +/******************************************************************************
 + * features.h
@@ -125014,9 +190069,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/features.h l
 +#define xen_feature(flag)     (xen_features[flag])
 +
 +#endif /* __ASM_XEN_FEATURES_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/firmware.h linux-2.6.18-xen.hg/include/xen/firmware.h
---- linux-2.6.18/include/xen/firmware.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/firmware.h 2007-12-23 11:15:46.471920991 +0100
+--- linux-2.6.18.8/include/xen/firmware.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/firmware.h 2008-05-19 00:34:28.325237304 +0300
 @@ -0,0 +1,10 @@
 +#ifndef __XEN_FIRMWARE_H__
 +#define __XEN_FIRMWARE_H__
@@ -125028,9 +190082,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/firmware.h l
 +void copy_edid(void);
 +
 +#endif /* __XEN_FIRMWARE_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/gnttab.h linux-2.6.18-xen.hg/include/xen/gnttab.h
---- linux-2.6.18/include/xen/gnttab.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/gnttab.h   2007-12-23 11:15:46.471920991 +0100
+--- linux-2.6.18.8/include/xen/gnttab.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/gnttab.h   2008-05-19 00:34:28.325237304 +0300
 @@ -0,0 +1,163 @@
 +/******************************************************************************
 + * gnttab.h
@@ -125195,9 +190248,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/gnttab.h lin
 +}
 +
 +#endif /* __ASM_GNTTAB_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/hvm.h linux-2.6.18-xen.hg/include/xen/hvm.h
---- linux-2.6.18/include/xen/hvm.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/hvm.h      2007-12-23 11:15:46.471920991 +0100
+--- linux-2.6.18.8/include/xen/hvm.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/hvm.h      2008-05-19 00:34:28.325237304 +0300
 @@ -0,0 +1,23 @@
 +/* Simple wrappers around HVM functions */
 +#ifndef XEN_HVM_H__
@@ -125222,18 +190274,17 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/hvm.h linux-
 +}
 +
 +#endif /* XEN_HVM_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/hypercall.h linux-2.6.18-xen.hg/include/xen/hypercall.h
---- linux-2.6.18/include/xen/hypercall.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/hypercall.h        2007-12-23 11:15:46.471920991 +0100
-@@ -0,0 +1,24 @@
+--- linux-2.6.18.8/include/xen/hypercall.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/hypercall.h        2008-05-19 00:34:28.325237304 +0300
+@@ -0,0 +1,30 @@
 +#ifndef __XEN_HYPERCALL_H__
 +#define __XEN_HYPERCALL_H__
 +
 +#include <asm/hypercall.h>
 +
-+static inline int
++static inline int __must_check
 +HYPERVISOR_multicall_check(
-+      multicall_entry_t *call_list, int nr_calls,
++      multicall_entry_t *call_list, unsigned int nr_calls,
 +      const unsigned long *rc_list)
 +{
 +      int rc = HYPERVISOR_multicall(call_list, nr_calls);
@@ -125241,6 +190292,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/hypercall.h
 +      if (unlikely(rc < 0))
 +              return rc;
 +      BUG_ON(rc);
++      BUG_ON((int)nr_calls < 0);
 +
 +      for ( ; nr_calls > 0; --nr_calls, ++call_list)
 +              if (unlikely(call_list->result != (rc_list ? *rc_list++ : 0)))
@@ -125249,10 +190301,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/hypercall.h
 +      return 0;
 +}
 +
++/* A construct to ignore the return value of hypercall wrappers in a few
++ * exceptional cases (simply casting the function result to void doesn't
++ * avoid the compiler warning): */
++#define VOID(expr) ((void)((expr)?:0))
++
 +#endif /* __XEN_HYPERCALL_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/hypervisor_sysfs.h linux-2.6.18-xen.hg/include/xen/hypervisor_sysfs.h
---- linux-2.6.18/include/xen/hypervisor_sysfs.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/hypervisor_sysfs.h 2007-12-23 11:15:46.471920991 +0100
+--- linux-2.6.18.8/include/xen/hypervisor_sysfs.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/hypervisor_sysfs.h 2008-05-19 00:34:28.325237304 +0300
 @@ -0,0 +1,30 @@
 +/*
 + *  copyright (c) 2006 IBM Corporation
@@ -125284,9 +190340,49 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/hypervisor_s
 +};
 +
 +#endif /* _HYP_SYSFS_H_ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/acm.h linux-2.6.18-xen.hg/include/xen/interface/acm.h
---- linux-2.6.18/include/xen/interface/acm.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/acm.h    2007-12-23 11:15:46.475254497 +0100
+--- linux-2.6.18.8/include/xen/interface/COPYING       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/COPYING  2008-05-19 00:34:28.325237304 +0300
+@@ -0,0 +1,38 @@
++XEN NOTICE
++==========
++
++This copyright applies to all files within this subdirectory and its
++subdirectories:
++  include/public/*.h
++  include/public/hvm/*.h
++  include/public/io/*.h
++
++The intention is that these files can be freely copied into the source
++tree of an operating system when porting that OS to run on Xen. Doing
++so does *not* cause the OS to become subject to the terms of the GPL.
++
++All other files in the Xen source distribution are covered by version
++2 of the GNU General Public License except where explicitly stated
++otherwise within individual source files.
++
++ -- Keir Fraser (on behalf of the Xen team)
++
++=====================================================================
++
++Permission is hereby granted, free of charge, to any person obtaining a copy
++of this software and associated documentation files (the "Software"), to
++deal in the Software without restriction, including without limitation the
++rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++sell copies of the Software, and to permit persons to whom the Software is
++furnished to do so, subject to the following conditions:
++
++The above copyright notice and this permission notice shall be included in
++all copies or substantial portions of the Software.
++
++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
++IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
++FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
++AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
++LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
++FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
++DEALINGS IN THE SOFTWARE.
+--- linux-2.6.18.8/include/xen/interface/acm.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/acm.h    2008-05-19 00:34:28.329237535 +0300
 @@ -0,0 +1,228 @@
 +/*
 + * acm.h: Xen access control module interface defintions
@@ -125516,9 +190612,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ac
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/acm_ops.h linux-2.6.18-xen.hg/include/xen/interface/acm_ops.h
---- linux-2.6.18/include/xen/interface/acm_ops.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/acm_ops.h        2007-12-23 11:15:46.475254497 +0100
+--- linux-2.6.18.8/include/xen/interface/acm_ops.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/acm_ops.h        2008-05-19 00:34:28.329237535 +0300
 @@ -0,0 +1,159 @@
 +/*
 + * acm_ops.h: Xen access control module hypervisor commands
@@ -125679,9 +190774,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ac
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/arch-ia64/debug_op.h linux-2.6.18-xen.hg/include/xen/interface/arch-ia64/debug_op.h
---- linux-2.6.18/include/xen/interface/arch-ia64/debug_op.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/arch-ia64/debug_op.h     2007-12-23 11:15:46.475254497 +0100
+--- linux-2.6.18.8/include/xen/interface/arch-ia64/debug_op.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-ia64/debug_op.h     2008-05-19 00:34:28.333237766 +0300
 @@ -0,0 +1,96 @@
 +/******************************************************************************
 + * debug_op.h
@@ -125779,9 +190873,99 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +DEFINE_XEN_GUEST_HANDLE(xen_ia64_debug_op_t);
 +
 +#endif /* __XEN_PUBLIC_IA64_DEBUG_OP_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/arch-ia64/hvm/save.h linux-2.6.18-xen.hg/include/xen/interface/arch-ia64/hvm/save.h
---- linux-2.6.18/include/xen/interface/arch-ia64/hvm/save.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/arch-ia64/hvm/save.h     2007-12-23 11:15:46.475254497 +0100
+--- linux-2.6.18.8/include/xen/interface/arch-ia64/hvm/memmap.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-ia64/hvm/memmap.h   2008-05-19 00:34:28.333237766 +0300
+@@ -0,0 +1,88 @@
++/******************************************************************************
++ * memmap.h
++ *
++ * Copyright (c) 2008 Tristan Gingold <tgingold AT free fr>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#ifndef __XEN_PUBLIC_HVM_MEMMAP_IA64_H__
++#define __XEN_PUBLIC_HVM_MEMMAP_IA64_H__
++
++#define MEM_G  (1UL << 30)
++#define MEM_M  (1UL << 20)
++#define MEM_K  (1UL << 10)
++
++/* Guest physical address of IO ports space.  */
++#define MMIO_START  (3 * MEM_G)
++#define MMIO_SIZE   (512 * MEM_M)
++
++#define VGA_IO_START  0xA0000UL
++#define VGA_IO_SIZE   0x20000
++
++#define LEGACY_IO_START  (MMIO_START + MMIO_SIZE)
++#define LEGACY_IO_SIZE   (64 * MEM_M)
++
++#define IO_PAGE_START  (LEGACY_IO_START + LEGACY_IO_SIZE)
++#define IO_PAGE_SIZE   XEN_PAGE_SIZE
++
++#define STORE_PAGE_START  (IO_PAGE_START + IO_PAGE_SIZE)
++#define STORE_PAGE_SIZE   XEN_PAGE_SIZE
++
++#define BUFFER_IO_PAGE_START  (STORE_PAGE_START + STORE_PAGE_SIZE)
++#define BUFFER_IO_PAGE_SIZE   XEN_PAGE_SIZE
++
++#define BUFFER_PIO_PAGE_START  (BUFFER_IO_PAGE_START + BUFFER_IO_PAGE_SIZE)
++#define BUFFER_PIO_PAGE_SIZE   XEN_PAGE_SIZE
++
++#define IO_SAPIC_START  0xfec00000UL
++#define IO_SAPIC_SIZE   0x100000
++
++#define PIB_START  0xfee00000UL
++#define PIB_SIZE   0x200000
++
++#define GFW_START  (4 * MEM_G - 16 * MEM_M)
++#define GFW_SIZE   (16 * MEM_M)
++
++/* domVTI */
++#define GPFN_FRAME_BUFFER  0x1 /* VGA framebuffer */
++#define GPFN_LOW_MMIO      0x2 /* Low MMIO range */
++#define GPFN_PIB           0x3 /* PIB base */
++#define GPFN_IOSAPIC       0x4 /* IOSAPIC base */
++#define GPFN_LEGACY_IO     0x5 /* Legacy I/O base */
++#define GPFN_HIGH_MMIO     0x6 /* High MMIO range */
++
++/* Nvram belongs to GFW memory space  */
++#define NVRAM_SIZE   (MEM_K * 64)
++#define NVRAM_START  (GFW_START + 10 * MEM_M)
++
++#define NVRAM_VALID_SIG  0x4650494e45584948 /* "HIXENIPF" */
++struct nvram_save_addr {
++    unsigned long addr;
++    unsigned long signature;
++};
++
++#endif /* __XEN_PUBLIC_HVM_MEMMAP_IA64_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+--- linux-2.6.18.8/include/xen/interface/arch-ia64/hvm/save.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-ia64/hvm/save.h     2008-05-19 00:34:28.333237766 +0300
 @@ -0,0 +1,201 @@
 +/******************************************************************************
 + * save_types.h
@@ -125984,10 +191168,101 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/arch-ia64.h linux-2.6.18-xen.hg/include/xen/interface/arch-ia64.h
---- linux-2.6.18/include/xen/interface/arch-ia64.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/arch-ia64.h      2007-12-23 11:15:46.475254497 +0100
-@@ -0,0 +1,666 @@
+--- linux-2.6.18.8/include/xen/interface/arch-ia64/sioemu.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-ia64/sioemu.h       2008-05-19 00:34:28.333237766 +0300
+@@ -0,0 +1,89 @@
++/******************************************************************************
++ * sioemu.h
++ *
++ * Copyright (c) 2008 Tristan Gingold <tgingold@free.fr>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the Free Software
++ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
++ *
++ */
++
++#ifndef __XEN_PUBLIC_IA64_SIOEMU_H__
++#define __XEN_PUBLIC_IA64_SIOEMU_H__
++
++/* SIOEMU specific hypercalls.
++   The numbers are the minor part of FW_HYPERCALL_SIOEMU.  */
++
++/* Defines the callback entry point.  r8=ip, r9=data.
++   Must be called per-vcpu.  */
++#define SIOEMU_HYPERCALL_SET_CALLBACK 0x01
++
++/* Finish sioemu fw initialization and start firmware.  r8=ip.  */
++#define SIOEMU_HYPERCALL_START_FW 0x02
++
++/* Add IO pages in physmap.  */
++#define SIOEMU_HYPERCALL_ADD_IO_PHYSMAP 0x03
++
++/* Get wallclock time.  */
++#define SIOEMU_HYPERCALL_GET_TIME 0x04
++
++/* Flush cache.  */
++#define SIOEMU_HYPERCALL_FLUSH_CACHE 0x07
++
++/* Get freq base.  */
++#define SIOEMU_HYPERCALL_FREQ_BASE 0x08
++
++/* Return from callback.  */
++#define SIOEMU_HYPERCALL_CALLBACK_RETURN 0x09
++
++/* Deliver an interrupt.  */
++#define SIOEMU_HYPERCALL_DELIVER_INT 0x0a
++
++/* SIOEMU callback reason.  */
++
++/* An event (from event channel) has to be delivered.  */
++#define SIOEMU_CB_EVENT       0x00
++
++/* Emulate an IO access.  */
++#define SIOEMU_CB_IO_EMULATE  0x01
++
++/* An IPI is sent to a dead vcpu.  */
++#define SIOEMU_CB_WAKEUP_VCPU 0x02
++
++/* A SAL hypercall is executed.  */
++#define SIOEMU_CB_SAL_ASSIST  0x03
++
++#ifndef __ASSEMBLY__
++struct sioemu_callback_info {
++    /* Saved registers.  */
++    unsigned long ip;
++    unsigned long psr;
++    unsigned long ifs;
++    unsigned long nats;
++    unsigned long r8;
++    unsigned long r9;
++    unsigned long r10;
++    unsigned long r11;
++
++    /* Callback parameters.  */
++    unsigned long cause;
++    unsigned long arg0;
++    unsigned long arg1;
++    unsigned long arg2;
++    unsigned long arg3;
++    unsigned long _pad2[2];
++    unsigned long r2;
++};
++#endif /* __ASSEMBLY__ */
++#endif /* __XEN_PUBLIC_IA64_SIOEMU_H__ */
+--- linux-2.6.18.8/include/xen/interface/arch-ia64.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-ia64.h      2008-05-19 00:34:28.329237535 +0300
+@@ -0,0 +1,620 @@
 +/******************************************************************************
 + * arch-ia64/hypervisor-if.h
 + * 
@@ -126013,18 +191288,28 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 + *
 + */
 +
++#include "xen.h"
++
 +#ifndef __HYPERVISOR_IF_IA64_H__
 +#define __HYPERVISOR_IF_IA64_H__
 +
++#if !defined(__GNUC__) || defined(__STRICT_ANSI__)
++#error "Anonymous structs/unions are a GNU extension."
++#endif
++
 +/* Structural guest handles introduced in 0x00030201. */
 +#if __XEN_INTERFACE_VERSION__ >= 0x00030201
-+#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \
 +    typedef struct { type *p; } __guest_handle_ ## name
 +#else
-+#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \
 +    typedef type * __guest_handle_ ## name
 +#endif
 +
++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++    ___DEFINE_XEN_GUEST_HANDLE(name, type);   \
++    ___DEFINE_XEN_GUEST_HANDLE(const_##name, const type)
++
 +#define DEFINE_XEN_GUEST_HANDLE(name)   __DEFINE_XEN_GUEST_HANDLE(name, name)
 +#define XEN_GUEST_HANDLE(name)          __guest_handle_ ## name
 +#define XEN_GUEST_HANDLE_64(name)       XEN_GUEST_HANDLE(name)
@@ -126035,18 +191320,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +#endif
 +
 +#ifndef __ASSEMBLY__
-+/* Guest handles for primitive C types. */
-+__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char);
-+__DEFINE_XEN_GUEST_HANDLE(uint,  unsigned int);
-+__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long);
-+__DEFINE_XEN_GUEST_HANDLE(u64,   unsigned long);
-+DEFINE_XEN_GUEST_HANDLE(char);
-+DEFINE_XEN_GUEST_HANDLE(int);
-+DEFINE_XEN_GUEST_HANDLE(long);
-+DEFINE_XEN_GUEST_HANDLE(void);
-+
 +typedef unsigned long xen_pfn_t;
-+DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
 +#define PRI_xen_pfn "lx"
 +#endif
 +
@@ -126059,6 +191333,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +/* WARNING: before changing this, check that shared_info fits on a page */
 +#define MAX_VIRT_CPUS 64
 +
++/* IO ports location for PV.  */
++#define IO_PORTS_PADDR          0x00000ffffc000000UL
++#define IO_PORTS_SIZE           0x0000000004000000UL
++
 +#ifndef __ASSEMBLY__
 +
 +typedef unsigned long xen_ulong_t;
@@ -126071,54 +191349,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +
 +#define INVALID_MFN       (~0UL)
 +
-+#define MEM_G   (1UL << 30)
-+#define MEM_M   (1UL << 20)
-+#define MEM_K   (1UL << 10)
-+
-+/* Guest physical address of IO ports space.  */
-+#define IO_PORTS_PADDR          0x00000ffffc000000UL
-+#define IO_PORTS_SIZE           0x0000000004000000UL
-+
-+#define MMIO_START       (3 * MEM_G)
-+#define MMIO_SIZE        (512 * MEM_M)
-+
-+#define VGA_IO_START     0xA0000UL
-+#define VGA_IO_SIZE      0x20000
-+
-+#define LEGACY_IO_START  (MMIO_START + MMIO_SIZE)
-+#define LEGACY_IO_SIZE   (64*MEM_M)
-+
-+#define IO_PAGE_START (LEGACY_IO_START + LEGACY_IO_SIZE)
-+#define IO_PAGE_SIZE  XEN_PAGE_SIZE
-+
-+#define STORE_PAGE_START (IO_PAGE_START + IO_PAGE_SIZE)
-+#define STORE_PAGE_SIZE  XEN_PAGE_SIZE
-+
-+#define BUFFER_IO_PAGE_START (STORE_PAGE_START + STORE_PAGE_SIZE)
-+#define BUFFER_IO_PAGE_SIZE  XEN_PAGE_SIZE
-+
-+#define BUFFER_PIO_PAGE_START (BUFFER_IO_PAGE_START + BUFFER_IO_PAGE_SIZE)
-+#define BUFFER_PIO_PAGE_SIZE  XEN_PAGE_SIZE
-+
-+#define IO_SAPIC_START   0xfec00000UL
-+#define IO_SAPIC_SIZE    0x100000
-+
-+#define PIB_START 0xfee00000UL
-+#define PIB_SIZE 0x200000
-+
-+#define GFW_START        (4*MEM_G -16*MEM_M)
-+#define GFW_SIZE         (16*MEM_M)
-+
-+/* Nvram belongs to GFW memory space  */
-+#define NVRAM_SIZE       (MEM_K * 64)
-+#define NVRAM_START      (GFW_START + 10 * MEM_M)
-+
-+#define NVRAM_VALID_SIG 0x4650494e45584948            // "HIXENIPF"
-+struct nvram_save_addr {
-+    unsigned long addr;
-+    unsigned long signature;
-+};
-+
 +struct pt_fpreg {
 +    union {
 +        unsigned long bits[2];
@@ -126500,6 +191730,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +/* Internal only: associated with PGC_allocated bit */
 +#define _ASSIGN_pgc_allocated           3
 +#define ASSIGN_pgc_allocated            (1UL << _ASSIGN_pgc_allocated)
++/* Page is an IO page.  */
++#define _ASSIGN_io                      4
++#define ASSIGN_io                       (1UL << _ASSIGN_io)
 +
 +/* This structure has the same layout of struct ia64_boot_param, defined in
 +   <asm/system.h>.  It is redefined here to ease use.  */
@@ -126592,21 +191825,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 + * This is useful in guests using region 7 for identity mapping
 + * like the linux kernel does.
 + */
-+#define XEN_IA64_OPTF_IDENT_MAP_REG7_BIT      0
-+#define XEN_IA64_OPTF_IDENT_MAP_REG7          \
-+      (1UL << XEN_IA64_OPTF_IDENT_MAP_REG7_BIT)
++#define XEN_IA64_OPTF_IDENT_MAP_REG7    1
 +
 +/* Identity mapping of region 4 addresses in HVM. */
-+#define XEN_IA64_OPTF_IDENT_MAP_REG4_BIT        \
-+        (XEN_IA64_OPTF_IDENT_MAP_REG7_BIT + 1)
-+#define XEN_IA64_OPTF_IDENT_MAP_REG4            \
-+        (1UL << XEN_IA64_OPTF_IDENT_MAP_REG4_BIT)
++#define XEN_IA64_OPTF_IDENT_MAP_REG4    2
 +
 +/* Identity mapping of region 5 addresses in HVM. */
-+#define XEN_IA64_OPTF_IDENT_MAP_REG5_BIT        \
-+        (XEN_IA64_OPTF_IDENT_MAP_REG7_BIT + 2)
-+#define XEN_IA64_OPTF_IDENT_MAP_REG5            \
-+        (1UL << XEN_IA64_OPTF_IDENT_MAP_REG5_BIT)
++#define XEN_IA64_OPTF_IDENT_MAP_REG5    3
 +
 +#define XEN_IA64_OPTF_IDENT_MAP_NOT_SET  (0)
 +
@@ -126643,6 +191868,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +#endif /* __ASSEMBLY__ */
 +#endif /* XEN */
 +
++#ifndef __ASSEMBLY__
++#include "arch-ia64/hvm/memmap.h"
++#endif
++
 +#endif /* __HYPERVISOR_IF_IA64_H__ */
 +
 +/*
@@ -126654,10 +191883,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/arch-powerpc.h linux-2.6.18-xen.hg/include/xen/interface/arch-powerpc.h
---- linux-2.6.18/include/xen/interface/arch-powerpc.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/arch-powerpc.h   2007-12-23 11:15:46.478588006 +0100
-@@ -0,0 +1,125 @@
+--- linux-2.6.18.8/include/xen/interface/arch-powerpc.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-powerpc.h   2008-05-19 00:34:28.333237766 +0300
+@@ -0,0 +1,120 @@
 +/*
 + * Permission is hereby granted, free of charge, to any person obtaining a copy
 + * of this software and associated documentation files (the "Software"), to
@@ -126682,15 +191910,20 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 + * Authors: Hollis Blanchard <hollisb@us.ibm.com>
 + */
 +
++#include "xen.h"
++
 +#ifndef __XEN_PUBLIC_ARCH_PPC_64_H__
 +#define __XEN_PUBLIC_ARCH_PPC_64_H__
 +
-+#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \
 +    typedef struct { \
 +        int __pad[(sizeof (long long) - sizeof (void *)) / sizeof (int)]; \
 +        type *p; \
 +    } __attribute__((__aligned__(8))) __guest_handle_ ## name
 +
++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++    ___DEFINE_XEN_GUEST_HANDLE(name, type);   \
++    ___DEFINE_XEN_GUEST_HANDLE(const_##name, const type)
 +#define DEFINE_XEN_GUEST_HANDLE(name) __DEFINE_XEN_GUEST_HANDLE(name, name)
 +#define XEN_GUEST_HANDLE(name)        __guest_handle_ ## name
 +#define set_xen_guest_handle(hnd, val) \
@@ -126705,17 +191938,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +#endif
 +
 +#ifndef __ASSEMBLY__
-+/* Guest handles for primitive C types. */
-+__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char);
-+__DEFINE_XEN_GUEST_HANDLE(uint,  unsigned int);
-+__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long);
-+DEFINE_XEN_GUEST_HANDLE(char);
-+DEFINE_XEN_GUEST_HANDLE(int);
-+DEFINE_XEN_GUEST_HANDLE(long);
-+DEFINE_XEN_GUEST_HANDLE(void);
-+
 +typedef unsigned long long xen_pfn_t;
-+DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
 +#define PRI_xen_pfn "llx"
 +#endif
 +
@@ -126783,10 +192006,80 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +#endif
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/arch-x86/hvm/save.h linux-2.6.18-xen.hg/include/xen/interface/arch-x86/hvm/save.h
---- linux-2.6.18/include/xen/interface/arch-x86/hvm/save.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86/hvm/save.h      2007-12-23 11:15:46.478588006 +0100
-@@ -0,0 +1,413 @@
+--- linux-2.6.18.8/include/xen/interface/arch-x86/cpuid.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86/cpuid.h 2008-05-19 00:34:28.337237996 +0300
+@@ -0,0 +1,68 @@
++/******************************************************************************
++ * arch-x86/cpuid.h
++ * 
++ * CPUID interface to Xen.
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ * 
++ * Copyright (c) 2007 Citrix Systems, Inc.
++ * 
++ * Authors:
++ *    Keir Fraser <keir.fraser@citrix.com>
++ */
++
++#ifndef __XEN_PUBLIC_ARCH_X86_CPUID_H__
++#define __XEN_PUBLIC_ARCH_X86_CPUID_H__
++
++/* Xen identification leaves start at 0x40000000. */
++#define XEN_CPUID_FIRST_LEAF 0x40000000
++#define XEN_CPUID_LEAF(i)    (XEN_CPUID_FIRST_LEAF + (i))
++
++/*
++ * Leaf 1 (0x40000000)
++ * EAX: Largest Xen-information leaf. All leaves up to an including @EAX
++ *      are supported by the Xen host.
++ * EBX-EDX: "XenVMMXenVMM" signature, allowing positive identification
++ *      of a Xen host.
++ */
++#define XEN_CPUID_SIGNATURE_EBX 0x566e6558 /* "XenV" */
++#define XEN_CPUID_SIGNATURE_ECX 0x65584d4d /* "MMXe" */
++#define XEN_CPUID_SIGNATURE_EDX 0x4d4d566e /* "nVMM" */
++
++/*
++ * Leaf 2 (0x40000001)
++ * EAX[31:16]: Xen major version.
++ * EAX[15: 0]: Xen minor version.
++ * EBX-EDX: Reserved (currently all zeroes).
++ */
++
++/*
++ * Leaf 3 (0x40000002)
++ * EAX: Number of hypercall transfer pages. This register is always guaranteed
++ *      to specify one hypercall page.
++ * EBX: Base address of Xen-specific MSRs.
++ * ECX: Features 1. Unused bits are set to zero.
++ * EDX: Features 2. Unused bits are set to zero.
++ */
++
++/* Does the host support MMU_PT_UPDATE_PRESERVE_AD for this guest? */
++#define _XEN_CPUID_FEAT1_MMU_PT_UPDATE_PRESERVE_AD 0
++#define XEN_CPUID_FEAT1_MMU_PT_UPDATE_PRESERVE_AD  (1u<<0)
++
++#endif /* __XEN_PUBLIC_ARCH_X86_CPUID_H__ */
+--- linux-2.6.18.8/include/xen/interface/arch-x86/hvm/save.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86/hvm/save.h      2008-05-19 00:34:28.337237996 +0300
+@@ -0,0 +1,429 @@
 +/* 
 + * Structure definitions for HVM state that is held by Xen and must
 + * be saved along with the domain's memory and device-model state.
@@ -127060,8 +192353,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +DECLARE_HVM_SAVE_TYPE(LAPIC, 5, struct hvm_hw_lapic);
 +
 +struct hvm_hw_lapic_regs {
-+    /* A 4k page of register state */
-+    uint8_t  data[0x400];
++    uint8_t data[1024];
 +};
 +
 +DECLARE_HVM_SAVE_TYPE(LAPIC_REGS, 6, struct hvm_hw_lapic_regs);
@@ -127194,225 +192486,32 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +
 +DECLARE_HVM_SAVE_TYPE(PMTIMER, 13, struct hvm_hw_pmtimer);
 +
-+/* 
-+ * Largest type-code in use
-+ */
-+#define HVM_SAVE_CODE_MAX 13
-+
-+#endif /* __XEN_PUBLIC_HVM_SAVE_X86_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/arch-x86/xen.h linux-2.6.18-xen.hg/include/xen/interface/arch-x86/xen.h
---- linux-2.6.18/include/xen/interface/arch-x86/xen.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86/xen.h   2007-12-23 11:15:46.478588006 +0100
-@@ -0,0 +1,205 @@
-+/******************************************************************************
-+ * arch-x86/xen.h
-+ * 
-+ * Guest OS interface to x86 Xen.
-+ * 
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this software and associated documentation files (the "Software"), to
-+ * deal in the Software without restriction, including without limitation the
-+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-+ * sell copies of the Software, and to permit persons to whom the Software is
-+ * furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ *
-+ * Copyright (c) 2004-2006, K A Fraser
-+ */
-+
-+#ifndef __XEN_PUBLIC_ARCH_X86_XEN_H__
-+#define __XEN_PUBLIC_ARCH_X86_XEN_H__
-+
-+/* Structural guest handles introduced in 0x00030201. */
-+#if __XEN_INTERFACE_VERSION__ >= 0x00030201
-+#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
-+    typedef struct { type *p; } __guest_handle_ ## name
-+#else
-+#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
-+    typedef type * __guest_handle_ ## name
-+#endif
-+
-+#define DEFINE_XEN_GUEST_HANDLE(name)   __DEFINE_XEN_GUEST_HANDLE(name, name)
-+#define __XEN_GUEST_HANDLE(name)        __guest_handle_ ## name
-+#define XEN_GUEST_HANDLE(name)          __XEN_GUEST_HANDLE(name)
-+#define set_xen_guest_handle(hnd, val)  do { (hnd).p = val; } while (0)
-+#ifdef __XEN_TOOLS__
-+#define get_xen_guest_handle(val, hnd)  do { val = (hnd).p; } while (0)
-+#endif
-+
-+#if defined(__i386__)
-+#include "xen-x86_32.h"
-+#elif defined(__x86_64__)
-+#include "xen-x86_64.h"
-+#endif
-+
-+#ifndef __ASSEMBLY__
-+/* Guest handles for primitive C types. */
-+__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char);
-+__DEFINE_XEN_GUEST_HANDLE(uint,  unsigned int);
-+__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long);
-+DEFINE_XEN_GUEST_HANDLE(char);
-+DEFINE_XEN_GUEST_HANDLE(int);
-+DEFINE_XEN_GUEST_HANDLE(long);
-+DEFINE_XEN_GUEST_HANDLE(void);
-+
-+typedef unsigned long xen_pfn_t;
-+DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
-+#define PRI_xen_pfn "lx"
-+#endif
-+
-+/*
-+ * SEGMENT DESCRIPTOR TABLES
-+ */
-+/*
-+ * A number of GDT entries are reserved by Xen. These are not situated at the
-+ * start of the GDT because some stupid OSes export hard-coded selector values
-+ * in their ABI. These hard-coded values are always near the start of the GDT,
-+ * so Xen places itself out of the way, at the far end of the GDT.
-+ */
-+#define FIRST_RESERVED_GDT_PAGE  14
-+#define FIRST_RESERVED_GDT_BYTE  (FIRST_RESERVED_GDT_PAGE * 4096)
-+#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
-+
-+/* Maximum number of virtual CPUs in multi-processor guests. */
-+#define MAX_VIRT_CPUS 32
-+
-+#ifndef __ASSEMBLY__
-+
-+typedef unsigned long xen_ulong_t;
-+
 +/*
-+ * Send an array of these to HYPERVISOR_set_trap_table().
-+ * The privilege level specifies which modes may enter a trap via a software
-+ * interrupt. On x86/64, since rings 1 and 2 are unavailable, we allocate
-+ * privilege levels as follows:
-+ *  Level == 0: Noone may enter
-+ *  Level == 1: Kernel may enter
-+ *  Level == 2: Kernel may enter
-+ *  Level == 3: Everyone may enter
++ * MTRR MSRs
 + */
-+#define TI_GET_DPL(_ti)      ((_ti)->flags & 3)
-+#define TI_GET_IF(_ti)       ((_ti)->flags & 4)
-+#define TI_SET_DPL(_ti,_dpl) ((_ti)->flags |= (_dpl))
-+#define TI_SET_IF(_ti,_if)   ((_ti)->flags |= ((!!(_if))<<2))
-+struct trap_info {
-+    uint8_t       vector;  /* exception vector                              */
-+    uint8_t       flags;   /* 0-3: privilege level; 4: clear event enable?  */
-+    uint16_t      cs;      /* code selector                                 */
-+    unsigned long address; /* code offset                                   */
-+};
-+typedef struct trap_info trap_info_t;
-+DEFINE_XEN_GUEST_HANDLE(trap_info_t);
-+
-+typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */
-+
-+/*
-+ * The following is all CPU context. Note that the fpu_ctxt block is filled 
-+ * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
-+ */
-+struct vcpu_guest_context {
-+    /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
-+    struct { char x[512]; } fpu_ctxt;       /* User-level FPU registers     */
-+#define VGCF_I387_VALID                (1<<0)
-+#define VGCF_IN_KERNEL                 (1<<2)
-+#define _VGCF_i387_valid               0
-+#define VGCF_i387_valid                (1<<_VGCF_i387_valid)
-+#define _VGCF_in_kernel                2
-+#define VGCF_in_kernel                 (1<<_VGCF_in_kernel)
-+#define _VGCF_failsafe_disables_events 3
-+#define VGCF_failsafe_disables_events  (1<<_VGCF_failsafe_disables_events)
-+#define _VGCF_syscall_disables_events  4
-+#define VGCF_syscall_disables_events   (1<<_VGCF_syscall_disables_events)
-+#define _VGCF_online                   5
-+#define VGCF_online                    (1<<_VGCF_online)
-+    unsigned long flags;                    /* VGCF_* flags                 */
-+    struct cpu_user_regs user_regs;         /* User-level CPU registers     */
-+    struct trap_info trap_ctxt[256];        /* Virtual IDT                  */
-+    unsigned long ldt_base, ldt_ents;       /* LDT (linear address, # ents) */
-+    unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
-+    unsigned long kernel_ss, kernel_sp;     /* Virtual TSS (only SS1/SP1)   */
-+    /* NB. User pagetable on x86/64 is placed in ctrlreg[1]. */
-+    unsigned long ctrlreg[8];               /* CR0-CR7 (control registers)  */
-+    unsigned long debugreg[8];              /* DB0-DB7 (debug registers)    */
-+#ifdef __i386__
-+    unsigned long event_callback_cs;        /* CS:EIP of event callback     */
-+    unsigned long event_callback_eip;
-+    unsigned long failsafe_callback_cs;     /* CS:EIP of failsafe callback  */
-+    unsigned long failsafe_callback_eip;
-+#else
-+    unsigned long event_callback_eip;
-+    unsigned long failsafe_callback_eip;
-+#ifdef __XEN__
-+    union {
-+        unsigned long syscall_callback_eip;
-+        struct {
-+            unsigned int event_callback_cs;    /* compat CS of event cb     */
-+            unsigned int failsafe_callback_cs; /* compat CS of failsafe cb  */
-+        };
-+    };
-+#else
-+    unsigned long syscall_callback_eip;
-+#endif
-+#endif
-+    unsigned long vm_assist;                /* VMASST_TYPE_* bitmap */
-+#ifdef __x86_64__
-+    /* Segment base addresses. */
-+    uint64_t      fs_base;
-+    uint64_t      gs_base_kernel;
-+    uint64_t      gs_base_user;
-+#endif
-+};
-+typedef struct vcpu_guest_context vcpu_guest_context_t;
-+DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
 +
-+struct arch_shared_info {
-+    unsigned long max_pfn;                  /* max pfn that appears in table */
-+    /* Frame containing list of mfns containing list of mfns containing p2m. */
-+    xen_pfn_t     pfn_to_mfn_frame_list_list;
-+    unsigned long nmi_reason;
-+    uint64_t pad[32];
++struct hvm_hw_mtrr {
++#define MTRR_VCNT 8
++#define NUM_FIXED_MSR 11
++    uint64_t msr_pat_cr;
++    /* mtrr physbase & physmask msr pair*/
++    uint64_t msr_mtrr_var[MTRR_VCNT*2];
++    uint64_t msr_mtrr_fixed[NUM_FIXED_MSR];
++    uint64_t msr_mtrr_cap;
++    uint64_t msr_mtrr_def_type;
 +};
-+typedef struct arch_shared_info arch_shared_info_t;
 +
-+#endif /* !__ASSEMBLY__ */
++DECLARE_HVM_SAVE_TYPE(MTRR, 14, struct hvm_hw_mtrr);
 +
-+/*
-+ * Prefix forces emulation of some non-trapping instructions.
-+ * Currently only CPUID.
++/* 
++ * Largest type-code in use
 + */
-+#ifdef __ASSEMBLY__
-+#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
-+#define XEN_CPUID          XEN_EMULATE_PREFIX cpuid
-+#else
-+#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
-+#define XEN_CPUID          XEN_EMULATE_PREFIX "cpuid"
-+#endif
-+
-+#endif /* __XEN_PUBLIC_ARCH_X86_XEN_H__ */
++#define HVM_SAVE_CODE_MAX 14
 +
-+/*
-+ * Local variables:
-+ * mode: C
-+ * c-set-style: "BSD"
-+ * c-basic-offset: 4
-+ * tab-width: 4
-+ * indent-tabs-mode: nil
-+ * End:
-+ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/arch-x86/xen-x86_32.h linux-2.6.18-xen.hg/include/xen/interface/arch-x86/xen-x86_32.h
---- linux-2.6.18/include/xen/interface/arch-x86/xen-x86_32.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86/xen-x86_32.h    2007-12-23 11:15:46.478588006 +0100
-@@ -0,0 +1,185 @@
++#endif /* __XEN_PUBLIC_HVM_SAVE_X86_H__ */
+--- linux-2.6.18.8/include/xen/interface/arch-x86/xen-x86_32.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86/xen-x86_32.h    2008-05-19 00:34:28.337237996 +0300
+@@ -0,0 +1,180 @@
 +/******************************************************************************
 + * xen-x86_32.h
 + * 
@@ -127489,6 +192588,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +#define MACH2PHYS_VIRT_END_PAE         \
 +    mk_unsigned_long(__MACH2PHYS_VIRT_END_PAE)
 +
++/* Non-PAE bounds are obsolete. */
 +#define __HYPERVISOR_VIRT_START_NONPAE 0xFC000000
 +#define __MACH2PHYS_VIRT_START_NONPAE  0xFC000000
 +#define __MACH2PHYS_VIRT_END_NONPAE    0xFC400000
@@ -127499,15 +192599,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +#define MACH2PHYS_VIRT_END_NONPAE      \
 +    mk_unsigned_long(__MACH2PHYS_VIRT_END_NONPAE)
 +
-+#ifdef CONFIG_X86_PAE
 +#define __HYPERVISOR_VIRT_START __HYPERVISOR_VIRT_START_PAE
 +#define __MACH2PHYS_VIRT_START  __MACH2PHYS_VIRT_START_PAE
 +#define __MACH2PHYS_VIRT_END    __MACH2PHYS_VIRT_END_PAE
-+#else
-+#define __HYPERVISOR_VIRT_START __HYPERVISOR_VIRT_START_NONPAE
-+#define __MACH2PHYS_VIRT_START  __MACH2PHYS_VIRT_START_NONPAE
-+#define __MACH2PHYS_VIRT_END    __MACH2PHYS_VIRT_END_NONPAE
-+#endif
 +
 +#ifndef HYPERVISOR_VIRT_START
 +#define HYPERVISOR_VIRT_START mk_unsigned_long(__HYPERVISOR_VIRT_START)
@@ -127522,8 +192616,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +
 +/* 32-/64-bit invariability for control interfaces (domctl/sysctl). */
 +#if defined(__XEN__) || defined(__XEN_TOOLS__)
-+#undef __DEFINE_XEN_GUEST_HANDLE
-+#define __DEFINE_XEN_GUEST_HANDLE(name, type)                   \
++#undef ___DEFINE_XEN_GUEST_HANDLE
++#define ___DEFINE_XEN_GUEST_HANDLE(name, type)                  \
 +    typedef struct { type *p; }                                 \
 +        __guest_handle_ ## name;                                \
 +    typedef struct { union { type *p; uint64_aligned_t q; }; }  \
@@ -127598,10 +192692,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/arch-x86/xen-x86_64.h linux-2.6.18-xen.hg/include/xen/interface/arch-x86/xen-x86_64.h
---- linux-2.6.18/include/xen/interface/arch-x86/xen-x86_64.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86/xen-x86_64.h    2007-12-23 11:15:46.478588006 +0100
-@@ -0,0 +1,211 @@
+--- linux-2.6.18.8/include/xen/interface/arch-x86/xen-x86_64.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86/xen-x86_64.h    2008-05-19 00:34:28.337237996 +0300
+@@ -0,0 +1,212 @@
 +/******************************************************************************
 + * xen-x86_64.h
 + * 
@@ -127701,8 +192794,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +#define machine_to_phys_mapping ((unsigned long *)HYPERVISOR_VIRT_START)
 +#endif
 +
-+#ifndef __ASSEMBLY__
-+
 +/*
 + * int HYPERVISOR_set_segment_base(unsigned int which, unsigned long base)
 + *  @which == SEGBASE_*  ;  @base == 64-bit base address
@@ -127737,13 +192828,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 +#define _VGCF_in_syscall 8
 +#define VGCF_in_syscall  (1<<_VGCF_in_syscall)
 +#define VGCF_IN_SYSCALL  VGCF_in_syscall
++
++#ifndef __ASSEMBLY__
++
 +struct iret_context {
 +    /* Top of stack (%rsp at point of hypercall). */
 +    uint64_t rax, r11, rcx, flags, rip, cs, rflags, rsp, ss;
 +    /* Bottom of iret stack frame. */
 +};
 +
-+#ifdef __GNUC__
++#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
 +/* Anonymous union includes both 32- and 64-bit names (e.g., eax/rax). */
 +#define __DECL_REG(name) union { \
 +    uint64_t r ## name, e ## name; \
@@ -127813,9 +192907,211 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/arch-x86_32.h linux-2.6.18-xen.hg/include/xen/interface/arch-x86_32.h
---- linux-2.6.18/include/xen/interface/arch-x86_32.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86_32.h    2007-12-23 11:15:46.478588006 +0100
+--- linux-2.6.18.8/include/xen/interface/arch-x86/xen.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86/xen.h   2008-05-19 00:34:28.341238227 +0300
+@@ -0,0 +1,200 @@
++/******************************************************************************
++ * arch-x86/xen.h
++ * 
++ * Guest OS interface to x86 Xen.
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ *
++ * Copyright (c) 2004-2006, K A Fraser
++ */
++
++#include "../xen.h"
++
++#ifndef __XEN_PUBLIC_ARCH_X86_XEN_H__
++#define __XEN_PUBLIC_ARCH_X86_XEN_H__
++
++/* Structural guest handles introduced in 0x00030201. */
++#if __XEN_INTERFACE_VERSION__ >= 0x00030201
++#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \
++    typedef struct { type *p; } __guest_handle_ ## name
++#else
++#define ___DEFINE_XEN_GUEST_HANDLE(name, type) \
++    typedef type * __guest_handle_ ## name
++#endif
++
++#define __DEFINE_XEN_GUEST_HANDLE(name, type) \
++    ___DEFINE_XEN_GUEST_HANDLE(name, type);   \
++    ___DEFINE_XEN_GUEST_HANDLE(const_##name, const type)
++#define DEFINE_XEN_GUEST_HANDLE(name)   __DEFINE_XEN_GUEST_HANDLE(name, name)
++#define __XEN_GUEST_HANDLE(name)        __guest_handle_ ## name
++#define XEN_GUEST_HANDLE(name)          __XEN_GUEST_HANDLE(name)
++#define set_xen_guest_handle(hnd, val)  do { (hnd).p = val; } while (0)
++#ifdef __XEN_TOOLS__
++#define get_xen_guest_handle(val, hnd)  do { val = (hnd).p; } while (0)
++#endif
++
++#if defined(__i386__)
++#include "xen-x86_32.h"
++#elif defined(__x86_64__)
++#include "xen-x86_64.h"
++#endif
++
++#ifndef __ASSEMBLY__
++typedef unsigned long xen_pfn_t;
++#define PRI_xen_pfn "lx"
++#endif
++
++/*
++ * SEGMENT DESCRIPTOR TABLES
++ */
++/*
++ * A number of GDT entries are reserved by Xen. These are not situated at the
++ * start of the GDT because some stupid OSes export hard-coded selector values
++ * in their ABI. These hard-coded values are always near the start of the GDT,
++ * so Xen places itself out of the way, at the far end of the GDT.
++ */
++#define FIRST_RESERVED_GDT_PAGE  14
++#define FIRST_RESERVED_GDT_BYTE  (FIRST_RESERVED_GDT_PAGE * 4096)
++#define FIRST_RESERVED_GDT_ENTRY (FIRST_RESERVED_GDT_BYTE / 8)
++
++/* Maximum number of virtual CPUs in multi-processor guests. */
++#define MAX_VIRT_CPUS 32
++
++#ifndef __ASSEMBLY__
++
++typedef unsigned long xen_ulong_t;
++
++/*
++ * Send an array of these to HYPERVISOR_set_trap_table().
++ * The privilege level specifies which modes may enter a trap via a software
++ * interrupt. On x86/64, since rings 1 and 2 are unavailable, we allocate
++ * privilege levels as follows:
++ *  Level == 0: Noone may enter
++ *  Level == 1: Kernel may enter
++ *  Level == 2: Kernel may enter
++ *  Level == 3: Everyone may enter
++ */
++#define TI_GET_DPL(_ti)      ((_ti)->flags & 3)
++#define TI_GET_IF(_ti)       ((_ti)->flags & 4)
++#define TI_SET_DPL(_ti,_dpl) ((_ti)->flags |= (_dpl))
++#define TI_SET_IF(_ti,_if)   ((_ti)->flags |= ((!!(_if))<<2))
++struct trap_info {
++    uint8_t       vector;  /* exception vector                              */
++    uint8_t       flags;   /* 0-3: privilege level; 4: clear event enable?  */
++    uint16_t      cs;      /* code selector                                 */
++    unsigned long address; /* code offset                                   */
++};
++typedef struct trap_info trap_info_t;
++DEFINE_XEN_GUEST_HANDLE(trap_info_t);
++
++typedef uint64_t tsc_timestamp_t; /* RDTSC timestamp */
++
++/*
++ * The following is all CPU context. Note that the fpu_ctxt block is filled 
++ * in by FXSAVE if the CPU has feature FXSR; otherwise FSAVE is used.
++ */
++struct vcpu_guest_context {
++    /* FPU registers come first so they can be aligned for FXSAVE/FXRSTOR. */
++    struct { char x[512]; } fpu_ctxt;       /* User-level FPU registers     */
++#define VGCF_I387_VALID                (1<<0)
++#define VGCF_IN_KERNEL                 (1<<2)
++#define _VGCF_i387_valid               0
++#define VGCF_i387_valid                (1<<_VGCF_i387_valid)
++#define _VGCF_in_kernel                2
++#define VGCF_in_kernel                 (1<<_VGCF_in_kernel)
++#define _VGCF_failsafe_disables_events 3
++#define VGCF_failsafe_disables_events  (1<<_VGCF_failsafe_disables_events)
++#define _VGCF_syscall_disables_events  4
++#define VGCF_syscall_disables_events   (1<<_VGCF_syscall_disables_events)
++#define _VGCF_online                   5
++#define VGCF_online                    (1<<_VGCF_online)
++    unsigned long flags;                    /* VGCF_* flags                 */
++    struct cpu_user_regs user_regs;         /* User-level CPU registers     */
++    struct trap_info trap_ctxt[256];        /* Virtual IDT                  */
++    unsigned long ldt_base, ldt_ents;       /* LDT (linear address, # ents) */
++    unsigned long gdt_frames[16], gdt_ents; /* GDT (machine frames, # ents) */
++    unsigned long kernel_ss, kernel_sp;     /* Virtual TSS (only SS1/SP1)   */
++    /* NB. User pagetable on x86/64 is placed in ctrlreg[1]. */
++    unsigned long ctrlreg[8];               /* CR0-CR7 (control registers)  */
++    unsigned long debugreg[8];              /* DB0-DB7 (debug registers)    */
++#ifdef __i386__
++    unsigned long event_callback_cs;        /* CS:EIP of event callback     */
++    unsigned long event_callback_eip;
++    unsigned long failsafe_callback_cs;     /* CS:EIP of failsafe callback  */
++    unsigned long failsafe_callback_eip;
++#else
++    unsigned long event_callback_eip;
++    unsigned long failsafe_callback_eip;
++#ifdef __XEN__
++    union {
++        unsigned long syscall_callback_eip;
++        struct {
++            unsigned int event_callback_cs;    /* compat CS of event cb     */
++            unsigned int failsafe_callback_cs; /* compat CS of failsafe cb  */
++        };
++    };
++#else
++    unsigned long syscall_callback_eip;
++#endif
++#endif
++    unsigned long vm_assist;                /* VMASST_TYPE_* bitmap */
++#ifdef __x86_64__
++    /* Segment base addresses. */
++    uint64_t      fs_base;
++    uint64_t      gs_base_kernel;
++    uint64_t      gs_base_user;
++#endif
++};
++typedef struct vcpu_guest_context vcpu_guest_context_t;
++DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
++
++struct arch_shared_info {
++    unsigned long max_pfn;                  /* max pfn that appears in table */
++    /* Frame containing list of mfns containing list of mfns containing p2m. */
++    xen_pfn_t     pfn_to_mfn_frame_list_list;
++    unsigned long nmi_reason;
++    uint64_t pad[32];
++};
++typedef struct arch_shared_info arch_shared_info_t;
++
++#endif /* !__ASSEMBLY__ */
++
++/*
++ * Prefix forces emulation of some non-trapping instructions.
++ * Currently only CPUID.
++ */
++#ifdef __ASSEMBLY__
++#define XEN_EMULATE_PREFIX .byte 0x0f,0x0b,0x78,0x65,0x6e ;
++#define XEN_CPUID          XEN_EMULATE_PREFIX cpuid
++#else
++#define XEN_EMULATE_PREFIX ".byte 0x0f,0x0b,0x78,0x65,0x6e ; "
++#define XEN_CPUID          XEN_EMULATE_PREFIX "cpuid"
++#endif
++
++#endif /* __XEN_PUBLIC_ARCH_X86_XEN_H__ */
++
++/*
++ * Local variables:
++ * mode: C
++ * c-set-style: "BSD"
++ * c-basic-offset: 4
++ * tab-width: 4
++ * indent-tabs-mode: nil
++ * End:
++ */
+--- linux-2.6.18.8/include/xen/interface/arch-x86_32.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86_32.h    2008-05-19 00:34:28.341238227 +0300
 @@ -0,0 +1,27 @@
 +/******************************************************************************
 + * arch-x86_32.h
@@ -127844,9 +193140,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 + */
 +
 +#include "arch-x86/xen.h"
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/arch-x86_64.h linux-2.6.18-xen.hg/include/xen/interface/arch-x86_64.h
---- linux-2.6.18/include/xen/interface/arch-x86_64.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86_64.h    2007-12-23 11:15:46.481921515 +0100
+--- linux-2.6.18.8/include/xen/interface/arch-x86_64.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/arch-x86_64.h    2008-05-19 00:34:28.341238227 +0300
 @@ -0,0 +1,27 @@
 +/******************************************************************************
 + * arch-x86_64.h
@@ -127875,9 +193170,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ar
 + */
 +
 +#include "arch-x86/xen.h"
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/callback.h linux-2.6.18-xen.hg/include/xen/interface/callback.h
---- linux-2.6.18/include/xen/interface/callback.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/callback.h       2007-12-23 11:15:46.481921515 +0100
+--- linux-2.6.18.8/include/xen/interface/callback.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/callback.h       2008-05-19 00:34:28.341238227 +0300
 @@ -0,0 +1,121 @@
 +/******************************************************************************
 + * callback.h
@@ -128000,51 +193294,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ca
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/COPYING linux-2.6.18-xen.hg/include/xen/interface/COPYING
---- linux-2.6.18/include/xen/interface/COPYING 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/COPYING  2007-12-23 11:15:46.471920991 +0100
-@@ -0,0 +1,38 @@
-+XEN NOTICE
-+==========
-+
-+This copyright applies to all files within this subdirectory and its
-+subdirectories:
-+  include/public/*.h
-+  include/public/hvm/*.h
-+  include/public/io/*.h
-+
-+The intention is that these files can be freely copied into the source
-+tree of an operating system when porting that OS to run on Xen. Doing
-+so does *not* cause the OS to become subject to the terms of the GPL.
-+
-+All other files in the Xen source distribution are covered by version
-+2 of the GNU General Public License except where explicitly stated
-+otherwise within individual source files.
-+
-+ -- Keir Fraser (on behalf of the Xen team)
-+
-+=====================================================================
-+
-+Permission is hereby granted, free of charge, to any person obtaining a copy
-+of this software and associated documentation files (the "Software"), to
-+deal in the Software without restriction, including without limitation the
-+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-+sell copies of the Software, and to permit persons to whom the Software is
-+furnished to do so, subject to the following conditions:
-+
-+The above copyright notice and this permission notice shall be included in
-+all copies or substantial portions of the Software.
-+
-+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
-+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
-+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
-+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
-+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
-+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
-+DEALINGS IN THE SOFTWARE.
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/dom0_ops.h linux-2.6.18-xen.hg/include/xen/interface/dom0_ops.h
---- linux-2.6.18/include/xen/interface/dom0_ops.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/dom0_ops.h       2007-12-23 11:15:46.481921515 +0100
+--- linux-2.6.18.8/include/xen/interface/dom0_ops.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/dom0_ops.h       2008-05-19 00:34:28.341238227 +0300
 @@ -0,0 +1,120 @@
 +/******************************************************************************
 + * dom0_ops.h
@@ -128166,10 +193417,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/domctl.h linux-2.6.18-xen.hg/include/xen/interface/domctl.h
---- linux-2.6.18/include/xen/interface/domctl.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/domctl.h 2007-12-23 11:15:46.481921515 +0100
-@@ -0,0 +1,606 @@
+--- linux-2.6.18.8/include/xen/interface/domctl.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/domctl.h 2008-05-19 00:34:28.345238457 +0300
+@@ -0,0 +1,649 @@
 +/******************************************************************************
 + * domctl.h
 + * 
@@ -128209,7 +193459,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 +#define XEN_DOMCTL_INTERFACE_VERSION 0x00000005
 +
 +struct xenctl_cpumap {
-+    XEN_GUEST_HANDLE_64(uint8_t) bitmap;
++    XEN_GUEST_HANDLE_64(uint8) bitmap;
 +    uint32_t nr_cpus;
 +};
 +
@@ -128225,6 +193475,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 + /* Is this an HVM guest (as opposed to a PV guest)? */
 +#define _XEN_DOMCTL_CDF_hvm_guest 0
 +#define XEN_DOMCTL_CDF_hvm_guest  (1U<<_XEN_DOMCTL_CDF_hvm_guest)
++ /* Use hardware-assisted paging if available? */
++#define _XEN_DOMCTL_CDF_hap       1
++#define XEN_DOMCTL_CDF_hap        (1U<<_XEN_DOMCTL_CDF_hap)
 +    uint32_t flags;
 +};
 +typedef struct xen_domctl_createdomain xen_domctl_createdomain_t;
@@ -128287,7 +193540,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 +    uint64_aligned_t max_pfns;
 +    /* Start index in guest's page list. */
 +    uint64_aligned_t start_pfn;
-+    XEN_GUEST_HANDLE_64(uint64_t) buffer;
++    XEN_GUEST_HANDLE_64(uint64) buffer;
 +    /* OUT variables. */
 +    uint64_aligned_t num_pfns;
 +};
@@ -128324,7 +193577,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 +    /* IN variables. */
 +    uint64_aligned_t num;
 +    /* IN/OUT variables. */
-+    XEN_GUEST_HANDLE_64(uint32_t) array;
++    XEN_GUEST_HANDLE_64(uint32) array;
 +};
 +typedef struct xen_domctl_getpageframeinfo2 xen_domctl_getpageframeinfo2_t;
 +DEFINE_XEN_GUEST_HANDLE(xen_domctl_getpageframeinfo2_t);
@@ -128398,7 +193651,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 +    uint32_t       mb;       /* Shadow memory allocation in MB */
 +
 +    /* OP_PEEK / OP_CLEAN */
-+    XEN_GUEST_HANDLE_64(uint8_t) dirty_bitmap;
++    XEN_GUEST_HANDLE_64(uint8) dirty_bitmap;
 +    uint64_aligned_t pages; /* Size of buffer. Updated with actual size. */
 +    struct xen_domctl_shadow_op_stats stats;
 +};
@@ -128545,6 +193798,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 +#define XEN_DOMAINSETUP_hvm_guest  (1UL<<_XEN_DOMAINSETUP_hvm_guest)
 +#define _XEN_DOMAINSETUP_query 1 /* Get parameters (for save)  */
 +#define XEN_DOMAINSETUP_query  (1UL<<_XEN_DOMAINSETUP_query)
++#define _XEN_DOMAINSETUP_sioemu_guest 2
++#define XEN_DOMAINSETUP_sioemu_guest  (1UL<<_XEN_DOMAINSETUP_sioemu_guest)
 +typedef struct xen_domctl_arch_setup {
 +    uint64_aligned_t flags;  /* XEN_DOMAINSETUP_* */
 +#ifdef __ia64__
@@ -128570,10 +193825,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 +#define XEN_DOMCTL_sethvmcontext     34
 +typedef struct xen_domctl_hvmcontext {
 +    uint32_t size; /* IN/OUT: size of buffer / bytes filled */
-+    XEN_GUEST_HANDLE_64(uint8_t) buffer; /* IN/OUT: data, or call
-+                                          * gethvmcontext with NULL
-+                                          * buffer to get size
-+                                          * req'd */
++    XEN_GUEST_HANDLE_64(uint8) buffer; /* IN/OUT: data, or call
++                                        * gethvmcontext with NULL
++                                        * buffer to get size req'd */
 +} xen_domctl_hvmcontext_t;
 +DEFINE_XEN_GUEST_HANDLE(xen_domctl_hvmcontext_t);
 +
@@ -128607,9 +193861,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 +
 +
 +/* Assign PCI device to HVM guest. Sets up IOMMU structures. */
-+#define XEN_DOMCTL_assign_device     37
-+#define DPCI_ADD_MAPPING         1
-+#define DPCI_REMOVE_MAPPING      0 
++#define XEN_DOMCTL_assign_device      37
++#define XEN_DOMCTL_test_assign_device 45
++#define XEN_DOMCTL_deassign_device 47
 +struct xen_domctl_assign_device {
 +    uint32_t  machine_bdf;   /* machine PCI ID of assigned device */
 +};
@@ -128619,9 +193873,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 +
 +/* Pass-through interrupts: bind real irq -> hvm devfn. */
 +#define XEN_DOMCTL_bind_pt_irq       38
++#define XEN_DOMCTL_unbind_pt_irq     48
 +typedef enum pt_irq_type_e {
 +    PT_IRQ_TYPE_PCI,
-+    PT_IRQ_TYPE_ISA
++    PT_IRQ_TYPE_ISA,
++    PT_IRQ_TYPE_MSI,
 +} pt_irq_type_t;
 +struct xen_domctl_bind_pt_irq {
 +    uint32_t machine_irq;
@@ -128637,6 +193893,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 +            uint8_t device;
 +            uint8_t intx;
 +        } pci;
++        struct {
++            uint8_t gvec;
++            uint32_t gflags;
++        } msi;
 +    } u;
 +};
 +typedef struct xen_domctl_bind_pt_irq xen_domctl_bind_pt_irq_t;
@@ -128645,6 +193905,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 +
 +/* Bind machine I/O address range -> HVM address range. */
 +#define XEN_DOMCTL_memory_mapping    39
++#define DPCI_ADD_MAPPING         1
++#define DPCI_REMOVE_MAPPING      0
 +struct xen_domctl_memory_mapping {
 +    uint64_aligned_t first_gfn; /* first page (hvm guest phys page) in range */
 +    uint64_aligned_t first_mfn; /* first page (machine page) in range */
@@ -128716,13 +193978,40 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 + */
 +#define XEN_DOMCTL_set_opt_feature    44
 +struct xen_domctl_set_opt_feature {
-+#ifdef __ia64__
++#if defined(__ia64__)
 +    struct xen_ia64_opt_feature optf;
++#else
++    /* Make struct non-empty: do not depend on this field name! */
++    uint64_t dummy;
 +#endif
 +};
 +typedef struct xen_domctl_set_opt_feature xen_domctl_set_opt_feature_t;
 +DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_opt_feature_t);
 +
++/*
++ * Set the target domain for a domain
++ */
++#define XEN_DOMCTL_set_target    46
++struct xen_domctl_set_target {
++    domid_t target;
++};
++typedef struct xen_domctl_set_target xen_domctl_set_target_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_set_target_t);
++
++#if defined(__i386__) || defined(__x86_64__)
++# define XEN_CPUID_INPUT_UNUSED  0xFFFFFFFF
++# define XEN_DOMCTL_set_cpuid 49
++struct xen_domctl_cpuid {
++  unsigned int  input[2];
++  unsigned int  eax;
++  unsigned int  ebx;
++  unsigned int  ecx;
++  unsigned int  edx;
++};
++typedef struct xen_domctl_cpuid xen_domctl_cpuid_t;
++DEFINE_XEN_GUEST_HANDLE(xen_domctl_cpuid_t);
++#endif
++
 +struct xen_domctl {
 +    uint32_t cmd;
 +    uint32_t interface_version; /* XEN_DOMCTL_INTERFACE_VERSION */
@@ -128759,6 +194048,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 +        struct xen_domctl_pin_mem_cacheattr pin_mem_cacheattr;
 +        struct xen_domctl_ext_vcpucontext   ext_vcpucontext;
 +        struct xen_domctl_set_opt_feature   set_opt_feature;
++        struct xen_domctl_set_target        set_target;
++#if defined(__i386__) || defined(__x86_64__)
++        struct xen_domctl_cpuid             cpuid;
++#endif
 +        uint8_t                             pad[128];
 +    } u;
 +};
@@ -128776,9 +194069,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/do
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/elfnote.h linux-2.6.18-xen.hg/include/xen/interface/elfnote.h
---- linux-2.6.18/include/xen/interface/elfnote.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/elfnote.h        2007-12-23 11:15:46.481921515 +0100
+--- linux-2.6.18.8/include/xen/interface/elfnote.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/elfnote.h        2008-05-19 00:34:28.345238457 +0300
 @@ -0,0 +1,233 @@
 +/******************************************************************************
 + * elfnote.h
@@ -129013,9 +194305,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/el
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/elfstructs.h linux-2.6.18-xen.hg/include/xen/interface/elfstructs.h
---- linux-2.6.18/include/xen/interface/elfstructs.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/elfstructs.h     2007-12-23 11:15:46.481921515 +0100
+--- linux-2.6.18.8/include/xen/interface/elfstructs.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/elfstructs.h     2008-05-19 00:34:28.345238457 +0300
 @@ -0,0 +1,527 @@
 +#ifndef __XEN_PUBLIC_ELFSTRUCTS_H__
 +#define __XEN_PUBLIC_ELFSTRUCTS_H__ 1
@@ -129544,9 +194835,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/el
 +#endif
 +
 +#endif /* __XEN_PUBLIC_ELFSTRUCTS_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/event_channel.h linux-2.6.18-xen.hg/include/xen/interface/event_channel.h
---- linux-2.6.18/include/xen/interface/event_channel.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/event_channel.h  2007-12-23 11:15:46.485255025 +0100
+--- linux-2.6.18.8/include/xen/interface/event_channel.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/event_channel.h  2008-05-19 00:34:28.349238688 +0300
 @@ -0,0 +1,264 @@
 +/******************************************************************************
 + * event_channel.h
@@ -129812,10 +195102,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ev
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/features.h linux-2.6.18-xen.hg/include/xen/interface/features.h
---- linux-2.6.18/include/xen/interface/features.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/features.h       2007-12-23 11:15:46.485255025 +0100
-@@ -0,0 +1,71 @@
+--- linux-2.6.18.8/include/xen/interface/features.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/features.h       2008-05-19 00:34:28.349238688 +0300
+@@ -0,0 +1,74 @@
 +/******************************************************************************
 + * features.h
 + * 
@@ -129874,6 +195163,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/fe
 + */
 +#define XENFEAT_pae_pgdir_above_4gb        4
 +
++/* x86: Does this Xen host support the MMU_PT_UPDATE_PRESERVE_AD hypercall? */
++#define XENFEAT_mmu_pt_update_preserve_ad  5
++
 +#define XENFEAT_NR_SUBMAPS 1
 +
 +#endif /* __XEN_PUBLIC_FEATURES_H__ */
@@ -129887,9 +195179,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/fe
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/foreign/Makefile linux-2.6.18-xen.hg/include/xen/interface/foreign/Makefile
---- linux-2.6.18/include/xen/interface/foreign/Makefile        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/foreign/Makefile 2007-12-23 11:15:46.485255025 +0100
+--- linux-2.6.18.8/include/xen/interface/foreign/Makefile      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/foreign/Makefile 2008-05-19 00:34:28.349238688 +0300
 @@ -0,0 +1,37 @@
 +XEN_ROOT=../../../..
 +include $(XEN_ROOT)/Config.mk
@@ -129928,9 +195219,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/fo
 +
 +checker.c: $(scripts)
 +      python mkchecker.py $(XEN_TARGET_ARCH) $@ $(architectures)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/foreign/mkchecker.py linux-2.6.18-xen.hg/include/xen/interface/foreign/mkchecker.py
---- linux-2.6.18/include/xen/interface/foreign/mkchecker.py    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/foreign/mkchecker.py     2007-12-23 11:15:46.485255025 +0100
+--- linux-2.6.18.8/include/xen/interface/foreign/mkchecker.py  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/foreign/mkchecker.py     2008-05-19 00:34:28.349238688 +0300
 @@ -0,0 +1,58 @@
 +#!/usr/bin/python
 +
@@ -129990,9 +195280,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/fo
 +
 +f.close();
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/foreign/mkheader.py linux-2.6.18-xen.hg/include/xen/interface/foreign/mkheader.py
---- linux-2.6.18/include/xen/interface/foreign/mkheader.py     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/foreign/mkheader.py      2007-12-23 11:15:46.485255025 +0100
+--- linux-2.6.18.8/include/xen/interface/foreign/mkheader.py   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/foreign/mkheader.py      2008-05-19 00:34:28.393241224 +0300
 @@ -0,0 +1,167 @@
 +#!/usr/bin/python
 +
@@ -130161,9 +195450,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/fo
 +f.write(output);
 +f.close;
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/foreign/reference.size linux-2.6.18-xen.hg/include/xen/interface/foreign/reference.size
---- linux-2.6.18/include/xen/interface/foreign/reference.size  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/foreign/reference.size   2007-12-23 11:15:46.485255025 +0100
+--- linux-2.6.18.8/include/xen/interface/foreign/reference.size        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/foreign/reference.size   2008-05-19 00:34:28.393241224 +0300
 @@ -0,0 +1,18 @@
 +
 +structs                   |  x86_32  x86_64    ia64
@@ -130183,9 +195471,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/fo
 +arch_shared_info          |     268     280     272
 +shared_info               |    2584    3368    4384
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/foreign/structs.py linux-2.6.18-xen.hg/include/xen/interface/foreign/structs.py
---- linux-2.6.18/include/xen/interface/foreign/structs.py      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/foreign/structs.py       2007-12-23 11:15:46.485255025 +0100
+--- linux-2.6.18.8/include/xen/interface/foreign/structs.py    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/foreign/structs.py       2008-05-19 00:34:28.393241224 +0300
 @@ -0,0 +1,58 @@
 +# configuration: what needs translation
 +
@@ -130245,10 +195532,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/fo
 +            "MAX_VIRT_CPUS",
 +            "MAX_GUEST_CMDLINE" ];
 +
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/grant_table.h linux-2.6.18-xen.hg/include/xen/interface/grant_table.h
---- linux-2.6.18/include/xen/interface/grant_table.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/grant_table.h    2007-12-23 11:15:46.488588533 +0100
-@@ -0,0 +1,429 @@
+--- linux-2.6.18.8/include/xen/interface/grant_table.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/grant_table.h    2008-05-19 00:34:28.393241224 +0300
+@@ -0,0 +1,431 @@
 +/******************************************************************************
 + * grant_table.h
 + * 
@@ -130651,7 +195937,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/gr
 +#define GNTST_no_device_space  (-7) /* Out of space in I/O MMU.              */
 +#define GNTST_permission_denied (-8) /* Not enough privilege for operation.  */
 +#define GNTST_bad_page         (-9) /* Specified page was invalid for op.    */
-+#define GNTST_bad_copy_arg    (-10) /* copy arguments cross page boundary */
++#define GNTST_bad_copy_arg    (-10) /* copy arguments cross page boundary.   */
++#define GNTST_address_too_big (-11) /* transfer page address too large.      */
 +
 +#define GNTTABOP_error_msgs {                   \
 +    "okay",                                     \
@@ -130664,7 +195951,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/gr
 +    "no spare translation slot in the I/O MMU", \
 +    "permission denied",                        \
 +    "bad page",                                 \
-+    "copy arguments cross page boundary"        \
++    "copy arguments cross page boundary",       \
++    "page address size too large"               \
 +}
 +
 +#endif /* __XEN_PUBLIC_GRANT_TABLE_H__ */
@@ -130678,9 +195966,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/gr
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hvm/e820.h linux-2.6.18-xen.hg/include/xen/interface/hvm/e820.h
---- linux-2.6.18/include/xen/interface/hvm/e820.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/hvm/e820.h       2007-12-23 11:15:46.488588533 +0100
+--- linux-2.6.18.8/include/xen/interface/hvm/e820.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/hvm/e820.h       2008-05-19 00:34:28.397241455 +0300
 @@ -0,0 +1,34 @@
 +
 +/*
@@ -130716,9 +196003,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 +#define HVM_BELOW_4G_MMIO_LENGTH    ((1ULL << 32) - HVM_BELOW_4G_MMIO_START)
 +
 +#endif /* __XEN_PUBLIC_HVM_E820_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hvm/hvm_info_table.h linux-2.6.18-xen.hg/include/xen/interface/hvm/hvm_info_table.h
---- linux-2.6.18/include/xen/interface/hvm/hvm_info_table.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/hvm/hvm_info_table.h     2007-12-23 11:15:46.488588533 +0100
+--- linux-2.6.18.8/include/xen/interface/hvm/hvm_info_table.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/hvm/hvm_info_table.h     2008-05-19 00:34:28.397241455 +0300
 @@ -0,0 +1,41 @@
 +/******************************************************************************
 + * hvm/hvm_info_table.h
@@ -130761,10 +196047,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 +};
 +
 +#endif /* __XEN_PUBLIC_HVM_HVM_INFO_TABLE_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hvm/hvm_op.h linux-2.6.18-xen.hg/include/xen/interface/hvm/hvm_op.h
---- linux-2.6.18/include/xen/interface/hvm/hvm_op.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/hvm/hvm_op.h     2007-12-23 11:15:46.488588533 +0100
-@@ -0,0 +1,76 @@
+--- linux-2.6.18.8/include/xen/interface/hvm/hvm_op.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/hvm/hvm_op.h     2008-05-19 00:34:28.397241455 +0300
+@@ -0,0 +1,97 @@
 +/*
 + * Permission is hereby granted, free of charge, to any person obtaining a copy
 + * of this software and associated documentation files (the "Software"), to
@@ -130840,11 +196125,31 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 +/* Flushes all VCPU TLBs: @arg must be NULL. */
 +#define HVMOP_flush_tlbs          5
 +
++/* Following tools-only interfaces may change in future. */
++#if defined(__XEN__) || defined(__XEN_TOOLS__)
++
++/* Track dirty VRAM. */
++#define HVMOP_track_dirty_vram    6
++struct xen_hvm_track_dirty_vram {
++    /* Domain to be tracked. */
++    domid_t  domid;
++    /* First pfn to track. */
++    uint64_aligned_t first_pfn;
++    /* Number of pages to track. */
++    uint64_aligned_t nr;
++    /* OUT variable. */
++    /* Dirty bitmap buffer. */
++    XEN_GUEST_HANDLE_64(uint8) dirty_bitmap;
++};
++typedef struct xen_hvm_track_dirty_vram xen_hvm_track_dirty_vram_t;
++DEFINE_XEN_GUEST_HANDLE(xen_hvm_track_dirty_vram_t);
++
++#endif /* defined(__XEN__) || defined(__XEN_TOOLS__) */
++
 +#endif /* __XEN_PUBLIC_HVM_HVM_OP_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hvm/ioreq.h linux-2.6.18-xen.hg/include/xen/interface/hvm/ioreq.h
---- linux-2.6.18/include/xen/interface/hvm/ioreq.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/hvm/ioreq.h      2007-12-23 11:15:46.488588533 +0100
-@@ -0,0 +1,122 @@
+--- linux-2.6.18.8/include/xen/interface/hvm/ioreq.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/hvm/ioreq.h      2008-05-19 00:34:28.397241455 +0300
+@@ -0,0 +1,127 @@
 +/*
 + * ioreq.h: I/O request definitions for device models
 + * Copyright (c) 2004, Intel Corporation.
@@ -130881,14 +196186,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 +
 +#define IOREQ_TYPE_PIO          0 /* pio */
 +#define IOREQ_TYPE_COPY         1 /* mmio ops */
-+#define IOREQ_TYPE_AND          2
-+#define IOREQ_TYPE_OR           3
-+#define IOREQ_TYPE_XOR          4
-+#define IOREQ_TYPE_XCHG         5
-+#define IOREQ_TYPE_ADD          6
 +#define IOREQ_TYPE_TIMEOFFSET   7
 +#define IOREQ_TYPE_INVALIDATE   8 /* mapcache */
-+#define IOREQ_TYPE_SUB          9
 +
 +/*
 + * VMExit dispatcher should cooperate with instruction decoder to
@@ -130905,6 +196204,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 +                             *   of the real data to use.   */
 +    uint8_t dir:1;          /*  1=read, 0=write             */
 +    uint8_t df:1;
++    uint8_t pad:1;
 +    uint8_t type;           /* I/O type                     */
 +    uint8_t _pad0[6];
 +    uint64_t io_count;      /* How many IO done on a vcpu   */
@@ -130924,11 +196224,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 +};
 +typedef struct shared_iopage shared_iopage_t;
 +
-+#define IOREQ_BUFFER_SLOT_NUM     80
++struct buf_ioreq {
++    uint8_t  type;   /* I/O type                    */
++    uint8_t  pad:1;
++    uint8_t  dir:1;  /* 1=read, 0=write             */
++    uint8_t  size:2; /* 0=>1, 1=>2, 2=>4, 3=>8. If 8, use two buf_ioreqs */
++    uint32_t addr:20;/* physical address            */
++    uint32_t data;   /* data                        */
++};
++typedef struct buf_ioreq buf_ioreq_t;
++
++#define IOREQ_BUFFER_SLOT_NUM     511 /* 8 bytes each, plus 2 4-byte indexes */
 +struct buffered_iopage {
-+    unsigned int    read_pointer;
-+    unsigned int    write_pointer;
-+    ioreq_t         ioreq[IOREQ_BUFFER_SLOT_NUM];
++    unsigned int read_pointer;
++    unsigned int write_pointer;
++    buf_ioreq_t buf_ioreq[IOREQ_BUFFER_SLOT_NUM];
 +}; /* NB. Size of this structure must be no greater than one page. */
 +typedef struct buffered_iopage buffered_iopage_t;
 +
@@ -130950,11 +196260,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 +};
 +#endif /* defined(__ia64__) */
 +
-+#if defined(__i386__) || defined(__x86_64__)
 +#define ACPI_PM1A_EVT_BLK_ADDRESS           0x0000000000001f40
 +#define ACPI_PM1A_CNT_BLK_ADDRESS           (ACPI_PM1A_EVT_BLK_ADDRESS + 0x04)
 +#define ACPI_PM_TMR_BLK_ADDRESS             (ACPI_PM1A_EVT_BLK_ADDRESS + 0x08)
-+#endif /* defined(__i386__) || defined(__x86_64__) */
++#define ACPI_GPE0_BLK_ADDRESS               (ACPI_PM_TMR_BLK_ADDRESS + 0x20)
++#define ACPI_GPE0_BLK_LEN                   0x08
 +
 +#endif /* _IOREQ_H_ */
 +
@@ -130967,10 +196277,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hvm/params.h linux-2.6.18-xen.hg/include/xen/interface/hvm/params.h
---- linux-2.6.18/include/xen/interface/hvm/params.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/hvm/params.h     2007-12-23 11:15:46.488588533 +0100
-@@ -0,0 +1,61 @@
+--- linux-2.6.18.8/include/xen/interface/hvm/params.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/hvm/params.h     2008-05-19 00:34:28.397241455 +0300
+@@ -0,0 +1,95 @@
 +/*
 + * Permission is hereby granted, free of charge, to any person obtaining a copy
 + * of this software and associated documentation files (the "Software"), to
@@ -131026,16 +196335,49 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 +#ifdef __ia64__
 +#define HVM_PARAM_NVRAM_FD     7
 +#define HVM_PARAM_VHPT_SIZE    8
-+#define HVM_NR_PARAMS          9
-+#else
-+#define HVM_NR_PARAMS          7
++#define HVM_PARAM_BUFPIOREQ_PFN       9
 +#endif
 +
++/*
++ * Set mode for virtual timers (currently x86 only):
++ *  delay_for_missed_ticks (default):
++ *   Do not advance a vcpu's time beyond the correct delivery time for
++ *   interrupts that have been missed due to preemption. Deliver missed
++ *   interrupts when the vcpu is rescheduled and advance the vcpu's virtual
++ *   time stepwise for each one.
++ *  no_delay_for_missed_ticks:
++ *   As above, missed interrupts are delivered, but guest time always tracks
++ *   wallclock (i.e., real) time while doing so.
++ *  no_missed_ticks_pending:
++ *   No missed interrupts are held pending. Instead, to ensure ticks are
++ *   delivered at some non-zero rate, if we detect missed ticks then the
++ *   internal tick alarm is not disabled if the VCPU is preempted during the
++ *   next tick period.
++ *  one_missed_tick_pending:
++ *   Missed interrupts are collapsed together and delivered as one 'late tick'.
++ *   Guest time always tracks wallclock (i.e., real) time.
++ */
++#define HVM_PARAM_TIMER_MODE   10
++#define HVMPTM_delay_for_missed_ticks    0
++#define HVMPTM_no_delay_for_missed_ticks 1
++#define HVMPTM_no_missed_ticks_pending   2
++#define HVMPTM_one_missed_tick_pending   3
++
++/* Boolean: Enable virtual HPET (high-precision event timer)? (x86-only) */
++#define HVM_PARAM_HPET_ENABLED 11
++
++/* Identity-map page directory used by Intel EPT when CR0.PG=0. */
++#define HVM_PARAM_IDENT_PT     12
++
++/* Device Model domain, defaults to 0. */
++#define HVM_PARAM_DM_DOMAIN    13
++
++#define HVM_NR_PARAMS          14
++
 +#endif /* __XEN_PUBLIC_HVM_PARAMS_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hvm/save.h linux-2.6.18-xen.hg/include/xen/interface/hvm/save.h
---- linux-2.6.18/include/xen/interface/hvm/save.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/hvm/save.h       2007-12-23 11:15:46.488588533 +0100
-@@ -0,0 +1,84 @@
+--- linux-2.6.18.8/include/xen/interface/hvm/save.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/hvm/save.h       2008-05-19 00:34:28.401241685 +0300
+@@ -0,0 +1,88 @@
 +/* 
 + * hvm/save.h
 + *
@@ -131077,6 +196419,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 + * Internal mechanisms should be kept in Xen-private headers.
 + */
 +
++#if !defined(__GNUC__) || defined(__STRICT_ANSI__)
++#error "Anonymous structs/unions are a GNU extension."
++#endif
++
 +/* 
 + * Each entry is preceded by a descriptor giving its type and length
 + */
@@ -131120,9 +196466,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 +#endif
 +
 +#endif /* __XEN_PUBLIC_HVM_SAVE_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hvm/vmx_assist.h linux-2.6.18-xen.hg/include/xen/interface/hvm/vmx_assist.h
---- linux-2.6.18/include/xen/interface/hvm/vmx_assist.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/hvm/vmx_assist.h 2007-12-23 11:15:46.491922039 +0100
+--- linux-2.6.18.8/include/xen/interface/hvm/vmx_assist.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/hvm/vmx_assist.h 2008-05-19 00:34:28.401241685 +0300
 @@ -0,0 +1,122 @@
 +/*
 + * vmx_assist.h: Context definitions for the VMXASSIST world switch.
@@ -131246,9 +196591,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/hv
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io/blkif.h linux-2.6.18-xen.hg/include/xen/interface/io/blkif.h
---- linux-2.6.18/include/xen/interface/io/blkif.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/io/blkif.h       2007-12-23 11:15:46.491922039 +0100
+--- linux-2.6.18.8/include/xen/interface/io/blkif.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/blkif.h       2008-05-19 00:34:28.401241685 +0300
 @@ -0,0 +1,141 @@
 +/******************************************************************************
 + * blkif.h
@@ -131391,9 +196735,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io/console.h linux-2.6.18-xen.hg/include/xen/interface/io/console.h
---- linux-2.6.18/include/xen/interface/io/console.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/io/console.h     2007-12-23 11:15:46.491922039 +0100
+--- linux-2.6.18.8/include/xen/interface/io/console.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/console.h     2008-05-19 00:34:28.401241685 +0300
 @@ -0,0 +1,51 @@
 +/******************************************************************************
 + * console.h
@@ -131446,10 +196789,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io/fbif.h linux-2.6.18-xen.hg/include/xen/interface/io/fbif.h
---- linux-2.6.18/include/xen/interface/io/fbif.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/io/fbif.h        2007-12-23 11:15:46.491922039 +0100
-@@ -0,0 +1,138 @@
+--- linux-2.6.18.8/include/xen/interface/io/fbif.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/fbif.h        2008-05-19 00:34:28.405241916 +0300
+@@ -0,0 +1,157 @@
 +/*
 + * fbif.h -- Xen virtual frame buffer device
 + *
@@ -131502,12 +196844,29 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +    int32_t height; /* rect height */
 +};
 +
++/*
++ * Framebuffer resize notification event
++ * Capable backend sets feature-resize in xenstore.
++ */
++#define XENFB_TYPE_RESIZE 3
++
++struct xenfb_resize
++{
++    uint8_t type;    /* XENFB_TYPE_RESIZE */
++    int32_t width;   /* width in pixels */
++    int32_t height;  /* height in pixels */
++    int32_t stride;  /* stride in bytes */
++    int32_t depth;   /* depth in bits */
++    int32_t offset;  /* offset of the framebuffer in bytes */
++};
++
 +#define XENFB_OUT_EVENT_SIZE 40
 +
 +union xenfb_out_event
 +{
 +    uint8_t type;
 +    struct xenfb_update update;
++    struct xenfb_resize resize;
 +    char pad[XENFB_OUT_EVENT_SIZE];
 +};
 +
@@ -131561,15 +196920,17 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +     * Each directory page holds PAGE_SIZE / sizeof(*pd)
 +     * framebuffer pages, and can thus map up to PAGE_SIZE *
 +     * PAGE_SIZE / sizeof(*pd) bytes.  With PAGE_SIZE == 4096 and
-+     * sizeof(unsigned long) == 4, that's 4 Megs.  Two directory
-+     * pages should be enough for a while.
++     * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2 Megs
++     * 64 bit.  256 directories give enough room for a 512 Meg
++     * framebuffer with a max resolution of 12,800x10,240.  Should
++     * be enough for a while with room leftover for expansion.
 +     */
-+    unsigned long pd[2];
++    unsigned long pd[256];
 +};
 +
 +/*
-+ * Wart: xenkbd needs to know resolution.  Put it here until a better
-+ * solution is found, but don't leak it to the backend.
++ * Wart: xenkbd needs to know default resolution.  Put it here until a
++ * better solution is found, but don't leak it to the backend.
 + */
 +#ifdef __KERNEL__
 +#define XENFB_WIDTH 800
@@ -131588,9 +196949,192 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io/kbdif.h linux-2.6.18-xen.hg/include/xen/interface/io/kbdif.h
---- linux-2.6.18/include/xen/interface/io/kbdif.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/io/kbdif.h       2007-12-23 11:15:46.491922039 +0100
+--- linux-2.6.18.8/include/xen/interface/io/fsif.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/fsif.h        2008-05-19 00:34:28.405241916 +0300
+@@ -0,0 +1,181 @@
++/******************************************************************************
++ * fsif.h
++ * 
++ * Interface to FS level split device drivers.
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ *
++ * Copyright (c) 2007, Grzegorz Milos, Sun Microsystems, Inc.  
++ */
++
++#ifndef __XEN_PUBLIC_IO_FSIF_H__
++#define __XEN_PUBLIC_IO_FSIF_H__
++
++#include "ring.h"
++#include "../grant_table.h"
++
++#define REQ_FILE_OPEN        1
++#define REQ_FILE_CLOSE       2
++#define REQ_FILE_READ        3
++#define REQ_FILE_WRITE       4
++#define REQ_STAT             5
++#define REQ_FILE_TRUNCATE    6
++#define REQ_REMOVE           7
++#define REQ_RENAME           8
++#define REQ_CREATE           9
++#define REQ_DIR_LIST        10
++#define REQ_CHMOD           11
++#define REQ_FS_SPACE        12
++#define REQ_FILE_SYNC       13
++
++struct fsif_open_request {
++    grant_ref_t gref;
++};
++
++struct fsif_close_request {
++    uint32_t fd;
++};
++
++struct fsif_read_request {
++    uint32_t fd;
++    grant_ref_t gref;
++    uint64_t len;
++    uint64_t offset;
++};
++
++struct fsif_write_request {
++    uint32_t fd;
++    grant_ref_t gref;
++    uint64_t len;
++    uint64_t offset;
++};
++
++struct fsif_stat_request {
++    uint32_t fd;
++    grant_ref_t gref;
++};
++
++/* This structure is a copy of some fields from stat structure, writen to the
++ * granted page. */
++struct fsif_stat_response {
++    int32_t  stat_mode;
++    uint32_t stat_uid;
++    uint32_t stat_gid;
++    int32_t  pad;
++    int64_t  stat_size;
++    int64_t  stat_atime;
++    int64_t  stat_mtime;
++    int64_t  stat_ctime;
++};
++
++struct fsif_truncate_request {
++    uint32_t fd;
++    int32_t pad;
++    int64_t length;
++};
++
++struct fsif_remove_request {
++    grant_ref_t gref;
++};
++
++struct fsif_rename_request {
++    uint16_t old_name_offset;
++    uint16_t new_name_offset;
++    grant_ref_t gref;
++};
++
++struct fsif_create_request {
++    int8_t directory;
++    int8_t pad;
++    int16_t pad2;
++    int32_t mode;
++    grant_ref_t gref;
++};
++
++struct fsif_list_request {
++    uint32_t offset;
++    grant_ref_t gref;
++};
++
++#define NR_FILES_SHIFT  0
++#define NR_FILES_SIZE   16   /* 16 bits for the number of files mask */
++#define NR_FILES_MASK   (((1ULL << NR_FILES_SIZE) - 1) << NR_FILES_SHIFT)
++#define ERROR_SIZE      32   /* 32 bits for the error mask */
++#define ERROR_SHIFT     (NR_FILES_SIZE + NR_FILES_SHIFT)
++#define ERROR_MASK      (((1ULL << ERROR_SIZE) - 1) << ERROR_SHIFT)
++#define HAS_MORE_SHIFT  (ERROR_SHIFT + ERROR_SIZE)    
++#define HAS_MORE_FLAG   (1ULL << HAS_MORE_SHIFT)
++
++struct fsif_chmod_request {
++    uint32_t fd;
++    int32_t mode;
++};
++
++struct fsif_space_request {
++    grant_ref_t gref;
++};
++
++struct fsif_sync_request {
++    uint32_t fd;
++};
++
++
++/* FS operation request */
++struct fsif_request {
++    uint8_t type;                 /* Type of the request                  */
++    uint8_t pad;
++    uint16_t id;                  /* Request ID, copied to the response   */
++    uint32_t pad2;
++    union {
++        struct fsif_open_request     fopen;
++        struct fsif_close_request    fclose;
++        struct fsif_read_request     fread;
++        struct fsif_write_request    fwrite;
++        struct fsif_stat_request     fstat;
++        struct fsif_truncate_request ftruncate;
++        struct fsif_remove_request   fremove;
++        struct fsif_rename_request   frename;
++        struct fsif_create_request   fcreate;
++        struct fsif_list_request     flist;
++        struct fsif_chmod_request    fchmod;
++        struct fsif_space_request    fspace;
++        struct fsif_sync_request     fsync;
++    } u;
++};
++typedef struct fsif_request fsif_request_t;
++
++/* FS operation response */
++struct fsif_response {
++    uint16_t id;
++    uint16_t pad1;
++    uint32_t pad2;
++    uint64_t ret_val;
++};
++
++typedef struct fsif_response fsif_response_t;
++
++
++DEFINE_RING_TYPES(fsif, struct fsif_request, struct fsif_response);
++
++#define STATE_INITIALISED     "init"
++#define STATE_READY           "ready"
++
++
++
++#endif
+--- linux-2.6.18.8/include/xen/interface/io/kbdif.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/kbdif.h       2008-05-19 00:34:28.405241916 +0300
 @@ -0,0 +1,132 @@
 +/*
 + * kbdif.h -- Xen virtual keyboard/mouse
@@ -131659,7 +197203,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +    uint8_t type;        /* XENKBD_TYPE_POS */
 +    int32_t abs_x;       /* absolute X position (in FB pixels) */
 +    int32_t abs_y;       /* absolute Y position (in FB pixels) */
-+    int32_t abs_z;       /* absolute Z position (wheel) */
++    int32_t rel_z;       /* relative Z motion (wheel) */
 +};
 +
 +#define XENKBD_IN_EVENT_SIZE 40
@@ -131724,9 +197268,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io/netif.h linux-2.6.18-xen.hg/include/xen/interface/io/netif.h
---- linux-2.6.18/include/xen/interface/io/netif.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/io/netif.h       2007-12-23 11:15:46.491922039 +0100
+--- linux-2.6.18.8/include/xen/interface/io/netif.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/netif.h       2008-05-19 00:34:28.417242608 +0300
 @@ -0,0 +1,205 @@
 +/******************************************************************************
 + * netif.h
@@ -131933,10 +197476,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io/pciif.h linux-2.6.18-xen.hg/include/xen/interface/io/pciif.h
---- linux-2.6.18/include/xen/interface/io/pciif.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/io/pciif.h       2007-12-23 11:15:46.491922039 +0100
-@@ -0,0 +1,83 @@
+--- linux-2.6.18.8/include/xen/interface/io/pciif.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/pciif.h       2008-05-19 00:34:28.417242608 +0300
+@@ -0,0 +1,97 @@
 +/*
 + * PCI Backend/Frontend Common Data Structures & Macros
 + *
@@ -131973,6 +197515,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +/* xen_pci_op commands */
 +#define XEN_PCI_OP_conf_read    (0)
 +#define XEN_PCI_OP_conf_write   (1)
++#define XEN_PCI_OP_enable_msi   (2)
++#define XEN_PCI_OP_disable_msi  (3)
++#define XEN_PCI_OP_enable_msix  (4)
++#define XEN_PCI_OP_disable_msix (5)
 +
 +/* xen_pci_op error numbers */
 +#define XEN_PCI_ERR_success          (0)
@@ -131983,6 +197529,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +/* XEN_PCI_ERR_op_failed - backend failed to complete the operation */
 +#define XEN_PCI_ERR_op_failed       (-5)
 +
++/*
++ * it should be PAGE_SIZE-sizeof(struct xen_pci_op))/sizeof(struct msix_entry))
++ * Should not exceed 128
++ */
++#define SH_INFO_MAX_VEC     128
++
 +struct xen_pci_op {
 +    /* IN: what action to perform: XEN_PCI_OP_* */
 +    uint32_t cmd;
@@ -132001,6 +197553,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +
 +    /* IN/OUT: Contains the result after a READ or the value to WRITE */
 +    uint32_t value;
++    /* IN: Contains extra infor for this operation */
++    uint32_t info;
++    /*IN:  param for msi-x */
++    struct msix_entry msix_entries[SH_INFO_MAX_VEC];
 +};
 +
 +struct xen_pci_sharedinfo {
@@ -132020,17 +197576,37 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io/protocols.h linux-2.6.18-xen.hg/include/xen/interface/io/protocols.h
---- linux-2.6.18/include/xen/interface/io/protocols.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/io/protocols.h   2007-12-23 11:15:46.495255548 +0100
-@@ -0,0 +1,21 @@
+--- linux-2.6.18.8/include/xen/interface/io/protocols.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/protocols.h   2008-05-19 00:34:28.417242608 +0300
+@@ -0,0 +1,40 @@
++/******************************************************************************
++ * protocols.h
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ */
++
 +#ifndef __XEN_PROTOCOLS_H__
 +#define __XEN_PROTOCOLS_H__
 +
 +#define XEN_IO_PROTO_ABI_X86_32     "x86_32-abi"
 +#define XEN_IO_PROTO_ABI_X86_64     "x86_64-abi"
 +#define XEN_IO_PROTO_ABI_IA64       "ia64-abi"
-+#define XEN_IO_PROTO_ABI_POWERPC64  "powerpc64-abi"
 +
 +#if defined(__i386__)
 +# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_32
@@ -132038,17 +197614,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_X86_64
 +#elif defined(__ia64__)
 +# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_IA64
-+#elif defined(__powerpc64__)
-+# define XEN_IO_PROTO_ABI_NATIVE XEN_IO_PROTO_ABI_POWERPC64
 +#else
 +# error arch fixup needed here
 +#endif
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io/ring.h linux-2.6.18-xen.hg/include/xen/interface/io/ring.h
---- linux-2.6.18/include/xen/interface/io/ring.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/io/ring.h        2007-12-23 11:15:46.495255548 +0100
-@@ -0,0 +1,299 @@
+--- linux-2.6.18.8/include/xen/interface/io/ring.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/ring.h        2008-05-19 00:34:28.417242608 +0300
+@@ -0,0 +1,307 @@
 +/******************************************************************************
 + * ring.h
 + * 
@@ -132078,6 +197651,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +#ifndef __XEN_PUBLIC_IO_RING_H__
 +#define __XEN_PUBLIC_IO_RING_H__
 +
++#include "../xen-compat.h"
++
++#if __XEN_INTERFACE_VERSION__ < 0x00030208
++#define xen_mb()  mb()
++#define xen_rmb() rmb()
++#define xen_wmb() wmb()
++#endif
++
 +typedef unsigned int RING_IDX;
 +
 +/* Round a 32-bit unsigned constant down to the nearest power of two. */
@@ -132262,12 +197843,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +    (((_cons) - (_r)->rsp_prod_pvt) >= RING_SIZE(_r))
 +
 +#define RING_PUSH_REQUESTS(_r) do {                                     \
-+    wmb(); /* back sees requests /before/ updated producer index */     \
++    xen_wmb(); /* back sees requests /before/ updated producer index */ \
 +    (_r)->sring->req_prod = (_r)->req_prod_pvt;                         \
 +} while (0)
 +
 +#define RING_PUSH_RESPONSES(_r) do {                                    \
-+    wmb(); /* front sees responses /before/ updated producer index */   \
++    xen_wmb(); /* front sees resps /before/ updated producer index */   \
 +    (_r)->sring->rsp_prod = (_r)->rsp_prod_pvt;                         \
 +} while (0)
 +
@@ -132304,9 +197885,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +#define RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(_r, _notify) do {           \
 +    RING_IDX __old = (_r)->sring->req_prod;                             \
 +    RING_IDX __new = (_r)->req_prod_pvt;                                \
-+    wmb(); /* back sees requests /before/ updated producer index */     \
++    xen_wmb(); /* back sees requests /before/ updated producer index */ \
 +    (_r)->sring->req_prod = __new;                                      \
-+    mb(); /* back sees new requests /before/ we check req_event */      \
++    xen_mb(); /* back sees new requests /before/ we check req_event */  \
 +    (_notify) = ((RING_IDX)(__new - (_r)->sring->req_event) <           \
 +                 (RING_IDX)(__new - __old));                            \
 +} while (0)
@@ -132314,9 +197895,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +#define RING_PUSH_RESPONSES_AND_CHECK_NOTIFY(_r, _notify) do {          \
 +    RING_IDX __old = (_r)->sring->rsp_prod;                             \
 +    RING_IDX __new = (_r)->rsp_prod_pvt;                                \
-+    wmb(); /* front sees responses /before/ updated producer index */   \
++    xen_wmb(); /* front sees resps /before/ updated producer index */   \
 +    (_r)->sring->rsp_prod = __new;                                      \
-+    mb(); /* front sees new responses /before/ we check rsp_event */    \
++    xen_mb(); /* front sees new resps /before/ we check rsp_event */    \
 +    (_notify) = ((RING_IDX)(__new - (_r)->sring->rsp_event) <           \
 +                 (RING_IDX)(__new - __old));                            \
 +} while (0)
@@ -132325,7 +197906,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +    (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r);                   \
 +    if (_work_to_do) break;                                             \
 +    (_r)->sring->req_event = (_r)->req_cons + 1;                        \
-+    mb();                                                               \
++    xen_mb();                                                           \
 +    (_work_to_do) = RING_HAS_UNCONSUMED_REQUESTS(_r);                   \
 +} while (0)
 +
@@ -132333,7 +197914,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +    (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);                  \
 +    if (_work_to_do) break;                                             \
 +    (_r)->sring->rsp_event = (_r)->rsp_cons + 1;                        \
-+    mb();                                                               \
++    xen_mb();                                                           \
 +    (_work_to_do) = RING_HAS_UNCONSUMED_RESPONSES(_r);                  \
 +} while (0)
 +
@@ -132348,9 +197929,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io/tpmif.h linux-2.6.18-xen.hg/include/xen/interface/io/tpmif.h
---- linux-2.6.18/include/xen/interface/io/tpmif.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/io/tpmif.h       2007-12-23 11:15:46.495255548 +0100
+--- linux-2.6.18.8/include/xen/interface/io/tpmif.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/tpmif.h       2008-05-19 00:34:28.421242838 +0300
 @@ -0,0 +1,77 @@
 +/******************************************************************************
 + * tpmif.h
@@ -132429,10 +198009,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io/xenbus.h linux-2.6.18-xen.hg/include/xen/interface/io/xenbus.h
---- linux-2.6.18/include/xen/interface/io/xenbus.h     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/io/xenbus.h      2007-12-23 11:15:46.495255548 +0100
-@@ -0,0 +1,73 @@
+--- linux-2.6.18.8/include/xen/interface/io/xenbus.h   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/xenbus.h      2008-05-19 00:34:28.469245605 +0300
+@@ -0,0 +1,80 @@
 +/*****************************************************************************
 + * xenbus.h
 + *
@@ -132491,7 +198070,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +     */
 +    XenbusStateClosing       = 5,
 +
-+    XenbusStateClosed        = 6
++    XenbusStateClosed        = 6,
++
++    /*
++     * Reconfiguring: The device is being reconfigured.
++     */
++    XenbusStateReconfiguring = 7,
++
++    XenbusStateReconfigured  = 8
 +};
 +typedef enum xenbus_state XenbusState;
 +
@@ -132506,10 +198092,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io/xs_wire.h linux-2.6.18-xen.hg/include/xen/interface/io/xs_wire.h
---- linux-2.6.18/include/xen/interface/io/xs_wire.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/io/xs_wire.h     2007-12-23 11:15:46.571926242 +0100
-@@ -0,0 +1,121 @@
+--- linux-2.6.18.8/include/xen/interface/io/xs_wire.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/io/xs_wire.h     2008-05-19 00:34:28.469245605 +0300
+@@ -0,0 +1,130 @@
 +/*
 + * Details of the "wire" protocol between Xen Store Daemon and client
 + * library or guest kernel.
@@ -132558,7 +198143,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +    XS_WATCH_EVENT,
 +    XS_ERROR,
 +    XS_IS_DOMAIN_INTRODUCED,
-+    XS_RESUME
++    XS_RESUME,
++    XS_SET_TARGET
 +};
 +
 +#define XS_WRITE_NONE "NONE"
@@ -132572,6 +198158,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +    const char *errstring;
 +};
 +#define XSD_ERROR(x) { x, #x }
++/* LINTED: static unused */
 +static struct xsd_errors xsd_errors[]
 +#if defined(__GNUC__)
 +__attribute__((unused))
@@ -132620,6 +198207,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 +    XENSTORE_RING_IDX rsp_cons, rsp_prod;
 +};
 +
++/* Violating this is very bad.  See docs/misc/xenstore.txt. */
++#define XENSTORE_PAYLOAD_MAX 4096
++
++/* Violating these just gets you an error back */
++#define XENSTORE_ABS_PATH_MAX 3072
++#define XENSTORE_REL_PATH_MAX 2048
++
 +#endif /* _XS_WIRE_H */
 +
 +/*
@@ -132631,13 +198225,30 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/io
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/kexec.h linux-2.6.18-xen.hg/include/xen/interface/kexec.h
---- linux-2.6.18/include/xen/interface/kexec.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/kexec.h  2007-12-23 11:15:46.575259748 +0100
-@@ -0,0 +1,140 @@
+--- linux-2.6.18.8/include/xen/interface/kexec.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/kexec.h  2008-05-19 00:34:28.469245605 +0300
+@@ -0,0 +1,167 @@
 +/******************************************************************************
 + * kexec.h - Public portion
 + * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ * 
 + * Xen port written by:
 + * - Simon 'Horms' Horman <horms@verge.net.au>
 + * - Magnus Damm <magnus@valinux.co.jp>
@@ -132745,9 +198356,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ke
 +    xen_kexec_image_t image;
 +} xen_kexec_load_t;
 +
-+#define KEXEC_RANGE_MA_CRASH 0   /* machine address and size of crash area */
-+#define KEXEC_RANGE_MA_XEN   1   /* machine address and size of Xen itself */
-+#define KEXEC_RANGE_MA_CPU   2   /* machine address and size of a CPU note */
++#define KEXEC_RANGE_MA_CRASH      0 /* machine address and size of crash area */
++#define KEXEC_RANGE_MA_XEN        1 /* machine address and size of Xen itself */
++#define KEXEC_RANGE_MA_CPU        2 /* machine address and size of a CPU note */
++#define KEXEC_RANGE_MA_XENHEAP    3 /* machine address and size of xenheap
++                                     * Note that although this is adjacent
++                                     * to Xen it exists in a separate EFI
++                                     * region on ia64, and thus needs to be
++                                     * inserted into iomem_machine separately */
++#define KEXEC_RANGE_MA_BOOT_PARAM 4 /* machine address and size of
++                                     * the ia64_boot_param */
++#define KEXEC_RANGE_MA_EFI_MEMMAP 5 /* machine address and size of
++                                     * of the EFI Memory Map */
 +
 +/*
 + * Find the address and size of certain memory areas
@@ -132775,17 +198395,36 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ke
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/libelf.h linux-2.6.18-xen.hg/include/xen/interface/libelf.h
---- linux-2.6.18/include/xen/interface/libelf.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/libelf.h 2007-12-23 11:15:46.575259748 +0100
-@@ -0,0 +1,245 @@
+--- linux-2.6.18.8/include/xen/interface/libelf.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/libelf.h 2008-05-19 00:34:28.469245605 +0300
+@@ -0,0 +1,265 @@
++/******************************************************************************
++ * libelf.h
++ * 
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ */
++
 +#ifndef __XC_LIBELF__
 +#define __XC_LIBELF__ 1
 +
-+#if defined(__i386__) || defined(__x86_64) || defined(__ia64__)
++#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
 +#define XEN_ELF_LITTLE_ENDIAN
-+#elif defined(__powerpc__)
-+#define XEN_ELF_BIG_ENDIAN
 +#else
 +#error define architectural endianness
 +#endif
@@ -133024,9 +198663,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/li
 +                  struct elf_dom_parms *parms);
 +
 +#endif /* __XC_LIBELF__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/memory.h linux-2.6.18-xen.hg/include/xen/interface/memory.h
---- linux-2.6.18/include/xen/interface/memory.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/memory.h 2007-12-23 11:15:46.575259748 +0100
+--- linux-2.6.18.8/include/xen/interface/memory.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/memory.h 2008-05-19 00:34:28.473245836 +0300
 @@ -0,0 +1,281 @@
 +/******************************************************************************
 + * memory.h
@@ -133309,9 +198947,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/me
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/nmi.h linux-2.6.18-xen.hg/include/xen/interface/nmi.h
---- linux-2.6.18/include/xen/interface/nmi.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/nmi.h    2007-12-23 11:15:46.575259748 +0100
+--- linux-2.6.18.8/include/xen/interface/nmi.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/nmi.h    2008-05-19 00:34:28.473245836 +0300
 @@ -0,0 +1,78 @@
 +/******************************************************************************
 + * nmi.h
@@ -133391,10 +199028,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/nm
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/physdev.h linux-2.6.18-xen.hg/include/xen/interface/physdev.h
---- linux-2.6.18/include/xen/interface/physdev.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/physdev.h        2007-12-23 11:15:46.575259748 +0100
-@@ -0,0 +1,169 @@
+--- linux-2.6.18.8/include/xen/interface/physdev.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/physdev.h        2008-05-19 00:34:28.473245836 +0300
+@@ -0,0 +1,205 @@
 +/*
 + * Permission is hereby granted, free of charge, to any person obtaining a copy
 + * of this software and associated documentation files (the "Software"), to
@@ -133478,7 +199114,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ph
 +#define PHYSDEVOP_set_iobitmap           7
 +struct physdev_set_iobitmap {
 +    /* IN */
-+    XEN_GUEST_HANDLE_00030205(uint8_t) bitmap;
++#if __XEN_INTERFACE_VERSION__ >= 0x00030205
++    XEN_GUEST_HANDLE(uint8) bitmap;
++#else
++    uint8_t *bitmap;
++#endif
 +    uint32_t nr_ports;
 +};
 +typedef struct physdev_set_iobitmap physdev_set_iobitmap_t;
@@ -133514,6 +199154,38 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ph
 +};
 +typedef struct physdev_irq physdev_irq_t;
 +DEFINE_XEN_GUEST_HANDLE(physdev_irq_t);
++ 
++#define MAP_PIRQ_TYPE_MSI               0x0
++#define MAP_PIRQ_TYPE_GSI               0x1
++#define MAP_PIRQ_TYPE_UNKNOWN           0x2
++
++#define PHYSDEVOP_map_pirq               13
++struct physdev_map_pirq {
++    domid_t domid;
++    /* IN */
++    int type;
++    /* IN */
++    int index;
++    /* IN or OUT */
++    int pirq;
++    /* IN */
++    struct {
++        int bus, devfn, entry_nr;
++              int msi;  /* 0 - MSIX    1 - MSI */
++    } msi_info;
++};
++typedef struct physdev_map_pirq physdev_map_pirq_t;
++DEFINE_XEN_GUEST_HANDLE(physdev_map_pirq_t);
++
++#define PHYSDEVOP_unmap_pirq             14
++struct physdev_unmap_pirq {
++    domid_t domid;
++    /* IN */
++    int pirq;
++};
++
++typedef struct physdev_unmap_pirq physdev_unmap_pirq_t;
++DEFINE_XEN_GUEST_HANDLE(physdev_unmap_pirq_t);
 +
 +/*
 + * Argument to physdev_op_compat() hypercall. Superceded by new physdev_op()
@@ -133564,10 +199236,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ph
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/platform.h linux-2.6.18-xen.hg/include/xen/interface/platform.h
---- linux-2.6.18/include/xen/interface/platform.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/platform.h       2007-12-23 11:15:46.575259748 +0100
-@@ -0,0 +1,232 @@
+--- linux-2.6.18.8/include/xen/interface/platform.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/platform.h       2008-05-19 00:34:28.473245836 +0300
+@@ -0,0 +1,346 @@
 +/******************************************************************************
 + * platform.h
 + * 
@@ -133716,7 +199387,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/pl
 +            uint8_t capabilities;
 +            uint8_t edid_transfer_time;
 +            /* must refer to 128-byte buffer */
-+            XEN_GUEST_HANDLE(uint8_t) edid;
++            XEN_GUEST_HANDLE(uint8) edid;
 +        } vbeddc_info; /* XEN_FW_VBEDDC_INFO */
 +    } u;
 +};
@@ -133756,12 +199427,12 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/pl
 +struct xenpf_getidletime {
 +    /* IN/OUT variables */
 +    /* IN: CPUs to interrogate; OUT: subset of IN which are present */
-+    XEN_GUEST_HANDLE(uint8_t) cpumap_bitmap;
++    XEN_GUEST_HANDLE(uint8) cpumap_bitmap;
 +    /* IN variables */
 +    /* Size of cpumap bitmap. */
 +    uint32_t cpumap_nr_cpus;
 +    /* Must be indexable for every cpu in cpumap_bitmap. */
-+    XEN_GUEST_HANDLE(uint64_t) idletime;
++    XEN_GUEST_HANDLE(uint64) idletime;
 +    /* OUT variables */
 +    /* System time when the idletime snapshots were taken. */
 +    uint64_t now;
@@ -133769,6 +199440,119 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/pl
 +typedef struct xenpf_getidletime xenpf_getidletime_t;
 +DEFINE_XEN_GUEST_HANDLE(xenpf_getidletime_t);
 +
++#define XENPF_set_processor_pminfo      54
++
++/* ability bits */
++#define XEN_PROCESSOR_PM_CX   1
++#define XEN_PROCESSOR_PM_PX   2
++#define XEN_PROCESSOR_PM_TX   4
++
++/* cmd type */
++#define XEN_PM_CX   0
++#define XEN_PM_PX   1
++#define XEN_PM_TX   2
++
++/* Px sub info type */
++#define XEN_PX_PCT   1
++#define XEN_PX_PSS   2
++#define XEN_PX_PPC   4
++#define XEN_PX_PSD   8
++
++struct xen_power_register {
++    uint32_t     space_id;
++    uint32_t     bit_width;
++    uint32_t     bit_offset;
++    uint32_t     access_size;
++    uint64_t     address;
++};
++
++struct xen_processor_csd {
++    uint32_t    domain;      /* domain number of one dependent group */
++    uint32_t    coord_type;  /* coordination type */
++    uint32_t    num;         /* number of processors in same domain */
++};
++typedef struct xen_processor_csd xen_processor_csd_t;
++DEFINE_XEN_GUEST_HANDLE(xen_processor_csd_t);
++
++struct xen_processor_cx {
++    struct xen_power_register  reg; /* GAS for Cx trigger register */
++    uint8_t     type;     /* cstate value, c0: 0, c1: 1, ... */
++    uint32_t    latency;  /* worst latency (ms) to enter/exit this cstate */
++    uint32_t    power;    /* average power consumption(mW) */
++    uint32_t    dpcnt;    /* number of dependency entries */
++    XEN_GUEST_HANDLE(xen_processor_csd_t) dp; /* NULL if no dependency */
++};
++typedef struct xen_processor_cx xen_processor_cx_t;
++DEFINE_XEN_GUEST_HANDLE(xen_processor_cx_t);
++
++struct xen_processor_flags {
++    uint32_t bm_control:1;
++    uint32_t bm_check:1;
++    uint32_t has_cst:1;
++    uint32_t power_setup_done:1;
++    uint32_t bm_rld_set:1;
++};
++
++struct xen_processor_power {
++    uint32_t count;  /* number of C state entries in array below */
++    struct xen_processor_flags flags;  /* global flags of this processor */
++    XEN_GUEST_HANDLE(xen_processor_cx_t) states; /* supported c states */
++};
++
++struct xen_pct_register {
++    uint8_t  descriptor;
++    uint16_t length;
++    uint8_t  space_id;
++    uint8_t  bit_width;
++    uint8_t  bit_offset;
++    uint8_t  reserved;
++    uint64_t address;
++};
++
++struct xen_processor_px {
++    uint64_t core_frequency; /* megahertz */
++    uint64_t power;      /* milliWatts */
++    uint64_t transition_latency; /* microseconds */
++    uint64_t bus_master_latency; /* microseconds */
++    uint64_t control;        /* control value */
++    uint64_t status;     /* success indicator */
++};
++typedef struct xen_processor_px xen_processor_px_t;
++DEFINE_XEN_GUEST_HANDLE(xen_processor_px_t);
++
++struct xen_psd_package {
++    uint64_t num_entries;
++    uint64_t revision;
++    uint64_t domain;
++    uint64_t coord_type;
++    uint64_t num_processors;
++};
++
++struct xen_processor_performance {
++    uint32_t flags;     /* flag for Px sub info type */
++    uint32_t ppc;       /* Platform limitation on freq usage */
++    struct xen_pct_register control_register;
++    struct xen_pct_register status_register;
++    uint32_t state_count;     /* total available performance states */
++    XEN_GUEST_HANDLE(xen_processor_px_t) states;
++    struct xen_psd_package domain_info;
++    uint32_t shared_type;     /* coordination type of this processor */
++};
++typedef struct xen_processor_performance xen_processor_performance_t;
++DEFINE_XEN_GUEST_HANDLE(xen_processor_performance_t);
++
++struct xenpf_set_processor_pminfo {
++    /* IN variables */
++    uint32_t id;    /* ACPI CPU ID */
++    uint32_t type;  /* {XEN_PM_CX, XEN_PM_PX} */
++    union {
++        struct xen_processor_power          power;/* Cx: _CST/_CSD */
++        struct xen_processor_performance    perf; /* Px: _PPC/_PCT/_PSS/_PSD */
++    };
++};
++typedef struct xenpf_set_processor_pminfo xenpf_set_processor_pminfo_t;
++DEFINE_XEN_GUEST_HANDLE(xenpf_set_processor_pminfo_t);
++
 +struct xen_platform_op {
 +    uint32_t cmd;
 +    uint32_t interface_version; /* XENPF_INTERFACE_VERSION */
@@ -133783,6 +199567,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/pl
 +        struct xenpf_enter_acpi_sleep  enter_acpi_sleep;
 +        struct xenpf_change_freq       change_freq;
 +        struct xenpf_getidletime       getidletime;
++        struct xenpf_set_processor_pminfo set_pminfo;
 +        uint8_t                        pad[128];
 +    } u;
 +};
@@ -133800,9 +199585,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/pl
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/sched.h linux-2.6.18-xen.hg/include/xen/interface/sched.h
---- linux-2.6.18/include/xen/interface/sched.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/sched.h  2007-12-23 11:15:46.578593257 +0100
+--- linux-2.6.18.8/include/xen/interface/sched.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/sched.h  2008-05-19 00:34:28.477246066 +0300
 @@ -0,0 +1,121 @@
 +/******************************************************************************
 + * sched.h
@@ -133925,10 +199709,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/sc
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/sysctl.h linux-2.6.18-xen.hg/include/xen/interface/sysctl.h
---- linux-2.6.18/include/xen/interface/sysctl.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/sysctl.h 2007-12-23 11:15:46.578593257 +0100
-@@ -0,0 +1,238 @@
+--- linux-2.6.18.8/include/xen/interface/sysctl.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/sysctl.h 2008-05-19 00:34:28.477246066 +0300
+@@ -0,0 +1,280 @@
 +/******************************************************************************
 + * sysctl.h
 + * 
@@ -134015,8 +199798,13 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/sy
 + * Get physical information about the host machine
 + */
 +#define XEN_SYSCTL_physinfo          3
++ /* (x86) The platform supports HVM guests. */
++#define _XEN_SYSCTL_PHYSCAP_hvm          0
++#define XEN_SYSCTL_PHYSCAP_hvm           (1u<<_XEN_SYSCTL_PHYSCAP_hvm)
++ /* (x86) The platform supports HVM-guest direct access to I/O devices. */
++#define _XEN_SYSCTL_PHYSCAP_hvm_directio 1
++#define XEN_SYSCTL_PHYSCAP_hvm_directio  (1u<<_XEN_SYSCTL_PHYSCAP_hvm_directio)
 +struct xen_sysctl_physinfo {
-+    /* IN variables. */
 +    uint32_t threads_per_core;
 +    uint32_t cores_per_socket;
 +    uint32_t nr_cpus;
@@ -134027,7 +199815,6 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/sy
 +    uint64_aligned_t scrub_pages;
 +    uint32_t hw_cap[8];
 +
-+    /* IN/OUT variables. */
 +    /*
 +     * IN: maximum addressable entry in the caller-provided cpu_to_node array.
 +     * OUT: largest cpu identifier in the system.
@@ -134042,7 +199829,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/sy
 +     * If the actual @max_cpu_id is smaller than the array then the trailing
 +     * elements of the array will not be written by the sysctl.
 +     */
-+    XEN_GUEST_HANDLE_64(uint32_t) cpu_to_node;
++    XEN_GUEST_HANDLE_64(uint32) cpu_to_node;
++
++    /* XEN_SYSCTL_PHYSCAP_??? */
++    uint32_t capabilities;
 +};
 +typedef struct xen_sysctl_physinfo xen_sysctl_physinfo_t;
 +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_physinfo_t);
@@ -134136,6 +199926,40 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/sy
 +};
 +typedef struct xen_sysctl_availheap xen_sysctl_availheap_t;
 +DEFINE_XEN_GUEST_HANDLE(xen_sysctl_availheap_t);
++
++#define XEN_SYSCTL_get_pmstat        10
++struct pm_px_val {
++    uint64_aligned_t freq;        /* Px core frequency */
++    uint64_aligned_t residency;   /* Px residency time */
++    uint64_aligned_t count;       /* Px transition count */
++};
++typedef struct pm_px_val pm_px_val_t;
++DEFINE_XEN_GUEST_HANDLE(pm_px_val_t);
++
++struct pm_px_stat {
++    uint8_t total;        /* total Px states */
++    uint8_t usable;       /* usable Px states */
++    uint8_t last;         /* last Px state */
++    uint8_t cur;          /* current Px state */
++    XEN_GUEST_HANDLE_64(uint64) trans_pt;   /* Px transition table */
++    XEN_GUEST_HANDLE_64(pm_px_val_t) pt;
++};
++typedef struct pm_px_stat pm_px_stat_t;
++DEFINE_XEN_GUEST_HANDLE(pm_px_stat_t);
++
++struct xen_sysctl_get_pmstat {
++#define PMSTAT_get_max_px   0x11
++#define PMSTAT_get_pxstat   0x12
++#define PMSTAT_reset_pxstat 0x13
++    uint32_t type;
++    uint32_t cpuid;
++    union {
++        struct pm_px_stat getpx;
++        /* other struct for cx, tx, etc */
++    } u;
++};
++typedef struct xen_sysctl_get_pmstat xen_sysctl_get_pmstat_t;
++DEFINE_XEN_GUEST_HANDLE(xen_sysctl_get_pmstat_t);
 + 
 +struct xen_sysctl {
 +    uint32_t cmd;
@@ -134150,6 +199974,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/sy
 +        struct xen_sysctl_debug_keys        debug_keys;
 +        struct xen_sysctl_getcpuinfo        getcpuinfo;
 +        struct xen_sysctl_availheap         availheap;
++        struct xen_sysctl_get_pmstat        get_pmstat;
 +        uint8_t                             pad[128];
 +    } u;
 +};
@@ -134167,10 +199992,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/sy
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/trace.h linux-2.6.18-xen.hg/include/xen/interface/trace.h
---- linux-2.6.18/include/xen/interface/trace.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/trace.h  2007-12-23 11:15:46.578593257 +0100
-@@ -0,0 +1,159 @@
+--- linux-2.6.18.8/include/xen/interface/trace.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/trace.h  2008-05-19 00:34:28.477246066 +0300
+@@ -0,0 +1,167 @@
 +/******************************************************************************
 + * include/public/trace.h
 + * 
@@ -134314,6 +200138,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/tr
 + * field, indexes into an array of struct t_rec's.
 + */
 +struct t_buf {
++    /* Assume the data buffer size is X.  X is generally not a power of 2.
++     * CONS and PROD are incremented modulo (2*X):
++     *     0 <= cons < 2*X
++     *     0 <= prod < 2*X
++     * This is done because addition modulo X breaks at 2^32 when X is not a
++     * power of 2:
++     *     (((2^32 - 1) % X) + 1) % X != (2^32) % X
++     */
 +    uint32_t cons;   /* Offset of next item to be consumed by control tools. */
 +    uint32_t prod;   /* Offset of next item to be produced by Xen.           */
 +    /*  Records follow immediately after the meta-data header.    */
@@ -134330,10 +200162,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/tr
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/vcpu.h linux-2.6.18-xen.hg/include/xen/interface/vcpu.h
---- linux-2.6.18/include/xen/interface/vcpu.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/vcpu.h   2007-12-23 11:15:46.578593257 +0100
-@@ -0,0 +1,195 @@
+--- linux-2.6.18.8/include/xen/interface/vcpu.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/vcpu.h   2008-05-19 00:34:28.493246989 +0300
+@@ -0,0 +1,213 @@
 +/******************************************************************************
 + * vcpu.h
 + * 
@@ -134506,7 +200337,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/vc
 + *
 + * This may be called only once per vcpu.
 + */
-+#define VCPUOP_register_vcpu_info   10  /* arg == struct vcpu_info */
++#define VCPUOP_register_vcpu_info   10  /* arg == vcpu_register_vcpu_info_t */
 +struct vcpu_register_vcpu_info {
 +    uint64_t mfn;    /* mfn of page to place vcpu_info */
 +    uint32_t offset; /* offset within page */
@@ -134518,6 +200349,24 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/vc
 +/* Send an NMI to the specified VCPU. @extra_arg == NULL. */
 +#define VCPUOP_send_nmi             11
 +
++/* 
++ * Get the physical ID information for a pinned vcpu's underlying physical
++ * processor.  The physical ID informmation is architecture-specific.
++ * On x86: id[31:0]=apic_id, id[63:32]=acpi_id, and all values 0xff and
++ *         greater are reserved.
++ * This command returns -EINVAL if it is not a valid operation for this VCPU.
++ */
++#define VCPUOP_get_physid           12 /* arg == vcpu_get_physid_t */
++struct vcpu_get_physid {
++    uint64_t phys_id;
++};
++typedef struct vcpu_get_physid vcpu_get_physid_t;
++DEFINE_XEN_GUEST_HANDLE(vcpu_get_physid_t);
++#define xen_vcpu_physid_to_x86_apicid(physid) \
++    ((((uint32_t)(physid)) >= 0xff) ? 0xff : ((uint8_t)(physid)))
++#define xen_vcpu_physid_to_x86_acpiid(physid) \
++    ((((uint32_t)((physid)>>32)) >= 0xff) ? 0xff : ((uint8_t)((physid)>>32)))
++
 +#endif /* __XEN_PUBLIC_VCPU_H__ */
 +
 +/*
@@ -134529,9 +200378,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/vc
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/version.h linux-2.6.18-xen.hg/include/xen/interface/version.h
---- linux-2.6.18/include/xen/interface/version.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/version.h        2007-12-23 11:15:46.578593257 +0100
+--- linux-2.6.18.8/include/xen/interface/version.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/version.h        2008-05-19 00:34:28.493246989 +0300
 @@ -0,0 +1,91 @@
 +/******************************************************************************
 + * version.h
@@ -134624,55 +200472,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/ve
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xencomm.h linux-2.6.18-xen.hg/include/xen/interface/xencomm.h
---- linux-2.6.18/include/xen/interface/xencomm.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/xencomm.h        2007-12-23 11:15:46.581926766 +0100
-@@ -0,0 +1,41 @@
-+/*
-+ * Permission is hereby granted, free of charge, to any person obtaining a copy
-+ * of this software and associated documentation files (the "Software"), to
-+ * deal in the Software without restriction, including without limitation the
-+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
-+ * sell copies of the Software, and to permit persons to whom the Software is
-+ * furnished to do so, subject to the following conditions:
-+ *
-+ * The above copyright notice and this permission notice shall be included in
-+ * all copies or substantial portions of the Software.
-+ *
-+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
-+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-+ * DEALINGS IN THE SOFTWARE.
-+ *
-+ * Copyright (C) IBM Corp. 2006
-+ */
-+
-+#ifndef _XEN_XENCOMM_H_
-+#define _XEN_XENCOMM_H_
-+
-+/* A xencomm descriptor is a scatter/gather list containing physical
-+ * addresses corresponding to a virtually contiguous memory area. The
-+ * hypervisor translates these physical addresses to machine addresses to copy
-+ * to and from the virtually contiguous area.
-+ */
-+
-+#define XENCOMM_MAGIC 0x58434F4D /* 'XCOM' */
-+#define XENCOMM_INVALID (~0UL)
-+
-+struct xencomm_desc {
-+    uint32_t magic;
-+    uint32_t nr_addrs; /* the number of entries in address[] */
-+    uint64_t address[0];
-+};
-+
-+#endif /* _XEN_XENCOMM_H_ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xen-compat.h linux-2.6.18-xen.hg/include/xen/interface/xen-compat.h
---- linux-2.6.18/include/xen/interface/xen-compat.h    1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/xen-compat.h     2007-12-23 11:15:46.578593257 +0100
-@@ -0,0 +1,51 @@
+--- linux-2.6.18.8/include/xen/interface/xen-compat.h  1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/xen-compat.h     2008-05-19 00:34:28.497247219 +0300
+@@ -0,0 +1,44 @@
 +/******************************************************************************
 + * xen-compat.h
 + * 
@@ -134702,7 +200504,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xe
 +#ifndef __XEN_PUBLIC_XEN_COMPAT_H__
 +#define __XEN_PUBLIC_XEN_COMPAT_H__
 +
-+#define __XEN_LATEST_INTERFACE_VERSION__ 0x00030207
++#define __XEN_LATEST_INTERFACE_VERSION__ 0x00030208
 +
 +#if defined(__XEN__) || defined(__XEN_TOOLS__)
 +/* Xen is built with matching headers and implements the latest interface. */
@@ -134716,18 +200518,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xe
 +#error "These header files do not support the requested interface version."
 +#endif
 +
-+/* Fields defined as a Xen guest handle since 0x00030205. */
-+#if __XEN_INTERFACE_VERSION__ >= 0x00030205
-+#define XEN_GUEST_HANDLE_00030205(type) XEN_GUEST_HANDLE(type)
-+#else
-+#define XEN_GUEST_HANDLE_00030205(type) type *
-+#endif
-+
 +#endif /* __XEN_PUBLIC_XEN_COMPAT_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xen.h linux-2.6.18-xen.hg/include/xen/interface/xen.h
---- linux-2.6.18/include/xen/interface/xen.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/xen.h    2007-12-23 11:15:46.581926766 +0100
-@@ -0,0 +1,618 @@
+--- linux-2.6.18.8/include/xen/interface/xen.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/xen.h    2008-05-19 00:34:28.553250447 +0300
+@@ -0,0 +1,638 @@
 +/******************************************************************************
 + * xen.h
 + * 
@@ -134763,12 +200557,23 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xe
 +#include "arch-x86/xen.h"
 +#elif defined(__ia64__)
 +#include "arch-ia64.h"
-+#elif defined(__powerpc__)
-+#include "arch-powerpc.h"
 +#else
 +#error "Unsupported architecture"
 +#endif
 +
++#ifndef __ASSEMBLY__
++/* Guest handles for primitive C types. */
++DEFINE_XEN_GUEST_HANDLE(char);
++__DEFINE_XEN_GUEST_HANDLE(uchar, unsigned char);
++DEFINE_XEN_GUEST_HANDLE(int);
++__DEFINE_XEN_GUEST_HANDLE(uint,  unsigned int);
++DEFINE_XEN_GUEST_HANDLE(long);
++__DEFINE_XEN_GUEST_HANDLE(ulong, unsigned long);
++DEFINE_XEN_GUEST_HANDLE(void);
++
++DEFINE_XEN_GUEST_HANDLE(xen_pfn_t);
++#endif
++
 +/*
 + * HYPERCALLS
 + */
@@ -134898,9 +200703,14 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xe
 + * ptr[:2]  -- Machine address within the frame whose mapping to modify.
 + *             The frame must belong to the FD, if one is specified.
 + * val      -- Value to write into the mapping entry.
++ * 
++ * ptr[1:0] == MMU_PT_UPDATE_PRESERVE_AD:
++ * As MMU_NORMAL_PT_UPDATE above, but A/D bits currently in the PTE are ORed
++ * with those in @val.
 + */
-+#define MMU_NORMAL_PT_UPDATE     0 /* checked '*ptr = val'. ptr is MA.       */
-+#define MMU_MACHPHYS_UPDATE      1 /* ptr = MA of frame to modify entry for  */
++#define MMU_NORMAL_PT_UPDATE      0 /* checked '*ptr = val'. ptr is MA.      */
++#define MMU_MACHPHYS_UPDATE       1 /* ptr = MA of frame to modify entry for */
++#define MMU_PT_UPDATE_PRESERVE_AD 2 /* atomically: *ptr = val | (*ptr&(A|D)) */
 +
 +/*
 + * MMU EXTENDED OPERATIONS
@@ -134975,7 +200785,11 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xe
 +        /* SET_LDT */
 +        unsigned int nr_ents;
 +        /* TLB_FLUSH_MULTI, INVLPG_MULTI */
-+        XEN_GUEST_HANDLE_00030205(void) vcpumask;
++#if __XEN_INTERFACE_VERSION__ >= 0x00030205
++        XEN_GUEST_HANDLE(void) vcpumask;
++#else
++        void *vcpumask;
++#endif
 +    } arg2;
 +};
 +typedef struct mmuext_op mmuext_op_t;
@@ -135313,10 +201127,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xe
 +#define __mk_unsigned_long(x) x ## UL
 +#define mk_unsigned_long(x) __mk_unsigned_long(x)
 +
-+DEFINE_XEN_GUEST_HANDLE(uint8_t);
-+DEFINE_XEN_GUEST_HANDLE(uint16_t);
-+DEFINE_XEN_GUEST_HANDLE(uint32_t);
-+DEFINE_XEN_GUEST_HANDLE(uint64_t);
++__DEFINE_XEN_GUEST_HANDLE(uint8,  uint8_t);
++__DEFINE_XEN_GUEST_HANDLE(uint16, uint16_t);
++__DEFINE_XEN_GUEST_HANDLE(uint32, uint32_t);
++__DEFINE_XEN_GUEST_HANDLE(uint64, uint64_t);
 +
 +#else /* __ASSEMBLY__ */
 +
@@ -135346,9 +201160,52 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xe
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xenoprof.h linux-2.6.18-xen.hg/include/xen/interface/xenoprof.h
---- linux-2.6.18/include/xen/interface/xenoprof.h      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/xenoprof.h       2007-12-23 11:15:46.581926766 +0100
+--- linux-2.6.18.8/include/xen/interface/xencomm.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/xencomm.h        2008-05-19 00:34:28.553250447 +0300
+@@ -0,0 +1,41 @@
++/*
++ * Permission is hereby granted, free of charge, to any person obtaining a copy
++ * of this software and associated documentation files (the "Software"), to
++ * deal in the Software without restriction, including without limitation the
++ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
++ * sell copies of the Software, and to permit persons to whom the Software is
++ * furnished to do so, subject to the following conditions:
++ *
++ * The above copyright notice and this permission notice shall be included in
++ * all copies or substantial portions of the Software.
++ *
++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
++ * DEALINGS IN THE SOFTWARE.
++ *
++ * Copyright (C) IBM Corp. 2006
++ */
++
++#ifndef _XEN_XENCOMM_H_
++#define _XEN_XENCOMM_H_
++
++/* A xencomm descriptor is a scatter/gather list containing physical
++ * addresses corresponding to a virtually contiguous memory area. The
++ * hypervisor translates these physical addresses to machine addresses to copy
++ * to and from the virtually contiguous area.
++ */
++
++#define XENCOMM_MAGIC 0x58434F4D /* 'XCOM' */
++#define XENCOMM_INVALID (~0UL)
++
++struct xencomm_desc {
++    uint32_t magic;
++    uint32_t nr_addrs; /* the number of entries in address[] */
++    uint64_t address[0];
++};
++
++#endif /* _XEN_XENCOMM_H_ */
+--- linux-2.6.18.8/include/xen/interface/xenoprof.h    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/xenoprof.h       2008-05-19 00:34:28.553250447 +0300
 @@ -0,0 +1,138 @@
 +/******************************************************************************
 + * xenoprof.h
@@ -135488,10 +201345,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xe
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xsm/acm.h linux-2.6.18-xen.hg/include/xen/interface/xsm/acm.h
---- linux-2.6.18/include/xen/interface/xsm/acm.h       1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/xsm/acm.h        2007-12-23 11:15:46.581926766 +0100
-@@ -0,0 +1,229 @@
+--- linux-2.6.18.8/include/xen/interface/xsm/acm.h     1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/xsm/acm.h        2008-05-19 00:34:28.557250678 +0300
+@@ -0,0 +1,235 @@
 +/*
 + * acm.h: Xen access control module interface defintions
 + *
@@ -135585,7 +201441,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xs
 + * whenever the interpretation of the related
 + * policy's data structure changes
 + */
-+#define ACM_POLICY_VERSION 3
++#define ACM_POLICY_VERSION 4
 +#define ACM_CHWALL_VERSION 1
 +#define ACM_STE_VERSION  1
 +
@@ -135596,6 +201452,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xs
 +#define ACMHOOK_none          0
 +#define ACMHOOK_sharing       1
 +#define ACMHOOK_authorization 2
++#define ACMHOOK_conflictset   3
 +
 +/* -------security policy relevant type definitions-------- */
 +
@@ -135624,6 +201481,10 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xs
 +/* high-16 = version, low-16 = check magic */
 +#define ACM_MAGIC  0x0001debc
 +
++/* size of the SHA1 hash identifying the XML policy from which the
++   binary policy was created */
++#define ACM_SHA1_HASH_SIZE    20
++
 +/* each offset in bytes from start of the struct they
 + * are part of */
 +
@@ -135653,6 +201514,7 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xs
 +    uint32_t secondary_policy_code;
 +    uint32_t secondary_buffer_offset;
 +    struct acm_policy_version xml_pol_version; /* add in V3 */
++    uint8_t xml_policy_hash[ACM_SHA1_HASH_SIZE]; /* added in V4 */
 +};
 +
 +
@@ -135721,9 +201583,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xs
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xsm/acm_ops.h linux-2.6.18-xen.hg/include/xen/interface/xsm/acm_ops.h
---- linux-2.6.18/include/xen/interface/xsm/acm_ops.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/xsm/acm_ops.h    2007-12-23 11:15:46.581926766 +0100
+--- linux-2.6.18.8/include/xen/interface/xsm/acm_ops.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/xsm/acm_ops.h    2008-05-19 00:34:28.557250678 +0300
 @@ -0,0 +1,159 @@
 +/*
 + * acm_ops.h: Xen access control module hypervisor commands
@@ -135884,9 +201745,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xs
 + * indent-tabs-mode: nil
 + * End:
 + */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xsm/flask_op.h linux-2.6.18-xen.hg/include/xen/interface/xsm/flask_op.h
---- linux-2.6.18/include/xen/interface/xsm/flask_op.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/interface/xsm/flask_op.h   2007-12-23 11:15:46.581926766 +0100
+--- linux-2.6.18.8/include/xen/interface/xsm/flask_op.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/interface/xsm/flask_op.h   2008-05-19 00:34:28.557250678 +0300
 @@ -0,0 +1,43 @@
 +/*
 + *  This file contains the flask_op hypercall commands and definitions.
@@ -135931,9 +201791,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/interface/xs
 +DEFINE_XEN_GUEST_HANDLE(flask_op_t);
 +
 +#endif
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/pcifront.h linux-2.6.18-xen.hg/include/xen/pcifront.h
---- linux-2.6.18/include/xen/pcifront.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/pcifront.h 2007-12-23 11:15:46.585260277 +0100
+--- linux-2.6.18.8/include/xen/pcifront.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/pcifront.h 2008-05-19 00:34:28.557250678 +0300
 @@ -0,0 +1,83 @@
 +/*
 + * PCI Frontend - arch-dependendent declarations
@@ -136018,9 +201877,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/pcifront.h l
 +#endif /* __KERNEL__ */
 +
 +#endif /* __XEN_ASM_PCIFRONT_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/public/evtchn.h linux-2.6.18-xen.hg/include/xen/public/evtchn.h
---- linux-2.6.18/include/xen/public/evtchn.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/public/evtchn.h    2007-12-23 11:15:46.585260277 +0100
+--- linux-2.6.18.8/include/xen/public/evtchn.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/public/evtchn.h    2008-05-19 00:34:28.565251139 +0300
 @@ -0,0 +1,88 @@
 +/******************************************************************************
 + * evtchn.h
@@ -136110,10 +201968,9 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/public/evtch
 +      _IOC(_IOC_NONE, 'E', 5, 0)
 +
 +#endif /* __LINUX_PUBLIC_EVTCHN_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/public/gntdev.h linux-2.6.18-xen.hg/include/xen/public/gntdev.h
---- linux-2.6.18/include/xen/public/gntdev.h   1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/public/gntdev.h    2007-12-23 11:15:46.585260277 +0100
-@@ -0,0 +1,105 @@
+--- linux-2.6.18.8/include/xen/public/gntdev.h 1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/public/gntdev.h    2008-05-19 00:34:28.569251370 +0300
+@@ -0,0 +1,119 @@
 +/******************************************************************************
 + * gntdev.h
 + * 
@@ -136218,10 +202075,23 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/public/gntde
 +      uint32_t pad;
 +};
 +
++/*
++ * Sets the maximum number of grants that may mapped at once by this gntdev
++ * instance.
++ *
++ * N.B. This must be called before any other ioctl is performed on the device.
++ */
++#define IOCTL_GNTDEV_SET_MAX_GRANTS \
++_IOC(_IOC_NONE, 'G', 3, sizeof(struct ioctl_gntdev_set_max_grants))
++struct ioctl_gntdev_set_max_grants {
++      /* IN parameter */
++      /* The maximum number of grants that may be mapped at once. */
++      uint32_t count;
++};
++
 +#endif /* __LINUX_PUBLIC_GNTDEV_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/public/privcmd.h linux-2.6.18-xen.hg/include/xen/public/privcmd.h
---- linux-2.6.18/include/xen/public/privcmd.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/public/privcmd.h   2007-12-23 11:15:46.585260277 +0100
+--- linux-2.6.18.8/include/xen/public/privcmd.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/public/privcmd.h   2008-05-19 00:34:28.569251370 +0300
 @@ -0,0 +1,79 @@
 +/******************************************************************************
 + * privcmd.h
@@ -136302,9 +202172,23 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/public/privc
 +      _IOC(_IOC_NONE, 'P', 3, sizeof(privcmd_mmapbatch_t))
 +
 +#endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/xenbus.h linux-2.6.18-xen.hg/include/xen/xenbus.h
---- linux-2.6.18/include/xen/xenbus.h  1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/xenbus.h   2007-12-23 11:15:46.585260277 +0100
+--- linux-2.6.18.8/include/xen/xen_proc.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/xen_proc.h 2008-05-19 00:34:28.569251370 +0300
+@@ -0,0 +1,12 @@
++
++#ifndef __ASM_XEN_PROC_H__
++#define __ASM_XEN_PROC_H__
++
++#include <linux/proc_fs.h>
++
++extern struct proc_dir_entry *create_xen_proc_entry(
++      const char *name, mode_t mode);
++extern void remove_xen_proc_entry(
++      const char *name);
++
++#endif /* __ASM_XEN_PROC_H__ */
+--- linux-2.6.18.8/include/xen/xenbus.h        1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/xenbus.h   2008-05-19 00:34:28.569251370 +0300
 @@ -0,0 +1,307 @@
 +/******************************************************************************
 + * xenbus.h
@@ -136613,9 +202497,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/xenbus.h lin
 +int xenbus_for_each_frontend(void *arg, int (*fn)(struct device *, void *));
 +
 +#endif /* _XEN_XENBUS_H */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/xencomm.h linux-2.6.18-xen.hg/include/xen/xencomm.h
---- linux-2.6.18/include/xen/xencomm.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/xencomm.h  2007-12-23 11:15:46.588593784 +0100
+--- linux-2.6.18.8/include/xen/xencomm.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/xencomm.h  2008-05-19 00:34:28.569251370 +0300
 @@ -0,0 +1,77 @@
 +/*
 + * This program is free software; you can redistribute it and/or modify
@@ -136694,9 +202577,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/xencomm.h li
 +#define xen_guest_handle(hnd)  ((hnd).p)
 +
 +#endif /* _LINUX_XENCOMM_H_ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/xencons.h linux-2.6.18-xen.hg/include/xen/xencons.h
---- linux-2.6.18/include/xen/xencons.h 1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/xencons.h  2007-12-23 11:15:46.588593784 +0100
+--- linux-2.6.18.8/include/xen/xencons.h       1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/xencons.h  2008-05-19 00:34:28.573251600 +0300
 @@ -0,0 +1,17 @@
 +#ifndef __ASM_XENCONS_H__
 +#define __ASM_XENCONS_H__
@@ -136715,9 +202597,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/xencons.h li
 +int xencons_ring_send(const char *data, unsigned len);
 +
 +#endif /* __ASM_XENCONS_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/xenoprof.h linux-2.6.18-xen.hg/include/xen/xenoprof.h
---- linux-2.6.18/include/xen/xenoprof.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/xenoprof.h 2007-12-23 11:15:46.588593784 +0100
+--- linux-2.6.18.8/include/xen/xenoprof.h      1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/include/xen/xenoprof.h 2008-05-19 00:34:28.573251600 +0300
 @@ -0,0 +1,42 @@
 +/******************************************************************************
 + * xen/xenoprof.h
@@ -136761,25 +202642,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/xenoprof.h l
 +
 +#endif /* CONFIG_XEN */
 +#endif /* __XEN_XENOPROF_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/include/xen/xen_proc.h linux-2.6.18-xen.hg/include/xen/xen_proc.h
---- linux-2.6.18/include/xen/xen_proc.h        1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/include/xen/xen_proc.h 2007-12-23 11:15:46.585260277 +0100
-@@ -0,0 +1,12 @@
-+
-+#ifndef __ASM_XEN_PROC_H__
-+#define __ASM_XEN_PROC_H__
-+
-+#include <linux/proc_fs.h>
-+
-+extern struct proc_dir_entry *create_xen_proc_entry(
-+      const char *name, mode_t mode);
-+extern void remove_xen_proc_entry(
-+      const char *name);
-+
-+#endif /* __ASM_XEN_PROC_H__ */
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/cpu.c linux-2.6.18-xen.hg/kernel/cpu.c
---- linux-2.6.18/kernel/cpu.c  2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/kernel/cpu.c   2007-12-23 11:15:46.618595361 +0100
+--- linux-2.6.18.8/kernel/Kconfig.preempt      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/kernel/Kconfig.preempt 2008-05-19 00:34:29.029277887 +0300
+@@ -35,6 +35,7 @@
+ config PREEMPT
+       bool "Preemptible Kernel (Low-Latency Desktop)"
++      depends on !XEN
+       help
+         This option reduces the latency of the kernel by making
+         all kernel code (that is not executing in a critical section)
+--- linux-2.6.18.8/kernel/cpu.c        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/kernel/cpu.c   2008-05-19 00:34:29.037278348 +0300
 @@ -48,7 +48,10 @@
  
  void unlock_cpu_hotplug(void)
@@ -136791,9 +202665,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/cpu.c linux-2.6.1
        if (recursive_depth) {
                recursive_depth--;
                return;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/fork.c linux-2.6.18-xen.hg/kernel/fork.c
---- linux-2.6.18/kernel/fork.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/kernel/fork.c  2007-12-23 11:15:46.625262374 +0100
+--- linux-2.6.18.8/kernel/fork.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/kernel/fork.c  2008-05-19 00:34:29.049279040 +0300
 @@ -276,6 +276,9 @@
                if (retval)
                        goto out;
@@ -136804,9 +202677,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/fork.c linux-2.6.
        retval = 0;
  out:
        up_write(&mm->mmap_sem);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/irq/spurious.c linux-2.6.18-xen.hg/kernel/irq/spurious.c
---- linux-2.6.18/kernel/irq/spurious.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/kernel/irq/spurious.c  2007-12-23 11:15:46.631929392 +0100
+--- linux-2.6.18.8/kernel/hrtimer.c    2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/kernel/hrtimer.c       2008-05-19 00:34:29.049279040 +0300
+@@ -59,7 +59,7 @@
+  *
+  * returns the time in ktime_t format
+  */
+-static ktime_t ktime_get_real(void)
++ktime_t ktime_get_real(void)
+ {
+       struct timespec now;
+--- linux-2.6.18.8/kernel/irq/spurious.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/kernel/irq/spurious.c  2008-05-19 00:34:29.085281115 +0300
 @@ -139,6 +139,7 @@
                    irqreturn_t action_ret, struct pt_regs *regs)
  {
@@ -136815,20 +202698,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/irq/spurious.c li
                desc->irqs_unhandled++;
                if (unlikely(action_ret != IRQ_NONE))
                        report_bad_irq(irq, desc, action_ret);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/Kconfig.preempt linux-2.6.18-xen.hg/kernel/Kconfig.preempt
---- linux-2.6.18/kernel/Kconfig.preempt        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/kernel/Kconfig.preempt 2007-12-23 11:15:46.611928341 +0100
-@@ -35,6 +35,7 @@
- config PREEMPT
-       bool "Preemptible Kernel (Low-Latency Desktop)"
-+      depends on !XEN
-       help
-         This option reduces the latency of the kernel by making
-         all kernel code (that is not executing in a critical section)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/kexec.c linux-2.6.18-xen.hg/kernel/kexec.c
---- linux-2.6.18/kernel/kexec.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/kernel/kexec.c 2007-12-23 11:15:46.631929392 +0100
+--- linux-2.6.18.8/kernel/kexec.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/kernel/kexec.c 2008-05-19 00:34:29.113282729 +0300
 @@ -330,13 +330,26 @@
        return 0;
  }
@@ -137055,9 +202926,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/kexec.c linux-2.6
        /* Take the kexec_lock here to prevent sys_kexec_load
         * running on one cpu from replacing the crash kernel
         * we are using after a panic on a different cpu.
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/resource.c linux-2.6.18-xen.hg/kernel/resource.c
---- linux-2.6.18/kernel/resource.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/kernel/resource.c      2007-12-23 11:15:46.655263952 +0100
+--- linux-2.6.18.8/kernel/resource.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/kernel/resource.c      2008-05-19 00:34:29.161285496 +0300
 @@ -36,6 +36,16 @@
  };
  EXPORT_SYMBOL(iomem_resource);
@@ -137124,9 +202994,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/resource.c linux-
        return 0;
  }
  __initcall(ioresources_init);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/softlockup.c linux-2.6.18-xen.hg/kernel/softlockup.c
---- linux-2.6.18/kernel/softlockup.c   2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/kernel/softlockup.c    2007-12-23 11:15:46.665264476 +0100
+--- linux-2.6.18.8/kernel/softlockup.c 2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/kernel/softlockup.c    2008-05-19 00:34:29.177286418 +0300
 @@ -40,6 +40,19 @@
  }
  EXPORT_SYMBOL(touch_softlockup_watchdog);
@@ -137147,9 +203016,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/softlockup.c linu
  /*
   * This callback runs from the timer interrupt, and checks
   * whether the watchdog thread has hung or not:
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/sysctl.c linux-2.6.18-xen.hg/kernel/sysctl.c
---- linux-2.6.18/kernel/sysctl.c       2007-12-23 11:26:51.296802316 +0100
-+++ linux-2.6.18-xen.hg/kernel/sysctl.c        2007-12-23 11:15:46.668597986 +0100
+--- linux-2.6.18.8/kernel/sysctl.c     2008-05-19 00:42:34.409259256 +0300
++++ linux-2.6.18-xen.hg/kernel/sysctl.c        2008-05-19 00:34:29.185286879 +0300
 @@ -661,7 +661,7 @@
                .proc_handler   = &proc_dointvec,
        },
@@ -137159,9 +203027,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/sysctl.c linux-2.
        {
                .ctl_name       = KERN_ACPI_VIDEO_FLAGS,
                .procname       = "acpi_video_flags",
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/timer.c linux-2.6.18-xen.hg/kernel/timer.c
---- linux-2.6.18/kernel/timer.c        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/kernel/timer.c 2007-12-23 11:15:46.671931494 +0100
+--- linux-2.6.18.8/kernel/timer.c      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/kernel/timer.c 2008-05-19 00:34:29.189287110 +0300
 @@ -485,7 +485,9 @@
                if (hr_expires < 3)
                        return hr_expires + jiffies;
@@ -137173,9 +203040,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/kernel/timer.c linux-2.6
  
        base = __get_cpu_var(tvec_bases);
        spin_lock(&base->lock);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/lib/Makefile linux-2.6.18-xen.hg/lib/Makefile
---- linux-2.6.18/lib/Makefile  2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/lib/Makefile   2007-12-23 11:15:46.678598509 +0100
+--- linux-2.6.18.8/lib/Makefile        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/lib/Makefile   2008-05-19 00:34:29.197287571 +0300
 @@ -52,6 +52,9 @@
  obj-$(CONFIG_AUDIT_GENERIC) += audit.o
  
@@ -137186,9 +203052,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/lib/Makefile linux-2.6.1
  
  hostprogs-y   := gen_crc32table
  clean-files   := crc32table.h
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/lib/swiotlb-xen.c linux-2.6.18-xen.hg/lib/swiotlb-xen.c
---- linux-2.6.18/lib/swiotlb-xen.c     1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/lib/swiotlb-xen.c      2007-12-23 11:15:46.731934648 +0100
+--- linux-2.6.18.8/lib/swiotlb-xen.c   1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/lib/swiotlb-xen.c      2008-05-19 00:34:29.249290569 +0300
 @@ -0,0 +1,745 @@
 +/*
 + * Dynamic DMA mapping support.
@@ -137935,9 +203800,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/lib/swiotlb-xen.c linux-
 +EXPORT_SYMBOL(swiotlb_sync_sg_for_device);
 +EXPORT_SYMBOL(swiotlb_dma_mapping_error);
 +EXPORT_SYMBOL(swiotlb_dma_supported);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/mm/highmem.c linux-2.6.18-xen.hg/mm/highmem.c
---- linux-2.6.18/mm/highmem.c  2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/mm/highmem.c   2007-12-23 11:15:46.748602187 +0100
+--- linux-2.6.18.8/mm/highmem.c        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/mm/highmem.c   2008-05-19 00:34:29.281292413 +0300
 @@ -142,6 +142,17 @@
        return vaddr;
  }
@@ -137956,9 +203820,21 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/mm/highmem.c linux-2.6.1
  void fastcall *kmap_high(struct page *page)
  {
        unsigned long vaddr;
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/mm/memory.c linux-2.6.18-xen.hg/mm/memory.c
---- linux-2.6.18/mm/memory.c   2007-12-23 11:26:51.296802316 +0100
-+++ linux-2.6.18-xen.hg/mm/memory.c    2007-12-23 11:15:46.751935698 +0100
+@@ -457,6 +468,12 @@
+       mempool_t *pool;
+       /*
++       * Data-less bio, nothing to bounce
++       */
++      if (bio_empty_barrier(*bio_orig))
++              return;
++
++      /*
+        * for non-isa bounce case, just check if the bounce pfn is equal
+        * to or bigger than the highest pfn in the system -- in that case,
+        * don't waste time iterating over bio segments
+--- linux-2.6.18.8/mm/memory.c 2008-05-19 00:42:34.409259256 +0300
++++ linux-2.6.18-xen.hg/mm/memory.c    2008-05-19 00:34:29.289292874 +0300
 @@ -396,6 +396,12 @@
                        return NULL;
        }
@@ -138137,9 +204013,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/mm/memory.c linux-2.6.18
  /*
   * handle_pte_fault chooses page fault handler according to an entry
   * which was read non-atomically.  Before making any commitment, on
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/mm/mmap.c linux-2.6.18-xen.hg/mm/mmap.c
---- linux-2.6.18/mm/mmap.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/mm/mmap.c      2007-12-23 11:15:46.755269206 +0100
+--- linux-2.6.18.8/mm/mmap.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/mm/mmap.c      2008-05-19 00:34:29.301293566 +0300
 @@ -1963,6 +1963,10 @@
        unsigned long nr_accounted = 0;
        unsigned long end;
@@ -138151,9 +204026,19 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/mm/mmap.c linux-2.6.18-x
        lru_add_drain();
        flush_cache_mm(mm);
        tlb = tlb_gather_mmu(mm, 1);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/mm/page_alloc.c linux-2.6.18-xen.hg/mm/page_alloc.c
---- linux-2.6.18/mm/page_alloc.c       2007-12-23 11:26:51.300135824 +0100
-+++ linux-2.6.18-xen.hg/mm/page_alloc.c        2007-12-23 11:15:46.761936217 +0100
+--- linux-2.6.18.8/mm/mprotect.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/mm/mprotect.c  2008-05-19 00:34:29.305293797 +0300
+@@ -76,6 +76,8 @@
+               next = pmd_addr_end(addr, end);
+               if (pmd_none_or_clear_bad(pmd))
+                       continue;
++              if (arch_change_pte_range(mm, pmd, addr, next, newprot))
++                      continue;
+               change_pte_range(mm, pmd, addr, next, newprot);
+       } while (pmd++, addr = next, addr != end);
+ }
+--- linux-2.6.18.8/mm/page_alloc.c     2008-05-19 00:42:34.413259487 +0300
++++ linux-2.6.18-xen.hg/mm/page_alloc.c        2008-05-19 00:34:29.317294489 +0300
 @@ -154,7 +154,11 @@
                        1 << PG_slab    |
                        1 << PG_swapcache |
@@ -138219,9 +204104,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/mm/page_alloc.c linux-2.
        arch_free_page(page, 0);
  
        if (PageAnon(page))
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/bridge/br_netfilter.c linux-2.6.18-xen.hg/net/bridge/br_netfilter.c
---- linux-2.6.18/net/bridge/br_netfilter.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/net/bridge/br_netfilter.c      2007-12-23 11:15:47.175291252 +0100
+--- linux-2.6.18.8/net/bridge/br_netfilter.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/net/bridge/br_netfilter.c      2008-05-19 00:34:29.813323081 +0300
 @@ -127,10 +127,10 @@
  
  static inline void nf_bridge_save_header(struct sk_buff *skb)
@@ -138235,9 +204119,27 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/bridge/br_netfilter.
  
        memcpy(skb->nf_bridge->data, skb->data - header_size, header_size);
  }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/core/dev.c linux-2.6.18-xen.hg/net/core/dev.c
---- linux-2.6.18/net/core/dev.c        2007-12-23 11:26:51.306802839 +0100
-+++ linux-2.6.18-xen.hg/net/core/dev.c 2007-12-23 11:15:47.228627387 +0100
+--- linux-2.6.18.8/net/bridge/netfilter/ebtables.c     2008-05-19 00:42:34.441261101 +0300
++++ linux-2.6.18-xen.hg/net/bridge/netfilter/ebtables.c        2008-05-19 00:34:29.889327462 +0300
+@@ -597,7 +597,7 @@
+       struct ebt_entry_target *t;
+       struct ebt_target *target;
+       unsigned int i, j, hook = 0, hookmask = 0;
+-      size_t gap = e->next_offset - e->target_offset;
++      size_t gap;
+       int ret;
+       /* don't mess with the struct ebt_entries */
+@@ -647,6 +647,7 @@
+       if (ret != 0)
+               goto cleanup_watchers;
+       t = (struct ebt_entry_target *)(((char *)e) + e->target_offset);
++      gap = e->next_offset - e->target_offset;
+       target = find_target_lock(t->u.name, &ret, &ebt_mutex);
+       if (!target)
+               goto cleanup_watchers;
+--- linux-2.6.18.8/net/core/dev.c      2008-05-19 00:42:34.441261101 +0300
++++ linux-2.6.18-xen.hg/net/core/dev.c 2008-05-19 00:34:29.897327923 +0300
 @@ -113,11 +113,18 @@
  #include <linux/wireless.h>
  #include <net/iw_handler.h>
@@ -138342,9 +204244,18 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/core/dev.c linux-2.6
  
  #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
  EXPORT_SYMBOL(br_handle_frame_hook);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/core/skbuff.c linux-2.6.18-xen.hg/net/core/skbuff.c
---- linux-2.6.18/net/core/skbuff.c     2007-12-23 11:26:51.306802839 +0100
-+++ linux-2.6.18-xen.hg/net/core/skbuff.c      2007-12-23 11:15:47.238627923 +0100
+--- linux-2.6.18.8/net/core/neighbour.c        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/net/core/neighbour.c   2008-05-19 00:34:29.905328384 +0300
+@@ -2679,7 +2679,6 @@
+ EXPORT_SYMBOL(neigh_table_init);
+ EXPORT_SYMBOL(neigh_table_init_no_netlink);
+ EXPORT_SYMBOL(neigh_update);
+-EXPORT_SYMBOL(neigh_update_hhs);
+ EXPORT_SYMBOL(pneigh_enqueue);
+ EXPORT_SYMBOL(pneigh_lookup);
+ EXPORT_SYMBOL(neightbl_dump_info);
+--- linux-2.6.18.8/net/core/skbuff.c   2008-05-19 00:42:34.441261101 +0300
++++ linux-2.6.18-xen.hg/net/core/skbuff.c      2008-05-19 00:34:29.921329306 +0300
 @@ -240,6 +240,7 @@
        skb_shinfo(skb)->gso_size = 0;
        skb_shinfo(skb)->gso_segs = 0;
@@ -138364,9 +204275,16 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/core/skbuff.c linux-
        C(pkt_type);
        C(ip_summed);
        C(priority);
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/ipv4/netfilter/ip_nat_proto_tcp.c linux-2.6.18-xen.hg/net/ipv4/netfilter/ip_nat_proto_tcp.c
---- linux-2.6.18/net/ipv4/netfilter/ip_nat_proto_tcp.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/net/ipv4/netfilter/ip_nat_proto_tcp.c  2007-12-23 11:15:47.355300712 +0100
+@@ -2071,7 +2076,6 @@
+ EXPORT_SYMBOL(pskb_expand_head);
+ EXPORT_SYMBOL(skb_checksum);
+ EXPORT_SYMBOL(skb_clone);
+-EXPORT_SYMBOL(skb_clone_fraglist);
+ EXPORT_SYMBOL(skb_copy);
+ EXPORT_SYMBOL(skb_copy_and_csum_bits);
+ EXPORT_SYMBOL(skb_copy_and_csum_dev);
+--- linux-2.6.18.8/net/ipv4/netfilter/ip_nat_proto_tcp.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/net/ipv4/netfilter/ip_nat_proto_tcp.c  2008-05-19 00:34:30.301351212 +0300
 @@ -129,6 +129,11 @@
        if (hdrsize < sizeof(*hdr))
                return 1;
@@ -138379,9 +204297,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/ipv4/netfilter/ip_na
        hdr->check = ip_nat_cheat_check(~oldip, newip,
                                        ip_nat_cheat_check(oldport ^ 0xFFFF,
                                                           newport,
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/ipv4/netfilter/ip_nat_proto_udp.c linux-2.6.18-xen.hg/net/ipv4/netfilter/ip_nat_proto_udp.c
---- linux-2.6.18/net/ipv4/netfilter/ip_nat_proto_udp.c 2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/net/ipv4/netfilter/ip_nat_proto_udp.c  2007-12-23 11:15:47.355300712 +0100
+--- linux-2.6.18.8/net/ipv4/netfilter/ip_nat_proto_udp.c       2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/net/ipv4/netfilter/ip_nat_proto_udp.c  2008-05-19 00:34:30.301351212 +0300
 @@ -113,11 +113,17 @@
                newport = tuple->dst.u.udp.port;
                portptr = &hdr->dest;
@@ -138401,9 +204318,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/ipv4/netfilter/ip_na
        *portptr = newport;
        return 1;
  }
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/ipv4/tcp_input.c linux-2.6.18-xen.hg/net/ipv4/tcp_input.c
---- linux-2.6.18/net/ipv4/tcp_input.c  2007-12-23 11:26:51.333470906 +0100
-+++ linux-2.6.18-xen.hg/net/ipv4/tcp_input.c   2007-12-23 11:15:47.401969829 +0100
+--- linux-2.6.18.8/net/ipv4/tcp_input.c        2008-05-19 00:42:34.461262254 +0300
++++ linux-2.6.18-xen.hg/net/ipv4/tcp_input.c   2008-05-19 00:34:30.357354440 +0300
 @@ -127,7 +127,7 @@
        /* skb->len may jitter because of SACKs, even if peer
         * sends good full-sized frames.
@@ -138413,9 +204329,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/ipv4/tcp_input.c lin
        if (len >= icsk->icsk_ack.rcv_mss) {
                icsk->icsk_ack.rcv_mss = len;
        } else {
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/ipv4/xfrm4_output.c linux-2.6.18-xen.hg/net/ipv4/xfrm4_output.c
---- linux-2.6.18/net/ipv4/xfrm4_output.c       2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/net/ipv4/xfrm4_output.c        2007-12-23 11:15:47.411970353 +0100
+--- linux-2.6.18.8/net/ipv4/xfrm4_output.c     2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/net/ipv4/xfrm4_output.c        2008-05-19 00:34:30.373355362 +0300
 @@ -18,6 +18,8 @@
  #include <net/xfrm.h>
  #include <net/icmp.h>
@@ -138436,9 +204351,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/net/ipv4/xfrm4_output.c
        if (skb->ip_summed == CHECKSUM_HW) {
                err = skb_checksum_help(skb, 0);
                if (err)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/scripts/Makefile.build linux-2.6.18-xen.hg/scripts/Makefile.build
---- linux-2.6.18/scripts/Makefile.build        2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/scripts/Makefile.build 2007-12-23 11:15:48.838711942 +0100
+--- linux-2.6.18.8/scripts/Makefile.build      2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/scripts/Makefile.build 2008-05-19 00:34:31.393414161 +0300
 @@ -68,6 +68,20 @@
  $(warning kbuild: Makefile.build is included improperly)
  endif
@@ -138460,9 +204374,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/scripts/Makefile.build l
  # ===========================================================================
  
  ifneq ($(strip $(lib-y) $(lib-m) $(lib-n) $(lib-)),)
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/scripts/Makefile.lib linux-2.6.18-xen.hg/scripts/Makefile.lib
---- linux-2.6.18/scripts/Makefile.lib  2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/scripts/Makefile.lib   2007-12-23 11:15:48.842045453 +0100
+--- linux-2.6.18.8/scripts/Makefile.lib        2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/scripts/Makefile.lib   2008-05-19 00:34:31.397414391 +0300
 @@ -13,6 +13,12 @@
  
  lib-y := $(filter-out $(obj-y), $(sort $(lib-y) $(lib-m)))
@@ -138476,9 +204389,8 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/scripts/Makefile.lib lin
  
  # Handle objects in subdirs
  # ---------------------------------------------------------------------------
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/scripts/Makefile.xen.awk linux-2.6.18-xen.hg/scripts/Makefile.xen.awk
---- linux-2.6.18/scripts/Makefile.xen.awk      1970-01-01 01:00:00.000000000 +0100
-+++ linux-2.6.18-xen.hg/scripts/Makefile.xen.awk       2007-12-23 11:15:48.842045453 +0100
+--- linux-2.6.18.8/scripts/Makefile.xen.awk    1970-01-01 03:00:00.000000000 +0300
++++ linux-2.6.18-xen.hg/scripts/Makefile.xen.awk       2008-05-19 00:34:31.397414391 +0300
 @@ -0,0 +1,34 @@
 +BEGIN {
 +      is_rule = 0
@@ -138514,23 +204426,25 @@ diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/scripts/Makefile.xen.awk
 +      print $0
 +      next
 +}
-diff -burN --exclude .hg --exclude .hgtags linux-2.6.18/sound/pci/hda/hda_intel.c linux-2.6.18-xen.hg/sound/pci/hda/hda_intel.c
---- linux-2.6.18/sound/pci/hda/hda_intel.c     2006-09-20 05:42:06.000000000 +0200
-+++ linux-2.6.18-xen.hg/sound/pci/hda/hda_intel.c      2007-12-23 11:15:52.298893641 +0100
-@@ -80,6 +80,7 @@
+--- linux-2.6.18.8/sound/pci/hda/hda_intel.c   2006-09-20 06:42:06.000000000 +0300
++++ linux-2.6.18-xen.hg/sound/pci/hda/hda_intel.c      2008-05-19 00:34:34.397587328 +0300
+@@ -80,6 +80,8 @@
                         "{Intel, ICH7},"
                         "{Intel, ESB2},"
                         "{Intel, ICH8},"
 +                       "{Intel, ICH9},"
++                       "{Intel, ICH10},"
                         "{ATI, SB450},"
                         "{ATI, SB600},"
                         "{ATI, RS600},"
-@@ -1634,6 +1635,8 @@
+@@ -1634,6 +1636,10 @@
        { 0x8086, 0x27d8, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH7 */
        { 0x8086, 0x269a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ESB2 */
        { 0x8086, 0x284b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH8 */
 +      { 0x8086, 0x293e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
 +      { 0x8086, 0x293f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH9 */
++      { 0x8086, 0x3a3e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */
++      { 0x8086, 0x3a6e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ICH }, /* ICH10 */
        { 0x1002, 0x437b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB450 */
        { 0x1002, 0x4383, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATI }, /* ATI SB600 */
        { 0x1002, 0x793b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, AZX_DRIVER_ATIHDMI }, /* ATI RS600 HDMI */
This page took 8.062676 seconds and 4 git commands to generate.