All of lore.kernel.org
 help / color / mirror / Atom feed
* [Xenomai-core] kernel threads crash
@ 2011-04-08 12:58 Jesper Christensen
  2011-04-08 13:12 ` Philippe Gerum
  2011-04-08 19:15 ` Richard Cochran
  0 siblings, 2 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-08 12:58 UTC (permalink / raw)
  To: xenomai

Hi

I'm trying to implement some gateway functionality in the kernel on a
emerson CPCI6200 board, but have run into some strange errors. The
kernel module is made up of two threads that run every 1 ms. I have also
made use of the rtpc dispatcher in rtnet to dispatch control messages
from a netlink socket to the RT part of my kernel module.

The problem is that when loaded the threads get suspended due to exceptions:

Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
after exception #1792

or

Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
exception #1025

or

Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
after exception #1792


I have ported the "gianfar" driver from linux to rtnet.

The versions and hardware are listed below. The errors are most likely
due to faulty software on my part, but i would like to ask if there are
any known issues with the versions or hardware i'm using. I would also
like to ask if there are any ways of further debugging the errors as i
am not getting very far with the above messages.



System info:

Linux kernel: 2.6.29.6
i-pipe version: 2.7-04
processor: powerpc mpc8572
xenomai version: 2.5.3
rtnet version: 0.9.12

-- 
/Jesper




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-08 12:58 [Xenomai-core] kernel threads crash Jesper Christensen
@ 2011-04-08 13:12 ` Philippe Gerum
  2011-04-08 13:20   ` Jesper Christensen
  2011-04-11 14:13   ` Jesper Christensen
  2011-04-08 19:15 ` Richard Cochran
  1 sibling, 2 replies; 42+ messages in thread
From: Philippe Gerum @ 2011-04-08 13:12 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
> Hi
> 
> I'm trying to implement some gateway functionality in the kernel on a
> emerson CPCI6200 board, but have run into some strange errors. The
> kernel module is made up of two threads that run every 1 ms. I have also
> made use of the rtpc dispatcher in rtnet to dispatch control messages
> from a netlink socket to the RT part of my kernel module.
> 
> The problem is that when loaded the threads get suspended due to exceptions:
> 
> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
> after exception #1792
> 
> or
> 
> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
> exception #1025
> 
> or
> 
> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
> after exception #1792
> 
> 
> I have ported the "gianfar" driver from linux to rtnet.
> 
> The versions and hardware are listed below. The errors are most likely
> due to faulty software on my part, but i would like to ask if there are
> any known issues with the versions or hardware i'm using. I would also
> like to ask if there are any ways of further debugging the errors as i
> am not getting very far with the above messages.

A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
which would cause exactly the kind of weird behavior you are seeing
right now. The bug triggered random code execution due to stack memory
pollution at init on powerpc for Xenomai kthreads:
http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47

You need at the very least those three patches (from the top of my
head), but it would be much better to upgrade to 2.5.6.

> 
> 
> 
> System info:
> 
> Linux kernel: 2.6.29.6
> i-pipe version: 2.7-04
> processor: powerpc mpc8572
> xenomai version: 2.5.3
> rtnet version: 0.9.12
> 

-- 
Philippe.




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-08 13:12 ` Philippe Gerum
@ 2011-04-08 13:20   ` Jesper Christensen
  2011-04-08 13:39     ` Philippe Gerum
  2011-04-11 14:13   ` Jesper Christensen
  1 sibling, 1 reply; 42+ messages in thread
From: Jesper Christensen @ 2011-04-08 13:20 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai

Thanks i'll give 2.5.6 a shot.

Also it has come to my attention that there is some source files
(arch/powerpc/platforms/85xx/cpci6200.c,
arch/powerpc/platforms/85xx/cpci6200.h,
arch/powerpc/platforms/85xx/cpci6200_timer.c) that are probably not
covered by the adeos patch. Am i correct in assuming these need some
work to support i-pipe?

/Jesper


On 2011-04-08 15:12, Philippe Gerum wrote:
> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
>   
>> Hi
>>
>> I'm trying to implement some gateway functionality in the kernel on a
>> emerson CPCI6200 board, but have run into some strange errors. The
>> kernel module is made up of two threads that run every 1 ms. I have also
>> made use of the rtpc dispatcher in rtnet to dispatch control messages
>> from a netlink socket to the RT part of my kernel module.
>>
>> The problem is that when loaded the threads get suspended due to exceptions:
>>
>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
>> after exception #1792
>>
>> or
>>
>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
>> exception #1025
>>
>> or
>>
>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
>> after exception #1792
>>
>>
>> I have ported the "gianfar" driver from linux to rtnet.
>>
>> The versions and hardware are listed below. The errors are most likely
>> due to faulty software on my part, but i would like to ask if there are
>> any known issues with the versions or hardware i'm using. I would also
>> like to ask if there are any ways of further debugging the errors as i
>> am not getting very far with the above messages.
>>     
> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
> which would cause exactly the kind of weird behavior you are seeing
> right now. The bug triggered random code execution due to stack memory
> pollution at init on powerpc for Xenomai kthreads:
> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
>
> You need at the very least those three patches (from the top of my
> head), but it would be much better to upgrade to 2.5.6.
>
>   
>>
>>
>> System info:
>>
>> Linux kernel: 2.6.29.6
>> i-pipe version: 2.7-04
>> processor: powerpc mpc8572
>> xenomai version: 2.5.3
>> rtnet version: 0.9.12
>>
>>     
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-08 13:20   ` Jesper Christensen
@ 2011-04-08 13:39     ` Philippe Gerum
  2011-04-08 13:47       ` Jesper Christensen
  2011-04-08 14:33       ` Jesper Christensen
  0 siblings, 2 replies; 42+ messages in thread
From: Philippe Gerum @ 2011-04-08 13:39 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On Fri, 2011-04-08 at 15:20 +0200, Jesper Christensen wrote:
> Thanks i'll give 2.5.6 a shot.
> 
> Also it has come to my attention that there is some source files
> (arch/powerpc/platforms/85xx/cpci6200.c,
> arch/powerpc/platforms/85xx/cpci6200.h,
> arch/powerpc/platforms/85xx/cpci6200_timer.c) that are probably not
> covered by the adeos patch. Am i correct in assuming these need some
> work to support i-pipe?
> 

I can't tell since I have no access to them, this is probably not a
mainline port.

In any case, if any of those files implements the support for the
programmable interrupt controller, hw timer, gpios and/or any form of
cascaded interrupt handling, this is correct: they should be made I-pipe
aware.

> /Jesper
> 
> 
> On 2011-04-08 15:12, Philippe Gerum wrote:
> > On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
> >   
> >> Hi
> >>
> >> I'm trying to implement some gateway functionality in the kernel on a
> >> emerson CPCI6200 board, but have run into some strange errors. The
> >> kernel module is made up of two threads that run every 1 ms. I have also
> >> made use of the rtpc dispatcher in rtnet to dispatch control messages
> >> from a netlink socket to the RT part of my kernel module.
> >>
> >> The problem is that when loaded the threads get suspended due to exceptions:
> >>
> >> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
> >> after exception #1792
> >>
> >> or
> >>
> >> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
> >> exception #1025
> >>
> >> or
> >>
> >> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
> >> after exception #1792
> >>
> >>
> >> I have ported the "gianfar" driver from linux to rtnet.
> >>
> >> The versions and hardware are listed below. The errors are most likely
> >> due to faulty software on my part, but i would like to ask if there are
> >> any known issues with the versions or hardware i'm using. I would also
> >> like to ask if there are any ways of further debugging the errors as i
> >> am not getting very far with the above messages.
> >>     
> > A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
> > which would cause exactly the kind of weird behavior you are seeing
> > right now. The bug triggered random code execution due to stack memory
> > pollution at init on powerpc for Xenomai kthreads:
> > http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
> > http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
> > http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
> >
> > You need at the very least those three patches (from the top of my
> > head), but it would be much better to upgrade to 2.5.6.
> >
> >   
> >>
> >>
> >> System info:
> >>
> >> Linux kernel: 2.6.29.6
> >> i-pipe version: 2.7-04
> >> processor: powerpc mpc8572
> >> xenomai version: 2.5.3
> >> rtnet version: 0.9.12
> >>
> >>     
> >   
> 

-- 
Philippe.




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-08 13:39     ` Philippe Gerum
@ 2011-04-08 13:47       ` Jesper Christensen
  2011-04-08 14:33       ` Jesper Christensen
  1 sibling, 0 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-08 13:47 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai

[-- Attachment #1: Type: text/plain, Size: 3212 bytes --]

Just in case ;)

/Jesper


On 2011-04-08 15:39, Philippe Gerum wrote:
> On Fri, 2011-04-08 at 15:20 +0200, Jesper Christensen wrote:
>   
>> Thanks i'll give 2.5.6 a shot.
>>
>> Also it has come to my attention that there is some source files
>> (arch/powerpc/platforms/85xx/cpci6200.c,
>> arch/powerpc/platforms/85xx/cpci6200.h,
>> arch/powerpc/platforms/85xx/cpci6200_timer.c) that are probably not
>> covered by the adeos patch. Am i correct in assuming these need some
>> work to support i-pipe?
>>
>>     
> I can't tell since I have no access to them, this is probably not a
> mainline port.
>
> In any case, if any of those files implements the support for the
> programmable interrupt controller, hw timer, gpios and/or any form of
> cascaded interrupt handling, this is correct: they should be made I-pipe
> aware.
>
>   
>> /Jesper
>>
>>
>> On 2011-04-08 15:12, Philippe Gerum wrote:
>>     
>>> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
>>>   
>>>       
>>>> Hi
>>>>
>>>> I'm trying to implement some gateway functionality in the kernel on a
>>>> emerson CPCI6200 board, but have run into some strange errors. The
>>>> kernel module is made up of two threads that run every 1 ms. I have also
>>>> made use of the rtpc dispatcher in rtnet to dispatch control messages
>>>> from a netlink socket to the RT part of my kernel module.
>>>>
>>>> The problem is that when loaded the threads get suspended due to exceptions:
>>>>
>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
>>>> after exception #1792
>>>>
>>>> or
>>>>
>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
>>>> exception #1025
>>>>
>>>> or
>>>>
>>>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
>>>> after exception #1792
>>>>
>>>>
>>>> I have ported the "gianfar" driver from linux to rtnet.
>>>>
>>>> The versions and hardware are listed below. The errors are most likely
>>>> due to faulty software on my part, but i would like to ask if there are
>>>> any known issues with the versions or hardware i'm using. I would also
>>>> like to ask if there are any ways of further debugging the errors as i
>>>> am not getting very far with the above messages.
>>>>     
>>>>         
>>> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
>>> which would cause exactly the kind of weird behavior you are seeing
>>> right now. The bug triggered random code execution due to stack memory
>>> pollution at init on powerpc for Xenomai kthreads:
>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
>>>
>>> You need at the very least those three patches (from the top of my
>>> head), but it would be much better to upgrade to 2.5.6.
>>>
>>>   
>>>       
>>>>
>>>> System info:
>>>>
>>>> Linux kernel: 2.6.29.6
>>>> i-pipe version: 2.7-04
>>>> processor: powerpc mpc8572
>>>> xenomai version: 2.5.3
>>>> rtnet version: 0.9.12
>>>>
>>>>     
>>>>         
>>>   
>>>       
>>     
>   

[-- Attachment #2: patch-2.6.29.6-emerson.rm02 --]
[-- Type: text/plain, Size: 1675670 bytes --]

diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/dts/cpci6200.dts linux-2.6.29.6.mod/arch/powerpc/boot/dts/cpci6200.dts
--- linux-2.6.29.6.orig/arch/powerpc/boot/dts/cpci6200.dts	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/dts/cpci6200.dts	2009-08-06 16:50:48.000000000 -0700
@@ -0,0 +1,486 @@
+/*
+ * CPCI6200 Device Tree Source
+ *
+ * Author; ajit.prem@emerson.com
+ *
+ * Copyright 2008 Emerson Network Power Embedded Computing Inc.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+/ {
+	model = "CPCI6200";
+	compatible = "CPCI6200";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+        aliases {
+                ethernet0 = &enet0;
+                ethernet1 = &enet1;
+                ethernet2 = &enet2;
+                ethernet3 = &enet3;
+                serial0 = &serial0;
+                serial1 = &serial1;
+                pci1 = &pci1;
+                pci2 = &pci2;
+        };
+
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,8572@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <32>;	// 32 bytes
+			i-cache-line-size = <32>;	// 32 bytes
+			d-cache-size = <0x8000>;		// L1=32K
+			i-cache-size = <0x8000>;		// L1=32K
+			timebase-frequency = <0>;	// from bootwrapper
+			bus-frequency = <0>;		// from bw
+			clock-frequency = <0>;		// from bootwrapper
+			next-level-cache = <&L2>;
+		};
+		PowerPC,8572@1 {
+			device_type = "cpu";
+			reg = <1>;
+			d-cache-line-size = <32>;	// 32 bytes
+			i-cache-line-size = <32>;	// 32 bytes
+			d-cache-size = <0x8000>;		// L1=32K
+			i-cache-size = <0x8000>;		// L1=32K
+			timebase-frequency = <0>;	// from bootwrapper
+			bus-frequency = <0>;		// from bw
+			clock-frequency = <0>;		// from bootwrapper
+			next-level-cache = <&L2>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x80000000>;	// 2 GB (fixed by bootwrapper)
+	};
+
+	soc8572@f1000000 {
+		device_type = "soc";
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		ranges = <0x0 0xf1000000 0x00100000>;
+		reg = <0xf1000000 0x00100000>;	
+		bus-frequency = <0>;	
+
+		memory-controller@2000 {
+                        compatible = "fsl,8572-memory-controller";
+			device_type = "memory-controller";
+			reg = <0x2000 0x1000>;
+			virtual-reg = <0xf1002000>;
+			interrupts = <0x12 2>;
+			interrupt-parent = <&soc8572_pic>;
+		};
+
+                memory-controller@6000 {
+                        compatible = "fsl,mpc8572-memory-controller";
+			device_type = "memory-controller";
+                        reg = <0x6000 0x1000>;
+			virtual-reg = <0xf1006000>;
+			interrupts = <0x12 2>;
+			interrupt-parent = <&soc8572_pic>;
+                };
+
+		L2: l2_cache-controller@20000 {
+                        compatible = "fsl,8572-l2-cache-controller";
+			device_type = "l2_cache-controller";
+			reg = <0x20000 0x1000>;
+			virtual-reg = <0xf1020000>;
+                        cache-line-size = <32>; // 32 bytes
+                        cache-size = <0x100000>;   // L2, 1MB
+			interrupts = <0x10 2>;
+			interrupt-parent = <&soc8572_pic>;
+		};
+
+		i2c@3000 {
+			cell-index = <0>;
+			compatible = "fsl-i2c";
+			device_type = "i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x3000 0x100>;
+			virtual-reg = <0xf1003000>;
+			dfsrr;
+
+                        rtc@68 {
+                                device_type = "rtc";
+                                compatible = "m41t82";
+                                reg = <0x68>;
+                                interrupts = <0x9 1>;
+                                interrupt-parent = <&soc8572_pic>;
+                        };
+		};
+	
+                i2c@3100 {
+                        cell-index = <1>;
+                        compatible = "fsl-i2c-ipmi";
+                        #address-cells = <1>;
+			device_type = "i2c";
+                        #size-cells = <0>;
+                        reg = <0x3100 0x100>;
+			virtual-reg = <0xf1003100>;
+                        dfsrr;
+                };
+
+                dma@c300 {
+                        #address-cells = <1>;
+                        #size-cells = <1>;
+                        compatible = "fsl,mpc8572-dma", "fsl,eloplus-dma";
+                        reg = <0xc300 0x4>;
+                        ranges = <0x0 0xc100 0x200>;
+                        cell-index = <1>;
+                        dma-channel@0 {
+                                compatible = "fsl,mpc8572-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x0 0x80>;
+                                cell-index = <0>;
+				interrupt-parent = <&soc8572_pic>;
+                                interrupts = <76 2>;
+                        };
+                        dma-channel@80 {
+                                compatible = "fsl,mpc8572-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x80 0x80>;
+                                cell-index = <1>;
+				interrupt-parent = <&soc8572_pic>;
+                                interrupts = <77 2>;
+                        };
+                        dma-channel@100 {
+                                compatible = "fsl,mpc8572-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x100 0x80>;
+                                cell-index = <2>;
+				interrupt-parent = <&soc8572_pic>;
+                                interrupts = <78 2>;
+                        };
+                        dma-channel@180 {
+                                compatible = "fsl,mpc8572-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x180 0x80>;
+                                cell-index = <3>;
+				interrupt-parent = <&soc8572_pic>;
+                                interrupts = <79 2>;
+                        };
+                };
+
+                dma@21300 {
+                        #address-cells = <1>;
+                        #size-cells = <1>;
+                        compatible = "fsl,mpc8572-dma", "fsl,eloplus-dma";
+                        reg = <0x21300 0x4>;
+                        ranges = <0x0 0x21100 0x200>;
+                        cell-index = <0>;
+                        dma-channel@0 {
+                                compatible = "fsl,mpc8572-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x0 0x80>;
+                                cell-index = <0>;
+				interrupt-parent = <&soc8572_pic>;
+                                interrupts = <20 2>;
+                        };
+                        dma-channel@80 {
+                                compatible = "fsl,mpc8572-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x80 0x80>;
+                                cell-index = <1>;
+				interrupt-parent = <&soc8572_pic>;
+                                interrupts = <21 2>;
+                        };
+                        dma-channel@100 {
+                                compatible = "fsl,mpc8572-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x100 0x80>;
+                                cell-index = <2>;
+				interrupt-parent = <&soc8572_pic>;
+                                interrupts = <22 2>;
+                        };
+                        dma-channel@180 {
+                                compatible = "fsl,mpc8572-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x180 0x80>;
+                                cell-index = <3>;
+				interrupt-parent = <&soc8572_pic>;
+                                interrupts = <23 2>;
+                        };
+                };
+
+		mdio@24520 {
+			compatible = "fsl,gianfar-mdio";
+                        cell-index = <0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";
+			reg = <0x24520 0x20>;
+
+			phy0_1: ethernet-phy@1 {
+				compatible = "broadcom,bcm5482";
+				device_type = "ethernet-phy";
+				interrupt-parent = <&soc8572_pic>;
+				interrupts = <0xa 1>;
+				reg = <1>;
+			};
+
+			phy0_2: ethernet-phy@2 {
+				compatible = "broadcom,bcm5482";
+				device_type = "ethernet-phy";
+				interrupt-parent = <&soc8572_pic>;
+				interrupts = <0xa 1>;
+				reg = <2>;
+			};
+		};
+
+		mdio@26520 {
+			compatible = "fsl,gianfar-mdio";
+                        cell-index = <1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";
+			reg = <0x26520 0x20>;
+
+			phy1_3: ethernet-phy@3 {
+				compatible = "broadcom,bcm5482";
+				device_type = "ethernet-phy";
+				interrupt-parent = <&soc8572_pic>;
+				interrupts = <0xa 1>;
+				reg = <3>;
+			};
+
+			phy1_4: ethernet-phy@4 {
+				compatible = "broadcom,bcm5482";
+				device_type = "ethernet-phy";
+				interrupt-parent = <&soc8572_pic>;
+				interrupts = <0xa 1>;
+				reg = <4>;
+			};
+		};
+
+		enet0: ethernet@24000 { /* MAC addresses set by bootwrapper */
+			cell-index = <0>;
+			compatible = "gianfar";
+			device_type = "network";
+			model = "eTSEC";
+			reg = <0x24000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <0x1d 2 0x1e 2 0x22 2>;
+			interrupt-parent = <&soc8572_pic>;
+			phy-handle = <&phy0_1>;
+                        phy-connection-type = "rgmii-id";
+		};
+
+		enet1: ethernet@25000 {
+			cell-index = <1>;
+			compatible = "gianfar";
+			device_type = "network";
+			model = "eTSEC";
+			reg = <0x25000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <0x23 2 0x24 2 0x28 2>;
+			interrupt-parent = <&soc8572_pic>;
+			phy-handle = <&phy0_2>;
+                        phy-connection-type = "rgmii-id";
+		};
+
+		enet2: ethernet@26000 {
+			cell-index = <2>;
+			compatible = "gianfar";
+			device_type = "network";
+			model = "eTSEC";
+			reg = <0x26000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+                        interrupts = <0x1f 2 0x20 2 0x21 2>;
+			interrupt-parent = <&soc8572_pic>;
+                        phy-handle = <&phy1_3>;
+                        phy-connection-type = "rgmii-id";
+                };
+
+                enet3: ethernet@27000 {
+                        cell-index = <3>;
+                        compatible = "gianfar";
+                        device_type = "network";
+                        model = "eTSEC";
+                        reg = <0x27000 0x1000>;
+                        local-mac-address = [ 00 00 00 00 00 00 ];
+                        interrupts = <0x25 2 0x26 2 0x27 2>;
+			interrupt-parent = <&soc8572_pic>;
+                        phy-handle = <&phy1_4>;
+                        phy-connection-type = "rgmii-id";
+                };
+
+		serial0: serial@4500 {
+                        cell-index = <0>;
+			compatible = "ns16550";
+			device_type = "serial";
+			reg = <0x4500 0x100>; 	
+			virtual-reg = <0xf1004500>;
+			clock-frequency = <0>; 	
+			current-speed = <9600>;  
+			interrupts = <0x2a 2>;
+			interrupt-parent = <&soc8572_pic>;
+		};
+
+		serial1: serial@4600 {
+                        cell-index = <1>;
+			compatible = "ns16550";
+			device_type = "serial";
+			reg = <0x4600 0x100>; 	
+			virtual-reg = <0xf1004500>;
+			clock-frequency = <0>; 	
+			current-speed = <9600>;  
+			interrupts = <0x2a 2>;
+			interrupt-parent = <&soc8572_pic>;
+		};
+
+                global-utilities@e0000 {        //global utilities reg
+                        compatible = "fsl,mpc8572-guts";
+                        reg = <0xe0000 0x1000>;
+                        fsl,has-rstcr;
+                };
+
+                crypto@30000 {
+                        compatible = "fsl,sec3.0", "fsl,sec2.4", "fsl,sec2.2",
+                                     "fsl,sec2.1", "fsl,sec2.0";
+                        reg = <0x30000 0x10000>;
+                        interrupts = <45 2 58 2>;
+			interrupt-parent = <&soc8572_pic>;
+                        fsl,num-channels = <4>;
+                        fsl,channel-fifo-len = <24>;
+                        fsl,exec-units-mask = <0x9fe>;
+                        fsl,descriptor-types-mask = <0x3ab0ebf>;
+                };
+
+		soc8572_pic: pic@40000 {
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <0x40000 0x40000>;
+			big-endian;
+		};
+	};
+
+        pci1: pci@f1009000 {
+		cell-index = <0>;
+		compatible = "fsl,mpc8548-pcie";
+		device_type = "pci";
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = <0xf1009000 0x1000>;
+		bus-range = <0x0 0xff>;
+                ranges = <0x02000000 0x0 0xf0400000 0xf0400000 0x0 0x00400000
+                          0x01000000 0x0 0x00000000 0xf0000000 0x0 0x00400000>;
+		clock-frequency = <0>;
+		interrupts = <0x19 2>;
+		interrupt-parent = <&soc8572_pic>;
+		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+                interrupt-map = <
+                        /* IDSEL 0x0 */
+                        0x0000 0 0 1 &soc8572_pic 4 1
+                        0x0000 0 0 2 &soc8572_pic 5 1
+                        0x0000 0 0 3 &soc8572_pic 6 1
+                        0x0000 0 0 4 &soc8572_pic 7 1>;
+		pcie@0 {
+                        reg = <0 0 0 0 0>;
+                        #size-cells = <2>;
+                        #address-cells = <3>;
+                        device_type = "pci";
+                        ranges = <0x02000000 0x0 0xf0400000
+                                  0x02000000 0x0 0xf0400000
+                                  0x0 0x00400000
+
+                                  0x01000000 0x0 0x00000000
+                                  0x01000000 0x0 0x00000000
+                                  0x0 0x00400000>;
+                };
+	};
+
+        pci2: pci@f100a000 {
+                cell-index = <2>;
+                compatible = "fsl,mpc8548-pcie";
+                device_type = "pci";
+                #interrupt-cells = <1>;
+                #size-cells = <2>;
+                #address-cells = <3>;
+                reg = <0xf100a000 0x1000>;
+                bus-range = <0x0 0xff>;
+		ranges = <0x02000000 0 0xe0000000 0xe0000000 0x0 0x08000000
+			  0x42000000 0 0xe8000000 0xe8000000 0x0 0x08000000
+			  0x01000000 0 0x00000000 0xf0800000 0x0 0x00800000>;
+                clock-frequency = <0>;
+		interrupt-parent = <&soc8572_pic>;
+                interrupts = <0x1a 2>;
+                interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+                interrupt-map = <
+                        /* IDSEL 0x0 */
+                        0x0000 0 0 1 &soc8572_pic 0 1
+                        0x0000 0 0 2 &soc8572_pic 1 1
+                        0x0000 0 0 3 &soc8572_pic 2 1
+                        0x0000 0 0 4 &soc8572_pic 3 1>;
+		pcie@0 {
+                        reg = <0 0 0 0 0>;
+                        #size-cells = <2>;
+                        #address-cells = <3>;
+                        device_type = "pci";
+                        ranges = <0x02000000 0x0 0xe0000000
+                                  0x02000000 0x0 0xe0000000
+                                  0x0 0x08000000
+
+				  0x42000000 0x0 0xe8000000
+				  0x42000000 0x0 0xe8000000
+				  0x0 0x08000000
+
+                                  0x01000000 0x0 0x00000000
+                                  0x01000000 0x0 0x00000000
+                                  0x0 0x00800000>;
+                };
+	};
+
+	board_timers@f2020000 {
+		device_type = "board_timers";
+		reg = <0xf2020000 0x4c>;
+		interrupts = <0xb 1>;
+		interrupt-parent = <&soc8572_pic>;
+	};
+	
+	serial@f2013000 {
+		device_type = "serial";
+		compatible = "ns16550";
+		reg = <0xf2013000 0x100>; 
+		virtual-reg = <0xf2013000>;
+		clock-frequency = <10000000>; 	
+		current-speed = <9600>;  
+		interrupts = <0xb 1>;
+		interrupt-parent = <&soc8572_pic>;
+	};
+
+	serial@f2014000 {
+		device_type = "serial";
+		compatible = "ns16550";
+		reg = <0xf2014000 0x100>; 
+		virtual-reg = <0xf2014000>;
+		clock-frequency = <10000000>; 	
+		current-speed = <9600>;  
+		interrupts = <0xb 1>;
+		interrupt-parent = <&soc8572_pic>;
+	};
+
+	chosen {
+		bootargs = "root=/dev/sda2 console=ttyS0,9600";
+		linux,stdout-path = "/soc8572@f1000000/serial@4500";
+	};
+};
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/dts/mvme3100.dts linux-2.6.29.6.mod/arch/powerpc/boot/dts/mvme3100.dts
--- linux-2.6.29.6.orig/arch/powerpc/boot/dts/mvme3100.dts	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/dts/mvme3100.dts	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,360 @@
+/*
+ * MVME3100 Device Tree Source
+ *
+ * Author; ajit.prem@emerson.com
+ *
+ * Copyright 2008-2009 Emerson Network Power Embedded Computing Inc.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+/ {
+	model = "MVME3100";
+	compatible = "MVME3100";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+        aliases {
+                ethernet0 = &enet0;
+                ethernet1 = &enet1;
+                ethernet2 = &enet2;
+                serial0 = &serial0;
+                pci0 = &pci0;
+        };
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,8540@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <32>;	// 32 bytes
+			i-cache-line-size = <32>;	// 32 bytes
+			d-cache-size = <32768>;		// L1=32K
+			i-cache-size = <32768>;		// L1=32K
+			timebase-frequency = <0>;	// from bootwrapper
+			bus-frequency = <0>;		// 333 MHz, from bw
+			clock-frequency = <0>;		// from bootwrapper
+                        next-level-cache = <&L2>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <00000000 0x10000000>;	// 256M (fixed by bootwrapper)
+	};
+
+	soc8540@e1000000 {
+		device_type = "soc";
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		ranges = <0 0xe1000000 0x00100000>;
+		reg = <0xe1000000 0x00100000>;	
+		bus-frequency = <0>;		// 333 MHz
+
+		memory-controller@2000 {
+                        compatible = "fsl,8540-memory-controller";
+			device_type = "memory-controller";
+			reg = <0x2000 0x1000>;
+			virtual-reg = <0xe1002000>;
+			interrupts = <0x12 2>;
+			interrupt-parent = <&soc8540_pic>;
+		};
+
+		L2: l2_cache-controller@20000 {
+                        compatible = "fsl,8540-l2-cache-controller";
+			device_type = "l2_cache-controller";
+			reg = <0x20000 0x1000>;
+			virtual-reg = <0xe1020000>;
+                        cache-line-size = <32>; // 32 bytes
+                        cache-size = <0x40000>;   // L2, 256K
+			interrupts = <0x10 2>;
+			interrupt-parent = <&soc8540_pic>;
+		};
+
+		i2c@3000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <0>;
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <0x3000 0x100>;
+			virtual-reg = <0xe1003000>;
+			interrupts = <0x2b 2>;
+			interrupt-parent = <&soc8540_pic>;
+			dfsrr;
+
+			thermostat@4c {
+				compatible = "ds1621";
+				device_type = "thermostat";
+				reg = <0x4c>;
+				parent = "/soc8540@e1000000/i2c@3000";
+				interrupts = <0x9 1>;
+				interrupt-parent = <&soc8540_pic>;
+			};
+		};
+	
+		mdio@24520 {
+			compatible = "fsl,gianfar-mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";
+			reg = <0x24520 0x20>;
+
+			phy1: ethernet-phy@1 {
+				device_type = "ethernet-phy";
+				compatible = "broadcom,bcm5461";
+				interrupt-parent = <&soc8540_pic>;
+				interrupts = <0xa 1>;
+				reg = <1>;
+			};
+
+			phy2: ethernet-phy@2 {
+				device_type = "ethernet-phy";
+				compatible = "broadcom,bcm5461";
+				interrupt-parent = <&soc8540_pic>;
+				interrupts = <0xa 1>;
+				reg = <2>;
+			};
+
+			phy3: ethernet-phy@3 {
+				device_type = "ethernet-phy";
+				compatible = "broadcom,bcm5421";
+				interrupt-parent = <&soc8540_pic>;
+				interrupts = <0xa 1>;
+				reg = <3>;
+			};
+		};
+
+		enet0: ethernet@24000 { /* MAC addresses set by bootwrapper */
+			cell-index = <0>;
+			compatible = "gianfar";
+			device_type = "network";
+			model = "TSEC";
+			reg = <0x24000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <0x1d 2 0x1e 2 0x22 2>;
+			interrupt-parent = <&soc8540_pic>;
+			phy-handle = <&phy1>;
+		};
+
+		enet1: ethernet@25000 {
+			cell-index = <1>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <0x25000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <0x23 2 0x24 2 0x28 2>;
+			interrupt-parent = <&soc8540_pic>;
+			phy-handle = <&phy2>;
+		};
+
+		enet2: ethernet@26000 {
+			cell-index = <2>;
+			device_type = "network";
+			model = "FEC";
+			compatible = "gianfar";
+			reg = <0x26000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <0x29 2>;
+			interrupt-parent = <&soc8540_pic>;
+			phy-handle = <&phy3>;
+		};
+
+                dma@21300 {
+                        #address-cells = <1>;
+                        #size-cells = <1>;
+                        compatible = "fsl,mpc8540-dma", "fsl,eloplus-dma";
+                        reg = <0x21300 0x4>;
+                        ranges = <0x0 0x21100 0x200>;
+                        cell-index = <0>;
+                        dma-channel@0 {
+                                compatible = "fsl,mpc8540-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x0 0x80>;
+                                cell-index = <0>;
+				interrupt-parent = <&soc8540_pic>;
+                                interrupts = <0x14 2>;
+                        };
+                        dma-channel@80 {
+                                compatible = "fsl,mpc8540-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x80 0x80>;
+                                cell-index = <1>;
+				interrupt-parent = <&soc8540_pic>;
+                                interrupts = <0x15 2>;
+                        };
+                        dma-channel@100 {
+                                compatible = "fsl,mpc8540-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x100 0x80>;
+                                cell-index = <2>;
+				interrupt-parent = <&soc8540_pic>;
+                                interrupts = <0x16 2>;
+                        };
+                        dma-channel@180 {
+                                compatible = "fsl,mpc8540-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x180 0x80>;
+                                cell-index = <3>;
+				interrupt-parent = <&soc8540_pic>;
+                                interrupts = <0x17 2>;
+                        };
+                };
+
+		serial0: serial@4500 {
+                        cell-index = <0>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x4500 0x100>; 	
+			virtual-reg = <0xe1004500>;
+			clock-frequency = <0>; 	
+			current-speed = <9600>; 
+			interrupts = <0x2a 2>;
+			interrupt-parent = <&soc8540_pic>;
+		};
+
+		soc8540_pic: pic@40000 {
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <0x40000 0x40000>;
+			big-endian;
+		};
+	};
+
+	pci0: pci@e1008000 {
+                cell-index = <0>;
+		compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci";
+		device_type = "pci";
+		#address-cells = <3>;
+		#size-cells = <2>;
+		#interrupt-cells = <1>;
+		reg = <0xe1008000 0x1000>;
+		ranges = <0x02000000 0 0x80000000 0x80000000 0 0x60000000
+			  0x01000000 0 0x00000000 0xe0000000 0 0x01000000>;
+		bus-range = <0x0 0xff>;
+		clock-frequency = <0>;
+		interrupt-parent = <&soc8540_pic>;
+		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+		interrupt-map = <
+			/* IDSEL 0x01 */
+			0x0800 0 0 1 &soc8540_pic 0 1
+			0x0800 0 0 2 &soc8540_pic 1 1
+			0x0800 0 0 3 &soc8540_pic 2 1
+			0x0800 0 0 4 &soc8540_pic 3 1
+
+			/* IDSEL 0x02 */
+			0x1000 0 0 1 &soc8540_pic 4 1
+			0x1000 0 0 2 &soc8540_pic 5 1
+			0x1000 0 0 3 &soc8540_pic 6 1
+			0x1000 0 0 4 &soc8540_pic 7 1
+
+			/* IDSEL 0x03 */
+			0x1800 0 0 1 &soc8540_pic 4 1
+			0x1800 0 0 2 &soc8540_pic 5 1
+			0x1800 0 0 3 &soc8540_pic 6 1
+			0x1800 0 0 4 &soc8540_pic 7 1
+
+			/* IDSEL 0x04 */
+			0x2000 0 0 1 &soc8540_pic 2 1
+			0x2000 0 0 2 &soc8540_pic 2 1
+			0x2000 0 0 3 &soc8540_pic 2 1
+			0x2000 0 0 4 &soc8540_pic 2 1
+
+			/* IDSEL 0x11 */
+			0x8800 0 0 1 &soc8540_pic 0 1
+			0x8800 0 0 2 &soc8540_pic 1 1
+			0x8800 0 0 3 &soc8540_pic 2 1
+			0x8800 0 0 4 &soc8540_pic 3 1
+
+			/* IDSEL 0x12 */
+			0x9000 0 0 1 &soc8540_pic 4 1
+			0x9000 0 0 2 &soc8540_pic 5 1
+			0x9000 0 0 3 &soc8540_pic 6 1
+			0x9000 0 0 4 &soc8540_pic 7 1
+
+			/* IDSEL 0x13 */
+			0x9800 0 0 1 &soc8540_pic 4 1
+			0x9800 0 0 2 &soc8540_pic 5 1
+			0x9800 0 0 3 &soc8540_pic 6 1
+			0x9800 0 0 4 &soc8540_pic 7 1
+
+			/* IDSEL 0x14 */
+			0xa000 0 0 1 &soc8540_pic 2 1
+			0xa000 0 0 2 &soc8540_pic 2 1
+			0xa000 0 0 3 &soc8540_pic 2 1
+			0xa000 0 0 4 &soc8540_pic 2 1
+		>;
+		interrupts = <0x18 2>;
+	};
+
+	board_timers@e2020000 {
+		device_type = "board_timers";
+		reg = <0xe2020000 0x4c>;
+		interrupts = <0x1 1>;
+		interrupt-parent = <&soc8540_pic>;
+	};
+	
+	serial@e2011000 {
+		device_type = "serial";
+		compatible = "ns16550";
+		reg = <0xe2011000 0x100>; 
+		virtual-reg = <0xe2011000>;
+		clock-frequency = <0x1c2000>; 	
+		current-speed = <9600>;  
+		interrupts = <0x3 1>;
+		interrupt-parent = <&soc8540_pic>;
+	};
+
+	serial@e2012000 {
+		device_type = "serial";
+		compatible = "ns16550";
+		reg = <0xe2012000 0x100>; 
+		virtual-reg = <0xe2012000>;
+		clock-frequency = <0x1c2000>; 	
+		current-speed = <9600>;  
+		interrupts = <0x3 1>;
+		interrupt-parent = <&soc8540_pic>;
+	};
+
+	serial@e2013000 {
+		device_type = "serial";
+		compatible = "ns16550";
+		reg = <0xe2013000 0x100>; 
+		virtual-reg = <0xe2013000>;
+		clock-frequency = <0x1c2000>; 	
+		current-speed = <9600>;  
+		interrupts = <0x3 1>;
+		interrupt-parent = <&soc8540_pic>;
+	};
+
+	serial@e2014000 {
+		device_type = "serial";
+		compatible = "ns16550";
+		reg = <0xe2014000 0x100>; 
+		virtual-reg = <0xe2014000>;
+		clock-frequency = <0x1c2000>; 	
+		current-speed = <9600>;  
+		interrupts = <0x3 1>;
+		interrupt-parent = <&soc8540_pic>;
+	};
+
+	chosen {
+		name = "chosen";
+		bootargs = "root=/dev/ram0 ramdisk_size=64000 console=ttyS0,9600";
+		linux,stdout-path = "/soc8540@e1000000/serial@4500";
+	};
+};
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/dts/mvme4100.dts linux-2.6.29.6.mod/arch/powerpc/boot/dts/mvme4100.dts
--- linux-2.6.29.6.orig/arch/powerpc/boot/dts/mvme4100.dts	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/dts/mvme4100.dts	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,437 @@
+/*
+ * MVME4100 Device Tree Source
+ *
+ * Author; ajit.prem@emerson.com
+ *
+ * Copyright 2008 Emerson Network Power Embedded Computing Inc.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+/ {
+	model = "MVME4100";
+	compatible = "MVME4100";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+        aliases {
+                ethernet0 = &enet0;
+                ethernet1 = &enet1;
+                ethernet2 = &enet2;
+                ethernet3 = &enet3;
+                serial0 = &serial0;
+                pci0 = &pci0;
+                pci2 = &pci2;
+        };
+
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,8548@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <32>;	// 32 bytes
+			i-cache-line-size = <32>;	// 32 bytes
+			d-cache-size = <32768>;		// L1=32K
+			i-cache-size = <32768>;		// L1=32K
+			timebase-frequency = <0>;	// from bootwrapper
+			bus-frequency = <0>;		// from bw
+			clock-frequency = <0>;		// from bootwrapper
+			next-level-cache = <&L2>;
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x40000000>;	// 1 GB (fixed by bootwrapper)
+	};
+
+	soc8548@f1000000 {
+		device_type = "soc";
+		compatible = "simple-bus";
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#interrupt-cells = <2>;
+		ranges = <0x0 0xf1000000 0x00100000>;
+		reg = <0xf1000000 0x00100000>;	
+		bus-frequency = <0>;	
+
+		memory-controller@2000 {
+                        compatible = "fsl,8548-memory-controller";
+			device_type = "memory-controller";
+			reg = <0x2000 0x1000>;
+			virtual-reg = <0xf1002000>;
+			interrupts = <0x12 2>;
+			interrupt-parent = <&soc8548_pic>;
+		};
+
+		L2: l2_cache-controller@20000 {
+                        compatible = "fsl,8548-l2-cache-controller";
+			device_type = "l2_cache-controller";
+			reg = <0x20000 0x1000>;
+			virtual-reg = <0xf1020000>;
+                        cache-line-size = <32>; // 32 bytes
+                        cache-size = <524288>;   // L2, 512K
+			interrupts = <0x10 2>;
+			interrupt-parent = <&soc8548_pic>;
+		};
+
+		i2c@3000 {
+			cell-index = <0>;
+			compatible = "fsl-i2c";
+			device_type = "i2c";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <0x3000 0x100>;
+			virtual-reg = <0xf1003000>;
+			interrupts = <0x2b 2>;
+			interrupt-parent = <&soc8548_pic>;
+			dfsrr;
+
+			thermostat@4c {
+                                compatible = "adt7461", "lm90";
+				device_type = "thermostat";
+				reg = <0x4c>;
+				parent = "/soc8548@f1000000/i2c@3000";
+				interrupts = <0x9 1>;
+				interrupt-parent = <&soc8548_pic>;
+			};
+
+		};
+	
+                i2c@3100 {
+                        cell-index = <1>;
+                        compatible = "fsl-i2c";
+                        #address-cells = <1>;
+                        #size-cells = <0>;
+                        reg = <0x3100 0x100>;
+			virtual-reg = <0xf1003100>;
+                        interrupts = <0x2b 2>;
+			interrupt-parent = <&soc8548_pic>;
+                        dfsrr;
+                };
+
+                dma@21300 {
+                        #address-cells = <1>;
+                        #size-cells = <1>;
+                        compatible = "fsl,mpc8548-dma", "fsl,eloplus-dma";
+                        reg = <0x21300 0x4>;
+                        ranges = <0x0 0x21100 0x200>;
+                        cell-index = <0>;
+                        dma-channel@0 {
+                                compatible = "fsl,mpc8548-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x0 0x80>;
+                                cell-index = <0>;
+				interrupt-parent = <&soc8548_pic>;
+                                interrupts = <20 2>;
+                        };
+                        dma-channel@80 {
+                                compatible = "fsl,mpc8548-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x80 0x80>;
+                                cell-index = <1>;
+				interrupt-parent = <&soc8548_pic>;
+                                interrupts = <21 2>;
+                        };
+                        dma-channel@100 {
+                                compatible = "fsl,mpc8548-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x100 0x80>;
+                                cell-index = <2>;
+				interrupt-parent = <&soc8548_pic>;
+                                interrupts = <22 2>;
+                        };
+                        dma-channel@180 {
+                                compatible = "fsl,mpc8548-dma-channel",
+                                                "fsl,eloplus-dma-channel";
+                                reg = <0x180 0x80>;
+                                cell-index = <3>;
+				interrupt-parent = <&soc8548_pic>;
+                                interrupts = <23 2>;
+                        };
+                };
+
+		mdio@24520 {
+			compatible = "fsl,gianfar-mdio";
+			#address-cells = <1>;
+			#size-cells = <0>;
+			device_type = "mdio";
+			reg = <0x24520 0x20>;
+
+			phy0: ethernet-phy@1 {
+				compatible = "broadcom,bcm5482";
+				device_type = "ethernet-phy";
+				interrupt-parent = <&soc8548_pic>;
+				interrupts = <0xa 1>;
+				reg = <1>;
+			};
+
+			phy1: ethernet-phy@2 {
+				compatible = "broadcom,bcm5482";
+				device_type = "ethernet-phy";
+				interrupt-parent = <&soc8548_pic>;
+				interrupts = <0xa 1>;
+				reg = <2>;
+			};
+
+			phy2: ethernet-phy@3 {
+				compatible = "broadcom,bcm5482";
+				device_type = "ethernet-phy";
+				interrupt-parent = <&soc8548_pic>;
+				interrupts = <0xa 1>;
+				reg = <3>;
+			};
+
+			phy3: ethernet-phy@4 {
+				compatible = "broadcom,bcm5482";
+				device_type = "ethernet-phy";
+				interrupt-parent = <&soc8548_pic>;
+				interrupts = <0xa 1>;
+				reg = <4>;
+			};
+		};
+
+		enet0: ethernet@24000 { /* MAC addresses set by bootwrapper */
+			cell-index = <0>;
+			compatible = "gianfar";
+			device_type = "network";
+			model = "eTSEC";
+			reg = <0x24000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <0x1d 2 0x1e 2 0x22 2>;
+			interrupt-parent = <&soc8548_pic>;
+			phy-handle = <&phy0>;
+		};
+
+		enet1: ethernet@25000 {
+			cell-index = <1>;
+			compatible = "gianfar";
+			device_type = "network";
+			model = "eTSEC";
+			reg = <0x25000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <0x23 2 0x24 2 0x28 2>;
+			interrupt-parent = <&soc8548_pic>;
+			phy-handle = <&phy1>;
+		};
+
+		enet2: ethernet@26000 {
+			cell-index = <2>;
+			compatible = "gianfar";
+			device_type = "network";
+			model = "eTSEC";
+			reg = <0x26000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+                        interrupts = <0x1f 2 0x20 2 0x21 2>;
+			interrupt-parent = <&soc8548_pic>;
+                        phy-handle = <&phy2>;
+                };
+
+                enet3: ethernet@27000 {
+                        cell-index = <3>;
+                        compatible = "gianfar";
+                        device_type = "network";
+                        model = "eTSEC";
+                        reg = <0x27000 0x1000>;
+                        local-mac-address = [ 00 00 00 00 00 00 ];
+                        interrupts = <0x25 2 0x26 2 0x27 2>;
+			interrupt-parent = <&soc8548_pic>;
+                        phy-handle = <&phy3>;
+                };
+
+		serial0: serial@4500 {
+                        cell-index = <0>;
+			compatible = "ns16550";
+			device_type = "serial";
+			reg = <0x4500 0x100>; 	
+			virtual-reg = <0xf1004500>;
+			clock-frequency = <0>; 	
+			current-speed = <9600>;  
+			interrupts = <0x2a 2>;
+			interrupt-parent = <&soc8548_pic>;
+		};
+
+                global-utilities@e0000 {        //global utilities reg
+                        compatible = "fsl,mpc8548-guts";
+                        reg = <0xe0000 0x1000>;
+                        fsl,has-rstcr;
+                };
+
+                crypto@30000 {
+                        compatible = "fsl,sec2.1", "fsl,sec2.0";
+                        reg = <0x30000 0x10000>;
+                        interrupts = <45 2>;
+			interrupt-parent = <&soc8548_pic>;
+                        fsl,num-channels = <4>;
+                        fsl,channel-fifo-len = <24>;
+                        fsl,exec-units-mask = <0xfe>;
+                        fsl,descriptor-types-mask = <0x12b0ebf>;
+                };
+
+		soc8548_pic: pic@40000 {
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <0x40000 0x40000>;
+			big-endian;
+		};
+	};
+
+        pci0: pci@f1008000 {
+		cell-index = <0>;
+		compatible = "fsl,mpc8540-pcix", "fsl,mpc8540-pci";
+		device_type = "pci";
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = <0xf1008000 0x1000>;
+		bus-range = <0x0 0xff>;
+		ranges = <0x02000000 0 0x80000000 0x80000000 0x0 0x10000000
+			  0x42000000 0 0x90000000 0x90000000 0x0 0x40000000
+			  0x01000000 0 0x00000000 0xf0000000 0x0 0x00800000>;
+		clock-frequency = <0>;
+		interrupts = <0x18 2>;
+		interrupt-parent = <&soc8548_pic>;
+		interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+		interrupt-map = <
+			/* IDSEL 0x01  TSI148  PCI-X */
+			0x0800 0 0 1 &soc8548_pic 0 1
+			0x0800 0 0 2 &soc8548_pic 1 1
+			0x0800 0 0 3 &soc8548_pic 2 1
+			0x0800 0 0 4 &soc8548_pic 3 1
+
+			/* IDSEL 0x02  PCI6520-1 */
+			0x1000 0 0 1 &soc8548_pic 4 1
+			0x1000 0 0 2 &soc8548_pic 5 1
+			0x1000 0 0 3 &soc8548_pic 6 1
+			0x1000 0 0 4 &soc8548_pic 7 1
+
+			/* IDSEL 0x03  PCI6520-2 */
+			0x1800 0 0 1 &soc8548_pic 4 1
+			0x1800 0 0 2 &soc8548_pic 5 1
+			0x1800 0 0 3 &soc8548_pic 6 1
+			0x1800 0 0 4 &soc8548_pic 7 1
+
+			/* IDSEL 0x11  TSI148  PCI */
+			0x8800 0 0 1 &soc8548_pic 0 1
+			0x8800 0 0 2 &soc8548_pic 1 1
+			0x8800 0 0 3 &soc8548_pic 2 1
+			0x8800 0 0 4 &soc8548_pic 3 1
+
+			/* IDSEL 0x12  PCI6520-1 */
+			0x9000 0 0 1 &soc8548_pic 4 1
+			0x9000 0 0 2 &soc8548_pic 5 1
+			0x9000 0 0 3 &soc8548_pic 6 1
+			0x9000 0 0 4 &soc8548_pic 7 1
+
+			/* IDSEL 0x13 PCI6520-2 */
+			0x9800 0 0 1 &soc8548_pic 4 1
+			0x9800 0 0 2 &soc8548_pic 5 1
+			0x9800 0 0 3 &soc8548_pic 6 1
+			0x9800 0 0 4 &soc8548_pic 7 1
+		>;
+	};
+
+        pci2: pci@f100a000 {
+                cell-index = <2>;
+                compatible = "fsl,mpc8548-pcie";
+                device_type = "pci";
+                #interrupt-cells = <1>;
+                #size-cells = <2>;
+                #address-cells = <3>;
+                reg = <0xf100a000 0x1000>;
+                bus-range = <0x0 0xff>;
+                ranges = <0x02000000 0x0 0xd0000000 0xd0000000 0x0 0x08000000
+                          0x01000000 0x0 0x00000000 0xf0800000 0x0 0x00800000>;
+                clock-frequency = <0>;
+		interrupt-parent = <&soc8548_pic>;
+                interrupts = <0x19 2>;
+                interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+                interrupt-map = <
+                        /* IDSEL 0x0 */
+                        0x0000 0 0 1 &soc8548_pic 0 1
+                        0x0000 0 0 2 &soc8548_pic 1 1
+                        0x0000 0 0 3 &soc8548_pic 2 1
+                        0x0000 0 0 4 &soc8548_pic 3 1>;
+		pcie@0 {
+                        reg = <0 0 0 0 0>;
+                        #size-cells = <2>;
+                        #address-cells = <3>;
+                        device_type = "pci";
+                        ranges = <0x02000000 0x0 0xd0000000
+                                  0x02000000 0x0 0xd0000000
+                                  0x0 0x08000000
+
+                                  0x01000000 0x0 0x00000000
+                                  0x01000000 0x0 0x00000000
+                                  0x0 0x00800000>;
+                };
+	};
+
+	board_timers@f2020000 {
+		device_type = "board_timers";
+		reg = <0xf2020000 0x4c>;
+		interrupts = <0xb 1>;
+		interrupt-parent = <&soc8548_pic>;
+	};
+	
+	serial@f2011000 {
+		device_type = "serial";
+		compatible = "ns16550";
+		reg = <0xf2011000 0x100>; 
+		virtual-reg = <0xf2011000>;
+		clock-frequency = <0x1c2000>; 	
+		current-speed = <9600>;  
+		interrupts = <0xb 1>;
+		interrupt-parent = <&soc8548_pic>;
+	};
+
+	serial@f2012000 {
+		device_type = "serial";
+		compatible = "ns16550";
+		reg = <0xf2012000 0x100>; 
+		virtual-reg = <0xf2012000>;
+		clock-frequency = <0x1c2000>; 	
+		current-speed = <9600>;  
+		interrupts = <0xb 1>;
+		interrupt-parent = <&soc8548_pic>;
+	};
+
+	serial@f2013000 {
+		device_type = "serial";
+		compatible = "ns16550";
+		reg = <0xf2013000 0x100>; 
+		virtual-reg = <0xf2013000>;
+		clock-frequency = <0x1c2000>; 	
+		current-speed = <9600>;  
+		interrupts = <0xb 1>;
+		interrupt-parent = <&soc8548_pic>;
+	};
+
+	serial@f2014000 {
+		device_type = "serial";
+		compatible = "ns16550";
+		reg = <0xf2014000 0x100>; 
+		virtual-reg = <0xf2014000>;
+		clock-frequency = <0x1c2000>; 	
+		current-speed = <9600>;  
+		interrupts = <0xb 1>;
+		interrupt-parent = <&soc8548_pic>;
+	};
+
+	chosen {
+		bootargs = "root=/dev/sda2 console=ttyS0,9600";
+		linux,stdout-path = "/soc8548@f1000000/serial@4500";
+	};
+};
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/dts/mvme7100.dts linux-2.6.29.6.mod/arch/powerpc/boot/dts/mvme7100.dts
--- linux-2.6.29.6.orig/arch/powerpc/boot/dts/mvme7100.dts	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/dts/mvme7100.dts	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,461 @@
+/*
+ * MVME7100 Device Tree Source
+ *
+ * Author: Ajit Prem (Ajit.Prem@emerson.com)
+ *
+ * Copyright 2008 Emerson Network Power Embedded Computing Inc.
+ *
+ * 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.
+ */
+
+
+/dts-v1/;
+
+/ {
+	model = "MVME7100";
+	compatible = "emerson,mvme7100";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+        aliases {
+                ethernet0 = &enet0;
+                ethernet1 = &enet1;
+                ethernet2 = &enet2;
+                ethernet3 = &enet3;
+                serial0 = &serial0;
+                pci0 = &pci0;
+                pci1 = &pci1;
+        };
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		PowerPC,8641@0 {
+			device_type = "cpu";
+			reg = <0>;
+			d-cache-line-size = <32>;	// 32 bytes
+			i-cache-line-size = <32>;	// 32 bytes
+			d-cache-size = <32786>;		// L1, 32K
+			i-cache-size = <32768>;		// L1, 32K
+			timebase-frequency = <0>;	// from bootwrapper
+			bus-frequency = <0>;	// 533 MHz, from bw
+			clock-frequency = <0>;	// 1333 MHz, from bw
+		};
+		PowerPC,8641@1 {
+			device_type = "cpu";
+			reg = <1>;
+			d-cache-line-size = <32>;	// 32 bytes
+			i-cache-line-size = <32>;	// 32 bytes
+			d-cache-size = <32768>;		// L1, 32K
+			i-cache-size = <32768>;		// L1, 32K
+			timebase-frequency = <0>;	// from bootwrapper
+			bus-frequency = <0>;	// 533 MHz. from bw
+			clock-frequency = <0>;	// 1333 MHz, from bw
+		};
+	};
+
+	memory {
+		device_type = "memory";
+		reg = <0x00000000 0x80000000>;	// 2G at 0x0
+	};
+
+        localbus@f1005000 {
+                #address-cells = <2>;
+                #size-cells = <1>;
+                compatible = "fsl,mpc8641-localbus", "simple-bus";
+                reg = <0xf1005000 0x1000>;
+                interrupts = <19 2>;
+                interrupt-parent = <&mpic>;
+
+                ranges = <0 0 0xf8000000 0x08000000>;
+
+                flash@0,0 {
+                        compatible = "cfi-flash";
+                        reg = <0 0 0x08000000>;
+                        bank-width = <2>;
+                        device-width = <2>;
+                        #address-cells = <1>;
+                        #size-cells = <1>;
+                        partition@0 {
+                                label = "kernel";
+                                reg = <0x00000000 0x02000000>;
+                        };
+                        partition@2000000 {
+                                label = "fs";
+                                reg = <0x02000000 0x05e00000>;
+                        };
+                        partition@7e00000 {
+                                label = "firmware b";
+                                reg = <0x07e00000 0x00100000>;
+                                read-only;
+                        };
+                        partition@7f00000 {
+                                label = "firmware a";
+                                reg = <0x07f00000 0x00100000>;
+                                read-only;
+                        };
+                };
+        };
+
+	soc8641@f1000000 {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		device_type = "soc";
+		compatible = "simple-bus";
+		ranges = <0x00000000 0xf1000000 0x00100000>;
+		reg = <0xf1000000 0x00001000>;	// CCSRBAR
+		bus-frequency = <0>;	// 533 MHz. from bw
+
+                memory-controller@2000 {
+                        compatible = "fsl,mpc8641-memory-controller";
+                        device_type = "memory-controller";
+                        reg = <0x2000 0xe60>;
+                        virtual-reg = <0xf1002000>;
+			interrupts = <18 2>;
+                        interrupt-parent = <&mpic>;
+                };
+
+                l2_cache@20000 {
+                        device_type = "l2_cache";
+                        reg = <0x20000 0xe60>;
+                        virtual-reg = <0xf1020000>;
+                        interrupts = <16 2>;
+                        interrupt-parent = <&mpic>;
+                };
+
+
+		i2c@3000 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <0>;
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <0x3000 0x100>;
+			virtual-reg = <0xf1003000>;
+			interrupts = <43 2>;
+			interrupt-parent = <&mpic>;
+			dfsrr;
+			thermostat@4c {
+				device_type = "thermostat";
+				compatible = "adt7461", "lm90";
+				reg = <0x4c>;
+                        	interrupts = <9 1>;
+                		interrupt-parent = <&mpic>;
+				};
+		};
+
+		i2c@3100 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			cell-index = <1>;
+			device_type = "i2c";
+			compatible = "fsl-i2c";
+			reg = <0x3100 0x100>;
+			virtual-reg = <0xf1003100>;
+			interrupts = <43 2>;
+			interrupt-parent = <&mpic>;
+			dfsrr;
+		};
+
+		mdio@24520 {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			compatible = "fsl,gianfar-mdio";
+			reg = <0x24520 0x20>;
+
+			phy0: ethernet-phy@0 {
+				device_type = "ethernet-phy";
+				compatible = "broadcom,bcm5482";
+				interrupt-parent = <&mpic>;
+				interrupts = <10 1>;
+				reg = <1>;
+			};
+			phy1: ethernet-phy@1 {
+				device_type = "ethernet-phy";
+				compatible = "broadcom,bcm5482";
+				interrupt-parent = <&mpic>;
+				interrupts = <10 1>;
+				reg = <2>;
+			};
+			phy2: ethernet-phy@2 {
+				device_type = "ethernet-phy";
+				compatible = "broadcom,bcm5482";
+				interrupt-parent = <&mpic>;
+				interrupts = <10 1>;
+				reg = <3>;
+			};
+			phy3: ethernet-phy@3 {
+				device_type = "ethernet-phy";
+				compatible = "broadcom,bcm5482";
+				interrupt-parent = <&mpic>;
+				interrupts = <10 1>;
+				reg = <4>;
+			};
+		};
+
+		enet0: ethernet@24000 {
+			cell-index = <0>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <0x24000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <29 2 30 2 34 2>;
+			interrupt-parent = <&mpic>;
+			phy-handle = <&phy0>;
+			phy-connection-type = "rgmii-id";
+		};
+
+		enet1: ethernet@25000 {
+			cell-index = <1>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <0x25000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <35 2 36 2 40 2>;
+			interrupt-parent = <&mpic>;
+			phy-handle = <&phy1>;
+			phy-connection-type = "rgmii-id";
+		};
+		
+		enet2: ethernet@26000 {
+			cell-index = <2>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <0x26000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <31 2 32 2 33 2>;
+			interrupt-parent = <&mpic>;
+			phy-handle = <&phy2>;
+			phy-connection-type = "rgmii-id";
+		};
+
+		enet3: ethernet@27000 {
+			cell-index = <3>;
+			device_type = "network";
+			model = "TSEC";
+			compatible = "gianfar";
+			reg = <0x27000 0x1000>;
+			local-mac-address = [ 00 00 00 00 00 00 ];
+			interrupts = <37 2 38 2 39 2>;
+			interrupt-parent = <&mpic>;
+			phy-handle = <&phy3>;
+			phy-connection-type = "rgmii-id";
+		};
+
+		serial0: serial@4500 {
+			cell-index = <0>;
+			device_type = "serial";
+			compatible = "ns16550";
+			reg = <0x4500 0x100>;
+			virtual-reg = <0xf1004500>;
+			clock-frequency = <0>;
+			current-speed = <9600>;
+			interrupts = <42 2>;
+			interrupt-parent = <&mpic>;
+		};
+
+		mpic: pic@40000 {
+			clock-frequency = <0>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			reg = <0x40000 0x40000>;
+			compatible = "chrp,open-pic";
+			device_type = "open-pic";
+                        big-endian;
+		};
+
+                global-utilities@e0000 {
+                        compatible = "fsl,mpc8641-guts";
+                        reg = <0xe0000 0x1000>;
+                        fsl,has-rstcr;
+                };
+
+		dma@21300 { 
+			#address-cells = <1>; 
+			#size-cells = <1>; 
+			compatible = "fsl,mpc8641-dma", "fsl,eloplus-dma"; 
+			reg = <0x21300 4>; 
+			cell-index = <0>;
+			ranges = <0 0x21100 0x200>; 
+			dma-channel@0 { 
+				compatible = "fsl,mpc8641-dma-channel",
+						"fsl,eloplus-dma-channel"; 
+				reg = <0 0x80>; 
+				cell-index = <0>;
+				interrupt-parent = <&mpic>; 
+				interrupts = <20 2>; 
+			}; 
+			dma-channel@80 { 
+				compatible = "fsl,mpc8641-dma-channel",
+						"fsl,eloplus-dma-channel"; 
+				reg = <0x80 0x80>; 
+				cell-index = <1>;
+				interrupt-parent = <&mpic>; 
+				interrupts = <21 2>; 
+			}; 
+			dma-channel@100 { 
+				compatible = "fsl,mpc8641-dma-channel",
+						"fsl,eloplus-dma-channel"; 
+				reg = <0x100 0x80>; 
+				cell-index = <2>;
+				interrupt-parent = <&mpic>; 
+				interrupts = <22 2>; 
+			}; 
+			dma-channel@180 { 
+				compatible = "fsl,mpc8641-dma-channel",
+						"fsl,eloplus-dma-channel"; 
+				reg = <0x180 0x80>; 
+				cell-index = <3>;
+				interrupt-parent = <&mpic>; 
+				interrupts = <23 2>; 
+			}; 
+		}; 
+        };
+
+	pci0: pcie@f1008000 {
+		cell-index = <0>;
+		compatible = "fsl,mpc8641-pcie";
+		device_type = "pci";
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = <0xf1008000 0x1000>;
+		bus-range = <0x0 0xff>;
+		ranges = <0x02000000 0x0 0x80000000 0x80000000 0x0 0x10000000
+			  0x42000000 0x0 0x90000000 0x90000000 0x0 0x40000000
+			  0x01000000 0x0 0x00000000 0xf0000000 0x0 0x00100000>;
+		clock-frequency = <0>;
+		interrupt-parent = <&mpic>;
+		interrupts = <24 2>;
+		interrupt-map-mask = <0xf800 0 0 7>;
+		interrupt-map = <
+			/* IDSEL 0x0 */
+			0x0000 0 0 1 &mpic 0 1
+			0x0000 0 0 2 &mpic 1 1
+			0x0000 0 0 3 &mpic 2 1
+			0x0000 0 0 4 &mpic 3 1
+			>;
+		pcie@0 {
+			reg = <0 0 0 0 0>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			ranges = <0x02000000 0x0 0x80000000
+			  	  0x02000000 0x0 0x80000000
+				  0x0 0x10000000
+
+				  0x42000000 0x0 0x90000000
+				  0x42000000 0x0 0x90000000
+				  0x0 0x40000000
+
+				  0x01000000 0x0 0x00000000
+				  0x01000000 0x0 0x00000000
+				  0x0 0x00100000>;
+		};
+	};
+
+	pci1: pcie@f1009000 {
+		cell-index = <1>;
+		compatible = "fsl,mpc8641-pcie";
+		device_type = "pci";
+		#interrupt-cells = <1>;
+		#size-cells = <2>;
+		#address-cells = <3>;
+		reg = <0xf1009000 0x1000>;
+		bus-range = <0 0xff>;
+		ranges = <0x02000000 0x0 0xd0000000 0xd0000000 0x0 0x10000000
+			  0x01000000 0x0 0x00000000 0xf0100000 0x0 0x00100000>;
+		clock-frequency = <0>;
+		interrupt-parent = <&mpic>;
+		interrupts = <25 2>;
+		interrupt-map-mask = <0xf800 0 0 7>;
+		interrupt-map = <
+			/* IDSEL 0x0 */
+			0x0000 0 0 1 &mpic 4 1
+			0x0000 0 0 2 &mpic 5 1
+			0x0000 0 0 3 &mpic 6 1
+			0x0000 0 0 4 &mpic 7 1
+			>;
+		pcie@0 {
+			reg = <0 0 0 0 0>;
+			#size-cells = <2>;
+			#address-cells = <3>;
+			device_type = "pci";
+			ranges = <0x02000000 0x0 0xd0000000
+			  	  0x02000000 0x0 0xd0000000
+				  0x0 0x10000000
+
+				  0x01000000 0x0 0x00000000
+				  0x01000000 0x0 0x00000000
+				  0x0 0x00100000>;
+		};
+	};
+
+        board_timers@f2020000 {
+                device_type = "board_timers";
+                reg = <0xf2020000 0x4c>;
+                interrupts = <11 1>;
+                interrupt-parent = <&mpic>;
+        };
+
+        serial@f2011000 {
+                device_type = "serial";
+                compatible = "ns16550";
+                reg = <0xf2011000 0x100>;
+                virtual-reg = <0xf2011000>;
+                clock-frequency = <0x1c2000>;
+                current-speed = <9600>;  // 9600=0x2580
+                interrupts = <11 1>;
+                interrupt-parent = <&mpic>;
+        };
+
+        serial@f2012000 {
+                device_type = "serial";
+                compatible = "ns16550";
+                reg = <0xf2012000 0x100>;
+                virtual-reg = <0xf2012000>;
+                clock-frequency = <0x1c2000>;
+                current-speed = <9600>;  // 9600=0x2580
+                interrupts = <11 1>;
+                interrupt-parent = <&mpic>;
+        };
+
+        serial@f2013000 {
+                device_type = "serial";
+                compatible = "ns16550";
+                reg = <0xf2013000 0x100>;
+                virtual-reg = <0xf2013000>;
+                clock-frequency = <0x1c2000>;
+                current-speed = <9600>;  // 9600=0x2580
+                interrupts = <11 1>;
+                interrupt-parent = <&mpic>;
+        };
+
+
+        serial@f2014000 {
+                device_type = "serial";
+                compatible = "ns16550";
+                reg = <0xf2014000 0x100>;
+                virtual-reg = <0xf2014000>;
+                clock-frequency = <0x1c2000>;
+                current-speed = <9600>;  // 9600=0x2580
+                interrupts = <11 1>;
+                interrupt-parent = <&mpic>;
+        };
+
+	chosen {
+		bootargs = "root=/dev/ram0 rw console=ttyS0,9600 ramdisk_size=64000";
+		linux,initrd-start =<00000000>; 
+		linux,initrd-end =<00000000>; 
+		linux,stdout-path = "/soc8641@f1000000/serial@4500";
+	};
+
+};
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/main.c linux-2.6.29.6.mod/arch/powerpc/boot/main.c
--- linux-2.6.29.6.orig/arch/powerpc/boot/main.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/main.c	2009-07-21 11:28:17.000000000 -0700
@@ -10,6 +10,7 @@
  */
 #include <stdarg.h>
 #include <stddef.h>
+#include "../../../include/linux/autoconf.h"
 #include "elf.h"
 #include "page.h"
 #include "string.h"
@@ -142,8 +143,16 @@
 static char cmdline[COMMAND_LINE_SIZE]
 	__attribute__((__section__("__builtin_cmdline")));
 
+#ifdef CONFIG_CMDLINE_BOOL
+static char compiled_string[COMMAND_LINE_SIZE] = CONFIG_CMDLINE;
+#endif
+
 static void prep_cmdline(void *chosen)
 {
+#ifdef CONFIG_CMDLINE_BOOL
+	memcpy (cmdline, compiled_string, COMMAND_LINE_SIZE);
+#endif
+
 	if (cmdline[0] == '\0')
 		getprop(chosen, "bootargs", cmdline, COMMAND_LINE_SIZE-1);
 
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/Makefile linux-2.6.29.6.mod/arch/powerpc/boot/Makefile
--- linux-2.6.29.6.orig/arch/powerpc/boot/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/Makefile	2009-08-13 14:12:55.000000000 -0700
@@ -60,7 +60,7 @@
 		gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
 		4xx.c ebony.c mv64x60.c mpsc.c mv64x60_i2c.c cuboot.c bamboo.c \
 		cpm-serial.c stdlib.c mpc52xx-psc.c planetcore.c uartlite.c \
-		fsl-soc.c mpc8xx.c pq2.c
+		fsl-soc.c mpc8xx.c pq2.c 
 src-plat := of.c cuboot-52xx.c cuboot-824x.c cuboot-83xx.c cuboot-85xx.c holly.c \
 		cuboot-ebony.c treeboot-ebony.c prpmc2800.c \
 		ps3-head.S ps3-hvcall.S ps3.c treeboot-bamboo.c cuboot-8xx.c \
@@ -70,7 +70,8 @@
 		cuboot-katmai.c cuboot-rainier.c redboot-8xx.c ep8248e.c \
 		cuboot-warp.c cuboot-85xx-cpm2.c cuboot-yosemite.c simpleboot.c \
 		virtex405-head.S virtex.c redboot-83xx.c cuboot-sam440ep.c \
-		cuboot-acadia.c
+		cuboot-acadia.c pplusboot-mvme3100.c pplusboot-mvme7100.c \
+		pplusboot-mvme4100.c pplusboot-cpci6200.c
 src-boot := $(src-wlib) $(src-plat) empty.c
 
 src-boot := $(addprefix $(obj)/, $(src-boot))
@@ -124,7 +125,7 @@
 $(obj)/wrapper.a: $(obj-wlib) FORCE
 	$(call if_changed,bootar)
 
-hostprogs-y	:= addnote addRamDisk hack-coff mktree dtc
+hostprogs-y	:= addnote addRamDisk hack-coff mktree dtc mkprep
 
 targets		+= $(patsubst $(obj)/%,%,$(obj-boot) wrapper.a)
 extra-y		:= $(obj)/wrapper.a $(obj-plat) $(obj)/empty.o \
@@ -133,7 +134,7 @@
 dtstree		:= $(srctree)/$(src)/dts
 
 wrapper		:=$(srctree)/$(src)/wrapper
-wrapperbits	:= $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree dtc) \
+wrapperbits	:= $(extra-y) $(addprefix $(obj)/,addnote hack-coff mktree mkprep dtc) \
 			$(wrapper) FORCE
 
 #############
@@ -227,6 +228,7 @@
 image-$(CONFIG_WARP)			+= cuImage.warp
 image-$(CONFIG_YOSEMITE)		+= cuImage.yosemite
 
+
 # Board ports in arch/powerpc/platform/8xx/Kconfig
 image-$(CONFIG_MPC86XADS)		+= cuImage.mpc866ads
 image-$(CONFIG_MPC885ADS)		+= cuImage.mpc885ads
@@ -268,6 +270,12 @@
 image-$(CONFIG_SBC8548)			+= cuImage.sbc8548
 image-$(CONFIG_SBC8560)			+= cuImage.sbc8560
 image-$(CONFIG_KSI8560)			+= cuImage.ksi8560
+image-$(CONFIG_MVME3100)		+= pplusImage.mvme3100
+image-$(CONFIG_MVME4100)		+= pplusImage.mvme4100
+image-$(CONFIG_CPCI6200)		+= pplusImage.cpci6200
+
+# Board ports in arch/powerpc/platform/86xx/Kconfig
+image-$(CONFIG_MVME7100)                += pplusImage.mvme7100
 
 # Board ports in arch/powerpc/platform/embedded6xx/Kconfig
 image-$(CONFIG_STORCENTER)		+= cuImage.storcenter
@@ -287,7 +295,8 @@
 initrd-y := $(patsubst zImage%, zImage.initrd%, \
 		$(patsubst dtbImage%, dtbImage.initrd%, \
 		$(patsubst simpleImage%, simpleImage.initrd%, \
-		$(patsubst treeImage%, treeImage.initrd%, $(image-y)))))
+		$(patsubst treeImage%, treeImage.initrd%, $(image-y)) \
+		$(patsubst pplusImage%, pplusImage.initrd%, $(image-y)))))
 initrd-y := $(filter-out $(image-y), $(initrd-y))
 targets	+= $(image-y) $(initrd-y)
 
@@ -341,6 +350,12 @@
 $(obj)/treeImage.%: vmlinux $(obj)/%.dtb $(wrapperbits)
 	$(call if_changed,wrap,treeboot-$*,,$(obj)/$*.dtb)
 
+$(obj)/pplusImage.initrd.%: vmlinux $(obj)/%.dtb $(wrapperbits)
+	$(call if_changed,wrap,pplusboot-$*,,$(obj)/$*.dtb,$(obj)/ramdisk.image.gz)
+
+$(obj)/pplusImage.%: vmlinux $(obj)/%.dtb $(wrapperbits)
+	$(call if_changed,wrap,pplusboot-$*,,$(obj)/$*.dtb)
+
 # Rule to build device tree blobs
 $(obj)/%.dtb: $(dtstree)/%.dts $(obj)/dtc
 	$(obj)/dtc -O dtb -o $(obj)/$*.dtb -b 0 $(DTS_FLAGS) $(dtstree)/$*.dts
@@ -362,7 +377,7 @@
 clean-files += $(image-) $(initrd-) cuImage.* dtbImage.* treeImage.* \
 	zImage zImage.initrd zImage.chrp zImage.coff zImage.holly \
 	zImage.iseries zImage.miboot zImage.pmac zImage.pseries \
-	otheros.bld *.dtb
+	otheros.bld *.dtb pplusImage.*
 
 # clean up files cached by wrapper
 clean-kernel := vmlinux.strip vmlinux.bin
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/mkprep.c linux-2.6.29.6.mod/arch/powerpc/boot/mkprep.c
--- linux-2.6.29.6.orig/arch/powerpc/boot/mkprep.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/mkprep.c	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,314 @@
+/*
+ * Makes a prep bootable image which can be dd'd onto
+ * a disk device to make a bootdisk.  Will take
+ * as input a elf executable, strip off the header
+ * and write out a boot image as:
+ * 1) default - strips elf header
+ *      suitable as a network boot image
+ * 2) -pbp - strips elf header and writes out prep boot partition image
+ *      cat or dd onto disk for booting
+ * 3) -asm - strips elf header and writes out as asm data
+ *      useful for generating data for a compressed image
+ *                  -- Cort
+ *
+ * Modified for x86 hosted builds by Matt Porter <porter@neta.com>
+ * Modified for Sparc hosted builds by Peter Wahl <PeterWahl@web.de>
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+
+/* size of read buffer */
+#define SIZE 0x1000
+
+/*
+ * Partition table entry
+ *  - from the PReP spec
+ */
+typedef struct partition_entry {
+	unsigned char boot_indicator;
+	unsigned char starting_head;
+	unsigned char starting_sector;
+	unsigned char starting_cylinder;
+
+	unsigned char system_indicator;
+	unsigned char ending_head;
+	unsigned char ending_sector;
+	unsigned char ending_cylinder;
+
+	unsigned char beginning_sector[4];
+	unsigned char number_of_sectors[4];
+} partition_entry_t;
+
+#define BootActive	0x80
+#define SystemPrep	0x41
+
+void copy_image(FILE *, FILE *);
+void write_prep_partition(FILE *, FILE *);
+void write_asm_data(FILE *, FILE *);
+
+unsigned int elfhdr_size = 65536;
+
+#define ROUNDUP(len)    (((len) + 3) & ~3)
+
+unsigned char buf[512];
+
+#define GET_16BE(off)   ((buf[off] << 8) + (buf[(off)+1]))
+#define GET_32BE(off)   ((GET_16BE(off) << 16) + GET_16BE((off)+2))
+
+#define PUT_16BE(off, v)        (buf[off] = ((v) >> 8) & 0xff, \
+                                 buf[(off) + 1] = (v) & 0xff)
+#define PUT_32BE(off, v)        (PUT_16BE((off), (v) >> 16), \
+                                 PUT_16BE((off) + 2, (v)))
+
+
+/* Structure of an ELF file */
+#define E_IDENT         0       /* ELF header */
+#define E_PHOFF         28
+#define E_PHENTSIZE     42
+#define E_PHNUM         44
+#define E_HSIZE         52      /* size of ELF header */
+
+#define EI_MAGIC        0       /* offsets in E_IDENT area */
+#define EI_CLASS        4
+#define EI_DATA         5
+
+#define PH_TYPE         0       /* ELF program header */
+#define PH_OFFSET       4
+#define PH_FILESZ       16
+#define PH_HSIZE        32      /* size of program header */
+
+#define PT_LOAD         1       /* Program header type = load */
+
+#define ELFCLASS32      1
+#define ELFDATA2MSB     2
+
+unsigned char elf_magic[4] = { 0x7f, 'E', 'L', 'F' };
+
+
+int main(int argc, char *argv[])
+{
+	FILE *in, *out;
+	int argptr = 1;
+	int prep = 0;
+	int fd, n;
+	int ph, ps, np;
+	int asmoutput = 0;
+
+	if (argc < 3 || argc > 4) {
+		fprintf(stderr, "usage: %s [-pbp] [-asm] <boot-file> <image>\n",
+			argv[0]);
+		exit(-1);
+	}
+
+/* needs to handle args more elegantly -- but this is a small/simple program */
+
+	/* check for -pbp */
+	if (!strcmp(argv[argptr], "-pbp")) {
+		prep = 1;
+		argptr++;
+	}
+
+	/* check for -asm */
+	if (!strcmp(argv[argptr], "-asm")) {
+		asmoutput = 1;
+		argptr++;
+	}
+
+	/* input file */
+	if (!strcmp(argv[argptr], "-"))
+		in = stdin;
+	else if (!(in = fopen(argv[argptr], "r")))
+		exit(-1);
+
+	fd = open(argv[argptr], O_RDWR);
+        if (fd < 0) {
+                perror(argv[argptr]);
+                exit(1);
+        }
+	argptr++;
+
+	/* output file */
+	if (!strcmp(argv[argptr], "-"))
+		out = stdout;
+	else if (!(out = fopen(argv[argptr], "w")))
+		exit(-1);
+	argptr++;
+
+       n = read(fd, buf, sizeof(buf));
+        if (n < 0) {
+                perror("read");
+                exit(-1);
+        }
+
+        if (n < E_HSIZE || memcmp(&buf[E_IDENT+EI_MAGIC], elf_magic, 4) != 0) {
+                fprintf(stderr, "Not an ELF file\n");
+                exit(-1);
+	}
+
+        ph = GET_32BE(E_PHOFF);
+        ps = GET_16BE(E_PHENTSIZE);
+        np = GET_16BE(E_PHNUM);
+
+        if (ph < E_HSIZE || ps < PH_HSIZE || np < 1) {
+                fprintf(stderr, "Error parsing ELF file\n");
+                exit(-1);
+	}
+
+        if (GET_32BE(ph + PH_TYPE) == PT_LOAD) {
+        	if (GET_32BE(ph + PH_OFFSET) == 0x40000) 
+			elfhdr_size = 0x40000;
+	}
+
+	/* skip elf header in input file */
+	/*if ( !prep )*/
+	fseek(in, elfhdr_size, SEEK_SET);
+
+	/* write prep partition if necessary */
+	if (prep)
+		write_prep_partition(in, out);
+
+	/* write input image to bootimage */
+	if (asmoutput)
+		write_asm_data(in, out);
+	else
+		copy_image(in, out);
+
+	return 0;
+}
+
+void store_le32(unsigned int v, unsigned char *p)
+{
+	p[0] = v;
+	p[1] = v >>= 8;
+	p[2] = v >>= 8;
+	p[3] = v >> 8;
+}
+
+void write_prep_partition(FILE *in, FILE *out)
+{
+	unsigned char block[512];
+	partition_entry_t pe;
+	unsigned char *entry  = block;
+	unsigned char *length = block + 4;
+	long pos = ftell(in), size;
+
+	if (fseek(in, 0, SEEK_END) < 0) {
+		fprintf(stderr,"info failed\n");
+		exit(-1);
+	}
+	size = ftell(in);
+	if (fseek(in, pos, SEEK_SET) < 0) {
+		fprintf(stderr,"info failed\n");
+		exit(-1);
+	}
+
+	memset(block, '\0', sizeof(block));
+
+	/* set entry point and boot image size skipping over elf header */
+	store_le32(0x400/*+65536*/, entry);
+	store_le32(size-elfhdr_size+0x400, length);
+
+	/* sets magic number for msdos partition (used by linux) */
+	block[510] = 0x55;
+	block[511] = 0xAA;
+
+	/*
+	* Build a "PReP" partition table entry in the boot record
+	*  - "PReP" may only look at the system_indicator
+	*/
+	pe.boot_indicator   = BootActive;
+	pe.system_indicator = SystemPrep;
+	/*
+	* The first block of the diskette is used by this "boot record" which
+	* actually contains the partition table. (The first block of the
+	* partition contains the boot image, but I digress...)  We'll set up
+	* one partition on the diskette and it shall contain the rest of the
+	* diskette.
+	*/
+	pe.starting_head     = 0;	/* zero-based			     */
+	pe.starting_sector   = 2;	/* one-based			     */
+	pe.starting_cylinder = 0;	/* zero-based			     */
+	pe.ending_head       = 1;	/* assumes two heads		     */
+	pe.ending_sector     = 18;	/* assumes 18 sectors/track	     */
+	pe.ending_cylinder   = 79;	/* assumes 80 cylinders/diskette     */
+
+	/*
+	* The "PReP" software ignores the above fields and just looks at
+	* the next two.
+	*   - size of the diskette is (assumed to be)
+	*     (2 tracks/cylinder)(18 sectors/tracks)(80 cylinders/diskette)
+	*   - unlike the above sector numbers, the beginning sector is zero-based!
+	*/
+#if 0
+	store_le32(1, pe.beginning_sector);
+#else
+	/* This has to be 0 on the PowerStack? */
+	store_le32(0, pe.beginning_sector);
+#endif
+
+	store_le32(2*18*80-1, pe.number_of_sectors);
+
+	memcpy(&block[0x1BE], &pe, sizeof(pe));
+
+	fwrite(block, sizeof(block), 1, out);
+	fwrite(entry, 4, 1, out);
+	fwrite(length, 4, 1, out);
+	/* set file position to 2nd sector where image will be written */
+	fseek( out, 0x400, SEEK_SET );
+}
+
+
+
+void copy_image(FILE *in, FILE *out)
+{
+	char buf[SIZE];
+	int n;
+
+	while ( (n = fread(buf, 1, SIZE, in)) > 0 )
+		fwrite(buf, 1, n, out);
+}
+
+
+void
+write_asm_data(FILE *in, FILE *out)
+{
+	int i, cnt, pos = 0;
+	unsigned int cksum = 0, val;
+	unsigned char *lp;
+	unsigned char buf[SIZE];
+	size_t len;
+
+	fputs("\t.data\n\t.globl input_data\ninput_data:\n", out);
+	while ((len = fread(buf, 1, sizeof(buf), in)) > 0) {
+		cnt = 0;
+		lp = buf;
+		/* Round up to longwords */
+		while (len & 3)
+			buf[len++] = '\0';
+		for (i = 0;  i < len;  i += 4) {
+			if (cnt == 0)
+				fputs("\t.long\t", out);
+			fprintf(out, "0x%02X%02X%02X%02X",
+				lp[0], lp[1], lp[2], lp[3]);
+			val = *(unsigned long *)lp;
+			cksum ^= val;
+			lp += 4;
+			if (++cnt == 4) {
+				cnt = 0;
+				fprintf(out, " # %x \n", pos+i-12);
+			} else {
+				fputs(",", out);
+			}
+		}
+		if (cnt)
+			fputs("0\n", out);
+		pos += len;
+	}
+	fprintf(out, "\t.globl input_len\ninput_len:\t.long\t0x%x\n", pos);
+	fprintf(stderr, "cksum = %x\n", cksum);
+}
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/ppcboot.h linux-2.6.29.6.mod/arch/powerpc/boot/ppcboot.h
--- linux-2.6.29.6.orig/arch/powerpc/boot/ppcboot.h	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/ppcboot.h	2009-07-21 11:28:17.000000000 -0700
@@ -43,10 +43,10 @@
 	unsigned long	bi_sramstart;	/* start of SRAM memory */
 	unsigned long	bi_sramsize;	/* size	 of SRAM memory */
 #if defined(TARGET_8xx) || defined(TARGET_CPM2) || defined(TARGET_85xx) ||\
-	defined(TARGET_83xx)
+	defined(TARGET_83xx) || defined(TARGET_MVME7100) || defined(TARGET_MVME3100) || defined(TARGET_MVME4100) || defined(TARGET_CPCI6200)
 	unsigned long	bi_immr_base;	/* base of IMMR register */
 #endif
-#if defined(TARGET_PPC_MPC52xx)
+#if defined(TARGET_PPC_MPC52xx) 
 	unsigned long   bi_mbar_base;   /* base of internal registers */
 #endif
 	unsigned long	bi_bootflags;	/* boot / reboot flag (for LynxOS) */
@@ -78,18 +78,18 @@
 	hymod_conf_t	bi_hymod_conf;	/* hymod configuration information */
 #endif
 #if defined(TARGET_EVB64260) || defined(TARGET_405EP) || defined(TARGET_44x) || \
-	defined(TARGET_85xx) ||	defined(TARGET_83xx) || defined(TARGET_HAS_ETH1)
+	defined(TARGET_85xx) ||	defined(TARGET_MVME7100) || defined(TARGET_MVME3100) || defined(TARGET_MVME4100) || defined(TARGET_CPCI6200) || defined(TARGET_83xx) || defined(TARGET_HAS_ETH1)
 	/* second onboard ethernet port */
 	unsigned char	bi_enet1addr[6];
 #define HAVE_ENET1ADDR
 #endif
 #if defined(TARGET_EVB64260) || defined(TARGET_440GX) || \
-    defined(TARGET_85xx) || defined(TARGET_HAS_ETH2)
+    defined(TARGET_85xx) || defined(TARGET_HAS_ETH2) || defined(TARGET_MVME7100) || defined(TARGET_MVME3100) || defined(TARGET_MVME4100) || defined(TARGET_CPCI6200)
 	/* third onboard ethernet ports */
 	unsigned char	bi_enet2addr[6];
 #define HAVE_ENET2ADDR
 #endif
-#if defined(TARGET_440GX) || defined(TARGET_HAS_ETH3)
+#if defined(TARGET_440GX) || defined(TARGET_HAS_ETH3) || defined(TARGET_MVME7100) || defined(TARGET_MVME4100) || defined(TARGET_CPCI6200)
 	/* fourth onboard ethernet ports */
 	unsigned char	bi_enet3addr[6];
 #define HAVE_ENET3ADDR
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/pplusboot-cpci6200.c linux-2.6.29.6.mod/arch/powerpc/boot/pplusboot-cpci6200.c
--- linux-2.6.29.6.orig/arch/powerpc/boot/pplusboot-cpci6200.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/pplusboot-cpci6200.c	2009-08-13 14:14:14.000000000 -0700
@@ -0,0 +1,232 @@
+/*
+ * Emerson Network Power Embedded Computing CPCI6200 bootwrapper code.
+ *
+ * Author: Ajit Prem <ajit.prem@emerson.com>
+ *
+ * Copyright 2008 Emerson Network Power Embedded Computing Inc.
+ *
+ * This file is licensed under the terms of the GNU 
+ * General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, 
+ * whether express or implied.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+#include "gunzip_util.h"
+
+#define TARGET_CPCI6200
+#include "ppcboot.h"
+
+extern char _end[];
+extern char _vmlinux_start[], _vmlinux_end[];
+extern char _dtb_start[], _dtb_end[];
+
+
+static unsigned char enet0_addr[6];
+static unsigned char enet1_addr[6];
+static unsigned char enet2_addr[6];
+static unsigned char enet3_addr[6];
+static bd_t bdinfo;
+
+#define KB	1024U
+#define MB	(KB*KB)
+
+#define EEPROM_ADDR	0xA8
+
+BSS_STACK(16 * KB);
+
+void cpci6200_reset(void)
+{
+        out_8((u8 *) 0xf2000001, 0xA0);
+
+	for (;;) 
+		;
+}
+
+static void cpci6200_fixups(void)
+{
+	void *devp;
+	u32 v[2];
+
+
+	/* Now fixup device tree properties */
+	/* Set /model appropriately */
+	devp = finddevice("/");
+	if (devp == NULL)
+		fatal("Error: Missing '/' device tree node\n\r");
+
+	/* Set /cpus/PowerPC,8572@0/clock-frequency */
+	devp = finddevice("/cpus/PowerPC,8572@0");
+	if (devp == NULL)
+		fatal("Error: Missing proper /cpus device tree node\n\r");
+
+	v[0] = bdinfo.bi_intfreq;
+	v[0] *= 1000000;
+	setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
+
+//	printf("Clock-frequency CPU 0 0x%x\n\r", v[0]);
+
+	v[0] = bdinfo.bi_busfreq;
+	v[0] *= 1000000;
+	setprop(devp, "bus-frequency", &v[0], sizeof(v[0]));
+
+//	printf("bus-frequency CPU0 0x%x\n\r", v[0]);
+
+	v[0] /= 8;
+	setprop(devp, "timebase-frequency", &v[0], sizeof(v[0]));
+
+//	printf("timebase-frequency CPU0 0x%x\n\r", v[0]);
+
+	devp = finddevice("/cpus/PowerPC,8572@1");
+	if (devp == NULL)
+		fatal("Error: Missing proper /cpus device tree node\n\r");
+
+	v[0] = bdinfo.bi_intfreq;
+	v[0] *= 1000000;
+	setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
+
+//	printf("Clock-frequency CPU 1 0x%x\n\r", v[0]);
+
+	v[0] = bdinfo.bi_busfreq;
+	v[0] *= 1000000;
+	setprop(devp, "bus-frequency", &v[0], sizeof(v[0]));
+
+//	printf("bus-frequency CPU 1 0x%x\n\r", v[0]);
+
+	v[0] /= 8;
+	setprop(devp, "timebase-frequency", &v[0], sizeof(v[0]));
+
+//	printf("timebase-frequency CPU1 0x%x\n\r", v[0]);
+
+	/* Set memory size */
+	devp = finddevice("/memory");
+	if (devp == NULL)
+		fatal("Error: Missing /memory device tree node\n\r");
+	v[0] = 0;
+	v[1] = bdinfo.bi_memsize;
+	setprop(devp, "reg", v, sizeof(v));
+
+//	printf("Memory Size 0x%x\n\r", v[1]);
+
+        devp = finddevice("/soc8572@f1000000");
+        if (devp == NULL)
+                fatal("Error: Missing soc8572 device tree node\n\r");
+        v[0] = bdinfo.bi_busfreq;
+        v[0] *= 1000000;
+        setprop(devp, "bus-frequency", &v[0], sizeof(v[0]));
+
+	devp = finddevice("/soc8572/serial@4500");
+	if (devp == NULL)
+		fatal("Error: Missing soc8572 serial device tree node 0\n\r");
+	v[0] = bdinfo.bi_busfreq;
+	v[0] *= 1000000;
+	setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
+
+	devp = finddevice("/soc8572/serial@4600");
+	if (devp == NULL)
+		fatal("Error: Missing soc8572 serial device tree node 1\n\r");
+	v[0] = bdinfo.bi_busfreq;
+	v[0] *= 1000000;
+	setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
+
+//	printf("serial-clock-frequency 0x%x\n\r", v[0]);
+
+	memcpy(enet0_addr, bdinfo.bi_enetaddr, 6);
+	memcpy(enet1_addr, bdinfo.bi_enet1addr, 6);
+	memcpy(enet2_addr, bdinfo.bi_enet2addr, 6);
+	memcpy(enet3_addr, bdinfo.bi_enet3addr, 6);
+
+	devp = finddevice("/soc8572/ethernet@24000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet0_addr[0], sizeof(enet0_addr));
+
+	devp = finddevice("/soc8572/ethernet@25000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet1_addr[0], sizeof(enet0_addr));
+
+	devp = finddevice("/soc8572/ethernet@26000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet2_addr[0], sizeof(enet0_addr));
+
+	devp = finddevice("/soc8572/ethernet@27000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet3_addr[0], sizeof(enet0_addr));
+}
+
+#define HEAP_SIZE	(16*MB)
+static struct gunzip_state gzstate;
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		   unsigned long r6, unsigned long r7)
+{
+	struct elf_info ei;
+	char *heap_start, *dtb;
+	int dt_size = _dtb_end - _dtb_start;
+	void *vmlinuz_addr = _vmlinux_start;
+	unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start;
+	char elfheader[256];
+	bd_t *bp = (bd_t *) r3;
+
+	memcpy(&bdinfo, bp, sizeof(bd_t));
+	if (dt_size <= 0) {	/* No fdt */
+		exit();
+	}
+
+	/*
+	 * Start heap after end of the kernel (after decompressed to
+	 * address 0) or the end of the zImage, whichever is higher.
+	 * That's so things allocated by simple_alloc won't overwrite
+	 * any part of the zImage and the kernel won't overwrite the dtb
+	 * when decompressed & relocated.
+	 */
+	gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size);
+	gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
+
+	if (!parse_elf32(elfheader, &ei))
+		exit();
+
+	heap_start = (char *)(ei.memsize + ei.elfoffset);/* end of kernel */
+	heap_start = max(heap_start, (char *)_end);	/* end of zImage */
+
+
+	if ((unsigned)simple_alloc_init(heap_start, HEAP_SIZE, 2 * KB, 16)
+	    > (128 * MB))
+		exit();
+
+	/* Relocate dtb to safe area past end of zImage & kernel */
+	dtb = malloc(dt_size);
+	if (!dtb)
+		exit();
+	memmove(dtb, _dtb_start, dt_size);
+	fdt_init(dtb);
+
+
+	platform_ops.fixups = cpci6200_fixups;
+	platform_ops.exit = cpci6200_reset;
+
+	if (serial_console_init() < 0)
+		exit();
+//	printf("offset 0x%x start 0x%x dtb 0x%x\n\r", ei.elfoffset, heap_start, dtb);
+}
+
+asm("	.globl _zimage_start\n\
+	_zimage_start:\n\
+		mfmsr   10\n\
+		rlwinm  10,10,0,~(1<<15)        /* Clear MSR_EE */\n\
+		sync\n\
+		mtmsr   10\n\
+		isync\n\
+		b _zimage_start_lib\n\
+");
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/pplusboot-mvme3100.c linux-2.6.29.6.mod/arch/powerpc/boot/pplusboot-mvme3100.c
--- linux-2.6.29.6.orig/arch/powerpc/boot/pplusboot-mvme3100.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/pplusboot-mvme3100.c	2009-08-13 14:14:37.000000000 -0700
@@ -0,0 +1,181 @@
+/*
+ * Emerson Network Power Embedded Computing  MVME3100 bootwrapper code.
+ *
+ * Author: Ajit Prem <ajit.prem@emerson.com>
+ *
+ * Copyright 2008 Emerson Network Power Embedded Computing Inc.
+ *
+ * This file is licensed under * the terms of the GNU 
+ * General Public License version 2.  This program
+ * is licensed "as is" without any warranty of any kind, 
+ * whether express or implied.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+#include "gunzip_util.h"
+
+#define TARGET_MVME3100
+#include "ppcboot.h"
+
+extern char _end[];
+extern char _vmlinux_start[], _vmlinux_end[];
+extern char _dtb_start[], _dtb_end[];
+
+static unsigned char enet0_addr[6];
+static unsigned char enet1_addr[6];
+static unsigned char enet2_addr[6];
+static bd_t bdinfo;
+
+#define KB	1024U
+#define MB	(KB*KB)
+
+#define EEPROM_ADDR	0xA8
+
+BSS_STACK(16 * KB);
+
+static void mvme3100_reset(void)
+{
+	out_8((u8 *) 0xf2000001, 0xA0);
+
+	for (;;) 
+		;
+}
+
+static void mvme3100_fixups(void)
+{
+	void *devp;
+	u32 v[2];
+
+	/* Now fixup device tree properties */
+	/* Set /model appropriately */
+	devp = finddevice("/");
+	if (devp == NULL)
+		fatal("Error: Missing '/' device tree node\n\r");
+
+	/* Set /cpus/PowerPC,8540/clock-frequency */
+	devp = finddevice("/cpus/PowerPC,8540");
+	if (devp == NULL)
+		fatal("Error: Missing proper /cpus device tree node\n\r");
+
+	v[0] = bdinfo.bi_intfreq;
+	v[0] *= 1000000;
+	setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
+//	printf("clock-frequency 0x%x\n\r", v[0]);
+
+	v[0] = bdinfo.bi_busfreq;
+	v[0] *= 1000000;
+	setprop(devp, "bus-frequency", &v[0], sizeof(v[0]));
+//	printf("bus-frequency 0x%x\n\r", v[0]);
+
+        v[0] /= 8;
+        setprop(devp, "timebase-frequency", &v[0], sizeof(v[0]));
+//	printf("timebase-frequency 0x%x\n\r", v[0]);
+
+	/* Set memory size */
+	devp = finddevice("/memory");
+	if (devp == NULL)
+		fatal("Error: Missing /memory device tree node\n\r");
+	v[0] = 0;
+	v[1] = bdinfo.bi_memsize;
+	setprop(devp, "reg", v, sizeof(v));
+//	printf("Memory Size 0x%x\n\r", v[1]);
+
+        devp = finddevice("/soc8540/serial@4500");
+        if (devp == NULL)
+                fatal("Error: Missing soc8540 serial device tree node\n\r");
+        v[0] = bdinfo.bi_busfreq;
+        v[0] *= 1000000;
+        setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
+//	printf("serial-clock-frequency 0x%x\n\r", v[0]);
+
+	memcpy(enet0_addr, bdinfo.bi_enetaddr, 6);
+	memcpy(enet1_addr, bdinfo.bi_enet1addr, 6);
+	memcpy(enet2_addr, bdinfo.bi_enet2addr, 6);
+
+	devp = finddevice("/soc8540/ethernet@24000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet0_addr[0], sizeof(enet0_addr));
+
+	devp = finddevice("/soc8540/ethernet@25000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet1_addr[0], sizeof(enet0_addr));
+
+	devp = finddevice("/soc8540/ethernet@26000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet2_addr[0], sizeof(enet0_addr));
+}
+
+#define HEAP_SIZE	(16*MB)
+static struct gunzip_state gzstate;
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		   unsigned long r6, unsigned long r7)
+{
+	struct elf_info ei;
+	char *heap_start, *dtb;
+	int dt_size = _dtb_end - _dtb_start;
+	void *vmlinuz_addr = _vmlinux_start;
+	unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start;
+	char elfheader[256];
+	bd_t *bp = (bd_t *) r3;
+
+	memcpy(&bdinfo, bp, sizeof(bd_t));
+
+	if (dt_size <= 0) {	/* No fdt */
+		exit();
+	}
+
+	/*
+	 * Start heap after end of the kernel (after decompressed to
+	 * address 0) or the end of the zImage, whichever is higher.
+	 * That's so things allocated by simple_alloc won't overwrite
+	 * any part of the zImage and the kernel won't overwrite the dtb
+	 * when decompressed & relocated.
+	 */
+	gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size);
+	gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
+
+	if (!parse_elf32(elfheader, &ei))
+		exit();
+
+	heap_start = (char *)(ei.memsize + ei.elfoffset);/* end of kernel */
+	heap_start = max(heap_start, (char *)_end);	/* end of zImage */
+
+	if ((unsigned)simple_alloc_init(heap_start, HEAP_SIZE, 2 * KB, 16)
+	    > (128 * MB))
+		exit();
+
+	/* Relocate dtb to safe area past end of zImage & kernel */
+	dtb = malloc(dt_size);
+	if (!dtb)
+		exit();
+	memmove(dtb, _dtb_start, dt_size);
+	fdt_init(dtb);
+
+	platform_ops.fixups = mvme3100_fixups;
+	platform_ops.exit = mvme3100_reset;
+
+	if (serial_console_init() < 0)
+		exit();
+}
+
+asm("	.globl _zimage_start\n\
+	_zimage_start:\n\
+		mfmsr   10\n\
+		rlwinm  10,10,0,~(1<<15)        /* Clear MSR_EE */\n\
+		sync\n\
+		mtmsr   10\n\
+		isync\n\
+		b _zimage_start_lib\n\
+");
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/pplusboot-mvme4100.c linux-2.6.29.6.mod/arch/powerpc/boot/pplusboot-mvme4100.c
--- linux-2.6.29.6.orig/arch/powerpc/boot/pplusboot-mvme4100.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/pplusboot-mvme4100.c	2009-08-13 14:13:52.000000000 -0700
@@ -0,0 +1,195 @@
+/*
+ * Emerson Network Power Embedded Computing MVME4100 bootwrapper code.
+ *
+ * Author: Ajit Prem <ajit.prem@emerson.com>
+ *
+ * Copyright 2008 Emerson Network Power Embedded Computing Inc.
+ *
+ * This file is licensed under the terms of the GNU 
+ * General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, 
+ * whether express or implied.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+#include "gunzip_util.h"
+
+#define TARGET_MVME4100
+#include "ppcboot.h"
+
+extern char _end[];
+extern char _vmlinux_start[], _vmlinux_end[];
+extern char _dtb_start[], _dtb_end[];
+
+
+
+static unsigned char enet0_addr[6];
+static unsigned char enet1_addr[6];
+static unsigned char enet2_addr[6];
+static unsigned char enet3_addr[6];
+static bd_t bdinfo;
+
+#define KB	1024U
+#define MB	(KB*KB)
+
+#define EEPROM_ADDR	0xA8
+
+BSS_STACK(16 * KB);
+
+void mvme4100_reset(void)
+{
+        out_8((u8 *) 0xf2000001, 0xA0);
+
+	for (;;) 
+		;
+}
+
+static void mvme4100_fixups(void)
+{
+	void *devp;
+	u32 v[2];
+
+	/* Now fixup device tree properties */
+	/* Set /model appropriately */
+	devp = finddevice("/");
+	if (devp == NULL)
+		fatal("Error: Missing '/' device tree node\n\r");
+
+	/* Set /cpus/PowerPC,8548/clock-frequency */
+	devp = finddevice("/cpus/PowerPC,8548");
+	if (devp == NULL)
+		fatal("Error: Missing proper /cpus device tree node\n\r");
+
+	v[0] = bdinfo.bi_intfreq;
+	v[0] *= 1000000;
+	setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
+
+//	printf("Clock-frequency 0x%x\n\r", v[0]);
+
+	v[0] = bdinfo.bi_busfreq;
+	v[0] *= 1000000;
+	setprop(devp, "bus-frequency", &v[0], sizeof(v[0]));
+
+//	printf("bus-frequency 0x%x\n\r", v[0]);
+
+	v[0] /= 8;
+	setprop(devp, "timebase-frequency", &v[0], sizeof(v[0]));
+
+	/* Set memory size */
+	devp = finddevice("/memory");
+	if (devp == NULL)
+		fatal("Error: Missing /memory device tree node\n\r");
+	v[0] = 0;
+	v[1] = bdinfo.bi_memsize;
+	setprop(devp, "reg", v, sizeof(v));
+
+//	printf("Memory Size 0x%x\n\r", v[1]);
+
+	devp = finddevice("/soc8548/serial@4500");
+	if (devp == NULL)
+		fatal("Error: Missing soc8548 serial device tree node\n\r");
+	v[0] = bdinfo.bi_busfreq;
+	v[0] *= 1000000;
+	setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
+
+//	printf("serial-clock-frequency 0x%x\n\r", v[0]);
+
+	memcpy(enet0_addr, bdinfo.bi_enetaddr, 6);
+	memcpy(enet1_addr, bdinfo.bi_enet1addr, 6);
+	memcpy(enet2_addr, bdinfo.bi_enet2addr, 6);
+	memcpy(enet3_addr, bdinfo.bi_enet3addr, 6);
+
+	devp = finddevice("/soc8548/ethernet@24000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet0_addr[0], sizeof(enet0_addr));
+
+	devp = finddevice("/soc8548/ethernet@25000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet1_addr[0], sizeof(enet0_addr));
+
+	devp = finddevice("/soc8548/ethernet@26000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet2_addr[0], sizeof(enet0_addr));
+
+	devp = finddevice("/soc8548/ethernet@27000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet3_addr[0], sizeof(enet0_addr));
+}
+
+#define HEAP_SIZE	(16*MB)
+static struct gunzip_state gzstate;
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		   unsigned long r6, unsigned long r7)
+{
+	struct elf_info ei;
+	char *heap_start, *dtb;
+	int dt_size = _dtb_end - _dtb_start;
+	void *vmlinuz_addr = _vmlinux_start;
+	unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start;
+	char elfheader[256];
+	bd_t *bp = (bd_t *) r3;
+
+	memcpy(&bdinfo, bp, sizeof(bd_t));
+	if (dt_size <= 0) {	/* No fdt */
+		exit();
+	}
+
+	/*
+	 * Start heap after end of the kernel (after decompressed to
+	 * address 0) or the end of the zImage, whichever is higher.
+	 * That's so things allocated by simple_alloc won't overwrite
+	 * any part of the zImage and the kernel won't overwrite the dtb
+	 * when decompressed & relocated.
+	 */
+	gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size);
+	gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
+
+	if (!parse_elf32(elfheader, &ei))
+		exit();
+
+	heap_start = (char *)(ei.memsize + ei.elfoffset);/* end of kernel */
+	heap_start = max(heap_start, (char *)_end);	/* end of zImage */
+
+
+	if ((unsigned)simple_alloc_init(heap_start, HEAP_SIZE, 2 * KB, 16)
+	    > (128 * MB))
+		exit();
+
+	/* Relocate dtb to safe area past end of zImage & kernel */
+	dtb = malloc(dt_size);
+	if (!dtb)
+		exit();
+	memmove(dtb, _dtb_start, dt_size);
+	fdt_init(dtb);
+
+
+	platform_ops.fixups = mvme4100_fixups;
+	platform_ops.exit = mvme4100_reset;
+
+	if (serial_console_init() < 0)
+		exit();
+//	printf("offset 0x%x start 0x%x dtb 0x%x\n\r", ei.elfoffset, heap_start, dtb);
+}
+
+asm("	.globl _zimage_start\n\
+	_zimage_start:\n\
+		mfmsr   10\n\
+		rlwinm  10,10,0,~(1<<15)        /* Clear MSR_EE */\n\
+		sync\n\
+		mtmsr   10\n\
+		isync\n\
+		b _zimage_start_lib\n\
+");
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/pplusboot-mvme7100.c linux-2.6.29.6.mod/arch/powerpc/boot/pplusboot-mvme7100.c
--- linux-2.6.29.6.orig/arch/powerpc/boot/pplusboot-mvme7100.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/pplusboot-mvme7100.c	2009-08-13 14:17:29.000000000 -0700
@@ -0,0 +1,210 @@
+/*
+ * Motorola ECC MVME7100 bootwrapper code.
+ *
+ * Author: Ajit Prem <Ajit.Prem@emerson.com>
+ *
+ * 2007 (c) Motorola, Inc.  
+ * 2008-2009 (c) Emerson Network Power Embedded Computing  
+ *
+ * This file is licensed under the terms of the GNU 
+ * General Public License version 2. This program
+ * is licensed "as is" without any warranty of any kind, 
+ * whether express or implied.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "types.h"
+#include "elf.h"
+#include "page.h"
+#include "string.h"
+#include "stdio.h"
+#include "io.h"
+#include "ops.h"
+#include "gunzip_util.h"
+
+#define TARGET_MVME7100
+#include "ppcboot.h"
+
+extern char _end[];
+extern char _vmlinux_start[], _vmlinux_end[];
+extern char _dtb_start[], _dtb_end[];
+
+static unsigned char enet0_addr[6];
+static unsigned char enet1_addr[6];
+static unsigned char enet2_addr[6];
+static unsigned char enet3_addr[6];
+static bd_t bdinfo;
+
+#define KB	1024U
+#define MB	(KB*KB)
+
+#define EEPROM_ADDR	0xA2
+
+BSS_STACK(16 * KB);
+
+void mvme7100_reset(void)
+{
+        u32 *rstcr;
+        rstcr = (u32 *) (0xf1000000 + 0x000e00b0);
+
+        /* Assert reset request to Reset Control Register */
+        out_be32(rstcr, 0x2);
+
+	for (;;) 
+		;
+}
+
+static void mvme7100_fixups(void)
+{
+	void *devp;
+	u32 v[2];
+
+	/* Now fixup device tree properties */
+	/* Set /model appropriately */
+	devp = finddevice("/");
+	if (devp == NULL)
+		fatal("Error: Missing '/' device tree node\n\r");
+
+	/* Set /cpus/PowerPC,8641@0/clock-frequency */
+	devp = finddevice("/cpus/PowerPC,8641@0");
+	if (devp == NULL)
+		fatal("Error: Missing proper /cpus device tree node\n\r");
+
+	v[0] = bdinfo.bi_intfreq;
+	v[0] *= 1000000;
+	setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
+
+	v[0] = bdinfo.bi_busfreq;
+	v[0] *= 1000000;
+	setprop(devp, "bus-frequency", &v[0], sizeof(v[0]));
+
+	v[0] /= 4;
+	setprop(devp, "timebase-frequency", &v[0], sizeof(v[0]));
+
+	/* Set /cpus/PowerPC,8641@1/clock-frequency */
+	devp = finddevice("/cpus/PowerPC,8641@1");
+	if (devp == NULL)
+		fatal("Error: Missing proper /cpus device tree node\n\r");
+
+	v[0] = bdinfo.bi_intfreq;
+	v[0] *= 1000000;
+	setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
+
+	v[0] = bdinfo.bi_busfreq;
+	v[0] *= 1000000;
+	setprop(devp, "bus-frequency", &v[0], sizeof(v[0]));
+
+	v[0] /= 4;
+	setprop(devp, "timebase-frequency", &v[0], sizeof(v[0]));
+
+	/* Set memory size */
+	devp = finddevice("/memory");
+	if (devp == NULL)
+		fatal("Error: Missing /memory device tree node\n\r");
+	v[0] = 0;
+	v[1] = bdinfo.bi_memsize;
+	setprop(devp, "reg", v, sizeof(v));
+
+	devp = finddevice("/soc8641@f1000000");
+	if (devp == NULL)
+		fatal("Error: Missing soc8641 device tree node\n\r");
+	v[0] = bdinfo.bi_busfreq;
+	v[0] *= 1000000;
+	setprop(devp, "bus-frequency", &v[0], sizeof(v[0]));
+
+	devp = finddevice("/soc8641/serial@4500");
+	if (devp == NULL)
+		fatal("Error: Missing soc8641 serial device tree node\n\r");
+	v[0] = bdinfo.bi_busfreq;
+	v[0] *= 1000000;
+	setprop(devp, "clock-frequency", &v[0], sizeof(v[0]));
+
+	memcpy(enet0_addr, bdinfo.bi_enetaddr, 6);
+	memcpy(enet1_addr, bdinfo.bi_enet1addr, 6);
+	memcpy(enet2_addr, bdinfo.bi_enet2addr, 6);
+	memcpy(enet3_addr, bdinfo.bi_enet3addr, 6);
+
+	devp = finddevice("/soc8641/ethernet@24000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet0_addr[0], sizeof(enet0_addr));
+
+	devp = finddevice("/soc8641/ethernet@25000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet1_addr[0], sizeof(enet0_addr));
+
+	devp = finddevice("/soc8641/ethernet@26000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet2_addr[0], sizeof(enet0_addr));
+
+	devp = finddevice("/soc8641/ethernet@27000");
+	if (devp == NULL)
+		fatal("Error: Missing ethernet device tree node\n\r");
+	setprop(devp, "local-mac-address", &enet3_addr[0], sizeof(enet0_addr));
+}
+
+#define HEAP_SIZE	(16*MB)
+static struct gunzip_state gzstate;
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5,
+		   unsigned long r6, unsigned long r7)
+{
+	struct elf_info ei;
+	char *heap_start, *dtb;
+	int dt_size = _dtb_end - _dtb_start;
+	void *vmlinuz_addr = _vmlinux_start;
+	unsigned long vmlinuz_size = _vmlinux_end - _vmlinux_start;
+	char elfheader[256];
+	bd_t *bp = (bd_t *) r3;
+
+	memcpy(&bdinfo, bp, sizeof(bd_t));
+	if (dt_size <= 0) {	/* No fdt */
+		exit();
+	}
+
+	/*
+	 * Start heap after end of the kernel (after decompressed to
+	 * address 0) or the end of the zImage, whichever is higher.
+	 * That's so things allocated by simple_alloc won't overwrite
+	 * any part of the zImage and the kernel won't overwrite the dtb
+	 * when decompressed & relocated.
+	 */
+	gunzip_start(&gzstate, vmlinuz_addr, vmlinuz_size);
+	gunzip_exactly(&gzstate, elfheader, sizeof(elfheader));
+
+	if (!parse_elf32(elfheader, &ei))
+		exit();
+
+	heap_start = (char *)(ei.memsize + ei.elfoffset);/* end of kernel */
+	heap_start = max(heap_start, (char *)_end);	/* end of zImage */
+
+	if ((unsigned)simple_alloc_init(heap_start, HEAP_SIZE, 2 * KB, 16)
+	    > (128 * MB))
+		exit();
+
+	/* Relocate dtb to safe area past end of zImage & kernel */
+	dtb = malloc(dt_size);
+	if (!dtb)
+		exit();
+	memmove(dtb, _dtb_start, dt_size);
+	fdt_init(dtb);
+
+	platform_ops.fixups = mvme7100_fixups;
+	platform_ops.exit = mvme7100_reset;
+
+	if (serial_console_init() < 0)
+		exit();
+}
+
+asm("	.globl _zimage_start\n\
+	_zimage_start:\n\
+		mfmsr   10\n\
+		rlwinm  10,10,0,~(1<<15)        /* Clear MSR_EE */\n\
+		sync\n\
+		mtmsr   10\n\
+		isync\n\
+		b _zimage_start_lib\n\
+");
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/serial.c linux-2.6.29.6.mod/arch/powerpc/boot/serial.c
--- linux-2.6.29.6.orig/arch/powerpc/boot/serial.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/serial.c	2009-07-21 11:28:17.000000000 -0700
@@ -44,7 +44,7 @@
 	cp = &buf[count];
 	count++;
 
-	while (timer++ < 5*1000) {
+	while (timer++ < 10*1000) {
 		if (scdp->tstc()) {
 			while (((ch = scdp->getc()) != '\n') && (ch != '\r')) {
 				/* Test for backspace/delete */
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/boot/wrapper linux-2.6.29.6.mod/arch/powerpc/boot/wrapper
--- linux-2.6.29.6.orig/arch/powerpc/boot/wrapper	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/boot/wrapper	2009-07-21 11:28:17.000000000 -0700
@@ -326,6 +326,12 @@
     fi
     exit 0
     ;;
+pplusboot*)
+    mv "$ofile" "$ofile.elf"
+    $objbin/mkprep -pbp "$ofile.elf" "$ofile"
+    rm -f "$ofile.elf"
+    exit 0
+    ;;
 ps3)
     # The ps3's loader supports loading a gzipped binary image from flash
     # rom to ram addr zero. The loader then enters the system reset
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/configs/cpci6200_defconfig linux-2.6.29.6.mod/arch/powerpc/configs/cpci6200_defconfig
--- linux-2.6.29.6.orig/arch/powerpc/configs/cpci6200_defconfig	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/configs/cpci6200_defconfig	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,1813 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29.5
+# Thu Jun 25 14:23:57 2009
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_6xx is not set
+CONFIG_PPC_85xx=y
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+# CONFIG_PPC_E500MC is not set
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+CONFIG_FSL_EMB_PERFMON=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_PPC_MMU_NOHASH=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+CONFIG_PPC_UDBG_16550=y
+CONFIG_GENERIC_TBSYNC=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=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 is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NS is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_DEVICE is not set
+# CONFIG_CPUSETS is not set
+# CONFIG_CGROUP_CPUACCT is not set
+# CONFIG_RESOURCE_COUNTERS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+CONFIG_MARKERS=y
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# Platform support
+#
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+CONFIG_MPC85xx=y
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_MPC85xx_CDS is not set
+# CONFIG_MPC85xx_MDS is not set
+# CONFIG_MPC8536_DS is not set
+# CONFIG_MPC85xx_DS is not set
+# CONFIG_KSI8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+# CONFIG_TQM8541 is not set
+# CONFIG_TQM8548 is not set
+# CONFIG_TQM8555 is not set
+# CONFIG_TQM8560 is not set
+# CONFIG_SBC8548 is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_MVME3100 is not set
+# CONFIG_MVME4100 is not set
+CONFIG_CPCI6200=y
+CONFIG_CPCI6200_ENABLE_DDR_ERRORS=y
+CONFIG_CPCI6200_ENABLE_L2_ERRORS=y
+CONFIG_CPCI6200_ENABLE_PCI_ERRORS=y
+# CONFIG_CPCI6200_TICK_TIMERS is not set
+# CONFIG_IPIC is not set
+CONFIG_MPIC=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_QUICC_ENGINE is not set
+# CONFIG_CPM2 is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_MPC8xxx_GPIO is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+# CONFIG_IRQ_ALL_CPUS is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_MIGRATION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600 root=/dev/ram0 ramdisk_size=64000"
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIEASPM is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+CONFIG_LOWMEM_SIZE_BOOL=y
+CONFIG_LOWMEM_SIZE=0x40000000
+# CONFIG_RELOCATABLE is not set
+CONFIG_PAGE_OFFSET_BOOL=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_KERNEL_START_BOOL=y
+CONFIG_KERNEL_START=0x80000000
+# CONFIG_PHYSICAL_START_BOOL is not set
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_PHYSICAL_ALIGN=0x10000000
+CONFIG_TASK_SIZE_BOOL=y
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# 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
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_DEFRAG_IPV4 is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# 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 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_OF_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+CONFIG_SSFDC=y
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_GEOMETRY is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PHYSMAP_OF is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+CONFIG_MTD_CPCI6200=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_VERIFY_WRITE=y
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_CPCI6200=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_PLATFORM=y
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+# CONFIG_MTD_NAND_FSL_UPM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# 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_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+# 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=131072
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+CONFIG_EEPROM_LEGACY=y
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 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 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# 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_SL82C105 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_BLK_DEV_TC86C001 is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+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_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_SCAN_ASYNC=y
+# CONFIG_SCSI_WAIT_SCAN is not set
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# 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_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_LIBFC is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_STEX 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 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_FSL is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+CONFIG_PATA_PDC2027X=y
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+# CONFIG_MD_AUTODETECT is not set
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID456=y
+CONFIG_MD_RAID5_RESHAPE=y
+CONFIG_MD_MULTIPATH=y
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_CRYPT is not set
+CONFIG_DM_SNAPSHOT=y
+CONFIG_DM_MIRROR=y
+CONFIG_DM_ZERO=y
+CONFIG_DM_MULTIPATH=y
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+CONFIG_BROADCOM_PHY=y
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+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
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR 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_E100 is not set
+# 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_R6040 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB 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_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# 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_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_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=5
+CONFIG_SERIAL_8250_RUNTIME_UARTS=5
+CONFIG_SERIAL_8250_EXTENDED=y
+# CONFIG_SERIAL_8250_MANY_PORTS is not set
+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_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_CONSOLE_POLL=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HVC_UDBG is not set
+CONFIG_IPMI_HANDLER=y
+# CONFIG_IPMI_PANIC_EVENT is not set
+CONFIG_IPMI_DEVICE_INTERFACE=y
+# CONFIG_IPMI_SI is not set
+CONFIG_IPMI_SMB=m
+# CONFIG_IPMI_WATCHDOG is not set
+# CONFIG_IPMI_POWEROFF is not set
+# CONFIG_IPMI_OOPS_CONSOLE is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# 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_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_MPC=y
+CONFIG_I2C_MPC_IPMI=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_BOOKE_WDT is not set
+CONFIG_CPCI6200_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+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
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_FSL is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD 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_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_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1375 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+CONFIG_RTC_DRV_M41T80=y
+# CONFIG_RTC_DRV_M41T80_WDT is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PPC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# 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_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_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+CONFIG_YAFFS_DOES_ECC=y
+# CONFIG_YAFFS_ECC_WRONG_ORDER is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+# 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
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# 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_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 is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+CONFIG_NLS_ASCII=y
+# CONFIG_NLS_ISO8859_1 is not set
+# 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
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS 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_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_KGDB=y
+CONFIG_KGDB_SERIAL_CONSOLE=y
+# CONFIG_KGDB_TESTS is not set
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+CONFIG_DEBUGGER=y
+# CONFIG_IRQSTACKS is not set
+CONFIG_VIRQ_DEBUG=y
+CONFIG_BDI_SWITCH=y
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_XOR_BLOCKS=y
+CONFIG_ASYNC_CORE=y
+CONFIG_ASYNC_MEMCPY=y
+CONFIG_ASYNC_XOR=y
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_TALITOS is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/configs/mvme3100_defconfig linux-2.6.29.6.mod/arch/powerpc/configs/mvme3100_defconfig
--- linux-2.6.29.6.orig/arch/powerpc/configs/mvme3100_defconfig	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/configs/mvme3100_defconfig	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,1830 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29
+# Thu Apr  2 12:52:03 2009
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_6xx is not set
+CONFIG_PPC_85xx=y
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+# CONFIG_PPC_E500MC is not set
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+CONFIG_FSL_EMB_PERFMON=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_PPC_MMU_NOHASH=y
+# CONFIG_PPC_MM_SLICES is not set
+# CONFIG_SMP is not set
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=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 is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NS is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_DEVICE is not set
+# CONFIG_CGROUP_CPUACCT is not set
+# CONFIG_RESOURCE_COUNTERS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_COMPAT_BRK is not set
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+CONFIG_MARKERS=y
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# Platform support
+#
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+CONFIG_MPC85xx=y
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_MPC85xx_CDS is not set
+# CONFIG_MPC85xx_MDS is not set
+# CONFIG_MPC8536_DS is not set
+# CONFIG_MPC85xx_DS is not set
+# CONFIG_KSI8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+# CONFIG_TQM8541 is not set
+# CONFIG_TQM8548 is not set
+# CONFIG_TQM8555 is not set
+# CONFIG_TQM8560 is not set
+# CONFIG_SBC8548 is not set
+# CONFIG_SBC8560 is not set
+CONFIG_MVME3100=y
+# CONFIG_MVME4100 is not set
+# CONFIG_CPCI6200 is not set
+CONFIG_MVME3100_ENABLE_DDR_ERRORS=y
+CONFIG_MVME3100_ENABLE_L2_ERRORS=y
+CONFIG_MVME3100_ENABLE_PCI_ERRORS=y
+CONFIG_MVME3100_TICK_TIMERS=y
+# CONFIG_IPIC is not set
+CONFIG_MPIC=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_QUICC_ENGINE is not set
+# CONFIG_CPM2 is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_MPC8xxx_GPIO is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+# CONFIG_HIGHMEM is not set
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+CONFIG_HZ=250
+CONFIG_SCHED_HRTICK=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_MIGRATION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600 root=/dev/ram0 ramdisk_size=64000"
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+CONFIG_LOWMEM_SIZE_BOOL=y
+CONFIG_LOWMEM_SIZE=0x40000000
+# CONFIG_RELOCATABLE is not set
+CONFIG_PAGE_OFFSET_BOOL=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_KERNEL_START_BOOL=y
+CONFIG_KERNEL_START=0x80000000
+# CONFIG_PHYSICAL_START_BOOL is not set
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_PHYSICAL_ALIGN=0x10000000
+CONFIG_TASK_SIZE_BOOL=y
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_NET_KEY=y
+# CONFIG_NET_KEY_MIGRATE is not set
+CONFIG_INET=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_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+CONFIG_NET_IPIP=y
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# 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=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+CONFIG_INET_LRO=y
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+CONFIG_NETFILTER_NETLINK=y
+CONFIG_NETFILTER_NETLINK_QUEUE=y
+CONFIG_NETFILTER_NETLINK_LOG=y
+CONFIG_NF_CONNTRACK=y
+# CONFIG_NF_CT_ACCT is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+# CONFIG_NF_CONNTRACK_FTP is not set
+# CONFIG_NF_CONNTRACK_H323 is not set
+# CONFIG_NF_CONNTRACK_IRC is not set
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+# CONFIG_NF_CONNTRACK_SIP is not set
+# CONFIG_NF_CONNTRACK_TFTP is not set
+# CONFIG_NF_CT_NETLINK is not set
+CONFIG_NETFILTER_XTABLES=y
+# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE is not set
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_MAC is not set
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+# CONFIG_IP_NF_FILTER is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+# CONFIG_NF_NAT is not set
+# CONFIG_IP_NF_MANGLE is not set
+# CONFIG_IP_NF_RAW is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_NF_CONNTRACK_IPV6 is not set
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# 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 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_OF_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+# CONFIG_MTD_MAP_BANK_WIDTH_1 is not set
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+# CONFIG_MTD_CFI_I1 is not set
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+# CONFIG_MTD_CFI_INTELEXT is not set
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PHYSMAP_OF is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+CONFIG_MTD_MVME3100=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# 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_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+# 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=65536
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+CONFIG_EEPROM_AT24=y
+CONFIG_EEPROM_LEGACY=y
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+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_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_SCAN_ASYNC=y
+CONFIG_SCSI_WAIT_SCAN=y
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# 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_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_LIBFC is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_STEX 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 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_FSL is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+CONFIG_SATA_VITESSE=y
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+CONFIG_PATA_PDC2027X=y
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+# CONFIG_MD_AUTODETECT is not set
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID456=y
+CONFIG_MD_RAID5_RESHAPE=y
+CONFIG_MD_MULTIPATH=y
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_CRYPT is not set
+CONFIG_DM_SNAPSHOT=y
+CONFIG_DM_MIRROR=y
+CONFIG_DM_ZERO=y
+CONFIG_DM_MULTIPATH=y
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+CONFIG_BROADCOM_PHY=y
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+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
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+# CONFIG_NET_PCI is not set
+# CONFIG_B44 is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB 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_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# 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_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_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=5
+CONFIG_SERIAL_8250_RUNTIME_UARTS=5
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=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_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+
+#
+# VME Bridge devices
+#
+CONFIG_VME_BRIDGE=y
+# CONFIG_VME_BRIDGE_BOOTMEM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_HELPER_AUTO=y
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# 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_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+CONFIG_SENSORS_DS1621=y
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S 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_LM93 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 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_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ALIM7101_WDT is not set
+CONFIG_BOOKE_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_COMPAT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+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
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_FSL is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD 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_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_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+CONFIG_RTC_DRV_DS1375=y
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PPC is not set
+CONFIG_DMADEVICES=y
+
+#
+# DMA Devices
+#
+CONFIG_FSL_DMA=y
+CONFIG_DMA_ENGINE=y
+
+#
+# DMA Clients
+#
+CONFIG_NET_DMA=y
+# CONFIG_DMATEST is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# 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_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_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_YAFFS_FS is not set
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+# 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
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# 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_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 is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=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 is not set
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=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
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS 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_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+# CONFIG_IRQSTACKS is not set
+CONFIG_VIRQ_DEBUG=y
+CONFIG_BDI_SWITCH=y
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_XOR_BLOCKS=y
+CONFIG_ASYNC_CORE=y
+CONFIG_ASYNC_MEMCPY=y
+CONFIG_ASYNC_XOR=y
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/configs/mvme4100_defconfig linux-2.6.29.6.mod/arch/powerpc/configs/mvme4100_defconfig
--- linux-2.6.29.6.orig/arch/powerpc/configs/mvme4100_defconfig	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/configs/mvme4100_defconfig	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,1859 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29.5
+# Thu Jun 25 17:00:38 2009
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+# CONFIG_6xx is not set
+CONFIG_PPC_85xx=y
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_E500=y
+# CONFIG_PPC_E500MC is not set
+CONFIG_BOOKE=y
+CONFIG_FSL_BOOKE=y
+CONFIG_FSL_EMB_PERFMON=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_SPE=y
+CONFIG_PPC_MMU_NOHASH=y
+# CONFIG_PPC_MM_SLICES is not set
+# CONFIG_SMP is not set
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+CONFIG_PPC_UDBG_16550=y
+# CONFIG_GENERIC_TBSYNC is not set
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=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 is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NS is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_DEVICE is not set
+# CONFIG_CGROUP_CPUACCT is not set
+# CONFIG_RESOURCE_COUNTERS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+# CONFIG_SLUB_DEBUG is not set
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+CONFIG_MARKERS=y
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# Platform support
+#
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PQ2ADS is not set
+CONFIG_MPC85xx=y
+# CONFIG_MPC8540_ADS is not set
+# CONFIG_MPC8560_ADS is not set
+# CONFIG_MPC85xx_CDS is not set
+# CONFIG_MPC85xx_MDS is not set
+# CONFIG_MPC8536_DS is not set
+# CONFIG_MPC85xx_DS is not set
+# CONFIG_KSI8560 is not set
+# CONFIG_STX_GP3 is not set
+# CONFIG_TQM8540 is not set
+# CONFIG_TQM8541 is not set
+# CONFIG_TQM8548 is not set
+# CONFIG_TQM8555 is not set
+# CONFIG_TQM8560 is not set
+# CONFIG_SBC8548 is not set
+# CONFIG_SBC8560 is not set
+# CONFIG_MVME3100 is not set
+CONFIG_MVME4100=y
+# CONFIG_CPCI6200 is not set
+CONFIG_MVME4100_ENABLE_DDR_ERRORS=y
+CONFIG_MVME4100_ENABLE_L2_ERRORS=y
+CONFIG_MVME4100_ENABLE_PCI_ERRORS=y
+CONFIG_MVME4100_TICK_TIMERS=y
+# CONFIG_IPIC is not set
+CONFIG_MPIC=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_QUICC_ENGINE is not set
+# CONFIG_CPM2 is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_MPC8xxx_GPIO is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=y
+CONFIG_MATH_EMULATION=y
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_MIGRATION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600 root=/dev/ram0 ramdisk_size=64000"
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIEASPM is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+CONFIG_LOWMEM_SIZE_BOOL=y
+CONFIG_LOWMEM_SIZE=0x40000000
+# CONFIG_RELOCATABLE is not set
+CONFIG_PAGE_OFFSET_BOOL=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_KERNEL_START_BOOL=y
+CONFIG_KERNEL_START=0x80000000
+# CONFIG_PHYSICAL_START_BOOL is not set
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_PHYSICAL_ALIGN=0x10000000
+CONFIG_TASK_SIZE_BOOL=y
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# 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
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_DEFRAG_IPV4 is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# 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 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_OF_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+CONFIG_SSFDC=y
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PHYSMAP_OF is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+CONFIG_MTD_MVME4100=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_VERIFY_WRITE=y
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_MVME4100=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_PLATFORM=y
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+# CONFIG_MTD_NAND_FSL_UPM is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# 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_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+# 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=131072
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+CONFIG_EEPROM_LEGACY=y
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 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 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# 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_SL82C105 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_BLK_DEV_TC86C001 is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+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_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_SCAN_ASYNC=y
+# CONFIG_SCSI_WAIT_SCAN is not set
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# 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_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_LIBFC is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_STEX 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 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_FSL is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+CONFIG_PATA_PDC2027X=y
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+# CONFIG_MD_AUTODETECT is not set
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID456=y
+CONFIG_MD_RAID5_RESHAPE=y
+CONFIG_MD_MULTIPATH=y
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_CRYPT is not set
+CONFIG_DM_SNAPSHOT=y
+CONFIG_DM_MIRROR=y
+CONFIG_DM_ZERO=y
+CONFIG_DM_MULTIPATH=y
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+CONFIG_BROADCOM_PHY=y
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+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
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR 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_E100 is not set
+# 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_R6040 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+CONFIG_E1000E=y
+# CONFIG_IP1000 is not set
+# CONFIG_IGB 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_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# 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_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_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=5
+CONFIG_SERIAL_8250_RUNTIME_UARTS=5
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=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_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_CONSOLE_POLL=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+
+#
+# VME Bridge devices
+#
+CONFIG_VME_BRIDGE=y
+# CONFIG_VME_BRIDGE_BOOTMEM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# 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_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S 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=y
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 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_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_BOOKE_WDT is not set
+CONFIG_MVME4100_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_COMPAT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+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
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_FSL is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD 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_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_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+CONFIG_RTC_DRV_DS1375=y
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PPC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# 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_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_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+CONFIG_YAFFS_DOES_ECC=y
+# CONFIG_YAFFS_ECC_WRONG_ORDER is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+# 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
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# 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_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 is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+CONFIG_NLS_ASCII=y
+# CONFIG_NLS_ISO8859_1 is not set
+# 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
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS 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_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_KGDB=y
+CONFIG_KGDB_SERIAL_CONSOLE=y
+# CONFIG_KGDB_TESTS is not set
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+CONFIG_DEBUGGER=y
+# CONFIG_IRQSTACKS is not set
+CONFIG_VIRQ_DEBUG=y
+CONFIG_BDI_SWITCH=y
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_XOR_BLOCKS=y
+CONFIG_ASYNC_CORE=y
+CONFIG_ASYNC_MEMCPY=y
+CONFIG_ASYNC_XOR=y
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_TALITOS is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/configs/mvme7100_defconfig linux-2.6.29.6.mod/arch/powerpc/configs/mvme7100_defconfig
--- linux-2.6.29.6.orig/arch/powerpc/configs/mvme7100_defconfig	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/configs/mvme7100_defconfig	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,1863 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29.4
+# Mon Jun 22 11:32:03 2009
+#
+# CONFIG_PPC64 is not set
+
+#
+# Processor support
+#
+CONFIG_6xx=y
+# CONFIG_PPC_85xx is not set
+# CONFIG_PPC_8xx is not set
+# CONFIG_40x is not set
+# CONFIG_44x is not set
+# CONFIG_E200 is not set
+CONFIG_PPC_FPU=y
+# CONFIG_PHYS_64BIT is not set
+CONFIG_ALTIVEC=y
+CONFIG_PPC_STD_MMU=y
+CONFIG_PPC_STD_MMU_32=y
+# CONFIG_PPC_MM_SLICES is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=2
+CONFIG_PPC32=y
+CONFIG_WORD_SIZE=32
+# CONFIG_ARCH_PHYS_ADDR_T_64BIT is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_CMOS_UPDATE=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_GENERIC_HARDIRQS=y
+# CONFIG_HAVE_SETUP_PER_CPU_AREA is not set
+CONFIG_IRQ_PER_CPU=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_GENERIC_LOCKBREAK=y
+CONFIG_ARCH_HAS_ILOG2_U32=y
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+# CONFIG_ARCH_NO_VIRT_TO_BUS is not set
+CONFIG_PPC=y
+CONFIG_EARLY_PRINTK=y
+CONFIG_GENERIC_NVRAM=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_ARCH_MAY_HAVE_PC_FDC=y
+CONFIG_PPC_OF=y
+CONFIG_OF=y
+CONFIG_PPC_UDBG_16550=y
+CONFIG_GENERIC_TBSYNC=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_GENERIC_BUG=y
+# CONFIG_DEFAULT_UIMAGE is not set
+# CONFIG_PPC_DCR_NATIVE is not set
+# CONFIG_PPC_DCR_MMIO is not set
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=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 is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_GROUP_SCHED=y
+CONFIG_FAIR_GROUP_SCHED=y
+CONFIG_RT_GROUP_SCHED=y
+CONFIG_USER_SCHED=y
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_CGROUPS=y
+# CONFIG_CGROUP_DEBUG is not set
+# CONFIG_CGROUP_NS is not set
+# CONFIG_CGROUP_FREEZER is not set
+# CONFIG_CGROUP_DEVICE is not set
+# CONFIG_CPUSETS is not set
+# CONFIG_CGROUP_CPUACCT is not set
+# CONFIG_RESOURCE_COUNTERS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
+CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_EMBEDDED=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+CONFIG_COMPAT_BRK=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+CONFIG_MARKERS=y
+CONFIG_OPROFILE=y
+CONFIG_HAVE_OPROFILE=y
+CONFIG_KPROBES=y
+CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS=y
+CONFIG_KRETPROBES=y
+CONFIG_HAVE_IOREMAP_PROT=y
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+# CONFIG_FREEZER is not set
+
+#
+# Platform support
+#
+CONFIG_PPC_MULTIPLATFORM=y
+CONFIG_CLASSIC32=y
+# CONFIG_PPC_CHRP is not set
+# CONFIG_MPC5121_ADS is not set
+# CONFIG_MPC5121_GENERIC is not set
+# CONFIG_PPC_MPC52xx is not set
+# CONFIG_PPC_PMAC is not set
+# CONFIG_PPC_CELL is not set
+# CONFIG_PPC_CELL_NATIVE is not set
+# CONFIG_PPC_82xx is not set
+# CONFIG_PQ2ADS is not set
+# CONFIG_PPC_83xx is not set
+CONFIG_PPC_86xx=y
+# CONFIG_MPC8641_HPCN is not set
+# CONFIG_SBC8641D is not set
+# CONFIG_MPC8610_HPCD is not set
+# CONFIG_GEF_SBC610 is not set
+CONFIG_MVME7100=y
+CONFIG_MPC8641=y
+CONFIG_MVME7100_ENABLE_DDR_ERRORS=y
+CONFIG_MVME7100_ENABLE_L2_ERRORS=y
+CONFIG_MVME7100_ENABLE_PCI_ERRORS=y
+CONFIG_MVME7100_TICK_TIMERS=y
+# CONFIG_IPIC is not set
+CONFIG_MPIC=y
+# CONFIG_MPIC_WEIRD is not set
+# CONFIG_PPC_I8259 is not set
+# CONFIG_PPC_RTAS is not set
+# CONFIG_MMIO_NVRAM is not set
+# CONFIG_PPC_MPC106 is not set
+# CONFIG_PPC_970_NAP is not set
+# CONFIG_PPC_INDIRECT_IO is not set
+# CONFIG_GENERIC_IOMAP is not set
+# CONFIG_CPU_FREQ is not set
+# CONFIG_TAU is not set
+# CONFIG_QUICC_ENGINE is not set
+# CONFIG_FSL_ULI1575 is not set
+# CONFIG_MPC8xxx_GPIO is not set
+# CONFIG_SIMPLE_GPIO is not set
+
+#
+# Kernel options
+#
+CONFIG_HIGHMEM=y
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+# CONFIG_HZ_100 is not set
+# CONFIG_HZ_250 is not set
+# CONFIG_HZ_300 is not set
+CONFIG_HZ_1000=y
+CONFIG_HZ=1000
+CONFIG_SCHED_HRTICK=y
+# CONFIG_PREEMPT_NONE is not set
+# CONFIG_PREEMPT_VOLUNTARY is not set
+CONFIG_PREEMPT=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=y
+# CONFIG_IOMMU_HELPER is not set
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_HAS_WALK_MEMORY=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+# CONFIG_KEXEC is not set
+# CONFIG_CRASH_DUMP is not set
+# CONFIG_IRQ_ALL_CPUS is not set
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+# CONFIG_MIGRATION is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_PPC_4K_PAGES=y
+# CONFIG_PPC_16K_PAGES is not set
+# CONFIG_PPC_64K_PAGES is not set
+CONFIG_FORCE_MAX_ZONEORDER=11
+CONFIG_PROC_DEVICETREE=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600 root=/dev/ram0 ramdisk_size=64000"
+CONFIG_EXTRA_TARGETS=""
+# CONFIG_PM is not set
+CONFIG_SECCOMP=y
+CONFIG_ISA_DMA_API=y
+
+#
+# Bus options
+#
+CONFIG_ZONE_DMA=y
+CONFIG_GENERIC_ISA_DMA=y
+CONFIG_PPC_INDIRECT_PCI=y
+CONFIG_FSL_SOC=y
+CONFIG_FSL_PCI=y
+CONFIG_PPC_PCI_CHOICE=y
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+CONFIG_PCIEPORTBUS=y
+CONFIG_PCIEAER=y
+# CONFIG_PCIEASPM is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+# CONFIG_PCCARD is not set
+# CONFIG_HOTPLUG_PCI is not set
+# CONFIG_HAS_RAPIDIO is not set
+
+#
+# Advanced setup
+#
+CONFIG_ADVANCED_OPTIONS=y
+CONFIG_LOWMEM_SIZE_BOOL=y
+CONFIG_LOWMEM_SIZE=0x40000000
+CONFIG_PAGE_OFFSET_BOOL=y
+CONFIG_PAGE_OFFSET=0x80000000
+CONFIG_KERNEL_START_BOOL=y
+CONFIG_KERNEL_START=0x80000000
+CONFIG_PHYSICAL_START=0x00000000
+CONFIG_TASK_SIZE_BOOL=y
+CONFIG_TASK_SIZE=0x80000000
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=y
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# 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
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+CONFIG_INET_TUNNEL=y
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+CONFIG_IPV6=y
+# CONFIG_IPV6_PRIVACY is not set
+# CONFIG_IPV6_ROUTER_PREF is not set
+# CONFIG_IPV6_OPTIMISTIC_DAD is not set
+# CONFIG_INET6_AH is not set
+# CONFIG_INET6_ESP is not set
+# CONFIG_INET6_IPCOMP is not set
+# CONFIG_IPV6_MIP6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+CONFIG_INET6_XFRM_MODE_TRANSPORT=y
+CONFIG_INET6_XFRM_MODE_TUNNEL=y
+CONFIG_INET6_XFRM_MODE_BEET=y
+# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
+CONFIG_IPV6_SIT=y
+CONFIG_IPV6_NDISC_NODETYPE=y
+# CONFIG_IPV6_TUNNEL is not set
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETLABEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+# CONFIG_NF_CONNTRACK is not set
+# CONFIG_NETFILTER_XTABLES is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_DEFRAG_IPV4 is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
+
+#
+# IPv6: Netfilter Configuration
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# 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 is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_NET_TCPPROBE is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+CONFIG_MTD_CONCAT=y
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_OF_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+CONFIG_SSFDC=y
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+CONFIG_MTD_CFI=y
+CONFIG_MTD_JEDECPROBE=y
+CONFIG_MTD_GEN_PROBE=y
+CONFIG_MTD_CFI_ADV_OPTIONS=y
+CONFIG_MTD_CFI_NOSWAP=y
+# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set
+# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set
+CONFIG_MTD_CFI_GEOMETRY=y
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_OTP is not set
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_CFI_STAA=y
+CONFIG_MTD_CFI_UTIL=y
+# CONFIG_MTD_RAM is not set
+CONFIG_MTD_ROM=y
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_PHYSMAP_OF is not set
+# CONFIG_MTD_PCI is not set
+# CONFIG_MTD_INTEL_VR_NOR is not set
+# CONFIG_MTD_PLATRAM is not set
+CONFIG_MTD_MVME7100=y
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_PMC551 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_VERIFY_WRITE=y
+CONFIG_MTD_NAND_ECC_SMC=y
+# CONFIG_MTD_NAND_MUSEUM_IDS is not set
+CONFIG_MTD_NAND_MVME7100=y
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_CAFE is not set
+# CONFIG_MTD_NAND_NANDSIM is not set
+CONFIG_MTD_NAND_PLATFORM=y
+# CONFIG_MTD_ALAUDA is not set
+# CONFIG_MTD_NAND_FSL_ELBC is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+CONFIG_OF_DEVICE=y
+CONFIG_OF_I2C=y
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_FD is not set
+# 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_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+CONFIG_BLK_DEV_NBD=y
+# 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=131072
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+CONFIG_EEPROM_LEGACY=y
+# CONFIG_EEPROM_93CX6 is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+
+#
+# PCI IDE chipsets support
+#
+# CONFIG_BLK_DEV_GENERIC is not set
+# CONFIG_BLK_DEV_OPTI621 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 is not set
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+# CONFIG_BLK_DEV_PIIX is not set
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# 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_SL82C105 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_BLK_DEV_TC86C001 is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+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_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_SCAN_ASYNC=y
+# CONFIG_SCSI_WAIT_SCAN is not set
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# 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_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_SCSI_BUSLOGIC is not set
+# CONFIG_LIBFC is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_EATA is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GDTH is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_STEX 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 is not set
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_NSP32 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_DH is not set
+CONFIG_ATA=y
+# CONFIG_ATA_NONSTANDARD is not set
+# CONFIG_SATA_PMP is not set
+# CONFIG_SATA_AHCI is not set
+# CONFIG_SATA_SIL24 is not set
+# CONFIG_SATA_FSL is not set
+CONFIG_ATA_SFF=y
+# CONFIG_SATA_SVW is not set
+# CONFIG_ATA_PIIX is not set
+# CONFIG_SATA_MV is not set
+# CONFIG_SATA_NV is not set
+# CONFIG_PDC_ADMA is not set
+# CONFIG_SATA_QSTOR is not set
+# CONFIG_SATA_PROMISE is not set
+# CONFIG_SATA_SX4 is not set
+# CONFIG_SATA_SIL is not set
+# CONFIG_SATA_SIS is not set
+# CONFIG_SATA_ULI is not set
+# CONFIG_SATA_VIA is not set
+# CONFIG_SATA_VITESSE is not set
+# CONFIG_SATA_INIC162X is not set
+# CONFIG_PATA_ALI is not set
+# CONFIG_PATA_AMD is not set
+# CONFIG_PATA_ARTOP is not set
+# CONFIG_PATA_ATIIXP is not set
+# CONFIG_PATA_CMD640_PCI is not set
+# CONFIG_PATA_CMD64X is not set
+# CONFIG_PATA_CS5520 is not set
+# CONFIG_PATA_CS5530 is not set
+# CONFIG_PATA_CYPRESS is not set
+# CONFIG_PATA_EFAR is not set
+# CONFIG_ATA_GENERIC is not set
+# CONFIG_PATA_HPT366 is not set
+# CONFIG_PATA_HPT37X is not set
+# CONFIG_PATA_HPT3X2N is not set
+# CONFIG_PATA_HPT3X3 is not set
+# CONFIG_PATA_IT821X is not set
+# CONFIG_PATA_IT8213 is not set
+# CONFIG_PATA_JMICRON is not set
+# CONFIG_PATA_TRIFLEX is not set
+# CONFIG_PATA_MARVELL is not set
+# CONFIG_PATA_MPIIX is not set
+# CONFIG_PATA_OLDPIIX is not set
+# CONFIG_PATA_NETCELL is not set
+# CONFIG_PATA_NINJA32 is not set
+# CONFIG_PATA_NS87410 is not set
+# CONFIG_PATA_NS87415 is not set
+# CONFIG_PATA_OPTI is not set
+# CONFIG_PATA_OPTIDMA is not set
+# CONFIG_PATA_PDC_OLD is not set
+# CONFIG_PATA_RADISYS is not set
+# CONFIG_PATA_RZ1000 is not set
+# CONFIG_PATA_SC1200 is not set
+# CONFIG_PATA_SERVERWORKS is not set
+CONFIG_PATA_PDC2027X=y
+# CONFIG_PATA_SIL680 is not set
+# CONFIG_PATA_SIS is not set
+# CONFIG_PATA_VIA is not set
+# CONFIG_PATA_WINBOND is not set
+# CONFIG_PATA_PLATFORM is not set
+# CONFIG_PATA_SCH is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=y
+# CONFIG_MD_AUTODETECT is not set
+CONFIG_MD_LINEAR=y
+CONFIG_MD_RAID0=y
+CONFIG_MD_RAID1=y
+# CONFIG_MD_RAID10 is not set
+CONFIG_MD_RAID456=y
+CONFIG_MD_RAID5_RESHAPE=y
+CONFIG_MD_MULTIPATH=y
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=y
+# CONFIG_DM_DEBUG is not set
+# CONFIG_DM_CRYPT is not set
+CONFIG_DM_SNAPSHOT=y
+CONFIG_DM_MIRROR=y
+CONFIG_DM_ZERO=y
+CONFIG_DM_MULTIPATH=y
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_UEVENT is not set
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+# CONFIG_MACINTOSH_DRIVERS is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=y
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+CONFIG_BROADCOM_PHY=y
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+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
+# CONFIG_DNET is not set
+# CONFIG_NET_TULIP is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR 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_E100 is not set
+# 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_R6040 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+CONFIG_E1000E=y
+# CONFIG_IP1000 is not set
+# CONFIG_IGB 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_VIA_VELOCITY is not set
+# CONFIG_TIGON3 is not set
+# CONFIG_BNX2 is not set
+CONFIG_GIANFAR=y
+# CONFIG_MV643XX_ETH is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_ATL1C is not set
+# CONFIG_JME is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# 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_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_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_PCI is not set
+CONFIG_SERIAL_8250_NR_UARTS=5
+CONFIG_SERIAL_8250_RUNTIME_UARTS=5
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=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_UARTLITE is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_CONSOLE_POLL=y
+# CONFIG_SERIAL_JSM is not set
+# CONFIG_SERIAL_OF_PLATFORM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+# CONFIG_LEGACY_PTYS is not set
+# CONFIG_HVC_UDBG is not set
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+
+#
+# VME Bridge devices
+#
+CONFIG_VME_BRIDGE=y
+# CONFIG_VME_BRIDGE_BOOTMEM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=y
+# CONFIG_I2C_HELPER_AUTO is not set
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# 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_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_MPC=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 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_SPI is not set
+CONFIG_ARCH_WANT_OPTIONAL_GPIOLIB=y
+# CONFIG_GPIOLIB is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ADT7475 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S 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=y
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 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_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+# CONFIG_ALIM7101_WDT is not set
+# CONFIG_8xxx_WDT is not set
+CONFIG_MVME7100_WDT=y
+
+#
+# PCI-based Watchdog Cards
+#
+# CONFIG_PCIPCWATCHDOG is not set
+# CONFIG_WDTPCI is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_TWL4030_CORE is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_AGP is not set
+# CONFIG_DRM is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_COMPAT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+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
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_DEVICE_CLASS is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=y
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_EHCI_FSL is not set
+# CONFIG_USB_EHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_HCD_PPC_OF is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_UHCI_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD 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_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_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_EDAC is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+# CONFIG_RTC_DRV_DS1374 is not set
+CONFIG_RTC_DRV_DS1375=y
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# CONFIG_RTC_DRV_S35390A is not set
+# CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
+
+#
+# SPI RTC drivers
+#
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+# CONFIG_RTC_DRV_PPC is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+# CONFIG_STAGING is not set
+
+#
+# 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_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_EXT4_FS is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
+# CONFIG_XFS_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=y
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# 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_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+CONFIG_YAFFS_DOES_ECC=y
+# CONFIG_YAFFS_ECC_WRONG_ORDER is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED=y
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_CRAMFS is not set
+CONFIG_SQUASHFS=y
+# CONFIG_SQUASHFS_EMBEDDED is not set
+CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=y
+# CONFIG_NFSD_V3 is not set
+# CONFIG_NFSD_V4 is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+# 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
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# 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_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 is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+# CONFIG_NLS_CODEPAGE_437 is not set
+# 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 is not set
+CONFIG_NLS_ASCII=y
+# CONFIG_NLS_ISO8859_1 is not set
+# 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
+# CONFIG_DLM is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_HAVE_LMB=y
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS 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_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_HIGHMEM is not set
+# CONFIG_DEBUG_BUGVERBOSE is not set
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_KPROBES_SANITY_TEST is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_LKDTM is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_NOP_TRACER=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_HAVE_DYNAMIC_FTRACE=y
+CONFIG_HAVE_FTRACE_MCOUNT_RECORD=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+CONFIG_KGDB=y
+CONFIG_KGDB_SERIAL_CONSOLE=y
+# CONFIG_KGDB_TESTS is not set
+CONFIG_PRINT_STACK_DEPTH=64
+# CONFIG_DEBUG_STACKOVERFLOW is not set
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_PAGEALLOC is not set
+# CONFIG_CODE_PATCHING_SELFTEST is not set
+# CONFIG_FTR_FIXUP_SELFTEST is not set
+# CONFIG_MSI_BITMAP_SELFTEST is not set
+# CONFIG_XMON is not set
+CONFIG_DEBUGGER=y
+# CONFIG_IRQSTACKS is not set
+CONFIG_VIRQ_DEBUG=y
+CONFIG_BDI_SWITCH=y
+# CONFIG_BOOTX_TEXT is not set
+# CONFIG_PPC_EARLY_DEBUG is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+CONFIG_SECURITY=y
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_NETWORK is not set
+# CONFIG_SECURITY_PATH is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+# CONFIG_SECURITY_ROOTPLUG is not set
+CONFIG_SECURITY_DEFAULT_MMAP_MIN_ADDR=0
+CONFIG_XOR_BLOCKS=y
+CONFIG_ASYNC_CORE=y
+CONFIG_ASYNC_MEMCPY=y
+CONFIG_ASYNC_XOR=y
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_MANAGER2 is not set
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+# CONFIG_CRYPTO_DEV_TALITOS is not set
+# CONFIG_PPC_CLOCK is not set
+# CONFIG_VIRTUALIZATION is not set
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/include/asm/cpci6200_timer.h linux-2.6.29.6.mod/arch/powerpc/include/asm/cpci6200_timer.h
--- linux-2.6.29.6.orig/arch/powerpc/include/asm/cpci6200_timer.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/include/asm/cpci6200_timer.h	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,40 @@
+#ifndef __CPCI6200_TIMER_H
+#define __CPCI6200_TIMER_H
+
+#define CPCI6200_MIN_TIMER_NUMBER	0
+#define CPCI6200_MAX_TIMER_NUMBER	3
+
+#define MIN_TICKS_PER_MICROSECOND	1
+#define MAX_TICKS_PER_MICROSECOND	25
+
+typedef void (*cpci6200_timer_f) (void *data);
+
+/* 
+ * Start a timer
+ * Call func(data) after so many microsecoonds
+ * The function will be called in interrupt context.
+ */
+int cpci6200_timer_start(int timer_number, unsigned long microseconds, 
+			cpci6200_timer_f func, void *data, int periodic);
+
+/* 
+ * Stop a timer
+ */
+int cpci6200_timer_stop(int timer_number);
+
+/* 
+ * Get the timer resolution, in microseconds/tick
+ */
+unsigned long cpci6200_timer_get_resolution(void);
+
+/* 
+ * Set the timer resolution, in ticks/microseconds
+ */
+int cpci6200_timer_set_resolution(unsigned long ticks);
+
+/* 
+ * Get a timer counter value, in ticks
+ */
+unsigned long cpci6200_timer_get_ticks(int timer_number);
+
+#endif /* __CPCI6200_TIMER_H */
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/include/asm/mvme3100_timer.h linux-2.6.29.6.mod/arch/powerpc/include/asm/mvme3100_timer.h
--- linux-2.6.29.6.orig/arch/powerpc/include/asm/mvme3100_timer.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/include/asm/mvme3100_timer.h	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,41 @@
+#ifndef __MVME3100_TIMER_H
+#define __MVME3100_TIMER_H
+
+
+#define MVME3100_MIN_TIMER_NUMBER	0
+#define MVME3100_MAX_TIMER_NUMBER	3
+
+#define MIN_TICKS_PER_MICROSECOND	1
+#define MAX_TICKS_PER_MICROSECOND	25
+
+typedef void (*mvme3100_timer_f) (void *data);
+
+/* 
+ * Start a timer
+ * Call func(data) after so many microsecoonds
+ * The function will be called in interrupt context.
+ */
+int mvme3100_timer_start(int timer_number, unsigned long microseconds, 
+			mvme3100_timer_f func, void *data, int periodic);
+
+/* 
+ * Stop a timer
+ */
+int mvme3100_timer_stop(int timer_number);
+
+/* 
+ * Get the timer resolution, in microseconds/tick
+ */
+unsigned long mvme3100_timer_get_resolution(void);
+
+/* 
+ * Set the timer resolution, in ticks/microseconds
+ */
+int mvme3100_timer_set_resolution(unsigned long ticks);
+
+/* 
+ * Get a timer counter value, in ticks
+ */
+unsigned long mvme3100_timer_get_ticks(int timer_number);
+
+#endif /* __MVME3100_TIMER_H */
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/include/asm/mvme4100_timer.h linux-2.6.29.6.mod/arch/powerpc/include/asm/mvme4100_timer.h
--- linux-2.6.29.6.orig/arch/powerpc/include/asm/mvme4100_timer.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/include/asm/mvme4100_timer.h	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,40 @@
+#ifndef __MVME4100_TIMER_H
+#define __MVME4100_TIMER_H
+
+#define MVME4100_MIN_TIMER_NUMBER	0
+#define MVME4100_MAX_TIMER_NUMBER	3
+
+#define MIN_TICKS_PER_MICROSECOND	1
+#define MAX_TICKS_PER_MICROSECOND	25
+
+typedef void (*mvme4100_timer_f) (void *data);
+
+/* 
+ * Start a timer
+ * Call func(data) after so many microsecoonds
+ * The function will be called in interrupt context.
+ */
+int mvme4100_timer_start(int timer_number, unsigned long microseconds, 
+			mvme4100_timer_f func, void *data, int periodic);
+
+/* 
+ * Stop a timer
+ */
+int mvme4100_timer_stop(int timer_number);
+
+/* 
+ * Get the timer resolution, in microseconds/tick
+ */
+unsigned long mvme4100_timer_get_resolution(void);
+
+/* 
+ * Set the timer resolution, in ticks/microseconds
+ */
+int mvme4100_timer_set_resolution(unsigned long ticks);
+
+/* 
+ * Get a timer counter value, in ticks
+ */
+unsigned long mvme4100_timer_get_ticks(int timer_number);
+
+#endif /* __MVME4100_TIMER_H */
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/include/asm/mvme7100_timer.h linux-2.6.29.6.mod/arch/powerpc/include/asm/mvme7100_timer.h
--- linux-2.6.29.6.orig/arch/powerpc/include/asm/mvme7100_timer.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/include/asm/mvme7100_timer.h	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,40 @@
+#ifndef __MVME7100_TIMER_H
+#define __MVME7100_TIMER_H
+
+#define MVME7100_MIN_TIMER_NUMBER	0
+#define MVME7100_MAX_TIMER_NUMBER	3
+
+#define MIN_TICKS_PER_MICROSECOND	1
+#define MAX_TICKS_PER_MICROSECOND	25
+
+typedef void (*mvme7100_timer_f) (void *data);
+
+/* 
+ * Start a timer
+ * Call func(data) after so many microsecoonds
+ * The function will be called in interrupt context.
+ */
+int mvme7100_timer_start(int timer_number, unsigned long microseconds, 
+			mvme7100_timer_f func, void *data, int periodic);
+
+/* 
+ * Stop a timer
+ */
+int mvme7100_timer_stop(int timer_number);
+
+/* 
+ * Get the timer resolution, in microseconds/tick
+ */
+unsigned long mvme7100_timer_get_resolution(void);
+
+/* 
+ * Set the timer resolution, in ticks/microseconds
+ */
+int mvme7100_timer_set_resolution(unsigned long ticks);
+
+/* 
+ * Get a timer counter value, in ticks
+ */
+unsigned long mvme7100_timer_get_ticks(int timer_number);
+
+#endif /* __MVME7100_TIMER_H */
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/include/asm/reg_booke.h linux-2.6.29.6.mod/arch/powerpc/include/asm/reg_booke.h
--- linux-2.6.29.6.orig/arch/powerpc/include/asm/reg_booke.h	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/include/asm/reg_booke.h	2009-07-21 11:28:17.000000000 -0700
@@ -387,12 +387,14 @@
 #define ICCR_CACHE	1		/* Cacheable */
 
 /* Bit definitions for L1CSR0. */
+#define L1CSR0_DCPE     0x00010000      /* Data Cache Parity Enable */
 #define L1CSR0_CLFC	0x00000100	/* Cache Lock Bits Flash Clear */
 #define L1CSR0_DCFI	0x00000002	/* Data Cache Flash Invalidate */
 #define L1CSR0_CFI	0x00000002	/* Cache Flash Invalidate */
 #define L1CSR0_DCE	0x00000001	/* Data Cache Enable */
 
 /* Bit definitions for L1CSR1. */
+#define L1CSR1_ICPE     0x00010000      /* Instr Cache Parity Enable */
 #define L1CSR1_ICLFR	0x00000100	/* Instr Cache Lock Bits Flash Reset */
 #define L1CSR1_ICFI	0x00000002	/* Instr Cache Flash Invalidate */
 #define L1CSR1_ICE	0x00000001	/* Instr Cache Enable */
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/kernel/head_fsl_booke.S linux-2.6.29.6.mod/arch/powerpc/kernel/head_fsl_booke.S
--- linux-2.6.29.6.orig/arch/powerpc/kernel/head_fsl_booke.S	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/kernel/head_fsl_booke.S	2009-07-21 11:28:17.000000000 -0700
@@ -1052,6 +1052,94 @@
 	blr
 
 #ifdef CONFIG_SMP
+
+/* To boot secondary cpus, we need a place for them to start up.
+ * Normally, they start at 0xfffffffc, but that's usually the
+ * firmware, and we don't want to have to run the firmware again.
+ * Instead, the primary cpu will set the BPTR to point here to
+ * this page.  We then set up the core, and head to
+ * start_secondary.  Note that this means that the code below
+ * must never exceed 1023 instructions (the branch at the end
+ * would then be the 1024th).
+ */
+        .globl  __secondary_start_page
+        .align  12
+__secondary_start_page:
+/* First do some preliminary setup */
+        lis     r3, HID0_EMCP@h         /* enable machine check */
+        ori     r3,r3,0x4000       /* enable Timebase */
+#ifdef CONFIG_PHYS_64BIT
+        ori     r3,r3,0x0080     /* enable MAS7 updates */
+#endif
+        mtspr   SPRN_HID0,r3
+
+#if 1
+        mfspr   r3, SPRN_TCR
+        oris    r3,r3, TCR_DIE@h /* Enable the Decrementer Interrupt */
+        mtspr   SPRN_TCR,r3
+#endif
+
+	li	r3,0x3000
+        mtspr   SPRN_HID1,r3
+
+        /* Enable branch prediction */
+        li      r3,0x201
+        mtspr   SPRN_BUCSR,r3
+
+        /* Enable/invalidate the I-Cache */
+        mfspr   r0,SPRN_L1CSR1
+        ori     r0,r0,(L1CSR1_ICFI|L1CSR1_ICE)
+        oris    r0,r0,L1CSR1_ICPE@h
+        mtspr   SPRN_L1CSR1,r0
+        isync
+
+        /* Enable/invalidate the D-Cache */
+        mfspr   r0,SPRN_L1CSR0
+        ori     r0,r0,(L1CSR0_DCFI|L1CSR0_DCE)
+        oris    r0,r0,L1CSR0_DCPE@h
+        msync
+        isync
+        mtspr   SPRN_L1CSR0,r0
+        isync
+
+/*
+ * Coming here, we know the cpu has one TLB mapping in TLB1[0]
+ * which maps 0xfffff000-0xffffffff one-to-one.  We set up a
+ * second mapping that maps addr 1:1 for 64M, and then we jump to
+ * __early_start
+ */
+
+        lis     r10,(MAS0_TLBSEL(1)|MAS0_ESEL(1))@h
+        mtspr   SPRN_MAS0,r10
+        lis     r10,(MAS1_VALID|MAS1_IPROT)@h
+        ori     r10,r10,(MAS1_TSIZE(BOOKE_PAGESZ_64M))@l
+        mtspr   SPRN_MAS1,r10
+        /* WIMGE = 0b00000 for now */
+        li      r6,0x0
+        mtspr   SPRN_MAS2,r6    /* EPN is 0 */
+        lis     r7,0x0    /* RPN is 0 */
+        ori     r7,r7,(MAS3_SX|MAS3_SW|MAS3_SR)
+        mtspr   SPRN_MAS3,r7
+#ifdef CONFIG_ENABLE_36BIT_PHYS
+        li      r11,0
+        mtspr   SPRN_MAS7,r11
+#endif
+        tlbwe
+	isync
+
+/* Now we have another mapping for this page, so we jump to that
+ * mapping
+ */
+	mfmsr	r4
+        lis     r7,__early_start@h
+        ori     r7,r7,__early_start@l
+        rlwinm  r7,r7,0,20,31
+        mtspr   SPRN_SRR0,r7
+        mtspr   SPRN_SRR1,r4
+        rfi
+
+
+
 /* When we get here, r24 needs to hold the CPU # */
 	.globl __secondary_start
 __secondary_start:
@@ -1063,6 +1151,7 @@
 	mr	r4,r24		/* Why? */
 	bl	call_setup_cpu
 
+#if 0
 	lis	r3,tlbcam_index@ha
 	lwz	r3,tlbcam_index@l(r3)
 	mtctr	r3
@@ -1073,6 +1162,28 @@
 	bl	loadcam_entry
 	addi	r26,r26,1
 	bdnz	1b
+#else
+        /* r26 should be safe, here */
+        lis     r26, tlbcam_index@ha
+        lwz     r26, tlbcam_index@l(r26)
+
+        /* Load CAM 0 */
+        li      r3,0
+        bl      loadcam_entry
+
+        /* Load CAM 1, if it's set */
+        li      r3,1
+        cmpw    r3,r26
+        bgt     1f
+        bl      loadcam_entry
+1:
+        /* Load CAM 2, if it's set */
+        li      r3,2
+        cmpw    r3,r26
+        bgt     2f
+        bl      loadcam_entry
+2:
+#endif
 
 	/* get current_thread_info and current */
 	lis	r1,secondary_ti@ha
@@ -1106,6 +1217,14 @@
 	.globl __secondary_hold_acknowledge
 __secondary_hold_acknowledge:
 	.long	-1
+
+        /* Fill in the empty space.  The actual reset vector is
+         * the last word of the page */
+__secondary_start_code_end:
+        .space 4092 - (__secondary_start_code_end - __secondary_start_page)
+__secondary_reset_vector:
+        b       __secondary_start_page
+
 #endif
 
 /*
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/kernel/io.c linux-2.6.29.6.mod/arch/powerpc/kernel/io.c
--- linux-2.6.29.6.orig/arch/powerpc/kernel/io.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/kernel/io.c	2009-07-21 11:28:17.000000000 -0700
@@ -161,7 +161,7 @@
 		dest++;
 		n--;
 	}
-	while(n > 4) {
+	while(n >= 4) {
 		*((u32 *)dest) = *((volatile u32 *)vsrc);
 		eieio();
 		vsrc += 4;
@@ -190,7 +190,7 @@
 		vdest++;
 		n--;
 	}
-	while(n > 4) {
+	while(n >= 4) {
 		*((volatile u32 *)vdest) = *((volatile u32 *)src);
 		src += 4;
 		vdest += 4;
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/kernel/legacy_serial.c linux-2.6.29.6.mod/arch/powerpc/kernel/legacy_serial.c
--- linux-2.6.29.6.orig/arch/powerpc/kernel/legacy_serial.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/kernel/legacy_serial.c	2009-07-21 11:28:17.000000000 -0700
@@ -164,6 +164,33 @@
 		return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags, 0);
 }
 
+static int __init add_legacy_board_port(struct device_node *np)
+{
+        u64 addr;
+        const u32 *addrp;
+        upf_t flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST | UPF_SHARE_IRQ;
+
+        /* We only support ports that have a clock frequency properly
+         * encoded in the device-tree.
+         */
+        if (of_get_property(np, "clock-frequency", NULL) == NULL)
+                return -1;
+
+        /* Get the address */
+        addrp = of_get_address(np, 0, NULL, NULL);
+        if (addrp == NULL)
+                return -1;
+
+        addr = of_translate_address(np, addrp);
+        if (addr == OF_BAD_ADDR)
+                return -1;
+
+        /* Add port, irq will be dealt with later. We passed a translated
+         * IO port value. It will be fixed up later along with the irq
+         */
+        return add_legacy_port(np, -1, UPIO_MEM, addr, addr, NO_IRQ, flags, 0);
+}
+
 static int __init add_legacy_isa_port(struct device_node *np,
 				      struct device_node *isa_brg)
 {
@@ -332,7 +359,8 @@
 			index = add_legacy_soc_port(np, np);
 			if (index >= 0 && np == stdout)
 				legacy_serial_console = index;
-		}
+		} else 
+			index = add_legacy_board_port(np);
 		of_node_put(parent);
 	}
 
@@ -484,6 +512,8 @@
 			fixup_port_pio(i, np, port);
 		if ((port->iotype == UPIO_MEM) || (port->iotype == UPIO_TSI))
 			fixup_port_mmio(i, np, port);
+                udbg_init_uart(port->membase, legacy_serial_infos[i].speed,
+                                legacy_serial_infos[i].clock);
 	}
 
 	DBG("Registering platform serial ports\n");
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/kernel/pci-common.c linux-2.6.29.6.mod/arch/powerpc/kernel/pci-common.c
--- linux-2.6.29.6.orig/arch/powerpc/kernel/pci-common.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/kernel/pci-common.c	2009-07-21 11:28:17.000000000 -0700
@@ -740,7 +740,8 @@
 				size = 0x01000000;
 
 			/* 32 bits needs to map IOs here */
-			hose->io_base_virt = ioremap(cpu_addr, size);
+//			hose->io_base_virt = ioremap(cpu_addr, size);
+			hose->io_base_virt = (void __iomem *)(u32)cpu_addr;
 
 			/* Expect trouble if pci_addr is not 0 */
 			if (primary)
@@ -1290,7 +1291,7 @@
 			if (reparent_resources(pr, res) == 0)
 				continue;
 		}
-		printk(KERN_WARNING "PCI: Cannot allocate resource region "
+		printk(KERN_DEBUG "PCI: Cannot allocate resource region "
 		       "%d of PCI bridge %d, will remap\n", i, bus->number);
 clear_resource:
 		res->flags = 0;
@@ -1313,7 +1314,7 @@
 	pr = pci_find_parent_resource(dev, r);
 	if (!pr || (pr->flags & IORESOURCE_UNSET) ||
 	    request_resource(pr, r) < 0) {
-		printk(KERN_WARNING "PCI: Cannot allocate resource region %d"
+		printk(KERN_DEBUG "PCI: Cannot allocate resource region %d"
 		       " of device %s, will remap\n", idx, pci_name(dev));
 		if (pr)
 			pr_debug("PCI:  parent is %p: %016llx-%016llx [%x]\n",
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/kernel/setup_32.c linux-2.6.29.6.mod/arch/powerpc/kernel/setup_32.c
--- linux-2.6.29.6.orig/arch/powerpc/kernel/setup_32.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/kernel/setup_32.c	2009-07-21 11:28:17.000000000 -0700
@@ -322,7 +322,7 @@
 
 	/* set up the bootmem stuff with available memory */
 	do_init_bootmem();
-	if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
+//	if ( ppc_md.progress ) ppc_md.progress("setup_arch: bootmem", 0x3eab);
 
 #ifdef CONFIG_DUMMY_CONSOLE
 	conswitchp = &dummy_con;
@@ -330,7 +330,7 @@
 
 	if (ppc_md.setup_arch)
 		ppc_md.setup_arch();
-	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
+//	if ( ppc_md.progress ) ppc_md.progress("arch: exit", 0x3eab);
 
 	paging_init();
 
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/kernel/vmlinux.lds.S linux-2.6.29.6.mod/arch/powerpc/kernel/vmlinux.lds.S
--- linux-2.6.29.6.orig/arch/powerpc/kernel/vmlinux.lds.S	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/kernel/vmlinux.lds.S	2009-07-21 11:28:17.000000000 -0700
@@ -268,6 +268,7 @@
 		*(.data.page_aligned)
 	}
 
+	. = ALIGN(L1_CACHE_BYTES);
 	.data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) {
 		*(.data.cacheline_aligned)
 	}
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/mm/mmu_context_nohash.c linux-2.6.29.6.mod/arch/powerpc/mm/mmu_context_nohash.c
--- linux-2.6.29.6.orig/arch/powerpc/mm/mmu_context_nohash.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/mm/mmu_context_nohash.c	2009-08-03 10:46:54.000000000 -0700
@@ -46,7 +46,7 @@
 static unsigned long *context_map;
 static unsigned long *stale_map[NR_CPUS];
 static struct mm_struct **context_mm;
-static spinlock_t context_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(context_lock);
 
 #define CTX_MAP_SIZE	\
 	(sizeof(unsigned long) * (last_context / BITS_PER_LONG + 1))
@@ -73,7 +73,6 @@
 	struct mm_struct *mm;
 	unsigned int cpu, max;
 
- again:
 	max = last_context - first_context;
 
 	/* Attempt to free next_context first and then loop until we manage */
@@ -108,7 +107,9 @@
 	spin_unlock(&context_lock);
 	cpu_relax();
 	spin_lock(&context_lock);
-	goto again;
+
+	/* This will cause the caller to try again */
+	return MMU_NO_CONTEXT;
 }
 #endif  /* CONFIG_SMP */
 
@@ -127,12 +128,12 @@
 
 	pr_debug("[%d] steal context %d from mm @%p\n", cpu, id, mm);
 
-	/* Mark this mm has having no context anymore */
-	mm->context.id = MMU_NO_CONTEXT;
-
 	/* Flush the TLB for that context */
 	local_flush_tlb_mm(mm);
 
+	/* Mark this mm has having no context anymore */
+	mm->context.id = MMU_NO_CONTEXT;
+
 	/* XXX This clear should ultimately be part of local_flush_tlb_mm */
 	__clear_bit(id, stale_map[cpu]);
 
@@ -194,6 +195,8 @@
 		WARN_ON(prev->context.active < 1);
 		prev->context.active--;
 	}
+
+ again:
 #endif /* CONFIG_SMP */
 
 	/* If we already have a valid assigned context, skip all that */
@@ -212,7 +215,9 @@
 #ifdef CONFIG_SMP
 		if (num_online_cpus() > 1) {
 			id = steal_context_smp(id);
-			goto stolen;
+			if (id == MMU_NO_CONTEXT)
+				goto again;
+		goto stolen;
 		}
 #endif /* CONFIG_SMP */
 		id = steal_context_up(id);
@@ -272,6 +277,7 @@
  */
 void destroy_context(struct mm_struct *mm)
 {
+	unsigned long flags;
 	unsigned int id;
 
 	if (mm->context.id == MMU_NO_CONTEXT)
@@ -279,18 +285,18 @@
 
 	WARN_ON(mm->context.active != 0);
 
-	spin_lock(&context_lock);
+	spin_lock_irqsave(&context_lock, flags);
 	id = mm->context.id;
 	if (id != MMU_NO_CONTEXT) {
 		__clear_bit(id, context_map);
 		mm->context.id = MMU_NO_CONTEXT;
 #ifdef DEBUG_MAP_CONSISTENCY
 		mm->context.active = 0;
-		context_mm[id] = NULL;
 #endif
+		context_mm[id] = NULL;
 		nr_free_contexts++;
 	}
-	spin_unlock(&context_lock);
+	spin_unlock_irqrestore(&context_lock, flags);
 }
 
 #ifdef CONFIG_SMP
@@ -380,7 +386,7 @@
 #endif
 
 	printk(KERN_INFO
-	       "MMU: Allocated %d bytes of context maps for %d contexts\n",
+	       "MMU: Allocated %zu bytes of context maps for %d contexts\n",
 	       2 * CTX_MAP_SIZE + (sizeof(void *) * (last_context + 1)),
 	       last_context - first_context + 1);
 
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/cpci6200.c linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/cpci6200.c
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/cpci6200.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/cpci6200.c	2009-09-02 10:31:31.000000000 -0700
@@ -0,0 +1,1868 @@
+/*
+ * CPCI6200 setup and early boot code plus other random bits.
+ *
+ * Author: Ajit Prem
+ *
+ * Copyright 2008 Emerson Network Power Embedded Computing, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/root_dev.h>
+#include <linux/rtc.h>
+#include <linux/highmem.h>
+#include <linux/fsl_devices.h>
+#include <linux/of_platform.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/irq.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/kmap_types.h>
+#include <asm/edac.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+
+#include "cpci6200.h"
+
+extern unsigned long isa_io_base;
+
+static unsigned long hb_baddr;
+static	void __iomem *system_control_reg_addr;
+static int serial_irq;
+
+static void __iomem *l2_err_regs;
+
+#define L2_ERR_REGS_OFFSET      0x20E20
+#define L2_ERR_REGS_SIZE        0x3C
+
+#define L2_CAPT_DATA_HI         0x20E20
+#define L2_CAPT_DATA_LO         0x20E24
+#define L2_CAPT_ECC             0x20E28
+#define L2_ERR_DET              0x20E40
+#define L2_ERR_DIS              0x20E44
+#define L2_ERR_INT_EN           0x20E48
+#define L2_ERR_ATTR             0x20E4C
+#define L2_ERR_ADDR_HI          0x20E50
+#define L2_ERR_ADDR_LO          0x20E54
+#define L2_ERR_CTL              0x20E58
+
+#ifdef CONFIG_CPCI6200_ENABLE_L2_ERRORS
+static int l2_irq;
+static irqreturn_t cpci6200_l2cache_err_handler(int irq, void *dev_id);
+#endif
+
+#ifdef CONFIG_CPCI6200_ENABLE_DDR_ERRORS
+
+#define DDR1_REGS_OFFSET     	0x2000
+#define DDR2_REGS_OFFSET     	0x6000
+#define DDR_ERR_REGS_OFFSET     0xE00
+#define DDR_ERR_REGS_SIZE       0x5C
+
+#define DDR_CAPT_DATA_HI        0xE20
+#define DDR_CAPT_DATA_LO        0xE24
+#define DDR_CAPT_ECC            0xE28
+#define DDR_ERR_DET             0xE40
+#define DDR_ERR_DIS             0xE44
+#define DDR_ERR_INT_EN          0xE48
+#define DDR_CAPT_ATTR           0xE4C
+#define DDR_CAPT_ADDR           0xE50
+#define DDR_CAPT_EXT_ADDR       0xE54
+#define DDR_ERR_SBE             0xE58
+
+#define DDR_SBE                 0x4	/* single-bit ECC error */
+#define DDR_MBE                 0x8	/* multi-bit ECC error */
+#define DDR_MME                 0x80000000	/* multiple ECC error */
+
+static int ddr1_errors;
+static int ddr2_errors;
+static void __iomem *ddr1_err_regs;
+static void __iomem *ddr2_err_regs;
+static int ddr_irq;
+static irqreturn_t cpci6200_ddr_err_handler(int irq, void *dev_id);
+
+#endif
+
+#define PCI1_REGS_OFFSET	0x9000
+#define PCI2_REGS_OFFSET	0xA000
+#define PCI_ERR_REGS_OFFSET     0xE00
+#define PCI_ERR_REGS_SIZE       0x38
+
+#define PCI_ERR_DET             0xE00
+#define PCI_ERR_INT_EN          0xE08
+#define PCI_ERR_CAP_DIS         0xE10
+#define PCI_ERR_CAP_STAT        0xE20
+#define PCI_ERR_CAP_R0          0xE28
+#define PCI_ERR_CAP_R1          0xE2C
+#define PCI_ERR_CAP_R2          0xE30
+#define PCI_ERR_CAP_R3          0xE34
+
+static int pci1_irq;
+static int pci2_irq;
+
+#ifdef CONFIG_CPCI6200_ENABLE_PCI_ERRORS
+static int pci1_errors;
+static void __iomem *pci1_err_regs;
+static irqreturn_t cpci6200_pci1_err_handler(int irq, void *dev_id);
+
+static int pci2_errors;
+static void __iomem *pci2_err_regs;
+static irqreturn_t cpci6200_pci2_err_handler(int irq, void *dev_id);
+#endif
+
+#ifdef CONFIG_CPCI6200_TICK_TIMERS
+int cpci6200_timer_irq;
+#endif
+
+#ifdef CONFIG_SENSORS_LM90
+int maxim6649_irq;
+#endif
+
+#ifdef CONFIG_CPCI6200_ENABLE_DDR_ERRORS
+
+static void cpci6200_determine_bit_location(u32 data_hi, u32 data_lo,
+					    u32 stored_ecc)
+{
+	u32 syndrome_bits;
+	u32 syndrome[8];
+	u32 calculated_ecc = 0;
+	int i;
+	u32 data0[32], data1[32];
+	unsigned char bitpos[8];
+
+	/* Initial 32-bit data */
+	for (i = 0; i < 32; i++) {
+		data0[i] = (data_hi >> (31 - i)) & 0x1;
+		data1[i] = (data_lo >> (31 - i)) & 0x1;
+	}
+
+	for (i = 0; i < 8; i++)
+		syndrome[i] = 0;
+	/* Calculate 8-bit ECC for the first 32-bit data */
+	for (i = 0; i < 32; ++i) {
+		/* Calculate syndrome[0] */
+		if ((i <= 15) || (i == 19) || (i == 23) || (i == 27) ||
+		    (i == 31))
+			syndrome[0] = syndrome[0] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[1] */
+		if ((i == 0) || (i == 4) || (i == 8) || (i == 12) || (i >= 16))
+			syndrome[1] = syndrome[1] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[2] */
+		if ((i == 1) || (i == 5) || (i == 9) || (i == 13) ||
+		    (i == 16) || (i == 20) || (i == 24) || (i == 28))
+			syndrome[2] = syndrome[2] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[3] */
+		if ((i == 2) || (i == 6) || (i == 10) || (i == 14) ||
+		    (i == 17) || (i == 21) || (i == 25) || (i == 29))
+			syndrome[3] = syndrome[3] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[4] */
+		if ((i == 3) || (i == 7) || (i == 11) || (i == 15) ||
+		    (i == 18) || (i == 19) || (i == 22) || (i == 23) ||
+		    (i == 26) || (i == 27) || (i == 30) || (i == 31))
+			syndrome[4] = syndrome[4] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[5] */
+		if (((i >= 4) && (i <= 7)) || ((i >= 12) && (i <= 15)) ||
+		    ((i >= 20) && (i <= 23)) || ((i >= 28) && (i <= 31)))
+			syndrome[5] = syndrome[5] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[6] */
+		if (((i >= 8) && (i <= 15)) || ((i >= 24) && (i <= 31)))
+			syndrome[6] = syndrome[6] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[7] */
+		if ((i <= 3) || ((i >= 12) && (i <= 18)) ||
+		    (i == 23) || ((i >= 27) && (i <= 30)))
+			syndrome[7] = syndrome[7] ^ (data0[i] & 0x1);
+	}
+
+	/* Calculate 8-bit ECC for the second 32-bit data */
+	for (i = 0; i < 32; ++i) {
+		/* Calculate syndrome[0] */
+		if ((i == 2) || (i == 6) || (i == 10) || (i == 14) ||
+		    (i == 19) || (i == 23) || (i == 27) || (i == 29))
+			syndrome[0] = syndrome[0] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[1] */
+		if ((i == 3) || (i == 7) || (i == 11) || (i == 15) ||
+		    (i == 16) || (i == 20) || (i == 24) || (i == 30))
+			syndrome[1] = syndrome[1] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[2] */
+		if ((i <= 15) || (i == 17) || (i == 21) || (i == 25) |
+		    (i == 31))
+			syndrome[2] = syndrome[2] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[3] */
+		if ((i == 0) || (i == 4) || (i == 8) || (i == 12) ||
+		    (i == 18) || (i == 22) || (i == 26) || (i >= 28))
+			syndrome[3] = syndrome[3] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[4] */
+		if (((i >= 1) && (i <= 3)) || ((i >= 5) && (i <= 7)) ||
+		    ((i >= 9) && (i <= 11)) || ((i >= 13) && (i <= 15)) ||
+		    ((i >= 28) && (i <= 31)))
+			syndrome[4] = syndrome[4] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[5] */
+		if (((i >= 4) && (i <= 7)) || ((i >= 12) && (i <= 23)))
+			syndrome[5] = syndrome[5] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[6] */
+		if (((i >= 8) && (i <= 19)) || ((i >= 24) && (i <= 31)))
+			syndrome[6] = syndrome[6] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[7] */
+		if ((i == 0) || (i == 1) || (i == 6) || (i == 7) ||
+		    ((i >= 10) && (i <= 13)) || ((i >= 20) && (i <= 27)) ||
+		    ((i >= 29) && (i <= 31)))
+			syndrome[7] = syndrome[7] ^ (data1[i] & 0x1);
+	}
+
+	calculated_ecc = ((syndrome[7] << 0) | (syndrome[6] << 1) |
+			  (syndrome[5] << 2) | (syndrome[4] << 3) |
+			  (syndrome[3] << 4) | (syndrome[2] << 5) |
+			  (syndrome[1] << 6) | (syndrome[0] << 7));
+
+	syndrome_bits = calculated_ecc ^ stored_ecc;
+
+	switch (syndrome_bits) {
+	case 0xC1:
+		sprintf(bitpos, "%s", "0");
+		break;
+	case 0xA1:
+		sprintf(bitpos, "%s", "1");
+		break;
+	case 0x91:
+		sprintf(bitpos, "%s", "2");
+		break;
+	case 0x89:
+		sprintf(bitpos, "%s", "3");
+		break;
+	case 0xC4:
+		sprintf(bitpos, "%s", "4");
+		break;
+	case 0xA4:
+		sprintf(bitpos, "%s", "5");
+		break;
+	case 0x94:
+		sprintf(bitpos, "%s", "6");
+		break;
+	case 0x8C:
+		sprintf(bitpos, "%s", "7");
+		break;
+	case 0xC2:
+		sprintf(bitpos, "%s", "8");
+		break;
+	case 0xA2:
+		sprintf(bitpos, "%s", "9");
+		break;
+	case 0x92:
+		sprintf(bitpos, "%s", "10");
+		break;
+	case 0x8A:
+		sprintf(bitpos, "%s", "11");
+		break;
+	case 0xC7:
+		sprintf(bitpos, "%s", "12");
+		break;
+	case 0xA7:
+		sprintf(bitpos, "%s", "13");
+		break;
+	case 0x97:
+		sprintf(bitpos, "%s", "14");
+		break;
+	case 0x8F:
+		sprintf(bitpos, "%s", "15");
+		break;
+	case 0x61:
+		sprintf(bitpos, "%s", "16");
+		break;
+	case 0x51:
+		sprintf(bitpos, "%s", "17");
+		break;
+	case 0x49:
+		sprintf(bitpos, "%s", "18");
+		break;
+	case 0xC8:
+		sprintf(bitpos, "%s", "19");
+		break;
+	case 0x64:
+		sprintf(bitpos, "%s", "20");
+		break;
+	case 0x54:
+		sprintf(bitpos, "%s", "21");
+		break;
+	case 0x4C:
+		sprintf(bitpos, "%s", "22");
+		break;
+	case 0xCD:
+		sprintf(bitpos, "%s", "23");
+		break;
+	case 0x62:
+		sprintf(bitpos, "%s", "24");
+		break;
+	case 0x52:
+		sprintf(bitpos, "%s", "25");
+		break;
+	case 0x4A:
+		sprintf(bitpos, "%s", "26");
+		break;
+	case 0xCB:
+		sprintf(bitpos, "%s", "27");
+		break;
+	case 0x67:
+		sprintf(bitpos, "%s", "28");
+		break;
+	case 0x57:
+		sprintf(bitpos, "%s", "29");
+		break;
+	case 0x4F:
+		sprintf(bitpos, "%s", "30");
+		break;
+	case 0xCE:
+		sprintf(bitpos, "%s", "31");
+		break;
+	case 0x31:
+		sprintf(bitpos, "%s", "32");
+		break;
+	case 0x29:
+		sprintf(bitpos, "%s", "33");
+		break;
+	case 0xA8:
+		sprintf(bitpos, "%s", "34");
+		break;
+	case 0x68:
+		sprintf(bitpos, "%s", "35");
+		break;
+	case 0x34:
+		sprintf(bitpos, "%s", "36");
+		break;
+	case 0x2C:
+		sprintf(bitpos, "%s", "37");
+		break;
+	case 0xAD:
+		sprintf(bitpos, "%s", "38");
+		break;
+	case 0x6D:
+		sprintf(bitpos, "%s", "39");
+		break;
+	case 0x32:
+		sprintf(bitpos, "%s", "40");
+		break;
+	case 0x2A:
+		sprintf(bitpos, "%s", "41");
+		break;
+	case 0xAB:
+		sprintf(bitpos, "%s", "42");
+		break;
+	case 0x6B:
+		sprintf(bitpos, "%s", "43");
+		break;
+	case 0x37:
+		sprintf(bitpos, "%s", "44");
+		break;
+	case 0x2F:
+		sprintf(bitpos, "%s", "45");
+		break;
+	case 0xAE:
+		sprintf(bitpos, "%s", "46");
+		break;
+	case 0x6E:
+		sprintf(bitpos, "%s", "47");
+		break;
+	case 0x46:
+		sprintf(bitpos, "%s", "48");
+		break;
+	case 0x26:
+		sprintf(bitpos, "%s", "49");
+		break;
+	case 0x16:
+		sprintf(bitpos, "%s", "50");
+		break;
+	case 0x86:
+		sprintf(bitpos, "%s", "51");
+		break;
+	case 0x45:
+		sprintf(bitpos, "%s", "52");
+		break;
+	case 0x25:
+		sprintf(bitpos, "%s", "53");
+		break;
+	case 0x15:
+		sprintf(bitpos, "%s", "54");
+		break;
+	case 0x85:
+		sprintf(bitpos, "%s", "55");
+		break;
+	case 0x43:
+		sprintf(bitpos, "%s", "56");
+		break;
+	case 0x23:
+		sprintf(bitpos, "%s", "57");
+		break;
+	case 0x13:
+		sprintf(bitpos, "%s", "58");
+		break;
+	case 0x83:
+		sprintf(bitpos, "%s", "59");
+		break;
+	case 0x1A:
+		sprintf(bitpos, "%s", "60");
+		break;
+	case 0x9B:
+		sprintf(bitpos, "%s", "61");
+		break;
+	case 0x5B:
+		sprintf(bitpos, "%s", "62");
+		break;
+	case 0x3B:
+		sprintf(bitpos, "%s", "63");
+		break;
+	case 0x80:
+		sprintf(bitpos, "%s", "ECC-0");
+		break;
+	case 0x40:
+		sprintf(bitpos, "%s", "ECC-1");
+		break;
+	case 0x20:
+		sprintf(bitpos, "%s", "ECC-2");
+		break;
+	case 0x10:
+		sprintf(bitpos, "%s", "ECC-3");
+		break;
+	case 0x08:
+		sprintf(bitpos, "%s", "ECC-4");
+		break;
+	case 0x04:
+		sprintf(bitpos, "%s", "ECC-5");
+		break;
+	case 0x02:
+		sprintf(bitpos, "%s", "ECC-6");
+		break;
+	case 0x01:
+		sprintf(bitpos, "%s", "ECC-7");
+		break;
+	default:
+		sprintf(bitpos, "%s", "UNKNOWN");
+		break;
+	}
+	printk(KERN_ERR "DDR ERROR CALCULATED ECC: 0x%02x\n", calculated_ecc);
+	printk(KERN_ERR "DDR ERROR STORED ECC: 0x%02x\n", stored_ecc);
+	printk(KERN_ERR "DDR ERROR ECC SYNDROME: 0x%02x\n",
+	       calculated_ecc ^ stored_ecc);
+	printk(KERN_ERR "DDR ERROR BIT LOCATION: %s\n", bitpos);
+}
+
+static irqreturn_t cpci6200_ddr_err_handler(int irq, void *dev_id)
+{
+	u32 err_addr, data_hi, data_lo, ecc, err_attr, err_det, sbe_count;
+	u32 pfn, offset;
+	struct page *pg;
+	void *virt_addr;
+	unsigned long flags = 0;
+	int handled = IRQ_NONE;
+
+	err_det = readl(ddr1_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+	if (!err_det)
+		goto controller2;
+
+	/* Collect error information from the error registers */
+	err_attr = readl(ddr1_err_regs + DDR_CAPT_ATTR - DDR_ERR_REGS_OFFSET);
+	data_hi = readl(ddr1_err_regs + DDR_CAPT_DATA_HI - DDR_ERR_REGS_OFFSET);
+	data_lo = readl(ddr1_err_regs + DDR_CAPT_DATA_LO - DDR_ERR_REGS_OFFSET);
+	err_addr = readl(ddr1_err_regs + DDR_CAPT_ADDR - DDR_ERR_REGS_OFFSET);
+	ecc = readl(ddr1_err_regs + DDR_CAPT_ECC - DDR_ERR_REGS_OFFSET);
+	sbe_count = readl(ddr1_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+
+	ddr1_errors++;
+
+	/* Display error information */
+	printk(KERN_ERR "DDR Controller 1 Error!\n");
+	printk(KERN_ERR "DDR 1 ERROR DETECT REG 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "DDR 1 ERROR ADDRESS CAPTURE REG 0x%08x\n",
+	       swab32(err_addr));
+	printk(KERN_ERR "DDR 1 ERROR DATA HIGH CAPTURE REG 0x%08x\n",
+	       swab32(data_hi));
+	printk(KERN_ERR "DDR 1 ERROR DATA LOW CAPTURE REG 0x%08x\n",
+	       swab32(data_lo));
+	printk(KERN_ERR "DDR 1 ERROR ATTRIBUTES CAPTURE REG 0x%08x\n",
+	       swab32(err_attr));
+	printk(KERN_ERR "DDR 1 ERROR SBE REG 0x%08x\n", swab32(sbe_count));
+	printk(KERN_ERR "DDR 1 ERROR COUNT %u\n", ddr1_errors);
+
+	if (err_det & DDR_SBE) {
+		/* Scrub block */
+		pfn = err_addr >> PAGE_SHIFT;
+		offset = err_addr & ~PAGE_MASK;
+
+		pg = pfn_to_page(pfn);
+
+		if (PageHighMem(pg))
+			local_irq_save(flags);
+
+		virt_addr = kmap_atomic(pg, KM_BOUNCE_READ);
+		atomic_scrub(virt_addr + offset, 8);
+		kunmap_atomic(virt_addr, KM_BOUNCE_READ);
+
+		if (PageHighMem(pg))
+			local_irq_restore(flags);
+	}
+
+	/* Determine and display bit location */
+	cpci6200_determine_bit_location(swab32(data_hi),
+					swab32(data_lo), swab32(ecc) & 0xff);
+
+	/* Clear interrupt cause register */
+	writel(err_det, ddr1_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+
+	/* Clear capture attribute register */
+	writel(0, ddr1_err_regs + DDR_CAPT_ATTR - DDR_ERR_REGS_OFFSET);
+
+	handled = IRQ_HANDLED;
+
+controller2:
+	err_det = readl(ddr2_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+	if (!err_det)
+		return handled;
+
+	/* Collect error information from the error registers */
+	err_attr = readl(ddr2_err_regs + DDR_CAPT_ATTR - DDR_ERR_REGS_OFFSET);
+	data_hi = readl(ddr2_err_regs + DDR_CAPT_DATA_HI - DDR_ERR_REGS_OFFSET);
+	data_lo = readl(ddr2_err_regs + DDR_CAPT_DATA_LO - DDR_ERR_REGS_OFFSET);
+	err_addr = readl(ddr2_err_regs + DDR_CAPT_ADDR - DDR_ERR_REGS_OFFSET);
+	ecc = readl(ddr2_err_regs + DDR_CAPT_ECC - DDR_ERR_REGS_OFFSET);
+	sbe_count = readl(ddr2_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+
+	ddr2_errors++;
+
+	/* Display error information */
+	printk(KERN_ERR "DDR Controller 2 Error!\n");
+	printk(KERN_ERR "DDR 2 ERROR DETECT REG 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "DDR 2 ERROR ADDRESS CAPTURE REG 0x%08x\n",
+	       swab32(err_addr));
+	printk(KERN_ERR "DDR 2 ERROR DATA HIGH CAPTURE REG 0x%08x\n",
+	       swab32(data_hi));
+	printk(KERN_ERR "DDR 2 ERROR DATA LOW CAPTURE REG 0x%08x\n",
+	       swab32(data_lo));
+	printk(KERN_ERR "DDR 2 ERROR ATTRIBUTES CAPTURE REG 0x%08x\n",
+	       swab32(err_attr));
+	printk(KERN_ERR "DDR 2 ERROR SBE REG 0x%08x\n", swab32(sbe_count));
+	printk(KERN_ERR "DDR 2 ERROR COUNT %u\n", ddr2_errors);
+
+	if (err_det & DDR_SBE) {
+		/* Scrub block */
+		pfn = err_addr >> PAGE_SHIFT;
+		offset = err_addr & ~PAGE_MASK;
+
+		pg = pfn_to_page(pfn);
+
+		if (PageHighMem(pg))
+			local_irq_save(flags);
+
+		virt_addr = kmap_atomic(pg, KM_BOUNCE_READ);
+		atomic_scrub(virt_addr + offset, 8);
+		kunmap_atomic(virt_addr, KM_BOUNCE_READ);
+
+		if (PageHighMem(pg))
+			local_irq_restore(flags);
+	}
+
+	/* Determine and display bit location */
+	cpci6200_determine_bit_location(swab32(data_hi),
+					swab32(data_lo), swab32(ecc) & 0xff);
+
+	/* Clear interrupt cause register */
+	writel(err_det, ddr2_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+
+	/* Clear capture attribute register */
+	writel(0, ddr2_err_regs + DDR_CAPT_ATTR - DDR_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+#endif
+
+#ifdef CONFIG_CPCI6200_ENABLE_L2_ERRORS
+
+static irqreturn_t cpci6200_l2cache_err_handler(int irq, void *dev_id)
+{
+	u32 err_addr_hi, err_addr_lo, data_hi, data_lo, ecc, err_attr, err_det;
+
+	err_det = readl(l2_err_regs + L2_ERR_DET - L2_ERR_REGS_OFFSET);
+	if (!err_det)
+		return IRQ_NONE;
+
+	/* Collect error information from the error registers */
+	err_attr = readl(l2_err_regs + L2_ERR_ATTR - L2_ERR_REGS_OFFSET);
+	err_addr_hi = readl(l2_err_regs + L2_ERR_ADDR_HI - L2_ERR_REGS_OFFSET);
+	err_addr_lo = readl(l2_err_regs + L2_ERR_ADDR_LO - L2_ERR_REGS_OFFSET);
+	data_hi = readl(l2_err_regs + L2_CAPT_DATA_HI - L2_ERR_REGS_OFFSET);
+	data_lo = readl(l2_err_regs + L2_CAPT_DATA_LO - L2_ERR_REGS_OFFSET);
+	ecc = readl(l2_err_regs + L2_CAPT_ECC - L2_ERR_REGS_OFFSET);
+
+	/* Clear interrupt cause and capture registers */
+	writel(err_det, l2_err_regs + L2_ERR_DET - L2_ERR_REGS_OFFSET);
+	writel(0, l2_err_regs + L2_ERR_ATTR - L2_ERR_REGS_OFFSET);
+
+	/* Display error information */
+	printk(KERN_ERR "L2 Cache Error!\n");
+	printk(KERN_ERR "L2 ERROR DETECT REG 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "L2 ERROR ADDRESS HIGH CAPTURE REG 0x%08x\n",
+	       swab32(err_addr_hi));
+	printk(KERN_ERR "L2 ERROR ADDRESS LOW CAPTURE REG 0x%08x\n",
+	       swab32(err_addr_lo));
+	printk(KERN_ERR "L2 ERROR DATA HIGH CAPTURE REG 0x%08x\n",
+	       swab32(data_hi));
+	printk(KERN_ERR "L2 ERROR DATA LOW CAPTURE REG 0x%08x\n",
+	       swab32(data_lo));
+	printk(KERN_ERR "L2 ERROR ATTRIBUTES CAPTURE REG 0x%08x\n",
+	       swab32(err_attr));
+	printk(KERN_ERR "L2 ERROR SYNDROME REG 0x%08x\n", swab32(ecc));
+
+	return IRQ_HANDLED;
+}
+#endif
+
+#ifdef CONFIG_CPCI6200_ENABLE_PCI_ERRORS
+
+static irqreturn_t cpci6200_pci1_err_handler(int irq, void *dev_id)
+{
+	u32 err_det, err_status, err_cap0, err_cap1, err_cap2, err_cap3;
+
+	if (dev_id != &pci1_err_regs)
+		return IRQ_NONE;
+
+	/* Collect error information from the error registers */
+	err_det = readl(pci1_err_regs + PCI_ERR_DET - PCI_ERR_REGS_OFFSET);
+	if (!err_det)
+		return IRQ_NONE;
+
+	err_status =
+	    readl(pci1_err_regs + PCI_ERR_CAP_STAT - PCI_ERR_REGS_OFFSET);
+	err_cap0 = readl(pci1_err_regs + PCI_ERR_CAP_R0 - PCI_ERR_REGS_OFFSET);
+	err_cap1 = readl(pci1_err_regs + PCI_ERR_CAP_R1 - PCI_ERR_REGS_OFFSET);
+	err_cap2 = readl(pci1_err_regs + PCI_ERR_CAP_R2 - PCI_ERR_REGS_OFFSET);
+	err_cap3 = readl(pci1_err_regs + PCI_ERR_CAP_R3 - PCI_ERR_REGS_OFFSET);
+
+	pci1_errors++;
+	/* Display error information */
+	printk(KERN_ERR "PCI Controller 1 Error!\n");
+	printk(KERN_ERR "PCI ERROR DETECT REG 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "PCI ERR CAP STATUS REG 0x%08x\n", swab32(err_status));
+	printk(KERN_ERR "PCI ERR CAP REG0 0x%08x\n", swab32(err_cap0));
+	printk(KERN_ERR "PCI ERR CAP REG1 0x%08x\n", swab32(err_cap1));
+	printk(KERN_ERR "PCI ERR CAP REG2 0x%08x\n", swab32(err_cap2));
+	printk(KERN_ERR "PCI ERR CAP REG3 0x%08x\n", swab32(err_cap3));
+	printk(KERN_ERR "PCI Error Count: %u\n", pci1_errors);
+
+	/* Clear interrupt cause and capture registers */
+	writel(err_det, pci1_err_regs + PCI_ERR_DET - PCI_ERR_REGS_OFFSET);
+	writel(swab32(0x1),
+	       pci1_err_regs + PCI_ERR_CAP_STAT - PCI_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t cpci6200_pci2_err_handler(int irq, void *dev_id)
+{
+	u32 err_det, err_status, err_cap0, err_cap1, err_cap2, err_cap3;
+
+	if (dev_id != &pci2_err_regs)
+		return IRQ_NONE;
+
+	/* Collect error information from the error registers */
+	err_det = readl(pci2_err_regs + PCI_ERR_DET - PCI_ERR_REGS_OFFSET);
+	if (!err_det)
+		return IRQ_NONE;
+
+	err_status =
+	    readl(pci2_err_regs + PCI_ERR_CAP_STAT - PCI_ERR_REGS_OFFSET);
+	err_cap0 = readl(pci2_err_regs + PCI_ERR_CAP_R0 - PCI_ERR_REGS_OFFSET);
+	err_cap1 = readl(pci2_err_regs + PCI_ERR_CAP_R1 - PCI_ERR_REGS_OFFSET);
+	err_cap2 = readl(pci2_err_regs + PCI_ERR_CAP_R2 - PCI_ERR_REGS_OFFSET);
+	err_cap3 = readl(pci2_err_regs + PCI_ERR_CAP_R3 - PCI_ERR_REGS_OFFSET);
+
+	pci2_errors++;
+	/* Display error information */
+	printk(KERN_ERR "PCI Controller 2 Error!\n");
+	printk(KERN_ERR "PCI ERROR DETECT REG 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "PCI ERR CAP STATUS REG 0x%08x\n", swab32(err_status));
+	printk(KERN_ERR "PCI ERR CAP REG0 0x%08x\n", swab32(err_cap0));
+	printk(KERN_ERR "PCI ERR CAP REG1 0x%08x\n", swab32(err_cap1));
+	printk(KERN_ERR "PCI ERR CAP REG2 0x%08x\n", swab32(err_cap2));
+	printk(KERN_ERR "PCI ERR CAP REG3 0x%08x\n", swab32(err_cap3));
+	printk(KERN_ERR "PCI Error Count: %u\n", pci2_errors);
+
+	/* Clear interrupt cause and capture registers */
+	writel(err_det, pci2_err_regs + PCI_ERR_DET - PCI_ERR_REGS_OFFSET);
+	writel(swab32(0x1),
+	       pci2_err_regs + PCI_ERR_CAP_STAT - PCI_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+
+#endif
+
+static void cpci6200_restart(char *cmd)
+{
+	volatile ulong i = 10000000;
+
+	local_irq_disable();
+	writeb(CPCI6200_BOARD_RESET, system_control_reg_addr);
+
+	while (i-- > 0) ;
+	panic("restart failed\n");
+}
+
+static void __devinit skip_fake_bridge(struct pci_dev *dev)
+{
+	/* Make it an error to skip the fake bridge
+	 * in pci_setup_device() in probe.c */
+	dev->hdr_type = 0x7f;
+}
+
+DECLARE_PCI_FIXUP_EARLY(0x1957, 0x3fff, skip_fake_bridge);
+DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge);
+
+static void __init cpci6200_init_irq(void)
+{
+	struct mpic *mpic;
+	struct resource r;
+	struct device_node *np = NULL;
+
+	np = of_find_node_by_type(np, "open-pic");
+	if (np == NULL) {
+		printk(KERN_ERR "Could not find open-pic node\n");
+		return;
+	}
+
+	if (of_address_to_resource(np, 0, &r)) {
+		printk(KERN_ERR "Failed to map mpic register space\n");
+		of_node_put(np);
+		return;
+	}
+
+	mpic = mpic_alloc(np, r.start,
+			  MPIC_PRIMARY | MPIC_WANTS_RESET |
+			  MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+			  MPIC_SINGLE_DEST_CPU, 0, 256, " OpenPIC  ");
+	BUG_ON(mpic == NULL);
+
+	/* Return the mpic node */
+	of_node_put(np);
+
+	mpic_init(mpic);
+
+#ifdef CONFIG_CPCI6200_ENABLE_L2_ERRORS
+	np = of_find_node_by_type(NULL, "l2_cache-controller");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find l2_cache-controller node\n");
+	} else {
+		l2_irq = irq_of_parse_and_map(np, 0);
+		if (l2_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map L2 cache irq\n");
+		of_node_put(np);
+	}
+#endif
+
+#ifdef CONFIG_CPCI6200_ENABLE_DDR_ERRORS
+	np = of_find_node_by_type(NULL, "memory-controller");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find memory-controller node\n");
+	} else {
+		ddr_irq = irq_of_parse_and_map(np, 0);
+		if (ddr_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map DDR irq\n");
+		of_node_put(np);
+	}
+#endif
+
+	np = of_find_node_by_path("/pci@f1009000");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find PCI 1 node\n");
+	} else {
+		pci1_irq = irq_of_parse_and_map(np, 0);
+		if (pci1_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map PCI 1 irq\n");
+		of_node_put(np);
+	}
+
+	np = of_find_node_by_path("/pci@f100a000");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find PCI 2 node\n");
+	} else {
+		pci2_irq = irq_of_parse_and_map(np, 0);
+		if (pci2_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map PCI 2 irq\n");
+		of_node_put(np);
+	}
+
+#ifdef CONFIG_CPCI6200_TICK_TIMERS
+	np = of_find_node_by_path("/board_timers@f2020000");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find timers node\n");
+	} else {
+		cpci6200_timer_irq = irq_of_parse_and_map(np, 0);
+		if (cpci6200_timer_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map timers irq\n");
+		of_node_put(np);
+	}
+#endif
+
+	np = of_find_node_by_path("/serial@f2013000");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find serial@f2013000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@f2013000 irq\n");
+		of_node_put(np);
+	}
+
+	np = of_find_node_by_path("/serial@f2014000");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find serial@f2014000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@f2014000 irq\n");
+		of_node_put(np);
+	}
+}
+
+static void __init cpci6200_misc_init(void)
+{
+	void __iomem *reg_block;
+	u8 reg_value;
+	u32 reg32;
+	//     u32 val;
+	struct device_node *np = NULL;
+	const u32 *regs;
+//      unsigned long a;
+#ifdef CONFIG_CPCI6200_ENABLE_DDR_ERRORS
+	u32 sbe_count;
+#endif
+
+	np = of_find_node_by_type(np, "soc");
+	if (np == NULL) {
+		printk("Error:Cannot find soc node\n");
+		return;
+	}
+	regs = of_get_property(np, "reg", NULL);
+	if (regs == NULL) {
+		printk("Error:Cannot get reg property from soc node\n");
+		of_node_put(np);
+		return;
+	} else
+		hb_baddr = regs[0];
+
+	of_node_put(np);
+
+#ifdef CONFIG_CPCI6200_ENABLE_DDR_ERRORS	/* Enable DDR error reporting */
+	ddr1_err_regs =
+	    ioremap(hb_baddr + DDR1_REGS_OFFSET + DDR_ERR_REGS_OFFSET, DDR_ERR_REGS_SIZE);
+	/* Enable all error detection */
+	writel(0, ddr1_err_regs + DDR_ERR_DIS - DDR_ERR_REGS_OFFSET);
+	/* Clear logged DDR errors */
+	writel(swab32(0x8000000D),
+	       ddr1_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+	/* Set single-bit error threshold */
+	sbe_count = 0x00010000;
+	writel(swab32(sbe_count),
+	       ddr1_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+
+	ddr2_err_regs =
+	    ioremap(hb_baddr + DDR2_REGS_OFFSET + DDR_ERR_REGS_OFFSET, DDR_ERR_REGS_SIZE);
+	/* Enable all error detection */
+	writel(0, ddr2_err_regs + DDR_ERR_DIS - DDR_ERR_REGS_OFFSET);
+	/* Clear logged DDR errors */
+	writel(swab32(0x8000000D),
+	       ddr2_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+	/* Set single-bit error threshold */
+	sbe_count = 0x00010000;
+	writel(swab32(sbe_count),
+	       ddr2_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+#endif
+
+#ifdef CONFIG_CPCI6200_ENABLE_PCI_ERRORS
+	pci1_err_regs = ioremap(hb_baddr + PCI1_REGS_OFFSET + 
+			PCI_ERR_REGS_OFFSET, PCI_ERR_REGS_SIZE);
+	pci2_err_regs = ioremap(hb_baddr + PCI2_REGS_OFFSET + 
+			PCI_ERR_REGS_OFFSET, PCI_ERR_REGS_SIZE);
+#endif
+
+	reg_block = ioremap(CPCI6200_SYSTEM_STATUS_REG, 64);
+
+	/* Turn on USR2 Green LED */
+	reg_value = readb(reg_block + CPCI6200_STATUS_INDICATOR_REG_OFFSET);
+	reg_value |= CPCI6200_USR1_LED;
+	writeb(reg_value, reg_block + CPCI6200_STATUS_INDICATOR_REG_OFFSET);
+	/* Disable PLD, IPMI, RTC, Temp Sensor, and Abort interrupts */
+	reg_value = readb(reg_block + CPCI6200_INTERRUPT_MASK_REG_OFFSET);
+	reg_value |= CPCI6200_CPCI_PLD_INT_MASK | CPCI6200_IPMI_INT_MASK |
+	    CPCI6200_RTC_INT_MASK | CPCI6200_TEMP_INT_MASK |
+	    CPCI6200_ABORT_INT_MASK;
+	writeb(reg_value, reg_block + CPCI6200_INTERRUPT_MASK_REG_OFFSET);
+
+	/* Turn off NOR flash SW write-protect */
+	reg_value = readb(reg_block + CPCI6200_NOR_FLASH_CTRL_STAT_REG_OFFSET);
+	reg_value &= ~CPCI6200_NOR_FLASH_WP_SW;
+	writeb(reg_value, reg_block + CPCI6200_NOR_FLASH_CTRL_STAT_REG_OFFSET);
+
+	iounmap(reg_block);
+
+	/* Allow write access to MRAM */
+	reg_block = ioremap(hb_baddr + 0x5010, 4);
+	reg32 = swab32(readl(reg_block));
+	reg32 &= 0xFFFFFEFF;
+	writel(swab32(reg32), reg_block);
+	iounmap(reg_block);
+
+	system_control_reg_addr = ioremap(CPCI6200_SYSTEM_CONTROL_REG, 1);
+
+	return;
+}
+
+static void __init cpci6200_pcibios_fixup(void)
+{
+	struct pci_dev *dev = NULL;
+	u32 temp;
+
+	if ((dev = pci_get_device(PCI_VENDOR_ID_NEC,
+				  PCI_DEVICE_ID_NEC_USB, NULL))) {
+		/* Set System Clock to 48MHz oscillator in EXT2 register */
+		pci_write_config_byte(dev, 0xe4, 0x20);
+		/* max ports = 2 */
+		pci_read_config_dword(dev, 0xe0, &temp);
+		temp &= ~0x00000007;
+		temp |= 0x00000002;
+		pci_write_config_dword(dev, 0xe0, temp);
+	}
+
+	dev = NULL;
+	for_each_pci_dev(dev) {
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+				      L1_CACHE_BYTES >> 2);
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+	}
+
+	dev = NULL;
+	while ((dev = pci_get_device(PCI_VENDOR_ID_TUNDRA, 0x8114,
+				     dev)) != NULL) {
+		u32 temp;
+		pci_read_config_dword(dev, 0xbc, &temp);
+		temp |= 0x04000000;
+		pci_write_config_dword(dev, 0xbc, temp);
+	}
+
+#ifdef CONFIG_CPCI6200_ENABLE_L2_ERRORS
+	if (request_irq(l2_irq, cpci6200_l2cache_err_handler,
+			IRQF_DISABLED, "L2 Cache Error", (void *)&l2_irq) < 0) {
+		printk(KERN_ERR "Cannot install L2 cache error handler\n");
+	} else
+		writel(swab32(0x1D),
+		       l2_err_regs + L2_ERR_INT_EN - L2_ERR_REGS_OFFSET);
+#endif
+
+#ifdef CONFIG_CPCI6200_ENABLE_DDR_ERRORS
+	if (request_irq(ddr_irq, cpci6200_ddr_err_handler,
+			IRQF_DISABLED, "DDR Error",
+			(void *)&ddr1_err_regs) < 0) {
+		printk(KERN_ERR "Cannot install DDR error handler\n");
+	} else {
+		writel(swab32(0xD),
+		       ddr1_err_regs + DDR_ERR_INT_EN - DDR_ERR_REGS_OFFSET);
+		writel(swab32(0xD),
+		       ddr2_err_regs + DDR_ERR_INT_EN - DDR_ERR_REGS_OFFSET);
+	}
+#endif
+
+#ifdef CONFIG_CPCI6200_ENABLE_PCI_ERRORS
+	if (request_irq(pci1_irq, cpci6200_pci1_err_handler,
+			IRQF_SHARED, "PCI 1 Error",
+			(void *)&pci1_err_regs) < 0) {
+		printk(KERN_ERR
+		       "Cannot install PCI Express Port 1 error handler\n");
+
+	} else {
+		/* Enable PCI error detection */
+		writel(0, pci1_err_regs + PCI_ERR_CAP_DIS - PCI_ERR_REGS_OFFSET);
+		/* Enable all error interrupts */
+		writel(swab32(0x00bfff00),
+		       pci1_err_regs + PCI_ERR_INT_EN - PCI_ERR_REGS_OFFSET);
+	}
+	if (request_irq(pci2_irq, cpci6200_pci2_err_handler,
+			IRQF_SHARED, "PCI 2 Error",
+			(void *)&pci2_err_regs) < 0) {
+		printk(KERN_ERR
+		       "Cannot install PCI Express Port 2 error handler\n");
+	} else {
+		/* Enable PCI error detection */
+		writel(0, pci2_err_regs + PCI_ERR_CAP_DIS - PCI_ERR_REGS_OFFSET);
+		/* Enable all error interrupts */
+		writel(swab32(0x00bfff00),
+		       pci2_err_regs + PCI_ERR_INT_EN - PCI_ERR_REGS_OFFSET);
+	}
+#endif
+}
+
+void cpci6200_pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_dev *bridge;
+	struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
+	struct pci_bus_region region;
+	u32 l;
+
+	fsl_pcibios_fixup_bus(bus);
+	bridge = bus->self;
+	if (!bridge)
+		return;
+
+	if (hose->global_number == 0) {
+		if ((bridge->vendor == PCI_VENDOR_ID_FREESCALE) &&
+		    ((bridge->device == PCI_DEVICE_ID_MPC8572E) ||
+		     (bridge->device == PCI_DEVICE_ID_MPC8572))) {
+			bridge->irq = pci1_irq;
+		}
+	}
+
+	if (hose->global_number == 1) {
+		struct pci_bus *parent;
+
+		if ((bridge->vendor == PCI_VENDOR_ID_FREESCALE) &&
+		    ((bridge->device == PCI_DEVICE_ID_MPC8572E) ||
+		     (bridge->device == PCI_DEVICE_ID_MPC8572))) {
+			bridge->irq = pci2_irq;
+		}
+
+		parent = bus->parent;
+
+		if (bus->resource[1]) {
+			pcibios_resource_to_bus(bridge, &region,
+						bus->resource[1]);
+			if (bus->resource[1]->flags & IORESOURCE_MEM) {
+				struct pci_bus *parent;
+				unsigned long offset = 0;
+
+				parent = bus->parent;
+				offset = hose->pci_mem_offset;
+				if ((bridge->vendor == PCI_VENDOR_ID_PLX) &&
+				    (bridge->device == 0x8624) &&
+				    (bridge->devfn == 0) && parent
+				    && parent->self
+				    && (parent->self->vendor ==
+					PCI_VENDOR_ID_FREESCALE)
+				    &&
+				    ((parent->self->device ==
+				      PCI_DEVICE_ID_MPC8572E)
+				     || (parent->self->device ==
+					 PCI_DEVICE_ID_MPC8572))
+				    && (parent->self->devfn == 0)) {
+					region.start = 0xe0200000;
+					region.end = 0xe7ffffff;
+					bus->resource[1]->start =
+					    region.start + offset;
+					bus->resource[1]->end =
+					    region.end + offset;
+
+					l = (region.start >> 16) & 0xfff0;
+					l |= region.end & 0xfff00000;
+				}
+				pci_write_config_dword(bridge, PCI_MEMORY_BASE,
+						       l);
+			}
+		}
+
+		if (bus->resource[2]) {
+			pcibios_resource_to_bus(bridge, &region,
+						bus->resource[2]);
+			{
+				struct pci_bus *parent;
+				unsigned long offset = 0;
+
+				parent = bus->parent;
+				offset = hose->pci_mem_offset;
+
+				/* Clear out the upper 32 bits of PREF limit.
+				 * If PCI_PREF_BASE_UPPER32 was non-zero, this 
+				 * temporarily disables PREF range, which is ok. */
+				pci_write_config_dword(bridge,
+						       PCI_PREF_LIMIT_UPPER32,
+						       0);
+				if ((bridge->vendor == PCI_VENDOR_ID_PLX)
+				    && (bridge->device == 0x8624)
+				    && (bridge->devfn == 0) && parent
+				    && parent->self
+				    && (parent->self->vendor ==
+					PCI_VENDOR_ID_FREESCALE)
+				    &&
+				    ((parent->self->device ==
+				      PCI_DEVICE_ID_MPC8572E)
+				     || (parent->self->device ==
+					 PCI_DEVICE_ID_MPC8572))
+				    && (parent->self->devfn == 0)) {
+					region.start = 0xe8000000;
+					region.end = 0xefffffff;
+					bus->resource[2]->start =
+					    region.start + offset;
+					bus->resource[2]->end =
+					    region.end + offset;
+					bus->resource[2]->flags =
+					    IORESOURCE_MEM |
+					    IORESOURCE_PREFETCH;
+					l = (region.start >> 16) & 0xfff0;
+					l |= region.end & 0xfff00000;
+				} else if ((bridge->vendor == PCI_VENDOR_ID_PLX)
+					   && (bridge->device == 0x8624)
+					   && (bridge->devfn == 0x8) && parent
+					   && parent->self
+					   && (parent->self->vendor ==
+					       PCI_VENDOR_ID_PLX)
+					   && (parent->self->device == 0x8624)
+					   && (parent->self->devfn == 0)) {
+					region.start = 0xfff00000;
+					region.end = 0x000fffff;
+					bus->resource[2]->start =
+					    region.start + offset;
+					bus->resource[2]->end =
+					    region.end + offset;
+					bus->resource[2]->flags =
+					    IORESOURCE_MEM |
+					    IORESOURCE_PREFETCH;
+					l = 0x0000fff0;
+				} else if ((bridge->vendor == PCI_VENDOR_ID_PLX)
+					   && (bridge->device == 0x8624)
+					   && (bridge->devfn == 0x20) && parent
+					   && parent->self
+					   && (parent->self->vendor ==
+					       PCI_VENDOR_ID_PLX)
+					   && (parent->self->device == 0x8624)
+					   && (parent->self->devfn == 0)) {
+					region.start = 0xfff00000;
+					region.end = 0x000fffff;
+					bus->resource[2]->start =
+					    region.start + offset;
+					bus->resource[2]->end =
+					    region.end + offset;
+					bus->resource[2]->flags =
+					    IORESOURCE_MEM |
+					    IORESOURCE_PREFETCH;
+					l = 0x0000fff0;
+				} else if ((bridge->vendor == PCI_VENDOR_ID_PLX)
+					   && (bridge->device == 0x8624)
+					   && (bridge->devfn == 0x28) && parent
+					   && parent->self
+					   && (parent->self->vendor ==
+					       PCI_VENDOR_ID_PLX)
+					   && (parent->self->device == 0x8624)
+					   && (parent->self->devfn == 0)) {
+					region.start = 0xe8000000;
+					region.end = 0xe80fffff;
+					bus->resource[2]->start =
+					    region.start + offset;
+					bus->resource[2]->end =
+					    region.end + offset;
+					bus->resource[2]->flags =
+					    IORESOURCE_MEM |
+					    IORESOURCE_PREFETCH;
+					l = (region.start >> 16) & 0xfff0;
+					l |= region.end & 0xfff00000;
+				} else if ((bridge->vendor == PCI_VENDOR_ID_TUNDRA)
+					   && (bridge->device == 0x8114)
+					   && (bridge->devfn == 0x0) && parent
+					   && parent->self
+					   && (parent->self->vendor ==
+					       PCI_VENDOR_ID_PLX)
+					   && (parent->self->device == 0x8624)
+					   && (parent->self->devfn == 0x28)) {
+					region.start = 0xe8000000;
+					region.end = 0xe80fffff;
+					bus->resource[2]->start =
+					    region.start + offset;
+					bus->resource[2]->end =
+					    region.end + offset;
+					bus->resource[2]->flags =
+					    IORESOURCE_MEM |
+					    IORESOURCE_PREFETCH;
+					l = (region.start >> 16) & 0xfff0;
+					l |= region.end & 0xfff00000;
+				} else if ((bridge->vendor == PCI_VENDOR_ID_PLX)
+					   && (bridge->device == 0x8624)
+					   && (bridge->devfn == 0x30) && parent
+					   && parent->self
+					   && (parent->self->vendor ==
+					       PCI_VENDOR_ID_PLX)
+					   && (parent->self->device == 0x8624)
+					   && (parent->self->devfn == 0)) {
+					region.start = 0xe8100000;
+					region.end = 0xe81fffff;
+					bus->resource[2]->start =
+					    region.start + offset;
+					bus->resource[2]->end =
+					    region.end + offset;
+					bus->resource[2]->flags =
+					    IORESOURCE_MEM |
+					    IORESOURCE_PREFETCH;
+					l = (region.start >> 16) & 0xfff0;
+					l |= region.end & 0xfff00000;
+				} else if ((bridge->vendor == PCI_VENDOR_ID_TUNDRA)
+					   && (bridge->device == 0x8114)
+					   && (bridge->devfn == 0x0) && parent
+					   && parent->self
+					   && (parent->self->vendor ==
+					       PCI_VENDOR_ID_PLX)
+					   && (parent->self->device == 0x8624)
+					   && (parent->self->devfn == 0x30)) {
+					region.start = 0xe8100000;
+					region.end = 0xe81fffff;
+					bus->resource[2]->start =
+					    region.start + offset;
+					bus->resource[2]->end =
+					    region.end + offset;
+					bus->resource[2]->flags =
+					    IORESOURCE_MEM |
+					    IORESOURCE_PREFETCH;
+					l = (region.start >> 16) & 0xfff0;
+					l |= region.end & 0xfff00000;
+				} else if ((bridge->vendor == PCI_VENDOR_ID_PLX)
+					   && (bridge->device == 0x8624)
+					   && (bridge->devfn == 0x40) && parent
+					   && parent->self
+					   && (parent->self->vendor ==
+					       PCI_VENDOR_ID_PLX)
+					   && (parent->self->device == 0x8624)
+					   && (parent->self->devfn == 0)) {
+					region.start = 0xe8200000;
+					region.end = 0xefffffff;
+					bus->resource[2]->start =
+					    region.start + offset;
+					bus->resource[2]->end =
+					    region.end + offset;
+					bus->resource[2]->flags =
+					    IORESOURCE_MEM |
+					    IORESOURCE_PREFETCH;
+					l = (region.start >> 16) & 0xfff0;
+					l |= region.end & 0xfff00000;
+				} else if ((bridge->vendor == PCI_VENDOR_ID_TUNDRA)
+					   && (bridge->device == 0x8114)
+					   && (bridge->devfn == 0x0) && parent
+					   && parent->self
+					   && (parent->self->vendor ==
+					       PCI_VENDOR_ID_PLX)
+					   && (parent->self->device == 0x8624)
+					   && (parent->self->devfn == 0x40)) {
+					region.start = 0xe8200000;
+					region.end = 0xefffffff;
+					bus->resource[2]->start =
+					    region.start + offset;
+					bus->resource[2]->end =
+					    region.end + offset;
+					bus->resource[2]->flags =
+					    IORESOURCE_MEM |
+					    IORESOURCE_PREFETCH;
+					l = (region.start >> 16) & 0xfff0;
+					l |= region.end & 0xfff00000;
+				} else if ((bridge->vendor == PCI_VENDOR_ID_PLX)
+					   && (bridge->device == 0x6540) 
+					   && (bridge->devfn == 0x10) && parent
+					   && parent->self
+					   && (parent->self->vendor ==
+					       PCI_VENDOR_ID_TUNDRA)
+					   && (parent->self->device == 0x8114)
+					   && (parent->self->devfn == 0x0)) {
+					region.start = 0xe8200000;
+					region.end = 0xefffffff;
+					bus->resource[2]->start =
+					    region.start + offset;
+					bus->resource[2]->end =
+					    region.end + offset;
+					bus->resource[2]->flags =
+					    IORESOURCE_MEM |
+					    IORESOURCE_PREFETCH;
+					l = (region.start >> 16) & 0xfff0;
+					l |= region.end & 0xfff00000;
+				} else if ((bridge->vendor == PCI_VENDOR_ID_PLX)
+					   && (bridge->device == 0x8624)
+					   && (bridge->devfn == 0x48) && parent
+					   && parent->self
+					   && (parent->self->vendor ==
+					       PCI_VENDOR_ID_PLX)
+					   && (parent->self->device == 0x8624)
+					   && (parent->self->devfn == 0)) {
+					region.start = 0xfff00000;
+					region.end = 0x000fffff;
+					bus->resource[2]->start =
+					    region.start + offset;
+					bus->resource[2]->end =
+					    region.end + offset;
+					l = 0x0000fff0;
+				} else
+					pci_read_config_dword(bridge,
+							      PCI_PREF_MEMORY_BASE,
+							      &l);
+			}
+			pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+
+			/* Clear out the upper 32 bits of PREF base. */
+			pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32,
+					       0);
+			pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32,
+					       0);
+
+			pci_write_config_word(bridge, PCI_BRIDGE_CONTROL,
+					      bus->bridge_ctl);
+
+		}
+
+		if (bus->resource[0]) {
+			pcibios_resource_to_bus(bridge, &region,
+						bus->resource[0]);
+			if (bus->resource[0]->flags & IORESOURCE_IO) {
+				struct pci_bus *parent;
+				unsigned long offset = 0;
+				u32 io_upper16;
+
+				parent = bus->parent;
+				offset =
+				    (unsigned long)hose->io_base_virt -
+				    isa_io_base;
+				pci_read_config_dword(bridge, PCI_IO_BASE, &l);
+				l &= 0xffff0000;
+
+				if ((bridge->vendor == PCI_VENDOR_ID_FREESCALE)
+				    &&
+				    ((bridge->device == PCI_DEVICE_ID_MPC8572E)
+				     || (bridge->device ==
+					 PCI_DEVICE_ID_MPC8572))) {
+					region.start = 0x00000000;
+					region.end = 0x007fffff;
+					bus->resource[0]->start =
+					    region.start + offset;
+					bus->resource[0]->end =
+					    region.end + offset;
+
+					l = (region.start >> 8) & 0x00f0;
+					l |= region.end & 0xf000;
+					/* Set up upper 16 bits of I/O base limit */
+					io_upper16 = (region.end & 0xffff0000) |
+					    (region.start >> 16);
+					/* Temporarily disable the I/O range before updating PCI_IO_BASE. */
+					pci_write_config_dword(bridge,
+							       PCI_IO_BASE_UPPER16,
+							       0x0000ffff);
+					/* Update lower 16 bits of I/O base/limit. */
+					pci_write_config_dword(bridge,
+							       PCI_IO_BASE, l);
+					/* Update upper 16 bits of I/O base/limit. */
+					pci_write_config_dword(bridge,
+							       PCI_IO_BASE_UPPER16,
+							       io_upper16);
+				}
+			}
+		}
+	}
+}
+
+static void
+cpci6200_pcibios_fixup_resources(struct pci_dev *dev)
+{
+	int i;
+
+	if ((dev->vendor == PCI_VENDOR_ID_PLX) && 
+		((dev->device == 0x6540) || (dev->device == 0x6541) || 
+		(dev->device == 0x6542))) {
+		for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) {
+			struct resource *res = &dev->resource[i];
+			if (res->end > res->start) {    
+				res->end -= res->start;
+				res->start = 0;
+				res->flags |= IORESOURCE_UNSET;
+			}
+		}
+        }
+}
+
+static void cpci6200_init_caches(void)
+{
+	void __iomem *l2_ctl_addr;
+	struct device_node *dn = NULL;
+	const u32 *regs;
+	uint  spr;
+
+	dn = of_find_node_by_type(dn, "soc");
+	if (dn == NULL) {
+		printk("Error:Cannot find soc node\n");
+		return;
+	}
+	regs = of_get_property(dn, "reg", NULL);
+	if (regs == NULL) {
+		printk("Error:Cannot get reg property from soc node\n");
+		return;
+	} else {
+		hb_baddr = regs[0];
+	}
+
+	l2_err_regs = ioremap(hb_baddr + L2_ERR_REGS_OFFSET, L2_ERR_REGS_SIZE);
+
+	l2_ctl_addr = ioremap(hb_baddr + 0x20000, 4);
+
+	/* L1 inst, L1 data, and L2 are disabled at this point */
+
+	/* Enable L1 inst */
+	asm volatile("msync; isync");
+	spr = mfspr(SPRN_L1CSR1);
+	asm volatile("msync; isync");
+	mtspr(SPRN_L1CSR1, spr | L1CSR1_ICFI | L1CSR1_ICE | L1CSR1_ICPE);
+	asm volatile("msync; isync");
+
+	/* Enable L1 data */
+	if (!(mfspr(SPRN_L1CSR0) & L1CSR0_DCE)) {
+		asm volatile("msync; isync");
+		mtspr(SPRN_L1CSR0, 0x0);		/* Disable */
+		asm volatile("msync; isync");
+		mtspr(SPRN_L1CSR0, L1CSR0_DCFI);	/* Invalidate */
+		asm volatile("isync; sync");
+		spr = mfspr(SPRN_L1CSR0);
+		asm volatile("isync; sync");
+		mtspr(SPRN_L1CSR0, spr | L1CSR0_DCE | L1CSR0_DCPE);		/* Enable */
+		asm volatile("isync; sync");
+	}
+
+	/* Disable L2 */
+	asm volatile("msync; isync");
+	writel(0, l2_ctl_addr);
+	readl(l2_ctl_addr);
+	asm volatile("msync; isync");
+	/* Invalidate L2 */
+	writel(swab32(0x40000300), l2_ctl_addr);
+	readl(l2_ctl_addr);
+	asm volatile("msync; isync");
+	/* Enable L2 error detection */
+	writel(0, l2_err_regs + L2_ERR_DIS - L2_ERR_REGS_OFFSET);
+	/* Clear any logged L2 errors */
+	writel(swab32(0x0000001D),
+	       l2_err_regs + L2_ERR_DET - L2_ERR_REGS_OFFSET);
+
+	asm volatile("msync; isync");
+	/* Enable L2 */
+	writel(swab32(0x80000300), l2_ctl_addr);
+	readl(l2_ctl_addr);
+	asm volatile("msync; isync");
+	/* Clear Locks */
+	writel(swab32(0x80000700), l2_ctl_addr);
+	readl(l2_ctl_addr);
+	asm volatile("msync; isync");
+
+	printk
+	    ("L2 cache enabled (1MB cache, no memory-mapped SRAM). L2CTL reg: 0x%x\n",
+	     swab32(readl(l2_ctl_addr)));
+
+	iounmap(l2_ctl_addr);
+	of_node_put(dn);
+
+	return;
+}
+
+/*
+ * Setup the architecture
+ */
+#ifdef CONFIG_SMP
+extern void __init mpc85xx_smp_init(void);
+#endif
+
+static void __init cpci6200_setup_arch(void)
+{
+	struct device_node *np;
+
+	cpci6200_init_caches();
+
+#ifdef CONFIG_PCI
+	for_each_node_by_type(np, "pci") {
+		if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
+		    (of_device_is_compatible(np, "fsl,mpc8548-pcie"))) {
+			struct resource rsrc;
+
+			of_address_to_resource(np, 0, &rsrc);
+			if ((rsrc.start & 0xfffff) == 0x8000)
+				fsl_add_bridge(np, 1);
+			else
+				fsl_add_bridge(np, 0);
+		}
+	}
+#endif
+
+#ifdef CONFIG_SMP
+	mpc85xx_smp_init();
+#endif
+	printk
+	    ("CPCI6200 board from Emerson Network Power Embedded Computing\n");
+
+#ifdef  CONFIG_ROOT_NFS
+	ROOT_DEV = Root_NFS;
+#else
+	ROOT_DEV = Root_SDA2;
+#endif
+	cpci6200_misc_init();
+}
+
+#define SPRN_L1CFG0     0x203	/* L1 Cache Configuration Register 0  */
+#define SPRN_L1CFG1     0x204	/* L1 Cache Configuration Register 1  */
+
+static void cpci6200_show_cpuinfo(struct seq_file *m)
+{
+	struct device_node *root;
+	uint pvid, svid, phid1;
+	phys_addr_t immr_base;
+	uint memsize = total_memory;
+	const char *model = "";
+	void __iomem *reg_block;
+	u8 reg_value;
+	u32 reg32_value;
+	void __iomem *l2cache_addr;
+	u32 l1csr0, l1csr1, l2ctl;
+	char buff[16] = "";
+
+	seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+	root = of_find_node_by_path("/");
+	if (root)
+		model = of_get_property(root, "model", NULL);
+	seq_printf(m, "Machine\t\t: %s\n", model);
+	of_node_put(root);
+
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
+	immr_base = get_immrbase();
+
+	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+	seq_printf(m, "HID0\t\t: 0x%08lx\n", mfspr(SPRN_HID0));
+	seq_printf(m, "HID1\t\t: 0x%08lx\n", mfspr(SPRN_HID1));
+	seq_printf(m, "CCSR Base\t: 0x%08x\n", immr_base);
+
+	/* Display cpu Pll setting */
+	phid1 = mfspr(SPRN_HID1);
+	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+	/* Display the cache settings */
+	seq_printf(m, "\nCache Settings:\n\n");
+	l1csr0 = mfspr(SPRN_L1CSR0);
+	seq_printf(m, "L1CSR0 (L1 D-cache)\t: 0x%08x (%s)\n", l1csr0,
+		   (l1csr0 & 1) ? "on" : "off");
+	l1csr1 = mfspr(SPRN_L1CSR1);
+	seq_printf(m, "L1CSR1 (L1 I-cache)\t: 0x%08x (%s)\n", l1csr1,
+		   (l1csr1 & 1) ? "on" : "off");
+	seq_printf(m, "L1CFG0\t\t\t: 0x%08lx\n", mfspr(SPRN_L1CFG0));
+	seq_printf(m, "L1CFG1\t\t\t: 0x%08lx\n", mfspr(SPRN_L1CFG1));
+
+	l2cache_addr = ioremap(immr_base + 0x20000, 4);
+	l2ctl = swab32(readl(l2cache_addr));
+	seq_printf(m, "L2CTL (L2 cache)\t: 0x%x (%s)\n", l2ctl,
+		   (l2ctl & 0x80000000) ? "on" : "off");
+	iounmap(l2cache_addr);
+
+	seq_printf(m, "\nBOARD INFORMATION:\n\n");
+
+	seq_printf(m,
+		   "Board Vendor\t\t: Emerson Network Power Embedded Computing\n");
+	reg_block = ioremap(CPCI6200_SYSTEM_STATUS_REG, 64);
+
+	/* Display the amount of memory */
+	seq_printf(m, "Memory\t\t\t: %d MB\n", memsize / (1024 * 1024));
+	/* System Status Register */
+	reg_value = readb(reg_block);
+	seq_printf(m, "12V Power Enable Status\t: %s\n",
+		   ((reg_value & CPCI6200_PWR12V_EN_STS) ? "Enabled" :
+		    "Disabled"));
+	seq_printf(m, "+12V Power Status\t: %s\n",
+		   ((reg_value & CPCI6200_PWR_12P_STS) ? "Good" : "Not Good"));
+	seq_printf(m, "-12V Power Status\t: %s\n",
+		   ((reg_value & CPCI6200_PWR_12N_STS) ? "Good" : "Not Good"));
+	seq_printf(m, "SW5 State\t\t: %s\n",
+		   ((reg_value & CPCI6200_STATE_SW5) ? "OFF" : "ON"));
+
+	seq_printf(m, "Safe Start Status\t: %s\n",
+		   ((reg_value & CPCI6200_SAFE_START) ?
+		    "Safe ENV settings used" : "NVRAM ENV settings used"));
+
+	seq_printf(m, "PEX_8624 Error Status\t: %s\n",
+		   ((reg_value & CPCI6200_PEX8624_ERROR) ?
+		    "Fatal Error" : "No Fatal Error"));
+
+	switch (reg_value & CPCI6200_BOARD_TYPE_MASK) {
+	case CPCI6200_BOARD_TYPE_CPCI:
+		sprintf(buff, "CPCI");
+		break;
+	case CPCI6200_BOARD_TYPE_PRPMC:
+		sprintf(buff, "PrPMC");
+		break;
+	case CPCI6200_BOARD_TYPE_VME:
+		sprintf(buff, "VME");
+		break;
+	default:
+		sprintf(buff, "Unknown");
+		break;
+	}
+	seq_printf(m, "Board Type\t\t: %s\n", buff);
+
+	/* System Control Register */
+	reg_value = readb(reg_block + CPCI6200_SYSTEM_CONTROL_REG_OFFSET);
+	seq_printf(m, "EEPROM WP Status\t: %s\n",
+		   ((reg_value & CPCI6200_EEPROM_WP) ?
+		    "EEPROM Write Protected" : "EEPROM Not Write Protected"));
+
+	/* Status Indicator Register */
+	reg_value = readb(reg_block + CPCI6200_STATUS_INDICATOR_REG_OFFSET);
+	seq_printf(m, "USR1 Green LED\t\t: %s\n",
+		   ((reg_value & CPCI6200_USR1_LED) ? "Lit" : "Not Lit"));
+	seq_printf(m, "USR2 Yellow LED\t\t: %s\n",
+		   ((reg_value & CPCI6200_USR2_LED) ? "Lit" : "Not Lit"));
+
+	/* NOR Flash Control/Status Register */
+	reg_value = readb(reg_block + CPCI6200_NOR_FLASH_CTRL_STAT_REG_OFFSET);
+	seq_printf(m, "NOR Flash Map Select\t: %s\n",
+		   ((reg_value & CPCI6200_NOR_FLASH_MAP_SELECT) ?
+		    "Boot Block A Mapped to Highest Address" :
+		    "Flash Boot Block Select"));
+	seq_printf(m, "NOR Flash WP SW\t\t: %s\n",
+		   ((reg_value & CPCI6200_NOR_FLASH_WP_SW) ?
+		    "Write Protected" : "Not Write Protected"));
+	seq_printf(m, "NOR Flash WP HW\t\t: %s\n",
+		   ((reg_value & CPCI6200_NOR_FLASH_WP_HW) ?
+		    "Write Protected" : "Not Write Protected"));
+	seq_printf(m, "NOR Flash Boot Select\t: %s\n",
+		   ((reg_value & CPCI6200_NOR_FLASH_BLK_SEL) ?
+		    "Boot Block B Selected" : "Boot Block A Selected"));
+	seq_printf(m, "NOR Flash Ready Status\t: %s\n",
+		   ((reg_value & CPCI6200_NOR_FLASH_RDY) ?
+		    "Bit Set" : "Bit Not Set"));
+
+	/* Interrupt Register 1 */
+	reg_value = readb(reg_block + CPCI6200_INTERRUPT_REG_1_OFFSET);
+
+	if (reg_value & CPCI6200_TSEC4_PHY_INTERRUPT) {
+		seq_printf(m, "TSEC4 PHY Interrupt\t: %s\n", "Asserted");
+	};
+	if (reg_value & CPCI6200_TSEC3_PHY_INTERRUPT) {
+		seq_printf(m, "TSEC3 PHY Interrupt\t: %s\n", "Asserted");
+	};
+	if (reg_value & CPCI6200_TSEC2_PHY_INTERRUPT) {
+		seq_printf(m, "TSEC2 PHY Interrupt\t: %s\n", "Asserted");
+	};
+	if (reg_value & CPCI6200_TSEC1_PHY_INTERRUPT) {
+		seq_printf(m, "TSEC1 PHY Interrupt\t: %s\n", "Asserted");
+	};
+
+	/* Interrupt Register 2 */
+	reg_value = readb(reg_block + CPCI6200_INTERRUPT_REG_2_OFFSET);
+
+	seq_printf(m, "Control CPLD Interrupt Status\t: %s\n",
+		   ((reg_value & CPCI6200_CPCI_PLD_INT) ?
+		    "Interrupt Asserted" : "Not Asserted"));
+	seq_printf(m, "IPMI Interrupt Status\t\t: %s\n",
+		   ((reg_value & CPCI6200_IPMI_INT) ?
+		    "Asserted" : "Not Asserted"));
+	seq_printf(m, "RTC Interrupt Status\t\t: %s\n",
+		   ((reg_value & CPCI6200_RTC_INT) ?
+		    "Asserted" : "Not Asserted"));
+	seq_printf(m, "Temp Sensor Interrupt_Status\t: %s\n",
+		   ((reg_value & CPCI6200_TEMP_INT) ?
+		    "Asserted" : "Not Asserted"));
+	seq_printf(m, "Abort Switch Status\t\t: %s\n",
+		   ((reg_value & CPCI6200_ABORT_STATUS) ?
+		    "Pressed" : "Not Pressed"));
+
+	/* Interrupt Mask Register */
+	reg_value = readb(reg_block + CPCI6200_INTERRUPT_MASK_REG_OFFSET);
+
+	seq_printf(m, "CPCI PLD Interrupt Mask\t\t: %s\n",
+		   ((reg_value & CPCI6200_CPCI_PLD_INT_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+	seq_printf(m, "IPMI Interrupt Mask\t\t: %s\n",
+		   ((reg_value & CPCI6200_IPMI_INT_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+	seq_printf(m, "RTC Interrupt Mask\t\t: %s\n",
+		   ((reg_value & CPCI6200_RTC_INT_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+	seq_printf(m, "Temp Sensor Interrupt Mask\t: %s\n",
+		   ((reg_value & CPCI6200_TEMP_INT_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+	seq_printf(m, "ABORT Interrupt Mask\t\t: %s\n",
+		   ((reg_value & CPCI6200_ABORT_INT_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+
+	/* Presence Detect Register */
+	reg_value = readb(reg_block + CPCI6200_PRESENCE_DETECT_REG_OFFSET);
+
+	seq_printf(m, "ERDY2\t\t\t: %s\n",
+		   ((reg_value & CPCI6200_ERDY2) ?
+		    "ERDY2 Set" : "ERDY2 Not Set"));
+	seq_printf(m, "ERDY1\t\t\t: %s\n",
+		   ((reg_value & CPCI6200_ERDY2) ?
+		    "ERDY1 Set" : "ERDY1 Not Set"));
+	seq_printf(m, "RTM\t\t\t: %s\n",
+		   ((reg_value & CPCI6200_RTM_PRESENT) ?
+		    "RTM Installed" : "RTM Not Installed"));
+	seq_printf(m, "XMCSPAN\t\t\t: %s\n",
+		   ((reg_value & CPCI6200_XMCSPAN_PRESENT) ?
+		    "XMCSPAN Installed" : "XMCSPAN Not Installed"));
+	seq_printf(m, "PMC Site 2\t\t: %s\n",
+		   ((reg_value & CPCI6200_PMC2_PRESENT) ?
+		    "PMC Module Installed" : "PMC Module Not Installed"));
+	seq_printf(m, "PMC Site 1\t\t: %s\n",
+		   ((reg_value & CPCI6200_PMC1_PRESENT) ?
+		    "PMC Module Installed" : "PMC Module Not Installed"));
+
+	/* NAND Flash1 CTRL Register */
+	reg_value = readb(reg_block + CPCI6200_NAND_FLASH1_CTRL_REG_OFFSET);
+	seq_printf(m, "NAND 1 CONTROL Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash1 SELECT Register */
+	reg_value = readb(reg_block + CPCI6200_NAND_FLASH1_SELECT_REG_OFFSET);
+	seq_printf(m, "NAND 1 SELECT Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash1 Presence Register */
+	reg_value = readb(reg_block + CPCI6200_NAND_FLASH1_PRESENCE_REG_OFFSET);
+	seq_printf(m, "NAND 1 PRESENCE Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash1 STATUS Register */
+	reg_value = readb(reg_block + CPCI6200_NAND_FLASH1_STATUS_REG_OFFSET);
+	seq_printf(m, "NAND 1 STATUS Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 CTRL Register */
+	reg_value = readb(reg_block + CPCI6200_NAND_FLASH2_CTRL_REG_OFFSET);
+	seq_printf(m, "NAND 2 CONTROL Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 SELECT Register */
+	reg_value = readb(reg_block + CPCI6200_NAND_FLASH2_SELECT_REG_OFFSET);
+	seq_printf(m, "NAND 2 SELECT Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 Presence Register */
+	reg_value = readb(reg_block + CPCI6200_NAND_FLASH2_PRESENCE_REG_OFFSET);
+	seq_printf(m, "NAND 2 PRESENCE Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 STATUS Register */
+	reg_value = readb(reg_block + CPCI6200_NAND_FLASH2_STATUS_REG_OFFSET);
+	seq_printf(m, "NAND 2 STATUS Reg\t: 0x%02x\n", reg_value);
+
+	/* CPCI Control Status Register */
+	reg_value = readb(reg_block + CPCI6200_CPCI_CONTROL_STATUS_REG_OFFSET);
+
+	seq_printf(m, "Hot Swap Blue LED Mask\t: %s\n",
+		   ((reg_value & CPCI6200_HS_LED_MASK) ?
+		    "Disable Illumination" : "Enable Illumination"));
+
+	seq_printf(m, "Backplane Reset Mask\t: %s\n",
+		   ((reg_value & CPCI6200_BP_RESET_MASK) ?
+		    "Disable backplane bus reset" :
+		    "Enable backplane bus reset"));
+
+	seq_printf(m, "Hot Swap Blue LED\t: %s\n",
+		   ((reg_value & CPCI6200_HS_LED_ON) ? "On" : "Off"));
+
+	seq_printf(m, "Stand Alone Mode\t: %s\n",
+		   ((reg_value & CPCI6200_SA_MODE) ?
+		    "In Stand Alone Mode" : "In Normal Mode"));
+
+	seq_printf(m, "System Slot Status\t: %s\n",
+		   ((reg_value & CPCI6200_SYS_EN_STS) ?
+		    "In System Slot" : "In Peripheral Slot"));
+
+	/* Geographic Address Register */
+	reg_value = readb(reg_block + CPCI6200_GEOGRAPHIC_ADDRESS_REG_OFFSET);
+	seq_printf(m, "Geographic Address\t: %02d\n", reg_value >> 3);
+
+	/* PLD Revision Register */
+	reg_value = readb(reg_block + CPCI6200_PLD_REVISION_REG_OFFSET);
+
+	seq_printf(m, "PLD Revision\t\t: 0x%x\n", reg_value);
+
+	/* PLD Date Code Register */
+	reg32_value = readl(reg_block + CPCI6200_PLD_DATE_CODE_REG_OFFSET);
+	seq_printf(m, "PLD Date Code\t\t: 0x%08x\n",
+		   (((reg32_value & 0x000000ffU) << 24) |
+		    ((reg32_value & 0x0000ff00U) << 8) |
+		    ((reg32_value & 0x00ff0000U) >> 8) |
+		    ((reg32_value & 0xff000000U) >> 24)));
+
+	iounmap(reg_block);
+
+	return;
+}
+
+static struct of_device_id __initdata of_bus_ids[] = {
+	{.type = "soc",},
+	{.compatible = "simple-bus",},
+	{},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+	of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+	return 0;
+}
+
+machine_device_initcall(cpci6200, declare_of_platform_devices);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init cpci6200_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (of_flat_dt_is_compatible(root, "CPCI6200"))
+		return 1;
+	else
+		return 0;
+}
+
+define_machine(cpci6200)
+{
+	.name = "CPCI6200",
+	.probe = cpci6200_probe,
+	.setup_arch = cpci6200_setup_arch,
+	.init_IRQ = cpci6200_init_irq,
+	.show_cpuinfo = cpci6200_show_cpuinfo,
+	.get_irq = mpic_get_irq,
+	.restart = cpci6200_restart,
+	.pcibios_fixup = cpci6200_pcibios_fixup,
+	.pcibios_fixup_bus = cpci6200_pcibios_fixup_bus,
+	.pcibios_fixup_resources = cpci6200_pcibios_fixup_resources,
+	.calibrate_decr = generic_calibrate_decr,
+	.progress = udbg_progress,
+};
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/cpci6200.h linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/cpci6200.h
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/cpci6200.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/cpci6200.h	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,180 @@
+/*
+ * CPCI6200 board definitions
+ *
+ * Author: Ajit Prem <ajit.prem@emerson.com>
+ *
+ * Copyright 2008 Emerson Network Power - Embedded Computing
+ *
+ * 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.
+ *
+ */
+
+#ifndef __CPCI6200_H__
+#define __CPCI6200_H__
+
+#include <linux/init.h>
+
+
+/* Flash */
+#define CPCI6200_FLASH_BASE	0xF8000000
+#define CPCI6200_FLASH_SIZE	0x08000000
+
+
+/* System Control and Status Registers */
+#define CPCI6200_SYSTEM_STATUS_REG		0xF2000000
+#define CPCI6200_SYSTEM_CONTROL_REG		0xF2000001
+#define CPCI6200_STATUS_INDICATOR_REG		0xF2000002
+#define CPCI6200_NOR_FLASH_CTRL_STAT_REG	0xF2000003
+#define CPCI6200_INTERRUPT_REG_1		0xF2000004
+#define CPCI6200_INTERRUPT_REG_2		0xF2000005
+#define CPCI6200_INTERRUPT_MASK_REG		0xF2000006
+#define CPCI6200_PRESENCE_DETECT_REG		0xF2000008
+#define CPCI6200_NAND_FLASH1_CONTROL_REG	0xF2000010
+#define CPCI6200_NAND_FLASH1_SELECT_REG		0xF2000011
+#define CPCI6200_NAND_FLASH1_PRESENCE_REG	0xF2000012
+#define CPCI6200_NAND_FLASH1_STATUS_REG		0xF2000013
+#define CPCI6200_NAND_FLASH1_DATA_REG		0xF2030000
+#define CPCI6200_NAND_FLASH2_CONTROL_REG	0xF2000014
+#define CPCI6200_NAND_FLASH2_SELECT_REG		0xF2000015
+#define CPCI6200_NAND_FLASH2_PRESENCE_REG	0xF2000016
+#define CPCI6200_NAND_FLASH2_STATUS_REG		0xF2000017
+#define CPCI6200_NAND_FLASH2_DATA_REG		0xF2038000
+#define CPCI6200_CPCI_CONTROL_STATUS_REG	0xF2000018
+#define CPCI6200_GEOGRAPHIC_ADDRESS_REG		0xF2000019
+#define CPCI6200_WATCHDOG_TIMER_LOAD_REG	0xF2000020
+#define CPCI6200_WATCHDOG_CONTROL_REG		0xF2000024
+#define CPCI6200_WATCHDOG_TIMER_RESOLUTION_REG	0xF2000025
+#define CPCI6200_WATCHDOG_TIMER_COUNT_REG	0xF2000026
+#define CPCI6200_PLD_REVISION_REG		0xF2000030
+#define CPCI6200_PLD_DATE_CODE_REG		0xF2000034
+#define CPCI6200_TEST_1_REG			0xF2000038
+#define CPCI6200_TEST_2_REG			0xF200003C
+
+/* Register offsets */
+#define CPCI6200_SYSTEM_STATUS_REG_OFFSET		0x00000000
+#define CPCI6200_SYSTEM_CONTROL_REG_OFFSET		0x00000001
+#define CPCI6200_STATUS_INDICATOR_REG_OFFSET		0x00000002
+#define CPCI6200_NOR_FLASH_CTRL_STAT_REG_OFFSET		0x00000003
+#define CPCI6200_INTERRUPT_REG_1_OFFSET			0x00000004
+#define CPCI6200_INTERRUPT_REG_2_OFFSET			0x00000005
+#define CPCI6200_INTERRUPT_MASK_REG_OFFSET		0x00000006
+#define CPCI6200_PRESENCE_DETECT_REG_OFFSET		0x00000008
+#define CPCI6200_NAND_FLASH1_CTRL_REG_OFFSET		0x00000010
+#define CPCI6200_NAND_FLASH1_SELECT_REG_OFFSET		0x00000011
+#define CPCI6200_NAND_FLASH1_PRESENCE_REG_OFFSET	0x00000012
+#define CPCI6200_NAND_FLASH1_STATUS_REG_OFFSET		0x00000013
+#define CPCI6200_NAND_FLASH2_CTRL_REG_OFFSET		0x00000014
+#define CPCI6200_NAND_FLASH2_SELECT_REG_OFFSET		0x00000015
+#define CPCI6200_NAND_FLASH2_PRESENCE_REG_OFFSET	0x00000016
+#define CPCI6200_NAND_FLASH2_STATUS_REG_OFFSET		0x00000017
+#define CPCI6200_CPCI_CONTROL_STATUS_REG_OFFSET		0x00000018
+#define CPCI6200_GEOGRAPHIC_ADDRESS_REG_OFFSET		0x00000019
+#define CPCI6200_WATCHDOG_TIMER_LOAD_REG_OFFSET		0x00000020
+#define CPCI6200_WATCHDOG_CONTROL_REG_OFFSET		0x00000024
+#define CPCI6200_WATCHDOG_TIMER_RESOLUTION_REG_OFFSET	0x00000025
+#define CPCI6200_WATCHDOG_TIMER_COUNT_REG_OFFSET	0x00000026
+#define CPCI6200_PLD_REVISION_REG_OFFSET		0x00000030
+#define CPCI6200_PLD_DATE_CODE_REG_OFFSET		0x00000034
+#define CPCI6200_TEST_1_REG_OFFSET			0x00000038
+#define CPCI6200_TEST_2_REG_OFFSET			0x0000003C
+
+/* System Status Register */
+#define CPCI6200_PWR12V_EN_STS		0x80
+#define CPCI6200_PWR_12P_STS		0x40
+#define CPCI6200_PWR_12N_STS		0x20
+#define CPCI6200_STATE_SW5		0x10
+#define CPCI6200_SAFE_START		0x08
+#define CPCI6200_PEX8624_ERROR		0x04
+#define CPCI6200_BOARD_TYPE_MASK	0x03
+#define CPCI6200_BOARD_TYPE_CPCI	0x02
+#define CPCI6200_BOARD_TYPE_PRPMC	0x01
+#define CPCI6200_BOARD_TYPE_VME		0x00
+
+/* System Control Register */
+#define CPCI6200_BOARD_RESET		0xA0
+#define CPCI6200_EEPROM_WP		0x02
+
+/* Status Indicator Register */
+#define CPCI6200_USR1_LED		0x02
+#define CPCI6200_USR2_LED		0x01
+
+/* NOR Flash Control/Status Register */
+#define CPCI6200_NOR_FLASH_MAP_SELECT	0x10
+#define CPCI6200_NOR_FLASH_WP_SW	0x08
+#define CPCI6200_NOR_FLASH_WP_HW	0x04
+#define CPCI6200_NOR_FLASH_BLK_SEL	0x02
+#define CPCI6200_NOR_FLASH_RDY		0x01
+
+/* Interrupt Register 1 */
+#define CPCI6200_TSEC4_PHY_INTERRUPT	0x08
+#define CPCI6200_TSEC3_PHY_INTERRUPT	0x04
+#define CPCI6200_TSEC2_PHY_INTERRUPT	0x02
+#define CPCI6200_TSEC1_PHY_INTERRUPT	0x01
+
+/* Interrupt Register 2 */
+#define CPCI6200_CPCI_PLD_INT		0x10
+#define CPCI6200_IPMI_INT		0x08
+#define CPCI6200_RTC_INT		0x04
+#define CPCI6200_TEMP_INT		0x02
+#define CPCI6200_ABORT_STATUS		0x01
+
+/* Interrupt Mask Register */
+#define CPCI6200_CPCI_PLD_INT_MASK	0x10
+#define CPCI6200_IPMI_INT_MASK		0x08
+#define CPCI6200_RTC_INT_MASK		0x04
+#define CPCI6200_TEMP_INT_MASK		0x02
+#define CPCI6200_ABORT_INT_MASK		0x01
+
+/* Presence Detect Register */
+#define CPCI6200_ERDY2			0x20
+#define CPCI6200_ERDY1			0x10
+#define CPCI6200_RTM_PRESENT		0x08
+#define CPCI6200_XMCSPAN_PRESENT	0x04
+#define CPCI6200_PMC2_PRESENT		0x02
+#define CPCI6200_PMC1_PRESENT		0x01
+
+/* NAND Flash Chip Control Register */
+#define CPCI6200_NAND_FLASH_CLE		0x80
+#define CPCI6200_NAND_FLASH_ALE		0x40
+#define CPCI6200_NAND_FLASH_WP		0x20
+
+/* NAND Flash Chip Select Register */
+#define CPCI6200_NAND_FLASH_CE1		0x80
+#define CPCI6200_NAND_FLASH_CE2		0x40
+#define CPCI6200_NAND_FLASH_CE3		0x20
+#define CPCI6200_NAND_FLASH_CE4		0x10
+
+/* NAND Flash Chip Presence Register */
+#define CPCI6200_NAND_FLASH_CP		0x80
+
+/* NAND Flash Chip Status Register */
+#define CPCI6200_NAND_FLASH_RB1		0x80
+#define CPCI6200_NAND_FLASH_RB2		0x40
+#define CPCI6200_NAND_FLASH_RB3		0x20
+#define CPCI6200_NAND_FLASH_RB4		0x10
+
+/* CPCI Control Status Register */
+#define CPCI6200_HS_LED_MASK		0x80
+#define CPCI6200_BP_RESET_MASK		0x40
+#define CPCI6200_HS_LED_ON		0x20
+#define CPCI6200_SA_MODE		0x10
+#define CPCI6200_SYS_EN_STS		0x08
+
+/* Geographic Address Register */
+#define CPCI6200_GEO_ADDR_GA4		0x80
+#define CPCI6200_GEO_ADDR_GA3		0x40
+#define CPCI6200_GEO_ADDR_GA2		0x20
+#define CPCI6200_GEO_ADDR_GA1		0x10
+
+#define CPCI6200_BASE_BAUD		1843200
+
+#define DUART_BASE_BAUD			(CPCI6200_BASE_BAUD / 16)
+#define CPCI6200_UART_SIZE		0x8
+
+#define CPCI6200_SERIAL_1	0xF2013000U
+#define CPCI6200_SERIAL_2	0xF2014000U
+
+#endif	/* __CPCI6200_H__ */
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/cpci6200_timer.c linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/cpci6200_timer.c
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/cpci6200_timer.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/cpci6200_timer.c	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,394 @@
+/*
+ * arch/powerpc/platforms/85xx/cpci6200_timer.c
+ *
+ * CPCI6200 Tick Timers Support
+ *
+ * Author: Ajit Prem <Ajit.Prem@emerson.com>
+ *
+ * Copyright 2008 Emerson Network Power Embedded Computing Inc.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+#include "cpci6200.h"
+#include <asm/cpci6200_timer.h>
+
+#define CPCI6200_TICK_TIMER_BASE                0xF2020000
+#define CPCI6200_TICK_TIMER_BLOCK_SIZE          0x4C
+
+#define CPCI6200_TICK_TIMER_PRESCALER_REG_OFFSET        0x0
+#define CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET          0x10
+#define CPCI6200_TICK_TIMER_COMPARE_REG_OFFSET          0x14
+#define CPCI6200_TICK_TIMER_COUNTER_REG_OFFSET          0x18
+
+#define CPCI6200_TICK_TIMER_ENC                 0x00000001
+#define CPCI6200_TICK_TIMER_COC                 0x00000002
+#define CPCI6200_TICK_TIMER_COVF                0x00000004
+#define CPCI6200_TICK_TIMER_OVF                 0x000000F0
+#define CPCI6200_TICK_TIMER_ENINT               0x00000100
+#define CPCI6200_TICK_TIMER_CINT                0x00000200
+#define CPCI6200_TICK_TIMER_INTS                0x00000400
+
+#define	MIN_MICROSECONDS	10000
+#define MAX_TICKS		0xFFFFFFFF
+
+struct cpci6200_timer_t {
+	cpci6200_timer_f func;
+	void *func_data;
+	int started;
+	int periodic;
+	ulong period;
+	ulong ticks;
+};
+
+#define ALL_MSG "cpci6200_timer: "
+
+#ifdef CPCI6200_TIMER_DEBUG
+int cpci6200_timer_debug = CPCI6200_TIMER_DEBUG;
+MODULE_PARM(cpci6200_timer_debug, "i");
+#define DEBUG(n, fmt, args...) if (cpci6200_timer_debug>(n)) printk(KERN_INFO ALL_MSG fmt, ## args)
+static const char *version = "cpci6200_timer.c 1.0.0 (Ajit Prem)";
+#else
+#define DEBUG(n, fmt, args...)
+#endif
+
+extern int cpci6200_timer_irq;
+
+static struct cpci6200_timer_t cpci6200_timer[4];
+static void __iomem *cpci6200_timer_base;
+static u32 clk_out = 1;		/* Ticks per microsecond */
+static spinlock_t cpci6200_timer_lock = SPIN_LOCK_UNLOCKED;
+
+static irqreturn_t cpci6200_timer_int_handler(int irq, void *data)
+{
+	struct cpci6200_timer_t *info = data;
+	cpci6200_timer_f func;
+	void *func_data;
+	int timer_number;
+	u32 ctrl_reg;
+
+	if (data != (void *) &cpci6200_timer[0]) 
+		return IRQ_NONE;
+
+	for (timer_number = 0; timer_number <= 3; timer_number++) {
+		if (swab32(readl(cpci6200_timer_base +
+			 (timer_number + 1) *
+			 CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET)) &
+		   	 CPCI6200_TICK_TIMER_INTS) {
+			info = &cpci6200_timer[timer_number];
+			func_data = info->func_data;
+			func = info->func;
+
+			if (!info->periodic) {
+				cpci6200_timer_stop(timer_number);
+			} else {
+				ctrl_reg = swab32(readl(cpci6200_timer_base +
+					((timer_number + 1) *
+					 CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET)));
+				ctrl_reg &= ~CPCI6200_TICK_TIMER_ENC;
+				ctrl_reg =
+				    CPCI6200_TICK_TIMER_COVF |
+				    CPCI6200_TICK_TIMER_CINT;
+				writel(swab32(ctrl_reg),
+				       cpci6200_timer_base +
+				       ((timer_number + 1) *
+					CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET));
+				writel(0,
+				       cpci6200_timer_base +
+				       ((timer_number + 1) *
+					CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET)
+				       +
+				       (CPCI6200_TICK_TIMER_COUNTER_REG_OFFSET -
+					CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET));
+				DEBUG(1,
+				      ("Timer %d Counter 0x%x Compare 0x%x\n",
+				       timer_number,
+				       swab32(readl
+					      (cpci6200_timer_base +
+					       ((timer_number + 1) *
+						CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET)
+					       +
+					       (CPCI6200_TICK_TIMER_COUNTER_REG_OFFSET
+						-
+						CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET))),
+				       swab32(readl
+					      (cpci6200_timer_base +
+					       ((timer_number + 1) *
+						CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET)
+					       +
+					       (CPCI6200_TICK_TIMER_COMPARE_REG_OFFSET
+						-
+						CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET)))));
+				writel(swab32
+				       (CPCI6200_TICK_TIMER_ENC |
+					CPCI6200_TICK_TIMER_COC |
+					CPCI6200_TICK_TIMER_ENINT),
+				       cpci6200_timer_base + 
+					((timer_number + 1) *
+					CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET));
+			}
+			if (func) 
+				func(func_data);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* 
+ * Stop the timer
+ */
+EXPORT_SYMBOL(cpci6200_timer_stop);
+int cpci6200_timer_stop(int timer_number)
+{
+	u32 reset_value;
+	unsigned long flags;
+
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+
+	spin_lock_irqsave(&cpci6200_timer_lock, flags);
+	reset_value = swab32(readl(cpci6200_timer_base +
+				   ((timer_number + 1) *
+				    CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET)));
+	reset_value &= ~CPCI6200_TICK_TIMER_ENC;
+	reset_value &= ~CPCI6200_TICK_TIMER_ENINT;
+	reset_value = CPCI6200_TICK_TIMER_COVF | CPCI6200_TICK_TIMER_CINT;
+	writel(swab32(reset_value),
+	       cpci6200_timer_base +
+	       ((timer_number + 1) * CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0, cpci6200_timer_base +
+	       ((timer_number + 1) * CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (CPCI6200_TICK_TIMER_COUNTER_REG_OFFSET -
+		CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0xffffffff, cpci6200_timer_base +
+	       ((timer_number + 1) * CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (CPCI6200_TICK_TIMER_COMPARE_REG_OFFSET -
+		CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET));
+	cpci6200_timer[timer_number].func = NULL;
+	cpci6200_timer[timer_number].func_data = NULL;
+	cpci6200_timer[timer_number].started = 0;
+	cpci6200_timer[timer_number].periodic = 0;
+	cpci6200_timer[timer_number].period = 0;
+	cpci6200_timer[timer_number].ticks = 0xFFFFFFFF;
+	spin_unlock_irqrestore(&cpci6200_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Start the timer
+ */
+EXPORT_SYMBOL(cpci6200_timer_start);
+int cpci6200_timer_start(int timer_number, unsigned long microseconds,
+			 cpci6200_timer_f func, void *func_data, int periodic)
+{
+	int res = 0;
+	unsigned long flags;
+	unsigned long ticks;
+
+	printk(KERN_INFO
+	       "cpci6200_timer: start_timer: num %d microseconds 0x%lx periodic %d\n",
+	       timer_number, microseconds, periodic);
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+	if ((microseconds < MIN_MICROSECONDS) ||
+	    (microseconds > MAX_TICKS / clk_out))
+		return -EINVAL;
+	if (func == NULL)
+		return -EINVAL;
+	if (cpci6200_timer[timer_number].started == 1)
+		return -EBUSY;
+	if ((res = cpci6200_timer_stop(timer_number)) < 0)
+		return res;
+	ticks = microseconds * clk_out;
+	spin_lock_irqsave(&cpci6200_timer_lock, flags);
+	cpci6200_timer[timer_number].started = 1;
+	cpci6200_timer[timer_number].func = func;
+	cpci6200_timer[timer_number].func_data = func_data;
+	cpci6200_timer[timer_number].periodic = periodic;
+	cpci6200_timer[timer_number].period = microseconds;
+	cpci6200_timer[timer_number].ticks = ticks;
+	writel(swab32(ticks), cpci6200_timer_base +
+	       ((timer_number + 1) * CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (CPCI6200_TICK_TIMER_COMPARE_REG_OFFSET -
+		CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0, cpci6200_timer_base +
+	       ((timer_number + 1) * CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (CPCI6200_TICK_TIMER_COUNTER_REG_OFFSET -
+		CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(swab32(CPCI6200_TICK_TIMER_ENC | CPCI6200_TICK_TIMER_COC |
+		      CPCI6200_TICK_TIMER_ENINT),
+	       cpci6200_timer_base +
+	       ((timer_number + 1) * CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET));
+	spin_unlock_irqrestore(&cpci6200_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Get the timer resolution, in microseconds/tick
+ */
+EXPORT_SYMBOL(cpci6200_timer_get_resolution);
+unsigned long cpci6200_timer_get_resolution(void)
+{
+	u32 prescaler_adjust;
+
+	/* 
+	 * Prescaler_adjust = 256 - CLKIN/CLKOUT
+	 * CLKIN = 25 MHz
+	 */
+
+	prescaler_adjust = readl(cpci6200_timer_base +
+				 CPCI6200_TICK_TIMER_PRESCALER_REG_OFFSET);
+	return (25 / (256 - prescaler_adjust));
+}
+
+/* 
+ * Set the timer resolution, in ticks/microsecond
+ */
+EXPORT_SYMBOL(cpci6200_timer_set_resolution);
+int cpci6200_timer_set_resolution(unsigned long ticks)
+{
+	u32 prescaler_adjust;
+	int i;
+	unsigned long flags;
+
+	/* 
+	 * Prescaler_adjust = 256 - CLKIN/CLKOUT
+	 * CLKIN = 25 MHz
+	 */
+
+	if ((ticks < MIN_TICKS_PER_MICROSECOND) ||
+	    (ticks > MAX_TICKS_PER_MICROSECOND))
+		return -EINVAL;
+
+	clk_out = ticks;
+	prescaler_adjust = 256 - (25 / clk_out);
+
+	spin_lock_irqsave(&cpci6200_timer_lock, flags);
+	for (i = 0; i <= 3; i++) {
+		if (cpci6200_timer[i].started == 1) {
+			spin_unlock_irqrestore(&cpci6200_timer_lock, flags);
+			return -EBUSY;
+		}
+	}
+
+	writel(prescaler_adjust, cpci6200_timer_base +
+	       CPCI6200_TICK_TIMER_PRESCALER_REG_OFFSET);
+	spin_unlock_irqrestore(&cpci6200_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Get the timer value, in ticks
+ */
+EXPORT_SYMBOL(cpci6200_timer_get_ticks);
+unsigned long cpci6200_timer_get_ticks(int timer_number)
+{
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+
+	return swab32(readl(cpci6200_timer_base +
+			    ((timer_number +
+			      1) * CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET) +
+			    (CPCI6200_TICK_TIMER_COUNTER_REG_OFFSET -
+			     CPCI6200_TICK_TIMER_CONTROL_REG_OFFSET)));
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int
+cpci6200_timer_proc_read(char *buf, char **start, off_t off, int len, int *eof,
+			 void *data)
+{
+	int i;
+
+	len = 0;
+	len +=
+	    sprintf(buf + len,
+		    "\nTimer     Active  Periodic  Period(ticks)   Period(microseconds)\n");
+	len +=
+	    sprintf(buf + len,
+		    "_____     ______  ________  _____________   ____________________\n");
+	for (i = 0; i <= 3; i++) {
+		len +=
+		    sprintf(buf + len,
+			    "#%d        %c       %c         0x%08lx      %ld\n",
+			    i + 1,
+			    ((cpci6200_timer[i].started == 1) ? 'y' : 'n'),
+			    ((cpci6200_timer[i].periodic == 1) ? 'y' : 'n'),
+			    ((cpci6200_timer[i].periodic ==
+			      1) ? cpci6200_timer[i].ticks : 0),
+			    ((cpci6200_timer[i].periodic ==
+			      1) ? cpci6200_timer[i].period : 0));
+	}
+	return len;
+}
+
+#endif				/* CONFIG_PROC_FS */
+
+static __init int cpci6200_timer_init(void)
+{
+	int res = 0;
+	int i;
+
+	printk(KERN_INFO "cpci6200-timer: CPCI6200 Tick Timers\n");
+
+	cpci6200_timer_base = ioremap(CPCI6200_TICK_TIMER_BASE,
+				     CPCI6200_TICK_TIMER_BLOCK_SIZE);
+	if (cpci6200_timer_base == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i <= 3; i++) {
+		cpci6200_timer[i].func = NULL;
+		cpci6200_timer[i].func_data = NULL;
+		cpci6200_timer[i].started = 0;
+		cpci6200_timer[i].periodic = 0;
+		cpci6200_timer[i].period = 0;
+		cpci6200_timer[i].ticks = 0;
+	}
+	res = request_irq(cpci6200_timer_irq, cpci6200_timer_int_handler,
+			  IRQF_SHARED,
+			  "CPCI6200 Tick Timers", &cpci6200_timer[0]);
+	if (res < 0) {
+		printk(KERN_ERR "CPCI6200 Timer: Can't allocate IRQ %d.\n",
+		       cpci6200_timer_irq);
+		return res;
+	}
+#ifdef CONFIG_PROC_FS
+	create_proc_read_entry("cpci6200_timers", 0, NULL,
+			       cpci6200_timer_proc_read, NULL);
+#endif
+	return 0;
+}
+
+static __exit void cpci6200_timer_exit(void)
+{
+	int timer_number;
+
+	for (timer_number = 0; timer_number <= 3; timer_number++) {
+		cpci6200_timer_stop(timer_number);
+	}
+	free_irq(cpci6200_timer_irq, &cpci6200_timer[0]);
+	iounmap(cpci6200_timer_base);
+}
+
+MODULE_LICENSE("GPL");
+
+MODULE_AUTHOR("Ajit Prem <ajit.prem@emerson.com>");
+MODULE_DESCRIPTION("CPCI6200 Tick Timer driver");
+
+module_init(cpci6200_timer_init);
+module_exit(cpci6200_timer_exit);
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/Kconfig linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/Kconfig
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/Kconfig	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/Kconfig	2009-07-21 11:28:17.000000000 -0700
@@ -115,7 +115,83 @@
 	help
 	  This option enables support for the Wind River SBC8560 board
 
+config MVME3100
+        bool "Emerson Network Power Embedded Computing MVME3100"
+        help
+          This option enables support for the Emerson Network Power MVME3100 board
+
+config MVME4100
+        bool "Emerson Network Power Embedded Computing MVME4100"
+        help
+          This option enables support for the Emerson Network Power Embedded Computing MVME4100 board
+
+config CPCI6200
+        bool "Emerson Network Power Embedded Computing CPCI6200"
+        help
+          This option enables support for the Emerson Network Power Embedded Computing CPCI6200 board
+
 endif # MPC85xx
 
 config TQM85xx
 	bool
+
+config MVME3100_ENABLE_DDR_ERRORS
+        bool "Enable DDR Error Reporting"
+        depends on MVME3100
+        default y
+
+config MVME3100_ENABLE_L2_ERRORS
+        bool "Enable L2 Error Reporting"
+        depends on MVME3100
+        default y
+
+config MVME3100_ENABLE_PCI_ERRORS
+        bool "Enable PCI Error Reporting"
+        depends on MVME3100
+        default y
+
+config MVME3100_TICK_TIMERS
+        bool "Enable support for the Tick Timers on the MVME3100"
+        depends on MVME3100
+        default y
+
+config MVME4100_ENABLE_DDR_ERRORS
+        bool "Enable DDR Error Reporting"
+        depends on MVME4100
+        default y
+
+config MVME4100_ENABLE_L2_ERRORS
+        bool "Enable L2 Error Reporting"
+        depends on MVME4100
+        default y
+
+config MVME4100_ENABLE_PCI_ERRORS
+        bool "Enable PCI Error Reporting"
+        depends on MVME4100
+        default y
+
+config MVME4100_TICK_TIMERS
+        bool "Enable support for the Tick Timers on the MVME4100"
+        depends on MVME4100
+        default y
+
+config CPCI6200_ENABLE_DDR_ERRORS
+        bool "Enable DDR Error Reporting"
+        depends on CPCI6200
+        default y
+
+config CPCI6200_ENABLE_L2_ERRORS
+        bool "Enable L2 Error Reporting"
+        depends on CPCI6200
+        default y
+
+config CPCI6200_ENABLE_PCI_ERRORS
+        bool "Enable PCI Error Reporting"
+        depends on CPCI6200
+        default y
+
+config CPCI6200_TICK_TIMERS
+        bool "Enable support for the Tick Timers on the CPCI6200"
+        depends on CPCI6200
+        default y
+
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/Makefile linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/Makefile
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/Makefile	2009-08-13 14:15:19.000000000 -0700
@@ -14,3 +14,9 @@
 obj-$(CONFIG_SBC8560)     += sbc8560.o
 obj-$(CONFIG_SBC8548)     += sbc8548.o
 obj-$(CONFIG_KSI8560)	  += ksi8560.o
+obj-$(CONFIG_MVME3100)    += mvme3100.o 
+obj-$(CONFIG_MVME3100_TICK_TIMERS)	+= mvme3100_timer.o
+obj-$(CONFIG_MVME4100)			+= mvme4100.o
+obj-$(CONFIG_MVME4100_TICK_TIMERS)	+= mvme4100_timer.o
+obj-$(CONFIG_CPCI6200)			+= cpci6200.o 
+obj-$(CONFIG_CPCI6200_TICK_TIMERS)	+= cpci6200_timer.o
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme3100.c linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme3100.c
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme3100.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme3100.c	2009-09-02 10:57:37.000000000 -0700
@@ -0,0 +1,1025 @@
+/*
+ * MVME3100 setup and early boot code plus other random bits.
+ *
+ * Author: Ajit Prem (ajit.prem@emerson.com)
+ *
+ * Copyright 2008-2009 Emerson Network Power Embedded Computing, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/root_dev.h>
+#include <linux/rtc.h>
+#include <linux/highmem.h>
+#include <linux/fsl_devices.h>
+#include <linux/of_platform.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/irq.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/mpic.h>
+#include <asm/kmap_types.h>
+#include <asm/edac.h>
+#include <asm/udbg.h>
+
+#include <sysdev/fsl_pci.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mvme3100.h"
+
+static unsigned long hb_baddr;
+static unsigned int bus_frequency;
+static int serial_irq;
+
+static void __iomem *l2_err_regs;
+static void __iomem *system_control_reg_addr;
+
+#define L2_ERR_REGS_OFFSET      0x20E20
+#define L2_ERR_REGS_SIZE        0x3C
+
+#define L2_CAPT_DATA_HI         0x20E20
+#define L2_CAPT_DATA_LO         0x20E24
+#define L2_CAPT_ECC             0x20E28
+#define L2_ERR_DET              0x20E40
+#define L2_ERR_DIS              0x20E44
+#define L2_ERR_INT_EN           0x20E48
+#define L2_ERR_ATTR             0x20E4C
+#define L2_ERR_ADDR             0x20E50
+#define L2_ERR_CTL              0x20E58
+
+#ifdef CONFIG_MVME3100_ENABLE_L2_ERRORS
+static int l2_irq;
+static irqreturn_t mvme3100_l2cache_err_handler(int irq, void *dev_id);
+#endif
+
+#ifdef CONFIG_MVME3100_ENABLE_DDR_ERRORS
+
+#define DDR_ERR_REGS_OFFSET     0x2E00
+#define DDR_ERR_REGS_SIZE       0x5C
+
+#define DDR_CAPT_DATA_HI        0x2E20
+#define DDR_CAPT_DATA_LO        0x2E24
+#define DDR_CAPT_ECC            0x2E28
+#define DDR_ERR_DET             0x2E40
+#define DDR_ERR_DIS             0x2E44
+#define DDR_ERR_INT_EN          0x2E48
+#define DDR_CAPT_ATTR           0x2E4C
+#define DDR_CAPT_ADDR           0x2E50
+#define DDR_ERR_SBE             0x2E58
+
+#define DDR_SBE                 0x4     /* single-bit ECC error */
+#define DDR_MBE                 0x8     /* multi-bit ECC error */
+#define DDR_MME                 0x80000000      /* multiple ECC error */
+
+static int ddr_errors;
+static void __iomem *ddr_err_regs;
+static int ddr_irq;
+static irqreturn_t mvme3100_ddr_err_handler(int irq, void *dev_id);
+
+#endif
+
+
+#define PCI_ERR_REGS_OFFSET     0x8E00
+#define PCI_ERR_REGS_SIZE       0x28
+
+#define PCI_ERR_DET             0x8E00
+#define PCI_ERR_CAP_DIS         0x8E04
+#define PCI_ERR_INT_EN          0x8E08
+#define PCI_ERR_ATTR            0x8E0C
+#define PCI_ERR_ADDR            0x8E10
+#define PCI_ERR_EXT_ADDR        0x8E14
+#define PCI_ERR_DL              0x8E18
+#define PCI_ERR_DH              0x8E1C
+#define PCI_GAS_TIMR            0x8E20
+#define PCI_PCIX_TIMR           0x8E24
+
+static int pci_irq;
+
+#ifdef CONFIG_MVME3100_ENABLE_PCI_ERRORS
+static int pci_errors;
+static void __iomem *pci_err_regs;
+static irqreturn_t mvme3100_pci_err_handler(int irq, void *dev_id);
+
+#endif
+
+#ifdef CONFIG_VME_BRIDGE_BOOTMEM
+void *vme_driver_bootmem;
+unsigned int vme_bootmem_size;
+#endif
+
+#ifdef CONFIG_MVME3100_TICK_TIMERS
+int mvme3100_timer_irq;
+#endif
+
+#ifdef CONFIG_SENSORS_DS1621
+int ds1621_irq;
+#endif
+
+#ifdef CONFIG_MVME3100_ENABLE_DDR_ERRORS
+
+static irqreturn_t mvme3100_ddr_err_handler(int irq, void *dev_id)
+{
+	u32 err_addr, data_hi, data_lo, ecc, err_attr, err_det, sbe_count;
+        u32 pfn, offset;
+        struct page *pg;
+        void *virt_addr;
+        unsigned long flags = 0;
+
+	err_det = readl(ddr_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+	if (!err_det)
+		return IRQ_NONE;
+
+	/* Collect error information from the error registers */
+	err_addr = readl(ddr_err_regs + DDR_CAPT_ADDR - DDR_ERR_REGS_OFFSET);
+	data_hi = readl(ddr_err_regs + DDR_CAPT_DATA_HI - DDR_ERR_REGS_OFFSET);
+	data_lo = readl(ddr_err_regs + DDR_CAPT_DATA_LO - DDR_ERR_REGS_OFFSET);
+	err_attr = readl(ddr_err_regs + DDR_CAPT_ATTR - DDR_ERR_REGS_OFFSET);
+	ecc = readl(ddr_err_regs + DDR_CAPT_ECC - DDR_ERR_REGS_OFFSET);
+	sbe_count = readl(ddr_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+
+	ddr_errors++;
+
+	/* Display error information */
+	printk(KERN_ERR "DDR Error!\n");
+	printk(KERN_ERR "DDR ERROR DETECT REG 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "DDR ERROR ADDRESS CAPTURE REG 0x%08x\n",
+	       swab32(err_addr));
+	printk(KERN_ERR "DDR ERROR DATA HIGH CAPTURE REG 0x%08x\n",
+	       swab32(data_hi));
+	printk(KERN_ERR "DDR ERROR DATA LOW CAPTURE REG 0x%08x\n",
+	       swab32(data_lo));
+	printk(KERN_ERR "DDR ERROR ATTRIBUTES CAPTURE REG 0x%08x\n",
+	       swab32(err_attr));
+	printk(KERN_ERR "DDR ERROR SYNDROME REG 0x%08x\n", swab32(ecc));
+	printk(KERN_ERR "DDR ERROR SBE REG 0x%08x\n", swab32(sbe_count));
+        printk(KERN_ERR "DDR ERROR COUNT %u\n", ddr_errors);
+
+        if (err_det & DDR_SBE) {
+                /* Scrub block */
+                pfn = err_addr >> PAGE_SHIFT;
+                offset = err_addr & ~PAGE_MASK;
+
+                pg = pfn_to_page(pfn);
+
+                if (PageHighMem(pg))
+                        local_irq_save(flags);
+
+                virt_addr = kmap_atomic(pg, KM_BOUNCE_READ);
+                atomic_scrub(virt_addr + offset, 8);
+                kunmap_atomic(virt_addr, KM_BOUNCE_READ);
+
+                if (PageHighMem(pg))
+                        local_irq_restore(flags);
+        }
+
+	/* Clear interrupt cause register */
+	writel(err_det, ddr_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+
+#endif
+
+#ifdef CONFIG_MVME3100_ENABLE_L2_ERRORS
+
+static irqreturn_t mvme3100_l2cache_err_handler(int irq, void *dev_id)
+{
+	u32 err_addr, data_hi, data_lo, ecc, err_attr, err_det;
+
+	/* Collect error information from the error registers */
+	err_det = readl(l2_err_regs + L2_ERR_DET - L2_ERR_REGS_OFFSET);
+
+	if (!err_det)
+		return IRQ_NONE;
+
+	err_attr = readl(l2_err_regs + L2_ERR_ATTR - L2_ERR_REGS_OFFSET);
+	err_addr = readl(l2_err_regs + L2_ERR_ADDR - L2_ERR_REGS_OFFSET);
+	data_hi = readl(l2_err_regs + L2_CAPT_DATA_HI - L2_ERR_REGS_OFFSET);
+	data_lo = readl(l2_err_regs + L2_CAPT_DATA_LO - L2_ERR_REGS_OFFSET);
+	ecc = readl(l2_err_regs + L2_CAPT_ECC - L2_ERR_REGS_OFFSET);
+
+	if (swab32(err_det) & 0xc) {
+		/* ECC errors */
+		/* Invalidate line in L2 cache */
+		asm volatile("dcbf 0,%0" : : "r" (swab32(err_addr)) : "memory");
+		asm volatile("sync");
+	} else if (swab32(err_det) & 0x10) {
+		/* Tag parity error */
+		/* Flash invalidate L2 cache */
+	}
+
+	/* Display error information */
+	printk(KERN_ERR "L2 Cache Error!\n");
+	printk(KERN_ERR "L2 ERROR DETECT REG 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "L2 ERROR ADDRESS CAPTURE REG 0x%08x\n",
+	       swab32(err_addr));
+	printk(KERN_ERR "L2 ERROR DATA HIGH CAPTURE REG 0x%08x\n",
+	       swab32(data_hi));
+	printk(KERN_ERR "L2 ERROR DATA LOW CAPTURE REG 0x%08x\n",
+	       swab32(data_lo));
+	printk(KERN_ERR "L2 ERROR ATTRIBUTES CAPTURE REG 0x%08x\n",
+	       swab32(err_attr));
+	printk(KERN_ERR "L2 ERROR SYNDROME REG 0x%08x\n", swab32(ecc));
+
+	/* Clear interrupt cause and capture registers */
+	writel(err_det, l2_err_regs + L2_ERR_DET - L2_ERR_REGS_OFFSET);
+	writel(0, l2_err_regs + L2_ERR_ATTR - L2_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+#endif
+
+#ifdef CONFIG_MVME3100_ENABLE_PCI_ERRORS
+
+static irqreturn_t mvme3100_pci_err_handler(int irq, void *dev_id)
+{
+	u32 err_addr, data_hi, data_lo, err_attr, err_ext_addr, err_det;
+	u32 gas_timr, pcix_timr;
+
+	/* Collect error information from the error registers */
+	err_det = readl(pci_err_regs + PCI_ERR_DET - PCI_ERR_REGS_OFFSET);
+	if (!err_det)
+		return IRQ_NONE;
+
+	err_addr = readl(pci_err_regs + PCI_ERR_ADDR - PCI_ERR_REGS_OFFSET);
+	err_ext_addr =
+	    readl(pci_err_regs + PCI_ERR_EXT_ADDR - PCI_ERR_REGS_OFFSET);
+	err_attr = readl(pci_err_regs + PCI_ERR_ATTR - PCI_ERR_REGS_OFFSET);
+	data_lo = readl(pci_err_regs + PCI_ERR_DL - PCI_ERR_REGS_OFFSET);
+	data_hi = readl(pci_err_regs + PCI_ERR_DH - PCI_ERR_REGS_OFFSET);
+	gas_timr = readl(pci_err_regs + PCI_GAS_TIMR - PCI_ERR_REGS_OFFSET);
+	pcix_timr = readl(pci_err_regs + PCI_PCIX_TIMR - PCI_ERR_REGS_OFFSET);
+
+	/* Display error information */
+	if (pci_errors != 0) {
+		printk(KERN_ERR "PCI Error!\n");
+		printk(KERN_ERR "PCI ERROR DETECT REG 0x%08x\n",
+		       swab32(err_det));
+		printk(KERN_ERR "PCI ERROR ADDRESS REG 0x%08x\n",
+		       swab32(err_addr));
+		printk(KERN_ERR "PCI ERROR EXT ADDRESS REG 0x%08x\n",
+		       swab32(err_ext_addr));
+		printk(KERN_ERR "PCI ERROR ATTRIBUTES REG 0x%08x\n",
+		       swab32(err_attr));
+		printk(KERN_ERR "PCI ERROR DATA HIGH REG 0x%08x\n",
+		       swab32(data_hi));
+		printk(KERN_ERR "PCI ERROR DATA LOW REG 0x%08x\n",
+		       swab32(data_lo));
+		printk(KERN_ERR "PCI GASKET TIMER REG 0x%08x\n",
+		       swab32(gas_timr));
+		printk(KERN_ERR "PCI PCIX TIMER REG 0x%08x\n",
+		       swab32(pcix_timr));
+	}
+	pci_errors++;
+
+	/* Clear interrupt cause and capture registers */
+        writel(err_det, pci_err_regs + PCI_ERR_DET - PCI_ERR_REGS_OFFSET);
+	writel(swab32(0x1),
+		pci_err_regs + PCI_ERR_ATTR - PCI_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+#endif
+
+int mvme3100_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn)
+{
+	if (bus == 0 && PCI_SLOT(devfn) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	else
+		return PCIBIOS_SUCCESSFUL;
+}
+
+static void __init mvme3100_misc_init(void)
+{
+	void __iomem *reg_addr;
+        struct device_node *np = NULL;
+	u8 reg_value;
+	const u32 *regs;
+#ifdef CONFIG_MVME3100_ENABLE_DDR_ERRORS
+	u32 sbe_count;
+#endif
+
+        np = of_find_node_by_type(np, "soc");
+        if (np == NULL) {
+                printk("Error:Cannot find soc node\n");
+                return;
+        }
+        regs = of_get_property(np, "reg", NULL);
+        if (regs == NULL) {
+                printk("Error:Cannot get reg property from soc node\n");
+                of_node_put(np);
+                return;
+        } else
+                hb_baddr = regs[0];
+
+        of_node_put(np);
+
+#ifdef CONFIG_MVME3100_ENABLE_DDR_ERRORS	/* Enable DDR error reporting */
+	ddr_err_regs =
+	    ioremap(hb_baddr + DDR_ERR_REGS_OFFSET, DDR_ERR_REGS_SIZE);
+	/* Enable all error detection */
+	writel(0, ddr_err_regs + DDR_ERR_DIS - DDR_ERR_REGS_OFFSET);
+	/* Clear logged DDR errors */
+	writel(swab32(0x8000000D),
+	       ddr_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+	/* Set single-bit error threshold */
+	sbe_count = 0x00010000;
+	writel(swab32(sbe_count),
+	       ddr_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+#endif
+
+#ifdef CONFIG_MVME3100_ENABLE_PCI_ERRORS
+	pci_err_regs = ioremap(hb_baddr + PCI_ERR_REGS_OFFSET,
+			       PCI_ERR_REGS_SIZE);
+#endif
+
+#ifdef CONFIG_VME_BRIDGE
+	{
+		extern void vmemod_setup_options(char *);
+
+		vmemod_setup_options(cmd_line);
+	}
+#endif
+
+	reg_addr = ioremap(MVME3100_SYSTEM_CONTROL_REG, 3);
+
+	/* Mask FEC PHY interrupts */
+	reg_value = readb(reg_addr);
+	reg_value |= MVME3100_FEC_PHY_MASK;
+	writeb(reg_value, reg_addr);
+
+	/* Turn off Board Fail LED */
+	reg_value = readb(++reg_addr);
+	reg_value &= ~MVME3100_BRD_FAIL_LED;
+	writeb(reg_value, reg_addr);
+
+	/* Turn off SW flash write-protect */
+	reg_value = readb(++reg_addr);
+	reg_value &= ~MVME3100_FLASH_WP_SW;
+	writeb(reg_value, reg_addr);
+
+	iounmap(reg_addr);
+
+	system_control_reg_addr = ioremap(MVME3100_SYSTEM_CONTROL_REG, 1);
+
+	return;
+}
+
+void __init mvme3100_init_irq(void)
+{
+	struct mpic *mpic;
+	struct resource r;
+	struct device_node *np = NULL;
+
+	np = of_find_node_by_type(np, "open-pic");
+	if (np == NULL) {
+		printk(KERN_ERR "Could not find open-pic node\n");
+		return;
+	}
+
+	if (of_address_to_resource(np, 0, &r)) {
+		printk(KERN_ERR "Could not map mpic register space\n");
+		of_node_put(np);
+		return;
+	}
+
+	mpic = mpic_alloc(np, r.start,
+			  MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+			  0, 256, " OpenPIC  ");
+	BUG_ON(mpic == NULL);
+	of_node_put(np);
+
+	mpic_init(mpic);
+
+#ifdef CONFIG_MVME3100_ENABLE_L2_ERRORS
+	np = of_find_node_by_type(NULL, "l2_cache-controller");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find l2_cache-controller node\n");
+	} else {
+		l2_irq = irq_of_parse_and_map(np, 0);
+		if (l2_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map L2 cache irq\n");
+		of_node_put(np);
+	}
+#endif
+
+#ifdef CONFIG_MVME3100_ENABLE_DDR_ERRORS
+	np = of_find_node_by_type(NULL, "memory-controller");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find memory_controller node\n");
+	} else {
+		ddr_irq = irq_of_parse_and_map(np, 0);
+		if (ddr_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map DDR irq\n");
+		of_node_put(np);
+	}
+#endif
+
+#ifdef CONFIG_MVME3100_ENABLE_PCI_ERRORS
+	np = of_find_node_by_type(NULL, "pci");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find pci node\n");
+	} else {
+		pci_irq = irq_of_parse_and_map(np, 0);
+		if (pci_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map PCI irq\n");
+		of_node_put(np);
+	}
+#endif
+
+#ifdef CONFIG_SENSORS_DS1621
+	np = of_find_node_by_type(NULL, "thermostat");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find ds1621 node\n");
+	} else {
+		ds1621_irq = irq_of_parse_and_map(np, 0);
+		if (ds1621_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map DS1621 irq\n");
+		of_node_put(np);
+	}
+#endif
+
+#ifdef CONFIG_MVME3100_TICK_TIMERS
+	np = of_find_node_by_type(NULL, "board_timers");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find timers node\n");
+	} else {
+		mvme3100_timer_irq = irq_of_parse_and_map(np, 0);
+		if (mvme3100_timer_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map timers irq\n");
+		of_node_put(np);
+	}
+#endif
+
+	np = of_find_node_by_path("/serial@e2011000");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find serial@e2011000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@e2011000 irq\n");
+		of_node_put(np);
+	}
+
+	np = of_find_node_by_path("/serial@e2012000");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find serial@e2012000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@e2012000 irq\n");
+		of_node_put(np);
+	}
+
+	np = of_find_node_by_path("/serial@e2013000");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find serial@e2013000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@e2013000 irq\n");
+		of_node_put(np);
+	}
+
+	np = of_find_node_by_path("/serial@e2014000");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find serial@e2014000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@e2014000 irq\n");
+		of_node_put(np);
+	}
+
+	return;
+}
+
+static void __init mvme3100_pcibios_fixup(void)
+{
+	struct pci_dev *dev = NULL;
+	u32  temp;
+	int ret;
+
+	while ((dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev)) != NULL) {
+		/* Update all devices' cache line size */
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+				      L1_CACHE_BYTES >> 2);
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+	}
+
+	if ((dev = pci_get_device(PCI_VENDOR_ID_NEC,
+				   PCI_DEVICE_ID_NEC_USB, NULL))) {
+		/* Set System Clock to 48MHz oscillator in EXT2 register */
+		pci_read_config_dword(dev, 0xe4, &temp);
+		temp |= 0x00000020;
+		pci_write_config_dword(dev, 0xe4, temp);
+
+		/* Max Ports = 2 */
+		pci_read_config_dword(dev, 0xe0, &temp);
+		temp &= ~0x00000007;
+		temp |= 0x00000002;
+		pci_write_config_dword(dev, 0xe0, temp);
+	}
+
+#ifdef CONFIG_MVME3100_ENABLE_L2_ERRORS
+	if (request_irq(l2_irq, mvme3100_l2cache_err_handler,
+			IRQF_DISABLED, "L2 Cache Error",
+			(void *)&l2_err_regs) < 0) {
+		printk(KERN_ERR "Cannot install L2 cache error handler\n");
+	} else
+		writel(swab32(0x1D),
+		       l2_err_regs + L2_ERR_INT_EN - L2_ERR_REGS_OFFSET);
+#endif
+
+#ifdef CONFIG_MVME3100_ENABLE_DDR_ERRORS
+	if ((ret = request_irq(ddr_irq, mvme3100_ddr_err_handler,
+			       IRQF_DISABLED, "DDR Error",
+			       (void *)&ddr_err_regs)) < 0) {
+		printk(KERN_ERR "Cannot install DDR error handler\n");
+	} else
+		writel(swab32(0xD),
+		       ddr_err_regs + DDR_ERR_INT_EN - DDR_ERR_REGS_OFFSET);
+#endif
+
+#ifdef CONFIG_MVME3100_ENABLE_PCI_ERRORS
+	if (request_irq(pci_irq, mvme3100_pci_err_handler,
+			IRQF_DISABLED, "PCI Error",
+			(void *)&pci_err_regs) < 0) {
+		printk(KERN_ERR "Cannot install PCI error handler\n");
+	} else {
+		/* Enable PCI error detection */
+		writel(0, pci_err_regs + PCI_ERR_CAP_DIS - PCI_ERR_REGS_OFFSET);
+		/* Enable all error interrupts */
+		writel(swab32(0x7FF),
+		       pci_err_regs + PCI_ERR_INT_EN - PCI_ERR_REGS_OFFSET);
+	}
+#endif
+}
+
+static void mvme3100_init_caches(void)
+{
+	void __iomem *l2_ctl_addr;
+	struct device_node *dn = NULL;
+	const u32 *regs;
+	uint spr;
+
+	dn = of_find_node_by_type(dn, "soc");
+	if (dn == NULL) {
+		printk("Error:Cannot find soc node\n");
+		return;
+	}
+	regs = of_get_property(dn, "reg", NULL);
+	if (regs == NULL) {
+		printk("Error:Cannot get reg property from soc node\n");
+		return;
+	} else {
+		hb_baddr = regs[0];
+	}
+
+	l2_err_regs = ioremap(hb_baddr + L2_ERR_REGS_OFFSET, L2_ERR_REGS_SIZE);
+
+	l2_ctl_addr = ioremap(hb_baddr + 0x20000, 4);
+
+	/* L1 inst, L1 data, and L2 are disabled at this point */
+        /* Enable L1 inst */
+        asm volatile("msync; isync");
+        spr = mfspr(SPRN_L1CSR1);
+        asm volatile("msync; isync");
+        mtspr(SPRN_L1CSR1, spr | L1CSR1_ICFI | L1CSR1_ICE | L1CSR1_ICPE);
+        asm volatile("msync; isync");
+
+        /* Enable L1 data */
+        if (!(mfspr(SPRN_L1CSR0) & L1CSR0_DCE)) {
+                asm volatile("msync; isync");
+                mtspr(SPRN_L1CSR0, 0x0);                /* Disable */
+                asm volatile("msync; isync");
+                mtspr(SPRN_L1CSR0, L1CSR0_DCFI);        /* Invalidate */
+                asm volatile("isync; sync");
+                spr = mfspr(SPRN_L1CSR0);
+                asm volatile("isync; sync");
+                mtspr(SPRN_L1CSR0, spr | L1CSR0_DCE | L1CSR0_DCPE); /* Enable */
+                asm volatile("isync; sync");
+        }
+
+	asm volatile ("eieio");
+	asm volatile ("isync");
+	/* Disable L2 */
+	writel(0, l2_ctl_addr);
+	readl(l2_ctl_addr);
+	asm volatile ("eieio");
+	/* Invalidate L2 */
+	writel(swab32(0x48000300), l2_ctl_addr);
+	readl(l2_ctl_addr);
+	asm volatile ("eieio");
+	/* Enable L2 error detection */
+	writel(0, l2_err_regs + L2_ERR_DIS - L2_ERR_REGS_OFFSET);
+	readl(l2_ctl_addr);
+	asm volatile ("eieio");
+	/* Clear any logged L2 errors */
+	writel(swab32(0x8000001D), l2_err_regs + L2_ERR_DET - L2_ERR_REGS_OFFSET);
+	readl(l2_ctl_addr);
+	asm volatile ("eieio");
+	/* Enable L2 */
+	writel(swab32(0x88000700), l2_ctl_addr);
+	readl(l2_ctl_addr);
+	asm volatile ("eieio");
+
+	printk("L2 cache enabled (256K cache, no memory-mapped SRAM). L2CTL reg: 0x%x\n",
+	     swab32(readl(l2_ctl_addr)));
+
+	iounmap(l2_ctl_addr);
+	of_node_put(dn);
+
+	return;
+}
+
+static void __init mvme3100_setup_arch(void)
+{
+	struct device_node *cpu;
+	struct device_node *np;
+
+	mvme3100_init_caches();
+
+	cpu = of_find_node_by_type(NULL, "cpu");
+	if (cpu != 0) {
+		const unsigned int *fp;
+
+		fp = of_get_property(cpu, "clock-frequency", NULL);
+		if (fp != 0)
+			loops_per_jiffy = *fp / HZ;
+		else
+			loops_per_jiffy = 50000000 / HZ;
+
+		fp = of_get_property(cpu, "bus-frequency", NULL);
+		if (fp != 0)
+			bus_frequency = *fp;
+		else
+			bus_frequency = 333333333;
+		of_node_put(cpu);
+	}
+
+        for_each_compatible_node(np, "pci", "fsl,mpc8540-pci")
+                fsl_add_bridge(np, 1);
+	ppc_md.pci_exclude_device = mvme3100_exclude_device;
+
+	printk("MVME3100 board from Emerson Network Power Embedded Computing\n");
+
+#ifdef  CONFIG_ROOT_NFS
+	ROOT_DEV = Root_NFS;
+#else
+	ROOT_DEV = Root_SDA2;
+#endif
+
+#ifdef CONFIG_VME_BRIDGE_BOOTMEM
+	vme_bootmem_size = CONFIG_VME_BRIDGE_BOOTMEM_SIZE * 1024 * 1024;
+
+	if (vme_bootmem_size > (total_memory / 2)) {
+		printk(KERN_WARNING
+		       "BOOTMEM Size Requested: 0x%x Total Memory 0x%lx\n",
+		       vme_bootmem_size, total_memory);
+		printk(KERN_WARNING
+		       "BOOTMEM Size requested has been capped at half the total memory\n");
+		vme_bootmem_size = total_memory / 2;
+	}
+	vme_driver_bootmem = __alloc_bootmem(vme_bootmem_size, 0x10000, 0);
+	if (!vme_driver_bootmem) {
+		printk(KERN_WARNING "Unable to obtain boot memory for VME\n");
+		vme_bootmem_size = 0;
+	} else {
+		printk(KERN_INFO
+		       "0x%x of boot memory reserved for setup of VME inbound window 7\n",
+		       vme_bootmem_size);
+	}
+#endif
+
+	mvme3100_misc_init();
+}
+
+void mvme3100_show_cpuinfo(struct seq_file *m)
+{
+	uint pvid, svid, phid1;
+	uint memsize = total_memory;
+	phys_addr_t immr_base;
+	void __iomem *reg_addr, *reg_block;
+	void __iomem *l2cache_addr;
+	u8 reg_value;
+	u32 reg32_value;
+	u32 l1csr0, l1csr1;
+	u32 l2ctl;
+	char buff[16] = "";
+
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
+	immr_base = get_immrbase();
+
+	seq_printf(m, "Vendor\t\t: Emerson Network Power Embedded Computing\n");
+	seq_printf(m, "Machine\t\t: MVME3100\n");
+	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+	seq_printf(m, "HID0\t\t: 0x%08lx\n", mfspr(SPRN_HID0));
+	seq_printf(m, "HID1\t\t: 0x%08lx\n", mfspr(SPRN_HID1));
+	seq_printf(m, "CCSR Base\t: 0x%08zx\n", immr_base);
+	seq_printf(m, "Bus Frequency\t: %08d\n", bus_frequency);
+
+	/* Display cpu Pll setting */
+	phid1 = mfspr(SPRN_HID1);
+	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+	/* Display the cache settings */
+	seq_printf(m, "\nCache Settings:\n");
+	l1csr0 = mfspr(SPRN_L1CSR0);
+	seq_printf(m, "L1CSR0 (L1 D-cache)\t: 0x%08x (%s)\n", l1csr0,
+		   (l1csr0 & 1) ? "on" : "off");
+	l1csr1 = mfspr(SPRN_L1CSR1);
+	seq_printf(m, "L1CSR1 (L1 I-cache)\t: 0x%08x (%s)\n", l1csr1,
+		   (l1csr1 & 1) ? "on" : "off");
+	seq_printf(m, "L1CFG0\t\t\t: 0x%08lx\n", mfspr(SPRN_L1CFG0));
+	seq_printf(m, "L1CFG1\t\t\t: 0x%08lx\n", mfspr(SPRN_L1CFG1));
+
+	l2cache_addr = ioremap(immr_base + 0x20000, 4);
+	l2ctl = swab32(readl(l2cache_addr));
+	seq_printf(m, "L2CTL (L2 cache)\t: 0x%x (%s)\n", l2ctl,
+		   (l2ctl & 0x80000000) ? "on" : "off");
+	iounmap(l2cache_addr);
+
+	seq_printf(m, "\nBOARD INFORMATION:\n");
+	reg_block = ioremap(MVME3100_SYSTEM_STATUS_REG, 16);
+	reg_addr = reg_block;
+
+	/* Display the amount of memory */
+	seq_printf(m, "Memory\t\t\t: %d MB\n", memsize / (1024 * 1024));
+
+	/* System Status Register */
+	reg_value = readb(reg_addr++);
+	seq_printf(m, "Safe Start Status\t: %s\n",
+		   ((reg_value & MVME3100_SAFE_START) ?
+		    "Safe ENV settings used" : "NVRAM ENV settings used"));
+	seq_printf(m, "Abort Status\t\t: %s\n",
+		   ((reg_value & MVME3100_ABORT_STATUS) ?
+		    "Abort Switch Asserted" : "Abort Switch Not Asserted"));
+	switch (reg_value & MVME3100_BOARD_TYPE_MASK) {
+	case MVME3100_BOARD_TYPE_PRPMC:
+		sprintf(buff, "PrPMC");
+		break;
+	case MVME3100_BOARD_TYPE_VME:
+		sprintf(buff, "VME");
+		break;
+	default:
+		sprintf(buff, "Unknown");
+		break;
+	}
+	seq_printf(m, "Board Type\t\t: %s\n", buff);
+
+	/* System Control Register */
+	reg_value = readb(reg_addr++);
+	seq_printf(m, "EEPROM WP Status\t: %s\n",
+		   ((reg_value & MVME3100_EEPROM_WP) ?
+		    "EEPROM Write Protected" : "EEPROM Not Write Protected"));
+	seq_printf(m, "DS1621 Thermostat\t: %s\n",
+		   ((reg_value & MVME3100_TSTAT_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+
+	/* Status Indicator Register */
+	reg_value = readb(reg_addr++);
+	seq_printf(m, "Board Fail LED\t\t: %s\n",
+		   ((reg_value & MVME3100_BRD_FAIL_LED) ? "Lit" : "Not Lit"));
+	seq_printf(m, "USR1 LED\t\t: %s\n",
+		   ((reg_value & MVME3100_USR1_LED) ? "Lit" : "Not Lit"));
+	seq_printf(m, "USR2 LED\t\t: %s\n",
+		   ((reg_value & MVME3100_USR2_LED) ? "Lit" : "Not Lit"));
+	seq_printf(m, "USR3 LED\t\t: %s\n",
+		   ((reg_value & MVME3100_USR3_LED) ? "Lit" : "Not Lit"));
+
+	/* Flash Control/Status Register */
+	reg_value = readb(reg_addr++);
+	seq_printf(m, "Flash Map Select\t: %s\n",
+		   ((reg_value & MVME3100_FLASH_MAP_SELECT) ?
+		    "Boot Block A Mapped to Highest Address" :
+		    "Flash Memory Map Controlled by Flash Boot Block Select"));
+	seq_printf(m, "Flash Write Protect SW\t: %s\n",
+		   ((reg_value & MVME3100_FLASH_WP_SW) ?
+		    "Write Protected" : "Not Write Protected"));
+	seq_printf(m, "Flash Write Protect HW\t: %s\n",
+		   ((reg_value & MVME3100_FLASH_WP_HW) ?
+		    "Write Protected" : "Not Write Protected"));
+	seq_printf(m, "Flash Boot Block Select\t: %s\n",
+		   ((reg_value & MVME3100_FLASH_BLK_SEL) ?
+		    "Boot Block B Selected" : "Boot Block A Selected"));
+	seq_printf(m, "Flash Ready Status\t: %s\n",
+		   ((reg_value & MVME3100_FLASH_RDY) ?
+		    "Bit Set" : "Bit Not Set"));
+
+	/* PCI Bus A Status Register */
+	reg_value = readb(reg_addr++);
+	seq_printf(m, "PCI Bus A 64 Bit\t: %s\n",
+		   ((reg_value & MVME3100_PCI_BUS_A_64B) ?
+		    "64 Bit Enabled" : "32 Bit Mode"));
+	seq_printf(m, "PCI Bus A PCI-X\t\t: %s\n",
+		   ((reg_value & MVME3100_PCI_BUS_A_PCIX) ?
+		    "PCI-X Mode" : "PCI Mode"));
+	switch (reg_value & MVME3100_PCI_BUS_A_SPD_MASK) {
+	case MVME3100_PCI_BUS_A_SPD_133:
+		sprintf(buff, "133 MHz");
+		break;
+	case MVME3100_PCI_BUS_A_SPD_100:
+		sprintf(buff, "100 MHz");
+		break;
+	case MVME3100_PCI_BUS_A_SPD_66:
+		sprintf(buff, "66 MHz");
+		break;
+	case MVME3100_PCI_BUS_A_SPD_33:
+	default:
+		sprintf(buff, "33 MHz");
+		break;
+	}
+	seq_printf(m, "PCI Bus A Speed\t\t: %s\n", buff);
+
+	/* PCI Bus B Status Register */
+	reg_value = readb(reg_addr++);
+	if (reg_value & MVME3100_PCI_BUS_B_3_3V_VIO) {
+		seq_printf(m, "PCI Bus B 3.3V VIO\t: %s\n",
+			   "Configured for 3.3V VIO");
+	};
+	if (reg_value & MVME3100_PCI_BUS_B_5_0V_VIO) {
+		seq_printf(m, "PCI Bus B 5.0V VIO\t: %s\n",
+			   "Configured for 5.0V VIO");
+	};
+	seq_printf(m, "PCI Bus B ERDY2\t\t: %d\n",
+		   ((reg_value & MVME3100_PCI_BUS_B_ERDY2) ? 1 : 0));
+	seq_printf(m, "PCI Bus B ERDY1\t\t: %d\n",
+		   ((reg_value & MVME3100_PCI_BUS_B_ERDY1) ? 1 : 0));
+	seq_printf(m, "PCI Bus B 64 Bit\t: %s\n",
+		   ((reg_value & MVME3100_PCI_BUS_B_64B) ?
+		    "64 Bit Enabled" : "32 Bit Mode"));
+	seq_printf(m, "PCI Bus B PCI-X\t\t: %s\n",
+		   ((reg_value & MVME3100_PCI_BUS_B_PCIX) ?
+		    "PCI-X Mode" : "PCI Mode"));
+	switch (reg_value & MVME3100_PCI_BUS_B_SPD_MASK) {
+	case MVME3100_PCI_BUS_B_SPD_133:
+		sprintf(buff, "133 MHz");
+		break;
+	case MVME3100_PCI_BUS_B_SPD_100:
+		sprintf(buff, "100 MHz");
+		break;
+	case MVME3100_PCI_BUS_B_SPD_66:
+		sprintf(buff, "66 MHz");
+		break;
+	case MVME3100_PCI_BUS_B_SPD_33:
+	default:
+		sprintf(buff, "33 MHz");
+		break;
+	}
+	seq_printf(m, "PCI Bus B Speed\t\t: %s\n", buff);
+
+	/* PCI Bus C Status Register */
+	reg_value = readb(reg_addr++);
+	seq_printf(m, "PCI Bus C 64 Bit\t: %s\n",
+		   ((reg_value & MVME3100_PCI_BUS_C_64B) ?
+		    "64 Bit Enabled" : "32 Bit Mode"));
+	seq_printf(m, "PCI Bus C PCI-X\t\t: %s\n",
+		   ((reg_value & MVME3100_PCI_BUS_C_PCIX) ?
+		    "PCI-X Mode" : "PCI Mode"));
+	switch (reg_value & MVME3100_PCI_BUS_C_SPD_MASK) {
+	case MVME3100_PCI_BUS_C_SPD_133:
+		sprintf(buff, "133 MHz");
+		break;
+	case MVME3100_PCI_BUS_C_SPD_100:
+		sprintf(buff, "100 MHz");
+		break;
+	case MVME3100_PCI_BUS_C_SPD_66:
+		sprintf(buff, "66 MHz");
+		break;
+	case MVME3100_PCI_BUS_C_SPD_33:
+	default:
+		sprintf(buff, "33 MHz");
+		break;
+	}
+	seq_printf(m, "PCI Bus C Speed\t\t: %s\n", buff);
+
+	/* Interrupt Detect Register */
+	reg_value = readb(reg_addr++);
+
+	if (reg_value & MVME3100_FEC_PHY_INTERRUPT) {
+		seq_printf(m, "FEC PHY Interrupt\t: %s\n", "Asserted");
+	} else {
+		seq_printf(m, "FEC PHY Interrupt\t: %s\n", "Not Asserted");
+	};
+	if (reg_value & MVME3100_TSEC2_PHY_INTERRUPT) {
+		seq_printf(m, "TSEC2 PHY Interrupt\t: %s\n", "Asserted");
+	} else {
+		seq_printf(m, "TSEC2 PHY Interrupt\t: %s\n", "Not Asserted");
+	};
+	if (reg_value & MVME3100_TSEC1_PHY_INTERRUPT) {
+		seq_printf(m, "TSEC1 PHY Interrupt\t: %s\n", "Asserted");
+	} else {
+		seq_printf(m, "TSEC1 PHY Interrupt\t: %s\n", "Not Asserted");
+	};
+
+	/* Presence Detect Register */
+	reg_value = readb(reg_addr++);
+
+	seq_printf(m, "PMCSPAN\t\t\t: %s\n",
+		   ((reg_value & MVME3100_PMCSPAN_PRESENT) ?
+		    "PMCSPAN Installed" : "PMCSPAN Not Installed"));
+	seq_printf(m, "PMC Site 2\t\t: %s\n",
+		   ((reg_value & MVME3100_PMC2_PRESENT) ?
+		    "PMC Module Installed" : "PMC Module Not Installed"));
+	seq_printf(m, "PMC Site 1\t\t: %s\n",
+		   ((reg_value & MVME3100_PMC1_PRESENT) ?
+		    "PMC Module Installed" : "PMC Module Not Installed"));
+
+	/* PLD Revision Register */
+	reg_value = readb(reg_addr++);
+
+	seq_printf(m, "PLD Revision\t\t: 0x%x\n", reg_value);
+
+	/* PLD Date Code Register */
+	reg_addr++;
+	reg_addr++;
+	reg32_value = readl((u32 *) reg_addr);
+	seq_printf(m, "PLD Date Code\t\t: 0x%08x\n",
+		   (((reg32_value & 0x000000ffU) << 24) |
+		    ((reg32_value & 0x0000ff00U) << 8) |
+		    ((reg32_value & 0x00ff0000U) >> 8) |
+		    ((reg32_value & 0xff000000U) >> 24)));
+
+	iounmap(reg_block);
+
+	return;
+}
+
+static void mvme3100_restart(char *cmd)
+{
+	volatile ulong i = 10000000;
+
+	local_irq_disable();
+	writeb(MVME3100_BOARD_RESET, system_control_reg_addr);
+
+	while (i-- > 0) ;
+	panic("restart failed\n");
+}
+
+static struct of_device_id of_bus_ids[] = {
+	{.type = "soc",},
+	{.compatible = "soc",},
+        {.compatible = "simple-bus", },
+	{},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+        of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+        return 0;
+}
+machine_device_initcall(mvme3100, declare_of_platform_devices);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mvme3100_probe(void)
+{
+        unsigned long root = of_get_flat_dt_root();
+
+        if (of_flat_dt_is_compatible(root, "MVME3100"))
+		return 1;
+	else
+		return 0;
+}
+
+define_machine(mvme3100)
+{
+	.name = "MVME3100",
+	.probe = mvme3100_probe,
+	.setup_arch = mvme3100_setup_arch,
+	.init_IRQ = mvme3100_init_irq,
+	.show_cpuinfo = mvme3100_show_cpuinfo,
+	.get_irq = mpic_get_irq,
+	.restart = mvme3100_restart,
+	.pcibios_fixup = mvme3100_pcibios_fixup,
+	.calibrate_decr = generic_calibrate_decr,
+	.progress = udbg_progress,
+};
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme3100.h linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme3100.h
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme3100.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme3100.h	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,119 @@
+/*
+ * arch/powerpc/platforms/85xx/mvme3100.h
+ *
+ * MVME3100 board definitions
+ *
+ * Ajit Prem <Ajit.Prem@emerson.com>
+ *
+ * Copyright 2004-2007 Motorola Inc.
+ * Copyright 2008-2009 Emerson Network Power Embedded Computing Inc.
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MVME3100_H__
+#define __MVME3100_H__
+
+#include <linux/init.h>
+
+/* Flash */
+#define MVME3100_FLASH_BASE_128M	0xf8000000
+#define MVME3100_FLASH_SIZE_128M	0x08000000
+
+#define MVME3100_FLASH_BASE_64M		0xfc000000
+#define MVME3100_FLASH_SIZE_64M		0x04000000
+
+/* System Control and Status Registers */
+#define MVME3100_SYSTEM_STATUS_REG	0xE2000000
+#define MVME3100_SYSTEM_CONTROL_REG	0xE2000001
+#define MVME3100_STATUS_INDICATOR_REG	0xE2000002
+#define MVME3100_FLASH_CTRL_STAT_REG	0xE2000003
+#define MVME3100_PCI_BUS_A_STATUS_REG	0xE2000004
+#define MVME3100_PCI_BUS_B_STATUS_REG	0xE2000005
+#define MVME3100_PCI_BUS_C_STATUS_REG	0xE2000006
+#define MVME3100_INTERRUPT_DETECT_REG	0xE2000007
+#define MVME3100_PRESENCE_DETECT_REG	0xE2000008
+#define MVME3100_PLD_REVISION_REG	0xE2000009
+#define MVME3100_PLD_DATE_CODE_REG	0xE200000C
+
+/* System Status Register */
+#define MVME3100_SAFE_START		0x10
+#define MVME3100_ABORT_STATUS		0x08
+#define MVME3100_BOARD_TYPE_MASK	0x03
+#define MVME3100_BOARD_TYPE_PRPMC	0x01
+#define MVME3100_BOARD_TYPE_VME		0x00
+
+/* System Control Register */
+#define MVME3100_BOARD_RESET		0xA0
+#define MVME3100_FEC_PHY_MASK		0x04
+#define MVME3100_EEPROM_WP		0x02
+#define MVME3100_TSTAT_MASK		0x01
+
+/* Status Indicator Register */
+#define MVME3100_BRD_FAIL_LED		0x01
+#define MVME3100_USR1_LED		0x02
+#define MVME3100_USR2_LED		0x04
+#define MVME3100_USR3_LED		0x08
+
+/* Flash Control/Status Register */
+#define MVME3100_FLASH_MAP_SELECT	0x10
+#define MVME3100_FLASH_WP_SW		0x08
+#define MVME3100_FLASH_WP_HW		0x04
+#define MVME3100_FLASH_BLK_SEL		0x02
+#define MVME3100_FLASH_RDY		0x01
+
+/* PCI Bus A Status Register */
+#define MVME3100_PCI_BUS_A_64B		0x08
+#define MVME3100_PCI_BUS_A_PCIX		0x04
+#define MVME3100_PCI_BUS_A_SPD_MASK	0x03
+#define MVME3100_PCI_BUS_A_SPD_133	0x03
+#define MVME3100_PCI_BUS_A_SPD_100	0x02
+#define MVME3100_PCI_BUS_A_SPD_66	0x01
+#define MVME3100_PCI_BUS_A_SPD_33	0x00
+
+/* PCI Bus B Status Register */
+#define MVME3100_PCI_BUS_B_3_3V_VIO	0x80
+#define MVME3100_PCI_BUS_B_5_0V_VIO	0x40
+#define MVME3100_PCI_BUS_B_ERDY2	0x20
+#define MVME3100_PCI_BUS_B_ERDY1	0x10
+#define MVME3100_PCI_BUS_B_64B		0x08
+#define MVME3100_PCI_BUS_B_PCIX		0x04
+#define MVME3100_PCI_BUS_B_SPD_MASK	0x03
+#define MVME3100_PCI_BUS_B_SPD_133	0x03
+#define MVME3100_PCI_BUS_B_SPD_100	0x02
+#define MVME3100_PCI_BUS_B_SPD_66	0x01
+#define MVME3100_PCI_BUS_B_SPD_33	0x00
+
+/* PCI Bus C Status Register */
+#define MVME3100_PCI_BUS_C_64B		0x08
+#define MVME3100_PCI_BUS_C_PCIX		0x04
+#define MVME3100_PCI_BUS_C_SPD_MASK	0x03
+#define MVME3100_PCI_BUS_C_SPD_133	0x03
+#define MVME3100_PCI_BUS_C_SPD_100	0x02
+#define MVME3100_PCI_BUS_C_SPD_66	0x01
+#define MVME3100_PCI_BUS_C_SPD_33	0x00
+
+/* Interrupt Detect Register */
+#define MVME3100_FEC_PHY_INTERRUPT	0x04
+#define MVME3100_TSEC2_PHY_INTERRUPT	0x02
+#define MVME3100_TSEC1_PHY_INTERRUPT	0x01
+
+/* Presence Detect Register */
+#define MVME3100_PMCSPAN_PRESENT	0x04
+#define MVME3100_PMC2_PRESENT		0x02
+#define MVME3100_PMC1_PRESENT		0x01
+
+#define MVME3100_BASE_BAUD		1843200
+#define QUART_BASE_BAUD			(MVME3100_BASE_BAUD / 16)
+#define MVME3100_UART_SIZE		0x8
+
+#define MVME3100_SERIAL_1	0xE2011000U
+#define MVME3100_SERIAL_2	0xE2012000U
+#define MVME3100_SERIAL_3	0xE2013000U
+#define MVME3100_SERIAL_4	0xE2014000U
+
+#endif				/* __MVME3100_H__ */
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme3100_timer.c linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme3100_timer.c
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme3100_timer.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme3100_timer.c	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,392 @@
+/*
+ * arch/powerpc/platforms/85xx/mvme3100_timer.c
+ *
+ * MVME3100 Tick Timers Support
+ *
+ * Author: Ajit Prem <Ajit.Prem@emerson.com>
+ *
+ * Copyright 2005-2007 Motorola Inc.
+ * Copyright 2008-2009 Emerson Network Power Embedded Computing Inc.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+#include "mvme3100.h"
+#include <asm/mvme3100_timer.h>
+
+#define MVME3100_TICK_TIMER_BASE                0xE2020000
+#define MVME3100_TICK_TIMER_BLOCK_SIZE          0x4C
+
+#define MVME3100_TICK_TIMER_PRESCALER_REG_OFFSET        0x0
+#define MVME3100_TICK_TIMER_CONTROL_REG_OFFSET          0x10
+#define MVME3100_TICK_TIMER_COMPARE_REG_OFFSET          0x14
+#define MVME3100_TICK_TIMER_COUNTER_REG_OFFSET          0x18
+
+#define MVME3100_TICK_TIMER_ENC                 0x00000001
+#define MVME3100_TICK_TIMER_COC                 0x00000002
+#define MVME3100_TICK_TIMER_COVF                0x00000004
+#define MVME3100_TICK_TIMER_OVF                 0x000000F0
+#define MVME3100_TICK_TIMER_ENINT               0x00000100
+#define MVME3100_TICK_TIMER_CINT                0x00000200
+#define MVME3100_TICK_TIMER_INTS                0x00000400
+
+#define	MIN_MICROSECONDS	10000
+#define MAX_TICKS		0xFFFFFFFF
+
+struct mvme3100_timer_t {
+	mvme3100_timer_f func;
+	void *func_data;
+	int started;
+	int periodic;
+	ulong period;
+	ulong ticks;
+};
+
+#define ALL_MSG "mvme3100_timer: "
+
+#ifdef MVME3100_TIMER_DEBUG
+int mvme3100_timer_debug = MVME3100_TIMER_DEBUG;
+MODULE_PARM(mvme3100_timer_debug, "i");
+#define DEBUG(n, fmt, args...) if (mvme3100_timer_debug>(n)) printk(KERN_INFO ALL_MSG fmt, ## args)
+static const char *version = "mvme3100_timer.c 1.0.1 (Ajit Prem)";
+#else
+#define DEBUG(n, fmt, args...)
+#endif
+
+extern int mvme3100_timer_irq;
+
+static struct mvme3100_timer_t mvme3100_timer[4];
+static void __iomem *mvme3100_timer_base;
+static u32 clk_out = 1;		/* Ticks per microsecond */
+static spinlock_t mvme3100_timer_lock = SPIN_LOCK_UNLOCKED;
+
+static irqreturn_t mvme3100_timer_int_handler(int irq, void *data)
+{
+	struct mvme3100_timer_t *info = data;
+	mvme3100_timer_f func;
+	void *func_data;
+	int timer_number;
+	u32 ctrl_reg;
+
+	for (timer_number = 0; timer_number <= 3; timer_number++) {
+		if (swab32(readl(mvme3100_timer_base +
+			 (timer_number + 1) *
+			 MVME3100_TICK_TIMER_CONTROL_REG_OFFSET)) &
+		   	 MVME3100_TICK_TIMER_INTS) {
+			info = &mvme3100_timer[timer_number];
+			func_data = info->func_data;
+			func = info->func;
+
+			if (!info->periodic) {
+				mvme3100_timer_stop(timer_number);
+			} else {
+				ctrl_reg = swab32(readl(mvme3100_timer_base +
+					((timer_number + 1) *
+					 MVME3100_TICK_TIMER_CONTROL_REG_OFFSET)));
+				ctrl_reg &= ~MVME3100_TICK_TIMER_ENC;
+				ctrl_reg =
+				    MVME3100_TICK_TIMER_COVF |
+				    MVME3100_TICK_TIMER_CINT;
+				writel(swab32(ctrl_reg),
+				       mvme3100_timer_base +
+				       ((timer_number + 1) *
+					MVME3100_TICK_TIMER_CONTROL_REG_OFFSET));
+				writel(0,
+				       mvme3100_timer_base +
+				       ((timer_number + 1) *
+					MVME3100_TICK_TIMER_CONTROL_REG_OFFSET)
+				       +
+				       (MVME3100_TICK_TIMER_COUNTER_REG_OFFSET -
+					MVME3100_TICK_TIMER_CONTROL_REG_OFFSET));
+				DEBUG(1,
+				      ("Timer %d Counter 0x%x Compare 0x%x\n",
+				       timer_number,
+				       swab32(readl
+					      (mvme3100_timer_base +
+					       ((timer_number + 1) *
+						MVME3100_TICK_TIMER_CONTROL_REG_OFFSET)
+					       +
+					       (MVME3100_TICK_TIMER_COUNTER_REG_OFFSET
+						-
+						MVME3100_TICK_TIMER_CONTROL_REG_OFFSET))),
+				       swab32(readl
+					      (mvme3100_timer_base +
+					       ((timer_number + 1) *
+						MVME3100_TICK_TIMER_CONTROL_REG_OFFSET)
+					       +
+					       (MVME3100_TICK_TIMER_COMPARE_REG_OFFSET
+						-
+						MVME3100_TICK_TIMER_CONTROL_REG_OFFSET)))));
+				writel(swab32
+				       (MVME3100_TICK_TIMER_ENC |
+					MVME3100_TICK_TIMER_COC |
+					MVME3100_TICK_TIMER_ENINT),
+				       mvme3100_timer_base + 
+					((timer_number + 1) *
+					MVME3100_TICK_TIMER_CONTROL_REG_OFFSET));
+			}
+			if (func) 
+				func(func_data);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* 
+ * Stop the timer
+ */
+EXPORT_SYMBOL(mvme3100_timer_stop);
+int mvme3100_timer_stop(int timer_number)
+{
+	u32 reset_value;
+	unsigned long flags;
+
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+
+	spin_lock_irqsave(&mvme3100_timer_lock, flags);
+	reset_value = swab32(readl(mvme3100_timer_base +
+				   ((timer_number + 1) *
+				    MVME3100_TICK_TIMER_CONTROL_REG_OFFSET)));
+	reset_value &= ~MVME3100_TICK_TIMER_ENC;
+	reset_value &= ~MVME3100_TICK_TIMER_ENINT;
+	reset_value = MVME3100_TICK_TIMER_COVF | MVME3100_TICK_TIMER_CINT;
+	writel(swab32(reset_value),
+	       mvme3100_timer_base +
+	       ((timer_number + 1) * MVME3100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0, mvme3100_timer_base +
+	       ((timer_number + 1) * MVME3100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME3100_TICK_TIMER_COUNTER_REG_OFFSET -
+		MVME3100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0xffffffff, mvme3100_timer_base +
+	       ((timer_number + 1) * MVME3100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME3100_TICK_TIMER_COMPARE_REG_OFFSET -
+		MVME3100_TICK_TIMER_CONTROL_REG_OFFSET));
+	mvme3100_timer[timer_number].func = NULL;
+	mvme3100_timer[timer_number].func_data = NULL;
+	mvme3100_timer[timer_number].started = 0;
+	mvme3100_timer[timer_number].periodic = 0;
+	mvme3100_timer[timer_number].period = 0;
+	mvme3100_timer[timer_number].ticks = 0xFFFFFFFF;
+	spin_unlock_irqrestore(&mvme3100_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Start the timer
+ */
+EXPORT_SYMBOL(mvme3100_timer_start);
+int mvme3100_timer_start(int timer_number, unsigned long microseconds,
+			 mvme3100_timer_f func, void *func_data, int periodic)
+{
+	int res = 0;
+	unsigned long flags;
+	unsigned long ticks;
+
+	printk(KERN_INFO
+	       "mvme3100_timer: start_timer: num %d microseconds 0x%lx periodic %d\n",
+	       timer_number, microseconds, periodic);
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+	if ((microseconds < MIN_MICROSECONDS) ||
+	    (microseconds > MAX_TICKS / clk_out))
+		return -EINVAL;
+	if (func == NULL)
+		return -EINVAL;
+	if (mvme3100_timer[timer_number].started == 1)
+		return -EBUSY;
+	if ((res = mvme3100_timer_stop(timer_number)) < 0)
+		return res;
+	ticks = microseconds * clk_out;
+	spin_lock_irqsave(&mvme3100_timer_lock, flags);
+	mvme3100_timer[timer_number].started = 1;
+	mvme3100_timer[timer_number].func = func;
+	mvme3100_timer[timer_number].func_data = func_data;
+	mvme3100_timer[timer_number].periodic = periodic;
+	mvme3100_timer[timer_number].period = microseconds;
+	mvme3100_timer[timer_number].ticks = ticks;
+	writel(swab32(ticks), mvme3100_timer_base +
+	       ((timer_number + 1) * MVME3100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME3100_TICK_TIMER_COMPARE_REG_OFFSET -
+		MVME3100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0, mvme3100_timer_base +
+	       ((timer_number + 1) * MVME3100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME3100_TICK_TIMER_COUNTER_REG_OFFSET -
+		MVME3100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(swab32(MVME3100_TICK_TIMER_ENC | MVME3100_TICK_TIMER_COC |
+		      MVME3100_TICK_TIMER_ENINT),
+	       mvme3100_timer_base +
+	       ((timer_number + 1) * MVME3100_TICK_TIMER_CONTROL_REG_OFFSET));
+	spin_unlock_irqrestore(&mvme3100_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Get the timer resolution, in microseconds/tick
+ */
+EXPORT_SYMBOL(mvme3100_timer_get_resolution);
+unsigned long mvme3100_timer_get_resolution(void)
+{
+	u32 prescaler_adjust;
+
+	/* 
+	 * Prescaler_adjust = 256 - CLKIN/CLKOUT
+	 * CLKIN = 25 MHz
+	 */
+
+	prescaler_adjust = readl(mvme3100_timer_base +
+				 MVME3100_TICK_TIMER_PRESCALER_REG_OFFSET);
+	return (25 / (256 - prescaler_adjust));
+}
+
+/* 
+ * Set the timer resolution, in ticks/microsecond
+ */
+EXPORT_SYMBOL(mvme3100_timer_set_resolution);
+int mvme3100_timer_set_resolution(unsigned long ticks)
+{
+	u32 prescaler_adjust;
+	int i;
+	unsigned long flags;
+
+	/* 
+	 * Prescaler_adjust = 256 - CLKIN/CLKOUT
+	 * CLKIN = 25 MHz
+	 */
+
+	if ((ticks < MIN_TICKS_PER_MICROSECOND) ||
+	    (ticks > MAX_TICKS_PER_MICROSECOND))
+		return -EINVAL;
+
+	clk_out = ticks;
+	prescaler_adjust = 256 - (25 / clk_out);
+
+	spin_lock_irqsave(&mvme3100_timer_lock, flags);
+	for (i = 0; i <= 3; i++) {
+		if (mvme3100_timer[i].started == 1) {
+			spin_unlock_irqrestore(&mvme3100_timer_lock, flags);
+			return -EBUSY;
+		}
+	}
+
+	writel(prescaler_adjust, mvme3100_timer_base +
+	       MVME3100_TICK_TIMER_PRESCALER_REG_OFFSET);
+	spin_unlock_irqrestore(&mvme3100_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Get the timer value, in ticks
+ */
+EXPORT_SYMBOL(mvme3100_timer_get_ticks);
+unsigned long mvme3100_timer_get_ticks(int timer_number)
+{
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+
+	return swab32(readl(mvme3100_timer_base +
+			    ((timer_number +
+			      1) * MVME3100_TICK_TIMER_CONTROL_REG_OFFSET) +
+			    (MVME3100_TICK_TIMER_COUNTER_REG_OFFSET -
+			     MVME3100_TICK_TIMER_CONTROL_REG_OFFSET)));
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int
+mvme3100_timer_proc_read(char *buf, char **start, off_t off, int len, int *eof,
+			 void *data)
+{
+	int i;
+
+	len = 0;
+	len +=
+	    sprintf(buf + len,
+		    "\nTimer     Active  Periodic  Period(ticks)   Period(microseconds)\n");
+	len +=
+	    sprintf(buf + len,
+		    "_____     ______  ________  _____________   ____________________\n");
+	for (i = 0; i <= 3; i++) {
+		len +=
+		    sprintf(buf + len,
+			    "#%d        %c       %c         0x%08lx      %ld\n",
+			    i + 1,
+			    ((mvme3100_timer[i].started == 1) ? 'y' : 'n'),
+			    ((mvme3100_timer[i].periodic == 1) ? 'y' : 'n'),
+			    ((mvme3100_timer[i].periodic ==
+			      1) ? mvme3100_timer[i].ticks : 0),
+			    ((mvme3100_timer[i].periodic ==
+			      1) ? mvme3100_timer[i].period : 0));
+	}
+	return len;
+}
+
+#endif				/* CONFIG_PROC_FS */
+
+static __init int mvme3100_timer_init(void)
+{
+	int res = 0;
+	int i;
+
+	printk(KERN_INFO "mvme3100-timer: MVME3100 Tick Timers\n");
+
+	mvme3100_timer_base = ioremap(MVME3100_TICK_TIMER_BASE,
+				     MVME3100_TICK_TIMER_BLOCK_SIZE);
+	if (mvme3100_timer_base == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i <= 3; i++) {
+		mvme3100_timer[i].func = NULL;
+		mvme3100_timer[i].func_data = NULL;
+		mvme3100_timer[i].started = 0;
+		mvme3100_timer[i].periodic = 0;
+		mvme3100_timer[i].period = 0;
+		mvme3100_timer[i].ticks = 0;
+	}
+	res = request_irq(mvme3100_timer_irq, mvme3100_timer_int_handler,
+			  IRQF_SHARED,
+			  "MVME3100 Tick Timers", &mvme3100_timer[0]);
+	if (res < 0) {
+		printk(KERN_ERR "MVME3100 Timer: Can't allocate IRQ %d.\n",
+		       mvme3100_timer_irq);
+		return res;
+	}
+#ifdef CONFIG_PROC_FS
+	create_proc_read_entry("mvme3100_timers", 0, NULL,
+			       mvme3100_timer_proc_read, NULL);
+#endif
+	return 0;
+}
+
+static __exit void mvme3100_timer_exit(void)
+{
+	int timer_number;
+
+	for (timer_number = 0; timer_number <= 3; timer_number++) {
+		mvme3100_timer_stop(timer_number);
+	}
+	free_irq(mvme3100_timer_irq, &mvme3100_timer[0]);
+	iounmap(mvme3100_timer_base);
+}
+
+MODULE_LICENSE("GPL");
+
+MODULE_AUTHOR("Ajit Prem <Ajit.Prem@motorola.com>");
+MODULE_DESCRIPTION("MVME3100 Tick Timer driver");
+
+module_init(mvme3100_timer_init);
+module_exit(mvme3100_timer_exit);
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme4100.c linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme4100.c
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme4100.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme4100.c	2009-09-02 10:30:57.000000000 -0700
@@ -0,0 +1,1543 @@
+/*
+ * MVME4100 setup and early boot code plus other random bits.
+ *
+ * Author: Ajit Prem
+ *
+ * Copyright 2008 Emerson Network Power Embedded Computing, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/reboot.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/initrd.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/root_dev.h>
+#include <linux/rtc.h>
+#include <linux/highmem.h>
+#include <linux/fsl_devices.h>
+#include <linux/of_platform.h>
+
+#include <asm/system.h>
+#include <asm/pgtable.h>
+#include <asm/page.h>
+#include <asm/atomic.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/irq.h>
+#include <mm/mmu_decl.h>
+#include <asm/prom.h>
+#include <asm/kmap_types.h>
+#include <asm/edac.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+
+#include "mvme4100.h"
+
+static unsigned long hb_baddr;
+static int serial_irq;
+
+static void __iomem *system_control_reg_addr;
+static void __iomem *l2_err_regs;
+
+#define L2_ERR_REGS_OFFSET      0x20E20
+#define L2_ERR_REGS_SIZE        0x3C
+
+#define L2_CAPT_DATA_HI         0x20E20
+#define L2_CAPT_DATA_LO         0x20E24
+#define L2_CAPT_ECC             0x20E28
+#define L2_ERR_DET              0x20E40
+#define L2_ERR_DIS              0x20E44
+#define L2_ERR_INT_EN           0x20E48
+#define L2_ERR_ATTR             0x20E4C
+#define L2_ERR_ADDR_HI          0x20E50
+#define L2_ERR_ADDR_LO          0x20E54
+#define L2_ERR_CTL              0x20E58
+
+#ifdef CONFIG_MVME4100_ENABLE_L2_ERRORS
+static int l2_irq;
+static irqreturn_t mvme4100_l2cache_err_handler(int irq, void *dev_id);
+#endif
+
+#ifdef CONFIG_MVME4100_ENABLE_DDR_ERRORS
+
+#define DDR_ERR_REGS_OFFSET     0x2E00
+#define DDR_ERR_REGS_SIZE       0x5C
+
+#define DDR_CAPT_DATA_HI        0x2E20
+#define DDR_CAPT_DATA_LO        0x2E24
+#define DDR_CAPT_ECC            0x2E28
+#define DDR_ERR_DET             0x2E40
+#define DDR_ERR_DIS             0x2E44
+#define DDR_ERR_INT_EN          0x2E48
+#define DDR_CAPT_ATTR           0x2E4C
+#define DDR_CAPT_ADDR           0x2E50
+#define DDR_CAPT_EXT_ADDR       0x2E54
+#define DDR_ERR_SBE             0x2E58
+
+#define DDR_SBE                 0x4	/* single-bit ECC error */
+#define DDR_MBE                 0x8	/* multi-bit ECC error */
+#define DDR_MME                 0x80000000	/* multiple ECC error */
+
+static int ddr_errors;
+static void __iomem *ddr_err_regs;
+static int ddr_irq;
+static irqreturn_t mvme4100_ddr_err_handler(int irq, void *dev_id);
+
+#endif
+
+#define PCI0_REGS_OFFSET        0x8000
+#define PCI2_REGS_OFFSET        0xA000
+#define PCI_ERR_REGS_OFFSET     0xE00
+#define PCI_ERR_REGS_SIZE       0x38
+
+#define PCI_ERR_DET             0xE00
+#define PCI_ERR_INT_EN          0xE08
+#define PCI_ERR_CAP_DIS         0xE10
+#define PCI_ERR_CAP_STAT        0xE20
+#define PCI_ERR_CAP_R0          0xE28
+#define PCI_ERR_CAP_R1          0xE2C
+#define PCI_ERR_CAP_R2          0xE30
+#define PCI_ERR_CAP_R3          0xE34
+
+static int pci0_irq;
+static int pci2_irq;
+
+#ifdef CONFIG_MVME4100_ENABLE_PCI_ERRORS
+static int pci0_errors;
+static void __iomem *pci0_err_regs;
+static irqreturn_t mvme4100_pci0_err_handler(int irq, void *dev_id);
+
+static int pci2_errors;
+static void __iomem *pci2_err_regs;
+static irqreturn_t mvme4100_pci2_err_handler(int irq, void *dev_id);
+#endif
+
+#ifdef CONFIG_VME_BRIDGE_BOOTMEM
+void *vme_driver_bootmem;
+unsigned int vme_bootmem_size;
+#endif
+
+#ifdef CONFIG_MVME4100_TICK_TIMERS
+int mvme4100_timer_irq;
+#endif
+
+#ifdef CONFIG_SENSORS_LM90
+int maxim6649_irq;
+#endif
+
+#ifdef CONFIG_MVME4100_ENABLE_DDR_ERRORS
+
+static void mvme4100_determine_bit_location(u32 data_hi, u32 data_lo,
+					    u32 stored_ecc)
+{
+	u32 syndrome_bits;
+	u32 syndrome[8];
+	u32 calculated_ecc = 0;
+	int i;
+	u32 data0[32], data1[32];
+	unsigned char bitpos[8];
+
+	/* Initial 32-bit data */
+	for (i = 0; i < 32; i++) {
+		data0[i] = (data_hi >> (31 - i)) & 0x1;
+		data1[i] = (data_lo >> (31 - i)) & 0x1;
+	}
+
+	for (i = 0; i < 8; i++)
+		syndrome[i] = 0;
+	/* Calculate 8-bit ECC for the first 32-bit data */
+	for (i = 0; i < 32; ++i) {
+		/* Calculate syndrome[0] */
+		if ((i <= 15) || (i == 19) || (i == 23) || (i == 27) ||
+		    (i == 31))
+			syndrome[0] = syndrome[0] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[1] */
+		if ((i == 0) || (i == 4) || (i == 8) || (i == 12) || (i >= 16))
+			syndrome[1] = syndrome[1] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[2] */
+		if ((i == 1) || (i == 5) || (i == 9) || (i == 13) ||
+		    (i == 16) || (i == 20) || (i == 24) || (i == 28))
+			syndrome[2] = syndrome[2] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[3] */
+		if ((i == 2) || (i == 6) || (i == 10) || (i == 14) ||
+		    (i == 17) || (i == 21) || (i == 25) || (i == 29))
+			syndrome[3] = syndrome[3] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[4] */
+		if ((i == 3) || (i == 7) || (i == 11) || (i == 15) ||
+		    (i == 18) || (i == 19) || (i == 22) || (i == 23) ||
+		    (i == 26) || (i == 27) || (i == 30) || (i == 31))
+			syndrome[4] = syndrome[4] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[5] */
+		if (((i >= 4) && (i <= 7)) || ((i >= 12) && (i <= 15)) ||
+		    ((i >= 20) && (i <= 23)) || ((i >= 28) && (i <= 31)))
+			syndrome[5] = syndrome[5] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[6] */
+		if (((i >= 8) && (i <= 15)) || ((i >= 24) && (i <= 31)))
+			syndrome[6] = syndrome[6] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[7] */
+		if ((i <= 3) || ((i >= 12) && (i <= 18)) ||
+		    (i == 23) || ((i >= 27) && (i <= 30)))
+			syndrome[7] = syndrome[7] ^ (data0[i] & 0x1);
+	}
+
+	/* Calculate 8-bit ECC for the second 32-bit data */
+	for (i = 0; i < 32; ++i) {
+		/* Calculate syndrome[0] */
+		if ((i == 2) || (i == 6) || (i == 10) || (i == 14) ||
+		    (i == 19) || (i == 23) || (i == 27) || (i == 29))
+			syndrome[0] = syndrome[0] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[1] */
+		if ((i == 3) || (i == 7) || (i == 11) || (i == 15) ||
+		    (i == 16) || (i == 20) || (i == 24) || (i == 30))
+			syndrome[1] = syndrome[1] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[2] */
+		if ((i <= 15) || (i == 17) || (i == 21) || (i == 25) |
+		    (i == 31))
+			syndrome[2] = syndrome[2] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[3] */
+		if ((i == 0) || (i == 4) || (i == 8) || (i == 12) ||
+		    (i == 18) || (i == 22) || (i == 26) || (i >= 28))
+			syndrome[3] = syndrome[3] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[4] */
+		if (((i >= 1) && (i <= 3)) || ((i >= 5) && (i <= 7)) ||
+		    ((i >= 9) && (i <= 11)) || ((i >= 13) && (i <= 15)) ||
+		    ((i >= 28) && (i <= 31)))
+			syndrome[4] = syndrome[4] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[5] */
+		if (((i >= 4) && (i <= 7)) || ((i >= 12) && (i <= 23)))
+			syndrome[5] = syndrome[5] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[6] */
+		if (((i >= 8) && (i <= 19)) || ((i >= 24) && (i <= 31)))
+			syndrome[6] = syndrome[6] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[7] */
+		if ((i == 0) || (i == 1) || (i == 6) || (i == 7) ||
+		    ((i >= 10) && (i <= 13)) || ((i >= 20) && (i <= 27)) ||
+		    ((i >= 29) && (i <= 31)))
+			syndrome[7] = syndrome[7] ^ (data1[i] & 0x1);
+	}
+
+	calculated_ecc = ((syndrome[7] << 0) | (syndrome[6] << 1) |
+			  (syndrome[5] << 2) | (syndrome[4] << 3) |
+			  (syndrome[3] << 4) | (syndrome[2] << 5) |
+			  (syndrome[1] << 6) | (syndrome[0] << 7));
+
+	syndrome_bits = calculated_ecc ^ stored_ecc;
+
+	switch (syndrome_bits) {
+	case 0xC1:
+		sprintf(bitpos, "%s", "0");
+		break;
+	case 0xA1:
+		sprintf(bitpos, "%s", "1");
+		break;
+	case 0x91:
+		sprintf(bitpos, "%s", "2");
+		break;
+	case 0x89:
+		sprintf(bitpos, "%s", "3");
+		break;
+	case 0xC4:
+		sprintf(bitpos, "%s", "4");
+		break;
+	case 0xA4:
+		sprintf(bitpos, "%s", "5");
+		break;
+	case 0x94:
+		sprintf(bitpos, "%s", "6");
+		break;
+	case 0x8C:
+		sprintf(bitpos, "%s", "7");
+		break;
+	case 0xC2:
+		sprintf(bitpos, "%s", "8");
+		break;
+	case 0xA2:
+		sprintf(bitpos, "%s", "9");
+		break;
+	case 0x92:
+		sprintf(bitpos, "%s", "10");
+		break;
+	case 0x8A:
+		sprintf(bitpos, "%s", "11");
+		break;
+	case 0xC7:
+		sprintf(bitpos, "%s", "12");
+		break;
+	case 0xA7:
+		sprintf(bitpos, "%s", "13");
+		break;
+	case 0x97:
+		sprintf(bitpos, "%s", "14");
+		break;
+	case 0x8F:
+		sprintf(bitpos, "%s", "15");
+		break;
+	case 0x61:
+		sprintf(bitpos, "%s", "16");
+		break;
+	case 0x51:
+		sprintf(bitpos, "%s", "17");
+		break;
+	case 0x49:
+		sprintf(bitpos, "%s", "18");
+		break;
+	case 0xC8:
+		sprintf(bitpos, "%s", "19");
+		break;
+	case 0x64:
+		sprintf(bitpos, "%s", "20");
+		break;
+	case 0x54:
+		sprintf(bitpos, "%s", "21");
+		break;
+	case 0x4C:
+		sprintf(bitpos, "%s", "22");
+		break;
+	case 0xCD:
+		sprintf(bitpos, "%s", "23");
+		break;
+	case 0x62:
+		sprintf(bitpos, "%s", "24");
+		break;
+	case 0x52:
+		sprintf(bitpos, "%s", "25");
+		break;
+	case 0x4A:
+		sprintf(bitpos, "%s", "26");
+		break;
+	case 0xCB:
+		sprintf(bitpos, "%s", "27");
+		break;
+	case 0x67:
+		sprintf(bitpos, "%s", "28");
+		break;
+	case 0x57:
+		sprintf(bitpos, "%s", "29");
+		break;
+	case 0x4F:
+		sprintf(bitpos, "%s", "30");
+		break;
+	case 0xCE:
+		sprintf(bitpos, "%s", "31");
+		break;
+	case 0x31:
+		sprintf(bitpos, "%s", "32");
+		break;
+	case 0x29:
+		sprintf(bitpos, "%s", "33");
+		break;
+	case 0xA8:
+		sprintf(bitpos, "%s", "34");
+		break;
+	case 0x68:
+		sprintf(bitpos, "%s", "35");
+		break;
+	case 0x34:
+		sprintf(bitpos, "%s", "36");
+		break;
+	case 0x2C:
+		sprintf(bitpos, "%s", "37");
+		break;
+	case 0xAD:
+		sprintf(bitpos, "%s", "38");
+		break;
+	case 0x6D:
+		sprintf(bitpos, "%s", "39");
+		break;
+	case 0x32:
+		sprintf(bitpos, "%s", "40");
+		break;
+	case 0x2A:
+		sprintf(bitpos, "%s", "41");
+		break;
+	case 0xAB:
+		sprintf(bitpos, "%s", "42");
+		break;
+	case 0x6B:
+		sprintf(bitpos, "%s", "43");
+		break;
+	case 0x37:
+		sprintf(bitpos, "%s", "44");
+		break;
+	case 0x2F:
+		sprintf(bitpos, "%s", "45");
+		break;
+	case 0xAE:
+		sprintf(bitpos, "%s", "46");
+		break;
+	case 0x6E:
+		sprintf(bitpos, "%s", "47");
+		break;
+	case 0x46:
+		sprintf(bitpos, "%s", "48");
+		break;
+	case 0x26:
+		sprintf(bitpos, "%s", "49");
+		break;
+	case 0x16:
+		sprintf(bitpos, "%s", "50");
+		break;
+	case 0x86:
+		sprintf(bitpos, "%s", "51");
+		break;
+	case 0x45:
+		sprintf(bitpos, "%s", "52");
+		break;
+	case 0x25:
+		sprintf(bitpos, "%s", "53");
+		break;
+	case 0x15:
+		sprintf(bitpos, "%s", "54");
+		break;
+	case 0x85:
+		sprintf(bitpos, "%s", "55");
+		break;
+	case 0x43:
+		sprintf(bitpos, "%s", "56");
+		break;
+	case 0x23:
+		sprintf(bitpos, "%s", "57");
+		break;
+	case 0x13:
+		sprintf(bitpos, "%s", "58");
+		break;
+	case 0x83:
+		sprintf(bitpos, "%s", "59");
+		break;
+	case 0x1A:
+		sprintf(bitpos, "%s", "60");
+		break;
+	case 0x9B:
+		sprintf(bitpos, "%s", "61");
+		break;
+	case 0x5B:
+		sprintf(bitpos, "%s", "62");
+		break;
+	case 0x3B:
+		sprintf(bitpos, "%s", "63");
+		break;
+	case 0x80:
+		sprintf(bitpos, "%s", "ECC-0");
+		break;
+	case 0x40:
+		sprintf(bitpos, "%s", "ECC-1");
+		break;
+	case 0x20:
+		sprintf(bitpos, "%s", "ECC-2");
+		break;
+	case 0x10:
+		sprintf(bitpos, "%s", "ECC-3");
+		break;
+	case 0x08:
+		sprintf(bitpos, "%s", "ECC-4");
+		break;
+	case 0x04:
+		sprintf(bitpos, "%s", "ECC-5");
+		break;
+	case 0x02:
+		sprintf(bitpos, "%s", "ECC-6");
+		break;
+	case 0x01:
+		sprintf(bitpos, "%s", "ECC-7");
+		break;
+	default:
+		sprintf(bitpos, "%s", "UNKNOWN");
+		break;
+	}
+	printk(KERN_ERR "DDR ERROR CALCULATED ECC: 0x%02x\n", calculated_ecc);
+	printk(KERN_ERR "DDR ERROR STORED ECC: 0x%02x\n", stored_ecc);
+	printk(KERN_ERR "DDR ERROR ECC SYNDROME: 0x%02x\n",
+	       calculated_ecc ^ stored_ecc);
+	printk(KERN_ERR "DDR ERROR BIT LOCATION: %s\n", bitpos);
+}
+
+
+static irqreturn_t mvme4100_ddr_err_handler(int irq, void *dev_id)
+{
+	u32 err_addr, data_hi, data_lo, ecc, err_attr, err_det, sbe_count;
+	u32 pfn, offset;
+	struct page *pg;
+	void *virt_addr;
+	unsigned long flags = 0;
+
+	err_det = readl(ddr_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+	if (!err_det)
+		return IRQ_NONE;
+
+	/* Collect error information from the error registers */
+	err_attr = readl(ddr_err_regs + DDR_CAPT_ATTR - DDR_ERR_REGS_OFFSET);
+	data_hi = readl(ddr_err_regs + DDR_CAPT_DATA_HI - DDR_ERR_REGS_OFFSET);
+	data_lo = readl(ddr_err_regs + DDR_CAPT_DATA_LO - DDR_ERR_REGS_OFFSET);
+	err_addr = readl(ddr_err_regs + DDR_CAPT_ADDR - DDR_ERR_REGS_OFFSET);
+	ecc = readl(ddr_err_regs + DDR_CAPT_ECC - DDR_ERR_REGS_OFFSET);
+	sbe_count = readl(ddr_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+
+	ddr_errors++;
+
+	/* Display error information */
+	printk(KERN_ERR "DDR Error!\n");
+	printk(KERN_ERR "DDR ERROR DETECT REG 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "DDR ERROR ADDRESS CAPTURE REG 0x%08x\n",
+	       swab32(err_addr));
+	printk(KERN_ERR "DDR ERROR DATA HIGH CAPTURE REG 0x%08x\n",
+	       swab32(data_hi));
+	printk(KERN_ERR "DDR ERROR DATA LOW CAPTURE REG 0x%08x\n",
+	       swab32(data_lo));
+	printk(KERN_ERR "DDR ERROR ATTRIBUTES CAPTURE REG 0x%08x\n",
+	       swab32(err_attr));
+	printk(KERN_ERR "DDR ERROR SBE REG 0x%08x\n", swab32(sbe_count));
+	printk(KERN_ERR "DDR ERROR COUNT %u\n", ddr_errors);
+
+	if (err_det & DDR_SBE) {
+		/* Scrub block */
+		pfn = err_addr >> PAGE_SHIFT;
+		offset = err_addr & ~PAGE_MASK;
+
+		pg = pfn_to_page(pfn);
+
+		if (PageHighMem(pg))
+			local_irq_save(flags);
+
+		virt_addr = kmap_atomic(pg, KM_BOUNCE_READ);
+		atomic_scrub(virt_addr + offset, 8);
+		kunmap_atomic(virt_addr, KM_BOUNCE_READ);
+
+		if (PageHighMem(pg))
+			local_irq_restore(flags);
+	}
+
+	/* Determine and display bit location */
+	mvme4100_determine_bit_location(swab32(data_hi),
+					swab32(data_lo), swab32(ecc) & 0xff);
+
+	/* Clear interrupt cause register */
+	writel(err_det, ddr_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+
+	/* Clear capture attributes register */
+	writel(0, ddr_err_regs + DDR_CAPT_ATTR - DDR_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+
+#endif
+
+#ifdef CONFIG_MVME4100_ENABLE_L2_ERRORS
+
+static irqreturn_t mvme4100_l2cache_err_handler(int irq, void *dev_id)
+{
+	u32 err_addr_hi, err_addr_lo, data_hi, data_lo, ecc, err_attr, err_det;
+
+	err_det = readl(l2_err_regs + L2_ERR_DET - L2_ERR_REGS_OFFSET);
+	if (!err_det)
+		return IRQ_NONE;
+
+	/* Collect error information from the error registers */
+	err_attr = readl(l2_err_regs + L2_ERR_ATTR - L2_ERR_REGS_OFFSET);
+	err_addr_hi = readl(l2_err_regs + L2_ERR_ADDR_HI - L2_ERR_REGS_OFFSET);
+	err_addr_lo = readl(l2_err_regs + L2_ERR_ADDR_LO - L2_ERR_REGS_OFFSET);
+	data_hi = readl(l2_err_regs + L2_CAPT_DATA_HI - L2_ERR_REGS_OFFSET);
+	data_lo = readl(l2_err_regs + L2_CAPT_DATA_LO - L2_ERR_REGS_OFFSET);
+	ecc = readl(l2_err_regs + L2_CAPT_ECC - L2_ERR_REGS_OFFSET);
+
+	/* Clear interrupt cause and capture registers */
+	writel(err_det, l2_err_regs + L2_ERR_DET - L2_ERR_REGS_OFFSET);
+	writel(0, l2_err_regs + L2_ERR_ATTR - L2_ERR_REGS_OFFSET);
+
+	/* Display error information */
+	printk(KERN_ERR "L2 Cache Error!\n");
+	printk(KERN_ERR "L2 ERROR DETECT REG 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "L2 ERROR ADDRESS HIGH CAPTURE REG 0x%08x\n",
+	       swab32(err_addr_hi));
+	printk(KERN_ERR "L2 ERROR ADDRESS LOW CAPTURE REG 0x%08x\n",
+	       swab32(err_addr_lo));
+	printk(KERN_ERR "L2 ERROR DATA HIGH CAPTURE REG 0x%08x\n",
+	       swab32(data_hi));
+	printk(KERN_ERR "L2 ERROR DATA LOW CAPTURE REG 0x%08x\n",
+	       swab32(data_lo));
+	printk(KERN_ERR "L2 ERROR ATTRIBUTES CAPTURE REG 0x%08x\n",
+	       swab32(err_attr));
+	printk(KERN_ERR "L2 ERROR SYNDROME REG 0x%08x\n", swab32(ecc));
+
+	return IRQ_HANDLED;
+}
+
+#endif
+
+#ifdef CONFIG_MVME4100_ENABLE_PCI_ERRORS
+
+static irqreturn_t mvme4100_pci0_err_handler(int irq, void *dev_id)
+{
+	u32 err_det, err_status, err_cap0, err_cap1, err_cap2, err_cap3;
+
+	if (dev_id != &pci0_err_regs)
+		return IRQ_NONE;
+
+	/* Collect error information from the error registers */
+	err_det = readl(pci0_err_regs + PCI_ERR_DET - PCI_ERR_REGS_OFFSET);
+	if (!err_det)
+		return IRQ_NONE;
+
+	err_status =
+	    readl(pci0_err_regs + PCI_ERR_CAP_STAT - PCI_ERR_REGS_OFFSET);
+	err_cap0 = readl(pci0_err_regs + PCI_ERR_CAP_R0 - PCI_ERR_REGS_OFFSET);
+	err_cap1 = readl(pci0_err_regs + PCI_ERR_CAP_R1 - PCI_ERR_REGS_OFFSET);
+	err_cap2 = readl(pci0_err_regs + PCI_ERR_CAP_R2 - PCI_ERR_REGS_OFFSET);
+	err_cap3 = readl(pci0_err_regs + PCI_ERR_CAP_R3 - PCI_ERR_REGS_OFFSET);
+
+	pci0_errors++;
+	/* Display error information */
+	printk(KERN_ERR "PCI Controller 0 Error!\n");
+	printk(KERN_ERR "PCI ERROR DETECT REG 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "PCI ERR CAP STATUS REG 0x%08x\n", swab32(err_status));
+	printk(KERN_ERR "PCI ERR CAP REG0 0x%08x\n", swab32(err_cap0));
+	printk(KERN_ERR "PCI ERR CAP REG1 0x%08x\n", swab32(err_cap1));
+	printk(KERN_ERR "PCI ERR CAP REG2 0x%08x\n", swab32(err_cap2));
+	printk(KERN_ERR "PCI ERR CAP REG3 0x%08x\n", swab32(err_cap3));
+	printk(KERN_ERR "PCI Error Count: %u\n", pci0_errors);
+
+	/* Clear interrupt cause and capture registers */
+	writel(err_det, pci0_err_regs + PCI_ERR_DET - PCI_ERR_REGS_OFFSET);
+	writel(swab32(0x1),
+	       pci0_err_regs + PCI_ERR_CAP_STAT - PCI_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mvme4100_pci2_err_handler(int irq, void *dev_id)
+{
+	u32 err_det, err_status, err_cap0, err_cap1, err_cap2, err_cap3;
+
+	if (dev_id != &pci2_err_regs)
+		return IRQ_NONE;
+
+	/* Collect error information from the error registers */
+	err_det = readl(pci2_err_regs + PCI_ERR_DET - PCI_ERR_REGS_OFFSET);
+	if (!err_det)
+		return IRQ_NONE;
+
+	err_status =
+	    readl(pci2_err_regs + PCI_ERR_CAP_STAT - PCI_ERR_REGS_OFFSET);
+	err_cap0 = readl(pci2_err_regs + PCI_ERR_CAP_R0 - PCI_ERR_REGS_OFFSET);
+	err_cap1 = readl(pci2_err_regs + PCI_ERR_CAP_R1 - PCI_ERR_REGS_OFFSET);
+	err_cap2 = readl(pci2_err_regs + PCI_ERR_CAP_R2 - PCI_ERR_REGS_OFFSET);
+	err_cap3 = readl(pci2_err_regs + PCI_ERR_CAP_R3 - PCI_ERR_REGS_OFFSET);
+
+	pci2_errors++;
+	/* Display error information */
+	printk(KERN_ERR "PCI Controller 2 Error!\n");
+	printk(KERN_ERR "PCI ERROR DETECT REG 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "PCI ERR CAP STATUS REG 0x%08x\n", swab32(err_status));
+	printk(KERN_ERR "PCI ERR CAP REG0 0x%08x\n", swab32(err_cap0));
+	printk(KERN_ERR "PCI ERR CAP REG1 0x%08x\n", swab32(err_cap1));
+	printk(KERN_ERR "PCI ERR CAP REG2 0x%08x\n", swab32(err_cap2));
+	printk(KERN_ERR "PCI ERR CAP REG3 0x%08x\n", swab32(err_cap3));
+	printk(KERN_ERR "PCI Error Count: %u\n", pci2_errors);
+
+	/* Clear interrupt cause and capture registers */
+	writel(err_det, pci2_err_regs + PCI_ERR_DET - PCI_ERR_REGS_OFFSET);
+	writel(swab32(0x1),
+	       pci2_err_regs + PCI_ERR_CAP_STAT - PCI_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+
+#endif
+
+static void mvme4100_restart(char *cmd)
+{
+	volatile ulong i = 10000000;
+
+	local_irq_disable();
+	writeb(MVME4100_BOARD_RESET, system_control_reg_addr);
+
+	while (i-- > 0) ;
+	panic("restart failed\n");
+}
+
+
+static void __devinit skip_fake_bridge(struct pci_dev *dev)
+{
+	/* Make it an error to skip the fake bridge
+	 * in pci_setup_device() in probe.c */
+	dev->hdr_type = 0x7f;
+}
+
+DECLARE_PCI_FIXUP_EARLY(0x1957, 0x3fff, skip_fake_bridge);
+DECLARE_PCI_FIXUP_EARLY(0x3fff, 0x1957, skip_fake_bridge);
+
+static void __init mvme4100_init_irq(void)
+{
+	struct mpic *mpic;
+	struct resource r;
+	struct device_node *np = NULL;
+
+	np = of_find_node_by_type(np, "open-pic");
+	if (np == NULL) {
+		printk(KERN_ERR "Could not find open-pic node\n");
+		return;
+	}
+
+	if (of_address_to_resource(np, 0, &r)) {
+		printk(KERN_ERR "Failed to map mpic register space\n");
+		of_node_put(np);
+		return;
+	}
+
+	mpic = mpic_alloc(np, r.start,
+			  MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN,
+			  0, 256, " OpenPIC  ");
+	BUG_ON(mpic == NULL);
+
+	/* Return the mpic node */
+	of_node_put(np);
+
+	mpic_init(mpic);
+
+#ifdef CONFIG_MVME4100_ENABLE_L2_ERRORS
+	np = of_find_node_by_type(NULL, "l2_cache-controller");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find l2_cache-controller node\n");
+	} else {
+		l2_irq = irq_of_parse_and_map(np, 0);
+		if (l2_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map L2 cache irq\n");
+		of_node_put(np);
+	}
+#endif
+
+#ifdef CONFIG_MVME4100_ENABLE_DDR_ERRORS
+	np = of_find_node_by_type(NULL, "memory-controller");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find memory-controller node\n");
+	} else {
+		ddr_irq = irq_of_parse_and_map(np, 0);
+		if (ddr_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map DDR irq\n");
+		of_node_put(np);
+	}
+#endif
+
+	np = of_find_node_by_path("/pci@f1008000");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find PCI 0 node\n");
+	} else {
+		pci0_irq = irq_of_parse_and_map(np, 0);
+		if (pci0_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map PCI 0 irq\n");
+		of_node_put(np);
+	}
+
+	np = of_find_node_by_path("/pci@f100a000");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find PCI 2 node\n");
+	} else {
+		pci2_irq = irq_of_parse_and_map(np, 0);
+		if (pci2_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map PCI 2 irq\n");
+		of_node_put(np);
+	}
+
+#ifdef CONFIG_SENSORS_LM90
+	np = of_find_node_by_type(NULL, "thermostat");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find temp sensor node\n");
+	} else {
+		maxim6649_irq = irq_of_parse_and_map(np, 0);
+		if (maxim6649_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map MAXIM6649 irq\n");
+		of_node_put(np);
+	}
+#endif
+
+#ifdef CONFIG_MVME4100_TICK_TIMERS
+	np = of_find_node_by_type(NULL, "board_timers");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find timers node\n");
+	} else {
+		mvme4100_timer_irq = irq_of_parse_and_map(np, 0);
+		if (mvme4100_timer_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map timers irq\n");
+		of_node_put(np);
+	}
+#endif
+
+	np = of_find_node_by_path("/serial@f2011000");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find serial@f2011000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@f2011000 irq\n");
+		of_node_put(np);
+	}
+
+	np = of_find_node_by_path("/serial@f2012000");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find serial@f2012000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@f2012000 irq\n");
+		of_node_put(np);
+	}
+	np = of_find_node_by_path("/serial@f2013000");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find serial@f2013000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@f2013000 irq\n");
+		of_node_put(np);
+	}
+	np = of_find_node_by_path("/serial@f2014000");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find serial@f2014000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@f2014000 irq\n");
+		of_node_put(np);
+	}
+}
+
+
+static void __init mvme4100_misc_init(void)
+{
+	void __iomem *reg_block;
+	u8 reg_value;
+	u32 reg32;
+	//     u32 val;
+	struct device_node *np = NULL;
+	const u32 *regs;
+//      unsigned long a;
+#ifdef CONFIG_MVME4100_ENABLE_DDR_ERRORS
+	u32 sbe_count;
+#endif
+
+	np = of_find_node_by_type(np, "soc");
+	if (np == NULL) {
+		printk("Error:Cannot find soc node\n");
+		return;
+	}
+	regs = of_get_property(np, "reg", NULL);
+	if (regs == NULL) {
+		printk("Error:Cannot get reg property from soc node\n");
+		of_node_put(np);
+		return;
+	} else
+		hb_baddr = regs[0];
+
+	of_node_put(np);
+
+#ifdef CONFIG_MVME4100_ENABLE_DDR_ERRORS	/* Enable DDR error reporting */
+	ddr_err_regs =
+	    ioremap(hb_baddr + DDR_ERR_REGS_OFFSET, DDR_ERR_REGS_SIZE);
+	/* Enable all error detection */
+	writel(0, ddr_err_regs + DDR_ERR_DIS - DDR_ERR_REGS_OFFSET);
+	/* Clear logged DDR errors */
+	writel(swab32(0x8000000D),
+	       ddr_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+	/* Set single-bit error threshold */
+	sbe_count = 0x00010000;
+	writel(swab32(sbe_count),
+	       ddr_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+#endif
+
+#ifdef CONFIG_MVME4100_ENABLE_PCI_ERRORS
+	pci0_err_regs = ioremap(hb_baddr + PCI0_REGS_OFFSET +
+				PCI_ERR_REGS_OFFSET, PCI_ERR_REGS_SIZE);
+	pci2_err_regs = ioremap(hb_baddr + PCI2_REGS_OFFSET +
+				PCI_ERR_REGS_OFFSET, PCI_ERR_REGS_SIZE);
+#endif
+
+#ifdef CONFIG_VME_BRIDGE
+	{
+		extern void vmemod_setup_options(char *);
+
+		vmemod_setup_options(cmd_line);
+	}
+#endif
+
+	reg_block = ioremap(MVME4100_SYSTEM_STATUS_REG, 64);
+
+	/* Turn off USR1 Red LED */
+	reg_value = readb(reg_block + MVME4100_STATUS_INDICATOR_REG_OFFSET);
+	reg_value &= ~MVME4100_USR1_RED_LED;
+	writeb(reg_value, reg_block + MVME4100_STATUS_INDICATOR_REG_OFFSET);
+	/* Disable RTC, Temp Sensor, and Abort interrupts */
+	reg_value = readb(reg_block + MVME4100_INTERRUPT_REG_2_OFFSET);
+	reg_value |= MVME4100_RTC_MASK | MVME4100_TEMP_MASK |
+	    MVME4100_ABORT_MASK;
+	writeb(reg_value, reg_block + MVME4100_INTERRUPT_REG_2_OFFSET);
+
+	/* Turn off NOR flash SW write-protect */
+	reg_value = readb(reg_block + MVME4100_NOR_FLASH_CTRL_STAT_REG_OFFSET);
+	reg_value &= ~MVME4100_NOR_FLASH_WP_SW;
+	writeb(reg_value, reg_block + MVME4100_NOR_FLASH_CTRL_STAT_REG_OFFSET);
+
+	iounmap(reg_block);
+
+	/* Allow write access to MRAM */
+	reg_block = ioremap(hb_baddr + 0x5018, 4);
+	reg32 = swab32(readl(reg_block));
+	reg32 &= 0xFFFFFEFF;
+	writel(swab32(reg32), reg_block);
+	iounmap(reg_block);
+	
+	system_control_reg_addr = ioremap(MVME4100_SYSTEM_CONTROL_REG, 1);
+
+	return;
+}
+
+
+static void __init mvme4100_pcibios_fixup(void)
+{
+	struct pci_dev *dev = NULL;
+	u32 temp;
+
+	if ((dev = pci_get_device(PCI_VENDOR_ID_NEC,
+				  PCI_DEVICE_ID_NEC_USB, NULL))) {
+		/* Set System Clock to 48MHz oscillator in EXT2 register */
+		pci_read_config_dword(dev, 0xe4, &temp);
+		temp |= 0x00000020;
+		pci_write_config_dword(dev, 0xe4, temp);
+                /* max ports = 2 */
+                pci_read_config_dword(dev, 0xe0, &temp);
+                temp &= ~0x00000007;
+                temp |= 0x00000002;
+                pci_write_config_dword(dev, 0xe0, temp);
+	} 
+
+	dev = NULL;
+	for_each_pci_dev(dev) {
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+				      L1_CACHE_BYTES >> 2);
+		pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+	}
+
+#ifdef CONFIG_MVME4100_ENABLE_L2_ERRORS
+	if (request_irq(l2_irq, mvme4100_l2cache_err_handler,
+			IRQF_DISABLED, "L2 Cache Error", (void *)&l2_irq) < 0) {
+		printk(KERN_ERR "Cannot install L2 cache error handler\n");
+	} else
+		writel(swab32(0x1D),
+		       l2_err_regs + L2_ERR_INT_EN - L2_ERR_REGS_OFFSET);
+#endif
+
+#ifdef CONFIG_MVME4100_ENABLE_DDR_ERRORS
+	if (request_irq(ddr_irq, mvme4100_ddr_err_handler,
+			       IRQF_DISABLED, "DDR Error",
+			       (void *)&ddr_err_regs) < 0) {
+		printk(KERN_ERR "Cannot install DDR error handler\n");
+	} else
+		writel(swab32(0xD),
+		       ddr_err_regs + DDR_ERR_INT_EN - DDR_ERR_REGS_OFFSET);
+#endif
+
+#ifdef CONFIG_MVME4100_ENABLE_PCI_ERRORS
+	if (request_irq(pci0_irq, mvme4100_pci0_err_handler,
+		IRQF_SHARED, "PCI 0 Error", (void *)&pci0_err_regs) < 0) {
+		printk(KERN_ERR "Cannot install PCI 0 error handler\n");
+	} else {
+		/* Enable PCI error detection */
+		writel(0, pci0_err_regs + PCI_ERR_CAP_DIS - PCI_ERR_REGS_OFFSET);
+		/* Enable all error interrupts */
+		writel(swab32(0x00bfff00),
+		       pci0_err_regs + PCI_ERR_INT_EN - PCI_ERR_REGS_OFFSET);
+	}
+
+	if (request_irq(pci2_irq, mvme4100_pci2_err_handler,
+		IRQF_SHARED, "PCI 2 Error", (void *)&pci2_err_regs) < 0) {
+		printk(KERN_ERR "Cannot install PCI 2 error handler\n");
+	} else {
+		/* Enable PCI error detection */
+		writel(0, pci2_err_regs + PCI_ERR_CAP_DIS - PCI_ERR_REGS_OFFSET);
+		/* Enable all error interrupts */
+		writel(swab32(0x00bfff00),
+		       pci2_err_regs + PCI_ERR_INT_EN - PCI_ERR_REGS_OFFSET);
+	}
+#endif
+}
+
+void mvme4100_pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_dev *bridge;
+	struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
+
+	fsl_pcibios_fixup_bus(bus);
+	bridge = bus->self;
+	if (!bridge) 
+		return;
+
+	if (hose->global_number == 0) {
+		if ((bridge->vendor == PCI_VENDOR_ID_FREESCALE) &&
+	    		(bridge->device == PCI_DEVICE_ID_MPC8548E))
+			bridge->irq = pci0_irq;
+	}
+
+	if (hose->global_number == 1) {
+		struct pci_bus *parent;
+
+		if ((bridge->vendor == PCI_VENDOR_ID_FREESCALE) &&
+	    		(bridge->device == PCI_DEVICE_ID_MPC8548E))
+			bridge->irq = pci2_irq;
+
+		parent = bus->parent;
+		/*  PLX 8114 errata - uses readline instead of read 
+		 *  of PCI MEM Space at offsets 0x1c, 0x3c, etc. 
+		 *  unless this bizarre workaround is used.
+		 */
+		if ((bridge->vendor == 0x10b5) &&
+		    (bridge->device == 0x8114) &&
+		    (bridge->devfn == 0x0) && parent &&
+		    parent->self &&
+		    (parent->self->vendor == 0x10b5) &&
+		    (parent->self->device == 0x8533)) {
+			pci_write_config_byte(bridge, PCI_CACHE_LINE_SIZE, 16);
+		}
+	}
+}
+
+
+static void mvme4100_init_caches(void)
+{
+	void __iomem *l2_ctl_addr;
+	struct device_node *dn = NULL;
+	const u32 *regs;
+	uint  spr;
+
+	dn = of_find_node_by_type(dn, "soc");
+	if (dn == NULL) {
+		printk("Error:Cannot find soc node\n");
+		return;
+	}
+	regs = of_get_property(dn, "reg", NULL);
+	if (regs == NULL) {
+		printk("Error:Cannot get reg property from soc node\n");
+		return;
+	} else {
+		hb_baddr = regs[0];
+	}
+
+	l2_err_regs = ioremap(hb_baddr + L2_ERR_REGS_OFFSET, L2_ERR_REGS_SIZE);
+
+	l2_ctl_addr = ioremap(hb_baddr + 0x20000, 4);
+
+	/* L1 inst, L1 data, and L2 are disabled at this point */
+
+        /* Enable L1 inst */
+        asm volatile("msync; isync");
+        spr = mfspr(SPRN_L1CSR1);
+        asm volatile("msync; isync");
+        mtspr(SPRN_L1CSR1, spr | L1CSR1_ICFI | L1CSR1_ICE | L1CSR1_ICPE);
+        asm volatile("msync; isync");
+
+        /* Enable L1 data */
+        if (!(mfspr(SPRN_L1CSR0) & L1CSR0_DCE)) {
+                asm volatile("msync; isync");
+                mtspr(SPRN_L1CSR0, 0x0);                /* Disable */
+                asm volatile("msync; isync");
+                mtspr(SPRN_L1CSR0, L1CSR0_DCFI);        /* Invalidate */
+                asm volatile("isync; sync");
+                spr = mfspr(SPRN_L1CSR0);
+                asm volatile("isync; sync");
+                mtspr(SPRN_L1CSR0, spr | L1CSR0_DCE | L1CSR0_DCPE); /* Enable */
+                asm volatile("isync; sync");
+        }
+
+	asm volatile ("eieio");
+	asm volatile ("isync");
+	/* Disable L2 */
+	writel(0, l2_ctl_addr);
+	readl(l2_ctl_addr);
+	asm volatile ("eieio");
+	/* Invalidate L2 */
+	writel(swab32(0x40000300), l2_ctl_addr);
+	readl(l2_ctl_addr);
+	asm volatile ("eieio");
+	/* Enable L2 error detection */
+	writel(0, l2_err_regs + L2_ERR_DIS - L2_ERR_REGS_OFFSET);
+	readl(l2_ctl_addr);
+	asm volatile ("eieio");
+	/* Clear any logged L2 errors */
+	writel(swab32(0x0000001D),
+	       l2_err_regs + L2_ERR_DET - L2_ERR_REGS_OFFSET);
+	readl(l2_ctl_addr);
+	asm volatile ("eieio");
+	/* Enable L2 */
+	writel(swab32(0x80000300), l2_ctl_addr);
+	asm volatile ("eieio");
+	asm volatile ("isync");
+	/* Clear Locks */
+	writel(swab32(0x80000700), l2_ctl_addr);
+	asm volatile ("eieio");
+
+	printk
+	    ("L2 cache enabled (512K cache, no memory-mapped SRAM). L2CTL reg: 0x%x\n",
+	     swab32(readl(l2_ctl_addr)));
+
+	iounmap(l2_ctl_addr);
+	of_node_put(dn);
+
+	return;
+}
+
+/*
+ * Setup the architecture
+ */
+static void __init mvme4100_setup_arch(void)
+{
+	struct device_node *np;
+
+	if (ppc_md.progress)
+		ppc_md.progress("mvme4100_setup_arch()", 0);
+
+
+	mvme4100_init_caches();
+
+#ifdef CONFIG_PCI
+	for_each_node_by_type(np, "pci") {
+		if (of_device_is_compatible(np, "fsl,mpc8540-pci") ||
+		    of_device_is_compatible(np, "fsl,mpc8548-pcie")) {
+			struct resource rsrc;
+
+			of_address_to_resource(np, 0, &rsrc);
+			if ((rsrc.start & 0xfffff) == 0x8000)
+				fsl_add_bridge(np, 1);
+			else
+				fsl_add_bridge(np, 0);
+		}
+	}
+#endif
+	printk("MVME4100 board from Emerson Network Power Embedded Computing\n");
+
+#ifdef  CONFIG_ROOT_NFS
+	ROOT_DEV = Root_NFS;
+#else
+	ROOT_DEV = Root_SDA2;
+#endif
+
+#ifdef CONFIG_VME_BRIDGE_BOOTMEM
+	vme_bootmem_size = CONFIG_VME_BRIDGE_BOOTMEM_SIZE * 1024 * 1024;
+
+	if (vme_bootmem_size > (total_memory / 2)) {
+		printk(KERN_WARNING
+		       "BOOTMEM Size Requested: 0x%x Total Memory 0x%lx\n",
+		       vme_bootmem_size, total_memory);
+		printk(KERN_WARNING
+		       "BOOTMEM Size requested has been capped at half the total memory\n");
+		vme_bootmem_size = total_memory / 2;
+	}
+	vme_driver_bootmem = __alloc_bootmem(vme_bootmem_size, 0x10000, 0);
+	if (!vme_driver_bootmem) {
+		printk(KERN_WARNING "Unable to obtain boot memory for VME\n");
+		vme_bootmem_size = 0;
+	} else {
+		printk(KERN_INFO
+		       "0x%x of boot memory reserved for setup of VME inbound window 7\n",
+		       vme_bootmem_size);
+	}
+#endif
+	mvme4100_misc_init();
+}
+
+#define SPRN_L1CFG0     0x203	/* L1 Cache Configuration Register 0  */
+#define SPRN_L1CFG1     0x204	/* L1 Cache Configuration Register 1  */
+
+
+static void mvme4100_show_cpuinfo(struct seq_file *m)
+{
+	struct device_node *root;
+	uint pvid, svid, phid1;
+	phys_addr_t immr_base;
+	uint memsize = total_memory;
+	const char *model = "";
+	void __iomem *reg_block;
+	u8 reg_value;
+	u32 reg32_value;
+	void __iomem *l2cache_addr;
+	u32 l1csr0, l1csr1, l2ctl;
+	char buff[16] = "";
+
+	seq_printf(m, "Vendor\t\t: Freescale Semiconductor\n");
+	root = of_find_node_by_path("/");
+	if (root)
+		model = of_get_property(root, "model", NULL);
+	seq_printf(m, "Machine\t\t: %s\n", model);
+	of_node_put(root);
+
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
+	immr_base = get_immrbase();
+
+	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+	seq_printf(m, "HID0\t\t: 0x%08lx\n", mfspr(SPRN_HID0));
+	seq_printf(m, "HID1\t\t: 0x%08lx\n", mfspr(SPRN_HID1));
+	seq_printf(m, "CCSR Base\t: 0x%08x\n", immr_base);
+
+	/* Display cpu Pll setting */
+	phid1 = mfspr(SPRN_HID1);
+	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+	/* Display the cache settings */
+	seq_printf(m, "\nCache Settings:\n\n");
+	l1csr0 = mfspr(SPRN_L1CSR0);
+	seq_printf(m, "L1CSR0 (L1 D-cache)\t: 0x%08x (%s)\n", l1csr0,
+		   (l1csr0 & 1) ? "on" : "off");
+	l1csr1 = mfspr(SPRN_L1CSR1);
+	seq_printf(m, "L1CSR1 (L1 I-cache)\t: 0x%08x (%s)\n", l1csr1,
+		   (l1csr1 & 1) ? "on" : "off");
+	seq_printf(m, "L1CFG0\t\t\t: 0x%08lx\n", mfspr(SPRN_L1CFG0));
+	seq_printf(m, "L1CFG1\t\t\t: 0x%08lx\n", mfspr(SPRN_L1CFG1));
+
+	l2cache_addr = ioremap(immr_base + 0x20000, 4);
+	l2ctl = swab32(readl(l2cache_addr));
+	seq_printf(m, "L2CTL (L2 cache)\t: 0x%x (%s)\n", l2ctl,
+		   (l2ctl & 0x80000000) ? "on" : "off");
+	iounmap(l2cache_addr);
+
+	seq_printf(m, "\nBOARD INFORMATION:\n\n");
+
+	seq_printf(m,
+		   "Board Vendor\t\t: Emerson Network Power Embedded Computing\n");
+	reg_block = ioremap(MVME4100_SYSTEM_STATUS_REG, 64);
+
+	/* Display the amount of memory */
+	seq_printf(m, "Memory\t\t\t: %d MB\n", memsize / (1024 * 1024));
+	/* System Status Register */
+	reg_value = readb(reg_block);
+	seq_printf(m, "SW8 State\t\t: %s\n",
+		   ((reg_value & MVME4100_STATE_SW8) ? "ON" : "OFF"));
+	seq_printf(m, "SW7 State\t\t: %s\n",
+		   ((reg_value & MVME4100_STATE_SW7) ? "ON" : "OFF"));
+	seq_printf(m, "SW6 State\t\t: %s\n",
+		   ((reg_value & MVME4100_STATE_SW6) ? "ON" : "OFF"));
+	seq_printf(m, "SW5 State\t\t: %s\n",
+		   ((reg_value & MVME4100_STATE_SW5) ? "ON" : "OFF"));
+
+	seq_printf(m, "Safe Start Status\t: %s\n",
+		   ((reg_value & MVME4100_SAFE_START) ?
+		    "Safe ENV settings used" : "NVRAM ENV settings used"));
+
+	switch (reg_value & MVME4100_BOARD_TYPE_MASK) {
+	case MVME4100_BOARD_TYPE_PRPMC:
+		sprintf(buff, "PrPMC");
+		break;
+	case MVME4100_BOARD_TYPE_VME:
+		sprintf(buff, "VME");
+		break;
+	default:
+		sprintf(buff, "Unknown");
+		break;
+	}
+	seq_printf(m, "Board Type\t\t: %s\n", buff);
+
+	/* System Control Register */
+	reg_value = readb(reg_block + MVME4100_SYSTEM_CONTROL_REG_OFFSET);
+	seq_printf(m, "EEPROM WP Status\t: %s\n",
+		   ((reg_value & MVME4100_EEPROM_WP) ?
+		    "EEPROM Write Protected" : "EEPROM Not Write Protected"));
+
+	/* Status Indicator Register */
+	reg_value = readb(reg_block + MVME4100_STATUS_INDICATOR_REG_OFFSET);
+	seq_printf(m, "USR1 Red LED\t\t: %s\n",
+		   ((reg_value & MVME4100_USR1_RED_LED) ? "Lit" : "Not Lit"));
+	seq_printf(m, "USR1 Yellow LED\t\t: %s\n",
+		   ((reg_value & MVME4100_USR1_YELLOW_LED) ? "Lit" :
+		    "Not Lit"));
+	seq_printf(m, "USR2 LED\t\t: %s\n",
+		   ((reg_value & MVME4100_USR2_LED) ? "Lit" : "Not Lit"));
+	seq_printf(m, "USR3 LED\t\t: %s\n",
+		   ((reg_value & MVME4100_USR3_LED) ? "Lit" : "Not Lit"));
+
+	/* NOR Flash Control/Status Register */
+	reg_value = readb(reg_block + MVME4100_NOR_FLASH_CTRL_STAT_REG_OFFSET);
+	seq_printf(m, "NOR Flash Map Select\t: %s\n",
+		   ((reg_value & MVME4100_NOR_FLASH_MAP_SELECT) ?
+		    "Boot Block A Mapped to Highest Address" :
+		    "Flash Memory Map Controlled by Flash Boot Block Select"));
+	seq_printf(m, "NOR Flash WP SW\t\t: %s\n",
+		   ((reg_value & MVME4100_NOR_FLASH_WP_SW) ?
+		    "Write Protected" : "Not Write Protected"));
+	seq_printf(m, "NOR Flash WP HW\t\t: %s\n",
+		   ((reg_value & MVME4100_NOR_FLASH_WP_HW) ?
+		    "Write Protected" : "Not Write Protected"));
+	seq_printf(m, "NOR Flash Boot Select\t: %s\n",
+		   ((reg_value & MVME4100_NOR_FLASH_BLK_SEL) ?
+		    "Boot Block B Selected" : "Boot Block A Selected"));
+	seq_printf(m, "NOR Flash Ready Status\t: %s\n",
+		   ((reg_value & MVME4100_NOR_FLASH_RDY) ?
+		    "Bit Set" : "Bit Not Set"));
+	/* Interrupt Register 1 */
+	reg_value = readb(reg_block + MVME4100_INTERRUPT_REG_1_OFFSET);
+
+	if (reg_value & MVME4100_TSEC4_PHY_INTERRUPT) {
+		seq_printf(m, "TSEC4 PHY Interrupt\t: %s\n", "Asserted");
+	};
+	if (reg_value & MVME4100_TSEC3_PHY_INTERRUPT) {
+		seq_printf(m, "TSEC3 PHY Interrupt\t: %s\n", "Asserted");
+	};
+	if (reg_value & MVME4100_TSEC2_PHY_INTERRUPT) {
+		seq_printf(m, "TSEC2 PHY Interrupt\t: %s\n", "Asserted");
+	};
+	if (reg_value & MVME4100_TSEC1_PHY_INTERRUPT) {
+		seq_printf(m, "TSEC1 PHY Interrupt\t: %s\n", "Asserted");
+	};
+
+	/* Interrupt Register 2 */
+	reg_value = readb(reg_block + MVME4100_INTERRUPT_REG_2_OFFSET);
+
+	seq_printf(m, "RTC Mask\t\t: %s\n",
+		   ((reg_value & MVME4100_RTC_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+	seq_printf(m, "Temperature Sensor Mask\t: %s\n",
+		   ((reg_value & MVME4100_TEMP_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+	seq_printf(m, "ABORT Mask\t\t: %s\n",
+		   ((reg_value & MVME4100_ABORT_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+
+	seq_printf(m, "RTC Status\t\t: %s\n",
+		   ((reg_value & MVME4100_RTC_STATUS) ?
+		    "RTC Output Asserted" : "RTC Output Not Asserted"));
+	seq_printf(m, "Temp Sensor Status\t: %s\n",
+		   ((reg_value & MVME4100_TEMP_STATUS) ?
+		    "Temperature Sensor Output Asserted" :
+		    "Temperature Sensor Output Not Asserted"));
+	seq_printf(m, "Abort Status\t\t: %s\n",
+		   ((reg_value & MVME4100_ABORT_STATUS) ?
+		    "Abort Switch Asserted" : "Abort Switch Not Asserted"));
+
+	/* Presence Detect Register */
+	reg_value = readb(reg_block + MVME4100_PRESENCE_DETECT_REG_OFFSET);
+
+	seq_printf(m, "ERDY2\t\t\t: %s\n",
+		   ((reg_value & MVME4100_ERDY2) ?
+		    "ERDY2 Set" : "ERDY2 Not Set"));
+	seq_printf(m, "ERDY1\t\t\t: %s\n",
+		   ((reg_value & MVME4100_ERDY2) ?
+		    "ERDY1 Set" : "ERDY1 Not Set"));
+	seq_printf(m, "XMCSPAN\t\t\t: %s\n",
+		   ((reg_value & MVME4100_XMCSPAN_PRESENT) ?
+		    "XMCSPAN Installed" : "XMCSPAN Not Installed"));
+	seq_printf(m, "PMC Site 2\t\t: %s\n",
+		   ((reg_value & MVME4100_PMC2_PRESENT) ?
+		    "PMC Module Installed" : "PMC Module Not Installed"));
+	seq_printf(m, "PMC Site 1\t\t: %s\n",
+		   ((reg_value & MVME4100_PMC1_PRESENT) ?
+		    "PMC Module Installed" : "PMC Module Not Installed"));
+
+	/* PCI Bus 1 Status Register */
+	reg_value = readb(reg_block + MVME4100_PCI_BUS_1_STATUS_REG_OFFSET);
+	seq_printf(m, "PCI Bus A 64 Bit\t: %s\n",
+		   ((reg_value & MVME4100_PCI_BUS_A_64B) ?
+		    "64 Bit Enabled" : "32 Bit Mode"));
+	seq_printf(m, "PCI Bus A PCI-X\t\t: %s\n",
+		   ((reg_value & MVME4100_PCI_BUS_A_PCIX) ?
+		    "PCI Mode" : "PCI-X Mode"));
+	switch (reg_value & MVME4100_PCI_BUS_A_SPD_MASK) {
+	case MVME4100_PCI_BUS_A_SPD_133:
+		sprintf(buff, "133 MHz");
+		break;
+	case MVME4100_PCI_BUS_A_SPD_100:
+		sprintf(buff, "100 MHz");
+		break;
+	case MVME4100_PCI_BUS_A_SPD_66:
+		sprintf(buff, "66 MHz");
+		break;
+	case MVME4100_PCI_BUS_A_SPD_33:
+	default:
+		sprintf(buff, "33 MHz");
+		break;
+	}
+	seq_printf(m, "PCI Bus A Speed\t\t: %s\n", buff);
+
+	/* PCI Bus 2 Status Register */
+	reg_value = readb(reg_block + MVME4100_PCI_BUS_2_STATUS_REG_OFFSET);
+	if (reg_value & MVME4100_PCI_BUS_B_3_3V_VIO) {
+		seq_printf(m, "PCI Bus B 3.3V VIO\t: %s\n",
+			   "Configured for 3.3V VIO");
+	};
+	if (reg_value & MVME4100_PCI_BUS_B_5_0V_VIO) {
+		seq_printf(m, "PCI Bus B 5.0V VIO\t: %s\n",
+			   "Configured for 5.0V VIO");
+	};
+	seq_printf(m, "PCI Bus B 64 Bit\t: %s\n",
+		   ((reg_value & MVME4100_PCI_BUS_B_64B) ?
+		    "64 Bit Enabled" : "32 Bit Mode"));
+	seq_printf(m, "PCI Bus B PCI-X\t\t: %s\n",
+		   ((reg_value & MVME4100_PCI_BUS_B_PCIX) ?
+		    "PCI-X Mode" : "PCI Mode"));
+	switch (reg_value & MVME4100_PCI_BUS_B_SPD_MASK) {
+	case MVME4100_PCI_BUS_B_SPD_133:
+		sprintf(buff, "133 MHz");
+		break;
+	case MVME4100_PCI_BUS_B_SPD_100:
+		sprintf(buff, "100 MHz");
+		break;
+	case MVME4100_PCI_BUS_B_SPD_66:
+		sprintf(buff, "66 MHz");
+		break;
+	case MVME4100_PCI_BUS_B_SPD_33:
+	default:
+		sprintf(buff, "33 MHz");
+		break;
+	}
+	seq_printf(m, "PCI Bus B Speed\t\t: %s\n", buff);
+
+	/* PCI Bus 2 Status Register */
+	reg_value = readb(reg_block + MVME4100_PCI_BUS_3_STATUS_REG_OFFSET);
+	seq_printf(m, "PCI Bus C 64 Bit\t: %s\n",
+		   ((reg_value & MVME4100_PCI_BUS_C_64B) ?
+		    "64 Bit Enabled" : "32 Bit Mode"));
+	seq_printf(m, "PCI Bus C PCI-X\t\t: %s\n",
+		   ((reg_value & MVME4100_PCI_BUS_C_PCIX) ?
+		    "PCI-X Mode" : "PCI Mode"));
+	switch (reg_value & MVME4100_PCI_BUS_C_SPD_MASK) {
+	case MVME4100_PCI_BUS_C_SPD_133:
+		sprintf(buff, "133 MHz");
+		break;
+	case MVME4100_PCI_BUS_C_SPD_100:
+		sprintf(buff, "100 MHz");
+		break;
+	case MVME4100_PCI_BUS_C_SPD_66:
+		sprintf(buff, "66 MHz");
+		break;
+	case MVME4100_PCI_BUS_C_SPD_33:
+	default:
+		sprintf(buff, "33 MHz");
+		break;
+	}
+	seq_printf(m, "PCI Bus C Speed\t\t: %s\n", buff);
+
+	/* NAND Flash1 CTRL Register */
+	reg_value = readb(reg_block + MVME4100_NAND_FLASH1_CTRL_REG_OFFSET);
+	seq_printf(m, "NAND 1 CONTROL Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash1 SELECT Register */
+	reg_value = readb(reg_block + MVME4100_NAND_FLASH1_SELECT_REG_OFFSET);
+	seq_printf(m, "NAND 1 SELECT Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash1 Presence Register */
+	reg_value = readb(reg_block + MVME4100_NAND_FLASH1_PRESENCE_REG_OFFSET);
+	seq_printf(m, "NAND 1 PRESENCE Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash1 STATUS Register */
+	reg_value = readb(reg_block + MVME4100_NAND_FLASH1_STATUS_REG_OFFSET);
+	seq_printf(m, "NAND 1 STATUS Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 CTRL Register */
+	reg_value = readb(reg_block + MVME4100_NAND_FLASH2_CTRL_REG_OFFSET);
+	seq_printf(m, "NAND 2 CONTROL Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 SELECT Register */
+	reg_value = readb(reg_block + MVME4100_NAND_FLASH2_SELECT_REG_OFFSET);
+	seq_printf(m, "NAND 2 SELECT Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 Presence Register */
+	reg_value = readb(reg_block + MVME4100_NAND_FLASH2_PRESENCE_REG_OFFSET);
+	seq_printf(m, "NAND 2 PRESENCE Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 STATUS Register */
+	reg_value = readb(reg_block + MVME4100_NAND_FLASH2_STATUS_REG_OFFSET);
+	seq_printf(m, "NAND 2 STATUS Reg\t: 0x%02x\n", reg_value);
+
+	/* PLD Revision Register */
+	reg_value = readb(reg_block + MVME4100_PLD_REVISION_REG_OFFSET);
+
+	seq_printf(m, "PLD Revision\t\t: 0x%x\n", reg_value);
+
+	/* PLD Date Code Register */
+	reg32_value = readl(reg_block + MVME4100_PLD_DATE_CODE_REG_OFFSET);
+	seq_printf(m, "PLD Date Code\t\t: 0x%08x\n",
+		   (((reg32_value & 0x000000ffU) << 24) |
+		    ((reg32_value & 0x0000ff00U) << 8) |
+		    ((reg32_value & 0x00ff0000U) >> 8) |
+		    ((reg32_value & 0xff000000U) >> 24)));
+
+	iounmap(reg_block);
+
+	return;
+}
+
+
+static struct of_device_id __initdata of_bus_ids[] = {
+	{.type = "soc",},
+        { .compatible = "simple-bus", },
+	{},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+	of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+	return 0;
+}
+
+machine_device_initcall(mvme4100, declare_of_platform_devices);
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mvme4100_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (of_flat_dt_is_compatible(root, "MVME4100"))
+		return 1;
+	else
+		return 0;
+}
+
+define_machine(mvme4100)
+{
+	.name = "MVME4100",
+	.probe = mvme4100_probe,
+	.setup_arch = mvme4100_setup_arch,
+	.init_IRQ = mvme4100_init_irq,
+	.show_cpuinfo = mvme4100_show_cpuinfo,
+	.get_irq = mpic_get_irq,
+	.restart = mvme4100_restart,
+	.pcibios_fixup = mvme4100_pcibios_fixup,
+	.pcibios_fixup_bus = mvme4100_pcibios_fixup_bus,
+	.calibrate_decr = generic_calibrate_decr,
+	.progress = udbg_progress,
+};
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme4100.h linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme4100.h
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme4100.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme4100.h	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,192 @@
+/*
+ * MVME4100 board definitions
+ *
+ * Author: Ajit Prem <ajit.prem@emerson.com>
+ *
+ * Copyright 2008 Emerson Network Power - Embedded Computing
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MVME4100_H__
+#define __MVME4100_H__
+
+#include <linux/init.h>
+
+
+/* Flash */
+#define MVME4100_FLASH_BASE	0xf8000000
+#define MVME4100_FLASH_SIZE	0x08000000
+
+
+/* System Control and Status Registers */
+#define MVME4100_SYSTEM_STATUS_REG		0xF2000000
+#define MVME4100_SYSTEM_CONTROL_REG		0xF2000001
+#define MVME4100_STATUS_INDICATOR_REG		0xF2000002
+#define MVME4100_NOR_FLASH_CTRL_STAT_REG	0xF2000003
+#define MVME4100_INTERRUPT_REG_1		0xF2000004
+#define MVME4100_INTERRUPT_REG_2		0xF2000005
+#define MVME4100_PRESENCE_DETECT_REG		0xF2000006
+#define MVME4100_PCI_BUS_1_STATUS_REG		0xF2000008
+#define MVME4100_PCI_BUS_2_STATUS_REG		0xF2000009
+#define MVME4100_PCI_BUS_3_STATUS_REG		0xF200000A
+#define MVME4100_NAND_FLASH1_CONTROL_REG	0xF2000010
+#define MVME4100_NAND_FLASH1_SELECT_REG		0xF2000011
+#define MVME4100_NAND_FLASH1_PRESENCE_REG	0xF2000014
+#define MVME4100_NAND_FLASH1_STATUS_REG		0xF2000015
+#define MVME4100_NAND_FLASH1_DATA_REG		0xF2030000
+#define MVME4100_NAND_FLASH2_CONTROL_REG	0xF2000018
+#define MVME4100_NAND_FLASH2_SELECT_REG		0xF2000019
+#define MVME4100_NAND_FLASH2_PRESENCE_REG	0xF200001C
+#define MVME4100_NAND_FLASH2_STATUS_REG		0xF200001D
+#define MVME4100_NAND_FLASH2_DATA_REG		0xF2031000
+#define MVME4100_WATCHDOG_TIMER_LOAD_REG	0xF2000020
+#define MVME4100_WATCHDOG_CONTROL_REG		0xF2000024
+#define MVME4100_WATCHDOG_TIMER_RESOLUTION_REG	0xF2000025
+#define MVME4100_WATCHDOG_TIMER_COUNT_REG	0xF2000026
+#define MVME4100_PLD_REVISION_REG		0xF2000030
+#define MVME4100_PLD_DATE_CODE_REG		0xF2000034
+#define MVME4100_TEST_1_REG			0xF2000038
+#define MVME4100_TEST_2_REG			0xF200003C
+
+/* Register offsets */
+#define MVME4100_SYSTEM_STATUS_REG_OFFSET		0x00000000
+#define MVME4100_SYSTEM_CONTROL_REG_OFFSET		0x00000001
+#define MVME4100_STATUS_INDICATOR_REG_OFFSET		0x00000002
+#define MVME4100_NOR_FLASH_CTRL_STAT_REG_OFFSET		0x00000003
+#define MVME4100_INTERRUPT_REG_1_OFFSET			0x00000004
+#define MVME4100_INTERRUPT_REG_2_OFFSET			0x00000005
+#define MVME4100_PRESENCE_DETECT_REG_OFFSET		0x00000006
+#define MVME4100_PCI_BUS_1_STATUS_REG_OFFSET		0x00000008
+#define MVME4100_PCI_BUS_2_STATUS_REG_OFFSET		0x00000009
+#define MVME4100_PCI_BUS_3_STATUS_REG_OFFSET		0x0000000A
+#define MVME4100_NAND_FLASH1_CTRL_REG_OFFSET		0x00000010
+#define MVME4100_NAND_FLASH1_SELECT_REG_OFFSET		0x00000011
+#define MVME4100_NAND_FLASH1_PRESENCE_REG_OFFSET	0x00000014
+#define MVME4100_NAND_FLASH1_STATUS_REG_OFFSET		0x00000015
+#define MVME4100_NAND_FLASH2_CTRL_REG_OFFSET		0x00000018
+#define MVME4100_NAND_FLASH2_SELECT_REG_OFFSET		0x00000019
+#define MVME4100_NAND_FLASH2_PRESENCE_REG_OFFSET	0x0000001C
+#define MVME4100_NAND_FLASH2_STATUS_REG_OFFSET		0x0000001D
+#define MVME4100_WATCHDOG_TIMER_LOAD_REG_OFFSET		0x00000020
+#define MVME4100_WATCHDOG_CONTROL_REG_OFFSET		0x00000024
+#define MVME4100_WATCHDOG_TIMER_RESOLUTION_REG_OFFSET	0x00000025
+#define MVME4100_WATCHDOG_TIMER_COUNT_REG_OFFSET	0x00000026
+#define MVME4100_PLD_REVISION_REG_OFFSET		0x00000030
+#define MVME4100_PLD_DATE_CODE_REG_OFFSET		0x00000034
+#define MVME4100_TEST_1_REG_OFFSET			0x00000038
+#define MVME4100_TEST_2_REG_OFFSET			0x0000003C
+
+/* System Status Register */
+#define MVME4100_STATE_SW8		0x80
+#define MVME4100_STATE_SW7		0x40
+#define MVME4100_STATE_SW6		0x20
+#define MVME4100_STATE_SW5		0x10
+#define MVME4100_SAFE_START		0x08
+#define MVME4100_BOARD_TYPE_MASK	0x03
+#define MVME4100_BOARD_TYPE_PRPMC	0x01
+#define MVME4100_BOARD_TYPE_VME		0x00
+
+/* System Control Register */
+#define MVME4100_BOARD_RESET		0xA0
+#define MVME4100_EEPROM_WP		0x02
+
+/* Status Indicator Register */
+#define MVME4100_USR1_RED_LED		0x01
+#define MVME4100_USR1_YELLOW_LED	0x02
+#define MVME4100_USR2_LED		0x04
+#define MVME4100_USR3_LED		0x08
+
+/* NOR Flash Control/Status Register */
+#define MVME4100_NOR_FLASH_MAP_SELECT	0x10
+#define MVME4100_NOR_FLASH_WP_SW	0x08
+#define MVME4100_NOR_FLASH_WP_HW	0x04
+#define MVME4100_NOR_FLASH_BLK_SEL	0x02
+#define MVME4100_NOR_FLASH_RDY		0x01
+
+/* Interrupt Register 1 */
+#define MVME4100_TSEC4_PHY_INTERRUPT	0x08
+#define MVME4100_TSEC3_PHY_INTERRUPT	0x04
+#define MVME4100_TSEC2_PHY_INTERRUPT	0x02
+#define MVME4100_TSEC1_PHY_INTERRUPT	0x01
+
+/* Interrupt Register 2 */
+#define MVME4100_RTC_MASK		0x40
+#define MVME4100_TEMP_MASK		0x20
+#define MVME4100_ABORT_MASK		0x10
+#define MVME4100_RTC_STATUS		0x04
+#define MVME4100_TEMP_STATUS		0x02
+#define MVME4100_ABORT_STATUS		0x01
+
+/* Presence Detect Register */
+#define MVME4100_ERDY2			0x20
+#define MVME4100_ERDY1			0x10
+#define MVME4100_XMCSPAN_PRESENT	0x04
+#define MVME4100_PMC2_PRESENT		0x02
+#define MVME4100_PMC1_PRESENT		0x01
+
+/* PCI Bus 1 Status Register */
+#define MVME4100_PCI_BUS_A_64B          0x08
+#define MVME4100_PCI_BUS_A_PCIX         0x04
+#define MVME4100_PCI_BUS_A_SPD_MASK     0x03
+#define MVME4100_PCI_BUS_A_SPD_133      0x03
+#define MVME4100_PCI_BUS_A_SPD_100      0x02
+#define MVME4100_PCI_BUS_A_SPD_66       0x01
+#define MVME4100_PCI_BUS_A_SPD_33       0x00
+
+/* PCI Bus 2 Status Register */
+#define MVME4100_PCI_BUS_B_3_3V_VIO     0x80
+#define MVME4100_PCI_BUS_B_5_0V_VIO     0x40
+#define MVME4100_PCI_BUS_B_64B          0x08
+#define MVME4100_PCI_BUS_B_PCIX         0x04
+#define MVME4100_PCI_BUS_B_SPD_MASK     0x03
+#define MVME4100_PCI_BUS_B_SPD_133      0x03
+#define MVME4100_PCI_BUS_B_SPD_100      0x02
+#define MVME4100_PCI_BUS_B_SPD_66       0x01
+#define MVME4100_PCI_BUS_B_SPD_33       0x00
+
+
+/* PCI Bus 3 Status Register */
+#define MVME4100_PCI_BUS_C_64B          0x08
+#define MVME4100_PCI_BUS_C_PCIX         0x04
+#define MVME4100_PCI_BUS_C_SPD_MASK     0x03
+#define MVME4100_PCI_BUS_C_SPD_133      0x03
+#define MVME4100_PCI_BUS_C_SPD_100      0x02
+#define MVME4100_PCI_BUS_C_SPD_66       0x01
+#define MVME4100_PCI_BUS_C_SPD_33       0x00
+
+
+/* NAND Flash Chip Control Register */
+#define MVME4100_NAND_FLASH_CLE		0x80
+#define MVME4100_NAND_FLASH_ALE		0x40
+#define MVME4100_NAND_FLASH_WP		0x20
+
+/* NAND Flash Chip Select Register */
+#define MVME4100_NAND_FLASH_CE1		0x80
+#define MVME4100_NAND_FLASH_CE2		0x40
+#define MVME4100_NAND_FLASH_CE3		0x20
+#define MVME4100_NAND_FLASH_CE4		0x10
+
+/* NAND Flash Chip Presence Register */
+#define MVME4100_NAND_FLASH_CP		0x80
+
+/* NAND Flash Chip Status Register */
+#define MVME4100_NAND_FLASH_RB1		0x80
+#define MVME4100_NAND_FLASH_RB2		0x40
+#define MVME4100_NAND_FLASH_RB3		0x20
+#define MVME4100_NAND_FLASH_RB4		0x10
+
+#define MVME4100_BASE_BAUD		1843200
+#define QUART_BASE_BAUD			(MVME4100_BASE_BAUD / 16)
+#define MVME4100_UART_SIZE		0x8
+
+#define MVME4100_SERIAL_1	0xF2011000U
+#define MVME4100_SERIAL_2	0xF2012000U
+#define MVME4100_SERIAL_3	0xF2013000U
+#define MVME4100_SERIAL_4	0xF2014000U
+
+#endif	/* __MVME4100_H__ */
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme4100_timer.c linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme4100_timer.c
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/mvme4100_timer.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/mvme4100_timer.c	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,394 @@
+/*
+ * arch/powerpc/platforms/85xx/mvme4100_timer.c
+ *
+ * MVME4100 Tick Timers Support
+ *
+ * Author: Ajit Prem <Ajit.Prem@motorola.com>
+ *
+ * Copyright 2005-2007 Motorola Inc.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+#include "mvme4100.h"
+#include <asm/mvme4100_timer.h>
+
+#define MVME4100_TICK_TIMER_BASE                0xF2020000
+#define MVME4100_TICK_TIMER_BLOCK_SIZE          0x4C
+
+#define MVME4100_TICK_TIMER_PRESCALER_REG_OFFSET        0x0
+#define MVME4100_TICK_TIMER_CONTROL_REG_OFFSET          0x10
+#define MVME4100_TICK_TIMER_COMPARE_REG_OFFSET          0x14
+#define MVME4100_TICK_TIMER_COUNTER_REG_OFFSET          0x18
+
+#define MVME4100_TICK_TIMER_ENC                 0x00000001
+#define MVME4100_TICK_TIMER_COC                 0x00000002
+#define MVME4100_TICK_TIMER_COVF                0x00000004
+#define MVME4100_TICK_TIMER_OVF                 0x000000F0
+#define MVME4100_TICK_TIMER_ENINT               0x00000100
+#define MVME4100_TICK_TIMER_CINT                0x00000200
+#define MVME4100_TICK_TIMER_INTS                0x00000400
+
+#define	MIN_MICROSECONDS	10000
+#define MAX_TICKS		0xFFFFFFFF
+
+struct mvme4100_timer_t {
+	mvme4100_timer_f func;
+	void *func_data;
+	int started;
+	int periodic;
+	ulong period;
+	ulong ticks;
+};
+
+#define ALL_MSG "mvme4100_timer: "
+
+#ifdef MVME4100_TIMER_DEBUG
+int mvme4100_timer_debug = MVME4100_TIMER_DEBUG;
+MODULE_PARM(mvme4100_timer_debug, "i");
+#define DEBUG(n, fmt, args...) if (mvme4100_timer_debug>(n)) printk(KERN_INFO ALL_MSG fmt, ## args)
+static const char *version = "mvme4100_timer.c 1.0.0 (Ajit Prem)";
+#else
+#define DEBUG(n, fmt, args...)
+#endif
+
+extern int mvme4100_timer_irq;
+
+static struct mvme4100_timer_t mvme4100_timer[4];
+static void __iomem *mvme4100_timer_base;
+static u32 clk_out = 1;		/* Ticks per microsecond */
+static spinlock_t mvme4100_timer_lock = SPIN_LOCK_UNLOCKED;
+
+static irqreturn_t mvme4100_timer_int_handler(int irq, void *data)
+{
+	struct mvme4100_timer_t *info = data;
+	mvme4100_timer_f func;
+	void *func_data;
+	int timer_number;
+	u32 ctrl_reg;
+
+	if (data != (void *) &mvme4100_timer[0]) 
+		return IRQ_NONE;
+
+	for (timer_number = 0; timer_number <= 3; timer_number++) {
+		if (swab32(readl(mvme4100_timer_base +
+			 (timer_number + 1) *
+			 MVME4100_TICK_TIMER_CONTROL_REG_OFFSET)) &
+		   	 MVME4100_TICK_TIMER_INTS) {
+			info = &mvme4100_timer[timer_number];
+			func_data = info->func_data;
+			func = info->func;
+
+			if (!info->periodic) {
+				mvme4100_timer_stop(timer_number);
+			} else {
+				ctrl_reg = swab32(readl(mvme4100_timer_base +
+					((timer_number + 1) *
+					 MVME4100_TICK_TIMER_CONTROL_REG_OFFSET)));
+				ctrl_reg &= ~MVME4100_TICK_TIMER_ENC;
+				ctrl_reg =
+				    MVME4100_TICK_TIMER_COVF |
+				    MVME4100_TICK_TIMER_CINT;
+				writel(swab32(ctrl_reg),
+				       mvme4100_timer_base +
+				       ((timer_number + 1) *
+					MVME4100_TICK_TIMER_CONTROL_REG_OFFSET));
+				writel(0,
+				       mvme4100_timer_base +
+				       ((timer_number + 1) *
+					MVME4100_TICK_TIMER_CONTROL_REG_OFFSET)
+				       +
+				       (MVME4100_TICK_TIMER_COUNTER_REG_OFFSET -
+					MVME4100_TICK_TIMER_CONTROL_REG_OFFSET));
+				DEBUG(1,
+				      ("Timer %d Counter 0x%x Compare 0x%x\n",
+				       timer_number,
+				       swab32(readl
+					      (mvme4100_timer_base +
+					       ((timer_number + 1) *
+						MVME4100_TICK_TIMER_CONTROL_REG_OFFSET)
+					       +
+					       (MVME4100_TICK_TIMER_COUNTER_REG_OFFSET
+						-
+						MVME4100_TICK_TIMER_CONTROL_REG_OFFSET))),
+				       swab32(readl
+					      (mvme4100_timer_base +
+					       ((timer_number + 1) *
+						MVME4100_TICK_TIMER_CONTROL_REG_OFFSET)
+					       +
+					       (MVME4100_TICK_TIMER_COMPARE_REG_OFFSET
+						-
+						MVME4100_TICK_TIMER_CONTROL_REG_OFFSET)))));
+				writel(swab32
+				       (MVME4100_TICK_TIMER_ENC |
+					MVME4100_TICK_TIMER_COC |
+					MVME4100_TICK_TIMER_ENINT),
+				       mvme4100_timer_base + 
+					((timer_number + 1) *
+					MVME4100_TICK_TIMER_CONTROL_REG_OFFSET));
+			}
+			if (func) 
+				func(func_data);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* 
+ * Stop the timer
+ */
+EXPORT_SYMBOL(mvme4100_timer_stop);
+int mvme4100_timer_stop(int timer_number)
+{
+	u32 reset_value;
+	unsigned long flags;
+
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+
+	spin_lock_irqsave(&mvme4100_timer_lock, flags);
+	reset_value = swab32(readl(mvme4100_timer_base +
+				   ((timer_number + 1) *
+				    MVME4100_TICK_TIMER_CONTROL_REG_OFFSET)));
+	reset_value &= ~MVME4100_TICK_TIMER_ENC;
+	reset_value &= ~MVME4100_TICK_TIMER_ENINT;
+	reset_value = MVME4100_TICK_TIMER_COVF | MVME4100_TICK_TIMER_CINT;
+	writel(swab32(reset_value),
+	       mvme4100_timer_base +
+	       ((timer_number + 1) * MVME4100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0, mvme4100_timer_base +
+	       ((timer_number + 1) * MVME4100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME4100_TICK_TIMER_COUNTER_REG_OFFSET -
+		MVME4100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0xffffffff, mvme4100_timer_base +
+	       ((timer_number + 1) * MVME4100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME4100_TICK_TIMER_COMPARE_REG_OFFSET -
+		MVME4100_TICK_TIMER_CONTROL_REG_OFFSET));
+	mvme4100_timer[timer_number].func = NULL;
+	mvme4100_timer[timer_number].func_data = NULL;
+	mvme4100_timer[timer_number].started = 0;
+	mvme4100_timer[timer_number].periodic = 0;
+	mvme4100_timer[timer_number].period = 0;
+	mvme4100_timer[timer_number].ticks = 0xFFFFFFFF;
+	spin_unlock_irqrestore(&mvme4100_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Start the timer
+ */
+EXPORT_SYMBOL(mvme4100_timer_start);
+int mvme4100_timer_start(int timer_number, unsigned long microseconds,
+			 mvme4100_timer_f func, void *func_data, int periodic)
+{
+	int res = 0;
+	unsigned long flags;
+	unsigned long ticks;
+
+	printk(KERN_INFO
+	       "mvme4100_timer: start_timer: num %d microseconds 0x%lx periodic %d\n",
+	       timer_number, microseconds, periodic);
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+	if ((microseconds < MIN_MICROSECONDS) ||
+	    (microseconds > MAX_TICKS / clk_out))
+		return -EINVAL;
+	if (func == NULL)
+		return -EINVAL;
+	if (mvme4100_timer[timer_number].started == 1)
+		return -EBUSY;
+	if ((res = mvme4100_timer_stop(timer_number)) < 0)
+		return res;
+	ticks = microseconds * clk_out;
+	spin_lock_irqsave(&mvme4100_timer_lock, flags);
+	mvme4100_timer[timer_number].started = 1;
+	mvme4100_timer[timer_number].func = func;
+	mvme4100_timer[timer_number].func_data = func_data;
+	mvme4100_timer[timer_number].periodic = periodic;
+	mvme4100_timer[timer_number].period = microseconds;
+	mvme4100_timer[timer_number].ticks = ticks;
+	writel(swab32(ticks), mvme4100_timer_base +
+	       ((timer_number + 1) * MVME4100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME4100_TICK_TIMER_COMPARE_REG_OFFSET -
+		MVME4100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0, mvme4100_timer_base +
+	       ((timer_number + 1) * MVME4100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME4100_TICK_TIMER_COUNTER_REG_OFFSET -
+		MVME4100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(swab32(MVME4100_TICK_TIMER_ENC | MVME4100_TICK_TIMER_COC |
+		      MVME4100_TICK_TIMER_ENINT),
+	       mvme4100_timer_base +
+	       ((timer_number + 1) * MVME4100_TICK_TIMER_CONTROL_REG_OFFSET));
+	spin_unlock_irqrestore(&mvme4100_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Get the timer resolution, in microseconds/tick
+ */
+EXPORT_SYMBOL(mvme4100_timer_get_resolution);
+unsigned long mvme4100_timer_get_resolution(void)
+{
+	u32 prescaler_adjust;
+
+	/* 
+	 * Prescaler_adjust = 256 - CLKIN/CLKOUT
+	 * CLKIN = 25 MHz
+	 */
+
+	prescaler_adjust = readl(mvme4100_timer_base +
+				 MVME4100_TICK_TIMER_PRESCALER_REG_OFFSET);
+	return (25 / (256 - prescaler_adjust));
+}
+
+/* 
+ * Set the timer resolution, in ticks/microsecond
+ */
+EXPORT_SYMBOL(mvme4100_timer_set_resolution);
+int mvme4100_timer_set_resolution(unsigned long ticks)
+{
+	u32 prescaler_adjust;
+	int i;
+	unsigned long flags;
+
+	/* 
+	 * Prescaler_adjust = 256 - CLKIN/CLKOUT
+	 * CLKIN = 25 MHz
+	 */
+
+	if ((ticks < MIN_TICKS_PER_MICROSECOND) ||
+	    (ticks > MAX_TICKS_PER_MICROSECOND))
+		return -EINVAL;
+
+	clk_out = ticks;
+	prescaler_adjust = 256 - (25 / clk_out);
+
+	spin_lock_irqsave(&mvme4100_timer_lock, flags);
+	for (i = 0; i <= 3; i++) {
+		if (mvme4100_timer[i].started == 1) {
+			spin_unlock_irqrestore(&mvme4100_timer_lock, flags);
+			return -EBUSY;
+		}
+	}
+
+	writel(prescaler_adjust, mvme4100_timer_base +
+	       MVME4100_TICK_TIMER_PRESCALER_REG_OFFSET);
+	spin_unlock_irqrestore(&mvme4100_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Get the timer value, in ticks
+ */
+EXPORT_SYMBOL(mvme4100_timer_get_ticks);
+unsigned long mvme4100_timer_get_ticks(int timer_number)
+{
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+
+	return swab32(readl(mvme4100_timer_base +
+			    ((timer_number +
+			      1) * MVME4100_TICK_TIMER_CONTROL_REG_OFFSET) +
+			    (MVME4100_TICK_TIMER_COUNTER_REG_OFFSET -
+			     MVME4100_TICK_TIMER_CONTROL_REG_OFFSET)));
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int
+mvme4100_timer_proc_read(char *buf, char **start, off_t off, int len, int *eof,
+			 void *data)
+{
+	int i;
+
+	len = 0;
+	len +=
+	    sprintf(buf + len,
+		    "\nTimer     Active  Periodic  Period(ticks)   Period(microseconds)\n");
+	len +=
+	    sprintf(buf + len,
+		    "_____     ______  ________  _____________   ____________________\n");
+	for (i = 0; i <= 3; i++) {
+		len +=
+		    sprintf(buf + len,
+			    "#%d        %c       %c         0x%08lx      %ld\n",
+			    i + 1,
+			    ((mvme4100_timer[i].started == 1) ? 'y' : 'n'),
+			    ((mvme4100_timer[i].periodic == 1) ? 'y' : 'n'),
+			    ((mvme4100_timer[i].periodic ==
+			      1) ? mvme4100_timer[i].ticks : 0),
+			    ((mvme4100_timer[i].periodic ==
+			      1) ? mvme4100_timer[i].period : 0));
+	}
+	return len;
+}
+
+#endif				/* CONFIG_PROC_FS */
+
+static __init int mvme4100_timer_init(void)
+{
+	int res = 0;
+	int i;
+
+	printk(KERN_INFO "mvme4100-timer: MVME4100 Tick Timers\n");
+
+	mvme4100_timer_base = ioremap(MVME4100_TICK_TIMER_BASE,
+				     MVME4100_TICK_TIMER_BLOCK_SIZE);
+	if (mvme4100_timer_base == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i <= 3; i++) {
+		mvme4100_timer[i].func = NULL;
+		mvme4100_timer[i].func_data = NULL;
+		mvme4100_timer[i].started = 0;
+		mvme4100_timer[i].periodic = 0;
+		mvme4100_timer[i].period = 0;
+		mvme4100_timer[i].ticks = 0;
+	}
+	res = request_irq(mvme4100_timer_irq, mvme4100_timer_int_handler,
+			  IRQF_SHARED,
+			  "MVME4100 Tick Timers", &mvme4100_timer[0]);
+	if (res < 0) {
+		printk(KERN_ERR "MVME4100 Timer: Can't allocate IRQ %d.\n",
+		       mvme4100_timer_irq);
+		return res;
+	}
+#ifdef CONFIG_PROC_FS
+	create_proc_read_entry("mvme4100_timers", 0, NULL,
+			       mvme4100_timer_proc_read, NULL);
+#endif
+	return 0;
+}
+
+static __exit void mvme4100_timer_exit(void)
+{
+	int timer_number;
+
+	for (timer_number = 0; timer_number <= 3; timer_number++) {
+		mvme4100_timer_stop(timer_number);
+	}
+	free_irq(mvme4100_timer_irq, &mvme4100_timer[0]);
+	iounmap(mvme4100_timer_base);
+}
+
+MODULE_LICENSE("GPL");
+
+MODULE_AUTHOR("Ajit Prem <ajit.prem@emerson.com>");
+MODULE_DESCRIPTION("MVME4100 Tick Timer driver");
+
+module_init(mvme4100_timer_init);
+module_exit(mvme4100_timer_exit);
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/smp.c linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/smp.c
--- linux-2.6.29.6.orig/arch/powerpc/platforms/85xx/smp.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/85xx/smp.c	2009-07-21 11:28:17.000000000 -0700
@@ -26,6 +26,7 @@
 
 extern volatile unsigned long __secondary_hold_acknowledge;
 extern void __early_start(void);
+extern void __secondary_start_page(void);
 
 #define BOOT_ENTRY_ADDR_UPPER	0
 #define BOOT_ENTRY_ADDR_LOWER	1
@@ -38,44 +39,111 @@
 #define NUM_BOOT_ENTRY		8
 #define SIZE_BOOT_ENTRY		(NUM_BOOT_ENTRY * sizeof(u32))
 
+#define EEBPCR_CPU1_EN 		0x02000000
+#define EEBPCR_CPU0_EN		0x01000000
+#define MPC85xx_ECM_OFFSET	0x1000
+#define MPC85xx_ECM_SIZE	0xf00
+#define ECM_PORT_CONFIG_OFFSET	0x0010
+#define MPC85xx_BPTR_OFFSET	0x20
+#define BPTR_EN			0x80000000
+#define MPC85xx_MPIC_GREG_OFFSET	0x40000
+#define MPC85xx_MPIC_GREG_SIZE	0x10000
+#define MPIC_PROC_INIT_OFFSET	0x1090
+
+
+static void __init smp_85xx_release_core(int nr)
+{
+	 __iomem u32 *ecm_vaddr;
+	unsigned long pcr;
+#if 0
+        void __iomem *mpic_greg;
+        u32 pir;
+#endif
+
+        /*
+	 * Startup Core #nr.
+	 */
+	ecm_vaddr = ioremap(get_immrbase() + MPC85xx_ECM_OFFSET,
+			MPC85xx_ECM_SIZE);
+	pcr = in_be32(ecm_vaddr + (ECM_PORT_CONFIG_OFFSET >> 2));
+#if 0
+        pcr &= ~EEBPCR_CPU1_EN;
+        out_be32(ecm_vaddr + (ECM_PORT_CONFIG_OFFSET >> 2), pcr);
+
+        /* Reset the core */
+        mpic_greg = ioremap(get_immrbase() + MPC85xx_MPIC_GREG_OFFSET,
+                            MPC85xx_MPIC_GREG_SIZE);
+        pir = in_be32(mpic_greg + MPIC_PROC_INIT_OFFSET);
+        out_be32(mpic_greg + MPIC_PROC_INIT_OFFSET, pir | (nr << 1));
+        out_be32(mpic_greg + MPIC_PROC_INIT_OFFSET, pir);
+#endif
+        /* Startup Core #nr */
+	pcr |= EEBPCR_CPU1_EN;
+	out_be32(ecm_vaddr + (ECM_PORT_CONFIG_OFFSET >> 2), pcr);
+	asm("sync; isync; msync");
+	iounmap(ecm_vaddr);
+}
+
 static void __init
 smp_85xx_kick_cpu(int nr)
 {
 	unsigned long flags;
+#ifndef CONFIG_CPCI6200
 	const u64 *cpu_rel_addr;
-	__iomem u32 *bptr_vaddr;
 	struct device_node *np;
+#endif
+	__iomem u32 *bptr_vaddr;
+	u32 bptr, oldbptr;
 	int n = 0;
 
 	WARN_ON (nr < 0 || nr >= NR_CPUS);
 
 	pr_debug("smp_85xx_kick_cpu: kick CPU #%d\n", nr);
 
-	local_irq_save(flags);
-
+#ifndef CONFIG_CPCI6200
 	np = of_get_cpu_node(nr, NULL);
 	cpu_rel_addr = of_get_property(np, "cpu-release-addr", NULL);
 
 	if (cpu_rel_addr == NULL) {
 		printk(KERN_ERR "No cpu-release-addr for cpu %d\n", nr);
-		local_irq_restore(flags);
 		return;
 	}
 
 	/* Map the spin table */
 	bptr_vaddr = ioremap(*cpu_rel_addr, SIZE_BOOT_ENTRY);
 
+	local_irq_save(flags);
+
 	out_be32(bptr_vaddr + BOOT_ENTRY_PIR, nr);
 	out_be32(bptr_vaddr + BOOT_ENTRY_ADDR_LOWER, __pa(__early_start));
 
+#else
+	/* Get the BPTR */
+	bptr_vaddr = ioremap(get_immrbase() + MPC85xx_BPTR_OFFSET, 4);
+
+	local_irq_save(flags);
+
+	/* Set the BPTR to the secondary boot page */
+	oldbptr = in_be32(bptr_vaddr);
+	bptr = (BPTR_EN | (__pa((unsigned)__secondary_start_page) >> 12));
+	out_be32(bptr_vaddr, bptr);
+
+	smp_85xx_release_core(nr);
+
+#endif
 	/* Wait a bit for the CPU to ack. */
 	while ((__secondary_hold_acknowledge != nr) && (++n < 1000))
 		mdelay(1);
 
-	iounmap(bptr_vaddr);
+#ifdef CONFIG_CPCI6200
+       /* Restore the BPTR */
+        out_be32(bptr_vaddr, oldbptr);
+#endif
 
 	local_irq_restore(flags);
 
+	iounmap(bptr_vaddr);
+
 	pr_debug("waited %d msecs for CPU #%d.\n", n, nr);
 }
 
@@ -96,6 +164,8 @@
 	.probe = smp_mpic_probe,
 	.kick_cpu = smp_85xx_kick_cpu,
 	.setup_cpu = smp_85xx_setup_cpu,
+        .take_timebase = smp_generic_take_timebase,
+        .give_timebase = smp_generic_give_timebase,
 };
 
 void __init
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/Kconfig linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/Kconfig
--- linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/Kconfig	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/Kconfig	2009-07-21 11:28:17.000000000 -0700
@@ -40,6 +40,11 @@
 	help
 	  This option enables support for GE Fanuc's SBC610.
 
+config MVME7100
+        bool "Emerson Network Power Embedded Computing MVME7100"
+        help
+          This option enables support for the Emerson MVME7100 board.
+
 endif
 
 config MPC8641
@@ -48,7 +53,7 @@
 	select FSL_PCI if PCI
 	select PPC_UDBG_16550
 	select MPIC
-	default y if MPC8641_HPCN || SBC8641D || GEF_SBC610
+	default y if MPC8641_HPCN || SBC8641D || GEF_SBC610 || MVME7100
 
 config MPC8610
 	bool
@@ -57,3 +62,25 @@
 	select PPC_UDBG_16550
 	select MPIC
 	default y if MPC8610_HPCD
+
+config MVME7100_ENABLE_DDR_ERRORS
+        bool "Enable DDR Error Reporting"
+        depends on MVME7100
+        default y
+
+config MVME7100_ENABLE_L2_ERRORS
+        bool "Enable L2 Error Reporting"
+        depends on MVME7100
+        default y
+
+config MVME7100_ENABLE_PCI_ERRORS
+        bool "Enable PCI Error Reporting"
+        depends on MVME7100
+        default y
+
+config MVME7100_TICK_TIMERS
+        bool "Enable support for the Tick Timers on the MVME7100"
+        depends on MVME7100
+        default y
+
+
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/Makefile linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/Makefile
--- linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/Makefile	2009-07-21 11:28:17.000000000 -0700
@@ -9,3 +9,5 @@
 obj-$(CONFIG_MPC8610_HPCD)	+= mpc8610_hpcd.o
 gef-gpio-$(CONFIG_GPIOLIB)	+= gef_gpio.o
 obj-$(CONFIG_GEF_SBC610)	+= gef_sbc610.o gef_pic.o $(gef-gpio-y)
+obj-$(CONFIG_MVME7100)          += mvme7100.o
+obj-$(CONFIG_MVME7100_TICK_TIMERS)      += mvme7100_timer.o
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c
--- linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/mpc86xx_hpcn.c	2009-07-21 11:28:17.000000000 -0700
@@ -145,6 +145,29 @@
 	return 0;
 }
 
+void __init mpc86xx_hpcn_pcibios_fixup(void)
+{
+	struct pci_dev *dev = NULL;
+		int ret;
+
+	if ((dev = pci_find_device(PCI_VENDOR_ID_AL, 0x5288, NULL))) {
+		dev->irq = 5;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 5);
+	}
+
+	if ((dev = pci_find_device(PCI_VENDOR_ID_AL, 0x5229, NULL))) {
+		dev->irq = 14;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 14);
+	}
+
+	if ((dev = pci_find_device(PCI_VENDOR_ID_AL, 0x5239, NULL))) {
+		dev->irq = 11;
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE, 11);
+	}
+
+
+}
+
 static __initdata struct of_device_id of_bus_ids[] = {
 	{ .compatible = "simple-bus", },
 	{ .compatible = "fsl,rapidio-delta", },
@@ -172,5 +195,6 @@
 	.progress		= udbg_progress,
 #ifdef CONFIG_PCI
 	.pcibios_fixup_bus	= fsl_pcibios_fixup_bus,
+	.pcibios_fixup		= mpc86xx_hpcn_pcibios_fixup,
 #endif
 };
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/mpc86xx_smp.c linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/mpc86xx_smp.c
--- linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/mpc86xx_smp.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/mpc86xx_smp.c	2009-07-21 11:28:17.000000000 -0700
@@ -89,17 +89,55 @@
 	pr_debug("wait CPU #%d for %d msecs.\n", nr, n);
 }
 
+/* Copy L2 cache settings from CPU0 to CPU1 */
+volatile static long int l2_cache;
 
-static void __init
-smp_86xx_setup_cpu(int cpu_nr)
+static void __devinit smp_86xx_init_caches(int cpu)
 {
+	if (cpu == 0) {
+		l2_cache = _get_L2CR();
+		printk("CPUO: L2CR is %lx\n", l2_cache);
+	} else {
+		printk("CPU%d: L2CR was %lx\n", cpu, _get_L2CR());
+		_set_L2CR(0);
+		_set_L2CR(l2_cache);
+		printk("CPU%d: L2CR set to %lx\n", cpu, l2_cache);
+	}
+}
+
+static int __init smp_86xx_probe(void)
+{
+	struct device_node *cpus;
+	int ncpus = 0;
+
+        /* Count CPUs in the device-tree */
+        for (cpus = NULL; (cpus = of_find_node_by_type(cpus, "cpu")) != NULL;)
+                ++ncpus;
+
+        printk(KERN_INFO "MPC86xx SMP probe found %d cpus\n", ncpus);
+
+        /* Nothing more to do if less than 2 of them */
+        if (ncpus <= 1)
+                return 1;
+
+	/* Collect L2CR value from CPU 0 */
+	smp_86xx_init_caches(0);
+
+	return smp_mpic_probe();
+}
+
+static void __init smp_86xx_setup_cpu(int cpu_nr)
+{
+	if (cpu_nr != 0)
+		smp_86xx_init_caches(cpu_nr);
+
 	mpic_setup_this_cpu();
 }
 
 
 struct smp_ops_t smp_86xx_ops = {
 	.message_pass = smp_mpic_message_pass,
-	.probe = smp_mpic_probe,
+	.probe = smp_86xx_probe,
 	.kick_cpu = smp_86xx_kick_cpu,
 	.setup_cpu = smp_86xx_setup_cpu,
 	.take_timebase = smp_generic_take_timebase,
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/mvme7100.c linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/mvme7100.c
--- linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/mvme7100.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/mvme7100.c	2009-09-02 10:31:53.000000000 -0700
@@ -0,0 +1,1734 @@
+/*
+ * MVME7100 board specific routines
+ *
+ * Author: Ajit Prem <ajit.prem@emerson.com>
+ *
+ * Copyright 2008 Emerson Network Power Embedded Computing Inc.
+ *
+ * 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.
+ */
+
+#include <linux/stddef.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/kdev_t.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/of_platform.h>
+#include <linux/root_dev.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/highmem.h>
+
+#include <asm/of_device.h>
+#include <asm/system.h>
+#include <asm/time.h>
+#include <asm/machdep.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpc86xx.h>
+#include <asm/prom.h>
+#include <asm/page.h>
+#include <asm/kmap_types.h>
+#include <asm/edac.h>
+#include <mm/mmu_decl.h>
+#include <asm/udbg.h>
+
+#include <asm/mpic.h>
+
+#include <sysdev/fsl_pci.h>
+#include <sysdev/fsl_soc.h>
+
+#include "mpc86xx.h"
+#include "mvme7100.h"
+
+#undef DEBUG
+
+#ifdef DEBUG
+#define DBG(fmt...) do { printk(KERN_ERR fmt); } while(0)
+#else
+#define DBG(fmt...) do { } while(0)
+#endif
+
+static unsigned long hb_baddr;
+static int serial_irq;
+static void __iomem *system_control_reg_addr;
+
+#ifdef CONFIG_MVME7100_ENABLE_L2_ERRORS
+
+#define SPRN_L2CAPTDATAHI       0x3DC
+#define SPRN_L2CAPTDATALO       0x3DD
+#define SPRN_L2CAPTECC          0x3DE
+#define SPRN_L2ERRDET           0x3DF
+#define SPRN_L2ERRDIS           0x3E0
+#define SPRN_L2ERRINTEN         0x3E1
+#define SPRN_L2ERRATTR          0x3E2
+#define SPRN_L2ERRADDR          0x3E3
+#define SPRN_L2ERREADDR         0x3E4
+#define SPRN_L2ERRCTL           0x3E5
+
+static int l2_irq;
+static irqreturn_t mvme7100_l2cache_err_handler(int irq, void *dev_id);
+
+#endif
+
+#ifdef CONFIG_MVME7100_ENABLE_DDR_ERRORS
+
+#define DDR1_REGS_OFFSET        0x2000
+#define DDR2_REGS_OFFSET        0x6000
+#define DDR_ERR_REGS_OFFSET     0xE00
+#define DDR_ERR_REGS_SIZE       0x5C
+
+#define DDR_CAPT_DATA_HI        0xE20
+#define DDR_CAPT_DATA_LO        0xE24
+#define DDR_CAPT_ECC            0xE28
+#define DDR_ERR_DET             0xE40
+#define DDR_ERR_DISABLE         0xE44
+#define DDR_ERR_INT_EN          0xE48
+#define DDR_CAPT_ATTR           0xE4C
+#define DDR_CAPT_ADDR           0xE50
+#define DDR_CAPT_EXT_ADDR       0xE54
+#define DDR_ERR_SBE             0xE58
+
+#define DDR_SBE                 0x4	/* single-bit ECC error */
+#define DDR_MBE                 0x8	/* multi-bit ECC error */
+#define DDR_MME                 0x80000000	/* multiple ECC error */
+
+static int ddr1_errors;
+static int ddr2_errors;
+static void __iomem *ddr1_err_regs;
+static void __iomem *ddr2_err_regs;
+static int mpc86xx_ddr_irq;
+static irqreturn_t mvme7100_ddr_err_handler(int irq, void *dev_id);
+
+#endif
+
+#ifdef CONFIG_MVME7100_ENABLE_PCI_ERRORS
+
+#define PCI0_REGS_OFFSET	0x8000
+#define PCI1_REGS_OFFSET	0x9000
+#define PEX_ERR_REGS_OFFSET     0xE00
+#define PEX_ERR_REGS_SIZE       0x38
+
+#define PEX_ERR_DR		0xE00
+#define PEX_ERR_EN		0xE08
+#define PEX_ERR_DISR		0xE10
+#define PEX_ERR_CAP_STAT        0xE20
+#define PEX_ERR_CAP_R0          0xE28
+#define PEX_ERR_CAP_R1          0xE2C
+#define PEX_ERR_CAP_R2          0xE30
+#define PEX_ERR_CAP_R3          0xE34
+
+static u32 pci0_errors;
+static u32 pci1_errors;
+static void __iomem *pci0_err_regs;
+static void __iomem *pci1_err_regs;
+static int pci0_irq;
+static int pci1_irq;
+static irqreturn_t mvme7100_pci0_err_handler(int irq, void *dev_id);
+static irqreturn_t mvme7100_pci1_err_handler(int irq, void *dev_id);
+
+#endif
+
+#ifdef CONFIG_VME_BRIDGE_BOOTMEM
+void *vme_driver_bootmem;
+unsigned int vme_bootmem_size;
+#endif
+
+#ifdef CONFIG_MVME7100_TICK_TIMERS
+int mvme7100_timer_irq;
+#endif
+
+#ifdef CONFIG_SENSORS_LM90
+int maxim6649_irq;
+#endif
+
+
+#ifdef CONFIG_MVME7100_ENABLE_DDR_ERRORS
+
+static void mvme7100_determine_bit_location(u32 data_hi, u32 data_lo,
+					    u32 stored_ecc)
+{
+	u32 syndrome_bits;
+	u32 syndrome[8];
+	u32 calculated_ecc = 0;
+	int i;
+	u32 data0[32], data1[32];
+	unsigned char bitpos[8];
+
+	/* Initial 32-bit data */
+	for (i = 0; i < 32; i++) {
+		data0[i] = (data_hi >> (31 - i)) & 0x1;
+		data1[i] = (data_lo >> (31 - i)) & 0x1;
+	}
+
+	for (i = 0; i < 8; i++)
+		syndrome[i] = 0;
+
+	/* Calculate 8-bit ECC for the first 32-bit data */
+	for (i = 0; i < 32; ++i) {
+		/* Calculate syndrome[0] */
+		if ((i <= 15) || (i == 19) || (i == 23) || (i == 27) ||
+		    (i == 31))
+			syndrome[0] = syndrome[0] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[1] */
+		if ((i == 0) || (i == 4) || (i == 8) || (i == 12) || (i >= 16))
+			syndrome[1] = syndrome[1] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[2] */
+		if ((i == 1) || (i == 5) || (i == 9) || (i == 13) ||
+		    (i == 16) || (i == 20) || (i == 24) || (i == 28))
+			syndrome[2] = syndrome[2] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[3] */
+		if ((i == 2) || (i == 6) || (i == 10) || (i == 14) ||
+		    (i == 17) || (i == 21) || (i == 25) || (i == 29))
+			syndrome[3] = syndrome[3] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[4] */
+		if ((i == 3) || (i == 7) || (i == 11) || (i == 15) ||
+		    (i == 18) || (i == 19) || (i == 22) || (i == 23) ||
+		    (i == 26) || (i == 27) || (i == 30) || (i == 31))
+			syndrome[4] = syndrome[4] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[5] */
+		if (((i >= 4) && (i <= 7)) || ((i >= 12) && (i <= 15)) ||
+		    ((i >= 20) && (i <= 23)) || ((i >= 28) && (i <= 31)))
+			syndrome[5] = syndrome[5] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[6] */
+		if (((i >= 8) && (i <= 15)) || ((i >= 24) && (i <= 31)))
+			syndrome[6] = syndrome[6] ^ (data0[i] & 0x1);
+
+		/* Calculate syndrome[7] */
+		if ((i <= 3) || ((i >= 12) && (i <= 18)) ||
+		    (i == 23) || ((i >= 27) && (i <= 30)))
+			syndrome[7] = syndrome[7] ^ (data0[i] & 0x1);
+	}
+	/* Calculate 8-bit ECC for the second 32-bit data */
+	for (i = 0; i < 32; ++i) {
+		/* Calculate syndrome[0] */
+		if ((i == 2) || (i == 6) || (i == 10) || (i == 14) ||
+		    (i == 19) || (i == 23) || (i == 27) || (i == 29))
+			syndrome[0] = syndrome[0] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[1] */
+		if ((i == 3) || (i == 7) || (i == 11) || (i == 15) ||
+		    (i == 16) || (i == 20) || (i == 24) || (i == 30))
+			syndrome[1] = syndrome[1] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[2] */
+		if ((i <= 15) || (i == 17) || (i == 21) || (i == 25) |
+		    (i == 31))
+			syndrome[2] = syndrome[2] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[3] */
+		if ((i == 0) || (i == 4) || (i == 8) || (i == 12) ||
+		    (i == 18) || (i == 22) || (i == 26) || (i >= 28))
+			syndrome[3] = syndrome[3] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[4] */
+		if (((i >= 1) && (i <= 3)) || ((i >= 5) && (i <= 7)) ||
+		    ((i >= 9) && (i <= 11)) || ((i >= 13) && (i <= 15)) ||
+		    ((i >= 28) && (i <= 31)))
+			syndrome[4] = syndrome[4] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[5] */
+		if (((i >= 4) && (i <= 7)) || ((i >= 12) && (i <= 23)))
+			syndrome[5] = syndrome[5] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[6] */
+		if (((i >= 8) && (i <= 19)) || ((i >= 24) && (i <= 31)))
+			syndrome[6] = syndrome[6] ^ (data1[i] & 0x1);
+
+		/* Calculate syndrome[7] */
+		if ((i == 0) || (i == 1) || (i == 6) || (i == 7) ||
+		    ((i >= 10) && (i <= 13)) || ((i >= 20) && (i <= 27)) ||
+		    ((i >= 29) && (i <= 31)))
+			syndrome[7] = syndrome[7] ^ (data1[i] & 0x1);
+	}
+
+	calculated_ecc = ((syndrome[7] << 0) | (syndrome[6] << 1) |
+			  (syndrome[5] << 2) | (syndrome[4] << 3) |
+			  (syndrome[3] << 4) | (syndrome[2] << 5) |
+			  (syndrome[1] << 6) | (syndrome[0] << 7));
+
+	syndrome_bits = calculated_ecc ^ stored_ecc;
+
+	switch (syndrome_bits) {
+	case 0xC1:
+		sprintf(bitpos, "%s", "0");
+		break;
+	case 0xA1:
+		sprintf(bitpos, "%s", "1");
+		break;
+	case 0x91:
+		sprintf(bitpos, "%s", "2");
+		break;
+	case 0x89:
+		sprintf(bitpos, "%s", "3");
+		break;
+	case 0xC4:
+		sprintf(bitpos, "%s", "4");
+		break;
+	case 0xA4:
+		sprintf(bitpos, "%s", "5");
+		break;
+	case 0x94:
+		sprintf(bitpos, "%s", "6");
+		break;
+	case 0x8C:
+		sprintf(bitpos, "%s", "7");
+		break;
+	case 0xC2:
+		sprintf(bitpos, "%s", "8");
+		break;
+	case 0xA2:
+		sprintf(bitpos, "%s", "9");
+		break;
+	case 0x92:
+		sprintf(bitpos, "%s", "10");
+		break;
+	case 0x8A:
+		sprintf(bitpos, "%s", "11");
+		break;
+	case 0xC7:
+		sprintf(bitpos, "%s", "12");
+		break;
+	case 0xA7:
+		sprintf(bitpos, "%s", "13");
+		break;
+	case 0x97:
+		sprintf(bitpos, "%s", "14");
+		break;
+	case 0x8F:
+		sprintf(bitpos, "%s", "15");
+		break;
+	case 0x61:
+		sprintf(bitpos, "%s", "16");
+		break;
+	case 0x51:
+		sprintf(bitpos, "%s", "17");
+		break;
+	case 0x49:
+		sprintf(bitpos, "%s", "18");
+		break;
+	case 0xC8:
+		sprintf(bitpos, "%s", "19");
+		break;
+	case 0x64:
+		sprintf(bitpos, "%s", "20");
+		break;
+	case 0x54:
+		sprintf(bitpos, "%s", "21");
+		break;
+	case 0x4C:
+		sprintf(bitpos, "%s", "22");
+		break;
+	case 0xCD:
+		sprintf(bitpos, "%s", "23");
+		break;
+	case 0x62:
+		sprintf(bitpos, "%s", "24");
+		break;
+	case 0x52:
+		sprintf(bitpos, "%s", "25");
+		break;
+	case 0x4A:
+		sprintf(bitpos, "%s", "26");
+		break;
+	case 0xCB:
+		sprintf(bitpos, "%s", "27");
+		break;
+	case 0x67:
+		sprintf(bitpos, "%s", "28");
+		break;
+	case 0x57:
+		sprintf(bitpos, "%s", "29");
+		break;
+	case 0x4F:
+		sprintf(bitpos, "%s", "30");
+		break;
+	case 0xCE:
+		sprintf(bitpos, "%s", "31");
+		break;
+	case 0x31:
+		sprintf(bitpos, "%s", "32");
+		break;
+	case 0x29:
+		sprintf(bitpos, "%s", "33");
+		break;
+	case 0xA8:
+		sprintf(bitpos, "%s", "34");
+		break;
+	case 0x68:
+		sprintf(bitpos, "%s", "35");
+		break;
+	case 0x34:
+		sprintf(bitpos, "%s", "36");
+		break;
+	case 0x2C:
+		sprintf(bitpos, "%s", "37");
+		break;
+	case 0xAD:
+		sprintf(bitpos, "%s", "38");
+		break;
+	case 0x6D:
+		sprintf(bitpos, "%s", "39");
+		break;
+	case 0x32:
+		sprintf(bitpos, "%s", "40");
+		break;
+	case 0x2A:
+		sprintf(bitpos, "%s", "41");
+		break;
+	case 0xAB:
+		sprintf(bitpos, "%s", "42");
+		break;
+	case 0x6B:
+		sprintf(bitpos, "%s", "43");
+		break;
+	case 0x37:
+		sprintf(bitpos, "%s", "44");
+		break;
+	case 0x2F:
+		sprintf(bitpos, "%s", "45");
+		break;
+	case 0xAE:
+		sprintf(bitpos, "%s", "46");
+		break;
+	case 0x6E:
+		sprintf(bitpos, "%s", "47");
+		break;
+	case 0x46:
+		sprintf(bitpos, "%s", "48");
+		break;
+	case 0x26:
+		sprintf(bitpos, "%s", "49");
+		break;
+	case 0x16:
+		sprintf(bitpos, "%s", "50");
+		break;
+	case 0x86:
+		sprintf(bitpos, "%s", "51");
+		break;
+	case 0x45:
+		sprintf(bitpos, "%s", "52");
+		break;
+	case 0x25:
+		sprintf(bitpos, "%s", "53");
+		break;
+	case 0x15:
+		sprintf(bitpos, "%s", "54");
+		break;
+	case 0x85:
+		sprintf(bitpos, "%s", "55");
+		break;
+	case 0x43:
+		sprintf(bitpos, "%s", "56");
+		break;
+	case 0x23:
+		sprintf(bitpos, "%s", "57");
+		break;
+	case 0x13:
+		sprintf(bitpos, "%s", "58");
+		break;
+	case 0x83:
+		sprintf(bitpos, "%s", "59");
+		break;
+	case 0x1A:
+		sprintf(bitpos, "%s", "60");
+		break;
+	case 0x9B:
+		sprintf(bitpos, "%s", "61");
+		break;
+	case 0x5B:
+		sprintf(bitpos, "%s", "62");
+		break;
+	case 0x3B:
+		sprintf(bitpos, "%s", "63");
+		break;
+	case 0x80:
+		sprintf(bitpos, "%s", "ECC-0");
+		break;
+	case 0x40:
+		sprintf(bitpos, "%s", "ECC-1");
+		break;
+	case 0x20:
+		sprintf(bitpos, "%s", "ECC-2");
+		break;
+	case 0x10:
+		sprintf(bitpos, "%s", "ECC-3");
+		break;
+	case 0x08:
+		sprintf(bitpos, "%s", "ECC-4");
+		break;
+	case 0x04:
+		sprintf(bitpos, "%s", "ECC-5");
+		break;
+	case 0x02:
+		sprintf(bitpos, "%s", "ECC-6");
+		break;
+	case 0x01:
+		sprintf(bitpos, "%s", "ECC-7");
+		break;
+	default:
+		sprintf(bitpos, "%s", "UNKNOWN");
+		break;
+	}
+	printk(KERN_ERR "DDR ERROR CALCULATED ECC: 0x%02x\n", calculated_ecc);
+	printk(KERN_ERR "DDR ERROR STORED ECC: 0x%02x\n", stored_ecc);
+	printk(KERN_ERR "DDR ERROR ECC SYNDROME: 0x%02x\n",
+	       calculated_ecc ^ stored_ecc);
+	printk(KERN_ERR "DDR ERROR BIT LOCATION: %s\n", bitpos);
+}
+
+static irqreturn_t mvme7100_ddr_err_handler(int irq, void *dev_id)
+{
+	u32 err_addr, data_hi, data_lo, ecc, err_attr, err_det, sbe_count;
+	u32 pfn, offset;
+	struct page *pg;
+	void *virt_addr;
+	unsigned long flags = 0;
+	int handled = IRQ_NONE;
+	
+	err_det = readl(ddr1_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+	if (!err_det)
+		goto controller2;
+
+	/* Collect error information from the error registers */
+	err_addr = readl(ddr1_err_regs + DDR_CAPT_ADDR - DDR_ERR_REGS_OFFSET);
+	data_hi = readl(ddr1_err_regs + DDR_CAPT_DATA_HI - DDR_ERR_REGS_OFFSET);
+	data_lo = readl(ddr1_err_regs + DDR_CAPT_DATA_LO - DDR_ERR_REGS_OFFSET);
+	err_attr = readl(ddr1_err_regs + DDR_CAPT_ATTR - DDR_ERR_REGS_OFFSET);
+	ecc = readl(ddr1_err_regs + DDR_CAPT_ECC - DDR_ERR_REGS_OFFSET);
+	sbe_count = readl(ddr1_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+
+	ddr1_errors++;
+
+	/* Display error information */
+	printk(KERN_ERR "DDR Controller 1 Error!\n");
+	printk(KERN_ERR "DDR 1 ERROR DETECT REG: 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "DDR 1 ERROR ADDRESS CAPTURE REG: 0x%08x\n",
+	       swab32(err_addr));
+	printk(KERN_ERR "DDR 1 ERROR DATA HIGH CAPTURE REG: 0x%08x\n",
+	       swab32(data_hi));
+	printk(KERN_ERR "DDR 1 ERROR DATA LOW CAPTURE REG: 0x%08x\n",
+	       swab32(data_lo));
+	printk(KERN_ERR "DDR 1 ERROR ATTRIBUTES CAPTURE REG: 0x%08x\n",
+	       swab32(err_attr));
+	printk(KERN_ERR "DDR 1 ERROR SBE REG: 0x%08x\n", swab32(sbe_count));
+	printk(KERN_ERR "DDR 1 ERROR COUNT: %u\n", ddr1_errors);
+
+	if (err_det & DDR_SBE) {
+		/* Scrub block */
+		pfn = err_addr >> PAGE_SHIFT;
+		offset = err_addr & ~PAGE_MASK;
+
+		pg = pfn_to_page(pfn);
+
+		if (PageHighMem(pg))
+			local_irq_save(flags);
+
+		virt_addr = kmap_atomic(pg, KM_BOUNCE_READ);
+		atomic_scrub(virt_addr + offset, 8);
+		kunmap_atomic(virt_addr, KM_BOUNCE_READ);
+
+		if (PageHighMem(pg))
+			local_irq_restore(flags);
+	}
+
+	/* Determine and display bit location */
+	mvme7100_determine_bit_location(swab32(data_hi),
+					swab32(data_lo), swab32(ecc) & 0xff);
+
+	/* Clear interrupt cause */
+	writel(err_det, ddr1_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+
+       /* Clear capture attribute register */
+        writel(0, ddr1_err_regs + DDR_CAPT_ATTR - DDR_ERR_REGS_OFFSET);
+
+        handled = IRQ_HANDLED;
+
+controller2:
+        err_det = readl(ddr2_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+        if (!err_det)
+                return handled;
+
+        /* Collect error information from the error registers */
+        err_attr = readl(ddr2_err_regs + DDR_CAPT_ATTR - DDR_ERR_REGS_OFFSET);
+        data_hi = readl(ddr2_err_regs + DDR_CAPT_DATA_HI - DDR_ERR_REGS_OFFSET);
+        data_lo = readl(ddr2_err_regs + DDR_CAPT_DATA_LO - DDR_ERR_REGS_OFFSET);
+        err_addr = readl(ddr2_err_regs + DDR_CAPT_ADDR - DDR_ERR_REGS_OFFSET);
+        ecc = readl(ddr2_err_regs + DDR_CAPT_ECC - DDR_ERR_REGS_OFFSET);
+        sbe_count = readl(ddr2_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+
+        ddr2_errors++;
+
+       /* Display error information */
+        printk(KERN_ERR "DDR Controller 2 Error!\n");
+        printk(KERN_ERR "DDR 2 ERROR DETECT REG 0x%08x\n", swab32(err_det));
+        printk(KERN_ERR "DDR 2 ERROR ADDRESS CAPTURE REG 0x%08x\n",
+               swab32(err_addr));
+        printk(KERN_ERR "DDR 2 ERROR DATA HIGH CAPTURE REG 0x%08x\n",
+               swab32(data_hi));
+        printk(KERN_ERR "DDR 2 ERROR DATA LOW CAPTURE REG 0x%08x\n",
+               swab32(data_lo));
+        printk(KERN_ERR "DDR 2 ERROR ATTRIBUTES CAPTURE REG 0x%08x\n",
+               swab32(err_attr));
+        printk(KERN_ERR "DDR 2 ERROR SBE REG 0x%08x\n", swab32(sbe_count));
+        printk(KERN_ERR "DDR 2 ERROR COUNT %u\n", ddr2_errors);
+
+        if (err_det & DDR_SBE) {
+                /* Scrub block */
+                pfn = err_addr >> PAGE_SHIFT;
+                offset = err_addr & ~PAGE_MASK;
+
+                pg = pfn_to_page(pfn);
+
+                if (PageHighMem(pg))
+                       local_irq_save(flags);
+
+                virt_addr = kmap_atomic(pg, KM_BOUNCE_READ);
+                atomic_scrub(virt_addr + offset, 8);
+                kunmap_atomic(virt_addr, KM_BOUNCE_READ);
+
+                if (PageHighMem(pg))
+                        local_irq_restore(flags);
+        }
+
+        /* Determine and display bit location */
+        mvme7100_determine_bit_location(swab32(data_hi),
+                                        swab32(data_lo), swab32(ecc) & 0xff);
+
+        /* Clear interrupt cause register */
+        writel(err_det, ddr2_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+
+        /* Clear capture attribute register */
+        writel(0, ddr2_err_regs + DDR_CAPT_ATTR - DDR_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+#endif
+
+#ifdef CONFIG_MVME7100_ENABLE_L2_ERRORS
+
+static irqreturn_t mvme7100_l2cache_err_handler(int irq, void *dev_id)
+{
+	u32 err_addr, data_hi, data_lo, ecc, err_attr, err_det, err_ctl;
+
+	/* Collect error information from the error registers */
+	err_det = mfspr(SPRN_L2ERRDET);
+	err_attr = mfspr(SPRN_L2ERRATTR);
+	err_addr = mfspr(SPRN_L2ERRADDR);
+	data_hi = mfspr(SPRN_L2CAPTDATAHI);
+	data_lo = mfspr(SPRN_L2CAPTDATALO);
+	ecc = mfspr(SPRN_L2CAPTECC);
+	err_ctl = mfspr(SPRN_L2ERRCTL);
+
+	/* Clear interrupt cause and capture registers */
+	mtspr(SPRN_L2ERRDET, err_det);
+	mtspr(SPRN_L2ERRATTR, 0);
+
+	/* Display error information */
+	printk(KERN_ERR "L2 Cache Error!\n");
+	printk(KERN_ERR "L2 ERROR DETECT REG: 0x%08x\n", err_det);
+	printk(KERN_ERR "L2 ERROR ADDRESS CAPTURE REG: 0x%08x\n", err_addr);
+	printk(KERN_ERR "L2 ERROR DATA HIGH CAPTURE REG: 0x%08x\n", data_hi);
+	printk(KERN_ERR "L2 ERROR DATA LOW CAPTURE REG: 0x%08x\n", data_lo);
+	printk(KERN_ERR "L2 ERROR ATTRIBUTES CAPTURE REG: 0x%08x\n", err_attr);
+	printk(KERN_ERR "L2 ERROR SYNDROME REG: 0x%08x\n", ecc);
+	printk(KERN_ERR "L2 ERROR CONTROL REG: 0x%08x\n", err_ctl);
+
+	return IRQ_HANDLED;
+}
+#endif
+
+#ifdef CONFIG_MVME7100_ENABLE_PCI_ERRORS
+
+static irqreturn_t mvme7100_pci0_err_handler(int irq, void *dev_id)
+{
+	u32 err_det, err_status, err_cap0, err_cap1, err_cap2, err_cap3;
+
+	if (dev_id != &pci0_err_regs)
+		return IRQ_NONE;
+
+	/* Collect error information from the error registers */
+	err_det = readl(pci0_err_regs + PEX_ERR_DR - PEX_ERR_REGS_OFFSET);
+	if (err_det == 0)
+		return IRQ_NONE;
+
+	err_status =
+	    readl(pci0_err_regs + PEX_ERR_CAP_STAT - PEX_ERR_REGS_OFFSET);
+	err_cap0 = readl(pci0_err_regs + PEX_ERR_CAP_R0 - PEX_ERR_REGS_OFFSET);
+	err_cap1 = readl(pci0_err_regs + PEX_ERR_CAP_R1 - PEX_ERR_REGS_OFFSET);
+	err_cap2 = readl(pci0_err_regs + PEX_ERR_CAP_R2 - PEX_ERR_REGS_OFFSET);
+	err_cap3 = readl(pci0_err_regs + PEX_ERR_CAP_R3 - PEX_ERR_REGS_OFFSET);
+
+	pci0_errors++;
+	/* Display error information */
+	printk(KERN_ERR "PCI Controller 0 Error!\n");
+	printk(KERN_ERR "PEX ERROR DETECT REG: 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "PEX ERR CAP STATUS REG: 0x%08x\n", swab32(err_status));
+	printk(KERN_ERR "PEX ERR CAP REG0: 0x%08x\n", swab32(err_cap0));
+	printk(KERN_ERR "PEX ERR CAP REG1: 0x%08x\n", swab32(err_cap1));
+	printk(KERN_ERR "PEX ERR CAP REG2: 0x%08x\n", swab32(err_cap2));
+	printk(KERN_ERR "PEX ERR CAP REG3: 0x%08x\n", swab32(err_cap3));
+	printk(KERN_ERR "PEX Error Count:\t%u\n", pci0_errors);
+
+	/* Clear interrupt cause and capture registers */
+	writel(err_det, pci0_err_regs + PEX_ERR_DR - PEX_ERR_REGS_OFFSET);
+	writel(swab32(0x1),
+	       pci0_err_regs + PEX_ERR_CAP_STAT - PEX_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mvme7100_pci1_err_handler(int irq, void *dev_id)
+{
+	u32 err_det, err_status, err_cap0, err_cap1, err_cap2, err_cap3;
+
+	if (dev_id != &pci1_err_regs)
+		return IRQ_NONE;
+
+	/* Collect error information from the error registers */
+	err_det = readl(pci1_err_regs + PEX_ERR_DR - PEX_ERR_REGS_OFFSET);
+	if (err_det == 0)
+		return IRQ_NONE;
+
+	err_status =
+	    readl(pci1_err_regs + PEX_ERR_CAP_STAT - PEX_ERR_REGS_OFFSET);
+	err_cap0 = readl(pci1_err_regs + PEX_ERR_CAP_R0 - PEX_ERR_REGS_OFFSET);
+	err_cap1 = readl(pci1_err_regs + PEX_ERR_CAP_R1 - PEX_ERR_REGS_OFFSET);
+	err_cap2 = readl(pci1_err_regs + PEX_ERR_CAP_R2 - PEX_ERR_REGS_OFFSET);
+	err_cap3 = readl(pci1_err_regs + PEX_ERR_CAP_R3 - PEX_ERR_REGS_OFFSET);
+
+	pci1_errors++;
+	/* Display error information */
+	printk(KERN_ERR "PCI Controller 1 Error!\n");
+	printk(KERN_ERR "PEX ERROR DETECT REG: 0x%08x\n", swab32(err_det));
+	printk(KERN_ERR "PEX ERR CAP STATUS REG: 0x%08x\n", swab32(err_status));
+	printk(KERN_ERR "PEX ERR CAP REG0: 0x%08x\n", swab32(err_cap0));
+	printk(KERN_ERR "PEX ERR CAP REG1: 0x%08x\n", swab32(err_cap1));
+	printk(KERN_ERR "PEX ERR CAP REG2: 0x%08x\n", swab32(err_cap2));
+	printk(KERN_ERR "PEX ERR CAP REG3: 0x%08x\n", swab32(err_cap3));
+	printk(KERN_ERR "PEX Error Count:\t%u\n", pci1_errors);
+
+	/* Clear interrupt cause and capture registers */
+	writel(err_det, pci1_err_regs + PEX_ERR_DR - PEX_ERR_REGS_OFFSET);
+	writel(swab32(0x1),
+	       pci1_err_regs + PEX_ERR_CAP_STAT - PEX_ERR_REGS_OFFSET);
+
+	return IRQ_HANDLED;
+}
+
+#endif
+
+
+void mvme7100_restart(char *cmd)
+{
+	volatile ulong i = 10000000;
+
+	local_irq_disable();
+	writeb(MVME7100_BOARD_RESET, system_control_reg_addr);
+
+	while (i-- > 0) ;
+	panic("restart failed\n");
+}
+
+
+void __init mvme7100_init_irq(void)
+{
+	struct mpic *mpic1;
+	struct device_node *np = NULL;
+	struct resource res;
+
+	/* Determine PIC address. */
+	np = of_find_node_by_type(NULL, "open-pic");
+	if (np == NULL) {
+		printk(KERN_ERR "Could not find open-pic node\n");
+		return;
+	}
+	if (of_address_to_resource(np, 0, &res)) {
+		printk(KERN_ERR "Could not map mpic register space\n");
+		of_node_put(np);
+		return;
+	}
+
+	/* Alloc mpic structure and per isu has 16 INT entries. */
+	mpic1 = mpic_alloc(np, res.start,
+			MPIC_PRIMARY | MPIC_WANTS_RESET | 
+			MPIC_BIG_ENDIAN | MPIC_BROKEN_FRR_NIRQS |
+			MPIC_SINGLE_DEST_CPU,
+			0, 256, " MPIC     ");
+	BUG_ON(mpic1 == NULL);
+
+	mpic_init(mpic1);
+	of_node_put(np);
+
+#ifdef CONFIG_MVME7100_ENABLE_L2_ERRORS
+	np = of_find_node_by_type(NULL, "l2_cache");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find l2_cache node\n");
+	} else {
+		l2_irq = irq_of_parse_and_map(np, 0);
+		if (l2_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map L2 cache irq\n");
+		of_node_put(np);
+	}
+#endif
+
+#ifdef CONFIG_MVME7100_ENABLE_DDR_ERRORS
+	np = of_find_node_by_type(NULL, "memory-controller");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find memory-controller node\n");
+	} else {
+		mpc86xx_ddr_irq = irq_of_parse_and_map(np, 0);
+		if (mpc86xx_ddr_irq == NO_IRQ)
+			printk(KERN_ERR
+			       "Unable to map memory controller irq\n");
+		of_node_put(np);
+	}
+#endif
+
+	np = of_find_node_by_path("/pcie@f1008000");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find PCI 0 node\n");
+	} else {
+		pci0_irq = irq_of_parse_and_map(np, 0);
+		if (pci0_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map PCI 0 irq\n");
+		of_node_put(np);
+	}
+
+	np = of_find_node_by_path("/pcie@f1009000");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find PCI 1 node\n");
+	} else {
+		pci1_irq = irq_of_parse_and_map(np, 0);
+		if (pci1_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map PCI 1 irq\n");
+		of_node_put(np);
+	}
+
+#ifdef CONFIG_SENSORS_LM90
+	np = of_find_node_by_type(NULL, "thermostat");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find temp sensor node\n");
+	} else {
+		maxim6649_irq = irq_of_parse_and_map(np, 0);
+		if (maxim6649_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map MAXIM6649 irq\n");
+		of_node_put(np);
+	}
+#endif
+
+#ifdef CONFIG_MVME7100_TICK_TIMERS
+	np = of_find_node_by_type(NULL, "board_timers");
+	if (np == NULL) {
+		printk(KERN_INFO "PIC init: cannot find timers node\n");
+	} else {
+		mvme7100_timer_irq = irq_of_parse_and_map(np, 0);
+		if (mvme7100_timer_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map timers irq\n");
+		of_node_put(np);
+	}
+#endif
+
+	np = of_find_node_by_path("/serial@f2011000");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find serial@f2011000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@f2011000 irq\n");
+		of_node_put(np);
+	}
+
+	np = of_find_node_by_path("/serial@f2012000");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find serial@f2012000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@f2012000 irq\n");
+		of_node_put(np);
+	}
+
+	np = of_find_node_by_path("/serial@f2013000");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find serial@f2013000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@f2013000 irq\n");
+		of_node_put(np);
+	}
+	np = of_find_node_by_path("/serial@f2014000");
+	if (np == NULL) {
+		printk(KERN_INFO
+		       "PIC init: cannot find serial@f2014000 node\n");
+	} else {
+		serial_irq = irq_of_parse_and_map(np, 0);
+		if (serial_irq == NO_IRQ)
+			printk(KERN_ERR "Unable to map serial@f2014000 irq\n");
+		of_node_put(np);
+	}
+}
+
+
+static void __init mvme7100_misc_init(void)
+{
+	void __iomem *reg_block;
+	u8 reg_value;
+	u32 val;
+	struct device_node *np = NULL;
+	const u32 *regs;
+#ifdef CONFIG_MVME7100_ENABLE_L2_ERRORS
+	unsigned long a;
+#endif
+#ifdef CONFIG_MVME7100_ENABLE_DDR_ERRORS
+	u32 sbe_count;
+#endif
+
+	np = of_find_node_by_type(np, "soc");
+	if (np == NULL) {
+		printk("Error:Cannot find soc node\n");
+		return;
+	}
+	regs = of_get_property(np, "reg", NULL);
+	if (regs == NULL) {
+		printk("Error:Cannot get reg property from soc node\n");
+		of_node_put(np);
+		return;
+	} else
+		hb_baddr = regs[0];
+
+	of_node_put(np);
+
+#ifdef CONFIG_MVME7100_ENABLE_L2_ERRORS
+
+	val = _get_L2CR();
+	val &= ~L2CR_L2E;
+	_set_L2CR(val);
+	for (a = KERNELBASE; a < KERNELBASE + 0x800000; a += 32)
+		asm volatile ("dcbf 0,%0"::"r" (a):"memory");
+	asm volatile ("sync");
+
+	/* Enable L2 cache error detection */
+	mtspr(SPRN_L2ERRDIS, 0);
+	asm volatile ("eieio");
+	asm volatile ("isync");
+	/* Clear any logged L2 errors */
+	mtspr(SPRN_L2ERRDET, 0x8000001C);
+	asm volatile ("eieio");
+	asm volatile ("isync");
+
+#endif
+	/* Enable L2 */
+	val = _get_L2CR();
+	val |= L2CR_L2E;
+	_set_L2CR(val);
+	printk("L2 cache enabled. L2CTL reg: 0x%lx\n", _get_L2CR());
+
+#ifdef CONFIG_MVME7100_ENABLE_DDR_ERRORS
+	ddr1_err_regs =
+	    ioremap(hb_baddr + DDR1_REGS_OFFSET + DDR_ERR_REGS_OFFSET, DDR_ERR_REGS_SIZE);
+	/* Enable all error detection */
+	writel(0, ddr1_err_regs + DDR_ERR_DISABLE - DDR_ERR_REGS_OFFSET);
+	/* Clear logged DDR errors */
+	writel(swab32(0x8000000D),
+	       ddr1_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+	/* Set single-bit error threshold */
+	sbe_count = 0x00010000;
+	writel(swab32(sbe_count),
+	       ddr1_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+
+        ddr2_err_regs =
+            ioremap(hb_baddr + DDR2_REGS_OFFSET + DDR_ERR_REGS_OFFSET, DDR_ERR_REGS_SIZE);
+        /* Enable all error detection */
+        writel(0, ddr2_err_regs + DDR_ERR_DISABLE - DDR_ERR_REGS_OFFSET);
+        /* Clear logged DDR errors */
+        writel(swab32(0x8000000D),
+               ddr2_err_regs + DDR_ERR_DET - DDR_ERR_REGS_OFFSET);
+        /* Set single-bit error threshold */
+        sbe_count = 0x00010000;
+        writel(swab32(sbe_count),
+               ddr2_err_regs + DDR_ERR_SBE - DDR_ERR_REGS_OFFSET);
+#endif
+
+#ifdef CONFIG_MVME7100_ENABLE_PCI_ERRORS
+	/* Map in PCI Error Registers */
+	pci0_err_regs = ioremap(hb_baddr + PCI0_REGS_OFFSET + 
+			       PEX_ERR_REGS_OFFSET, PEX_ERR_REGS_SIZE);
+	pci1_err_regs = ioremap(hb_baddr + PCI1_REGS_OFFSET + 
+			       PEX_ERR_REGS_OFFSET, PEX_ERR_REGS_SIZE);
+#endif
+
+#ifdef CONFIG_VME_BRIDGE
+	{
+		extern void vmemod_setup_options(char *);
+
+		vmemod_setup_options(cmd_line);
+	}
+#endif
+
+	reg_block = ioremap(MVME7100_SYSTEM_STATUS_REG, 64);
+
+	/* Turn off USR1 Red LED */
+	reg_value = readb(reg_block + MVME7100_STATUS_INDICATOR_REG_OFFSET);
+	reg_value &= ~MVME7100_USR1_RED_LED;
+	writeb(reg_value, reg_block + MVME7100_STATUS_INDICATOR_REG_OFFSET);
+
+	/* Disable RTC, Temp Sensor, and Abort interrupts */
+	reg_value = readb(reg_block + MVME7100_INTERRUPT_REG_2_OFFSET);
+	reg_value |= MVME7100_RTC_MASK | MVME7100_TEMP_MASK |
+	    MVME7100_ABORT_MASK;
+	writeb(reg_value, reg_block + MVME7100_INTERRUPT_REG_2_OFFSET);
+
+	/* Turn off NOR flash SW write-protect */
+	reg_value = readb(reg_block + MVME7100_NOR_FLASH_CTRL_STAT_REG_OFFSET);
+	reg_value &= ~MVME7100_NOR_FLASH_WP_SW;
+	writeb(reg_value, reg_block + MVME7100_NOR_FLASH_CTRL_STAT_REG_OFFSET);
+
+	iounmap(reg_block);
+
+	/* Hack for Rev A boards */
+#if 0
+	reg_block = ioremap(0xe1005008, 4);
+	val = swab32(readl(reg_block));
+	val &= ~1;
+	writel(swab32(val), reg_block);
+	iounmap(reg_block);
+#endif
+
+	system_control_reg_addr = ioremap(MVME7100_SYSTEM_CONTROL_REG, 1);
+
+	return;
+}
+
+static void __init mvme7100_setup_arch(void)
+{
+	struct device_node *np;
+
+	if (ppc_md.progress)
+		ppc_md.progress("mvme7100_setup_arch()", 0);
+
+#ifdef CONFIG_PCI
+	for_each_compatible_node(np, "pci", "fsl,mpc8641-pcie") {
+		struct resource rsrc;
+
+		of_address_to_resource(np, 0, &rsrc);
+		if ((rsrc.start & 0xfffff) == 0x8000)
+			fsl_add_bridge(np, 1);
+		else
+			fsl_add_bridge(np, 0);
+	}
+#endif
+
+	printk("MVME7100 board from Emerson Network Power Embedded Computing\n");
+
+#ifdef  CONFIG_ROOT_NFS
+	ROOT_DEV = Root_NFS;
+#else
+	ROOT_DEV = Root_SDA2;
+#endif
+
+#ifdef CONFIG_SMP
+	mpc86xx_smp_init();
+#endif
+
+#ifdef CONFIG_VME_BRIDGE_BOOTMEM
+	vme_bootmem_size = CONFIG_VME_BRIDGE_BOOTMEM_SIZE * 1024 * 1024;
+
+	if (vme_bootmem_size > (total_memory / 2)) {
+		printk(KERN_WARNING
+		       "BOOTMEM Size Requested: 0x%x Total Memory 0x%lx\n",
+		       vme_bootmem_size, total_memory);
+		printk(KERN_WARNING
+		       "BOOTMEM Size requested has been capped at half the total memory\n");
+		vme_bootmem_size = total_memory / 2;
+	}
+	vme_driver_bootmem = __alloc_bootmem(vme_bootmem_size, 0x10000, 0);
+	if (!vme_driver_bootmem) {
+		printk(KERN_WARNING "Unable to obtain boot memory for VME\n");
+		vme_bootmem_size = 0;
+	} else {
+		printk(KERN_INFO
+		       "0x%x of boot memory reserved for setup of VME inbound window 7\n",
+		       vme_bootmem_size);
+	}
+#endif
+	mvme7100_misc_init();
+}
+
+
+void mvme7100_show_cpuinfo(struct seq_file *m)
+{
+	struct device_node *root;
+	uint pvid, svid, phid1;
+	phys_addr_t immr_base;
+	uint memsize = total_memory;
+	const char *model = "";
+	void __iomem *reg_block;
+	u8 reg_value;
+	u32 reg32_value;
+	char buff[16] = "";
+
+	seq_printf(m, "Vendor\t\t: Freescale\n");
+
+	root = of_find_node_by_path("/");
+	if (root)
+		model = of_get_property(root, "model", NULL);
+	seq_printf(m, "Machine\t\t: %s\n", model);
+	of_node_put(root);
+
+	pvid = mfspr(SPRN_PVR);
+	svid = mfspr(SPRN_SVR);
+	immr_base = get_immrbase();
+
+	seq_printf(m, "PVR\t\t: 0x%x\n", pvid);
+	seq_printf(m, "SVR\t\t: 0x%x\n", svid);
+	seq_printf(m, "HID0\t\t: 0x%08lx\n", mfspr(SPRN_HID0));
+	seq_printf(m, "HID1\t\t: 0x%08lx\n", mfspr(SPRN_HID1));
+	seq_printf(m, "CCSR Base\t: 0x%08x\n", immr_base);
+
+	/* Display cpu Pll setting */
+	phid1 = mfspr(SPRN_HID1);
+	seq_printf(m, "PLL setting\t: 0x%x\n", ((phid1 >> 24) & 0x3f));
+
+	/* Display the cache settings */
+	seq_printf(m, "L2CR\t\t: 0x%lx\n", _get_L2CR());
+
+	seq_printf(m, "\nBOARD INFORMATION:\n\n");
+
+	reg_block = ioremap(MVME7100_SYSTEM_STATUS_REG, 64);
+
+	/* Display the amount of memory */
+	seq_printf(m, "Memory\t\t\t: %d MB\n", memsize / (1024 * 1024));
+
+	/* System Status Register */
+	reg_value = readb(reg_block);
+	seq_printf(m, "SW8 State\t\t: %s\n",
+		   ((reg_value & MVME7100_STATE_SW8) ? "ON" : "OFF"));
+	seq_printf(m, "SW7 State\t\t: %s\n",
+		   ((reg_value & MVME7100_STATE_SW7) ? "ON" : "OFF"));
+	seq_printf(m, "SW6 State\t\t: %s\n",
+		   ((reg_value & MVME7100_STATE_SW6) ? "ON" : "OFF"));
+	seq_printf(m, "SW5 State\t\t: %s\n",
+		   ((reg_value & MVME7100_STATE_SW5) ? "ON" : "OFF"));
+
+	seq_printf(m, "Safe Start Status\t: %s\n",
+		   ((reg_value & MVME7100_SAFE_START) ?
+		    "Safe ENV settings used" : "NVRAM ENV settings used"));
+
+	seq_printf(m, "PEX8525 Error Status\t: %s\n",
+		   ((reg_value & MVME7100_PEX8525_ERROR) ?
+		    "Fatal Error" : "No Fatal Error"));
+
+	switch (reg_value & MVME7100_BOARD_TYPE_MASK) {
+	case MVME7100_BOARD_TYPE_PRPMC:
+		sprintf(buff, "PrPMC");
+		break;
+	case MVME7100_BOARD_TYPE_VME:
+		sprintf(buff, "VME");
+		break;
+	default:
+		sprintf(buff, "Unknown");
+		break;
+	}
+	seq_printf(m, "Board Type\t\t: %s\n", buff);
+
+	/* System Control Register */
+	reg_value = readb(reg_block + MVME7100_SYSTEM_CONTROL_REG_OFFSET);
+	seq_printf(m, "EEPROM WP Status\t: %s\n",
+		   ((reg_value & MVME7100_EEPROM_WP) ?
+		    "EEPROM Write Protected" : "EEPROM Not Write Protected"));
+
+	/* Status Indicator Register */
+	reg_value = readb(reg_block + MVME7100_STATUS_INDICATOR_REG_OFFSET);
+	seq_printf(m, "USR1 Red LED\t\t: %s\n",
+		   ((reg_value & MVME7100_USR1_RED_LED) ? "Lit" : "Not Lit"));
+	seq_printf(m, "USR1 Yellow LED\t\t: %s\n",
+		   ((reg_value & MVME7100_USR1_YELLOW_LED) ? "Lit" :
+		    "Not Lit"));
+	seq_printf(m, "USR2 LED\t\t: %s\n",
+		   ((reg_value & MVME7100_USR2_LED) ? "Lit" : "Not Lit"));
+	seq_printf(m, "USR3 LED\t\t: %s\n",
+		   ((reg_value & MVME7100_USR3_LED) ? "Lit" : "Not Lit"));
+
+	/* NOR Flash Control/Status Register */
+	reg_value = readb(reg_block + MVME7100_NOR_FLASH_CTRL_STAT_REG_OFFSET);
+	seq_printf(m, "NOR Flash Map Select\t: %s\n",
+		   ((reg_value & MVME7100_NOR_FLASH_MAP_SELECT) ?
+		    "Boot Block A Mapped to Highest Address" :
+		    "Flash Memory Map Controlled by Flash Boot Block Select"));
+	seq_printf(m, "NOR Flash WP SW\t\t: %s\n",
+		   ((reg_value & MVME7100_NOR_FLASH_WP_SW) ?
+		    "Write Protected" : "Not Write Protected"));
+	seq_printf(m, "NOR Flash WP HW\t\t: %s\n",
+		   ((reg_value & MVME7100_NOR_FLASH_WP_HW) ?
+		    "Write Protected" : "Not Write Protected"));
+	seq_printf(m, "NOR Flash Boot Select\t: %s\n",
+		   ((reg_value & MVME7100_NOR_FLASH_BLK_SEL) ?
+		    "Boot Block B Selected" : "Boot Block A Selected"));
+	seq_printf(m, "NOR Flash Ready Status\t: %s\n",
+		   ((reg_value & MVME7100_NOR_FLASH_RDY) ?
+		    "Bit Set" : "Bit Not Set"));
+
+	/* Interrupt Register 1 */
+	reg_value = readb(reg_block + MVME7100_INTERRUPT_REG_1_OFFSET);
+
+	seq_printf(m, "TSEC4 PHY Interrupt\t: %s\n",
+		   ((reg_value & MVME7100_TSEC4_PHY_INTERRUPT) ?
+		    "Asserted" : "Not Asserted"));
+
+	seq_printf(m, "TSEC3 PHY Interrupt\t: %s\n",
+		   ((reg_value & MVME7100_TSEC3_PHY_INTERRUPT) ?
+		    "Asserted" : "Not Asserted"));
+
+	seq_printf(m, "TSEC2 PHY Interrupt\t: %s\n",
+		   ((reg_value & MVME7100_TSEC2_PHY_INTERRUPT) ?
+		    "Asserted" : "Not Asserted"));
+
+	seq_printf(m, "TSEC1 PHY Interrupt\t: %s\n",
+		   ((reg_value & MVME7100_TSEC1_PHY_INTERRUPT) ?
+		    "Asserted" : "Not Asserted"));
+
+	/* Interrupt Register 2 */
+	reg_value = readb(reg_block + MVME7100_INTERRUPT_REG_2_OFFSET);
+
+	seq_printf(m, "RTC Mask\t\t: %s\n",
+		   ((reg_value & MVME7100_RTC_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+	seq_printf(m, "Temperature Sensor Mask\t: %s\n",
+		   ((reg_value & MVME7100_TEMP_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+	seq_printf(m, "ABORT Mask\t\t: %s\n",
+		   ((reg_value & MVME7100_ABORT_MASK) ?
+		    "Interrupt Disabled" : "Interrupt Enabled"));
+
+	seq_printf(m, "RTC Status\t\t: %s\n",
+		   ((reg_value & MVME7100_RTC_STATUS) ?
+		    "RTC Output Asserted" : "RTC Output Not Asserted"));
+	seq_printf(m, "Temp Sensor Status\t: %s\n",
+		   ((reg_value & MVME7100_TEMP_STATUS) ?
+		    "Temperature Sensor Output Asserted" :
+		    "Temperature Sensor Output Not Asserted"));
+	seq_printf(m, "Abort Status\t\t: %s\n",
+		   ((reg_value & MVME7100_ABORT_STATUS) ?
+		    "Abort Switch Asserted" : "Abort Switch Not Asserted"));
+
+	/* Presence Detect Register */
+	reg_value = readb(reg_block + MVME7100_PRESENCE_DETECT_REG_OFFSET);
+
+	seq_printf(m, "ERDY2\t\t\t: %s\n",
+		   ((reg_value & MVME7100_ERDY2) ?
+		    "ERDY2 Set" : "ERDY2 Not Set"));
+	seq_printf(m, "ERDY1\t\t\t: %s\n",
+		   ((reg_value & MVME7100_ERDY2) ?
+		    "ERDY1 Set" : "ERDY1 Not Set"));
+	seq_printf(m, "XMCSPAN\t\t\t: %s\n",
+		   ((reg_value & MVME7100_XMCSPAN_PRESENT) ?
+		    "XMCSPAN Installed" : "XMCSPAN Not Installed"));
+	seq_printf(m, "PMC Site 2\t\t: %s\n",
+		   ((reg_value & MVME7100_PMC2_PRESENT) ?
+		    "PMC Module Installed" : "PMC Module Not Installed"));
+	seq_printf(m, "PMC Site 1\t\t: %s\n",
+		   ((reg_value & MVME7100_PMC1_PRESENT) ?
+		    "PMC Module Installed" : "PMC Module Not Installed"));
+
+	/* NAND Flash1 CTRL Register */
+	reg_value = readb(reg_block + MVME7100_NAND_FLASH1_CTRL_REG_OFFSET);
+	seq_printf(m, "NAND 1 CONTROL Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash1 SELECT Register */
+	reg_value = readb(reg_block + MVME7100_NAND_FLASH1_SELECT_REG_OFFSET);
+	seq_printf(m, "NAND 1 SELECT Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash1 Presence Register */
+	reg_value = readb(reg_block + MVME7100_NAND_FLASH1_PRESENCE_REG_OFFSET);
+	seq_printf(m, "NAND 1 PRESENCE Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash1 STATUS Register */
+	reg_value = readb(reg_block + MVME7100_NAND_FLASH1_STATUS_REG_OFFSET);
+	seq_printf(m, "NAND 1 STATUS Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 CTRL Register */
+	reg_value = readb(reg_block + MVME7100_NAND_FLASH2_CTRL_REG_OFFSET);
+	seq_printf(m, "NAND 2 CONTROL Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 SELECT Register */
+	reg_value = readb(reg_block + MVME7100_NAND_FLASH2_SELECT_REG_OFFSET);
+	seq_printf(m, "NAND 2 SELECT Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 Presence Register */
+	reg_value = readb(reg_block + MVME7100_NAND_FLASH2_PRESENCE_REG_OFFSET);
+	seq_printf(m, "NAND 2 PRESENCE Reg\t: 0x%02x\n", reg_value);
+
+	/* NAND Flash2 STATUS Register */
+	reg_value = readb(reg_block + MVME7100_NAND_FLASH2_STATUS_REG_OFFSET);
+	seq_printf(m, "NAND 2 STATUS Reg\t: 0x%02x\n", reg_value);
+
+	/* PLD Revision Register */
+	reg_value = readb(reg_block + MVME7100_PLD_REVISION_REG_OFFSET);
+
+	seq_printf(m, "PLD Revision\t\t: 0x%x\n", reg_value);
+
+	/* PLD Date Code Register */
+	reg32_value = readl(reg_block + MVME7100_PLD_DATE_CODE_REG_OFFSET);
+	seq_printf(m, "PLD Date Code\t\t: 0x%08x\n",
+		   (((reg32_value & 0x000000ffU) << 24) |
+		    ((reg32_value & 0x0000ff00U) << 8) |
+		    ((reg32_value & 0x00ff0000U) >> 8) |
+		    ((reg32_value & 0xff000000U) >> 24)));
+
+	iounmap(reg_block);
+
+	return;
+}
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mvme7100_probe(void)
+{
+	unsigned long root = of_get_flat_dt_root();
+
+	if (of_flat_dt_is_compatible(root, "emerson,mvme7100"))
+		return 1;	/* Looks good */
+
+	return 0;
+}
+
+long __init mpc86xx_time_init(void)
+{
+	unsigned int temp;
+
+	/* Set the time base to zero */
+	mtspr(SPRN_TBWL, 0);
+	mtspr(SPRN_TBWU, 0);
+
+	temp = mfspr(SPRN_HID0);
+	temp |= HID0_TBEN;
+	mtspr(SPRN_HID0, temp);
+	asm volatile ("isync");
+
+	return 0;
+}
+
+static __initdata struct of_device_id of_bus_ids[] = {
+        {.type = "soc",},
+	{.compatible = "simple-bus",},
+	{},
+};
+
+static int __init declare_of_platform_devices(void)
+{
+	of_platform_bus_probe(NULL, of_bus_ids, NULL);
+
+	return 0;
+}
+
+machine_device_initcall(mvme7100, declare_of_platform_devices);
+
+
+void __init mvme7100_pcibios_fixup(void)
+{
+	struct pci_dev *dev = NULL;
+	u32 temp;
+
+	if ((dev = pci_get_device(PCI_VENDOR_ID_NEC,
+				PCI_DEVICE_ID_NEC_USB, NULL))) {
+		/* Set System Clock to 48MHz oscillator in EXT2 register */
+		pci_read_config_dword(dev, 0xe4, &temp);
+		temp |= 0x00000020;
+		pci_write_config_dword(dev, 0xe4, temp);
+		/* Port Power is always active; max ports = 2 */
+		pci_read_config_dword(dev, 0xe0, &temp);
+		temp &= ~0x00200007;
+		temp |= 0x00000002;
+		pci_write_config_dword(dev, 0xe0, temp);
+	}
+
+        dev = NULL;
+        for_each_pci_dev(dev) {
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE,
+                                      L1_CACHE_BYTES >> 2);
+                pci_write_config_byte(dev, PCI_LATENCY_TIMER, 0x80);
+        }
+
+	dev = NULL;
+	while ((dev = pci_get_device(PCI_VENDOR_ID_PLX, 0x8114, dev)) != NULL) {
+		void __iomem *vaddr;
+		u16  ctl;
+
+		/* PLX PEX8114 Errata */
+		pci_write_config_byte(dev, PCI_CACHE_LINE_SIZE, 16);
+
+		/* Change Max Read Request Size from 512 to 4096 bytes */
+		pci_read_config_word(dev, 0x70, &ctl);
+		ctl = (ctl & 0x0fff) | 0x5000;
+		pci_write_config_word(dev, 0x70, ctl);
+
+		/* Enable Address Stepping; Enable Memory Read Line Multiple */
+		vaddr = ioremap(pci_resource_start(dev, 0), 
+				pci_resource_len(dev, 0));
+		writel(readl(vaddr + 0xfa0) | 0x00003000, vaddr + 0xfa0);
+		iounmap(vaddr);
+        }
+
+	dev = NULL;
+	while ((dev = pci_get_device(PCI_VENDOR_ID_TUNDRA, 0x8114, dev)) != NULL) {
+		u32  tmp;
+
+		pci_read_config_dword(dev, 0xbc, &tmp);
+		/* Change prefetch for Memory Read from 1/2 DWords to
+                 * whatever is set in the MRL_33/MRL_66 field */
+		tmp |= 0x04000000;
+		pci_write_config_dword(dev, 0xbc, tmp);
+        }
+
+#ifdef CONFIG_MVME7100_ENABLE_L2_ERRORS
+	if (request_irq(l2_irq, mvme7100_l2cache_err_handler,
+			IRQF_DISABLED, "L2 Cache Error", (void *)&l2_irq) < 0) {
+		printk(KERN_ERR "Cannot install L2 cache error handler\n");
+	} else {
+		/* Enable all error interrupts */
+		mtspr(SPRN_L2ERRINTEN, 0x1C);
+	}
+#endif
+
+#ifdef CONFIG_MVME7100_ENABLE_DDR_ERRORS
+	if (request_irq(mpc86xx_ddr_irq, mvme7100_ddr_err_handler,
+			IRQF_DISABLED, "DDR Error",
+			(void *)&ddr1_err_regs) < 0) {
+		printk(KERN_ERR "Cannot install DDR error handler\n");
+	} else {
+		/* Enable all error interrupts */
+		writel(swab32(0x0000000D),
+		       ddr1_err_regs + DDR_ERR_INT_EN - DDR_ERR_REGS_OFFSET);
+                writel(swab32(0x0000000D),
+                       ddr2_err_regs + DDR_ERR_INT_EN - DDR_ERR_REGS_OFFSET);
+
+	}
+#endif
+
+#ifdef CONFIG_MVME7100_ENABLE_PCI_ERRORS
+	if (request_irq(pci0_irq, mvme7100_pci0_err_handler,
+			IRQF_SHARED, "PCI 0 Error", (void *)&pci0_err_regs) < 0) {
+		printk(KERN_ERR "Cannot install PCI 0 error handler\n");
+	} else {
+		/* Enable detection of all errors */
+		writel(0, pci0_err_regs + PEX_ERR_DISR - PEX_ERR_REGS_OFFSET);
+		/* Enable all error interrupts */
+		writel(swab32(0x00bfff00),
+		       pci0_err_regs + PEX_ERR_EN - PEX_ERR_REGS_OFFSET);
+	}
+	if (request_irq(pci1_irq, mvme7100_pci1_err_handler,
+			IRQF_SHARED, "PCI 1 Error", (void *)&pci1_err_regs) < 0) {
+		printk(KERN_ERR "Cannot install PCI 1 error handler\n");
+	} else {
+		/* Enable detection of all errors */
+		writel(0, pci1_err_regs + PEX_ERR_DISR - PEX_ERR_REGS_OFFSET);
+		/* Enable all error interrupts */
+		writel(swab32(0x00bfff00),
+		       pci1_err_regs + PEX_ERR_EN - PEX_ERR_REGS_OFFSET);
+	}
+#endif
+}
+
+
+void mvme7100_pcibios_fixup_bus(struct pci_bus *bus)
+{
+	struct pci_dev *bridge;
+	struct pci_controller *hose = (struct pci_controller *)bus->sysdata;
+	struct pci_bus_region region;
+	u32 l;
+
+	fsl_pcibios_fixup_bus(bus);
+	bridge = bus->self;
+	if (!bridge)
+		return;
+
+	if (hose->global_number == 0) {
+		if ((bridge->vendor == PCI_VENDOR_ID_FREESCALE) &&
+	    		(bridge->device == PCI_DEVICE_ID_MPC8641D))
+			bridge->irq = pci0_irq;
+
+		if (!bus->resource[1])
+			return;
+		pcibios_resource_to_bus(bridge, &region, bus->resource[1]);
+		/* Parent bridge of the Tundra TSI148 VME Bridge has 
+		 * to be allocated a lot (1G here) of prefetchable PCI MEM 
+		 * which makes it necessary to adjust default allocations */
+		if (bus->resource[1]->flags & IORESOURCE_MEM) {
+			struct pci_bus *parent;
+			unsigned long offset = 0;
+
+			parent = bus->parent;
+			offset = hose->pci_mem_offset;
+			if ((bridge->vendor == 0x10b5)
+			    && (bridge->device == 0x8525)
+			    && (bridge->devfn == 0) && parent && parent->self
+			    && (parent->self->vendor == 0x1957)
+			    && (parent->self->device == 0x7011)
+			    && (parent->self->devfn == 0)) {
+				region.start = 0x80200000;
+				region.end = 0x8fffffff;
+				bus->resource[1]->start = region.start + offset;
+				bus->resource[1]->end = region.end + offset;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else if ((bridge->vendor == 0x10b5) &&
+				   (bridge->device == 0x8525) &&
+				   (bridge->devfn == 0) && parent &&
+				   parent->self &&
+				   (parent->self->vendor == 0x10b5) &&
+				   (parent->self->device == 0x8525) &&
+				   (parent->self->devfn == 0)) {
+				region.start = 0x80200000;
+				region.end = 0x802fffff;
+				bus->resource[1]->start = region.start + offset;
+				bus->resource[1]->end = region.end + offset;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else if ((bridge->vendor == 0x10b5) &&
+				   (bridge->device == 0x8525) &&
+				   (bridge->devfn == 0x8) && parent &&
+				   parent->self &&
+				   (parent->self->vendor == 0x10b5) &&
+				   (parent->self->device == 0x8525) &&
+				   (parent->self->devfn == 0)) {
+				region.start = 0x80300000;
+				region.end = 0x804fffff;
+				bus->resource[1]->start = region.start + offset;
+				bus->resource[1]->end = region.end + offset;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else if (((bridge->vendor == 0x10b5) || 
+				    (bridge->vendor == 0x10e3)) &&
+				   (bridge->device == 0x8114) &&
+				   (bridge->devfn == 0x0) && parent &&
+				   parent->self &&
+				   (parent->self->vendor == 0x10b5) &&
+				   (parent->self->device == 0x8525) &&
+				   (parent->self->devfn == 0x8)) {
+				region.start = 0x80400000;
+				region.end = 0x804fffff;
+				bus->resource[1]->start = region.start + offset;
+				bus->resource[1]->end = region.end + offset;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else if ((bridge->vendor == 0x10b5) &&
+				   (bridge->device == 0x8525) &&
+				   (bridge->devfn == 0x10) && parent &&
+				   parent->self &&
+				   (parent->self->vendor == 0x10b5) &&
+				   (parent->self->device == 0x8525) &&
+				   (parent->self->devfn == 0x0)) {
+				region.start = 0x80500000;
+				region.end = 0x806fffff;
+				bus->resource[1]->start = region.start + offset;
+				bus->resource[1]->end = region.end + offset;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else if (((bridge->vendor == 0x10b5) || 
+				    (bridge->vendor == 0x10e3)) &&
+				   (bridge->device == 0x8114) &&
+				   (bridge->devfn == 0x0) && parent &&
+				   parent->self &&
+				   (parent->self->vendor == 0x10b5) &&
+				   (parent->self->device == 0x8525) &&
+				   (parent->self->devfn == 0x10)) {
+
+				region.start = 0x80600000;
+				region.end = 0x806fffff;
+				bus->resource[1]->start = region.start + offset;
+				bus->resource[1]->end = region.end + offset;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else if ((bridge->vendor == 0x10b5) &&
+				   (bridge->device == 0x8525) &&
+				   (bridge->devfn == 0x48) && parent &&
+				   parent->self &&
+				   (parent->self->vendor == 0x10b5) &&
+				   (parent->self->device == 0x8525) &&
+				   (parent->self->devfn == 0x0)) {
+				region.start = 0x80700000;
+				region.end = 0x808fffff;
+				bus->resource[1]->start = region.start + offset;
+				bus->resource[1]->end = region.end + offset;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else if (((bridge->vendor == 0x10b5) || 
+				    (bridge->vendor == 0x10e3)) &&
+				   (bridge->device == 0x8114) &&
+				   (bridge->devfn == 0x0) && parent &&
+				   parent->self &&
+				   (parent->self->vendor == 0x10b5) &&
+				   (parent->self->device == 0x8525) &&
+				   (parent->self->devfn == 0x48)) {
+
+				region.start = 0x80800000;
+				region.end = 0x808fffff;
+				bus->resource[1]->start = region.start + offset;
+				bus->resource[1]->end = region.end + offset;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else if ((bridge->vendor == 0x10b5) &&
+				   (bridge->device == 0x8525) &&
+				   (bridge->devfn == 0x50) && parent &&
+				   parent->self &&
+				   (parent->self->vendor == 0x10b5) &&
+				   (parent->self->device == 0x8525) &&
+				   (parent->self->devfn == 0x0)) {
+				region.start = 0x80900000;
+				region.end = 0x80afffff;
+				bus->resource[1]->start = region.start + offset;
+				bus->resource[1]->end = region.end + offset;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else if ((bridge->vendor == 0x10b5) &&
+				   ((bridge->device == 0x8111) ||
+				    (bridge->device == 0x8112)) &&
+				   (bridge->devfn == 0x0) && parent &&
+				   parent->self &&
+				   (parent->self->vendor == 0x10b5) &&
+				   (parent->self->device == 0x8525) &&
+				   (parent->self->devfn == 0x50)) {
+				region.start = 0x80a00000;
+				region.end = 0x80afffff;
+				bus->resource[1]->start = region.start + offset;
+				bus->resource[1]->end = region.end + offset;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else {
+				pci_read_config_dword(bridge, PCI_MEMORY_BASE,
+						      &l);
+			}
+		} else {
+			l = 0x0000fff0;
+			printk(KERN_DEBUG "MEM window: disabled.\n");
+		}
+		pci_write_config_dword(bridge, PCI_MEMORY_BASE, l);
+
+		if (!bus->resource[2])
+			return;
+
+		pcibios_resource_to_bus(bridge, &region, bus->resource[2]);
+		{
+			struct pci_bus *parent;
+			unsigned long offset = 0;
+
+			parent = bus->parent;
+			offset = hose->pci_mem_offset;
+
+			/* Clear out the upper 32 bits of PREF limit.
+			   If PCI_PREF_BASE_UPPER32 was non-zero, this 
+			   temporarily disables PREF range, which is ok. */
+			pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32,
+					       0);
+
+			if ((bridge->vendor == 0x10b5) &&
+			    (bridge->device == 0x8525) &&
+			    (bridge->devfn == 0) && parent && parent->self &&
+			    (parent->self->vendor == 0x1957) &&
+			    (parent->self->device == 0x7011) &&
+			    (parent->self->devfn == 0)) {
+				region.start = 0x90000000;
+				region.end = 0xcfffffff;
+				bus->resource[2]->start = region.start + offset;
+				bus->resource[2]->end = region.end + offset;
+				bus->resource[2]->flags =
+				    IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else if ((bridge->vendor == 0x10b5) &&
+				   (bridge->device == 0x8525) &&
+				   (bridge->devfn == 0x8) && parent &&
+				   parent->self &&
+				   (parent->self->vendor == 0x10b5) &&
+				   (parent->self->device == 0x8525) &&
+				   (parent->self->devfn == 0)) {
+				region.start = 0x90000000;
+				region.end = 0xcfffffff;
+				bus->resource[2]->start = region.start + offset;
+				bus->resource[2]->end = region.end + offset;
+				bus->resource[2]->flags =
+				    IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else if (((bridge->vendor == 0x10b5) ||
+				    (bridge->vendor == 0x10e3)) &&
+				   (bridge->device == 0x8114) &&
+				   (bridge->devfn == 0x0) && parent &&
+				   parent->self &&
+				   (parent->self->vendor == 0x10b5) &&
+				   (parent->self->device == 0x8525) &&
+				   (parent->self->devfn == 0x8)) {
+
+				region.start = 0x90000000;
+				region.end = 0xcfffffff;
+				bus->resource[2]->start = region.start + offset;
+				bus->resource[2]->end = region.end + offset;
+				bus->resource[2]->flags =
+				    IORESOURCE_MEM | IORESOURCE_PREFETCH;
+
+				l = (region.start >> 16) & 0xfff0;
+				l |= region.end & 0xfff00000;
+			} else
+				pci_read_config_dword(bridge,
+						      PCI_PREF_MEMORY_BASE, &l);
+		}
+		pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l);
+
+		/* Clear out the upper 32 bits of PREF base. */
+		pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, 0);
+
+		pci_write_config_word(bridge, PCI_BRIDGE_CONTROL,
+				      bus->bridge_ctl);
+	}
+
+	if (hose->global_number == 1) {
+		if ((bridge->vendor == PCI_VENDOR_ID_FREESCALE) &&
+	    		(bridge->device == PCI_DEVICE_ID_MPC8641D))
+			bridge->irq = pci1_irq;
+	}
+}
+
+define_machine(mvme7100)
+{
+	.name = "MVME7100",
+	.probe = mvme7100_probe,
+	.setup_arch = mvme7100_setup_arch,
+	.init_IRQ = mvme7100_init_irq,
+	.show_cpuinfo = mvme7100_show_cpuinfo,
+	.pcibios_fixup = mvme7100_pcibios_fixup,
+	.pcibios_fixup_bus = mvme7100_pcibios_fixup_bus,
+	.get_irq = mpic_get_irq,
+	.restart = mvme7100_restart,
+	.time_init = mpc86xx_time_init,
+	.calibrate_decr = generic_calibrate_decr,
+	.progress = udbg_progress,
+};
+
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/mvme7100.h linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/mvme7100.h
--- linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/mvme7100.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/mvme7100.h	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,158 @@
+/*
+ * MVME7100 board definitions
+ *
+ * Author: Ajit Prem <ajit.prem@emerson.com>
+ *
+ * Copyright 2008 Emerson Network Power Embedded Computing
+ *
+ * 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.
+ *
+ */
+
+#ifndef __MVME7100_H__
+#define __MVME7100_H__
+
+#include <linux/init.h>
+
+#define MPC86XX_RSTCR_OFFSET	(0xe00b0)	/* Reset Control Register */
+
+
+/* Flash */
+#define MVME7100_FLASH_BASE	0xf8000000
+#define MVME7100_FLASH_SIZE	0x08000000
+
+
+/* System Control and Status Registers */
+#define MVME7100_SYSTEM_STATUS_REG		0xF2000000
+#define MVME7100_SYSTEM_CONTROL_REG		0xF2000001
+#define MVME7100_STATUS_INDICATOR_REG		0xF2000002
+#define MVME7100_NOR_FLASH_CTRL_STAT_REG	0xF2000003
+#define MVME7100_INTERRUPT_REG_1		0xF2000004
+#define MVME7100_INTERRUPT_REG_2		0xF2000005
+#define MVME7100_PRESENCE_DETECT_REG		0xF2000006
+#define MVME7100_NAND_FLASH1_CONTROL_REG	0xF2000010
+#define MVME7100_NAND_FLASH1_SELECT_REG		0xF2000011
+#define MVME7100_NAND_FLASH1_PRESENCE_REG	0xF2000014
+#define MVME7100_NAND_FLASH1_STATUS_REG		0xF2000015
+#define MVME7100_NAND_FLASH1_DATA_REG		0xF2030000
+#define MVME7100_NAND_FLASH2_CONTROL_REG	0xF2000018
+#define MVME7100_NAND_FLASH2_SELECT_REG		0xF2000019
+#define MVME7100_NAND_FLASH2_PRESENCE_REG	0xF200001C
+#define MVME7100_NAND_FLASH2_STATUS_REG		0xF200001D
+#define MVME7100_NAND_FLASH2_DATA_REG		0xF2031000
+#define MVME7100_WATCHDOG_TIMER_LOAD_REG	0xF2000020
+#define MVME7100_WATCHDOG_CONTROL_REG		0xF2000024
+#define MVME7100_WATCHDOG_TIMER_RESOLUTION_REG	0xF2000025
+#define MVME7100_WATCHDOG_TIMER_COUNT_REG	0xF2000026
+#define MVME7100_PLD_REVISION_REG		0xF2000030
+#define MVME7100_PLD_DATE_CODE_REG		0xF2000034
+#define MVME7100_TEST_1_REG			0xF2000038
+#define MVME7100_TEST_2_REG			0xF200003C
+
+/* Register offsets */
+#define MVME7100_SYSTEM_STATUS_REG_OFFSET		0x00000000
+#define MVME7100_SYSTEM_CONTROL_REG_OFFSET		0x00000001
+#define MVME7100_STATUS_INDICATOR_REG_OFFSET		0x00000002
+#define MVME7100_NOR_FLASH_CTRL_STAT_REG_OFFSET		0x00000003
+#define MVME7100_INTERRUPT_REG_1_OFFSET			0x00000004
+#define MVME7100_INTERRUPT_REG_2_OFFSET			0x00000005
+#define MVME7100_PRESENCE_DETECT_REG_OFFSET		0x00000006
+#define MVME7100_NAND_FLASH1_CTRL_REG_OFFSET		0x00000010
+#define MVME7100_NAND_FLASH1_SELECT_REG_OFFSET		0x00000011
+#define MVME7100_NAND_FLASH1_PRESENCE_REG_OFFSET	0x00000014
+#define MVME7100_NAND_FLASH1_STATUS_REG_OFFSET		0x00000015
+#define MVME7100_NAND_FLASH2_CTRL_REG_OFFSET		0x00000018
+#define MVME7100_NAND_FLASH2_SELECT_REG_OFFSET		0x00000019
+#define MVME7100_NAND_FLASH2_PRESENCE_REG_OFFSET	0x0000001C
+#define MVME7100_NAND_FLASH2_STATUS_REG_OFFSET		0x0000001D
+#define MVME7100_WATCHDOG_TIMER_LOAD_REG_OFFSET		0x00000020
+#define MVME7100_WATCHDOG_CONTROL_REG_OFFSET		0x00000024
+#define MVME7100_WATCHDOG_TIMER_RESOLUTION_REG_OFFSET	0x00000025
+#define MVME7100_WATCHDOG_TIMER_COUNT_REG_OFFSET	0x00000026
+#define MVME7100_PLD_REVISION_REG_OFFSET		0x00000030
+#define MVME7100_PLD_DATE_CODE_REG_OFFSET		0x00000034
+#define MVME7100_TEST_1_REG_OFFSET			0x00000038
+#define MVME7100_TEST_2_REG_OFFSET			0x0000003C
+
+/* System Status Register */
+#define MVME7100_STATE_SW8		0x80
+#define MVME7100_STATE_SW7		0x40
+#define MVME7100_STATE_SW6		0x20
+#define MVME7100_STATE_SW5		0x10
+#define MVME7100_SAFE_START		0x08
+#define MVME7100_PEX8525_ERROR		0x04
+#define MVME7100_BOARD_TYPE_MASK	0x03
+#define MVME7100_BOARD_TYPE_PRPMC	0x01
+#define MVME7100_BOARD_TYPE_VME		0x00
+
+/* System Control Register */
+#define MVME7100_BOARD_RESET		0xA0
+#define MVME7100_EEPROM_WP		0x02
+
+/* Status Indicator Register */
+#define MVME7100_USR1_RED_LED		0x01
+#define MVME7100_USR1_YELLOW_LED	0x02
+#define MVME7100_USR2_LED		0x04
+#define MVME7100_USR3_LED		0x08
+
+/* NOR Flash Control/Status Register */
+#define MVME7100_NOR_FLASH_MAP_SELECT	0x10
+#define MVME7100_NOR_FLASH_WP_SW	0x08
+#define MVME7100_NOR_FLASH_WP_HW	0x04
+#define MVME7100_NOR_FLASH_BLK_SEL	0x02
+#define MVME7100_NOR_FLASH_RDY		0x01
+
+/* Interrupt Register 1 */
+#define MVME7100_TSEC4_PHY_INTERRUPT	0x08
+#define MVME7100_TSEC3_PHY_INTERRUPT	0x04
+#define MVME7100_TSEC2_PHY_INTERRUPT	0x02
+#define MVME7100_TSEC1_PHY_INTERRUPT	0x01
+
+/* Interrupt Register 2 */
+#define MVME7100_RTC_MASK		0x40
+#define MVME7100_TEMP_MASK		0x20
+#define MVME7100_ABORT_MASK		0x10
+#define MVME7100_RTC_STATUS		0x04
+#define MVME7100_TEMP_STATUS		0x02
+#define MVME7100_ABORT_STATUS		0x01
+
+/* Presence Detect Register */
+#define MVME7100_ERDY2			0x20
+#define MVME7100_ERDY1			0x10
+#define MVME7100_XMCSPAN_PRESENT	0x04
+#define MVME7100_PMC2_PRESENT		0x02
+#define MVME7100_PMC1_PRESENT		0x01
+
+/* NAND Flash Chip Control Register */
+#define MVME7100_NAND_FLASH_CLE		0x80
+#define MVME7100_NAND_FLASH_ALE		0x40
+#define MVME7100_NAND_FLASH_WP		0x20
+
+/* NAND Flash Chip Select Register */
+#define MVME7100_NAND_FLASH_CE1		0x80
+#define MVME7100_NAND_FLASH_CE2		0x40
+#define MVME7100_NAND_FLASH_CE3		0x20
+#define MVME7100_NAND_FLASH_CE4		0x10
+
+/* NAND Flash Chip Presence Register */
+#define MVME7100_NAND_FLASH_CP		0x80
+
+/* NAND Flash Chip Status Register */
+#define MVME7100_NAND_FLASH_RB1		0x80
+#define MVME7100_NAND_FLASH_RB2		0x40
+#define MVME7100_NAND_FLASH_RB3		0x20
+#define MVME7100_NAND_FLASH_RB4		0x10
+
+#define MVME7100_BASE_BAUD		1843200
+#define QUART_BASE_BAUD			(MVME7100_BASE_BAUD / 16)
+#define MVME7100_UART_SIZE		0x8
+
+#define MVME7100_SERIAL_1	0xF2011000U
+#define MVME7100_SERIAL_2	0xF2012000U
+#define MVME7100_SERIAL_3	0xF2013000U
+#define MVME7100_SERIAL_4	0xF2014000U
+
+#endif	/* __MVME7100_H__ */
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/mvme7100_timer.c linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/mvme7100_timer.c
--- linux-2.6.29.6.orig/arch/powerpc/platforms/86xx/mvme7100_timer.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/platforms/86xx/mvme7100_timer.c	2009-07-21 11:28:17.000000000 -0700
@@ -0,0 +1,396 @@
+/*
+ * arch/ppc/platforms/86xx/mvme7100_timer.c
+ *
+ * MVME7100 Tick Timers Support
+ *
+ * Author: Ajit Prem <ajit.prem@emerson.com>
+ *
+ * Copyright 2007 Motorola Inc.
+ * Copyright 2008 Emerson Network Power Embedded Computing Inc.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/proc_fs.h>
+
+#include <asm/io.h>
+#include <asm/mpc86xx.h>
+#include "mvme7100.h"
+#include <asm/mvme7100_timer.h>
+
+#define MVME7100_TICK_TIMER_BASE                0xF2020000
+#define MVME7100_TICK_TIMER_BLOCK_SIZE          0x4C
+
+#define MVME7100_TICK_TIMER_PRESCALER_REG_OFFSET        0x0
+#define MVME7100_TICK_TIMER_CONTROL_REG_OFFSET          0x10
+#define MVME7100_TICK_TIMER_COMPARE_REG_OFFSET          0x14
+#define MVME7100_TICK_TIMER_COUNTER_REG_OFFSET          0x18
+
+#define MVME7100_TICK_TIMER_ENC                 0x00000001
+#define MVME7100_TICK_TIMER_COC                 0x00000002
+#define MVME7100_TICK_TIMER_COVF                0x00000004
+#define MVME7100_TICK_TIMER_OVF                 0x000000F0
+#define MVME7100_TICK_TIMER_ENINT               0x00000100
+#define MVME7100_TICK_TIMER_CINT                0x00000200
+#define MVME7100_TICK_TIMER_INTS                0x00000400
+
+#define	MIN_MICROSECONDS	10000
+#define MAX_TICKS		0xFFFFFFFF
+
+struct mvme7100_timer_t {
+	mvme7100_timer_f func;
+	void *func_data;
+	int started;
+	int periodic;
+	ulong period;
+	ulong ticks;
+};
+
+#define ALL_MSG "mvme7100_timer: "
+
+#ifdef MVME7100_TIMER_DEBUG
+int mvme7100_timer_debug = MVME7100_TIMER_DEBUG;
+MODULE_PARM(mvme7100_timer_debug, "i");
+#define DEBUG(n, fmt, args...) if (mvme7100_timer_debug>(n)) printk(KERN_INFO ALL_MSG fmt, ## args)
+static const char *version = "mvme7100_timer.c 1.0.0 (Ajit Prem)";
+#else
+#define DEBUG(n, fmt, args...)
+#endif
+
+extern int mvme7100_timer_irq;
+
+static struct mvme7100_timer_t mvme7100_timer[4];
+static void __iomem *mvme7100_timer_base;
+static u32 clk_out = 1;		/* Ticks per microsecond */
+static spinlock_t mvme7100_timer_lock = SPIN_LOCK_UNLOCKED;
+
+static irqreturn_t mvme7100_timer_int_handler(int irq, void *data)
+{
+	struct mvme7100_timer_t *info = data;
+	mvme7100_timer_f func;
+	void *func_data;
+	int timer_number;
+	u32 ctrl_reg;
+
+	if (data != (void *)&mvme7100_timer[0])
+		return IRQ_NONE;
+
+	for (timer_number = 0; timer_number <= 3; timer_number++) {
+		if (swab32(readl(mvme7100_timer_base +
+			 (timer_number + 1) *
+			 MVME7100_TICK_TIMER_CONTROL_REG_OFFSET)) &
+		   	 MVME7100_TICK_TIMER_INTS) {
+			info = &mvme7100_timer[timer_number];
+			func_data = info->func_data;
+			func = info->func;
+
+			if (!info->periodic) {
+				mvme7100_timer_stop(timer_number);
+			} else {
+				ctrl_reg = swab32(readl(mvme7100_timer_base +
+					((timer_number + 1) *
+					 MVME7100_TICK_TIMER_CONTROL_REG_OFFSET)));
+				ctrl_reg &= ~MVME7100_TICK_TIMER_ENC;
+				ctrl_reg =
+				    MVME7100_TICK_TIMER_COVF |
+				    MVME7100_TICK_TIMER_CINT;
+				writel(swab32(ctrl_reg),
+				       mvme7100_timer_base +
+				       ((timer_number + 1) *
+					MVME7100_TICK_TIMER_CONTROL_REG_OFFSET));
+				writel(0,
+				       mvme7100_timer_base +
+				       ((timer_number + 1) *
+					MVME7100_TICK_TIMER_CONTROL_REG_OFFSET)
+				       +
+				       (MVME7100_TICK_TIMER_COUNTER_REG_OFFSET -
+					MVME7100_TICK_TIMER_CONTROL_REG_OFFSET));
+				DEBUG(1,
+				      ("Timer %d Counter 0x%x Compare 0x%x\n",
+				       timer_number,
+				       swab32(readl
+					      (mvme7100_timer_base +
+					       ((timer_number + 1) *
+						MVME7100_TICK_TIMER_CONTROL_REG_OFFSET)
+					       +
+					       (MVME7100_TICK_TIMER_COUNTER_REG_OFFSET
+						-
+						MVME7100_TICK_TIMER_CONTROL_REG_OFFSET))),
+				       swab32(readl
+					      (mvme7100_timer_base +
+					       ((timer_number + 1) *
+						MVME7100_TICK_TIMER_CONTROL_REG_OFFSET)
+					       +
+					       (MVME7100_TICK_TIMER_COMPARE_REG_OFFSET
+						-
+						MVME7100_TICK_TIMER_CONTROL_REG_OFFSET)))));
+				writel(swab32
+				       (MVME7100_TICK_TIMER_ENC |
+					MVME7100_TICK_TIMER_COC |
+					MVME7100_TICK_TIMER_ENINT),
+				       mvme7100_timer_base + 
+					((timer_number + 1) *
+					MVME7100_TICK_TIMER_CONTROL_REG_OFFSET));
+			}
+			if (func) 
+				func(func_data);
+		}
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* 
+ * Stop the timer
+ */
+EXPORT_SYMBOL(mvme7100_timer_stop);
+int mvme7100_timer_stop(int timer_number)
+{
+	u32 reset_value;
+	unsigned long flags;
+
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+
+	spin_lock_irqsave(&mvme7100_timer_lock, flags);
+	reset_value = swab32(readl(mvme7100_timer_base +
+				   ((timer_number + 1) *
+				    MVME7100_TICK_TIMER_CONTROL_REG_OFFSET)));
+	reset_value &= ~MVME7100_TICK_TIMER_ENC;
+	reset_value &= ~MVME7100_TICK_TIMER_ENINT;
+	reset_value = MVME7100_TICK_TIMER_COVF | MVME7100_TICK_TIMER_CINT;
+	writel(swab32(reset_value),
+	       mvme7100_timer_base +
+	       ((timer_number + 1) * MVME7100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0, mvme7100_timer_base +
+	       ((timer_number + 1) * MVME7100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME7100_TICK_TIMER_COUNTER_REG_OFFSET -
+		MVME7100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0xffffffff, mvme7100_timer_base +
+	       ((timer_number + 1) * MVME7100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME7100_TICK_TIMER_COMPARE_REG_OFFSET -
+		MVME7100_TICK_TIMER_CONTROL_REG_OFFSET));
+	mvme7100_timer[timer_number].func = NULL;
+	mvme7100_timer[timer_number].func_data = NULL;
+	mvme7100_timer[timer_number].started = 0;
+	mvme7100_timer[timer_number].periodic = 0;
+	mvme7100_timer[timer_number].period = 0;
+	mvme7100_timer[timer_number].ticks = 0xFFFFFFFF;
+	spin_unlock_irqrestore(&mvme7100_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Start the timer
+ */
+EXPORT_SYMBOL(mvme7100_timer_start);
+int mvme7100_timer_start(int timer_number, unsigned long microseconds,
+			 mvme7100_timer_f func, void *func_data, int periodic)
+{
+	int res = 0;
+	unsigned long flags;
+	unsigned long ticks;
+
+	printk(KERN_INFO
+	       "mvme7100_timer: start_timer: num %d microseconds 0x%lx periodic %d\n",
+	       timer_number, microseconds, periodic);
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+	if ((microseconds < MIN_MICROSECONDS) ||
+	    (microseconds > MAX_TICKS / clk_out))
+		return -EINVAL;
+	if (func == NULL)
+		return -EINVAL;
+	if (mvme7100_timer[timer_number].started == 1)
+		return -EBUSY;
+	if ((res = mvme7100_timer_stop(timer_number)) < 0)
+		return res;
+	ticks = microseconds * clk_out;
+	spin_lock_irqsave(&mvme7100_timer_lock, flags);
+	mvme7100_timer[timer_number].started = 1;
+	mvme7100_timer[timer_number].func = func;
+	mvme7100_timer[timer_number].func_data = func_data;
+	mvme7100_timer[timer_number].periodic = periodic;
+	mvme7100_timer[timer_number].period = microseconds;
+	mvme7100_timer[timer_number].ticks = ticks;
+	writel(swab32(ticks), mvme7100_timer_base +
+	       ((timer_number + 1) * MVME7100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME7100_TICK_TIMER_COMPARE_REG_OFFSET -
+		MVME7100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(0, mvme7100_timer_base +
+	       ((timer_number + 1) * MVME7100_TICK_TIMER_CONTROL_REG_OFFSET) +
+	       (MVME7100_TICK_TIMER_COUNTER_REG_OFFSET -
+		MVME7100_TICK_TIMER_CONTROL_REG_OFFSET));
+	writel(swab32(MVME7100_TICK_TIMER_ENC | MVME7100_TICK_TIMER_COC |
+		      MVME7100_TICK_TIMER_ENINT),
+	       mvme7100_timer_base +
+	       ((timer_number + 1) * MVME7100_TICK_TIMER_CONTROL_REG_OFFSET));
+	spin_unlock_irqrestore(&mvme7100_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Get the timer resolution, in microseconds/tick
+ */
+EXPORT_SYMBOL(mvme7100_timer_get_resolution);
+unsigned long mvme7100_timer_get_resolution(void)
+{
+	u32 prescaler_adjust;
+
+	/* 
+	 * Prescaler_adjust = 256 - CLKIN/CLKOUT
+	 * CLKIN = 25 MHz
+	 */
+
+	prescaler_adjust = readl(mvme7100_timer_base +
+				 MVME7100_TICK_TIMER_PRESCALER_REG_OFFSET);
+	return (25 / (256 - prescaler_adjust));
+}
+
+/* 
+ * Set the timer resolution, in ticks/microsecond
+ */
+EXPORT_SYMBOL(mvme7100_timer_set_resolution);
+int mvme7100_timer_set_resolution(unsigned long ticks)
+{
+	u32 prescaler_adjust;
+	int i;
+	unsigned long flags;
+
+	/* 
+	 * Prescaler_adjust = 256 - CLKIN/CLKOUT
+	 * CLKIN = 25 MHz
+	 */
+
+	if ((ticks < MIN_TICKS_PER_MICROSECOND) ||
+	    (ticks > MAX_TICKS_PER_MICROSECOND))
+		return -EINVAL;
+
+	clk_out = ticks;
+	prescaler_adjust = 256 - (25 / clk_out);
+
+	spin_lock_irqsave(&mvme7100_timer_lock, flags);
+	for (i = 0; i <= 3; i++) {
+		if (mvme7100_timer[i].started == 1) {
+			spin_unlock_irqrestore(&mvme7100_timer_lock, flags);
+			return -EBUSY;
+		}
+	}
+
+	writel(prescaler_adjust, mvme7100_timer_base +
+	       MVME7100_TICK_TIMER_PRESCALER_REG_OFFSET);
+	spin_unlock_irqrestore(&mvme7100_timer_lock, flags);
+
+	return 0;
+}
+
+/* 
+ * Get the timer value, in ticks
+ */
+EXPORT_SYMBOL(mvme7100_timer_get_ticks);
+unsigned long mvme7100_timer_get_ticks(int timer_number)
+{
+	if ((timer_number < 0) || (timer_number > 3))
+		return -EINVAL;
+
+	return swab32(readl(mvme7100_timer_base +
+			    ((timer_number +
+			      1) * MVME7100_TICK_TIMER_CONTROL_REG_OFFSET) +
+			    (MVME7100_TICK_TIMER_COUNTER_REG_OFFSET -
+			     MVME7100_TICK_TIMER_CONTROL_REG_OFFSET)));
+}
+
+#ifdef CONFIG_PROC_FS
+
+static int
+mvme7100_timer_proc_read(char *buf, char **start, off_t off, int len, int *eof,
+			 void *data)
+{
+	int i;
+
+	len = 0;
+	len +=
+	    sprintf(buf + len,
+		    "\nTimer     Active  Periodic  Period(ticks)   Period(microseconds)\n");
+	len +=
+	    sprintf(buf + len,
+		    "_____     ______  ________  _____________   ____________________\n");
+	for (i = 0; i <= 3; i++) {
+		len +=
+		    sprintf(buf + len,
+			    "#%d        %c       %c         0x%08lx      %ld\n",
+			    i + 1,
+			    ((mvme7100_timer[i].started == 1) ? 'y' : 'n'),
+			    ((mvme7100_timer[i].periodic == 1) ? 'y' : 'n'),
+			    ((mvme7100_timer[i].periodic ==
+			      1) ? mvme7100_timer[i].ticks : 0),
+			    ((mvme7100_timer[i].periodic ==
+			      1) ? mvme7100_timer[i].period : 0));
+	}
+	return len;
+}
+
+#endif				/* CONFIG_PROC_FS */
+
+static __init int mvme7100_timer_init(void)
+{
+	int res = 0;
+	int i;
+
+	printk(KERN_INFO "mvme7100-timer: MVME7100 Tick Timers\n");
+
+	mvme7100_timer_base = ioremap(MVME7100_TICK_TIMER_BASE,
+				     MVME7100_TICK_TIMER_BLOCK_SIZE);
+	if (mvme7100_timer_base == NULL)
+		return -ENOMEM;
+
+	for (i = 0; i <= 3; i++) {
+		mvme7100_timer[i].func = NULL;
+		mvme7100_timer[i].func_data = NULL;
+		mvme7100_timer[i].started = 0;
+		mvme7100_timer[i].periodic = 0;
+		mvme7100_timer[i].period = 0;
+		mvme7100_timer[i].ticks = 0;
+	}
+	res = request_irq(mvme7100_timer_irq, mvme7100_timer_int_handler,
+			  IRQF_SHARED,
+			  "MVME7100 Tick Timers", &mvme7100_timer[0]);
+	if (res < 0) {
+		printk(KERN_ERR "MVME7100 Timer: Can't allocate IRQ %d.\n",
+		       mvme7100_timer_irq);
+		return res;
+	}
+#ifdef CONFIG_PROC_FS
+	create_proc_read_entry("mvme7100_timers", 0, NULL,
+			       mvme7100_timer_proc_read, NULL);
+#endif
+	return 0;
+}
+
+static __exit void mvme7100_timer_exit(void)
+{
+	int timer_number;
+
+	for (timer_number = 0; timer_number <= 3; timer_number++) {
+		mvme7100_timer_stop(timer_number);
+	}
+	free_irq(mvme7100_timer_irq, &mvme7100_timer[0]);
+	iounmap(mvme7100_timer_base);
+}
+
+MODULE_LICENSE("GPL");
+
+MODULE_AUTHOR("Ajit Prem <ajit.prem@emerson.com>");
+MODULE_DESCRIPTION("MVME7100 Tick Timer driver");
+
+module_init(mvme7100_timer_init);
+module_exit(mvme7100_timer_exit);
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/sysdev/fsl_pci.c linux-2.6.29.6.mod/arch/powerpc/sysdev/fsl_pci.c
--- linux-2.6.29.6.orig/arch/powerpc/sysdev/fsl_pci.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/sysdev/fsl_pci.c	2009-07-24 11:56:49.000000000 -0700
@@ -19,6 +19,8 @@
 #include <linux/string.h>
 #include <linux/init.h>
 #include <linux/bootmem.h>
+#include <linux/lmb.h>
+#include <linux/log2.h>
 
 #include <asm/io.h>
 #include <asm/prom.h>
@@ -28,6 +30,155 @@
 #include <sysdev/fsl_pci.h>
 
 #if defined(CONFIG_PPC_85xx) || defined(CONFIG_PPC_86xx)
+#if 1
+void __init setup_pci_atmu(struct pci_controller *hose, struct resource *rsrc)
+{
+        struct ccsr_pci __iomem *pci;
+        u32 flags = 0x80044000; /* enable & mem R/W */
+        u64 mem, sz, paddr_hi = 0;
+        u64 paddr_lo = ULLONG_MAX;
+        u32 pcicsrbar = 0, pcicsrbar_sz;
+        u32 piwar = PIWAR_EN | PIWAR_PF | PIWAR_TGI_LOCAL |
+                        PIWAR_READ_SNOOP | PIWAR_WRITE_SNOOP;
+        int i, mem_log, win_idx = 2;
+
+        pr_debug("PCI memory map start 0x%016llx, size 0x%016llx\n",
+                    (u64)rsrc->start, (u64)rsrc->end - (u64)rsrc->start + 1);
+        pci = ioremap(rsrc->start, rsrc->end - rsrc->start + 1);
+
+        /* Disable all windows (except powar0 since its ignored) */
+        for(i = 1; i < 5; i++)
+                out_be32(&pci->pow[i].powar, 0);
+        for(i = 0; i < 3; i++)
+                out_be32(&pci->piw[i].piwar, 0);
+
+        /* Setup outbound MEM window */
+        for(i = 0; i < 3; i++)
+                if (hose->mem_resources[i].flags & IORESOURCE_MEM){
+                        resource_size_t pci_addr_start =
+                                 hose->mem_resources[i].start -
+                                 hose->pci_mem_offset;
+                        pr_debug("PCI MEM resource start 0x%016llx, size 0x%016llx.\n",
+                                (u64)hose->mem_resources[i].start,
+                                (u64)hose->mem_resources[i].end
+                                  - (u64)hose->mem_resources[i].start + 1);
+			if (hose->mem_resources[i].flags & IORESOURCE_PREFETCH)
+				flags |= 0x10000000; /* enable relaxed ordering */
+                        out_be32(&pci->pow[i+1].potar, (pci_addr_start >> 12));
+                        out_be32(&pci->pow[i+1].potear, 0);
+                        out_be32(&pci->pow[i+1].powbar,
+                                (hose->mem_resources[i].start >> 12));
+                        /* Enable, Mem R/W */
+                        out_be32(&pci->pow[i+1].powar, flags
+                                | (__ilog2(hose->mem_resources[i].end
+                                - hose->mem_resources[i].start + 1) - 1));
+                }
+
+        /* Setup outbound IO window */
+        if (hose->io_resource.flags & IORESOURCE_IO){
+                pr_debug("PCI IO resource start 0x%016llx, size 0x%016llx, "
+                         "phy base 0x%016llx.\n",
+                        (u64)hose->io_resource.start,
+                        (u64)hose->io_resource.end - (u64)hose->io_resource.start + 1,
+                        (u64)hose->io_base_phys);
+                out_be32(&pci->pow[i+1].potar, (hose->io_resource.start >> 12));
+                out_be32(&pci->pow[i+1].potear, 0);
+                out_be32(&pci->pow[i+1].powbar, (hose->io_base_phys >> 12));
+                /* Enable, IO R/W */
+                out_be32(&pci->pow[i+1].powar, 0x80088000
+                        | (__ilog2(hose->io_resource.end
+                        - hose->io_resource.start + 1) - 1));
+        }
+
+        /* convert to pci address space */
+        paddr_hi -= hose->pci_mem_offset;
+        paddr_lo -= hose->pci_mem_offset;
+
+        if (paddr_hi == paddr_lo) {
+                pr_err("No outbound window space\n");
+                return ;
+        }
+
+        if (paddr_lo == 0) {
+                pr_err("No space for inbound window\n");
+                return ;
+        }
+
+        /* setup PCSRBAR/PEXCSRBAR */
+        early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, 0xffffffff);
+        early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, &pcicsrbar_sz);
+        pcicsrbar_sz = ~pcicsrbar_sz + 1;
+
+        if (paddr_hi < (0x100000000ull - pcicsrbar_sz) ||
+                (paddr_lo > 0x100000000ull))
+                pcicsrbar = 0x100000000ull - pcicsrbar_sz;
+        else
+                pcicsrbar = (paddr_lo - pcicsrbar_sz) & -pcicsrbar_sz;
+
+        early_write_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_0, pcicsrbar);
+        paddr_lo = min(paddr_lo, (u64)pcicsrbar);
+
+        pr_info("PCICSRBAR @ 0x%x\n", pcicsrbar);
+
+        /* Setup inbound mem window */
+        mem = lmb_end_of_DRAM();
+        sz = min(mem, paddr_lo);
+        mem_log = __ilog2_u64(sz);
+
+        /* PCIe can overmap inbound & outbound since RX & TX are separated */
+        if (early_find_capability(hose, 0, 0, PCI_CAP_ID_EXP)) {
+                /* Size window to exact size if power-of-two or one size up */
+                if ((1ull << mem_log) != mem) {
+                        if ((1ull << mem_log) > mem)
+                                pr_info("Setting PCI inbound window "
+                                        "greater than memory size\n");
+                        mem_log++;
+                }
+
+                piwar |= (mem_log - 1);
+
+                /* Setup inbound memory window */
+                out_be32(&pci->piw[win_idx].pitar,  0x00000000);
+                out_be32(&pci->piw[win_idx].piwbar, 0x00000000);
+                out_be32(&pci->piw[win_idx].piwar,  piwar);
+                win_idx--;
+
+        } else {
+                u64 paddr = 0;
+
+                /* Setup inbound memory window */
+                out_be32(&pci->piw[win_idx].pitar,  paddr >> 12);
+                out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
+                out_be32(&pci->piw[win_idx].piwar,  (piwar | (mem_log - 1)));
+                win_idx--;
+
+                paddr += 1ull << mem_log;
+                sz -= 1ull << mem_log;
+
+                if (sz) {
+                        mem_log = __ilog2_u64(sz);
+                        piwar |= (mem_log - 1);
+
+                        out_be32(&pci->piw[win_idx].pitar,  paddr >> 12);
+                        out_be32(&pci->piw[win_idx].piwbar, paddr >> 12);
+                        out_be32(&pci->piw[win_idx].piwar,  piwar);
+                        win_idx--;
+
+                        paddr += 1ull << mem_log;
+                }
+
+        }
+
+//        /* Setup 2G inbound Memory Window @ 1 */
+//        out_be32(&pci->piw[2].pitar, 0x00000000);
+//        out_be32(&pci->piw[2].piwbar,0x00000000);
+//        out_be32(&pci->piw[2].piwar, PIWAR_2G);
+
+	iounmap(pci);
+}
+
+#else
+
 static int __init setup_one_atmu(struct ccsr_pci __iomem *pci,
 	unsigned int index, const struct resource *res,
 	resource_size_t offset)
@@ -127,6 +278,7 @@
 
 	iounmap(pci);
 }
+#endif
 
 static void __init setup_pci_cmd(struct pci_controller *hose)
 {
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/sysdev/fsl_pci.h linux-2.6.29.6.mod/arch/powerpc/sysdev/fsl_pci.h
--- linux-2.6.29.6.orig/arch/powerpc/sysdev/fsl_pci.h	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/sysdev/fsl_pci.h	2009-07-24 11:55:04.000000000 -0700
@@ -17,6 +17,12 @@
 #define PCIE_LTSSM	0x0404		/* PCIE Link Training and Status */
 #define PCIE_LTSSM_L0	0x16		/* L0 state */
 #define PIWAR_2G	0xa0f5501e	/* Enable, Prefetch, Local Mem, Snoop R/W, 2G */
+#define PIWAR_EN                0x80000000      /* Enable */
+#define PIWAR_PF                0x20000000      /* prefetch */
+#define PIWAR_TGI_LOCAL         0x00f00000      /* target - local memory */
+#define PIWAR_READ_SNOOP        0x00050000
+#define PIWAR_WRITE_SNOOP       0x00005000
+
 
 /* PCI/PCI Express outbound window reg */
 struct pci_outbound_window_regs {
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/sysdev/fsl_soc.c linux-2.6.29.6.mod/arch/powerpc/sysdev/fsl_soc.c
--- linux-2.6.29.6.orig/arch/powerpc/sysdev/fsl_soc.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/sysdev/fsl_soc.c	2009-07-21 11:28:17.000000000 -0700
@@ -541,7 +541,7 @@
 						"register not mapped!\n");
 		}
 	} else
-		printk (KERN_INFO "rstcr compatible register does not exist!\n");
+		printk (KERN_DEBUG "rstcr compatible register does not exist!\n");
 	if (np)
 		of_node_put(np);
 	return 0;
diff -u --new-file --recursive linux-2.6.29.6.orig/arch/powerpc/sysdev/mpic.c linux-2.6.29.6.mod/arch/powerpc/sysdev/mpic.c
--- linux-2.6.29.6.orig/arch/powerpc/sysdev/mpic.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/arch/powerpc/sysdev/mpic.c	2009-07-24 11:54:48.000000000 -0700
@@ -230,14 +230,16 @@
 {
 	unsigned int	isu = src_no >> mpic->isu_shift;
 	unsigned int	idx = src_no & mpic->isu_mask;
+	unsigned int	val;
 
+	val = _mpic_read(mpic->reg_type, &mpic->isus[isu],
+				  reg + (idx * MPIC_INFO(IRQ_STRIDE)));
 #ifdef CONFIG_MPIC_BROKEN_REGREAD
 	if (reg == 0)
-		return mpic->isu_reg0_shadow[idx];
-	else
+		val = (val & (MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY)) |
+			mpic->isu_reg0_shadow[src_no];
 #endif
-		return _mpic_read(mpic->reg_type, &mpic->isus[isu],
-				  reg + (idx * MPIC_INFO(IRQ_STRIDE)));
+	return val;
 }
 
 static inline void _mpic_irq_write(struct mpic *mpic, unsigned int src_no,
@@ -251,7 +253,8 @@
 
 #ifdef CONFIG_MPIC_BROKEN_REGREAD
 	if (reg == 0)
-		mpic->isu_reg0_shadow[idx] = value;
+		mpic->isu_reg0_shadow[src_no] =
+			value & ~(MPIC_VECPRI_MASK | MPIC_VECPRI_ACTIVITY);
 #endif
 }
 
diff -u --new-file --recursive linux-2.6.29.6.orig/CREDITS linux-2.6.29.6.mod/CREDITS
--- linux-2.6.29.6.orig/CREDITS	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/CREDITS	2009-07-21 11:28:18.000000000 -0700
@@ -2818,6 +2818,17 @@
 E: fpotter@cirpack.com
 D: Some PCI kernel support
 
+N: Ajit Prem
+E: ajit.prem@emerson.com
+D: Added support for the MVME4100
+D: Added support for the MVME7100
+D: Added support for the MVME3100
+D: Added support for the CPCI6200
+D: Miscellaneous mods to support the boards above
+S: 2900 South Diablo Way, DW278
+S: Tempe, Arizona  85282
+S: USA
+
 N: Rui Prior
 E: rprior@inescn.pt
 D: ATM device driver for NICStAR based cards
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_devintf.c linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_devintf.c
--- linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_devintf.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_devintf.c	2009-07-21 11:28:18.000000000 -0700
@@ -162,6 +162,8 @@
 	if (rv)
 		return rv;
 
+	ipmi_fasync (-1, file, 0);
+
 	/* FIXME - free the messages in the list. */
 	kfree(priv);
 
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_msghandler.c linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_msghandler.c
--- linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_msghandler.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_msghandler.c	2009-09-02 10:33:25.000000000 -0700
@@ -49,7 +49,6 @@
 
 #define IPMI_DRIVER_VERSION "39.2"
 
-static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
 static int ipmi_init_msghandler(void);
 
 static int initialized;
@@ -285,6 +284,11 @@
 	/* Events that were received with the proper format. */
 	IPMI_STAT_events,
 
+	/* Retransmissions on IPMB that failed. */
+	IPMI_STAT_dropped_rexmit_ipmb_commands,
+
+	/* Retransmissions on LAN that failed. */
+	IPMI_STAT_dropped_rexmit_lan_commands,
 
 	/* This *must* remain last, add new values above this. */
 	IPMI_NUM_STATS
@@ -373,6 +377,14 @@
 	char             event_msg_printed;
 
 	/*
+	 * This will be non-null if someone registers to receive all
+	 * IPMI commands (this is for interface emulation).  There
+	 * may not be any things in the cmd_rcvrs list above when
+	 * this is registered.
+	 */
+	volatile ipmi_user_t all_cmd_rcvr;
+
+	/*
 	 * The event receiver for my BMC, only really used at panic
 	 * shutdown as a place to store this.
 	 */
@@ -445,6 +457,20 @@
 #define ipmi_get_stat(intf, stat) \
 	((unsigned int) atomic_read(&(intf)->stats[IPMI_STAT_ ## stat]))
 
+static int is_lan_addr(struct ipmi_addr *addr)
+{
+	return addr->addr_type == IPMI_LAN_ADDR_TYPE;
+}
+
+static int is_ipmb_addr(struct ipmi_addr *addr)
+{
+	return addr->addr_type == IPMI_IPMB_ADDR_TYPE;
+}
+
+static int is_ipmb_bcast_addr(struct ipmi_addr *addr)
+{
+	return addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE;
+}
 
 static void free_recv_msg_list(struct list_head *q)
 {
@@ -584,7 +610,7 @@
 	}
 }
 
-static int
+int
 ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2)
 {
 	if (addr1->addr_type != addr2->addr_type)
@@ -601,8 +627,7 @@
 		return (smi_addr1->lun == smi_addr2->lun);
 	}
 
-	if ((addr1->addr_type == IPMI_IPMB_ADDR_TYPE)
-	    || (addr1->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) {
+	if (is_ipmb_addr(addr1) || is_ipmb_bcast_addr(addr1)) {
 		struct ipmi_ipmb_addr *ipmb_addr1
 		    = (struct ipmi_ipmb_addr *) addr1;
 		struct ipmi_ipmb_addr *ipmb_addr2
@@ -612,7 +637,7 @@
 			&& (ipmb_addr1->lun == ipmb_addr2->lun));
 	}
 
-	if (addr1->addr_type == IPMI_LAN_ADDR_TYPE) {
+	if (is_lan_addr(addr1)) {
 		struct ipmi_lan_addr *lan_addr1
 			= (struct ipmi_lan_addr *) addr1;
 		struct ipmi_lan_addr *lan_addr2
@@ -627,6 +652,7 @@
 
 	return 1;
 }
+EXPORT_SYMBOL(ipmi_addr_equal);
 
 int ipmi_validate_addr(struct ipmi_addr *addr, int len)
 {
@@ -644,14 +670,13 @@
 	    || (addr->channel < 0))
 		return -EINVAL;
 
-	if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
-	    || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) {
+	if (is_ipmb_addr(addr) || is_ipmb_bcast_addr(addr)) {
 		if (len < sizeof(struct ipmi_ipmb_addr))
 			return -EINVAL;
 		return 0;
 	}
 
-	if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
+	if (is_lan_addr(addr)) {
 		if (len < sizeof(struct ipmi_lan_addr))
 			return -EINVAL;
 		return 0;
@@ -988,6 +1013,8 @@
 	 * synchronize_rcu()) then free everything in that list.
 	 */
 	mutex_lock(&intf->cmd_rcvrs_mutex);
+	if (intf->all_cmd_rcvr == user)
+		intf->all_cmd_rcvr = NULL;
 	list_for_each_entry_rcu(rcvr, &intf->cmd_rcvrs, link) {
 		if (rcvr->user == user) {
 			list_del_rcu(&rcvr->link);
@@ -1230,6 +1257,10 @@
 	rcvr->user = user;
 
 	mutex_lock(&intf->cmd_rcvrs_mutex);
+	if (user->intf->all_cmd_rcvr != NULL) {
+		rv = -EBUSY;
+		goto out_unlock;
+	}
 	/* Make sure the command/netfn is not already registered. */
 	if (!is_cmd_rcvr_exclusive(intf, netfn, cmd, chans)) {
 		rv = -EBUSY;
@@ -1503,8 +1534,7 @@
 			memcpy(&(smi_msg->data[2]), msg->data, msg->data_len);
 		smi_msg->data_size = msg->data_len + 2;
 		ipmi_inc_stat(intf, sent_local_commands);
-	} else if ((addr->addr_type == IPMI_IPMB_ADDR_TYPE)
-		   || (addr->addr_type == IPMI_IPMB_BROADCAST_ADDR_TYPE)) {
+	} else if (is_ipmb_addr(addr) || is_ipmb_bcast_addr(addr)) {
 		struct ipmi_ipmb_addr *ipmb_addr;
 		unsigned char         ipmb_seq;
 		long                  seqid;
@@ -1583,8 +1613,6 @@
 
 			spin_lock_irqsave(&(intf->seq_lock), flags);
 
-			ipmi_inc_stat(intf, sent_ipmb_commands);
-
 			/*
 			 * Create a sequence number with a 1 second
 			 * timeout and 4 retries.
@@ -1606,6 +1634,8 @@
 				goto out_err;
 			}
 
+			ipmi_inc_stat(intf, sent_ipmb_commands);
+
 			/*
 			 * Store the sequence number in the message,
 			 * so that when the send message response
@@ -1635,7 +1665,7 @@
 			 */
 			spin_unlock_irqrestore(&(intf->seq_lock), flags);
 		}
-	} else if (addr->addr_type == IPMI_LAN_ADDR_TYPE) {
+	} else if (is_lan_addr(addr)) {
 		struct ipmi_lan_addr  *lan_addr;
 		unsigned char         ipmb_seq;
 		long                  seqid;
@@ -1696,8 +1726,6 @@
 
 			spin_lock_irqsave(&(intf->seq_lock), flags);
 
-			ipmi_inc_stat(intf, sent_lan_commands);
-
 			/*
 			 * Create a sequence number with a 1 second
 			 * timeout and 4 retries.
@@ -1719,6 +1747,8 @@
 				goto out_err;
 			}
 
+			ipmi_inc_stat(intf, sent_lan_commands);
+
 			/*
 			 * Store the sequence number in the message,
 			 * so that when the send message response
@@ -1937,6 +1967,10 @@
 		       ipmi_get_stat(intf, invalid_events));
 	out += sprintf(out, "events:                      %u\n",
 		       ipmi_get_stat(intf, events));
+	out += sprintf(out, "failed rexmit LAN msgs:      %u\n",
+		       ipmi_get_stat(intf, dropped_rexmit_lan_commands));
+	out += sprintf(out, "failed rexmit IPMB msgs:     %u\n",
+		       ipmi_get_stat(intf, dropped_rexmit_ipmb_commands));
 
 	return (out - ((char *) page));
 }
@@ -2791,6 +2825,7 @@
 	init_waitqueue_head(&intf->waitq);
 	for (i = 0; i < IPMI_NUM_STATS; i++)
 		atomic_set(&intf->stats[i], 0);
+	intf->all_cmd_rcvr = NULL;
 
 	intf->proc_dir = NULL;
 
@@ -2839,6 +2874,7 @@
 		/* Assume a single IPMB channel at zero. */
 		intf->channels[0].medium = IPMI_CHANNEL_MEDIUM_IPMB;
 		intf->channels[0].protocol = IPMI_CHANNEL_PROTOCOL_IPMB;
+		intf->curr_channel = IPMI_MAX_CHANNELS;
 	}
 
 	if (rv == 0)
@@ -3012,12 +3048,15 @@
 	chan = msg->rsp[3] & 0xf;
 
 	rcu_read_lock();
-	rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
-	if (rcvr) {
-		user = rcvr->user;
-		kref_get(&user->refcount);
-	} else
-		user = NULL;
+	user = intf->all_cmd_rcvr;
+	if (!user) {
+		rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
+		if (rcvr) {
+			user = rcvr->user;
+			kref_get(&user->refcount);
+		} else
+			user = NULL;
+	}
 	rcu_read_unlock();
 
 	if (user == NULL) {
@@ -3201,12 +3240,15 @@
 	chan = msg->rsp[3] & 0xf;
 
 	rcu_read_lock();
-	rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
-	if (rcvr) {
-		user = rcvr->user;
-		kref_get(&user->refcount);
-	} else
-		user = NULL;
+	user = intf->all_cmd_rcvr;
+	if (!user) {
+		rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
+		if (rcvr) {
+			user = rcvr->user;
+			kref_get(&user->refcount);
+		} else
+			user = NULL;
+	}
 	rcu_read_unlock();
 
 	if (user == NULL) {
@@ -3267,6 +3309,114 @@
 	return rv;
 }
 
+/*
+ * This routine will handle "Get Message" command responses with
+ * channels that use an OEM Medium. The message format belongs to
+ * the OEM.  See IPMI 2.0 specification, Chapter 6 and
+ * Chapter 22, sections 22.6 and 22.24 for more details.
+ */
+static int handle_oem_get_msg_cmd(ipmi_smi_t          intf,
+				  struct ipmi_smi_msg *msg)
+{
+	struct cmd_rcvr       *rcvr;
+	int                   rv = 0;
+	unsigned char         netfn;
+	unsigned char         cmd;
+	unsigned char         chan;
+	ipmi_user_t           user = NULL;
+	struct ipmi_system_interface_addr *smi_addr;
+	struct ipmi_recv_msg  *recv_msg;
+
+	/*
+	 * We expect the OEM SW to perform error checking
+	 * so we just do some basic sanity checks
+	 */
+	if (msg->rsp_size < 4) {
+		/* Message not big enough, just ignore it. */
+		ipmi_inc_stat(intf, invalid_commands);
+		return 0;
+	}
+
+	if (msg->rsp[2] != 0) {
+		/* An error getting the response, just ignore it. */
+		return 0;
+	}
+
+	/*
+	 * This is an OEM Message so the OEM needs to know how
+	 * handle the message. We do no interpretation.
+	 */
+	netfn = msg->rsp[0] >> 2;
+	cmd = msg->rsp[1];
+	chan = msg->rsp[3] & 0xf;
+
+	rcu_read_lock();
+	rcvr = find_cmd_rcvr(intf, netfn, cmd, chan);
+	if (rcvr) {
+		user = rcvr->user;
+		kref_get(&user->refcount);
+	} else
+		user = NULL;
+	rcu_read_unlock();
+
+	if (user == NULL) {
+		/* We didn't find a user, just give up. */
+		ipmi_inc_stat(intf, unhandled_commands);
+
+		/*
+		 * Don't do anything with these messages, just allow
+		 * them to be freed.
+		 */
+
+		rv = 0;
+	} else {
+		/* Deliver the message to the user. */
+		ipmi_inc_stat(intf, handled_commands);
+
+		recv_msg = ipmi_alloc_recv_msg();
+		if (!recv_msg) {
+			/*
+			 * We couldn't allocate memory for the
+			 * message, so requeue it for handling
+			 * later.
+			 */
+			rv = 1;
+			kref_put(&user->refcount, free_user);
+		} else {
+			/*
+			 * OEM Messages are expected to be delivered via
+			 * the system interface to SMS software.  We might
+			 * need to visit this again depending on OEM
+			 * requirements
+			 */
+			smi_addr = ((struct ipmi_system_interface_addr *)
+				    &(recv_msg->addr));
+			smi_addr->addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+			smi_addr->channel = IPMI_BMC_CHANNEL;
+			smi_addr->lun = msg->rsp[0] & 3;
+
+			recv_msg->user = user;
+			recv_msg->user_msg_data = NULL;
+			recv_msg->recv_type = IPMI_OEM_RECV_TYPE;
+			recv_msg->msg.netfn = msg->rsp[0] >> 2;
+			recv_msg->msg.cmd = msg->rsp[1];
+			recv_msg->msg.data = recv_msg->msg_data;
+
+			/*
+			 * The message starts at byte 4 which follows the
+			 * the Channel Byte in the "GET MESSAGE" command
+			 */
+			recv_msg->msg.data_len = msg->rsp_size - 4;
+			memcpy(recv_msg->msg_data,
+			       &(msg->rsp[4]),
+			       msg->rsp_size - 4);
+			deliver_response(recv_msg);
+		}
+	}
+
+	return rv;
+}
+
 static void copy_event_into_recv_msg(struct ipmi_recv_msg *recv_msg,
 				     struct ipmi_smi_msg  *msg)
 {
@@ -3522,6 +3672,17 @@
 			goto out;
 		}
 
+		/*
+		** We need to make sure the channels have been initialized.
+		** The channel_handler routine will set the "curr_channel"
+		** equal to or greater than IPMI_MAX_CHANNELS when all the
+		** channels for this interface have been initialized.
+		*/
+		if (intf->curr_channel < IPMI_MAX_CHANNELS) {
+			requeue = 0;     /* Just throw the message away */
+			goto out;
+		}
+
 		switch (intf->channels[chan].medium) {
 		case IPMI_CHANNEL_MEDIUM_IPMB:
 			if (msg->rsp[4] & 0x04) {
@@ -3557,11 +3718,20 @@
 			break;
 
 		default:
-			/*
-			 * We don't handle the channel type, so just
-			 * free the message.
-			 */
-			requeue = 0;
+			/* Check for OEM Channels.  Clients had better
+			   register for these commands. */
+			if ((intf->channels[chan].medium
+			     >= IPMI_CHANNEL_MEDIUM_OEM_MIN)
+			    && (intf->channels[chan].medium
+				<= IPMI_CHANNEL_MEDIUM_OEM_MAX)) {
+				requeue = handle_oem_get_msg_cmd(intf, msg);
+			} else {
+				/*
+				 * We don't handle the channel type, so just
+				 * free the message.
+				 */
+				requeue = 0;
+			}
 		}
 
 	} else if ((msg->rsp[0] == ((IPMI_NETFN_APP_REQUEST|1) << 2))
@@ -3733,7 +3903,7 @@
 		list_add_tail(&msg->link, timeouts);
 		if (ent->broadcast)
 			ipmi_inc_stat(intf, timed_out_ipmb_broadcasts);
-		else if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
+		else if (is_lan_addr(&ent->recv_msg->addr))
 			ipmi_inc_stat(intf, timed_out_lan_commands);
 		else
 			ipmi_inc_stat(intf, timed_out_ipmb_commands);
@@ -3741,21 +3911,28 @@
 		struct ipmi_smi_msg *smi_msg;
 		/* More retries, send again. */
 
+		ent->retries_left--;
+		msg = ent->recv_msg;
+
+		if ((msg->msg.netfn == IPMI_NETFN_STORAGE_REQUEST) &&
+			(msg->msg.cmd == 0x22))
+			return;
 		/*
 		 * Start with the max timer, set to normal timer after
 		 * the message is sent.
 		 */
 		ent->timeout = MAX_MSG_TIMEOUT;
-		ent->retries_left--;
-		if (ent->recv_msg->addr.addr_type == IPMI_LAN_ADDR_TYPE)
-			ipmi_inc_stat(intf, retransmitted_lan_commands);
-		else
-			ipmi_inc_stat(intf, retransmitted_ipmb_commands);
-
 		smi_msg = smi_from_recv_msg(intf, ent->recv_msg, slot,
 					    ent->seqid);
-		if (!smi_msg)
+		if (!smi_msg) {
+			if (is_lan_addr(&ent->recv_msg->addr))
+				ipmi_inc_stat(intf,
+					      dropped_rexmit_lan_commands);
+			else
+				ipmi_inc_stat(intf,
+					      dropped_rexmit_ipmb_commands);
 			return;
+		}
 
 		spin_unlock_irqrestore(&intf->seq_lock, *flags);
 
@@ -3767,10 +3944,17 @@
 		 * resent.
 		 */
 		handlers = intf->handlers;
-		if (handlers)
+		if (handlers) {
+			if (is_lan_addr(&ent->recv_msg->addr))
+				ipmi_inc_stat(intf,
+					      retransmitted_lan_commands);
+			else
+				ipmi_inc_stat(intf,
+					      retransmitted_ipmb_commands);
+
 			intf->handlers->sender(intf->send_info,
 					       smi_msg, 0);
-		else
+		} else
 			ipmi_free_smi_msg(smi_msg);
 
 		spin_lock_irqsave(&intf->seq_lock, *flags);
@@ -3934,7 +4118,7 @@
 	kfree(msg);
 }
 
-static struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
+struct ipmi_recv_msg *ipmi_alloc_recv_msg(void)
 {
 	struct ipmi_recv_msg *rv;
 
@@ -3946,6 +4130,7 @@
 	}
 	return rv;
 }
+EXPORT_SYMBOL(ipmi_alloc_recv_msg);
 
 void ipmi_free_recv_msg(struct ipmi_recv_msg *msg)
 {
@@ -3955,6 +4140,60 @@
 }
 EXPORT_SYMBOL(ipmi_free_recv_msg);
 
+int
+ipmi_register_all_cmd_rcvr(ipmi_user_t user)
+{
+	int           rv = -EBUSY;
+
+	mutex_lock(&user->intf->cmd_rcvrs_mutex);
+	if ((user->intf->all_cmd_rcvr == NULL)
+	    && (list_empty(&user->intf->cmd_rcvrs))) {
+		user->intf->all_cmd_rcvr = user;
+		rv = 0;
+	}
+	mutex_unlock(&user->intf->cmd_rcvrs_mutex);
+	return rv;
+}
+EXPORT_SYMBOL(ipmi_register_all_cmd_rcvr);
+
+int
+ipmi_unregister_all_cmd_rcvr(ipmi_user_t user)
+{
+	int           rv = -EINVAL;
+
+	mutex_lock(&user->intf->cmd_rcvrs_mutex);
+	if (user->intf->all_cmd_rcvr == user) {
+		user->intf->all_cmd_rcvr = NULL;
+		rv = 0;
+	}
+	mutex_unlock(&user->intf->cmd_rcvrs_mutex);
+	return rv;
+}
+EXPORT_SYMBOL(ipmi_unregister_all_cmd_rcvr);
+
+int ipmi_request_with_source(ipmi_user_t      user,
+			     struct ipmi_addr *addr,
+			     long             msgid,
+			     struct kernel_ipmi_msg  *msg,
+			     void             *user_msg_data,
+			     int              priority,
+			     unsigned char    source_address,
+			     unsigned char    source_lun)
+{
+	return i_ipmi_request(user,
+			      user->intf,
+			      addr,
+			      msgid,
+			      msg,
+			      user_msg_data,
+			      NULL, NULL,
+			      priority,
+			      source_address,
+			      source_lun,
+			      -1, 0);
+}
+EXPORT_SYMBOL(ipmi_request_with_source);
+
 #ifdef CONFIG_IPMI_PANIC_EVENT
 
 static void dummy_smi_done_handler(struct ipmi_smi_msg *msg)
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_oops_console.c linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_oops_console.c
--- linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_oops_console.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_oops_console.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,256 @@
+/*
+ * ipmi_oops_console.c
+ *
+ * IPMI Oops Console
+ * Logging console message to SEL on oops
+ *
+ * Author: Hiroshi Shimamoto <h-shimamoto@ct.jp.nec.com>
+ *
+ * Copyright (C) 2008 NEC 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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/ipmi.h>
+#include <linux/ipmi_smi.h>
+#include <linux/console.h>
+#include <linux/jiffies.h>
+#include <asm/atomic.h>
+
+#define PFX "IPMI oops_console: "
+
+static ipmi_user_t oops_user;
+static int oops_intf = -1;
+
+static atomic_t oops_counter;
+
+#define SEL_MSGSIZE_TIMESTAMP	(6U)
+#define SEL_MSGSIZE		(13U)
+#define DEF_LIMIT		(100)
+#define TIMESTAMP_INTERVAL	(10 * HZ)
+
+static char oops_msg[SEL_MSGSIZE_TIMESTAMP + SEL_MSGSIZE];
+static char *msg_ptr = oops_msg;
+static unsigned int msg_len;
+static unsigned long msg_jiffies;
+static int msg_count, msg_limit = DEF_LIMIT;
+
+module_param(msg_limit, int, 0644);
+MODULE_PARM_DESC(msg_limit, "Message limit. Default: 100 entries.");
+
+static void oops_smi_msg_done(struct ipmi_smi_msg *msg)
+{
+	atomic_dec(&oops_counter);
+}
+static struct ipmi_smi_msg oops_smi_msg = {
+	.done = oops_smi_msg_done
+};
+
+static void oops_recv_msg_done(struct ipmi_recv_msg *msg)
+{
+	atomic_dec(&oops_counter);
+}
+static struct ipmi_recv_msg oops_recv_msg = {
+	.done = oops_recv_msg_done
+};
+
+static void ipmi_oops_console_log_to_sel(int timestamp)
+{
+	struct ipmi_system_interface_addr si;
+	struct kernel_ipmi_msg msg;
+	unsigned int len;
+	unsigned char data[16];
+	unsigned char my_addr;
+
+	if (!oops_user || !msg_len || msg_count >= msg_limit)
+		return;
+
+	len = min((timestamp ? SEL_MSGSIZE_TIMESTAMP : SEL_MSGSIZE), msg_len);
+
+	si.addr_type = IPMI_SYSTEM_INTERFACE_ADDR_TYPE;
+	si.channel = IPMI_BMC_CHANNEL;
+	si.lun = 0;
+
+	msg.netfn = IPMI_NETFN_STORAGE_REQUEST;
+	msg.cmd = IPMI_ADD_SEL_ENTRY_CMD;
+	msg.data = data;
+	msg.data_len = 16;
+
+	memset(data, 0, sizeof(data));
+	if (timestamp) {
+		len = min(SEL_MSGSIZE_TIMESTAMP, msg_len);
+		data[2] = 0xd1; /* OEM event with timestamp */
+		memcpy(data + 10, msg_ptr, len);
+		msg_jiffies = jiffies; /* save jiffies at timestamp */
+	} else {
+		len = min(SEL_MSGSIZE, msg_len);
+		data[2] = 0xf1; /* OEM event without timestamp */
+		memcpy(data + 3, msg_ptr, len);
+	}
+
+	preempt_disable();
+
+	if (ipmi_get_my_address(oops_user, 0, &my_addr))
+		goto out;
+
+	atomic_set(&oops_counter, 2);
+	if (ipmi_request_supply_msgs(oops_user, (struct ipmi_addr *)&si,
+				     0, &msg, NULL, &oops_smi_msg,
+				     &oops_recv_msg, 1) < 0)
+		goto out;
+	while (atomic_read(&oops_counter) > 0) {
+		ipmi_poll_interface(oops_user);
+		cpu_relax();
+	}
+
+	++msg_count;
+	msg_len -= len;
+	msg_ptr = msg_len ? &oops_msg[len] : oops_msg;
+out:
+	preempt_enable();
+}
+
+static void ipmi_oops_console_sync(void)
+{
+	if (!oops_user || !msg_len || msg_count >= msg_limit)
+		return;
+
+	if (jiffies > (msg_jiffies + TIMESTAMP_INTERVAL)) {
+		if (msg_ptr != oops_msg)
+			ipmi_oops_console_log_to_sel(0);
+		if (msg_len >= SEL_MSGSIZE_TIMESTAMP)
+			ipmi_oops_console_log_to_sel(1);
+		return;
+	}
+	if (msg_len >= SEL_MSGSIZE)
+		ipmi_oops_console_log_to_sel(0);
+}
+
+static void
+ipmi_oops_console_write(struct console *con, const char *s, unsigned int count)
+{
+	unsigned int size;
+
+	if (likely(!oops_in_progress)) {
+		ipmi_oops_console_log_to_sel(0);
+		return;
+	}
+
+	if (unlikely(!oops_user))
+		return;
+
+	while (msg_count < msg_limit && count > 0) {
+		size = min(SEL_MSGSIZE - msg_len, count);
+		memcpy(msg_ptr + msg_len, s, size);
+		msg_len += size;
+		s += size;
+		count -= size;
+		ipmi_oops_console_sync();
+	}
+}
+
+static struct console oops_console = {
+	.name	= "ttyIPMI",
+	.write	= ipmi_oops_console_write,
+	.unblank = ipmi_oops_console_sync,
+	.index	= -1,
+};
+
+static void ipmi_oops_recv(struct ipmi_recv_msg *msg, void *data)
+{
+	ipmi_free_recv_msg(msg);
+}
+
+static struct ipmi_user_hndl ipmi_handler = {
+	.ipmi_recv_hndl = ipmi_oops_recv,
+};
+
+static void ipmi_register_oops_console(int intf)
+{
+	int ret;
+
+	ret = ipmi_create_user(intf, &ipmi_handler, NULL, &oops_user);
+	if (ret < 0) {
+		printk(KERN_ERR PFX "unable to create user\n");
+		return;
+	}
+
+	oops_intf = intf;
+
+	register_console(&oops_console);
+
+	printk(KERN_INFO PFX "ready\n");
+}
+
+static void ipmi_unregister_oops_console(int intf)
+{
+	unregister_console(&oops_console);
+
+	ipmi_destroy_user(oops_user);
+	oops_user = NULL;
+	oops_intf = -1;
+}
+
+static void ipmi_new_smi(int if_num, struct device *dev)
+{
+	ipmi_register_oops_console(if_num);
+}
+
+static void ipmi_smi_gone(int if_num)
+{
+	ipmi_unregister_oops_console(if_num);
+}
+
+static struct ipmi_smi_watcher smi_watcher = {
+	.owner		= THIS_MODULE,
+	.new_smi	= ipmi_new_smi,
+	.smi_gone	= ipmi_smi_gone,
+};
+
+static int __init ipmi_oops_console_init(void)
+{
+	int ret;
+
+	ret = ipmi_smi_watcher_register(&smi_watcher);
+	if (ret) {
+		printk(KERN_ERR PFX "unable to register smi watcher\n");
+		return ret;
+	}
+
+	printk(KERN_INFO PFX "driver initialized\n");
+
+	return ret;
+}
+module_init(ipmi_oops_console_init);
+
+static void __exit ipmi_oops_console_exit(void)
+{
+	if (oops_intf >= 0)
+		ipmi_unregister_oops_console(oops_intf);
+}
+module_exit(ipmi_oops_console_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Hiroshi Shimamoto <h-shimamoto@ct.jp.nec.com>");
+MODULE_DESCRIPTION("oops console handler based upon the IPMI interface.");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_serial.c linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_serial.c
--- linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_serial.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_serial.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,2298 @@
+/*
+ * ipmi_serial.c
+ *
+ * The interface to the IPMI driver for the serial system interface
+ *
+ * Author: MontaVista Software, Inc.
+ *         David Griego <dgriego@mvista.com>
+ *         Corey Minyard <cminyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2005,2006,2007 MontaVista Software Inc.
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/mutex.h>
+#include <linux/rcupdate.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/ctype.h>
+#include <linux/ipmi_smi.h>
+#include <linux/ipmi_serial_sm.h>
+#include <linux/init.h>
+#include <linux/serial_core.h>
+
+#define PFX "ipmi_serial(%s%d): " /* %s%d is for info->name, info->line */
+#define NPFX "ipmi_serial: "
+
+#define MAX_SERIAL_SETUP_STR 100
+static char setup_str[MAX_SERIAL_SETUP_STR] = CONFIG_SERIAL_IPMI_SETUP;
+module_param_string(port_info, setup_str, MAX_SERIAL_SETUP_STR, 0444);
+MODULE_PARM_DESC(port_info, "Defines the perameters for the serial interface"
+		 " i.e. port_info=ttyS1,38400,Direct:ttyS2,9600n81r,"
+		 "TerminalMode,pp");
+
+static int hotmod_handler(const char *val, struct kernel_param *kp);
+
+module_param_call(hotmod, hotmod_handler, NULL, NULL, 0200);
+MODULE_PARM_DESC(hotmod, "Add and remove interfaces.  See"
+		 " Documentation/IPMI.txt in the kernel sources for the"
+		 " gory details.");
+
+static int unload_when_empty;
+module_param(unload_when_empty, int, 0);
+MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are"
+		 " specified or found, default is false (0).  Setting to 1"
+		 " is useful for not loading the module if nothing is"
+		 " found.");
+
+#define IPMI_SER_DEBUG_STATE		1
+#define IPMI_SER_DEBUG_MSG		2
+#define IPMI_SER_DEBUG_DATA		4
+#define IPMI_SER_DEBUG_TIMING		8
+#define IPMI_SER_DEBUG_CHAR_TIMING	16
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Set bit 0 to enable state debugging, bit 1 to"
+		 " enable data debugging, bit 2 to enable message debugging,"
+		 " bit 3 to enable message timing, bit 4 to enable"
+		 " character timing.");
+
+/* List of registered codecs */
+static LIST_HEAD(codec_list);
+
+/* List of interfaces that are configured. */
+static LIST_HEAD(info_list);
+
+/* Lock for the above two lists. */
+static DEFINE_MUTEX(list_lock);
+
+/* Call every 10 ms. */
+#define IPMI_SERIAL_TIMEOUT_TIME_USEC	10000
+#define IPMI_SERIAL_USEC_PER_JIFFY	(1000000 / HZ)
+#define IPMI_SERIAL_TIMEOUT_JIFFIES	(IPMI_SERIAL_TIMEOUT_TIME_USEC /      \
+					 IPMI_SERIAL_USEC_PER_JIFFY)
+
+
+/* Timeouts in microseconds. */
+#define IPMI_SERIAL_INIT_TIMEOUT	1000000
+#define IPMI_SERIAL_INIT_RETRIES	10
+#define IPMI_SERIAL_RETRY_TIMEOUT 	1000000
+#define IPMI_SERIAL_MAX_ERROR_RETRIES 	10
+
+/*
+ * Polling for flags.  Note that event if the interface doesn't
+ * request polling, we still poll once a second.
+ */
+#define NO_POLLING_FLAG_TIMEOUT		1000000
+#define POLLING_FLAG_TIMEOUT		100000
+
+enum ipmi_serial_state {
+	SERIAL_EMPTY,
+	SERIAL_HANDLING_MSG,
+	SERIAL_GETTING_FLAGS,
+	SERIAL_GETTING_EVENTS,
+	SERIAL_CLEARING_FLAGS,
+	SERIAL_GETTING_MESSAGES,
+	/* FIXME - add watchdog stuff. */
+};
+
+enum ipmi_serial_states {
+	SERIAL_IDLE,		/* The serial interface is currently
+				   doing nothing. */
+	SERIAL_WRITE,		/* We are writing bytes to the
+				   interface. */
+	SERIAL_READ,		/* We are waiting to read data from
+				   the interface. */
+	SERIAL_ASYNC_MSG,	/* Getting async message from BMC */
+	SERIAL_COMPLETE,	/* Allows get message to complete
+				   correctly */
+	SERIAL_ERROR0,		/* State to transition to the error
+				   handler, this was added to the
+				   state machine in the spec to be
+				   sure IBF was there. */
+	SERIAL_HOSED		/* The hardware failed to follow the
+				   state machine. */
+};
+
+#define TTY_NAME_LEN	8
+
+/*
+ * Indexes into stats[] in smb_info below.
+ */
+enum serial_stat_indexes {
+	/* Number of watchdog pretimeouts */
+	SERIAL_STAT_watchdog_pretimeouts = 0,
+
+	/* Number of asyncronous messages received. */
+	SERIAL_STAT_incoming_messages,
+
+	/* Number of events received. */
+	SERIAL_STAT_events,
+
+	/* Number of completed requests. */
+	SERIAL_STAT_complete_transactions,
+
+	/* Number of times flags were fetched. */
+	SERIAL_STAT_flag_fetches,
+
+	/* Number of ATTN characters receved. */
+	SERIAL_STAT_attentions,
+
+	/* Number of times the timer went off. */
+	SERIAL_STAT_timer_ticks,
+
+	/* Number of transmitted characters. */
+	SERIAL_STAT_xmit_chars,
+
+	/* Number of received characters. */
+	SERIAL_STAT_recv_chars,
+
+	/* Number of times the protocol was violated. */
+	SERIAL_STAT_protocol_violations,
+
+	/* Number of times the checksum was incorrect. */
+	SERIAL_STAT_checksum_errors,
+
+	/* Number of times a transaction timed out */
+	SERIAL_STAT_timeouts,
+
+	/* Number of times more data than allowed was received in a message. */
+	SERIAL_STAT_overruns,
+
+
+	/* This *must* remain last, add new values above this. */
+	SERIAL_NUM_STATS,
+};
+
+struct ipmi_serial_info {
+	ipmi_smi_t		intf;
+	struct list_head	link;
+
+	spinlock_t		lock;
+
+	struct list_head	xmit_msgs;
+	struct list_head	hp_xmit_msgs;
+	struct ipmi_smi_msg	*curr_msg;
+	struct ipmi_smi_msg	*to_send;
+
+	int                     msg_timeout;
+	int                     retries;
+	unsigned long           last_timeout_jiffies;
+	struct timer_list	timer;
+
+	enum ipmi_serial_state	state;
+
+	int upper_layer_ready;
+
+	unsigned char slave_addr;
+
+	/*
+	 * Used to deliver things to the upper layer when processing
+	 * is complete.  Instead of delivering immediately, we queue
+	 * things up and deliver them when all processing is done.
+	 * Makes locking a lot easier.
+	 */
+	int              watchdog_pretimeouts_to_deliver;
+	int              msg_delivery_in_progress;
+	struct list_head msgs_to_deliver;
+
+	/*
+	 * Sequence number for send messages.  Note that we reserve
+	 * zero for special messages (getting flags, etc.); it is
+	 * never used for normal messages.
+	 */
+	unsigned int     send_seq;
+
+	/*
+	 * If set to true, this will request events the next time the
+	 * state machine is idle.  Only do this if do_event_request is
+	 * true.  Otherwise the codec doesn't support this capability.
+	 */
+	int req_events;
+	int do_event_request;
+	int has_event_buffer;
+	int global_enable_valid;
+
+	/*
+	 * Used to handle automatic timing of getting flags.
+	 */
+	int flag_timeout;
+	int req_flags;
+	int flag_timer;
+	int supports_flags;
+
+	/*
+	 * If true, run the state machine to completion on every send
+	 * call.  Generally used after a panic to make sure stuff goes
+	 * out.
+	 */
+	int run_to_completion;
+
+	/*
+	 * The driver is shutting down, don't start anything new.
+	 */
+	int stop_operation;
+
+	/* Flags from the last GET_MSG_FLAGS command, used when an ATTN
+	   is set to hold the flags until we are done handling everything
+	   from the flags. */
+#define RECEIVE_MSG_AVAIL	0x01
+#define EVENT_MSG_BUFFER_FULL	0x02
+#define WDT_PRE_TIMEOUT_INT	0x08
+#define OEM0_DATA_AVAIL     0x20
+#define OEM1_DATA_AVAIL     0x40
+#define OEM2_DATA_AVAIL     0x80
+#define OEM_DATA_AVAIL      (OEM0_DATA_AVAIL | \
+			     OEM1_DATA_AVAIL | \
+			     OEM2_DATA_AVAIL)
+	unsigned char msg_flags;
+
+	/* Per-OEM handler, called from handle_flags().
+	   Returns 1 when handle_flags() needs to be re-run
+	   or 0 indicating it set si_state itself.
+	*/
+	int (*oem_data_avail_handler)(struct ipmi_serial_info *info);
+
+	/*
+	 * CODEC information.
+	 */
+	struct ipmi_serial_codec *codec;
+	struct ipmi_serial_codec_data *codec_data;
+	struct ipmi_serial_codec_data *alloc_codec_data;
+
+	/* Holds the parameter string. */
+	char             *keepstr;
+
+	/* Serial port information. */
+	char		 name[TTY_NAME_LEN];	/* Name of the serial driver
+						   we are looking for. */
+	int		 line;			/* Serial line we are looking
+						   for. */
+	char		 *options;		/* Options for serial port  */
+	char		 *codec_name;		/* Name of codec to try     */
+	char		 *codec_options;	/* Options for the codec    */
+	struct uart_direct direct;
+	struct uart_info   uinfo;
+	struct uart_info   *orig_port_info;
+	unsigned long	   poll_state;
+	char               uart_buffer[UART_XMIT_SIZE];
+	struct uart_port *port;
+	struct ktermios  termios, old_termios;
+
+	/* Buffer for incoming serial data. */
+#define SBUF_NEXT(v) ((v + 1) % 128)
+	unsigned char sbuf[128];
+	unsigned int  sbuf_start, sbuf_next;
+	int           delivering_char;
+
+	/* From the get device id response... */
+	int device_id_valid;
+	struct ipmi_device_id device_id;
+
+	/* Used to return intialization status. */
+	int init_status;
+
+	/* If this is set, returned responses will go to this function. */
+	void (*internal_msg_handler)(struct ipmi_serial_info *info,
+				     const unsigned char     *data,
+				     unsigned int            len);
+
+	atomic_t stats[SERIAL_NUM_STATS];
+};
+
+#define serial_inc_stat(serial, stat) \
+	atomic_inc(&(serial)->stats[SERIAL_STAT_ ## stat])
+#define serial_add_stat(serial, stat, val) \
+	atomic_add(val, &(serial)->stats[SERIAL_STAT_ ## stat])
+#define serial_get_stat(serial, stat) \
+	((unsigned int) atomic_read(&(serial)->stats[SERIAL_STAT_ ## stat]))
+
+static void ipmi_serial_cleanup_one(struct ipmi_serial_info *to_clean);
+
+struct baud_rates {
+	unsigned int rate;
+	unsigned int cflag;
+	char         *name;
+};
+
+static struct baud_rates baud_rates[] = {
+	{ 921600, B921600, "921600" },
+	{ 500000, B500000, "500000" },
+	{ 460800, B460800, "460800" },
+	{ 230400, B230400, "230400" },
+	{ 115200, B115200, "115200" },
+	{  57600, B57600,  "57600"  },
+	{  38400, B38400,  "38400"  },
+	{  19200, B19200,  "19200"  },
+	{   9600, B9600,   "9600"   },
+	{   4800, B4800,   "4800"   },
+	{   2400, B2400,   "2400"   },
+	{   1200, B1200,   "1200"   },
+	{      0, B38400,  "?"      }
+};
+
+/*
+ * If run_to_completion mode is on, return NULL to know the lock wasn't
+ * taken.  Otherwise lock info->lock and return the flags.
+ */
+static unsigned long *ipmi_serial_lock_cond(struct ipmi_serial_info *info,
+					    unsigned long *flags)
+{
+	if (info->run_to_completion)
+		return NULL;
+	spin_lock_irqsave(&info->lock, *flags);
+	return flags;
+}
+
+static void ipmi_serial_unlock_cond(struct ipmi_serial_info *info,
+				    unsigned long *flags)
+{
+	if (!flags)
+		return;
+	spin_unlock_irqrestore(&info->lock, *flags);
+}
+
+static void queue_return_msg(struct ipmi_serial_info *info)
+{
+	if (debug & IPMI_SER_DEBUG_TIMING) {
+		struct timeval t;
+		do_gettimeofday(&t);
+		printk(KERN_DEBUG PFX "Recv msg at %ld.%6.6ld\n",
+		       info->name, info->line, t.tv_sec, t.tv_usec);
+	}
+	if (debug & IPMI_SER_DEBUG_MSG) {
+		int i;
+		unsigned char *buf = info->curr_msg->rsp;
+		printk(KERN_DEBUG PFX "Received msg:", info->name, info->line);
+		for (i = 0; i < info->curr_msg->rsp_size; i++)
+			printk(" %2.2x(%c)", buf[i],
+			       isprint(buf[i]) ? buf[i] : ' ');
+		printk("\n");
+	}
+
+	/* Queue the message for delivery when we release the lock. */
+	list_add_tail(&info->curr_msg->link, &info->msgs_to_deliver);
+	info->curr_msg = NULL;
+}
+
+static void queue_async_msg(struct ipmi_serial_info *info,
+			    struct ipmi_smi_msg *msg)
+{
+	if (debug & IPMI_SER_DEBUG_TIMING) {
+		struct timeval t;
+		do_gettimeofday(&t);
+		printk(KERN_DEBUG PFX "Recv async msg at %ld.%6.6ld\n",
+		       info->name, info->line, t.tv_sec, t.tv_usec);
+	}
+	if (debug & IPMI_SER_DEBUG_MSG) {
+		int i;
+		unsigned char *buf = msg->rsp;
+		printk(KERN_DEBUG PFX "Received async msg:",
+		       info->name, info->line);
+		for (i = 0; i < msg->rsp_size; i++)
+			printk(" %2.2x(%c)", buf[i],
+			       isprint(buf[i]) ? buf[i] : ' ');
+		printk("\n");
+	}
+
+	/* Queue the message for delivery when we release the lock. */
+	list_add_tail(&msg->link, &info->msgs_to_deliver);
+}
+
+static void queue_return_err_msg(struct ipmi_serial_info *info, int err)
+{
+	struct ipmi_smi_msg *msg = info->curr_msg;
+
+	/* Make it a reponse */
+	msg->rsp[0] = msg->data[0] | 4;
+	msg->rsp[1] = msg->data[1];
+	msg->rsp[2] = err;
+	msg->rsp_size = 3;
+	queue_return_msg(info);
+}
+
+static int send_curr_msg(struct ipmi_serial_info *info)
+{
+	if (!info->port)
+		return -ENODEV;
+
+	WARN_ON(info->to_send);
+	if (info->to_send)
+		return -EBUSY;
+
+	if (debug & IPMI_SER_DEBUG_TIMING) {
+		struct timeval t;
+		do_gettimeofday(&t);
+		printk(KERN_DEBUG PFX "Send msg at %ld.%6.6ld\n",
+		       info->name, info->line, t.tv_sec, t.tv_usec);
+	}
+	if (debug & IPMI_SER_DEBUG_MSG) {
+		int i;
+		unsigned char *buf = info->curr_msg->data;
+		printk(KERN_DEBUG PFX "Sent msg:", info->name, info->line);
+		for (i = 0; i < info->curr_msg->data_size; i++)
+			printk(" %2.2x(%c)", buf[i],
+			       isprint(buf[i]) ? buf[i] : ' ');
+		printk("\n");
+	}
+	info->to_send = info->curr_msg;
+	return 0;
+}
+
+static int start_clear_flags(struct ipmi_serial_info *info)
+{
+	struct ipmi_smi_msg *msg;
+	int                 rv;
+
+	WARN_ON(info->curr_msg);
+	if (info->curr_msg)
+		return -EBUSY;
+
+	msg = ipmi_alloc_smi_msg();
+	if (!msg)
+		return -ENOMEM;
+	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg->data[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
+	msg->data[2] = WDT_PRE_TIMEOUT_INT;
+	msg->data_size = 3;
+	info->curr_msg = msg;
+	rv = send_curr_msg(info);
+	if (!rv)
+		info->state = SERIAL_CLEARING_FLAGS;
+	else {
+		msg->done(msg);
+		info->curr_msg = NULL;
+	}
+	return rv;
+}
+
+static int start_flag_fetch(struct ipmi_serial_info *info)
+{
+	struct ipmi_smi_msg *msg;
+	int                 rv;
+
+	WARN_ON(info->curr_msg);
+	if (info->curr_msg)
+		return -EBUSY;
+
+	msg = ipmi_alloc_smi_msg();
+	if (!msg)
+		return -ENOMEM;
+
+	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg->data[1] = IPMI_GET_MSG_FLAGS_CMD;
+	msg->data_size = 2;
+	info->curr_msg = msg;
+	rv = send_curr_msg(info);
+	if (!rv)
+		info->state = SERIAL_GETTING_FLAGS;
+	else {
+		msg->done(msg);
+		info->curr_msg = NULL;
+	}
+	return rv;
+}
+
+static int start_event_fetch(struct ipmi_serial_info *info)
+{
+	struct ipmi_smi_msg *msg;
+	int                 rv;
+
+	WARN_ON(info->curr_msg);
+	if (info->curr_msg)
+		return -EBUSY;
+
+	msg = ipmi_alloc_smi_msg();
+	if (!msg)
+		return -ENOMEM;
+
+	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
+	msg->data_size = 2;
+	info->curr_msg = msg;
+	rv = send_curr_msg(info);
+	if (rv) {
+		msg->done(msg);
+		info->curr_msg = NULL;
+	} else
+		info->state = SERIAL_GETTING_EVENTS;
+
+	return rv;
+}
+
+static int start_msg_fetch(struct ipmi_serial_info *info)
+{
+	struct ipmi_smi_msg *msg;
+	int                 rv;
+
+	WARN_ON(info->curr_msg);
+	if (info->curr_msg)
+		return -EBUSY;
+
+	msg = ipmi_alloc_smi_msg();
+	if (!msg)
+		return -ENOMEM;
+
+	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg->data[1] = IPMI_GET_MSG_CMD;
+	msg->data_size = 2;
+	info->curr_msg = msg;
+	rv = send_curr_msg(info);
+	if (rv) {
+		info->curr_msg->done(info->curr_msg);
+		info->curr_msg = NULL;
+	} else
+		info->state = SERIAL_GETTING_MESSAGES;
+
+	return rv;
+}
+
+static void handle_flags(struct ipmi_serial_info *info)
+{
+	int rv;
+
+ retry:
+	if (info->msg_flags & WDT_PRE_TIMEOUT_INT) {
+		/* Watchdog pre-timeout */
+		serial_inc_stat(info, watchdog_pretimeouts);
+
+		info->watchdog_pretimeouts_to_deliver++;
+		start_clear_flags(info);
+		info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
+	} else if (info->msg_flags & RECEIVE_MSG_AVAIL) {
+		/*
+		 * Messages available. If for some reason we fail,
+		 * just give up for now.  It will be retried.
+		 */
+		info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+		rv = start_msg_fetch(info);
+		if (rv)
+			goto retry;
+	} else if (info->msg_flags & EVENT_MSG_BUFFER_FULL) {
+		/*
+		 * Messages available. If for some reason we fail,
+		 * just give up for now.  It will be retried.
+		 */
+		info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+		rv = start_event_fetch(info);
+		if (rv)
+			goto retry;
+	} else if (info->msg_flags & OEM_DATA_AVAIL
+				&& info->oem_data_avail_handler) {
+		if (info->oem_data_avail_handler(info))
+			goto retry;
+	} else {
+		info->state = SERIAL_EMPTY;
+	}
+}
+
+/*
+ * This routine starts the next thing to be processed.  Called with
+ * the lock, and releases the lock.
+ *
+ * We delay handling of flags and transmissions of new messages here.
+ * We also delay the deliver of message to the upper and lower layer
+ * in a single-threaded but unlocked section below, so that we don't
+ * have worries of deadlocks calling back into this layer.
+ */
+static void start_next_msg(struct ipmi_serial_info *info, unsigned long *flags)
+{
+	struct list_head    to_deliver;
+	int                 wdog_pretimeout_count;
+	int                 rv;
+	struct ipmi_smi_msg *msg, *s;
+	unsigned long       oflags;
+
+ restart:
+	if (debug & IPMI_SER_DEBUG_STATE)
+		printk(KERN_DEBUG PFX "start_next_message state = %d\n",
+		       info->name, info->line, info->state);
+
+	if (info->state == SERIAL_EMPTY) {
+		if (info->msg_flags) {
+			/* Handle flags we have first. */
+			handle_flags(info);
+			if (info->state == SERIAL_EMPTY) {
+				info->msg_flags = 0;
+				goto restart;
+			}
+			info->msg_timeout = IPMI_SERIAL_RETRY_TIMEOUT;
+			info->retries = IPMI_SERIAL_MAX_ERROR_RETRIES;
+		} else if (info->req_events) {
+			/* We prefer fetching events over new messages. */
+			info->req_events = 0;
+			rv = start_event_fetch(info);
+			if (rv)
+				goto restart;
+			info->msg_timeout = IPMI_SERIAL_RETRY_TIMEOUT;
+			info->retries = IPMI_SERIAL_MAX_ERROR_RETRIES;
+		} else if (likely(info->upper_layer_ready) && info->req_flags) {
+			/* We prefer fetching flags over new messages. */
+			info->req_flags = 0;
+			rv = start_flag_fetch(info);
+			if (rv)
+				goto restart;
+			info->msg_timeout = IPMI_SERIAL_RETRY_TIMEOUT;
+			info->retries = IPMI_SERIAL_MAX_ERROR_RETRIES;
+		} else {
+			/* Look for messages to transmit. */
+			if (!list_empty(&info->hp_xmit_msgs)) {
+				msg = list_entry(info->hp_xmit_msgs.next,
+						 struct ipmi_smi_msg,
+						 link);
+			} else if (!list_empty(&info->xmit_msgs)) {
+				msg = list_entry(info->xmit_msgs.next,
+						 struct ipmi_smi_msg,
+						 link);
+			} else
+				msg = NULL;
+
+			info->curr_msg = msg;
+			if (msg) {
+				if (debug & IPMI_SER_DEBUG_TIMING) {
+					struct timeval t;
+					do_gettimeofday(&t);
+					printk(KERN_DEBUG PFX
+					       "Start send at %ld.%6.6ld\n",
+					       info->name, info->line,
+					       t.tv_sec, t.tv_usec);
+				}
+				info->state = SERIAL_HANDLING_MSG;
+				list_del(&msg->link);
+				rv = send_curr_msg(info);
+				if (rv) {
+					queue_return_err_msg(info,
+						       IPMI_ERR_UNSPECIFIED);
+					goto restart;
+				}
+				info->msg_timeout = IPMI_SERIAL_RETRY_TIMEOUT;
+				info->retries = IPMI_SERIAL_MAX_ERROR_RETRIES;
+			}
+		}
+	}
+
+ restart_delivery:
+	if (info->watchdog_pretimeouts_to_deliver
+	    || !list_empty(&info->msgs_to_deliver)
+	    || info->to_send) {
+		if (info->msg_delivery_in_progress) {
+			/*
+			 * Another thread is already delivering, tell
+			 * it there are more things to do and
+			 * leave.
+			 */
+			info->msg_delivery_in_progress = 2;
+			goto out_unlock;
+		}
+
+		/* Pull the data we need to deliver. */
+		wdog_pretimeout_count = info->watchdog_pretimeouts_to_deliver;
+		info->watchdog_pretimeouts_to_deliver = 0;
+
+		INIT_LIST_HEAD(&to_deliver);
+		if (!list_empty(&info->msgs_to_deliver))
+			list_splice_init(&info->msgs_to_deliver, &to_deliver);
+
+		info->msg_delivery_in_progress = 1;
+		ipmi_serial_unlock_cond(info, flags);
+		while (wdog_pretimeout_count > 0) {
+			ipmi_smi_watchdog_pretimeout(info->intf);
+			wdog_pretimeout_count--;
+		}
+
+		list_for_each_entry_safe(msg, s, &to_deliver, link) {
+			list_del(&msg->link);
+			ipmi_smi_msg_received(info->intf, msg);
+		}
+		if (info->to_send) {
+			if (debug & IPMI_SER_DEBUG_TIMING) {
+				struct timeval t;
+				do_gettimeofday(&t);
+				printk(KERN_DEBUG PFX
+				       "send to codec at %ld.%6.6ld\n",
+				       info->name, info->line,
+				       t.tv_sec, t.tv_usec);
+			}
+			info->send_seq++;
+			if (info->send_seq == 0)
+				info->send_seq++;
+			msg = info->to_send;
+			info->to_send = NULL;
+			rv = info->codec->send_msg(info->codec_data,
+						   msg->data,
+						   msg->data_size,
+						   info->send_seq);
+			if (rv)
+				printk(KERN_WARNING PFX
+				       "Error from codec send_msg: %d\n",
+				       info->name, info->line, rv);
+		}
+		flags = ipmi_serial_lock_cond(info, &oflags);
+		if (info->msg_delivery_in_progress > 1) {
+			/* Another thread put things in to be delivered, go
+			 * ahead and do the delivery since it couldn't. */
+			info->msg_delivery_in_progress = 0;
+			goto restart_delivery;
+		}
+		info->msg_delivery_in_progress = 0;
+	}
+ out_unlock:
+	ipmi_serial_unlock_cond(info, flags);
+}
+
+unsigned int ipmi_serial_ll_xmit(struct ipmi_serial_info *info,
+				 const unsigned char     *buf,
+				 unsigned int            count)
+{
+	struct uart_port *port;
+	unsigned long    oflags, *flags;
+	unsigned int     rv;
+
+	if (debug & IPMI_SER_DEBUG_CHAR_TIMING) {
+		struct timeval t;
+		do_gettimeofday(&t);
+		printk(KERN_DEBUG PFX "xmit chars at %ld.%6.6ld\n",
+		       info->name, info->line, t.tv_sec, t.tv_usec);
+	}
+
+	flags = ipmi_serial_lock_cond(info, &oflags);
+	port = info->port;
+	ipmi_serial_unlock_cond(info, flags);
+	if (!port)
+		return 0;
+
+	rv = uart_direct_write(port, buf, count, flags != NULL);
+	if (rv > 0)
+		serial_add_stat(info, xmit_chars, rv);
+
+	if (debug & IPMI_SER_DEBUG_DATA) {
+		int i;
+		printk(KERN_DEBUG PFX "Outgoing data:",
+		       info->name, info->line);
+		for (i = 0; i < rv; i++)
+			printk(" %2.2x(%c)", buf[i],
+			       isprint(buf[i]) ? buf[i] : ' ');
+		printk("\n");
+	}
+	return rv;
+}
+EXPORT_SYMBOL(ipmi_serial_ll_xmit);
+
+void ipmi_serial_ll_attn(struct ipmi_serial_info *info)
+{
+	unsigned long oflags, *flags;
+
+	if (info->stop_operation)
+		return;
+
+	flags = ipmi_serial_lock_cond(info, &oflags);
+	serial_inc_stat(info, attentions);
+	if (info->port)
+		info->req_flags = 1;
+	start_next_msg(info, flags);
+}
+EXPORT_SYMBOL(ipmi_serial_ll_attn);
+
+void ipmi_serial_ll_recv(struct ipmi_serial_info *info,
+			 const unsigned char     *msg,
+			 unsigned int            len,
+			 unsigned int            seq)
+{
+	struct ipmi_smi_msg *rmsg;
+	int                 truncated = 0;
+	unsigned long       oflags, *flags;
+
+	if (info->internal_msg_handler) {
+		info->internal_msg_handler(info, msg, len);
+		return;
+	}
+
+	flags = ipmi_serial_lock_cond(info, &oflags);
+	if (!info->intf) {
+		ipmi_serial_unlock_cond(info, flags);
+		return;
+	}
+	if (seq && (seq != info->send_seq)) {
+		/* Sequence doesn't match and is non-zero, just ignore. */
+		ipmi_serial_unlock_cond(info, flags);
+		return;
+	}
+	if (debug & IPMI_SER_DEBUG_STATE)
+		printk(KERN_DEBUG PFX "ll_recv state = %d\n",
+		       info->name, info->line, info->state);
+	switch (info->state) {
+	case SERIAL_EMPTY:
+		break;
+
+	case SERIAL_HANDLING_MSG:
+		serial_inc_stat(info, complete_transactions);
+		rmsg = info->curr_msg;
+		if (len > IPMI_MAX_MSG_LENGTH) {
+			rmsg->rsp_size = IPMI_MAX_MSG_LENGTH;
+			truncated = 1;
+		} else
+			rmsg->rsp_size = len;
+		memcpy(rmsg->rsp, msg, rmsg->rsp_size);
+		if (truncated && (msg[2] == 0))
+			rmsg->rsp[2] = IPMI_ERR_MSG_TRUNCATED;
+		queue_return_msg(info);
+		break;
+
+	case SERIAL_GETTING_FLAGS:
+		info->curr_msg->done(info->curr_msg);
+		info->curr_msg = NULL;
+		/* We got the flags from the SMI, now fetch them. */
+		if ((msg[2] == 0) && (len >= 4)) {
+			serial_inc_stat(info, flag_fetches);
+			info->msg_flags = msg[3];
+		}
+		break;
+
+	case SERIAL_GETTING_EVENTS:
+		rmsg = info->curr_msg;
+		if (len > IPMI_MAX_MSG_LENGTH) {
+			printk(KERN_WARNING PFX "got event response "
+			       "that was too long: %d\n", info->name,
+			       info->line, len);
+			break;
+		}
+		rmsg->rsp_size = len;
+		memcpy(rmsg->rsp, msg, rmsg->rsp_size);
+		if (rmsg->rsp[2] != 0) {
+			/* Error getting event, probably done. */
+			rmsg->done(rmsg);
+			info->curr_msg = NULL;
+		} else {
+			serial_inc_stat(info, events);
+
+			queue_return_msg(info);
+		}
+		break;
+
+	case SERIAL_CLEARING_FLAGS:
+		/* We cleared the flags. */
+		info->curr_msg->done(info->curr_msg);
+		info->curr_msg = NULL;
+		if (msg[2] != 0) {
+			/* Error clearing flags */
+			printk(KERN_WARNING
+			       PFX "Error clearing flags: %2.2x\n",
+			       info->name, info->line, msg[2]);
+		}
+		info->state = SERIAL_EMPTY;
+		break;
+
+	case SERIAL_GETTING_MESSAGES:
+		rmsg = info->curr_msg;
+		if (len > IPMI_MAX_MSG_LENGTH) {
+			printk(KERN_WARNING PFX "got incoming command "
+			       "that was too long: %d\n", info->name,
+			       info->line, len);
+			break;
+		}
+		rmsg->rsp_size = len;
+		memcpy(rmsg->rsp, msg, rmsg->rsp_size);
+		if (rmsg->rsp[2] != 0) {
+			/* Error getting message, probably done. */
+			rmsg->done(rmsg);
+			info->curr_msg = NULL;
+		} else {
+			serial_inc_stat(info, incoming_messages);
+			queue_return_msg(info);
+		}
+		break;
+	}
+	info->state = SERIAL_EMPTY; /* Tell start_next_msg to do something. */
+	start_next_msg(info, flags);
+}
+EXPORT_SYMBOL(ipmi_serial_ll_recv);
+
+void ipmi_serial_ll_async(struct ipmi_serial_info *info,
+			  const unsigned char *msg, unsigned int len)
+{
+	struct ipmi_smi_msg *rmsg;
+	unsigned long *flags, oflags;
+
+	if ((msg[0] >> 2) != IPMI_NETFN_APP_RESPONSE) {
+		printk(KERN_WARNING PFX "Got invalid async NETFN: 0x%x",
+		       info->name, info->line, msg[0] >> 2);
+		return;
+	}
+
+	flags = ipmi_serial_lock_cond(info, &oflags);
+	if (!info->intf) {
+		ipmi_serial_unlock_cond(info, flags);
+		return;
+	}
+
+	/* Validate that the message is allowed and do stats. */
+	switch (msg[1]) {
+	case IPMI_GET_MSG_CMD:
+		serial_inc_stat(info, incoming_messages);
+		break;
+
+	case IPMI_READ_EVENT_MSG_BUFFER_CMD:
+		serial_inc_stat(info, events);
+		break;
+
+	default:
+		printk(KERN_WARNING PFX "Got invalid async command: 0x%x",
+		       info->name, info->line, msg[1]);
+		goto out;
+	}
+
+	if (len > IPMI_MAX_MSG_LENGTH) {
+		/* FIXME - add peg */
+		printk(KERN_WARNING PFX "got incoming async msg "
+		       "that was too long: %d\n", info->name, info->line, len);
+		goto out;
+	}
+	rmsg = ipmi_alloc_smi_msg();
+	if (!rmsg) {
+		/* FIXME - add peg */
+		printk(KERN_WARNING PFX "Dropped incoming async msg, "
+		       "could not allocate message\n", info->name, info->line);
+		goto out;
+	}
+
+	/* Make it look like we sent the command. */
+	rmsg->data[0] = msg[0] & ~(1 << 2); /* Convert response to request */
+	rmsg->data[1] = msg[1]; /* command */
+	rmsg->data_size = 2;
+
+	rmsg->rsp_size = len;
+	memcpy(rmsg->rsp, msg, rmsg->rsp_size);
+	queue_async_msg(info, rmsg);
+
+ out:
+	start_next_msg(info, flags);
+}
+EXPORT_SYMBOL(ipmi_serial_ll_async);
+
+void ipmi_serial_ll_protocol_violation(struct ipmi_serial_info *info)
+{
+	serial_inc_stat(info, protocol_violations);
+}
+EXPORT_SYMBOL(ipmi_serial_ll_protocol_violation);
+
+void ipmi_serial_ll_checksum_error(struct ipmi_serial_info *info)
+{
+	serial_inc_stat(info, checksum_errors);
+}
+EXPORT_SYMBOL(ipmi_serial_ll_checksum_error);
+
+static void ipmi_serial_handle_char(struct uart_port *port,
+				    unsigned int status,
+				    unsigned int overrun, unsigned int ch,
+				    unsigned int flag)
+{
+	struct ipmi_serial_info *info = port->info->direct->direct_data;
+	unsigned int next;
+
+	if (debug & IPMI_SER_DEBUG_CHAR_TIMING) {
+		struct timeval t;
+		do_gettimeofday(&t);
+		printk(KERN_DEBUG PFX "Got char %2.2x(%c) at %ld.%6.6ld\n",
+		       info->name, info->line,
+		       ch, isprint(ch) ? ch : ' ',
+		       t.tv_sec, t.tv_usec);
+	}
+
+	serial_inc_stat(info, recv_chars);
+
+	if (status & overrun)
+		serial_inc_stat(info, overruns);
+
+	if (debug & IPMI_SER_DEBUG_DATA)
+		printk(KERN_DEBUG PFX "Incoming char: %2.2x '%c'\n",
+		       info->name, info->line, ch, isprint(ch) ? ch : ' ');
+
+	/*
+	 * No lock is needed.  We are the only place that changes
+	 * sbuf_next, and we are single-threaded here due to the port
+	 * lock.
+	 */
+	next = SBUF_NEXT(info->sbuf_next);
+	if (next == info->sbuf_start) {
+		serial_inc_stat(info, overruns);
+		return;
+	}
+	info->sbuf[info->sbuf_next] = ch;
+	smp_wmb();
+	info->sbuf_next = next;
+}
+
+static void ipmi_serial_push(struct uart_port *port)
+{
+	struct ipmi_serial_info *info = port->info->direct->direct_data;
+	unsigned long oflags, *flags;
+	struct ipmi_serial_codec_data *cdata;
+	unsigned char ch;
+
+	if (debug & IPMI_SER_DEBUG_CHAR_TIMING) {
+		struct timeval t;
+		do_gettimeofday(&t);
+		printk(KERN_DEBUG PFX "Got push at %ld.%6.6ld\n",
+		       info->name, info->line, t.tv_sec, t.tv_usec);
+	}
+
+	cdata = info->codec_data;
+	if (!cdata)
+		return;
+
+	flags = ipmi_serial_lock_cond(info, &oflags);
+	if (info->delivering_char)
+		goto out_unlock;
+	info->delivering_char = 1;
+	while (info->sbuf_next != info->sbuf_start) {
+		ch = info->sbuf[info->sbuf_start];
+		info->sbuf_start = SBUF_NEXT(info->sbuf_start);
+		ipmi_serial_unlock_cond(info, flags);
+		info->codec->handle_char(cdata, ch);
+		flags = ipmi_serial_lock_cond(info, &oflags);
+	}
+	info->delivering_char = 0;
+ out_unlock:
+	ipmi_serial_unlock_cond(info, flags);
+}
+
+static void ipmi_serial_tx_ready(unsigned long data)
+{
+	struct ipmi_serial_info *info = (struct ipmi_serial_info *) data;
+	struct ipmi_serial_codec_data *cdata;
+
+	cdata = info->codec_data;
+	if (cdata)
+		info->codec->tx_ready(cdata);
+}
+
+static void timeout_handling(struct ipmi_serial_info *info,
+			     unsigned int            delay_since_last)
+{
+	unsigned long oflags, *flags;
+
+	if (info->codec->timer_tick)
+		info->codec->timer_tick(info->codec_data, delay_since_last);
+
+	flags = ipmi_serial_lock_cond(info, &oflags);
+
+	info->flag_timer -= delay_since_last;
+	if (info->flag_timer <= 0) {
+		if (!info->stop_operation && info->supports_flags)
+			info->req_flags = 1;
+		info->flag_timer = info->flag_timeout;
+	}
+
+	info->msg_timeout -= delay_since_last;
+	if (info->msg_timeout > 0)
+		/* Haven't timed out yet. */
+		goto out_unlock;
+
+	serial_inc_stat(info, timeouts);
+
+	/*
+	 * Note that if we are doing flags, events, or things of that
+	 * nature, just ignore failures and continue on.  The
+	 * operation will be retried later, so no need to fret.
+	 * Just retry messages.
+	 */
+	if (debug & IPMI_SER_DEBUG_STATE)
+		printk(KERN_DEBUG PFX "timeout state = %d\n",
+		       info->name, info->line, info->state);
+	switch (info->state) {
+	case SERIAL_EMPTY:
+		break;
+
+	case SERIAL_HANDLING_MSG:
+		info->retries--;
+		if (info->retries > 0)
+			send_curr_msg(info); /* Retry the send */
+		else {
+			queue_return_err_msg(info, IPMI_TIMEOUT_ERR);
+			info->state = SERIAL_EMPTY;
+		}
+		break;
+
+	case SERIAL_GETTING_FLAGS:
+	case SERIAL_CLEARING_FLAGS:
+		info->curr_msg->done(info->curr_msg);
+		info->curr_msg = NULL;
+		info->state = SERIAL_EMPTY;
+		break;
+
+	case SERIAL_GETTING_EVENTS:
+		info->curr_msg->done(info->curr_msg);
+		info->curr_msg = NULL;
+		info->state = SERIAL_EMPTY;
+		break;
+
+	case SERIAL_GETTING_MESSAGES:
+		info->curr_msg->done(info->curr_msg);
+		info->curr_msg = NULL;
+		info->state = SERIAL_EMPTY;
+		break;
+	}
+
+ out_unlock:
+	start_next_msg(info, flags);
+}
+
+static void ipmi_serial_timeout(unsigned long data)
+{
+	struct ipmi_serial_info *info = (struct ipmi_serial_info *) data;
+	unsigned long curr_jif = jiffies;
+
+	serial_inc_stat(info, timer_ticks);
+
+	timeout_handling(info, ((curr_jif - info->last_timeout_jiffies)
+				* IPMI_SERIAL_USEC_PER_JIFFY));
+
+	info->last_timeout_jiffies = curr_jif;
+	mod_timer(&info->timer, curr_jif + IPMI_SERIAL_TIMEOUT_JIFFIES);
+}
+
+static int ipmi_serial_start_processing(void *send_info, ipmi_smi_t intf)
+{
+	struct ipmi_serial_info *info = send_info;
+	unsigned long curr_jif = jiffies;
+
+	info->intf = intf;
+	smp_wmb(); /* Make sure intf is set before anything else. */
+
+	info->upper_layer_ready = 1;
+	info->last_timeout_jiffies = curr_jif;
+	mod_timer(&info->timer, curr_jif + IPMI_SERIAL_TIMEOUT_JIFFIES);
+	return 0;
+}
+
+static void ipmi_serial_poll(void *send_info)
+{
+	struct ipmi_serial_info *info = send_info;
+	struct uart_port *port;
+	struct circ_buf *circ;
+
+	port = info->port;
+	if (!port)
+		return;
+
+	/*
+	 * No need for locks here, that would result in a deadlock and
+	 * the locks are unnecessary.
+	 */
+	udelay(10);
+	timeout_handling(info, 10);
+	if (info->run_to_completion) {
+		port->ops->poll(port, UART_POLL_FLAGS_TX | UART_POLL_FLAGS_RX);
+	} else {
+		unsigned long flags;
+		spin_lock_irqsave(&port->lock, flags);
+		port->ops->poll_startup(port, &info->poll_state);
+		port->ops->poll(port, UART_POLL_FLAGS_TX | UART_POLL_FLAGS_RX);
+		port->ops->poll_shutdown(port, info->poll_state);
+		spin_unlock_irqrestore(&port->lock, flags);
+	}
+	if (info->sbuf_next != info->sbuf_start)
+		ipmi_serial_push(port);
+	circ = uart_get_circ_buf(port);
+	if (uart_circ_chars_free(circ) > 0)
+		ipmi_serial_tx_ready((unsigned long) info);
+}
+
+static void ipmi_serial_sender(void                *send_info,
+			       struct ipmi_smi_msg *msg,
+			       int                 priority)
+{
+	struct ipmi_serial_info *info = send_info;
+	unsigned long           oflags, *flags;
+
+	flags = ipmi_serial_lock_cond(info, &oflags);
+	if (!info->port) {
+		info->curr_msg = msg;
+		queue_return_err_msg(info, IPMI_ERR_UNSPECIFIED);
+	} else if (priority > 0)
+		list_add_tail(&msg->link, &info->hp_xmit_msgs);
+	else
+		list_add_tail(&msg->link, &info->xmit_msgs);
+	start_next_msg(info, flags);
+
+	if (info->run_to_completion) {
+		while (info->curr_msg)
+			ipmi_serial_poll(info);
+	}
+}
+
+static void ipmi_serial_request_events(void *send_info)
+{
+	struct ipmi_serial_info *info = send_info;
+	unsigned long           oflags, *flags;
+
+	flags = ipmi_serial_lock_cond(info, &oflags);
+	if (!info->stop_operation && info->port && info->do_event_request
+				&& info->has_event_buffer)
+		info->req_events = 1;
+	start_next_msg(info, flags);
+}
+
+static void ipmi_serial_set_run_to_completion(void *send_info, int rtc_on)
+{
+	struct ipmi_serial_info *info = send_info;
+	struct uart_port *port;
+
+	if (info->run_to_completion == rtc_on)
+		return;
+
+	port = info->port;
+	if (!port)
+		return;
+
+	info->run_to_completion = rtc_on;
+	if (rtc_on) {
+		port->ops->poll_startup(port, &info->poll_state);
+		while (info->curr_msg)
+			ipmi_serial_poll(info);
+	} else
+		port->ops->poll_shutdown(port, info->poll_state);
+}
+
+static int ipmi_serial_inc_usecount(void *send_info)
+{
+	struct ipmi_serial_info *info = send_info;
+
+	if (!try_module_get(info->codec->owner))
+		return -ENODEV;
+	return 0;
+}
+
+static void ipmi_serial_dec_usecount(void *send_info)
+{
+	struct ipmi_serial_info *info = send_info;
+
+	module_put(info->codec->owner);
+}
+
+static struct ipmi_smi_handlers handlers = {
+	.owner                  = THIS_MODULE,
+	.start_processing       = ipmi_serial_start_processing,
+	.sender			= ipmi_serial_sender,
+	.request_events		= ipmi_serial_request_events,
+	.set_run_to_completion  = ipmi_serial_set_run_to_completion,
+	.poll			= ipmi_serial_poll,
+	.inc_usecount		= ipmi_serial_inc_usecount,
+	.dec_usecount		= ipmi_serial_dec_usecount
+};
+
+static int type_file_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	return sprintf(page, "serial\n");
+}
+
+static int param_read_proc(char *page, char **start, off_t off,
+			   int count, int *eof, void *data)
+{
+	char                    *out = page;
+	struct ipmi_serial_info *info = data;
+	struct ktermios         *t = &info->termios;
+	int                     i;
+	char                    parity, bits, stop, opts[4];
+
+	/* Translate from termios and mctrl. */
+	for (i = 0; baud_rates[i].rate; i++) {
+		if ((t->c_cflag & CBAUD) == baud_rates[i].cflag)
+			break;
+	}
+	if (!(t->c_cflag & PARENB))
+		parity = 'n';
+	else if (t->c_cflag & PARODD)
+		parity = 'o';
+	else
+		parity = 'e';
+	switch (t->c_cflag & CSIZE) {
+	case CS5:
+		bits = '5';
+		break;
+	case CS6:
+		bits = '6';
+		break;
+	case CS7:
+		bits = '7';
+		break;
+	case CS8:
+		bits = '8';
+		break;
+	default:
+		bits = '?';
+	}
+	if (t->c_cflag & CSTOPB)
+		stop = '2';
+	else
+		stop = '1';
+	opts[0] = '\0';
+	if (t->c_cflag & CRTSCTS)
+		strcat(opts, "r");
+	if (!(info->port->mctrl & TIOCM_RTS))
+		strcat(opts, "R");
+	if (!(info->port->mctrl & TIOCM_DTR))
+		strcat(opts, "D");
+
+	out += sprintf(out, "%s%d,%s%c%c%c%s,%s",
+		       info->name, info->line,
+		       baud_rates[i].name, parity, bits, stop, opts,
+		       info->codec->name);
+	out += info->codec->add_options(info->codec_data, out);
+	out += sprintf(out, "\n");
+
+	return out - page;
+}
+
+static int stat_file_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	char                    *out = page;
+	struct ipmi_serial_info *info = data;
+
+	out += sprintf(out, "timer_ticks:           %u\n",
+		       serial_get_stat(info, timer_ticks));
+	out += sprintf(out, "attentions:            %u\n",
+		       serial_get_stat(info, attentions));
+	out += sprintf(out, "flag_fetches:          %u\n",
+		       serial_get_stat(info, flag_fetches));
+	out += sprintf(out, "complete_transactions: %u\n",
+		       serial_get_stat(info, complete_transactions));
+	out += sprintf(out, "events:                %u\n",
+		       serial_get_stat(info, events));
+	out += sprintf(out, "watchdog_pretimeouts:  %u\n",
+		       serial_get_stat(info, watchdog_pretimeouts));
+	out += sprintf(out, "xmit_chars:            %u\n",
+		       serial_get_stat(info, xmit_chars));
+	out += sprintf(out, "recv_chars:            %u\n",
+		       serial_get_stat(info, recv_chars));
+	out += sprintf(out, "protocol_violations:   %u\n",
+		       serial_get_stat(info, protocol_violations));
+	out += sprintf(out, "checksum_errors:       %u\n",
+		       serial_get_stat(info, checksum_errors));
+	out += sprintf(out, "timeouts:              %u\n",
+		       serial_get_stat(info, timeouts));
+	out += sprintf(out, "overruns:              %u\n",
+		       serial_get_stat(info, overruns));
+
+	return out - page;
+}
+
+static void devid_handler(struct ipmi_serial_info *info,
+			  const unsigned char     *data,
+			  unsigned int            len)
+{
+	int rv;
+
+	rv = ipmi_demangle_device_id(data, len, &info->device_id);
+	if (rv) {
+		info->device_id_valid = rv;
+		return;
+	}
+
+	info->device_id_valid = 1;
+
+	if (info->codec->check_dev_id)
+		info->codec->check_dev_id(info->codec_data, &info->device_id);
+}
+
+static int try_get_dev_id(struct ipmi_serial_info *info)
+{
+	unsigned char msg[2];
+	int           rv;
+	int           timeout;
+
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_DEVICE_ID_CMD;
+
+	info->device_id_valid = 0;
+	info->internal_msg_handler = devid_handler;
+	rv = info->codec->send_msg(info->codec_data, msg, 2, 0);
+	if (rv)
+		goto out_err;
+
+	timeout = IPMI_SERIAL_RETRY_TIMEOUT;
+	while (!info->device_id_valid && (timeout > 0)) {
+		msleep(10);
+		timeout -= 10000;
+	}
+	if (!info->device_id_valid)
+		rv = -ETIMEDOUT;
+	else if (info->device_id_valid < 0)
+		rv = info->device_id_valid;
+
+ out_err:
+	info->internal_msg_handler = NULL;
+	return rv;
+}
+
+static void set_global_enable_handler(struct ipmi_serial_info *info,
+				      const unsigned char     *data,
+				      unsigned int            len)
+{
+	if (len < 3 ||
+			data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
+			data[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) {
+		printk(KERN_WARNING PFX
+		       "Invalid return from set global "
+		       " enables command, cannot enable the event"
+		       " buffer.\n", info->name, info->line);
+		info->global_enable_valid = -EINVAL;
+		return;
+	}
+
+	if (data[2] != 0)
+		info->global_enable_valid = 1;
+	else
+		info->global_enable_valid = -ENOENT;
+}
+
+static void get_global_enable_handler(struct ipmi_serial_info *info,
+				      const unsigned char     *data,
+				      unsigned int            len)
+{
+	unsigned char msg[3];
+	int rv;
+
+	if (len < 4 ||
+			data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
+			data[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD   ||
+			data[2] != 0) {
+		printk(KERN_WARNING PFX
+		       "Invalid return from get global"
+		       " enables command, cannot enable the event"
+		       " buffer.\n", info->name, info->line);
+		info->global_enable_valid = -EINVAL;
+		return;
+	}
+
+	if (data[3] & IPMI_BMC_EVT_MSG_BUFF) {
+		/* Nothing to do, it's enabled. */
+		info->global_enable_valid = 1;
+		return;
+	}
+
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+	msg[2] = data[3] | IPMI_BMC_EVT_MSG_BUFF;
+	info->internal_msg_handler = set_global_enable_handler;
+	rv = info->codec->send_msg(info->codec_data, msg, 3, 0);
+	if (rv)
+		info->global_enable_valid = rv;
+}
+
+static int try_enable_event_buffer(struct ipmi_serial_info *info)
+{
+	unsigned char msg[3];
+	int           timeout;
+	int           rv = 0;
+
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+	info->global_enable_valid = 0;
+	info->internal_msg_handler = get_global_enable_handler;
+	rv = info->codec->send_msg(info->codec_data, msg, 2, 0);
+	if (rv)
+		goto out_err;
+
+	timeout = IPMI_SERIAL_RETRY_TIMEOUT;
+	while (!info->global_enable_valid && (timeout > 0)) {
+		msleep(10);
+		timeout -= 10000;
+	}
+	if (!info->global_enable_valid)
+		rv = -ETIMEDOUT;
+	else if (info->global_enable_valid < 0)
+		rv = info->global_enable_valid;
+
+ out_err:
+	info->internal_msg_handler = NULL;
+	return rv;
+}
+
+void ipmi_serial_ll_init_complete(struct ipmi_serial_info *info,
+				  unsigned char slave_addr,
+				  int err)
+{
+	if (err)
+		info->init_status = err;
+	else {
+		if (slave_addr)
+			info->slave_addr = slave_addr;
+		info->init_status = 1;
+	}
+}
+EXPORT_SYMBOL(ipmi_serial_ll_init_complete);
+
+static int setup_termios(struct ipmi_serial_info *info)
+{
+	char *o = info->options;
+	int baud = 0;
+	int i;
+	unsigned int mctrl = 0;
+	unsigned long flags;
+	int rv;
+
+	/* Init some defaults. */
+	info->termios.c_cflag = CLOCAL | CREAD;
+	info->termios.c_iflag = IGNPAR;
+	info->termios.c_oflag = 0;
+	info->termios.c_lflag = 0;
+	info->termios.c_cc[VTIME] = 0; /* inter-character timer used */
+
+	rv = info->codec->setup_termios(&info->termios);
+	if (rv)
+		return rv;
+
+	if (o && *o) {
+		char *end;
+		baud = simple_strtoul(o, &end, 10);
+		if (end == o) {
+			printk(KERN_ERR PFX "no baud rate given\n",
+			       info->name, info->line);
+			return -EINVAL;
+		}
+		o = end;
+	}
+	for (i = 0; baud_rates[i].rate != 0; i++) {
+		if (baud_rates[i].rate == baud)
+			break;
+	}
+	if (baud_rates[i].rate == 0) {
+		printk(KERN_ERR PFX "invalid baud rate\n",
+		       info->name, info->line);
+		return -EINVAL;
+	}
+
+	info->termios.c_cflag |= baud_rates[i].cflag;
+
+	if (o && *o) {
+		switch (*o) {
+		case 'o': case 'O':
+			info->termios.c_cflag |= PARODD;
+			/*fall through*/
+		case 'e': case 'E':
+			info->termios.c_cflag |= PARENB;
+			break;
+		case 'n': case 'N':
+			break;
+		default:
+			printk(KERN_ERR PFX "Invalid parity: '%c'\n",
+			       info->name, info->line, *o);
+			return -EINVAL;
+		}
+		o++;
+	}
+	if (o && *o) {
+		switch (*o) {
+		case '5':
+			info->termios.c_cflag |= CS5;
+			break;
+		case '6':
+			info->termios.c_cflag |= CS6;
+			break;
+		case '7':
+			info->termios.c_cflag |= CS7;
+			break;
+		case '8':
+			info->termios.c_cflag |= CS8;
+			break;
+		default:
+			info->termios.c_cflag |= CS8;
+			printk(KERN_ERR PFX "Invalid bits: '%c'\n",
+			       info->name, info->line, *o);
+			return -EINVAL;
+		}
+		o++;
+	} else {
+		info->termios.c_cflag |= CS8;
+	}
+
+	if (o && *o) {
+		switch (*o) {
+		case '1':
+			break;
+		case '2':
+			info->termios.c_cflag |= CSTOPB;
+			break;
+		default:
+			printk(KERN_ERR PFX "Invalid stop bits: '%c'\n",
+			       info->name, info->line, *o);
+			return -EINVAL;
+		}
+		o++;
+	}
+
+	/*
+	 * Note that unless overridden always enable DTR and sending
+	 * RTS to the device.  The device can ignore it, but it can't
+	 * hurt to send it.  It can be overridden with options.
+	 */
+	mctrl |= TIOCM_RTS | TIOCM_DTR;
+
+	while (o && *o) {
+		switch (*o) {
+		case 'r':
+			info->termios.c_cflag |= CRTSCTS;
+			break;
+		case 'R':
+			mctrl &= ~TIOCM_RTS;
+			break;
+		case 'D':
+			mctrl &= ~TIOCM_DTR;
+			break;
+		default:
+			printk(KERN_ERR PFX "Invalid config option: '%c'\n",
+			       info->name, info->line, *o);
+			return -EINVAL;
+		}
+		o++;
+	}
+
+	spin_lock_irqsave(&info->port->lock, flags);
+	info->port->mctrl |= mctrl;
+	spin_unlock_irqrestore(&info->port->lock, flags);
+	info->port->ops->set_termios(info->port, &info->termios,
+				     &info->old_termios);
+	return 0;
+}
+
+/*
+ * Called when the serial layer says it found a serial driver that
+ * matches.  We use this to kick things off.
+ */
+static int ipmi_serial_found(struct ipmi_serial_info *info)
+{
+	int                     rv;
+	int                     timeout;
+	int                     retries;
+	unsigned int            capabilities;
+	char		        sysfs_name[sizeof(info->name) + 4];
+
+	printk(KERN_INFO PFX "Found a matching serial port\n",
+	       info->name, info->line);
+
+	info->stop_operation = 0;
+
+	setup_termios(info);
+
+	info->init_status = 0;
+	retries = IPMI_SERIAL_INIT_RETRIES;
+ retry:
+	rv = info->codec->init(info->alloc_codec_data, info,
+			       info->codec_options);
+	if (rv) {
+		printk(KERN_ERR PFX "codec initialization failed, "
+		       "interface is not usable: %d\n", info->name,
+		       info->line, rv);
+		return rv;
+	}
+
+	/* Allow the receiver to send to the codec. */
+	info->codec_data = info->alloc_codec_data;
+
+	if (info->codec->start) {
+		rv = info->codec->start(info->codec_data);
+		if (rv) {
+			printk(KERN_ERR PFX "codec start failed, "
+			       "interface is not usable: %d\n", info->name,
+			       info->line, rv);
+			goto out_err;
+		}
+	} else
+		ipmi_serial_ll_init_complete(info, 0, 0);
+
+	timeout = IPMI_SERIAL_INIT_TIMEOUT;
+	while (!info->init_status && (timeout > 0)) {
+		msleep(10);
+		timeout -= 10000;
+	}
+	if (!info->init_status) {
+		retries--;
+		if (retries > 0) {
+			/* Turn the receiver off and let it clear out. */
+			info->codec_data = NULL;
+			synchronize_sched();
+			info->codec->cleanup(info->alloc_codec_data);
+			goto retry;
+		}
+
+		printk(KERN_ERR PFX "codec initialization timed out, "
+		       "interface is not usable\n", info->name, info->line);
+		rv = -ETIMEDOUT;
+		goto out_err;
+	} else if (info->init_status < 0) {
+		rv = info->init_status;
+		printk(KERN_ERR PFX "Initialization failed: %d\n",
+		       info->name, info->line, rv);
+		goto out_err;
+	}
+
+	retries = IPMI_SERIAL_MAX_ERROR_RETRIES;
+ retry_devid:
+	rv = try_get_dev_id(info);
+	if (rv) {
+		retries--;
+		if (retries > 0)
+			goto retry_devid;
+		printk(KERN_ERR PFX "Device ID fetch failed, "
+		       "interface is not usable: %d\n", info->name,
+		       info->line, rv);
+		goto out_err;
+	}
+
+	capabilities = info->codec->capabilities(info->codec_data);
+	info->do_event_request = (capabilities
+				  & IPMI_SERIAL_SUPPORTS_EVENT_BUFFER);
+	if (capabilities & IPMI_SERIAL_NEEDS_GET_FLAGS_POLLING)
+		info->flag_timeout = POLLING_FLAG_TIMEOUT;
+	else
+		info->flag_timeout = NO_POLLING_FLAG_TIMEOUT;
+	info->flag_timer = info->flag_timeout;
+	info->supports_flags = (capabilities
+				& IPMI_SERIAL_SUPPORTS_GET_FLAGS);
+
+	if (info->do_event_request) {
+		if (try_enable_event_buffer(info) == 0)
+			info->has_event_buffer = 1;
+	}
+
+
+	snprintf(sysfs_name, sizeof(sysfs_name), "bmc:%s%d", info->name,
+		 info->line);
+
+	rv = ipmi_register_smi(&handlers,
+			       info,
+			       &info->device_id,
+			       info->port->dev,
+			       sysfs_name,
+			       info->slave_addr);
+	if (rv) {
+		printk(KERN_ERR PFX "Unable to register the "
+		       "interface with the IPMI message handler: %d\n",
+		       info->name, info->line, rv);
+		if (info->intf)
+			del_timer_sync(&info->timer);
+		info->intf = NULL;
+		goto out_err_stop_timer;
+	}
+
+	rv = ipmi_smi_add_proc_entry(info->intf, "type",
+				     type_file_read_proc,
+				     info, THIS_MODULE);
+	if (rv) {
+		printk(KERN_ERR PFX
+		       "Unable to create proc entry: %d\n", info->name,
+		       info->line, rv);
+		goto out_err_stop_timer;
+	}
+
+	rv = ipmi_smi_add_proc_entry(info->intf, "params",
+				     param_read_proc,
+				     info, THIS_MODULE);
+	if (rv) {
+		printk(KERN_ERR PFX
+		       "Unable to create proc entry: %d\n", info->name,
+		       info->line, rv);
+		goto out_err_stop_timer;
+	}
+
+	rv = ipmi_smi_add_proc_entry(info->intf, "serial_stats",
+				     stat_file_read_proc,
+				     info, THIS_MODULE);
+	if (rv) {
+		printk(KERN_ERR PFX
+		       "Unable to create proc entry: %d\n", info->name,
+		       info->line, rv);
+		goto out_err_stop_timer;
+	}
+
+	return 0;
+
+ out_err_stop_timer:
+	if (info->intf) {
+		del_timer_sync(&info->timer);
+		ipmi_unregister_smi(info->intf);
+		info->intf = NULL;
+	}
+ out_err:
+	/* Turn the receiver off and let it clear out. */
+	info->codec_data = NULL;
+	synchronize_sched();
+
+	info->codec->cleanup(info->alloc_codec_data);
+	return rv;
+}
+
+static void setup_intf(struct ipmi_serial_info *info,
+		       struct ipmi_serial_codec *codec)
+{
+	int rv;
+
+	info->alloc_codec_data = kmalloc(codec->size(), GFP_KERNEL);
+	if (!info->alloc_codec_data) {
+		printk(KERN_ERR PFX "Unable to allocate codec data\n",
+		       info->name, info->line);
+		return;
+	}
+
+	info->codec = codec;
+
+	/*
+	 * Tell the serial layer that we want to take over a specific
+	 * serial interface.
+	 */
+	info->port = uart_get_direct_port(info->name, info->line, 0);
+	if (!info->port) {
+		printk(KERN_ERR PFX "Unable to find serial port\n",
+		       info->name, info->line);
+		return;
+	}
+	info->orig_port_info = info->port->info;
+	info->port->info = &info->uinfo;
+
+	rv = info->port->ops->startup(info->port);
+	if (rv) {
+		info->port->info = info->orig_port_info;
+		uart_put_direct_port(info->port, 0);
+		info->port = NULL;
+		printk(KERN_ERR PFX "Unable setup serial port %d\n",
+		       info->name, info->line, rv);
+		return;
+	}
+
+	if (ipmi_serial_found(info)) {
+		info->port->info = info->orig_port_info;
+		info->port->ops->shutdown(info->port);
+		uart_put_direct_port(info->port, 0);
+		info->port = NULL;
+	}
+}
+
+static void free_info_memory(struct ipmi_serial_info *info)
+{
+	kfree(info->keepstr);
+	kfree(info);
+}
+
+static int name_line_from_str(const char *str, char *name, int len)
+{
+	if (str[0] >= '0' && str[0] <= '9') {
+		/* We convert a number to ttyS# */
+		strncpy(name, "ttyS", len);
+		return simple_strtoul(str, NULL, 10);
+	} else {
+		int size;
+		const char *s;
+		s = str;
+		while (*s && *s != ',' && (*s < '0' || *s > '9'))
+			s++;
+		size = s - str;
+		if (size >= len)
+			size = len - 1;
+		memcpy(name, str, size);
+		name[size] = '\0';
+		return simple_strtoul(s, NULL, 10);
+	}
+}
+
+/*
+ *	Setup a list of ipmi serial system interfaces.
+ */
+static void ipmi_serial_setup_one(const char *istr)
+{
+	struct ipmi_serial_codec *codec;
+	struct ipmi_serial_info  *info;
+	struct ipmi_serial_info  *cinfo;
+	char *str;
+	int i;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		printk(KERN_ERR NPFX "unable to allocate serial info: %s\n",
+		       istr);
+		return;
+	}
+	info->keepstr = kstrdup(istr, GFP_KERNEL);
+	if (!info->keepstr) {
+		printk(KERN_ERR NPFX "unable to allocate serial string: %s\n",
+		       istr);
+		kfree(info);
+		return;
+	}
+	str = info->keepstr;
+
+	spin_lock_init(&info->lock);
+	setup_timer(&info->timer, ipmi_serial_timeout, (long) info);
+	INIT_LIST_HEAD(&info->xmit_msgs);
+	INIT_LIST_HEAD(&info->hp_xmit_msgs);
+	INIT_LIST_HEAD(&info->msgs_to_deliver);
+	info->slave_addr = 0x20; /* default */
+
+	for (i = 0; i < SERIAL_NUM_STATS; i++)
+		atomic_set(&info->stats[i], 0);
+
+	/*
+	 * Decode str into name, options, codec, codec options.
+	 */
+	if (strlen(str) == 0) {
+		printk(KERN_ERR NPFX "Empty serial port name specified\n");
+		free_info_memory(info);
+		return;
+	}
+
+	info->line = name_line_from_str(str, info->name, sizeof(info->name));
+
+	/* First ',' points to serial port options */
+	info->options = strchr(str, ',');
+	if (info->options) {
+		*(info->options++) = '\0';
+
+		/* Second ',' points to the codec name. */
+		info->codec_name = strchr(info->options, ',');
+	}
+
+	if (info->codec_name) {
+		*(info->codec_name++) = '\0';
+
+		/* Third ',' points to the codec options. */
+		info->codec_options = strchr(info->codec_name, ',');
+	}
+
+	if (info->codec_options)
+		*(info->codec_options++) = 0;
+
+#ifdef __sparc__
+	if (!strcmp(info->name, "ttya")) {
+		strcpy(info->name, "ttyS");
+		info->line = 0;
+	}
+	if (!strcmp(info->name, "ttyb")) {
+		strcpy(info->name, "ttyS");
+		info->line = 1;
+	}
+#endif
+
+	info->direct.direct_data = info;
+	info->direct.handle_char = ipmi_serial_handle_char;
+	info->direct.push = ipmi_serial_push;
+	info->uinfo.xmit.buf = info->uart_buffer;
+	uart_circ_clear(&info->uinfo.xmit);
+	info->uinfo.flags = UIF_BOOT_ALLOCATED;
+	info->uinfo.direct = &info->direct;
+	tasklet_init(&info->uinfo.tlet, ipmi_serial_tx_ready,
+		     (unsigned long) info);
+	info->uinfo.flags |= UIF_TASKLET_SETUP;
+
+	mutex_lock(&list_lock);
+	/* Check for dups. */
+	list_for_each_entry(cinfo, &info_list, link) {
+		if ((strcmp(cinfo->name, info->name) == 0) &&
+					(cinfo->line == info->line)) {
+			printk(KERN_ERR NPFX "Duplicate port given: %s\n",
+			       str);
+			free_info_memory(info);
+			goto out_unlock;
+		}
+	}
+	list_add(&info->link, &info_list);
+
+	/* Try to match up this new interface with any registered codecs. */
+	list_for_each_entry(codec, &codec_list, link) {
+		if (strcmp(codec->name, info->codec_name) == 0) {
+			setup_intf(info, codec);
+			break;
+		}
+	}
+ out_unlock:
+	mutex_unlock(&list_lock);
+}
+
+static void ipmi_serial_remove_one(const char *str)
+{
+	struct ipmi_serial_info *info;
+	char                    *s;
+	int line;
+	char name[TTY_NAME_LEN];
+
+	line = name_line_from_str(str, name, sizeof(name));
+
+	s = strchr(str, ',');
+
+	mutex_lock(&list_lock);
+	list_for_each_entry(info, &info_list, link) {
+		if ((strcmp(name, info->name) == 0) && (info->line == line)) {
+			ipmi_serial_cleanup_one(info);
+			list_del(&info->link);
+			free_info_memory(info);
+			goto out_unlock;
+		}
+	}
+	printk(KERN_ERR NPFX "Could not find port to remove: %s.\n", str);
+ out_unlock:
+	mutex_unlock(&list_lock);
+}
+
+static int hotmod_handler(const char *istr, struct kernel_param *kp)
+{
+	char *str = kstrdup(istr, GFP_KERNEL);
+	char *s;
+	int  rv = -EINVAL;
+	int  len, i;
+	char *next, *curr;
+
+	if (!str)
+		return -ENOMEM;
+
+	/* Kill any trailing spaces, as we can get a "\n" from echo. */
+	len = strlen(str);
+	i = len - 1;
+	while ((i >= 0) && isspace(str[i])) {
+		str[i] = '\0';
+		i--;
+	}
+
+	for (curr = str; curr; curr = next) {
+		next = strchr(curr, ':');
+		if (next) {
+			*next = '\0';
+			next++;
+		}
+
+		s = strchr(curr, ',');
+		if (!s) {
+			printk(KERN_WARNING NPFX
+			       "No hotmod operation given.\n");
+			break;
+		}
+		*s = '\0';
+		s++;
+
+		if (strcmp(curr, "add") == 0) {
+			ipmi_serial_setup_one(s);
+			rv = len;
+		} else if (strcmp(curr, "remove") == 0) {
+			ipmi_serial_remove_one(s);
+			rv = len;
+		} else {
+			printk(KERN_WARNING NPFX
+			       "Invalid hotmod operation given: '%s'.\n",
+			       curr);
+			break;
+		}
+	}
+	kfree(str);
+
+	return rv;
+}
+
+static __init int init_ipmi_serial(void)
+{
+	int count = 0, len;
+	char *next, *curr, *str;
+
+	printk(KERN_INFO "IPMI Serial System Interface driver\n");
+
+	if (setup_str[0] == '\0') {
+		if (unload_when_empty) {
+			printk(KERN_WARNING NPFX "no interfaces specified\n");
+			return -ENODEV;
+		}
+		return 0;
+	}
+
+	curr = setup_str;
+	while (curr) {
+		next = strchr(curr, ':');
+		if (!next) {
+			str = kstrdup(curr, GFP_KERNEL);
+		} else {
+			/* Duplicate up to (but not including) the ':'. */
+			len = next - curr;
+			next++;
+			str = kmalloc(len + 1, GFP_KERNEL);
+			if (str) {
+				memcpy(str, curr, len);
+				str[len] = '\0';
+			}
+		}
+		if (!str) {
+			printk(KERN_ERR NPFX
+			       "could not allocate string setup: %s\n",
+			       curr);
+			if (count == 0)
+				return -ENOMEM;
+			else
+				/* We configured one, so don't error. */
+				return 0;
+			count++;
+		} else {
+			ipmi_serial_setup_one(str);
+			kfree(str);
+		}
+		curr = next;
+	}
+
+	return 0;
+}
+/*
+ * We have to initialize after the serial core has initialized because
+ * we needs its sysfs entries initialized.  So delay initialization to
+ * the end.
+ */
+late_initcall(init_ipmi_serial);
+
+static __exit void cleanup_ipmi_serial(void)
+{
+	struct ipmi_serial_info  *info, *s;
+
+	list_for_each_entry_safe(info, s, &info_list, link) {
+		list_del(&info->link);
+		free_info_memory(info);
+	}
+}
+module_exit(cleanup_ipmi_serial);
+
+static void ipmi_serial_cleanup_one(struct ipmi_serial_info *to_clean)
+{
+	int           rv;
+	unsigned long flags;
+	ipmi_smi_t    intf;
+
+	if (!to_clean)
+		return;
+
+	intf = to_clean->intf;
+
+	if (intf) {
+		to_clean->stop_operation = 1; /* Don't start anything new. */
+
+		del_timer_sync(&to_clean->timer);
+
+		/*
+		 * Interrupts and timeouts are stopped, now flush out
+		 * all the messages.
+		 */
+		spin_lock_irqsave(&to_clean->lock, flags);
+		while ((to_clean->state != SERIAL_EMPTY)
+				|| to_clean->msg_delivery_in_progress) {
+			spin_unlock_irqrestore(&to_clean->lock, flags);
+			msleep(10);
+			timeout_handling(to_clean, 10000);
+			spin_lock_irqsave(&to_clean->lock, flags);
+		}
+		to_clean->intf = NULL; /* No more messages allowed. */
+		spin_unlock_irqrestore(&to_clean->lock, flags);
+
+		/*
+		 * At this point we won't send any messages up, so we can
+		 * unregister the SMI.
+		 */
+		rv = ipmi_unregister_smi(intf);
+		if (rv) {
+			printk(KERN_ERR PFX
+			       "Unable to unregister device: errno=%d\n",
+			       to_clean->name, to_clean->line, rv);
+		}
+	}
+
+	if (to_clean->codec_data) {
+		to_clean->codec_data = NULL;
+		synchronize_sched();
+		to_clean->codec->cleanup(to_clean->alloc_codec_data);
+	}
+
+	if (to_clean->port) {
+		to_clean->uinfo.flags &= ~UIF_TASKLET_SETUP;
+		tasklet_kill(&to_clean->uinfo.tlet);
+		to_clean->port->ops->shutdown(to_clean->port);
+		to_clean->port->info = to_clean->orig_port_info;
+		uart_put_direct_port(to_clean->port, 0);
+	}
+}
+
+int ipmi_serial_codec_register(struct ipmi_serial_codec *codec)
+{
+	struct ipmi_serial_codec *c;
+	struct ipmi_serial_info  *info;
+
+	printk(KERN_INFO NPFX "Registering %s codec\n", codec->name);
+
+	mutex_lock(&list_lock);
+	/* Check for dups. */
+	list_for_each_entry(c, &codec_list, link) {
+		if (strcmp(c->name, codec->name) == 0) {
+			printk(KERN_WARNING NPFX
+			       "Registering duplicate codec: %s\n",
+			       codec->name);
+			mutex_unlock(&list_lock);
+			return -EBUSY;
+		}
+	}
+	list_add(&codec->link, &codec_list);
+
+	list_for_each_entry(info, &info_list, link) {
+		if (strcmp(info->codec_name, codec->name) == 0)
+			setup_intf(info, codec);
+	}
+	mutex_unlock(&list_lock);
+	return 0;
+}
+EXPORT_SYMBOL(ipmi_serial_codec_register);
+
+void ipmi_serial_codec_unregister(struct ipmi_serial_codec *codec)
+{
+	struct ipmi_serial_info *info;
+
+	/*
+	 * Guaranteed to be no users on any devices on this codec, it
+	 * can't unregister unless it's module is being unloaded and
+	 * the module's refcount is zero.
+	 */
+
+	printk(KERN_INFO NPFX "Unregistering %s codec\n", codec->name);
+
+	mutex_lock(&list_lock);
+	list_del(&codec->link);
+	list_for_each_entry(info, &info_list, link) {
+		if (info->codec == codec)
+			/* Does not remove the entry from the list. */
+			ipmi_serial_cleanup_one(info);
+	}
+	mutex_unlock(&list_lock);
+}
+EXPORT_SYMBOL(ipmi_serial_codec_unregister);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
+MODULE_DESCRIPTION("Support for IPMI over serial.");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_serial_direct.c linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_serial_direct.c
--- linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_serial_direct.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_serial_direct.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,643 @@
+/*
+ * ipmi_serial_direct.c
+ * Serial interface encoder and decoder routines for IPMI direct
+ * serial interfaces.
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *         Corey Minyard <cminyard@mvista.com>
+ *
+ * Copyright 2006 MontaVista Software Inc.
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/ipmi_smi.h>
+#include <linux/ipmi_msgdefs.h>
+#include <linux/ipmi_serial_sm.h>
+#include <linux/spinlock.h>
+
+#define PFX "ipmi_serial_direct: "
+
+struct tm_options {
+#define ATTN_OPTION "attn"
+	int attn;
+	int attn_forced; /* Set by command line. */
+
+#define EATTN_OPTION "eattn"
+	int eattn;
+	int eattn_forced; /* Set by command line. */
+	unsigned char eattn_char;
+
+#define RQADDR_OPTION "rqa"
+	unsigned char rqaddr;
+#define RSADDR_OPTION "rsa"
+	unsigned char rsaddr;
+};
+
+#define DEFAULT_RSADDR 0x20
+#define DEFAULT_RQADDR 0x61
+
+/*
+ * Give the remote end this much time (100ms) to send a handshake
+ * character before we give up.
+ */
+#define DM_HANDSHAKE_TIME 100000
+
+/*
+ * We have 4 bytes more for the header and then the ending checksum
+ * above the KCS header size we get/send to the upper layer.
+ */
+#define DM_HEADER_OVERHEAD_BYTES 5
+
+/*
+ * We have start, stop, 4 bytes more for the header beyond the header
+ * we get, and the checksum.  The start and stop do not need escaping,
+ * thus do not need doubling, but the rest do.  So we have:
+ *    2 + (5 * 2) = 12
+ */
+#define DM_OVERHEAD_BYTES (2 + (DM_HEADER_OVERHEAD_BYTES * 2))
+
+struct ipmi_serial_codec_data {
+	struct ipmi_serial_info *info;
+
+	unsigned char xmit_chars[IPMI_MAX_MSG_LENGTH * 2 + DM_OVERHEAD_BYTES];
+	unsigned int  xmit_chars_len;
+	unsigned int  xmit_chars_pos;
+
+	unsigned char seqno;
+	unsigned int seqnum_table[0x40];
+
+	unsigned char xmit_msg[IPMI_MAX_MSG_LENGTH + DM_HEADER_OVERHEAD_BYTES];
+	unsigned int  xmit_msg_len;
+
+	unsigned char recv_msg[IPMI_MAX_MSG_LENGTH + DM_HEADER_OVERHEAD_BYTES];
+	unsigned int  recv_msg_len;
+	int           in_recv_msg;
+	int           in_escape;
+	int           recv_msg_too_many;
+
+	spinlock_t lock;
+
+	/*
+	 * Used to time receiving a handshake.  We give the remote end
+	 * so much time to send the handshake before we give up and
+	 * just send.
+	 */
+	int handshake_time;
+
+	struct tm_options options;
+};
+
+#define SUN_MFG_ID		0x00002a
+#define SUN_CP3020_PROD_ID	0x0bcc
+
+/*
+ * BMCs that support using the ASCII escape char (0x1b) as attention.
+ */
+static struct { unsigned int mfg_id, prod_id; } attn_bmcs[] =
+{
+	{ 0, 0 }
+};
+
+/*
+ * BMCs that use a special escape sequence (0xaa <char>) as attention.
+ */
+static struct { unsigned int mfg_id, prod_id, val; } eattn_bmcs[] =
+{
+	{ SUN_MFG_ID,		SUN_CP3020_PROD_ID,		0x47 },
+	{ 0, 0 }
+};
+
+static void check_devid_options(struct ipmi_serial_codec_data *data,
+				struct ipmi_device_id *id)
+{
+	int i;
+
+	if (!data->options.attn_forced) {
+		for (i = 0; attn_bmcs[i].mfg_id != 0; i++) {
+			if ((id->manufacturer_id == attn_bmcs[i].mfg_id)
+			    && (id->product_id == attn_bmcs[i].prod_id)) {
+				data->options.attn = 1;
+				break;
+			}
+		}
+	}
+	if (!data->options.eattn_forced) {
+		for (i = 0; eattn_bmcs[i].mfg_id != 0; i++) {
+			if ((id->manufacturer_id == eattn_bmcs[i].mfg_id)
+			    && (id->product_id == eattn_bmcs[i].prod_id)) {
+				data->options.eattn = 1;
+				data->options.eattn_char = eattn_bmcs[i].val;
+				break;
+			}
+		}
+	}
+}
+
+static int check_options(struct ipmi_serial_codec_data *data,
+			 const char *options)
+{
+	const char *s;
+	char *optval;
+	int  optval_len;
+	char *next;
+	int  len;
+	char *end;
+
+	for (s = options; s; s = next) {
+		next = strchr(s, '+');
+		if (next) {
+			len = next - s;
+			next++;
+		} else
+			len = strlen(s);
+
+		optval = strchr(s, '=');
+		if (next && optval >= next)
+			optval = NULL;
+		if (optval) {
+			len = optval - s;
+			optval++;
+			if (next) {
+				optval_len = next - optval;
+				next++;
+			} else
+				optval_len = strlen(optval);
+		} else
+			optval_len = 0;
+		end = NULL;
+		if (strncmp(ATTN_OPTION, s, len) == 0) {
+			data->options.attn = 1;
+			data->options.attn_forced = 1;
+		} else if (strncmp("no" ATTN_OPTION, s, len) == 0) {
+			data->options.attn = 0;
+			data->options.attn_forced = 1;
+		} else if (strncmp(EATTN_OPTION, s, len) == 0) {
+			data->options.eattn = 1;
+			data->options.eattn_forced = 1;
+			if (optval)
+				data->options.eattn_char
+					= simple_strtoul(optval, &end, 0);
+			else
+				data->options.eattn_char = 0x47;
+		} else if (strncmp("no" EATTN_OPTION, s, len) == 0) {
+			data->options.attn = 0;
+			data->options.attn_forced = 1;
+		} else if (strncmp(RQADDR_OPTION, s, len) == 0) {
+			if (optval)
+				data->options.rqaddr
+					= simple_strtoul(optval, &end, 0);
+			else {
+				printk(KERN_WARNING PFX
+				       "rqa option given without value\n");
+				return -EINVAL;
+			}
+		} else if (strncmp(RSADDR_OPTION, s, len) == 0) {
+			if (optval)
+				data->options.rsaddr
+					= simple_strtoul(optval, &end, 0);
+			else {
+				printk(KERN_WARNING PFX
+				       "rsa option given without value\n");
+				return -EINVAL;
+			}
+		} else {
+			printk(KERN_WARNING PFX "Unknown options: %s\n",
+			       options);
+			return -EINVAL;
+		}
+
+		if (optval && !end) {
+			printk(KERN_WARNING PFX "No value needed at: %s\n", s);
+			return -EINVAL;
+		}
+		if (optval && end != (optval + optval_len)) {
+			printk(KERN_WARNING PFX "Invalid value for: %s\n", s);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int sd_add_options(struct ipmi_serial_codec_data *data, char *page)
+{
+	char pfx = ',';
+	char *out = page;
+
+	if (data->options.attn) {
+		out += sprintf(out, "%cattn", pfx);
+		pfx = '+';
+	}
+	if (data->options.eattn) {
+		out += sprintf(out, "%ceattn", pfx);
+		if (data->options.eattn_char != 0x47)
+			out += sprintf(out, "=0x%x", data->options.eattn_char);
+		pfx = '+';
+	}
+	if (data->options.rqaddr != DEFAULT_RQADDR) {
+		out += sprintf(out, "%crqa=0x%x", pfx, data->options.rqaddr);
+		pfx = '+';
+	}
+	if (data->options.rsaddr != DEFAULT_RSADDR)
+		out += sprintf(out, "%crsa=0x%x", pfx, data->options.rsaddr);
+
+	return out - page;
+}
+
+static unsigned char ipmb_checksum(unsigned char *data, int size)
+{
+	unsigned char csum = 0;
+
+	for (; size > 0; size--, data++)
+		csum += *data;
+
+	return -csum;
+}
+
+#define DM_START_CHAR		0xA0
+#define DM_STOP_CHAR		0xA5
+#define DM_PACKET_HANDSHAKE	0xA6
+#define DM_DATA_ESCAPE_CHAR	0xAA
+
+static void format_msg(struct ipmi_serial_codec_data *data,
+		       const unsigned char *msg, unsigned int msg_len)
+{
+	unsigned int i;
+	unsigned int len = 0;
+	unsigned char *c = data->xmit_chars;
+
+	c[len++] = 0xA0;
+	for (i = 0; i < msg_len; i++) {
+		switch (msg[i]) {
+		case 0xA0:
+			c[len++] = 0xAA;
+			c[len++] = 0xB0;
+			break;
+
+		case 0xA5:
+			c[len++] = 0xAA;
+			c[len++] = 0xB5;
+			break;
+
+		case 0xA6:
+			c[len++] = 0xAA;
+			c[len++] = 0xB6;
+			break;
+
+		case 0xAA:
+			c[len++] = 0xAA;
+			c[len++] = 0xBA;
+			break;
+
+		case 0x1B:
+			c[len++] = 0xAA;
+			c[len++] = 0x3B;
+			break;
+
+		default:
+			c[len++] = msg[i];
+		}
+
+	}
+	c[len++] = 0xA5;
+	data->xmit_chars_len = len;
+	data->xmit_chars_pos = 0;
+}
+
+static void handle_recv_msg(struct ipmi_serial_codec_data *data)
+{
+	unsigned int seq;
+	unsigned char *m = data->recv_msg;
+	unsigned int len = data->recv_msg_len;
+	int          i;
+
+	if (len < 8) {
+		/* Messages must be at least 8 bytes to be valid. */
+		ipmi_serial_ll_protocol_violation(data->info);
+		return;
+	}
+
+	/* Note that this validates both checksums in one shot. */
+	if (ipmb_checksum(m, len) != 0) {
+		ipmi_serial_ll_checksum_error(data->info);
+		return;
+	}
+	len--; /* Remove the checksum */
+
+	seq = m[4] >> 2;
+
+	/* Pull the rsLun and the NetFN together. */
+	m[0] = (m[1] & 0xfc) | (m[4] & 0x3);
+	/* Now the rest of the data */
+	for (i = 1; i < (len - 4); i++)
+		m[i] = m[i + 4];
+	len -= 4;
+
+	ipmi_serial_ll_recv(data->info, m, len, data->seqnum_table[seq]);
+}
+
+static void try_to_send_data(struct ipmi_serial_codec_data *data)
+{
+	unsigned char *c;
+	unsigned int  left;
+	unsigned int  sent;
+
+	if (!data->xmit_chars_len)
+		return;
+
+	if (data->handshake_time > 0)
+		return;
+
+	c = data->xmit_chars + data->xmit_chars_pos;
+	left = data->xmit_chars_len - data->xmit_chars_pos;
+	sent = ipmi_serial_ll_xmit(data->info, c, left);
+	if (sent == left) {
+		/* We are done with this message. */
+		if (data->xmit_msg_len) {
+			/* Send the next message we have waiting. */
+			format_msg(data, data->xmit_msg, data->xmit_msg_len);
+			data->xmit_msg_len = 0;
+		} else {
+			/* Nothing to do. */
+			data->xmit_chars_len = 0;
+		}
+		/* Wait for the handshake. */
+		data->handshake_time = DM_HANDSHAKE_TIME;
+	} else {
+		data->xmit_chars_pos += sent;
+	}
+}
+
+static int sd_setup_termios(struct ktermios *t)
+{
+	/* Nothing to do, the default is fine. */
+	return 0;
+}
+
+static int sd_init(struct ipmi_serial_codec_data *data,
+		   struct ipmi_serial_info *info,
+		   const char *options)
+{
+	memset(data, 0, sizeof(*data));
+	spin_lock_init(&data->lock);
+	data->info = info;
+
+	/* Pick some good defaults for header addresses. */
+	data->options.rsaddr = DEFAULT_RSADDR;
+	data->options.rqaddr = DEFAULT_RQADDR;
+
+	return check_options(data, options);
+}
+
+static void sd_cleanup(struct ipmi_serial_codec_data *data)
+{
+	/* Nothing to do. */
+}
+
+static int sd_size(void)
+{
+	return sizeof(struct ipmi_serial_codec_data);
+}
+
+static void sd_handle_char(struct ipmi_serial_codec_data *data,
+			   unsigned char ch)
+{
+	unsigned int len = data->recv_msg_len;
+	unsigned long flags;
+
+	switch (ch) {
+	case DM_START_CHAR:
+		if (data->in_recv_msg)
+			ipmi_serial_ll_protocol_violation(data->info);
+		data->in_recv_msg = 1;
+		data->recv_msg_len = 0;
+		data->recv_msg_too_many = 0;
+		data->in_escape = 0;
+		break;
+
+	case DM_STOP_CHAR:
+		if (!data->in_recv_msg)
+			ipmi_serial_ll_protocol_violation(data->info);
+		else if (data->in_escape) {
+			data->in_recv_msg = 0;
+			ipmi_serial_ll_protocol_violation(data->info);
+		} else if (data->recv_msg_too_many) {
+			data->in_recv_msg = 0;
+			ipmi_serial_ll_protocol_violation(data->info);
+		} else {
+			data->in_recv_msg = 0;
+			handle_recv_msg(data);
+		}
+		data->in_escape = 0;
+		break;
+
+	case DM_PACKET_HANDSHAKE:
+		/* Got a handshake, we can send now. */
+		spin_lock_irqsave(&data->lock, flags);
+		data->handshake_time = 0;
+		try_to_send_data(data);
+		spin_unlock_irqrestore(&data->lock, flags);
+		data->in_escape = 0;
+		break;
+
+	case DM_DATA_ESCAPE_CHAR:
+		data->in_escape = 1;
+		break;
+
+	case 0x1b:
+		if (data->options.attn)
+			ipmi_serial_ll_attn(data->info);
+		break;
+
+	default:
+		if (!data->in_recv_msg)
+			/* Ignore characters outside of messages. */
+			break;
+
+		if (data->in_escape) {
+			data->in_escape = 0;
+			if (data->options.eattn
+					&& (ch == data->options.eattn_char)) {
+				ipmi_serial_ll_attn(data->info);
+				goto out;
+			}
+
+			switch (ch) {
+			case 0xB0:
+				ch = DM_START_CHAR;
+				break;
+			case 0xB5:
+				ch = DM_STOP_CHAR;
+				break;
+			case 0xB6:
+				ch = DM_PACKET_HANDSHAKE;
+				break;
+			case 0xBA:
+				ch = DM_DATA_ESCAPE_CHAR;
+				break;
+			case 0x3B:
+				ch = 0x1b;
+				break;
+			default:
+				ipmi_serial_ll_protocol_violation(data->info);
+				data->recv_msg_too_many = 1;
+				return;
+			}
+		}
+
+		if (!data->recv_msg_too_many) {
+			if (len >= sizeof(data->recv_msg)) {
+				data->recv_msg_too_many = 1;
+				break;
+			}
+
+			data->recv_msg[len] = ch;
+			data->recv_msg_len++;
+		}
+		break;
+	}
+ out:
+	return;
+}
+
+static int sd_send_msg(struct ipmi_serial_codec_data *data,
+		       const unsigned char *msg, unsigned int msg_len,
+		       unsigned int seq)
+{
+	unsigned long flags;
+	int           rv = 0;
+	unsigned char *m;
+	unsigned int  i, j;
+	unsigned char seqno;
+
+	if (msg_len > IPMI_MAX_MSG_LENGTH)
+		return -EFBIG;
+	if (msg_len < 2)
+		return -EINVAL;
+
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->xmit_msg_len) {
+		/* Something is still waiting to be sent. */
+		rv = -EBUSY;
+		goto out_unlock;
+	}
+
+	i = 0;
+	m = data->xmit_msg;
+	m[i++] = data->options.rsaddr;	/* rsAddr */
+	m[i++] = msg[0];		/* NetFN/rsLUN */
+	m[i++] = ipmb_checksum(m, 2);	/* checksum1 */
+	m[i++] = data->options.rqaddr;	/* rqAddr */
+
+	seqno = data->seqno;
+	data->seqno = (data->seqno + 1) & 0x3f;
+	data->seqnum_table[seqno] = seq;
+	m[i++] = seqno << 2;		/* seqno/rqLUN */
+	m[i++] = msg[1];		/* cmd */
+	for (j = 2; j < msg_len; j++)
+		m[i++] = msg[j];	/* data */
+	m[i] = ipmb_checksum(m + 3, i - 3); /* checksum2 */
+	i++;
+
+	if (data->xmit_chars_len == 0) {
+		/* Transmit queue is empty, just format it now to go. */
+		format_msg(data, m, i);
+		try_to_send_data(data);
+	} else {
+		/* Save it for after the transmit queue emptying. */
+		data->xmit_msg_len = i;
+	}
+
+ out_unlock:
+	spin_unlock_irqrestore(&data->lock, flags);
+	return rv;
+}
+
+static void sd_tx_ready(struct ipmi_serial_codec_data *data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->lock, flags);
+	try_to_send_data(data);
+	spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static void sd_timer_tick(struct ipmi_serial_codec_data *data,
+			  unsigned int time_since_last)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->handshake_time > 0) {
+		data->handshake_time -= time_since_last;
+		if (data->handshake_time <= 0)
+			try_to_send_data(data);
+	}
+	spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static unsigned int sd_capabilities(struct ipmi_serial_codec_data *data)
+{
+	unsigned int c = (IPMI_SERIAL_SUPPORTS_GET_FLAGS
+			  | IPMI_SERIAL_SUPPORTS_EVENT_BUFFER);
+	if ((data->options.attn) || (data->options.eattn))
+		c |= IPMI_SERIAL_HAS_ATTN;
+	else
+		c |= IPMI_SERIAL_NEEDS_GET_FLAGS_POLLING;
+	return c;
+}
+
+static struct ipmi_serial_codec sd_codec = {
+	.owner = THIS_MODULE,
+	.name  = "Direct",
+
+	.capabilities	= sd_capabilities,
+	.setup_termios	= sd_setup_termios,
+	.init		= sd_init,
+	.cleanup	= sd_cleanup,
+	.size		= sd_size,
+	.send_msg	= sd_send_msg,
+	.handle_char	= sd_handle_char,
+	.check_dev_id   = check_devid_options,
+	.timer_tick     = sd_timer_tick,
+	.tx_ready	= sd_tx_ready,
+	.add_options	= sd_add_options
+};
+
+static __init int
+init_ipmi_serial_direct_codec(void)
+{
+	return ipmi_serial_codec_register(&sd_codec);
+}
+
+module_init(init_ipmi_serial_direct_codec);
+
+static __exit void
+exit_ipmi_serial_direct_codec(void)
+{
+	ipmi_serial_codec_unregister(&sd_codec);
+}
+module_exit(exit_ipmi_serial_direct_codec);
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_serial_radisys_ascii.c linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_serial_radisys_ascii.c
--- linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_serial_radisys_ascii.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_serial_radisys_ascii.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,611 @@
+/*
+ * ipmi_serial_radisys_ascii.c
+ * Serial interface encoder and decoder routines for Radisys ASCII mode.
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *         Corey Minyard <cminyard@mvista.com>
+ *
+ * Copyright 2006 MontaVista Software Inc.
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/ipmi_smi.h>
+#include <linux/ipmi_msgdefs.h>
+#include <linux/ipmi_serial_sm.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+
+#define PFX "ipmi_serial_radisys_ascii: "
+
+/*
+ * Two bytes for every character plus the trailing newline.  There are
+ * five overhead bytes that are for the header and checksum beyond the
+ * KCS header we get/send to the upper layer..
+ */
+#define RA_OVERHEAD 5
+#define RA_MAX_CHARS_SIZE (((IPMI_MAX_MSG_LENGTH + RA_OVERHEAD) * 2) + 4)
+
+/*
+ * Give the remote end this much time (100ms) to send a response
+ * before we give up and retry the given number of times.
+ */
+#define RA_HANDSHAKE_TIME    5000000
+#define RA_HANDSHAKE_RETRIES 5
+
+struct ipmi_serial_codec_data {
+	struct ipmi_serial_info *info;
+
+	unsigned char xmit_chars[RA_MAX_CHARS_SIZE];
+	unsigned int  xmit_chars_len;
+	unsigned int  xmit_chars_pos;
+	unsigned int  xmit_chars_seq;
+	unsigned char xmit_chars_netfn;
+	unsigned char xmit_chars_cmd;
+
+	unsigned char recv_chars[RA_MAX_CHARS_SIZE];
+	unsigned int  recv_chars_len;
+	int           recv_chars_too_many;
+
+	unsigned char seqno;
+	unsigned int seqnum_table[0x40];
+
+	unsigned char xmit_msg[IPMI_MAX_MSG_LENGTH + RA_OVERHEAD];
+	unsigned int  xmit_msg_len;
+	unsigned int  xmit_msg_seq;
+	unsigned char xmit_msg_netfn;
+	unsigned char xmit_msg_cmd;
+	unsigned char recv_msg[IPMI_MAX_MSG_LENGTH + RA_OVERHEAD];
+	unsigned int  recv_msg_len;
+
+	unsigned char bmc_i2c_addr;
+	unsigned char smi_i2c_addr;
+
+	/*
+	 * Used to time receiving the IPMB address.
+	 */
+	int handshake_time;
+	int handshake_retries_left;
+	int handshake_done;
+
+	spinlock_t lock;
+
+	void (*recv_msg_handler)(struct ipmi_serial_codec_data *data,
+				 const unsigned char *msg,
+				 unsigned int len);
+};
+
+static int ra_add_options(struct ipmi_serial_codec_data *data, char *page)
+{
+	return 0;
+}
+
+static unsigned char
+ipmb_checksum(const unsigned char *data, int size)
+{
+	unsigned char csum = 0;
+
+	for (; size > 0; size--, data++)
+		csum += *data;
+
+	return -csum;
+}
+
+static unsigned char hex2char[16] = {
+	'0', '1', '2', '3', '4', '5', '6', '7',
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+static void format_msg(struct ipmi_serial_codec_data *data,
+		       const unsigned char *msg, unsigned int msg_len)
+{
+	int i;
+	int len;
+	unsigned char *c = data->xmit_chars;
+
+	/*
+	 * No need for checks on the output length, the output buffer is
+	 * guaranteed to be big enough.
+	 */
+	len = 0;
+	for (i = 0; i < msg_len; i++) {
+		c[len++] = hex2char[msg[i] >> 4];
+		c[len++] = hex2char[msg[i] & 0xf];
+	}
+	c[len++] = 0x0d;
+
+	data->xmit_chars_pos = 0;
+	data->xmit_chars_len = len;
+	data->xmit_chars_seq = data->xmit_msg_seq;
+	data->xmit_chars_netfn = data->xmit_msg_netfn;
+	data->xmit_chars_cmd = data->xmit_msg_cmd;
+}
+
+static int fromhex(unsigned char c)
+{
+	if (isdigit(c))
+		return c - '0';
+	else if (isxdigit(c))
+		return tolower(c) - 'a' + 10;
+	else
+		return -EINVAL;
+}
+
+/*
+ * Called when the 0x0d is seen.
+ */
+static int unformat_msg(struct ipmi_serial_codec_data *data)
+{
+	unsigned char *r = data->recv_chars;
+	unsigned char *o = data->recv_msg;
+	unsigned int len = data->recv_chars_len;
+	unsigned int p = 0;
+	unsigned int i = 0;
+	int          rv;
+
+	while (p < len) {
+		if (i > sizeof(data->recv_msg))
+			return -EFBIG;
+		rv = fromhex(r[p]);
+		if (rv < 0)
+			return rv;
+		o[i] = rv << 4;
+		p++;
+		if (p >= len)
+			return -EINVAL;
+		rv = fromhex(r[p]);
+		if (rv < 0)
+			return rv;
+		o[i] |= rv;
+		p++;
+		i++;
+	}
+	data->recv_msg_len = i;
+	return 0;
+}
+
+static void handle_recv_msg(struct ipmi_serial_codec_data *data)
+{
+	unsigned int seq;
+	unsigned char *m = data->recv_msg;
+	unsigned int len = data->recv_msg_len;
+	int          i;
+
+	if (data->recv_msg_handler) {
+		data->recv_msg_handler(data, m, len);
+		return;
+	}
+
+	if (len < 8) {
+		/* Messages must be at least 8 bytes */
+		ipmi_serial_ll_protocol_violation(data->info);
+		return;
+	}
+
+	if (m[3] == data->bmc_i2c_addr) {
+		if (ipmb_checksum(m, len) != 0) {
+			ipmi_serial_ll_checksum_error(data->info);
+			return;
+		}
+		/* Remove the final checksum. */
+		len--;
+
+		/*
+		 * It's a message straight from the BMC (a response).
+		 * Take the data from the header that we need and
+		 * write over the header.
+		 */
+		m[0] = (m[1] & 0xfc) | (m[4] & 0x03);
+		m[1] = m[5];
+		seq = m[4] >> 2;
+		for (i = 2; i < (len - 4); i++)
+			m[i] = m[i+4];
+		ipmi_serial_ll_recv(data->info, m, len - 4,
+				    data->seqnum_table[seq]);
+	} else {
+		/* Not from the BMC, must be from the IPMB. */
+
+		if ((len + 3) > IPMI_MAX_MSG_LENGTH) {
+			ipmi_serial_ll_protocol_violation(data->info);
+			return;
+		}
+
+		/* Make room for a get message command header. */
+		for (i = len; i > 0; i--)
+			/*
+			 * Note: This is i + 3, not i + 4, because the
+			 * GET_MSG response does not have the
+			 * destination address in the message.  So we
+			 * write over that field.
+			 */
+			m[i + 3] = m[i];
+		/* Get message command header. */
+		m[0] = IPMI_NETFN_APP_RESPONSE << 2;
+		m[1] = IPMI_GET_MSG_CMD;
+		m[2] = 0; /* completion code */
+		m[3] = 0; /* channel */
+		ipmi_serial_ll_async(data->info, m, len + 3);
+	}
+}
+
+static void try_to_send_data(struct ipmi_serial_codec_data *data,
+			     unsigned long *flags)
+{
+	unsigned char *c;
+	unsigned int  left;
+	unsigned int  sent;
+
+	if (!data->xmit_chars_len)
+		return;
+
+ restart:
+	c = data->xmit_chars + data->xmit_chars_pos;
+	left = data->xmit_chars_len - data->xmit_chars_pos;
+	sent = ipmi_serial_ll_xmit(data->info, c, left);
+	if (sent == left) {
+		/* We are done with this message. */
+
+		if ((data->xmit_chars_netfn == IPMI_NETFN_APP_REQUEST)
+		    && (data->xmit_chars_cmd == IPMI_SEND_MSG_CMD)) {
+			/*
+			 * The transmitted characters will not get a
+			 * response from a send message, it goes
+			 * straight out onto the IPMB.  So simulate
+			 * the response.
+			 */
+			char msg[3];
+			spin_unlock_irqrestore(&data->lock, *flags);
+			/* Make into response */
+			msg[0] = (data->xmit_chars_netfn | 1) << 2;
+			msg[1] = data->xmit_chars_cmd;
+			msg[2] = 0;
+			ipmi_serial_ll_recv(data->info, msg, 3,
+					    data->xmit_chars_seq);
+			spin_lock_irqsave(&data->lock, *flags);
+		}
+
+		if (data->xmit_msg_len) {
+			/* Send the next message we have waiting. */
+			format_msg(data, data->xmit_msg, data->xmit_msg_len);
+			data->xmit_msg_len = 0;
+			goto restart;
+		} else {
+			/* Nothing to do. */
+			data->xmit_chars_len = 0;
+		}
+	} else {
+		data->xmit_chars_pos += sent;
+	}
+}
+
+static int ra_setup_termios(struct ktermios *t)
+{
+	/* Nothing to do, the default is fine. */
+	return 0;
+}
+
+#define RA_OEM1_NETFN		0x30
+#define RA_CONTROLLER_OEM_NETFN	0x3e
+#define RA_GET_IPMB_ADDR_CMD	0x12
+static unsigned char get_ipmbaddr_msg1[] = { 0x01, /* dest addr */
+					     RA_OEM1_NETFN << 2,
+					     0x3f, /* checksum1 */
+					     0x01, /* source addr */
+					     0x00, /* seq num/rsLUN */
+					     RA_GET_IPMB_ADDR_CMD,
+					     0xed  /* checksum2 */
+};
+
+static unsigned char get_ipmbaddr_msg2[] = { 0x01, /* dest addr */
+					     RA_CONTROLLER_OEM_NETFN << 2,
+					     0x07, /* checksum1 */
+					     0x01, /* source addr */
+					     0x00, /* seq num/rsLUN */
+					     RA_GET_IPMB_ADDR_CMD,
+					     0xed  /* checksum2 */
+};
+
+static void handle_init_getipmbaddr(struct ipmi_serial_codec_data *data,
+				    const unsigned char *msg,
+				    unsigned int len)
+{
+	unsigned long flags;
+
+	if (len < 8)
+		return;
+	if (ipmb_checksum(msg, len) != 0)
+		return;
+	len--;
+
+	if (((msg[1] >> 2) != (RA_OEM1_NETFN | 1)
+	     && (msg[1] >> 2) != (RA_CONTROLLER_OEM_NETFN | 1))
+	    || (msg[5] != RA_GET_IPMB_ADDR_CMD))
+		return;
+
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->handshake_done) {
+		spin_unlock_irqrestore(&data->lock, flags);
+		return;
+	}
+
+	if (msg[6] != 0) {
+		if ((msg[1] >> 2) == (RA_OEM1_NETFN | 1)) {
+			unsigned long flags;
+
+			format_msg(data, get_ipmbaddr_msg2,
+				   sizeof(get_ipmbaddr_msg2));
+			try_to_send_data(data, &flags);
+			spin_unlock_irqrestore(&data->lock, flags);
+		} else {
+			printk(KERN_ERR "IPMI: RadisysAscii: Got error"
+			       " fetching the IPMB address, this may not"
+			       " be a Radisys system.\n");
+			data->handshake_done = 1;
+			spin_unlock_irqrestore(&data->lock, flags);
+			ipmi_serial_ll_init_complete(data->info, 0, -EINVAL);
+		}
+		return;
+	}
+
+	data->bmc_i2c_addr = msg[7];
+	data->recv_msg_handler = NULL;
+	data->handshake_done = 1;
+	spin_unlock_irqrestore(&data->lock, flags);
+	ipmi_serial_ll_init_complete(data->info, data->bmc_i2c_addr, 0);
+}
+
+static int ra_init(struct ipmi_serial_codec_data *data,
+		   struct ipmi_serial_info *info,
+		   const char *options)
+{
+	memset(data, 0, sizeof(*data));
+	spin_lock_init(&data->lock);
+	data->info = info;
+	data->bmc_i2c_addr = 1; /* Initial setting should work ok. */
+	data->smi_i2c_addr = 1; /* Initial setting should work ok. */
+
+	data->handshake_time = RA_HANDSHAKE_TIME;
+	data->handshake_retries_left = RA_HANDSHAKE_RETRIES;
+
+	return 0;
+}
+
+static int ra_start(struct ipmi_serial_codec_data *data)
+{
+	unsigned long flags;
+
+	data->recv_msg_handler = handle_init_getipmbaddr;
+	spin_lock_irqsave(&data->lock, flags);
+	format_msg(data, get_ipmbaddr_msg1, sizeof(get_ipmbaddr_msg1));
+	try_to_send_data(data, &flags);
+	spin_unlock_irqrestore(&data->lock, flags);
+	return 0;
+}
+
+static void ra_cleanup(struct ipmi_serial_codec_data *data)
+{
+	/* Nothing to do. */
+}
+
+static int ra_size(void)
+{
+	return sizeof(struct ipmi_serial_codec_data);
+}
+
+static void ra_handle_char(struct ipmi_serial_codec_data *data,
+			   unsigned char ch)
+{
+	unsigned int len = data->recv_chars_len;
+	unsigned char *r;
+	int           rv;
+
+	if (ch == 0x0d) {
+		/* End of command, handle it. */
+		if (data->recv_chars_too_many) {
+			/* Input data overrun. */
+			ipmi_serial_ll_protocol_violation(data->info);
+			data->recv_chars_too_many = 0;
+			data->recv_chars_len = 0;
+			return;
+		}
+		rv = unformat_msg(data);
+		if (rv) {
+			/* Bad input data. */
+			ipmi_serial_ll_protocol_violation(data->info);
+			return;
+		}
+		handle_recv_msg(data);
+		data->recv_chars_len = 0;
+		return;
+	}
+
+	if (data->recv_chars_too_many)
+		return;
+
+	r = data->recv_chars;
+
+	if (len >= sizeof(data->recv_chars)) {
+		data->recv_chars_too_many = 1;
+	} else if (isspace(r[len-1]) && isspace(ch)) {
+		/* Ignore multiple spaces together. */
+	} else {
+		r[len] = ch;
+		data->recv_chars_len++;
+	}
+}
+
+static int ra_send_msg(struct ipmi_serial_codec_data *data,
+		       const unsigned char *msg, unsigned int msg_len,
+		       unsigned int seq)
+{
+	unsigned long flags;
+	int           rv = 0;
+	int           i, j;
+	unsigned char seqno;
+
+	if (msg_len > IPMI_MAX_MSG_LENGTH)
+		return -EFBIG;
+	if (msg_len < 2)
+		return -EINVAL;
+
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->xmit_msg_len) {
+		/* Something is still waiting to be sent. */
+		goto out_unlock;
+		rv = -EBUSY;
+	}
+
+	data->xmit_msg_netfn = msg[0] >> 2;
+	data->xmit_msg_cmd = msg[1];
+	data->xmit_msg_seq = seq;
+	i = 0;
+	if ((data->xmit_msg_netfn == IPMI_NETFN_APP_REQUEST)
+	    && (data->xmit_msg_cmd == IPMI_SEND_MSG_CMD)) {
+		if ((msg[2] & 0xf) != 0) {
+			/* Only channels 0 is supported. */
+			rv = -EINVAL;
+			goto out_unlock;
+		}
+		/*
+		 * Skip over the message header and send the raw IPMB
+		 * message.
+		 */
+		for (j = 3; j < msg_len; j++)
+			data->xmit_msg[i++] = msg[j];
+	} else {
+		data->xmit_msg[i++] = data->bmc_i2c_addr;
+		data->xmit_msg[i++] = msg[0];		/* NetFN/LUN */
+		data->xmit_msg[i++] = ipmb_checksum(data->xmit_msg, 2);
+		data->xmit_msg[i++] = data->smi_i2c_addr;
+		seqno = data->seqno;
+		data->seqno = (data->seqno + 1) & 0x3f;
+		data->seqnum_table[seqno] = seq;
+		data->xmit_msg[i++] = seqno << 2;	/* seqno/rqLUN */
+		data->xmit_msg[i++] = msg[1];		/* cmd */
+		for (j = 2; j < msg_len; j++)
+			data->xmit_msg[i++] = msg[j];
+		data->xmit_msg[i] = ipmb_checksum(data->xmit_msg + 3, i - 3);
+		i++;
+	}
+
+
+	if (data->xmit_chars_len == 0) {
+		/* Transmit queue is empty, just format it now to go. */
+		format_msg(data, data->xmit_msg, i);
+		try_to_send_data(data, &flags);
+	} else {
+		/*
+		 * Get it ready to be sent later when the transmit
+		 * queue empties.
+		 */
+		data->xmit_msg_len = i;
+	}
+ out_unlock:
+	spin_unlock_irqrestore(&data->lock, flags);
+	return rv;
+}
+
+static void ra_tx_ready(struct ipmi_serial_codec_data *data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->lock, flags);
+	try_to_send_data(data, &flags);
+	spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static unsigned int ra_capabilities(struct ipmi_serial_codec_data *data)
+{
+	return 0;
+}
+
+
+static void ra_timer_tick(struct ipmi_serial_codec_data *data,
+			  unsigned int time_since_last)
+{
+	unsigned long flags;
+
+	/* Check quickly first to avoid grabbing the lock normally. */
+	if (likely(data->handshake_done))
+		return;
+
+	spin_lock_irqsave(&data->lock, flags);
+	/* Recheck to avoid races */
+	if (data->handshake_done)
+		goto out_unlock;
+
+	data->handshake_time -= time_since_last;
+	if (data->handshake_time <= 0) {
+		data->handshake_retries_left--;
+		if (data->handshake_retries_left <= 0) {
+			data->handshake_done = 1;
+			spin_unlock_irqrestore(&data->lock, flags);
+			ipmi_serial_ll_init_complete(data->info, 0, -ETIMEDOUT);
+			goto out;
+		}
+
+		/* Resend the IPMB fetch */
+		data->handshake_time = RA_HANDSHAKE_TIME;
+		format_msg(data, get_ipmbaddr_msg1,
+			   sizeof(get_ipmbaddr_msg1));
+		try_to_send_data(data, &flags);
+	}
+ out_unlock:
+	spin_unlock_irqrestore(&data->lock, flags);
+ out:
+	return;
+}
+
+static struct ipmi_serial_codec ra_codec = {
+	.owner = THIS_MODULE,
+	.name  = "RadisysAscii",
+
+	.capabilities	= ra_capabilities,
+	.setup_termios	= ra_setup_termios,
+	.init		= ra_init,
+	.start		= ra_start,
+	.cleanup	= ra_cleanup,
+	.size		= ra_size,
+	.send_msg	= ra_send_msg,
+	.handle_char	= ra_handle_char,
+	.tx_ready	= ra_tx_ready,
+	.add_options	= ra_add_options,
+	.timer_tick     = ra_timer_tick
+};
+
+static __init int
+init_ipmi_serial_ra_codec(void)
+{
+	return ipmi_serial_codec_register(&ra_codec);
+}
+
+module_init(init_ipmi_serial_ra_codec);
+
+static __exit void
+exit_ipmi_serial_ra_codec(void)
+{
+	ipmi_serial_codec_unregister(&ra_codec);
+}
+module_exit(exit_ipmi_serial_ra_codec);
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_serial_terminal_mode.c linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_serial_terminal_mode.c
--- linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_serial_terminal_mode.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_serial_terminal_mode.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,880 @@
+/*
+ * ipmi_serial_terminal_mode.c
+ * Serial interface encoder and decoder routines for terminal mode
+ * serial interfaces.
+ *
+ * Author: MontaVista Software, Inc.
+ *         source@mvista.com
+ *         Corey Minyard <cminyard@mvista.com>
+ *
+ * Copyright 2006 MontaVista Software Inc.
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#include <linux/module.h>
+#include <linux/ipmi_smi.h>
+#include <linux/ipmi_msgdefs.h>
+#include <linux/ipmi_serial_sm.h>
+#include <linux/spinlock.h>
+#include <linux/ctype.h>
+
+#define PFX "ipmi_serial_terminal_mode: "
+
+struct tm_options {
+#define PIGEONPOINT_OPTION "pp"
+	int pigeonpoint;
+	int pigeonpoint_forced; /* Set by command line. */
+#define PIGEONPOINT_INVIANA_OPTION "ppInvIANA"
+	int pigeonpoint_iana_bad;
+	int pigeonpoint_iana_bad_forced; /* Set by command line. */
+#define ATTN_OPTION "attn"
+	int attn;
+	int attn_forced; /* Set by command line. */
+	unsigned char attn_char;
+};
+
+/*
+ * Three bytes for every character plus the bridge/seqno field and add
+ * the [, ], and newline and perhaps an extra space
+ */
+#define TM_MAX_CHARS_SIZE (((IPMI_MAX_MSG_LENGTH + 1) * 3) + 4)
+
+/*
+ * Give the remote end this much time (100ms) to send a response
+ * before we give up and retry the given number of times.
+ */
+#define TM_HANDSHAKE_TIME    100000
+#define TM_HANDSHAKE_RETRIES 5
+
+
+struct ipmi_serial_codec_data {
+	struct ipmi_serial_info *info;
+
+	unsigned char xmit_chars[TM_MAX_CHARS_SIZE];
+	unsigned int  xmit_chars_len;
+	unsigned int  xmit_chars_pos;
+
+	unsigned char recv_chars[TM_MAX_CHARS_SIZE];
+	unsigned int  recv_chars_len;
+	int           recv_chars_too_many;
+
+	unsigned char seqno;
+	unsigned int seqnum_table[0x40];
+
+	unsigned char xmit_msg[IPMI_MAX_MSG_LENGTH];
+	unsigned int  xmit_msg_len;
+	unsigned int  xmit_msg_seq;
+	unsigned char recv_msg[IPMI_MAX_MSG_LENGTH];
+	unsigned int  recv_msg_len;
+
+	char echo_on;
+	char pp_iana_retried;
+
+	spinlock_t lock;
+
+	/*
+	 * Handle receipt of a message.  This is a function var so it
+	 * can be replaced at init time and when special handling is
+	 * required for messages.
+	 */
+	void (*recv_msg_handler)(struct ipmi_serial_codec_data *data,
+				 const unsigned char *msg,
+				 unsigned int len,
+				 unsigned int seq);
+
+	struct ipmi_device_id id;
+	struct tm_options options;
+
+	/*
+	 * Used to time initialization messages.
+	 */
+	int handshake_time;
+	int handshake_retries_left;
+	int handshake_done;
+};
+
+#define MOTOROLA_MFG_ID			0x0000a1
+#define MOTOROLA_ATCA_F101_PROD_ID	0x0051
+#define MOTOROLA_ATCA_6101_PROD_ID	0x0053
+/* Table of BMCs that support the PigeonPoint echo handling. */
+static struct { unsigned int mfg_id, prod_id; } pp_bmcs[] =
+{
+	{ MOTOROLA_MFG_ID,	MOTOROLA_ATCA_F101_PROD_ID },
+	{ MOTOROLA_MFG_ID,	MOTOROLA_ATCA_6101_PROD_ID },
+	{ 0, 0 }
+};
+
+static struct { unsigned int mfg_id, prod_id, val; } attn_bmcs[] =
+{
+	{ MOTOROLA_MFG_ID,	MOTOROLA_ATCA_F101_PROD_ID,	0x07 },
+	{ MOTOROLA_MFG_ID,	MOTOROLA_ATCA_6101_PROD_ID,	0x07 },
+	{ 0, 0 }
+};
+
+static void check_devid_options(struct ipmi_serial_codec_data *data)
+{
+	int i;
+
+	if (!data->options.pigeonpoint_forced) {
+		for (i = 0; pp_bmcs[i].mfg_id != 0; i++) {
+			if ((data->id.manufacturer_id == pp_bmcs[i].mfg_id)
+			    && (data->id.product_id == pp_bmcs[i].prod_id)) {
+				data->options.pigeonpoint = 1;
+				break;
+			}
+		}
+	}
+	if (!data->options.attn_forced) {
+		for (i = 0; attn_bmcs[i].mfg_id != 0; i++) {
+			if ((data->id.manufacturer_id == attn_bmcs[i].mfg_id)
+			    && (data->id.product_id == attn_bmcs[i].prod_id)) {
+				data->options.attn = 1;
+				data->options.attn_char = attn_bmcs[i].val;
+				break;
+			}
+		}
+	}
+}
+
+static int check_options(struct ipmi_serial_codec_data *data,
+			 const char *options)
+{
+	const char *s;
+	char *optval;
+	int  optval_len;
+	char *next;
+	int  len;
+	char *end;
+
+	for (s = options; s; s = next) {
+		next = strchr(s, '+');
+		if (next) {
+			len = next - s;
+			next++;
+		} else
+			len = strlen(s);
+
+		optval = strchr(s, '=');
+		if (next && optval >= next)
+			optval = NULL;
+		if (optval) {
+			len = optval - s;
+			optval++;
+			if (next) {
+				optval_len = next - optval;
+				next++;
+			} else
+				optval_len = strlen(optval);
+		} else
+			optval_len = 0;
+		end = NULL;
+		if (strncmp(PIGEONPOINT_OPTION, s, len) == 0) {
+			data->options.pigeonpoint = 1;
+			data->options.pigeonpoint_forced = 1;
+		} else if (strncmp("no" PIGEONPOINT_OPTION, s, len) == 0) {
+			data->options.pigeonpoint = 0;
+			data->options.pigeonpoint_forced = 1;
+		} else if (strncmp(PIGEONPOINT_INVIANA_OPTION, s, len) == 0) {
+			data->options.pigeonpoint_iana_bad = 1;
+			data->options.pigeonpoint_iana_bad_forced = 1;
+		} else if (strncmp("no" PIGEONPOINT_INVIANA_OPTION, s, len)
+									== 0) {
+			data->options.pigeonpoint_iana_bad = 0;
+			data->options.pigeonpoint_iana_bad_forced = 1;
+		} else if (strncmp(ATTN_OPTION, s, len) == 0) {
+			data->options.attn = 1;
+			data->options.attn_forced = 1;
+			if (optval)
+				data->options.attn_char
+					= simple_strtoul(optval, &end, 0);
+			else
+				/* default to bell */
+				data->options.attn_char = 0x07;
+		} else if (strncmp("no" ATTN_OPTION, s, len) == 0) {
+			data->options.attn = 0;
+			data->options.attn_forced = 1;
+		} else {
+			printk(KERN_WARNING PFX "Unknown options: %s\n",
+			       options);
+		}
+
+		if (optval && !end) {
+			printk(KERN_WARNING PFX "No value needed at: %s\n", s);
+			return -EINVAL;
+		}
+		if (optval && end != (optval + optval_len)) {
+			printk(KERN_WARNING PFX "Invalid value for: %s\n", s);
+			return -EINVAL;
+		}
+	}
+
+	return 0;
+}
+
+static int tm_add_options(struct ipmi_serial_codec_data *data, char *page)
+{
+	char pfx = ',';
+	char *out = page;
+
+	if (data->options.pigeonpoint) {
+		out += sprintf(out, "%cpp", pfx);
+		pfx = '+';
+	}
+	if (data->options.attn) {
+		out += sprintf(out, "%cattn", pfx);
+		if (data->options.attn_char != 0x07)
+			out += sprintf(out, "=0x%x", data->options.attn_char);
+		pfx = '+';
+	}
+
+	return out - page;
+}
+
+static unsigned char hex2char[16] = {
+	'0', '1', '2', '3', '4', '5', '6', '7',
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+static void format_msg(struct ipmi_serial_codec_data *data,
+		       const unsigned char *msg, unsigned int msg_len,
+		       unsigned int seq)
+{
+	int i;
+	int len;
+	unsigned char *c = data->xmit_chars;
+	unsigned char seqno;
+
+	len = 0;
+	c[len] = '[';
+	len++;
+
+	c[len] = hex2char[msg[0] >> 4];
+	len++;
+	c[len] = hex2char[msg[0] & 0xf];
+	len++;
+
+	/*
+	 * Insert the sequence number and bridge bits.  Bridge bits
+	 * are always zero.
+	 */
+	seqno = data->seqno;
+	data->seqno = (data->seqno + 1) & 0x3f;
+	data->seqnum_table[seqno] = seq;
+	seqno <<= 2;
+	c[len] = hex2char[seqno >> 4];
+	len++;
+	c[len] = hex2char[seqno & 0xf];
+	len++;
+
+	/* Now the rest of the message. */
+	for (i = 1; ; ) {
+		c[len] = hex2char[msg[i] >> 4];
+		len++;
+		c[len] = hex2char[msg[i] & 0xf];
+		len++;
+		i++;
+		if (i == msg_len)
+			break;
+		c[len] = ' ';
+		len++;
+	}
+	c[len] = ']';
+	len++;
+	c[len] = 0x0a;
+	len++;
+	c[len] = 0x0d; /* We definitely have room for this byte. */
+	len++;
+
+	data->xmit_chars_pos = 0;
+	data->xmit_chars_len = len;
+}
+
+static int fromhex(unsigned char c)
+{
+	if (isdigit(c))
+		return c - '0';
+	else if (isxdigit(c))
+		return tolower(c) - 'a' + 10;
+	else
+		return -EINVAL;
+}
+
+/*
+ * Called when the ']' is seen, the leading '[' is removed, too.  We
+ * get this with a leading space and no more than one space between
+ * items.
+ */
+static int unformat_msg(struct ipmi_serial_codec_data *data)
+{
+	unsigned char *r = data->recv_chars;
+	unsigned char *o = data->recv_msg;
+	unsigned int len = data->recv_chars_len;
+	unsigned int p = 0;
+	unsigned int i = 0;
+	int          rv;
+
+	if (isspace(r[p]))
+		p++;
+	while (p < len) {
+		if (i >= sizeof(data->recv_msg))
+			return -EFBIG;
+		if (p >= len)
+			return -EINVAL;
+		rv = fromhex(r[p]);
+		if (rv < 0)
+			return rv;
+		o[i] = rv << 4;
+		p++;
+		if (p >= len)
+			return -EINVAL;
+		rv = fromhex(r[p]);
+		if (rv < 0)
+			return rv;
+		o[i] |= rv;
+		p++;
+		i++;
+		if (isspace(r[p]))
+			p++;
+	}
+	data->recv_msg_len = i;
+	return 0;
+}
+
+static void normal_recv(struct ipmi_serial_codec_data *data,
+			const unsigned char *msg,
+			unsigned int len,
+			unsigned int seq)
+{
+	if (((msg[0] >> 2) & 1) == 0)
+		/*
+		 * If the bottom bit of the message is zero, then it
+		 * is a command and most likely an echo.
+		 */
+		return;
+
+	if (len < 3) {
+		/* Responses must be at least 3 bytes after processing. */
+		ipmi_serial_ll_protocol_violation(data->info);
+		return;
+	}
+
+	ipmi_serial_ll_recv(data->info, msg, len, seq);
+}
+
+
+static void handle_recv_msg(struct ipmi_serial_codec_data *data)
+{
+	unsigned int seq;
+	unsigned char *m = data->recv_msg;
+	unsigned int len = data->recv_msg_len;
+	int          i;
+
+	if (len < 3) {
+		/* Messages must be at least 3 bytes */
+		ipmi_serial_ll_protocol_violation(data->info);
+		return;
+	}
+
+	seq = m[1] >> 2;
+
+	/* Now remove the seq# */
+	for (i = 1; i < len-1; i++)
+		m[i] = m[i+1];
+	len--;
+
+	data->recv_msg_handler(data, m, len, data->seqnum_table[seq]);
+}
+
+static void try_to_send_data(struct ipmi_serial_codec_data *data)
+{
+	unsigned char *c;
+	unsigned int  left;
+	unsigned int  sent;
+
+	if (!data->xmit_chars_len)
+		return;
+
+ restart:
+	c = data->xmit_chars + data->xmit_chars_pos;
+	left = data->xmit_chars_len - data->xmit_chars_pos;
+	sent = ipmi_serial_ll_xmit(data->info, c, left);
+	if (sent == left) {
+		/* We are done with this message. */
+		if (data->xmit_msg_len) {
+			/* Send the next message we have waiting. */
+			format_msg(data, data->xmit_msg, data->xmit_msg_len,
+				   data->xmit_msg_seq);
+			data->xmit_msg_len = 0;
+			goto restart;
+		} else {
+			/* Nothing to do. */
+			data->xmit_chars_len = 0;
+		}
+	} else {
+		data->xmit_chars_pos += sent;
+	}
+}
+
+static void finish_init(struct ipmi_serial_codec_data *data, int err)
+{
+	ipmi_serial_ll_init_complete(data->info, 0, err);
+}
+
+/*
+ * Handling for pigeonpoint-specific codec, we have special ways to
+ * turn on/off echo.
+ */
+#define PP_OEM_CHARS		0x0a, 0x40, 0x00
+#define PP_GET_SERIAL_INTF_CMD	0x01
+#define PP_SET_SERIAL_INTF_CMD	0x02
+#define PP_GET_SER_INTF_SIZE 6
+static unsigned char pp_get_ser_intf_cmd[PP_GET_SER_INTF_SIZE]
+	 = {IPMI_NETFN_OEM_REQUEST << 2, PP_GET_SERIAL_INTF_CMD,
+	    PP_OEM_CHARS, 0x01};
+#define PP_SET_SER_INTF_SIZE 7
+static unsigned char pp_set_ser_intf_cmd[PP_SET_SER_INTF_SIZE]
+	 = {IPMI_NETFN_OEM_REQUEST << 2, PP_SET_SERIAL_INTF_CMD,
+	    PP_OEM_CHARS, 0x01, 0x00};
+
+static void handle_pp_set_ser(struct ipmi_serial_codec_data *data,
+			      const unsigned char *msg,
+			      unsigned int len,
+			      unsigned int seq)
+{
+	unsigned long flags;
+
+	if (((msg[0] >> 2) & 1) == 0)
+		/* Got the echo */
+		return;
+
+	if (((msg[0] >> 2) != IPMI_NETFN_OEM_RESPONSE)
+	    || (msg[1] != PP_SET_SERIAL_INTF_CMD))
+		/* Not what we were expecting */
+		return;
+
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->handshake_done) {
+		spin_unlock_irqrestore(&data->lock, flags);
+		return;
+	}
+
+	if (msg[2] != 0) {
+		data->handshake_done = 1;
+		spin_unlock_irqrestore(&data->lock, flags);
+		printk(KERN_WARNING PFX
+		       "Error setting pigeonpoint serial parms: 0x%x\n",
+		       msg[2]);
+		finish_init(data, -EINVAL);
+	}
+
+	data->handshake_done = 1;
+	data->recv_msg_handler = normal_recv;
+	spin_unlock_irqrestore(&data->lock, flags);
+	finish_init(data, 0);
+}
+
+static void pp_start_disable_echo(struct ipmi_serial_codec_data *data);
+
+static void handle_pp_get_ser(struct ipmi_serial_codec_data *data,
+			      const unsigned char *msg,
+			      unsigned int len,
+			      unsigned int seq)
+{
+	unsigned long flags;
+
+	if (((msg[0] >> 2) & 1) == 0)
+		/* Got the echo */
+		return;
+
+	if (((msg[0] >> 2) != IPMI_NETFN_OEM_RESPONSE)
+	    || (msg[1] != PP_GET_SERIAL_INTF_CMD))
+		/* Not what we were expecting */
+		return;
+
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->handshake_done) {
+		spin_unlock_irqrestore(&data->lock, flags);
+		return;
+	}
+
+	if (msg[2] != 0) {
+		if (!data->options.pigeonpoint_iana_bad_forced &&
+		    !data->pp_iana_retried) {
+			/* Try swapping the IANA and see if that helps. */
+			data->pp_iana_retried = 1;
+			data->options.pigeonpoint_iana_bad
+				= !data->options.pigeonpoint_iana_bad;
+			pp_start_disable_echo(data);
+			spin_unlock_irqrestore(&data->lock, flags);
+			return;
+		}
+		data->handshake_done = 1;
+		spin_unlock_irqrestore(&data->lock, flags);
+		printk(KERN_WARNING PFX
+		       "Error getting pigeonpoint serial parms: 0x%x\n",
+		       msg[2]);
+		finish_init(data, -EINVAL);
+		return;
+	}
+
+	if (len < 6) {
+		data->handshake_done = 1;
+		spin_unlock_irqrestore(&data->lock, flags);
+		printk(KERN_WARNING PFX
+		       "Pigeonpoint serial parms too short: %d\n", len);
+		finish_init(data, -EINVAL);
+		return;
+	}
+
+	memcpy(data->xmit_msg, pp_set_ser_intf_cmd,
+	       sizeof(pp_set_ser_intf_cmd));
+	if (data->options.pigeonpoint_iana_bad) {
+		data->xmit_msg[2] = 0x00;
+		data->xmit_msg[4] = 0x0a;
+	}
+	data->xmit_msg[6] &= 0x7f; /* And off echo bit */
+
+	data->recv_msg_handler = handle_pp_set_ser;
+	data->handshake_time = TM_HANDSHAKE_TIME;
+	data->handshake_retries_left = TM_HANDSHAKE_RETRIES;
+	format_msg(data, data->xmit_msg, sizeof(pp_set_ser_intf_cmd), 0);
+	data->xmit_msg_len = 0;
+	try_to_send_data(data);
+
+	spin_unlock_irqrestore(&data->lock, flags);
+}
+
+
+static void pp_start_disable_echo(struct ipmi_serial_codec_data *data)
+{
+	memcpy(data->xmit_msg, pp_get_ser_intf_cmd,
+	       sizeof(pp_get_ser_intf_cmd));
+	if (data->options.pigeonpoint_iana_bad) {
+		data->xmit_msg[2] = 0x00;
+		data->xmit_msg[4] = 0x0a;
+	}
+
+	data->recv_msg_handler = handle_pp_get_ser;
+	data->handshake_time = TM_HANDSHAKE_TIME;
+	data->handshake_retries_left = TM_HANDSHAKE_RETRIES;
+	format_msg(data, data->xmit_msg, sizeof(pp_get_ser_intf_cmd), 0);
+	data->xmit_msg_len = 0;
+	try_to_send_data(data);
+}
+
+
+static int tm_setup_termios(struct ktermios *t)
+{
+	/* Nothing to do, the default is fine. */
+	return 0;
+}
+
+static unsigned char devid_msg[] = { IPMI_NETFN_APP_REQUEST << 2,
+				     IPMI_GET_DEVICE_ID_CMD };
+
+static void handle_init_devid(struct ipmi_serial_codec_data *data,
+			      const unsigned char *msg,
+			      unsigned int len,
+			      unsigned int seq)
+{
+	int rv;
+	unsigned long flags;
+
+	if ((len == sizeof(devid_msg))
+				&& (memcmp(msg, devid_msg, len) == 0)) {
+		data->echo_on = 1;
+		return;
+	}
+
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->handshake_done) {
+		spin_unlock_irqrestore(&data->lock, flags);
+		return;
+	}
+
+	rv = ipmi_demangle_device_id(msg, len, &data->id);
+	if (rv) {
+		data->handshake_done = 1;
+		spin_unlock_irqrestore(&data->lock, flags);
+		printk(KERN_WARNING PFX "invalid device id: %d\n", rv);
+		finish_init(data, rv);
+		return;
+	}
+
+	check_devid_options(data);
+
+	if (data->options.pigeonpoint && data->echo_on) {
+		pp_start_disable_echo(data);
+		spin_unlock_irqrestore(&data->lock, flags);
+	} else {
+		data->handshake_done = 1;
+		data->recv_msg_handler = normal_recv;
+		spin_unlock_irqrestore(&data->lock, flags);
+		finish_init(data, 0);
+	}
+}
+
+static int tm_init(struct ipmi_serial_codec_data *data,
+		   struct ipmi_serial_info *info,
+		   const char *options)
+{
+	memset(data, 0, sizeof(*data));
+	spin_lock_init(&data->lock);
+	data->info = info;
+	return check_options(data, options);
+}
+
+static int tm_start(struct ipmi_serial_codec_data *data)
+{
+	unsigned long flags;
+
+	/*
+	 * Send a "get device id" to test basic function and get
+	 * useful info.
+	 */
+	spin_lock_irqsave(&data->lock, flags);
+	data->recv_msg_handler = handle_init_devid;
+	data->handshake_time = TM_HANDSHAKE_TIME;
+	data->handshake_retries_left = TM_HANDSHAKE_RETRIES;
+	format_msg(data, devid_msg, sizeof(devid_msg), 0);
+	data->xmit_msg_len = 0;
+	try_to_send_data(data);
+	spin_unlock_irqrestore(&data->lock, flags);
+	return 0;
+}
+
+static void tm_cleanup(struct ipmi_serial_codec_data *data)
+{
+	/* Nothing to do. */
+}
+
+static int tm_size(void)
+{
+	return sizeof(struct ipmi_serial_codec_data);
+}
+
+static void tm_handle_char(struct ipmi_serial_codec_data *data,
+			   unsigned char ch)
+{
+	unsigned int len = data->recv_chars_len;
+	unsigned char *r;
+	int           rv;
+
+	if (data->options.attn && (ch == data->options.attn_char)) {
+		ipmi_serial_ll_attn(data->info);
+		return;
+	}
+
+	if (ch == '[') {
+		/*
+		 * Start of a command.  Note that if a command is
+		 * already in progress (len != 0) we abort it.
+		 */
+		if (len != 0)
+			ipmi_serial_ll_protocol_violation(data->info);
+
+		/* Convert the leading '[' to a space, that's innocuous. */
+		data->recv_chars[0] = ' ';
+		data->recv_chars_len = 1;
+		data->recv_chars_too_many = 0;
+		return;
+	}
+
+	if (len == 0)
+		/* Ignore everything outside [ ]. */
+		return;
+
+	if (ch == ']') {
+		/* End of command, handle it. */
+		if (data->recv_chars_too_many) {
+			/* Input data overrun. */
+			ipmi_serial_ll_protocol_violation(data->info);
+			data->recv_chars_too_many = 0;
+			data->recv_chars_len = 0;
+			return;
+		}
+		rv = unformat_msg(data);
+		data->recv_chars_len = 0;
+		if (rv) {
+			/* Bad input data. */
+			ipmi_serial_ll_protocol_violation(data->info);
+			return;
+		}
+		handle_recv_msg(data);
+		return;
+	}
+
+	if (data->recv_chars_too_many)
+		return;
+
+	r = data->recv_chars;
+
+	if (len >= sizeof(data->recv_chars)) {
+		data->recv_chars_too_many = 1;
+	} else if (isspace(r[len-1]) && isspace(ch)) {
+		/* Ignore multiple spaces together. */
+	} else {
+		r[len] = ch;
+		data->recv_chars_len++;
+	}
+}
+
+static int tm_send_msg(struct ipmi_serial_codec_data *data,
+		       const unsigned char *msg, unsigned int msg_len,
+		       unsigned int seq)
+{
+	unsigned long flags;
+	int           rv = 0;
+
+	if (msg_len > IPMI_MAX_MSG_LENGTH)
+		return -EFBIG;
+	if (msg_len < 2)
+		return -EINVAL;
+
+	spin_lock_irqsave(&data->lock, flags);
+	if (data->xmit_msg_len) {
+		/* Something is still waiting to be sent. */
+		rv = -EBUSY;
+		goto out_unlock;
+	}
+
+	if (data->xmit_chars_len == 0) {
+		/* Transmit queue is empty, just format it now to go. */
+		format_msg(data, msg, msg_len, seq);
+		try_to_send_data(data);
+	} else {
+		/*
+		 * Get it ready to be sent later when the transmit
+		 * queue empties.
+		 */
+		memcpy(data->xmit_msg, msg, msg_len);
+		data->xmit_msg_len = msg_len;
+		data->xmit_msg_seq = seq;
+	}
+
+ out_unlock:
+	spin_unlock_irqrestore(&data->lock, flags);
+	return rv;
+}
+
+static void tm_tx_ready(struct ipmi_serial_codec_data *data)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&data->lock, flags);
+	try_to_send_data(data);
+	spin_unlock_irqrestore(&data->lock, flags);
+}
+
+static unsigned int tm_capabilities(struct ipmi_serial_codec_data *data)
+{
+	unsigned int c = (IPMI_SERIAL_SUPPORTS_GET_FLAGS
+			  | IPMI_SERIAL_SUPPORTS_EVENT_BUFFER);
+	if (data->options.attn)
+		c |= IPMI_SERIAL_HAS_ATTN;
+	else
+		c |= IPMI_SERIAL_NEEDS_GET_FLAGS_POLLING;
+	return c;
+}
+
+static void tm_timer_tick(struct ipmi_serial_codec_data *data,
+			  unsigned int time_since_last)
+{
+	unsigned long flags;
+
+	/* Check quickly first to avoid grabbing the lock normally. */
+	if (likely(data->handshake_done))
+		return;
+
+	spin_lock_irqsave(&data->lock, flags);
+	/* Recheck to avoid races */
+	if (data->handshake_done)
+		goto out_unlock;
+
+	data->handshake_time -= time_since_last;
+	if (time_since_last <= 0) {
+		data->handshake_retries_left--;
+		if (data->handshake_retries_left <= 0) {
+			data->handshake_done = 1;
+			spin_unlock_irqrestore(&data->lock, flags);
+			finish_init(data, -ETIMEDOUT);
+			goto out;
+		}
+
+		/* Resend the appropriate message */
+		data->handshake_time = TM_HANDSHAKE_TIME;
+		if (data->recv_msg_handler == handle_init_devid) {
+			format_msg(data, devid_msg, sizeof(devid_msg), 0);
+			data->xmit_msg_len = 0;
+			try_to_send_data(data);
+		} else if (data->recv_msg_handler == handle_pp_get_ser) {
+			format_msg(data, data->xmit_msg,
+				   sizeof(pp_get_ser_intf_cmd), 0);
+			data->xmit_msg_len = 0;
+			try_to_send_data(data);
+		} else if (data->recv_msg_handler == handle_pp_set_ser) {
+			data->xmit_msg_len = sizeof(pp_set_ser_intf_cmd);
+			format_msg(data, data->xmit_msg,
+				   data->xmit_msg_len, 0);
+			data->xmit_msg_len = 0;
+			try_to_send_data(data);
+		}
+	}
+ out_unlock:
+	spin_unlock_irqrestore(&data->lock, flags);
+ out:
+	return;
+}
+
+static struct ipmi_serial_codec tm_codec = {
+	.owner = THIS_MODULE,
+	.name  = "TerminalMode",
+
+	.capabilities	= tm_capabilities,
+	.setup_termios	= tm_setup_termios,
+	.init		= tm_init,
+	.start		= tm_start,
+	.cleanup	= tm_cleanup,
+	.size		= tm_size,
+	.send_msg	= tm_send_msg,
+	.handle_char	= tm_handle_char,
+	.tx_ready	= tm_tx_ready,
+	.add_options	= tm_add_options,
+	.timer_tick     = tm_timer_tick
+};
+
+static __init int
+init_ipmi_serial_tm_codec(void)
+{
+	return ipmi_serial_codec_register(&tm_codec);
+}
+
+module_init(init_ipmi_serial_tm_codec);
+
+static __exit void
+exit_ipmi_serial_tm_codec(void)
+{
+	ipmi_serial_codec_unregister(&tm_codec);
+}
+module_exit(exit_ipmi_serial_tm_codec);
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_si_intf.c linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_si_intf.c
--- linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_si_intf.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_si_intf.c	2009-07-21 11:28:18.000000000 -0700
@@ -82,12 +82,6 @@
 #define SI_SHORT_TIMEOUT_USEC  250 /* .25ms when the SM request a
 				      short timeout */
 
-/* Bit for BMC global enables. */
-#define IPMI_BMC_RCV_MSG_INTR     0x01
-#define IPMI_BMC_EVT_MSG_INTR     0x02
-#define IPMI_BMC_EVT_MSG_BUFF     0x04
-#define IPMI_BMC_SYS_LOG          0x08
-
 enum si_intf_state {
 	SI_NORMAL,
 	SI_GETTING_FLAGS,
@@ -220,6 +214,9 @@
 			     OEM2_DATA_AVAIL)
 	unsigned char       msg_flags;
 
+	/* Does the BMC have an event buffer? */
+	char		    has_event_buffer;
+
 	/*
 	 * If set to true, this will request events the next time the
 	 * state machine is idle.
@@ -296,6 +293,7 @@
 
 static int force_kipmid[SI_MAX_PARMS];
 static int num_force_kipmid;
+static unsigned int kipmid_max_busy;
 
 static int unload_when_empty = 1;
 
@@ -927,20 +925,52 @@
 	}
 }
 
+static int ipmi_thread_must_sleep(enum si_sm_result smi_result, int *busy,
+				  struct timespec *busy_time)
+{
+	if (kipmid_max_busy == 0)
+		return 0;
+
+	if (smi_result != SI_SM_CALL_WITH_DELAY) {
+		if (*busy != 0)
+			*busy = 0;
+		return 0;
+	}
+
+	if (*busy == 0) {
+		*busy = 1;
+		getnstimeofday(busy_time);
+		timespec_add_ns(busy_time, kipmid_max_busy * NSEC_PER_USEC);
+	} else {
+		struct timespec now;
+		getnstimeofday(&now);
+		if (unlikely(timespec_compare(&now, busy_time) > 0)) {
+			*busy = 0;
+			return 1;
+		}
+	}
+	return 0;
+}
+
 static int ipmi_thread(void *data)
 {
 	struct smi_info *smi_info = data;
 	unsigned long flags;
 	enum si_sm_result smi_result;
+	struct timespec busy_time;
+	int busy = 0;
 
 	set_user_nice(current, 19);
 	while (!kthread_should_stop()) {
+		int must_sleep;
 		spin_lock_irqsave(&(smi_info->si_lock), flags);
 		smi_result = smi_event_handler(smi_info, 0);
 		spin_unlock_irqrestore(&(smi_info->si_lock), flags);
+		must_sleep = ipmi_thread_must_sleep(smi_result,
+						    &busy, &busy_time);
 		if (smi_result == SI_SM_CALL_WITHOUT_DELAY)
 			; /* do nothing */
-		else if (smi_result == SI_SM_CALL_WITH_DELAY)
+		else if (smi_result == SI_SM_CALL_WITH_DELAY && !must_sleep)
 			schedule();
 		else
 			schedule_timeout_interruptible(1);
@@ -968,7 +998,8 @@
 {
 	struct smi_info *smi_info = send_info;
 
-	if (atomic_read(&smi_info->stop_operation))
+	if (atomic_read(&smi_info->stop_operation) ||
+				!smi_info->has_event_buffer)
 		return;
 
 	atomic_set(&smi_info->req_events, 1);
@@ -1213,6 +1244,11 @@
 MODULE_PARM_DESC(unload_when_empty, "Unload the module if no interfaces are"
 		 " specified or found, default is 1.  Setting to 0"
 		 " is useful for hot add of devices using hotmod.");
+module_param(kipmid_max_busy, uint, 0644);
+MODULE_PARM_DESC(kipmid_max_busy,
+		 "Max time (in microseconds) to busy-wait for IPMI data before"
+		 " sleeping. 0 (default) means to wait forever. Set to 100-500"
+		 " if kipmid is using up a lot of CPU time.");
 
 
 static void std_irq_cleanup(struct smi_info *info)
@@ -2407,26 +2443,9 @@
 };
 #endif /* CONFIG_PPC_OF */
 
-
-static int try_get_dev_id(struct smi_info *smi_info)
+static int wait_for_msg_done(struct smi_info *smi_info)
 {
-	unsigned char         msg[2];
-	unsigned char         *resp;
-	unsigned long         resp_len;
 	enum si_sm_result     smi_result;
-	int                   rv = 0;
-
-	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
-	if (!resp)
-		return -ENOMEM;
-
-	/*
-	 * Do a Get Device ID command, since it comes back with some
-	 * useful info.
-	 */
-	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
-	msg[1] = IPMI_GET_DEVICE_ID_CMD;
-	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
 
 	smi_result = smi_info->handlers->event(smi_info->si_sm, 0);
 	for (;;) {
@@ -2441,16 +2460,39 @@
 		} else
 			break;
 	}
-	if (smi_result == SI_SM_HOSED) {
+	if (smi_result == SI_SM_HOSED)
 		/*
 		 * We couldn't get the state machine to run, so whatever's at
 		 * the port is probably not an IPMI SMI interface.
 		 */
-		rv = -ENODEV;
+		return -ENODEV;
+
+	return 0;
+}
+
+static int try_get_dev_id(struct smi_info *smi_info)
+{
+	unsigned char         msg[2];
+	unsigned char         *resp;
+	unsigned long         resp_len;
+	int                   rv = 0;
+
+	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	/*
+	 * Do a Get Device ID command, since it comes back with some
+	 * useful info.
+	 */
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_DEVICE_ID_CMD;
+	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+
+	rv = wait_for_msg_done(smi_info);
+	if (rv)
 		goto out;
-	}
 
-	/* Otherwise, we got some data. */
 	resp_len = smi_info->handlers->get_result(smi_info->si_sm,
 						  resp, IPMI_MAX_MSG_LENGTH);
 
@@ -2462,6 +2504,88 @@
 	return rv;
 }
 
+static int try_enable_event_buffer(struct smi_info *smi_info)
+{
+	unsigned char         msg[3];
+	unsigned char         *resp;
+	unsigned long         resp_len;
+	int                   rv = 0;
+
+	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 2);
+
+	rv = wait_for_msg_done(smi_info);
+	if (rv) {
+		printk(KERN_WARNING
+		       "ipmi_si: Error getting response from get global,"
+		       " enables command, the event buffer is not"
+		       " enabled.\n");
+		goto out;
+	}
+
+	resp_len = smi_info->handlers->get_result(smi_info->si_sm,
+						  resp, IPMI_MAX_MSG_LENGTH);
+
+	if (resp_len < 4 ||
+			resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
+			resp[1] != IPMI_GET_BMC_GLOBAL_ENABLES_CMD   ||
+			resp[2] != 0) {
+		printk(KERN_WARNING
+		       "ipmi_si: Invalid return from get global"
+		       " enables command, cannot enable the event"
+		       " buffer.\n");
+		rv = -EINVAL;
+		goto out;
+	}
+
+	if (resp[3] & IPMI_BMC_EVT_MSG_BUFF)
+		/* buffer is already enabled, nothing to do. */
+		goto out;
+
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+	msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF;
+	smi_info->handlers->start_transaction(smi_info->si_sm, msg, 3);
+
+	rv = wait_for_msg_done(smi_info);
+	if (rv) {
+		printk(KERN_WARNING
+		       "ipmi_si: Error getting response from set global,"
+		       " enables command, the event buffer is not"
+		       " enabled.\n");
+		goto out;
+	}
+
+	resp_len = smi_info->handlers->get_result(smi_info->si_sm,
+						  resp, IPMI_MAX_MSG_LENGTH);
+
+	if (resp_len < 3 ||
+			resp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2 ||
+			resp[1] != IPMI_SET_BMC_GLOBAL_ENABLES_CMD) {
+		printk(KERN_WARNING
+		       "ipmi_si: Invalid return from get global,"
+		       "enables command, not enable the event"
+		       " buffer.\n");
+		rv = -EINVAL;
+		goto out;
+	}
+
+	if (resp[2] != 0)
+		/*
+		 * An error when setting the event buffer bit means
+		 * that the event buffer is not supported.
+		 */
+		rv = -ENOENT;
+ out:
+	kfree(resp);
+	return rv;
+}
+
 static int type_file_read_proc(char *page, char **start, off_t off,
 			       int count, int *eof, void *data)
 {
@@ -2847,6 +2971,10 @@
 	new_smi->intf_num = smi_num;
 	smi_num++;
 
+	rv = try_enable_event_buffer(new_smi);
+	if (rv == 0)
+		new_smi->has_event_buffer = 1;
+
 	/*
 	 * Start clearing the flags before we enable interrupts or the
 	 * timer to avoid racing with the timer.
@@ -2863,7 +2991,7 @@
 		 */
 		new_smi->pdev = platform_device_alloc("ipmi_si",
 						      new_smi->intf_num);
-		if (rv) {
+		if (!new_smi->pdev) {
 			printk(KERN_ERR
 			       "ipmi_si_intf:"
 			       " Unable to allocate platform device\n");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_smb.c linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_smb.c
--- linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_smb.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_smb.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,1859 @@
+/*
+ * ipmi_smb.c
+ *
+ * The interface to the IPMI driver for SMBus access to a SMBus
+ * compliant device.
+ *
+ * Author: Intel Corporation
+ *         Todd Davis <todd.c.davis@intel.com>
+ *
+ * Rewritten by Corey Minyard <minyard@acm.org> to support the
+ * non-blocking I2C interface, add support for multi-part
+ * transactions, add PEC support, and general clenaup.
+ *
+ * Copyright 2003 Intel Corporation
+ * Copyright 2005 MontaVista Software
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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 holds the "policy" for the interface to the SMB state
+ * machine.  It does the configuration, handles timers and interrupts,
+ * and drives the real SMB state machine.
+ */
+
+/*
+ * TODO: Figure out how to use SMB alerts.  This will require a new
+ * interface into the I2C driver, I believe.
+ */
+
+#include <linux/version.h>
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <asm/system.h>
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <linux/ipmi_smi.h>
+#include <linux/init.h>
+#include <linux/dmi.h>
+
+#define PFX "ipmi_smb: "
+
+#define IPMI_GET_SYSTEM_INTERFACE_CAPABILITIES_CMD	0x57
+
+#define	SMB_IPMI_REQUEST			2
+#define	SMB_IPMI_MULTI_PART_REQUEST_START	6
+#define	SMB_IPMI_MULTI_PART_REQUEST_MIDDLE	7
+#define	SMB_IPMI_RESPONSE			3
+#define	SMB_IPMI_MULTI_PART_RESPONSE_MIDDLE	9
+
+/* smb_debug is a bit-field
+ *	SMB_DEBUG_MSG -	commands and their responses
+ *	SMB_DEBUG_STATES -	message states
+ *	SMB_DEBUG_TIMING -	 Measure times between events in the driver
+ */
+#define SMB_DEBUG_TIMING	4
+#define SMB_DEBUG_STATE		2
+#define SMB_DEBUG_MSG		1
+#define SMB_NODEBUG		1
+#define SMB_DEFAULT_DEBUG	(SMB_NODEBUG)
+
+/*
+ * Timer values
+ */
+#define SMB_MSG_USEC		20000	/* 20ms between message tries. */
+#define SMB_MSG_PART_USEC	5000	/* 5ms for a message part */
+
+/* How many times to we retry sending/receiving the message. */
+#define	SMB_SEND_RETRIES	5
+#define	SMB_RECV_RETRIES	250
+
+#define SMB_MSG_MSEC		(SMB_MSG_USEC / 1000)
+#define SMB_MSG_JIFFIES		((SMB_MSG_USEC * 1000) / TICK_NSEC)
+#define SMB_MSG_PART_JIFFIES	((SMB_MSG_PART_USEC * 1000) / TICK_NSEC)
+
+enum smb_intf_state {
+	SMB_NORMAL,
+	SMB_GETTING_FLAGS,
+	SMB_GETTING_EVENTS,
+	SMB_CLEARING_FLAGS,
+	SMB_GETTING_MESSAGES,
+	/* FIXME - add watchdog stuff. */
+};
+
+#define SMB_IDLE(smb)	 ((smb)->smb_state == SMB_NORMAL \
+			  && (smb)->curr_msg == NULL)
+
+/*
+ * Indexes into stats[] in smb_info below.
+ */
+enum smb_stat_indexes {
+	/* Number of total messages sent. */
+	SMB_STAT_sent_messages = 0,
+
+	/*
+	 * Number of message parts sent.  Messages may be broken into
+	 * parts if they are long.
+	 */
+	SMB_STAT_sent_messages_parts,
+
+	/*
+	 * Number of time a message was retried.
+	 */
+	SMB_STAT_send_retries,
+
+	/*
+	 * Number of times the send of a message failed.
+	 */
+	SMB_STAT_send_errors,
+
+	/*
+	 * Number of message responses received.
+	 */
+	SMB_STAT_received_messages,
+
+	/*
+	 * Number of message fragments received.
+	 */
+	SMB_STAT_received_message_parts,
+
+	/*
+	 * Number of times the receive of a message was retried.
+	 */
+	SMB_STAT_receive_retries,
+
+	/*
+	 * Number of errors receiving messages.
+	 */
+	SMB_STAT_receive_errors,
+
+	/*
+	 * Number of times a flag fetch was requested.
+	 */
+	SMB_STAT_flag_fetches,
+
+	/*
+	 * Number of times the hardware didn't follow the state machine.
+	 */
+	SMB_STAT_hosed,
+
+	/*
+	 * Number of received events.
+	 */
+	SMB_STAT_events,
+
+	/* Number of asyncronous messages received. */
+	SMB_STAT_incoming_messages,
+
+	/* Always add statistics before this value, it must be last. */
+	SMB_NUM_STATS
+};
+
+struct smb_info {
+	int                 pos;
+	ipmi_smi_t          intf;
+	spinlock_t          msg_lock;
+	struct list_head    xmit_msgs;
+	struct list_head    hp_xmit_msgs;
+	struct ipmi_smi_msg *curr_msg;
+	enum smb_intf_state smb_state;
+	unsigned long       smb_debug;
+
+	/*
+	 * Flags from the last GET_MSG_FLAGS command, used when an ATTN
+	 * is set to hold the flags until we are done handling everything
+	 * from the flags.
+	 */
+#define RECEIVE_MSG_AVAIL	0x01
+#define EVENT_MSG_BUFFER_FULL	0x02
+#define WDT_PRE_TIMEOUT_INT	0x08
+	unsigned char       msg_flags;
+
+	char		    has_event_buffer;
+
+	/*
+	 * If set to true, this will request events the next time the
+	 * state machine is idle.
+	 */
+	int                 req_events;
+
+	/*
+	 * If set to true, this will request flags the next time the
+	 * state machine is idle.
+	 */
+	int                 req_flags;
+
+	/*
+	 * If true, run the state machine to completion on every send
+	 * call.  Generally used after a panic or shutdown to make
+	 * sure stuff goes out.
+	 */
+	int                 run_to_completion;
+
+	/*
+	 * Used to perform timer operations when run-to-completion
+	 * mode is on.  This is a countdown timer.
+	 */
+	int                 rtc_us_timer;
+
+	/* Used for sending/receiving data.  +1 for the length. */
+	unsigned char data[IPMI_MAX_MSG_LENGTH + 1];
+	unsigned int  data_len;
+
+	/* Temp receive buffer, gets copied into data. */
+	unsigned char recv[I2C_SMBUS_BLOCK_MAX];
+
+	struct i2c_client client;
+	struct i2c_op_q_entry i2c_q_entry;
+
+	/* From the device id response. */
+	struct ipmi_device_id device_id;
+
+	/* Is the driver trying to stop? */
+	int stopping;
+
+	struct timer_list retry_timer;
+	int retries_left;
+
+	/* Info from SSIF cmd */
+	unsigned char max_xmit_msg_size;
+	unsigned char max_recv_msg_size;
+	unsigned int  multi_support;
+	int           supports_pec;
+
+#define SMB_NO_MULTI		0
+#define SMB_MULTI_2_PART	1
+#define SMB_MULTI_n_PART	2
+	unsigned char *multi_data;
+	unsigned int  multi_len;
+	unsigned int  multi_pos;
+
+	atomic_t stats[SMB_NUM_STATS];
+};
+
+#define smb_inc_stat(smb, stat) \
+	atomic_inc(&(smb)->stats[SMB_STAT_ ## stat])
+#define smb_get_stat(smb, stat) \
+	((unsigned int) atomic_read(&(smb)->stats[SMB_STAT_ ## stat]))
+
+static int initialized;
+static int smb_dbg_probe;
+
+static void return_hosed_msg(struct smb_info *smb_info,
+			     struct ipmi_smi_msg *msg);
+static void start_next_msg(struct smb_info *smb_info, unsigned long *flags);
+static int start_send(struct smb_info *smb_info,
+		      unsigned char   *data,
+		      unsigned int    len);
+
+/*
+ * If run_to_completion mode is on, return NULL to know the lock wasn't
+ * taken.  Otherwise lock info->lock and return the flags.
+ */
+static unsigned long *ipmi_smb_lock_cond(struct smb_info *smb_info,
+					 unsigned long *flags)
+{
+	if (smb_info->run_to_completion)
+		return NULL;
+	spin_lock_irqsave(&smb_info->msg_lock, *flags);
+	return flags;
+}
+
+static void ipmi_smb_unlock_cond(struct smb_info *smb_info,
+				 unsigned long *flags)
+{
+	if (!flags)
+		return;
+	spin_unlock_irqrestore(&smb_info->msg_lock, *flags);
+}
+
+static void deliver_recv_msg(struct smb_info *smb_info,
+			     struct ipmi_smi_msg *msg)
+{
+	ipmi_smi_t    intf = smb_info->intf;
+
+	if (!intf || (msg->rsp_size < 0)) {
+		return_hosed_msg(smb_info, msg);
+		printk(KERN_ERR
+		       "malformed message in deliver_recv_msg:"
+		       " rsp_size = %d\n", msg->rsp_size);
+		ipmi_free_smi_msg(msg);
+	} else {
+		ipmi_smi_msg_received(intf, msg);
+	}
+}
+
+static void return_hosed_msg(struct smb_info *smb_info,
+			     struct ipmi_smi_msg *msg)
+{
+	smb_inc_stat(smb_info, hosed);
+
+	/* Make it a response */
+	msg->rsp[0] = msg->data[0] | 4;
+	msg->rsp[1] = msg->data[1];
+	msg->rsp[2] = 0xFF; /* Unknown error. */
+	msg->rsp_size = 3;
+
+	deliver_recv_msg(smb_info, msg);
+}
+
+/*
+ * Must be called with the message lock held.  This will release the
+ * message lock.  Note that the caller will check SMB_IDLE and start a
+ * new operation, so there is no need to check for new messages to
+ * start in here.
+ */
+static void start_clear_flags(struct smb_info *smb_info, unsigned long *flags)
+{
+	unsigned char msg[3];
+
+	smb_info->msg_flags &= ~WDT_PRE_TIMEOUT_INT;
+	smb_info->smb_state = SMB_CLEARING_FLAGS;
+	ipmi_smb_unlock_cond(smb_info, flags);
+
+	/* Make sure the watchdog pre-timeout flag is not set at startup. */
+	msg[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
+	msg[2] = WDT_PRE_TIMEOUT_INT;
+
+	if (start_send(smb_info, msg, 3) != 0) {
+		/* Error, just go to normal state. */
+		smb_info->smb_state = SMB_NORMAL;
+	}
+}
+
+static void start_flag_fetch(struct smb_info *smb_info, unsigned long *flags)
+{
+	unsigned char mb[2];
+
+	smb_info->req_flags = 0;
+	smb_info->smb_state = SMB_GETTING_FLAGS;
+	ipmi_smb_unlock_cond(smb_info, flags);
+
+	mb[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	mb[1] = IPMI_GET_MSG_FLAGS_CMD;
+	if (start_send(smb_info, mb, 2) != 0)
+		smb_info->smb_state = SMB_NORMAL;
+}
+
+static void start_event_fetch(struct smb_info *smb_info, unsigned long *flags)
+{
+	struct ipmi_smi_msg *msg;
+
+	smb_info->req_events = 0;
+
+	msg = ipmi_alloc_smi_msg();
+	if (!msg) {
+		smb_info->smb_state = SMB_NORMAL;
+		return;
+	}
+
+	smb_info->curr_msg = msg;
+	smb_info->smb_state = SMB_GETTING_EVENTS;
+	ipmi_smb_unlock_cond(smb_info, flags);
+
+	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg->data[1] = IPMI_READ_EVENT_MSG_BUFFER_CMD;
+	msg->data_size = 2;
+
+	if (start_send(smb_info, msg->data, msg->data_size) != 0) {
+		unsigned long oflags;
+		flags = ipmi_smb_lock_cond(smb_info, &oflags);
+		smb_info->curr_msg = NULL;
+		smb_info->smb_state = SMB_NORMAL;
+		ipmi_smb_unlock_cond(smb_info, flags);
+		ipmi_free_smi_msg(msg);
+	}
+}
+
+static void start_recv_msg_fetch(struct smb_info *smb_info,
+				 unsigned long *flags)
+{
+	struct ipmi_smi_msg *msg;
+
+	msg = ipmi_alloc_smi_msg();
+	if (!msg) {
+		smb_info->smb_state = SMB_NORMAL;
+		return;
+	}
+
+	smb_info->curr_msg = msg;
+	smb_info->smb_state = SMB_GETTING_MESSAGES;
+	ipmi_smb_unlock_cond(smb_info, flags);
+
+	msg->data[0] = (IPMI_NETFN_APP_REQUEST << 2);
+	msg->data[1] = IPMI_GET_MSG_CMD;
+	msg->data_size = 2;
+
+	if (start_send(smb_info, msg->data, msg->data_size) != 0) {
+		unsigned long oflags;
+		flags = ipmi_smb_lock_cond(smb_info, &oflags);
+		smb_info->curr_msg = NULL;
+		smb_info->smb_state = SMB_NORMAL;
+		ipmi_smb_unlock_cond(smb_info, flags);
+		ipmi_free_smi_msg(msg);
+	}
+}
+
+/*
+ * Must be called with the message lock held.  This will release the
+ * message lock.  Note that the caller will check SMB_IDLE and start a
+ * new operation, so there is no need to check for new messages to
+ * start in here.
+ */
+static void handle_flags(struct smb_info *smb_info, unsigned long *flags)
+{
+	if (smb_info->msg_flags & WDT_PRE_TIMEOUT_INT)
+		/* Watchdog pre-timeout */
+		start_clear_flags(smb_info, flags);
+	else if (smb_info->msg_flags & RECEIVE_MSG_AVAIL)
+		/* Messages available. */
+		start_recv_msg_fetch(smb_info, flags);
+	else if (smb_info->msg_flags & EVENT_MSG_BUFFER_FULL)
+		/* Events available. */
+		start_event_fetch(smb_info, flags);
+	else {
+		smb_info->smb_state = SMB_NORMAL;
+		ipmi_smb_unlock_cond(smb_info, flags);
+	}
+}
+
+static void msg_done_handler(struct i2c_op_q_entry *i2ce);
+static void retry_timeout(unsigned long data)
+{
+	struct smb_info     *smb_info = (void *) data;
+	struct i2c_op_q_entry *i2ce;
+
+	smb_info->rtc_us_timer = 0;
+
+	i2ce = &smb_info->i2c_q_entry;
+	i2ce->xfer_type = I2C_OP_SMBUS;
+	i2ce->handler = msg_done_handler;
+	i2ce->handler_data = smb_info;
+	i2ce->smbus.read_write = I2C_SMBUS_READ;
+	i2ce->smbus.command = SMB_IPMI_RESPONSE;
+	i2ce->smbus.data = (union i2c_smbus_data *) smb_info->recv;
+	i2ce->smbus.size = I2C_SMBUS_BLOCK_DATA;
+
+	if (i2c_non_blocking_op(&smb_info->client, i2ce)) {
+		/* request failed, just return the error. */
+		if (smb_info->smb_debug & SMB_DEBUG_MSG) {
+			printk(KERN_INFO
+			       "Error from i2c_non_blocking_op(5)\n");
+		}
+		i2ce->result = -EIO;
+		msg_done_handler(i2ce);
+	}
+}
+
+static int start_resend(struct smb_info *smb_info);
+static void msg_done_handler(struct i2c_op_q_entry *i2ce)
+{
+	struct smb_info     *smb_info = i2ce->handler_data;
+	unsigned char       *data = smb_info->recv;
+	int                 len;
+	int                 result = i2ce->result;
+	struct ipmi_smi_msg *msg;
+	unsigned long       oflags, *flags;
+
+	/*
+	 * We are single-threaded here, so no need for a lock until we
+	 * start messing with driver states or the queues.
+	 */
+
+	if (result < 0) {
+		smb_info->retries_left--;
+		if (smb_info->retries_left > 0) {
+			smb_inc_stat(smb_info, receive_retries);
+
+			mod_timer(&smb_info->retry_timer,
+				  jiffies + SMB_MSG_JIFFIES);
+			smb_info->rtc_us_timer = SMB_MSG_USEC;
+			return;
+		}
+
+		smb_inc_stat(smb_info, receive_errors);
+
+		if  (smb_info->smb_debug & SMB_DEBUG_MSG)
+			printk(KERN_INFO
+			       "Error in msg_done_handler: %d\n", i2ce->result);
+		len = 0;
+		goto continue_op;
+	}
+
+	len = data[0]; /* Number of bytes *after* data[0]. */
+	data++;
+	if ((len > 1) && (smb_info->multi_pos == 0)
+				&& (data[0] == 0x00) && (data[1] == 0x01)) {
+		/* Start of multi-part read.  Start the next transaction. */
+		int i;
+
+		smb_inc_stat(smb_info, received_message_parts);
+
+		/* Remove the multi-part read marker. */
+		for (i = 0; i < (len-2); i++)
+			smb_info->data[i] = data[i+2];
+		len -= 2;
+		smb_info->multi_len = len;
+		smb_info->multi_pos = 1;
+
+		i2ce->xfer_type = I2C_OP_SMBUS;
+		i2ce->handler = msg_done_handler;
+		i2ce->handler_data = smb_info;
+		i2ce->smbus.read_write = I2C_SMBUS_READ;
+		i2ce->smbus.command = SMB_IPMI_MULTI_PART_RESPONSE_MIDDLE;
+		i2ce->smbus.data = ((union i2c_smbus_data *) smb_info->recv);
+		i2ce->smbus.size = I2C_SMBUS_BLOCK_DATA;
+		if (i2c_non_blocking_op(&smb_info->client, i2ce)) {
+			if (smb_info->smb_debug & SMB_DEBUG_MSG) {
+				printk(KERN_INFO
+				       "Error from i2c_non_blocking_op(1)\n");
+			}
+			result = -EIO;
+		} else
+			return;
+	} else if (smb_info->multi_pos) {
+		/* Middle of multi-part read.  Start the next transaction. */
+		int i;
+		unsigned char blocknum;
+
+		if (len == 0) {
+			result = -EIO;
+			if (smb_info->smb_debug & SMB_DEBUG_MSG) {
+				printk(KERN_INFO
+				       "Received middle message with no"
+				       " data\n");
+			}
+			goto continue_op;
+		}
+
+		blocknum = data[smb_info->multi_len];
+
+		if (smb_info->multi_len+len-1 > IPMI_MAX_MSG_LENGTH) {
+			/* Received message too big, abort the operation. */
+			result = -E2BIG;
+			if (smb_info->smb_debug & SMB_DEBUG_MSG) {
+				printk(KERN_INFO
+				       "Received message too big\n");
+			}
+			goto continue_op;
+		}
+
+		/* Remove the blocknum from the data. */
+		for (i = 0; i < (len-1); i++)
+			smb_info->data[i+smb_info->multi_len] = data[i+1];
+		len--;
+		smb_info->multi_len += len;
+		if (blocknum == 0xff) {
+			/* End of read */
+			len = smb_info->multi_len;
+			data = smb_info->data;
+		} else if ((blocknum+1) != smb_info->multi_pos) {
+			/*
+			 * Out of sequence block, just abort.  Block
+			 * numbers start at zero for the second block,
+			 * but multi_pos starts at one, so the +1.
+			 */
+			result = -EIO;
+		} else {
+			smb_inc_stat(smb_info, received_message_parts);
+
+			smb_info->multi_pos++;
+			i2ce->xfer_type = I2C_OP_SMBUS;
+			i2ce->handler = msg_done_handler;
+			i2ce->handler_data = smb_info;
+			i2ce->smbus.read_write = I2C_SMBUS_READ;
+			i2ce->smbus.command
+				= SMB_IPMI_MULTI_PART_RESPONSE_MIDDLE;
+			i2ce->smbus.data = ((union i2c_smbus_data *)
+					    smb_info->recv);
+			i2ce->smbus.size = I2C_SMBUS_BLOCK_DATA;
+
+			if (i2c_non_blocking_op(&smb_info->client, i2ce)) {
+				if (smb_info->smb_debug & SMB_DEBUG_MSG) {
+					printk(KERN_INFO "Error from"
+					       " i2c_non_blocking_op(2)\n");
+				}
+				result = -EIO;
+			} else
+				return;
+		}
+	}
+
+	if (result < 0) {
+		smb_inc_stat(smb_info, receive_errors);
+	} else {
+		smb_inc_stat(smb_info, received_messages);
+		smb_inc_stat(smb_info, received_message_parts);
+	}
+
+
+ continue_op:
+	if (smb_info->smb_debug & SMB_DEBUG_STATE)
+		printk(KERN_INFO "DONE 1: state = %d, result=%d.\n",
+		       smb_info->smb_state, result);
+
+	flags = ipmi_smb_lock_cond(smb_info, &oflags);
+	msg = smb_info->curr_msg;
+	if (msg) {
+		msg->rsp_size = len;
+		if (msg->rsp_size > IPMI_MAX_MSG_LENGTH)
+			msg->rsp_size = IPMI_MAX_MSG_LENGTH;
+		memcpy(msg->rsp, data, msg->rsp_size);
+		smb_info->curr_msg = NULL;
+	}
+
+	switch (smb_info->smb_state) {
+	case SMB_NORMAL:
+		ipmi_smb_unlock_cond(smb_info, flags);
+		if (!msg)
+			break;
+
+		if (result < 0)
+			return_hosed_msg(smb_info, msg);
+		else
+			deliver_recv_msg(smb_info, msg);
+		break;
+
+	case SMB_GETTING_FLAGS:
+		/* We got the flags from the SMB, now handle them. */
+		if ((result < 0) || (len < 4) || (data[2] != 0)) {
+			/*
+			 * Error fetching flags, or invalid length,
+			 * just give up for now.
+			 */
+			smb_info->smb_state = SMB_NORMAL;
+			ipmi_smb_unlock_cond(smb_info, flags);
+			printk(KERN_WARNING
+			       PFX "Error getting flags: %d %d, %2.2x\n",
+			       result, len, data[2]);
+		} else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
+			   || data[1] != IPMI_GET_MSG_FLAGS_CMD) {
+			printk(KERN_WARNING
+			       PFX "Invalid response getting flags: "
+			       "%2.2x %2.2x\n", data[0], data[1]);
+		} else {
+			smb_inc_stat(smb_info, flag_fetches);
+			smb_info->msg_flags = data[3];
+			handle_flags(smb_info, flags);
+		}
+		break;
+
+	case SMB_CLEARING_FLAGS:
+		/* We cleared the flags. */
+		if ((result < 0) || (len < 3) || (data[2] != 0)) {
+			/* Error clearing flags */
+			printk(KERN_WARNING
+			       PFX "Error clearing flags: %d %d, %2.2x\n",
+			       result, len, data[2]);
+		} else if (data[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
+			   || data[1] != IPMI_CLEAR_MSG_FLAGS_CMD) {
+			printk(KERN_WARNING
+			       PFX "Invalid response clearing flags: "
+			       "%2.2x %2.2x\n", data[0], data[1]);
+		}
+		smb_info->smb_state = SMB_NORMAL;
+		ipmi_smb_unlock_cond(smb_info, flags);
+		break;
+
+	case SMB_GETTING_EVENTS:
+		if ((result < 0) || (len < 3) || (msg->rsp[2] != 0)) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the event flag. */
+			smb_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+			handle_flags(smb_info, flags);
+		} else if (msg->rsp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
+			   || msg->rsp[1] != IPMI_READ_EVENT_MSG_BUFFER_CMD) {
+			printk(KERN_WARNING
+			       PFX "Invalid response getting events: "
+			       "%2.2x %2.2x\n", msg->rsp[0], msg->rsp[1]);
+			msg->done(msg);
+			/* Take off the event flag. */
+			smb_info->msg_flags &= ~EVENT_MSG_BUFFER_FULL;
+			handle_flags(smb_info, flags);
+		} else {
+			handle_flags(smb_info, flags);
+			smb_inc_stat(smb_info, events);
+			deliver_recv_msg(smb_info, msg);
+		}
+		break;
+
+	case SMB_GETTING_MESSAGES:
+		if ((result < 0) || (len < 3) || (msg->rsp[2] != 0)) {
+			/* Error getting event, probably done. */
+			msg->done(msg);
+
+			/* Take off the msg flag. */
+			smb_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+			handle_flags(smb_info, flags);
+		} else if (msg->rsp[0] != (IPMI_NETFN_APP_REQUEST | 1) << 2
+			   || msg->rsp[1] != IPMI_GET_MSG_CMD) {
+			printk(KERN_WARNING
+			       PFX "Invalid response clearing flags: "
+			       "%2.2x %2.2x\n", msg->rsp[0], msg->rsp[1]);
+			msg->done(msg);
+
+			/* Take off the msg flag. */
+			smb_info->msg_flags &= ~RECEIVE_MSG_AVAIL;
+			handle_flags(smb_info, flags);
+		} else {
+			smb_inc_stat(smb_info, incoming_messages);
+			handle_flags(smb_info, flags);
+			deliver_recv_msg(smb_info, msg);
+		}
+		break;
+	}
+
+	flags = ipmi_smb_lock_cond(smb_info, &oflags);
+	if (SMB_IDLE(smb_info)) {
+		if (smb_info->req_events)
+			start_event_fetch(smb_info, flags);
+		else if (smb_info->req_flags)
+			start_flag_fetch(smb_info, flags);
+		else
+			start_next_msg(smb_info, flags);
+	} else
+		ipmi_smb_unlock_cond(smb_info, flags);
+
+	if (smb_info->smb_debug & SMB_DEBUG_STATE)
+		printk(KERN_INFO "DONE 2: state = %d.\n", smb_info->smb_state);
+}
+
+static void msg_written_handler(struct i2c_op_q_entry *i2ce)
+{
+	struct smb_info *smb_info = i2ce->handler_data;
+
+	/* We are single-threaded here, so no need for a lock. */
+	if (i2ce->result < 0) {
+		smb_info->retries_left--;
+		if (smb_info->retries_left > 0) {
+			if (!start_resend(smb_info)) {
+				smb_inc_stat(smb_info, send_retries);
+				return;
+			}
+			/* request failed, just return the error. */
+			smb_inc_stat(smb_info, send_errors);
+
+			if (smb_info->smb_debug & SMB_DEBUG_MSG) {
+				printk(KERN_INFO "Out of retries in"
+				       " msg_written_handler\n");
+			}
+			i2ce->result = -EIO;
+			msg_done_handler(i2ce);
+			return;
+		}
+
+		smb_inc_stat(smb_info, send_errors);
+
+		/*
+		 * Got an error on transmit, let the done routine
+		 * handle it.
+		 */
+		if (smb_info->smb_debug & SMB_DEBUG_MSG) {
+			printk(KERN_INFO
+			       "Error in msg_written_handler: %d\n",
+			       i2ce->result);
+		}
+		msg_done_handler(i2ce);
+		return;
+	}
+
+	if (smb_info->multi_data) {
+		/* In the middle of a multi-data write. */
+		int left;
+
+		smb_inc_stat(smb_info, sent_messages_parts);
+
+		left = smb_info->multi_len - smb_info->multi_pos;
+		if (left > 32)
+			left = 32;
+		i2ce->xfer_type = I2C_OP_SMBUS;
+		i2ce->handler = msg_written_handler;
+		i2ce->handler_data = smb_info;
+		i2ce->smbus.read_write = I2C_SMBUS_WRITE;
+		i2ce->smbus.data
+			= ((union i2c_smbus_data *)
+			   (smb_info->multi_data + smb_info->multi_pos));
+		/* Length byte. */
+		smb_info->multi_data[smb_info->multi_pos] = left;
+		i2ce->smbus.size = I2C_SMBUS_BLOCK_DATA;
+		smb_info->multi_pos += left;
+		i2ce->smbus.command = SMB_IPMI_MULTI_PART_REQUEST_MIDDLE;
+		if (left < 32)
+			/*
+			 * Write is finished.  Note that we must end
+			 * with a write of less than 32 bytes to
+			 * complete the transaction, even if it is
+			 * zero bytes.
+			 */
+			smb_info->multi_data = NULL;
+	} else {
+		smb_inc_stat(smb_info, sent_messages);
+		smb_inc_stat(smb_info, sent_messages_parts);
+
+		/* Wait a jiffie then request the next message */
+		smb_info->retries_left = SMB_RECV_RETRIES;
+		mod_timer(&smb_info->retry_timer,
+			  jiffies + SMB_MSG_PART_JIFFIES);
+		smb_info->rtc_us_timer = SMB_MSG_PART_USEC;
+		return;
+	}
+
+	if (i2c_non_blocking_op(&smb_info->client, i2ce)) {
+		/* request failed, just return the error. */
+		smb_inc_stat(smb_info, send_errors);
+
+		if (smb_info->smb_debug & SMB_DEBUG_MSG) {
+			printk(KERN_INFO
+			       "Error from i2c_non_blocking_op(3)\n");
+		}
+		i2ce->result = -EIO;
+		msg_done_handler(i2ce);
+	}
+}
+
+static int start_resend(struct smb_info *smb_info)
+{
+	struct i2c_op_q_entry *i2ce;
+	int                   rv;
+
+	i2ce = &smb_info->i2c_q_entry;
+	i2ce->xfer_type = I2C_OP_SMBUS;
+	i2ce->handler = msg_written_handler;
+	i2ce->handler_data = smb_info;
+	i2ce->smbus.read_write = I2C_SMBUS_WRITE;
+
+	i2ce->smbus.data = (union i2c_smbus_data *) smb_info->data;
+	i2ce->smbus.size = I2C_SMBUS_BLOCK_DATA;
+
+	if (smb_info->data_len > 32) {
+		i2ce->smbus.command = SMB_IPMI_MULTI_PART_REQUEST_START;
+		smb_info->multi_data = smb_info->data;
+		smb_info->multi_len = smb_info->data_len;
+		/*
+		 * Subtle thing, this is 32, not 33, because we will
+		 * overwrite the thing at position 32 (which was just
+		 * transmitted) with the new length.
+		 */
+		smb_info->multi_pos = 32;
+		smb_info->data[0] = 32;
+	} else {
+		smb_info->multi_data = NULL;
+		i2ce->smbus.command = SMB_IPMI_REQUEST;
+		smb_info->data[0] = smb_info->data_len;
+	}
+
+	rv = i2c_non_blocking_op(&smb_info->client, i2ce);
+	if (rv && (smb_info->smb_debug & SMB_DEBUG_MSG)) {
+		printk(KERN_INFO
+		       "Error from i2c_non_blocking_op(4)\n");
+	}
+	return rv;
+}
+
+static int start_send(struct smb_info *smb_info,
+		      unsigned char   *data,
+		      unsigned int    len)
+{
+//	printk(KERN_ERR "start_send: data[0] 0x%x data[1] 0x%x len 0x%x\n", 
+//		data[0], data[1], len);
+
+	if (len > IPMI_MAX_MSG_LENGTH)
+		return -E2BIG;
+	if (len > smb_info->max_xmit_msg_size)
+		return -E2BIG;
+
+	smb_info->retries_left = SMB_SEND_RETRIES;
+	memcpy(smb_info->data+1, data, len);
+	smb_info->data_len = len;
+	return start_resend(smb_info);
+}
+
+/* Must be called with the message lock held. */
+static void start_next_msg(struct smb_info *smb_info, unsigned long *flags)
+{
+	struct list_head    *entry;
+	struct ipmi_smi_msg *msg;
+	unsigned long oflags;
+
+ restart:
+	entry = NULL;
+	if (!SMB_IDLE(smb_info)) {
+		ipmi_smb_unlock_cond(smb_info, flags);
+		return;
+	}
+
+	/* Pick the high priority queue first. */
+	if (!list_empty(&smb_info->hp_xmit_msgs))
+		entry = smb_info->hp_xmit_msgs.next;
+	else if (!list_empty(&smb_info->xmit_msgs))
+		entry = smb_info->xmit_msgs.next;
+
+	if (!entry) {
+		smb_info->curr_msg = NULL;
+		ipmi_smb_unlock_cond(smb_info, flags);
+	} else {
+		int rv;
+
+		list_del(entry);
+		msg = list_entry(entry, struct ipmi_smi_msg, link);
+		smb_info->curr_msg = msg;
+		ipmi_smb_unlock_cond(smb_info, flags);
+		rv = start_send(smb_info,
+				smb_info->curr_msg->data,
+				smb_info->curr_msg->data_size);
+		if (rv) {
+			smb_info->curr_msg = NULL;
+			return_hosed_msg(smb_info, msg);
+			flags = ipmi_smb_lock_cond(smb_info, &oflags);
+			goto restart;
+		}
+	}
+}
+
+static void sender(void                *send_info,
+		   struct ipmi_smi_msg *msg,
+		   int                 priority)
+{
+	struct smb_info *smb_info = (struct smb_info *) send_info;
+	unsigned long oflags, *flags;
+
+	flags = ipmi_smb_lock_cond(smb_info, &oflags);
+	if (smb_info->run_to_completion) {
+		/*
+		 * If we are running to completion, then throw it in
+		 * the list and run transactions until everything is
+		 * clear.  Priority doesn't matter here.
+		 */
+		list_add_tail(&msg->link, &smb_info->xmit_msgs);
+		start_next_msg(smb_info, flags);
+
+		i2c_poll(&smb_info->client, 0);
+		while (!SMB_IDLE(smb_info)) {
+			udelay(500);
+			if (smb_info->rtc_us_timer > 0) {
+				smb_info->rtc_us_timer -= 500;
+				if (smb_info->rtc_us_timer <= 0) {
+					retry_timeout((unsigned long) smb_info);
+					del_timer(&smb_info->retry_timer);
+				}
+			}
+			i2c_poll(&smb_info->client, 500);
+		}
+		return;
+	}
+
+
+	if (priority > 0)
+		list_add_tail(&msg->link, &smb_info->hp_xmit_msgs);
+	else
+		list_add_tail(&msg->link, &smb_info->xmit_msgs);
+	start_next_msg(smb_info, flags);
+
+	if (smb_info->smb_debug & SMB_DEBUG_TIMING) {
+		struct timeval     t;
+		do_gettimeofday(&t);
+		printk(KERN_INFO
+		       "**Enqueue %02x %02x: %ld.%6.6ld\n",
+		       msg->data[0], msg->data[1], t.tv_sec, t.tv_usec);
+	}
+}
+
+/*
+ * Instead of having our own timer to periodically check the message
+ * flags, we let the message handler drive us.
+ */
+static void request_events(void *send_info)
+{
+	struct smb_info *smb_info = (struct smb_info *) send_info;
+	unsigned long oflags, *flags;
+
+	/*
+	 * If we are stopping, just ignore requests for events.  It's
+	 * not a big deal if the stop fails and we miss one of
+	 * these.
+	 */
+	if (smb_info->stopping || !smb_info->has_event_buffer)
+		return;
+
+	flags = ipmi_smb_lock_cond(smb_info, &oflags);
+	/*
+	 * Request flags first, not events, because the lower layer
+	 * doesn't have a way to send an attention.  But make sure
+	 * event checking still happens.
+	 */
+	smb_info->req_events = 1;
+	if (SMB_IDLE(smb_info))
+		start_flag_fetch(smb_info, flags);
+	else {
+		smb_info->req_flags = 1;
+		ipmi_smb_unlock_cond(smb_info, flags);
+	}
+}
+
+static void set_run_to_completion(void *send_info, int i_run_to_completion)
+{
+	struct smb_info *smb_info = (struct smb_info *) send_info;
+
+	smb_info->run_to_completion = i_run_to_completion;
+	/*
+	 * Note that if this does not compile, there are some I2C
+	 * changes that you need to handle this properly.
+	 */
+	if (i_run_to_completion) {
+		i2c_poll(&smb_info->client, 0);
+		while (!SMB_IDLE(smb_info)) {
+			udelay(500);
+			if (smb_info->rtc_us_timer > 0) {
+				smb_info->rtc_us_timer -= 500;
+				if (smb_info->rtc_us_timer <= 0) {
+					retry_timeout((unsigned long) smb_info);
+					del_timer(&smb_info->retry_timer);
+				}
+			}
+			i2c_poll(&smb_info->client, 500);
+		}
+	}
+}
+
+static void poll(void *send_info)
+{
+	struct smb_info *smb_info = send_info;
+	i2c_poll(&smb_info->client, 10);
+}
+
+static int inc_usecount(void *send_info)
+{
+	struct smb_info *smb_info = send_info;
+	i2c_use_client(&smb_info->client);
+	return 0;
+}
+
+static void dec_usecount(void *send_info)
+{
+	struct smb_info *smb_info = send_info;
+	i2c_release_client(&smb_info->client);
+}
+
+static int smb_start_processing(void       *send_info,
+				ipmi_smi_t intf)
+{
+	struct smb_info *smb_info = send_info;
+	int             rv;
+
+	smb_info->intf = intf;
+
+	rv = i2c_attach_client(&smb_info->client);
+	if (rv) {
+		smb_info->intf = NULL;
+		printk(KERN_ERR
+		       "smb_found_one_addr_proc:"
+		       " Unable to attach i2c client: error %d\n",
+		       rv);
+	}
+
+	return rv;
+}
+
+static struct ipmi_smi_handlers handlers = {
+	.owner                 = THIS_MODULE,
+	.start_processing      = smb_start_processing,
+	.sender		       = sender,
+	.request_events        = request_events,
+	.set_run_to_completion = set_run_to_completion,
+	.poll		       = poll,
+	.inc_usecount	       = inc_usecount,
+	.dec_usecount	       = dec_usecount
+};
+
+static int type_file_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	return sprintf(page, "smb\n");
+}
+
+static int stat_file_read_proc(char *page, char **start, off_t off,
+			       int count, int *eof, void *data)
+{
+	char            *out = (char *) page;
+	struct smb_info *smb_info = data;
+
+	out += sprintf(out, "sent_messages:          %u\n",
+		       smb_get_stat(smb_info, sent_messages));
+	out += sprintf(out, "sent_messages_parts:    %u\n",
+		       smb_get_stat(smb_info, sent_messages_parts));
+	out += sprintf(out, "send_retries:           %u\n",
+		       smb_get_stat(smb_info, send_retries));
+	out += sprintf(out, "send_errors:            %u\n",
+		       smb_get_stat(smb_info, send_errors));
+	out += sprintf(out, "received_messages:      %u\n",
+		       smb_get_stat(smb_info, received_messages));
+	out += sprintf(out, "received_message_parts: %u\n",
+		       smb_get_stat(smb_info, received_message_parts));
+	out += sprintf(out, "receive_retries:        %u\n",
+		       smb_get_stat(smb_info, receive_retries));
+	out += sprintf(out, "receive_errors:         %u\n",
+		       smb_get_stat(smb_info, receive_errors));
+	out += sprintf(out, "flag_fetches:           %u\n",
+		       smb_get_stat(smb_info, flag_fetches));
+	out += sprintf(out, "hosed:                  %u\n",
+		       smb_get_stat(smb_info, hosed));
+	out += sprintf(out, "events:                 %u\n",
+		       smb_get_stat(smb_info, events));
+
+	return (out - ((char *) page));
+}
+
+
+static int attach_adapter(struct i2c_adapter *adapter);
+static int detach_client(struct i2c_client *client);
+static struct i2c_driver smb_i2c_driver = {
+	.attach_adapter = attach_adapter,
+	.detach_client  = detach_client,
+	.driver         = {
+		.name  = "ipmi_smb"
+	}
+//	.detect		= 
+//	.address_data	= &addr_data,
+};
+
+static int do_cmd(struct i2c_client *client, int len, unsigned char *msg,
+		  int *resp_len, unsigned char *resp)
+{
+	int retry_cnt;
+	int ret;
+
+	retry_cnt = SMB_SEND_RETRIES;
+ retry1:
+	ret = i2c_smbus_write_block_data(client, SMB_IPMI_REQUEST, len, msg);
+	if (ret) {
+		retry_cnt--;
+		if (retry_cnt > 0)
+			goto retry1;
+		return -ENODEV;
+	}
+
+	ret = -ENODEV;
+	retry_cnt = SMB_RECV_RETRIES;
+	while (retry_cnt > 0) {
+		ret = i2c_smbus_read_block_data(client, SMB_IPMI_RESPONSE,
+						resp);
+		if (ret > 0)
+			break;
+		msleep(SMB_MSG_MSEC);
+		retry_cnt--;
+		if (retry_cnt <= 0)
+			break;
+	}
+
+	if (ret > 0) {
+		/* Validate that the response is correct. */
+		if (ret < 3 ||
+		    (resp[0] != (msg[0] | (1 << 2))) ||
+		    (resp[1] != msg[1]))
+			ret = -EINVAL;
+		else {
+			*resp_len = ret;
+			ret = 0;
+		}
+	}
+
+	return ret;
+}
+
+static int ipmi_smb_detect_hardware(struct i2c_adapter *adapter, int addr,
+				    int debug, struct smb_info **smb_info)
+{
+	unsigned char     msg[3];
+	unsigned char     *resp;
+	struct smb_info   *info;
+	int               rv = 0;
+	struct i2c_client *client;
+	int               len;
+
+	resp = kmalloc(IPMI_MAX_MSG_LENGTH, GFP_KERNEL);
+	if (!resp)
+		return -ENOMEM;
+
+	info = kzalloc(sizeof(*info), GFP_KERNEL);
+	if (!info) {
+		kfree(resp);
+		return -ENOMEM;
+	}
+
+	client = &info->client;
+	strlcpy(client->name, "IPMI", I2C_NAME_SIZE);
+	client->addr = addr;
+	client->adapter = adapter;
+	client->driver = &smb_i2c_driver;
+
+	/* Do a Get Device ID command, since it comes back with some
+	   useful info. */
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_DEVICE_ID_CMD;
+	rv = do_cmd(client, 2, msg, &len, resp);
+	if (rv)
+		goto out;
+
+	rv = ipmi_demangle_device_id(resp, len, &info->device_id);
+	if (rv) 
+		goto out;
+
+	info->client = *client;
+	i2c_set_clientdata(&info->client, info);
+	info->smb_debug = debug;
+
+	/* Now check for system interface capabilities */
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_SYSTEM_INTERFACE_CAPABILITIES_CMD;
+	msg[2] = 0; /* SSIF */
+	rv = do_cmd(client, 3, msg, &len, resp);
+	if (!rv && (len >= 3) && (resp[2] == 0)) {
+		if (len < 7) {
+			if (smb_dbg_probe)
+				printk(KERN_INFO
+				       PFX "SSIF info too short: %d\n", len);
+			goto no_support;
+		}
+
+		/* Got a good SSIF response, handle it. */
+		info->max_xmit_msg_size = resp[5];
+		info->max_recv_msg_size = resp[6];
+		info->multi_support = (resp[4] >> 6) & 0x3;
+		info->supports_pec = (resp[4] >> 3) & 0x1;
+
+		/* Sanitize the data */
+		switch (info->multi_support) {
+		case SMB_NO_MULTI:
+			printk(KERN_INFO "ipmi_smb: No Multi Support. Max Rcv Size %d, Max Xmit Size %d\n", info->max_recv_msg_size, info->max_xmit_msg_size);
+			if (info->max_xmit_msg_size > 32)
+				info->max_xmit_msg_size = 32;
+			if (info->max_recv_msg_size > 32)
+				info->max_recv_msg_size = 32;
+			break;
+
+		case SMB_MULTI_2_PART:
+			printk(KERN_INFO "ipmi_smb: Multi 2 Part Support. Max Rcv Size %d, Max Xmit Size %d\n", info->max_recv_msg_size, info->max_xmit_msg_size);
+			if (info->max_xmit_msg_size > 64)
+				info->max_xmit_msg_size = 64;
+			if (info->max_recv_msg_size > 62)
+				info->max_recv_msg_size = 62;
+			break;
+
+		case SMB_MULTI_n_PART:
+			printk(KERN_INFO "ipmi_smb: Multi N Part Support. Max Rcv Size %d, Max Xmit Size %d\n", info->max_recv_msg_size, info->max_xmit_msg_size);
+			break;
+
+		default:
+			/* Data is not sane, just give up. */
+			printk(KERN_INFO "ipmi_smb: Incomprehensible Multi Support data\n"); 
+			goto no_support;
+		}
+	} else {
+ no_support:
+		/* Assume no multi-part or PEC support */
+		printk(KERN_INFO PFX "Error fetching SSIF: %d %d %2.2x, "
+		       "your system probably doesn't support this command so "
+		       "using defaults\n",
+		       rv, len, resp[2]);
+
+		info->max_xmit_msg_size = 32;
+		info->max_recv_msg_size = 32;
+		info->multi_support = SMB_NO_MULTI;
+		info->supports_pec = 0;
+	}
+
+	/* Make sure the NMI timeout is cleared. */
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_CLEAR_MSG_FLAGS_CMD;
+	msg[2] = WDT_PRE_TIMEOUT_INT;
+	rv = do_cmd(client, 3, msg, &len, resp);
+	if (rv || (len < 3) || (resp[2] != 0))
+		printk(KERN_WARNING
+		       PFX "Unable to clear NMI timeout flags: %d %d %2.2x\n",
+		       rv, len, resp[2]);
+
+	/* Attempt to enable the event buffer. */
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_GET_BMC_GLOBAL_ENABLES_CMD;
+	rv = do_cmd(client, 2, msg, &len, resp);
+	if (rv || (len < 4) || (resp[2] != 0)) {
+		printk(KERN_WARNING
+		       PFX "Error getting global enables: %d %d %2.2x\n",
+		       rv, len, resp[2]);
+		rv = 0; /* Not fatal */
+		goto done;
+	}
+
+	if (resp[3] & IPMI_BMC_EVT_MSG_BUFF) {
+		info->has_event_buffer = 1;
+		/* buffer is already enabled, nothing to do. */
+		goto done;
+	}
+
+	msg[0] = IPMI_NETFN_APP_REQUEST << 2;
+	msg[1] = IPMI_SET_BMC_GLOBAL_ENABLES_CMD;
+	msg[2] = resp[3] | IPMI_BMC_EVT_MSG_BUFF;
+	rv = do_cmd(client, 3, msg, &len, resp);
+	if (rv || (len < 2)) {
+		printk(KERN_WARNING
+		       PFX "Error enabling Event Buffer using set global enables: %d %d %2.2x\n",
+		       rv, len, resp[2]);
+		rv = 0; /* Not fatal */
+		goto done;
+	}
+
+	if (resp[2] == 0)
+		/* A successful return means the event buffer is supported. */
+		info->has_event_buffer = 1;
+ done:
+
+	*smb_info = info;
+
+ out:
+	if (rv)
+		kfree(info);
+	kfree(resp);
+	return rv;
+}
+
+#define MAX_SMB_BMCS 4
+/* no expressions allowed in __MODULE_STRING */
+#define MAX_SMB_ADDR_PAIRS	8
+
+/* An array of SMB interfaces. */
+static struct smb_info *smb_infos[MAX_SMB_BMCS];
+
+static unsigned short addr[MAX_SMB_BMCS*2];
+static int num_addrs;
+
+module_param_array(addr, ushort, &num_addrs, 0);
+MODULE_PARM_DESC(addr, "Sets the addresses to scan for IPMI BMCs on the SMBus."
+		 " By default the driver will scan for anything it finds in"
+		 " DMI or ACPI tables.  Otherwise you have to hand-specify"
+		 " the address.  This is a list of pairs (ie a,b,c,d) where"
+		 " each pair gives an adapter and an address.  In the"
+		 " previous example it will scan address b on adapter a"
+		 " and address d on adapter c."
+		 " The first pair is for the first interface, etc.  If you"
+		 " don't provide this and don't have DMI/ACPI, it probably"
+		 " won't work.");
+
+static int smb_defaultprobe;
+module_param_named(defaultprobe, smb_defaultprobe, int, 0);
+MODULE_PARM_DESC(defaultprobe, "Normally the driver will not scan anything"
+		 " but the specified values and DMI/ACPI values.  If you set"
+		 " this to non-zero it will scan all addresses except for"
+		 " certain dangerous ones.");
+
+static int slave_addrs[MAX_SMB_BMCS];
+static int num_slave_addrs;
+module_param_array(slave_addrs, int, &num_slave_addrs, 0);
+MODULE_PARM_DESC(slave_addrs, "Set the default IPMB slave address for"
+		 " the controller.  Normally this is 0x20, but can be"
+		 " overridden by this parm.  This is an array indexed"
+		 " by interface number.");
+
+static int dbg[MAX_SMB_BMCS];
+static int num_dbg;
+module_param_array(dbg, int, &num_dbg, 0);
+MODULE_PARM_DESC(dbg, "Turn on debugging.  Bit 0 enables message debugging,"
+		 " bit 1 enables state debugging, and bit 2 enables timing"
+		 " debugging.  This is an array indexed by interface number");
+
+module_param_named(dbg_probe, smb_dbg_probe, int, 0);
+MODULE_PARM_DESC(dbg_probe, "Enable debugging of probing of adapters.");
+
+/* force list has 2 entries - 0:bus/adapter no 1: i2c addr */
+#define	FORCE_LIST_ENTRIES	2
+static unsigned short const *smb_force_list[MAX_SMB_BMCS+1];
+static unsigned short smb_forces[MAX_SMB_BMCS][FORCE_LIST_ENTRIES+1];
+
+#define SMB_I2C_START_ADDR	0x20
+#define SMB_I2C_END_ADDR	0x4f
+
+static unsigned short normal_i2c[] = { 
+	0x10, 
+	I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD_1(IPMI);
+
+/*
+static unsigned int normal_isa[] = { SENSORS_ISA_END };
+static unsigned int normal_isa_range[] = { SENSORS_ISA_END };
+*/
+#if 0
+static unsigned short reserved[] =
+{
+/* As defined by SMBus Spec. Appendix C */
+	0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x28,
+	0x37,
+/* As defined by SMBus Spec. Sect. 5.2 */
+	0x01, 0x02, 0x03, 0x04, 0x05,
+	0x06, 0x07, 0x78, 0x79, 0x7a, 0x7b,
+	0x7c, 0x7d, 0x7e, 0x7f,
+/* Common PC addresses (bad idea) */
+	0x2d, 0x48, 0x49, /* sensors */
+	0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* eeproms */
+	0x69, /* clock chips */
+
+	I2C_CLIENT_END
+};
+#endif
+
+#if 0
+//static unsigned short smb_empty_list[] = { I2C_CLIENT_END, I2C_CLIENT_END };
+static unsigned short smb_empty_list[] = { SMB_I2C_START_ADDR, SMB_I2C_END_ADDR };
+
+static struct i2c_client_address_data smb_address_data = {
+	.normal_i2c 		= normal_i2c,
+//	.probe			= smb_empty_list,
+	.probe			= normal_i2c,
+	.ignore			= reserved,
+	.forces			= smb_force_list,
+};
+#endif
+
+static unsigned int pos_reserved_as(int pos)
+{
+	if (addr[pos*2+1] != 0)
+		return (addr[pos*2] << 16) | addr[pos*2+1];
+
+	return 0;
+}
+
+static int smb_found_addr_proc(struct i2c_adapter *adapter, int addr, int kind)
+{
+	int id = i2c_adapter_id(adapter);
+	int debug = 1;
+	int rv;
+	int i;
+	int next_pos;
+	struct smb_info *smb_info = NULL;
+
+	if (id >= MAX_SMB_BMCS)
+		return 0;
+	rv = ipmi_smb_detect_hardware(adapter, addr, debug, (struct smb_info **)&smb_info);
+	if (rv) {
+		if (smb_dbg_probe) {
+			printk(KERN_INFO
+			       "smb_found_addr_proc:No IPMI client 0x%x: %d\n",
+			       addr, rv);
+		}
+		return 0;
+	}
+
+	if (smb_dbg_probe) {
+		printk(KERN_INFO
+		       "smb_found_addr_proc: i2c_probe found device at"
+		       " i2c address %x\n", addr);
+	}
+
+	spin_lock_init(&smb_info->msg_lock);
+	INIT_LIST_HEAD(&smb_info->xmit_msgs);
+	INIT_LIST_HEAD(&smb_info->hp_xmit_msgs);
+	smb_info->smb_state = SMB_NORMAL;
+	init_timer(&smb_info->retry_timer);
+	smb_info->retry_timer.data = (unsigned long) smb_info;
+	smb_info->retry_timer.function = retry_timeout;
+
+	for (i = 0; i < SMB_NUM_STATS; i++)
+		atomic_set(&smb_info->stats[i], 0);
+
+	next_pos = -1;
+	for (i = 0; i < MAX_SMB_BMCS; i++) {
+		unsigned int res = pos_reserved_as(i);
+
+		if (res == ((id << 16) | addr)) {
+			/* We have a reserved position, use it. */
+			next_pos = i;
+			break;
+		}
+
+		/* Claim the first unused position */
+		if (!res && (next_pos == -1) && (smb_infos[next_pos] == NULL))
+			next_pos = i;
+	}
+	if (next_pos == -1) {
+		rv = -EBUSY;
+		goto out_err;
+	}
+
+	if (smb_info->supports_pec)
+		smb_info->client.flags |= I2C_CLIENT_PEC;
+
+	smb_info->pos = next_pos;
+	smb_infos[next_pos] = smb_info;
+
+	rv = ipmi_register_smi(&handlers,
+			       smb_info,
+			       &smb_info->device_id,
+			       &smb_info->client.dev,
+			       "bmc",
+			       slave_addrs[next_pos]);
+	 if (rv) {
+		if (smb_info->intf)
+			/* Only attached if intf is set. */
+			i2c_detach_client(&smb_info->client);
+		smb_infos[next_pos] = NULL;
+		printk(KERN_ERR
+		       PFX "Unable to register device: error %d\n",
+		       rv);
+		goto out_err;
+	}
+
+	rv = ipmi_smi_add_proc_entry(smb_info->intf, "type",
+				     type_file_read_proc,
+				     smb_info, THIS_MODULE);
+	if (rv) {
+		printk(KERN_ERR PFX "Unable to create proc entry: %d\n",
+		       rv);
+		goto out_err_unreg;
+	}
+
+	rv = ipmi_smi_add_proc_entry(smb_info->intf, "smb_stats",
+				     stat_file_read_proc,
+				     smb_info, THIS_MODULE);
+	if (rv) {
+		printk(KERN_ERR PFX "Unable to create proc entry: %d\n",
+		       rv);
+		goto out_err_unreg;
+	}
+
+	return 0;
+
+ out_err_unreg:
+	ipmi_unregister_smi(smb_info->intf);
+
+ out_err:
+	kfree(smb_info);
+	return rv;
+}
+
+static int attach_adapter(struct i2c_adapter *adapter)
+{
+	int id = i2c_adapter_id(adapter);
+
+#ifdef CONFIG_CPCI6200
+	if (id == 0)
+		return 0;
+#endif
+	if (smb_dbg_probe)
+		printk(KERN_INFO "init_one_smb: Checking SMBus adapter %d:"
+		       " %s\n", id, adapter->name);
+
+	if (!(i2c_get_functionality(adapter) & (I2C_FUNC_SMBUS_BLOCK_DATA)))
+		return 0;
+
+	if (smb_dbg_probe)
+		printk(KERN_INFO "init_one_smb: found SMBus adapter:"
+		       " %s\n", adapter->name);
+
+	if (!i2c_non_blocking_capable(adapter)) {
+	    if (smb_dbg_probe)
+		    printk(KERN_INFO
+			   "init_one_smb: adapter can't do non_blocking: %s\n",
+			   adapter->name);
+	    return 0;
+	}
+
+	i2c_probe(adapter, &addr_data, smb_found_addr_proc);
+
+	return 0;
+}
+
+int cleanup_one_smb(struct smb_info *to_clean)
+{
+	int rv;
+
+	if (!to_clean)
+		return 0;
+
+	/* Don't allow the upper layer to request events any more. */
+	to_clean->stopping = 1;
+
+	/* make sure the driver is not looking for flags any more. */
+	while (to_clean->smb_state != SMB_NORMAL)
+		msleep(1);
+
+	/*
+	 * After this point, we won't deliver anything asynchronously
+	 * to the message handler.  We can unregister ourself.
+	 */
+	rv = ipmi_unregister_smi(to_clean->intf);
+	if (rv) {
+		to_clean->stopping = 0;
+		printk(KERN_ERR
+		       PFX "Unable to unregister device: errno=%d\n",
+		       rv);
+		return rv;
+	}
+
+	/*
+	 * No message can be outstanding now, we have removed the
+	 * upper layer and it permitted us to do so.
+	 */
+
+	rv = i2c_detach_client(&to_clean->client);
+	if (rv) {
+		printk(KERN_ERR
+		       PFX "Unable to detach SMBUS client: errno=%d\n",
+		       rv);
+		return rv;
+	}
+
+	smb_infos[to_clean->pos] = NULL;
+	kfree(to_clean);
+	return 0;
+}
+
+static int detach_client(struct i2c_client *client)
+{
+	struct smb_info *smb_info = i2c_get_clientdata(client);
+
+	return cleanup_one_smb(smb_info);
+}
+
+#ifdef CONFIG_ACPI_INTERPRETER
+
+#include <linux/acpi.h>
+
+/*
+ * Defined in the IPMI 2.0 spec.
+ */
+struct SPMITable {
+	s8	Signature[4];
+	u32	Length;
+	u8	Revision;
+	u8	Checksum;
+	s8	OEMID[6];
+	s8	OEMTableID[8];
+	s8	OEMRevision[4];
+	s8	CreatorID[4];
+	s8	CreatorRevision[4];
+	u8	InterfaceType;
+	u8	IPMIlegacy;
+	s16	SpecificationRevision;
+
+	/*
+	 * Bit 0 - SCI interrupt supported
+	 * Bit 1 - I/O APIC/SAPIC
+	 */
+	u8	InterruptType;
+
+	/*
+	 * If bit 0 of InterruptType is set, then this is the SCI
+	 * interrupt in the GPEx_STS register.
+	 */
+	u8	GPE;
+
+	s16	Reserved;
+
+	/*
+	 * If bit 1 of InterruptType is set, then this is the I/O
+	 * APIC/SAPIC interrupt.
+	 */
+	u32	GlobalSystemInterrupt;
+
+	/* The actual register address. */
+	struct acpi_generic_address addr;
+
+	u8	UID[4];
+
+	s8      spmi_id[1]; /* A '\0' terminated array starts here. */
+};
+
+static int __devinit decode_acpi(int acpi_num)
+{
+	acpi_status      status;
+	struct SPMITable *spmi;
+
+	if (num_addrs >= MAX_SMB_BMCS)
+		return -1;
+
+	i = num_addrs;
+
+	status = acpi_get_firmware_table("SPMI", acpi+1,
+					 ACPI_LOGICAL_ADDRESSING,
+					 (struct acpi_table_header **) &spmi);
+	if (status != AE_OK)
+		return -ENODEV;
+
+	if (spmi->IPMIlegacy != 1) {
+		printk(KERN_WARNING "IPMI: Bad SPMI legacy %d\n",
+		       spmi->IPMIlegacy);
+		return -ENODEV;
+	}
+
+	if (spmi->InterfaceType != 4)
+		return -ENODEV;
+
+	if (spmi->addr.address_space_id != 4) {
+		printk(KERN_WARNING
+		       PFX "Invalid ACPI SSIF I/O Address type\n");
+		return -EIO;
+	}
+
+	num_addrs = i + 1;
+
+	/* User didn't specify, so use this one. */
+	addr[i*2] = 0; /* Assume adapter 0 */
+	addr[i*2+1] = spmi->addr.address >> 1;
+	printk(KERN_INFO PFX "ACPI/SPMI specifies SSIF @ 0x%x\n",
+	       addr[i*2+1]);
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_DMI
+static int __devinit decode_dmi(struct dmi_header *dm)
+{
+	int           addr_in_slave_addr = 0;
+	u8            *data = (u8 *)dm;
+	u8            len = dm->length;
+	int           i;
+
+	if (num_addrs >= MAX_SMB_BMCS)
+		return -1;
+
+	i = num_addrs;
+
+	if (len < 9)
+		return -1;
+
+	if (data[0x04] != 4) /* Not SSIF */
+		return -1;
+
+	num_addrs = i + 1;
+
+	addr[i*2] = 0; /* Assume adapter 0 */
+	if ((data[8] >> 1) == 0) {
+		/*
+		 * Some broken systems put the I2C address in
+		 * the slave address field.  We try to
+		 * accommodate them here.
+		 */
+		addr[i*2+1] = data[6] >> 1;
+		addr_in_slave_addr = 1;
+	} else
+		addr[i*2+1] = data[8] >> 1;
+
+	if (!addr_in_slave_addr) {
+		slave_addrs[i] = data[6];
+		printk(KERN_INFO PFX "DMI specifies SSIF @ 0x%x, "
+		       "slave address 0x%x\n",
+		       addr[i*2+1], slave_addrs[i]);
+	} else
+		printk(KERN_INFO PFX "DMI specifies SSIF @ 0x%x\n",
+		       addr[i*2+1]);
+
+	return 0;
+}
+
+static void __devinit dmi_iterator(void)
+{
+	const struct dmi_device *dev = NULL;
+
+	while ((dev = dmi_find_device(DMI_DEV_TYPE_IPMI, NULL, dev)))
+		decode_dmi((struct dmi_header *) dev->device_data);
+}
+#endif
+
+static __init int init_ipmi_smb(void)
+{
+	int i;
+	int rv;
+
+	if (initialized)
+		return 0;
+
+	printk(KERN_INFO "IPMI SMB Interface driver\n");
+
+#ifdef CONFIG_DMI
+	dmi_iterator();
+#endif
+#ifdef CONFIG_ACPI_INTERPRETER
+	for (i = 0; i < MAX_SMB_BMCS; i++)
+		decode_acpi(i);
+#endif
+
+	/* build force list from addr list */
+	for (i = 0; i < MAX_SMB_BMCS; i++) {
+		if (addr[i*2+1] == 0)
+			break;
+		smb_forces[i][0] = addr[i*2];
+		smb_forces[i][1] = addr[i*2+1];
+		smb_forces[i][2] = I2C_CLIENT_END;
+		smb_force_list[i] = smb_forces[i];
+	}
+	smb_force_list[i] = NULL;
+
+	/*
+	 * If the default probing is turned off, then disable the
+	 * range scanning.
+	 */
+	smb_defaultprobe=1;
+	if (!smb_defaultprobe)
+		normal_i2c[0] = I2C_CLIENT_END;
+
+	rv = i2c_add_driver(&smb_i2c_driver);
+	if (!rv)
+		initialized = 1;
+
+	return rv;
+}
+module_init(init_ipmi_smb);
+
+static __exit void cleanup_ipmi_smb(void)
+{
+	int i;
+
+	if (!initialized)
+		return;
+
+	for (i = 0; i < MAX_SMB_BMCS; i++)
+		cleanup_one_smb(smb_infos[i]);
+
+	initialized = 0;
+
+	i2c_del_driver(&smb_i2c_driver);
+}
+module_exit(cleanup_ipmi_smb);
+
+MODULE_AUTHOR("Todd C Davis <todd.c.davis@intel.com>, "
+	      "Corey Minyard <minyard@acm.org>");
+MODULE_DESCRIPTION("IPMI driver for management controllers on a SMBus");
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_watchdog.c linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_watchdog.c
--- linux-2.6.29.6.orig/drivers/char/ipmi/ipmi_watchdog.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/ipmi_watchdog.c	2009-07-21 11:28:18.000000000 -0700
@@ -552,6 +552,22 @@
 }
 
 /*
+ * Do a delayed shutdown, with the delay in milliseconds.  If power_off is
+ * false, do a reset.  If power_off is true, do a power down.  This is
+ * primarily for the IMB code's shutdown.
+ */
+void ipmi_delayed_shutdown(long delay, int power_off)
+{
+	ipmi_ignore_heartbeat = 1;
+	if (power_off)
+		ipmi_watchdog_state = WDOG_TIMEOUT_POWER_DOWN;
+	else
+		ipmi_watchdog_state = WDOG_TIMEOUT_RESET;
+	timeout = delay;
+	ipmi_set_timeout(IPMI_SET_TIMEOUT_HB_IF_NECESSARY);
+}
+
+/*
  * We use a mutex to make sure that only one thing can send a
  * heartbeat at one time, because we only have one copy of the data.
  * The semaphore is claimed when the set_timeout is sent and freed
@@ -870,6 +886,7 @@
 		clear_bit(0, &ipmi_wdog_open);
 	}
 
+	ipmi_fasync(-1, filep, 0);
 	expect_close = 0;
 
 	return 0;
@@ -1340,6 +1357,9 @@
 }
 module_exit(ipmi_wdog_exit);
 module_init(ipmi_wdog_init);
+
+EXPORT_SYMBOL(ipmi_delayed_shutdown);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Corey Minyard <minyard@mvista.com>");
 MODULE_DESCRIPTION("watchdog timer based upon the IPMI interface.");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/Kconfig linux-2.6.29.6.mod/drivers/char/ipmi/Kconfig
--- linux-2.6.29.6.orig/drivers/char/ipmi/Kconfig	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/Kconfig	2009-07-21 11:28:18.000000000 -0700
@@ -50,6 +50,17 @@
 	 Currently, only KCS and SMIC are supported.  If
 	 you are using IPMI, you should probably say "y" here.
 
+config IPMI_SMB
+       tristate 'IPMI SMBus handler'
+       select I2C
+       help
+         Provides a driver for a SMBus interface to a BMC, meaning that you
+	 have a driver that must be accessed over an I2C bus instead of a
+	 standard interface.  This module requires I2C support.  Note that
+	 you might need some I2C changes if CONFIG_IPMI_PANIC_EVENT is
+	 enabled along with this, so the I2C driver knows to run to
+	 completion during sending a panic event.
+
 config IPMI_WATCHDOG
        tristate 'IPMI Watchdog Timer'
        help
@@ -61,4 +72,11 @@
          This enables a function to power off the system with IPMI if
 	 the IPMI management controller is capable of this.
 
+config IPMI_OOPS_CONSOLE
+	tristate 'IPMI oops console'
+	help
+	  This enables the IPMI oops console. IPMI oops console logs oops or
+	  panic console messsages to SEL. The number of entries for this usage
+	  is limited by msg_limit, default is 100 entries.
+
 endif # IPMI_HANDLER
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/char/ipmi/Makefile linux-2.6.29.6.mod/drivers/char/ipmi/Makefile
--- linux-2.6.29.6.orig/drivers/char/ipmi/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/char/ipmi/Makefile	2009-07-21 11:28:18.000000000 -0700
@@ -7,5 +7,7 @@
 obj-$(CONFIG_IPMI_HANDLER) += ipmi_msghandler.o
 obj-$(CONFIG_IPMI_DEVICE_INTERFACE) += ipmi_devintf.o
 obj-$(CONFIG_IPMI_SI) += ipmi_si.o
+obj-$(CONFIG_IPMI_SMB) += ipmi_smb.o
 obj-$(CONFIG_IPMI_WATCHDOG) += ipmi_watchdog.o
 obj-$(CONFIG_IPMI_POWEROFF) += ipmi_poweroff.o
+obj-$(CONFIG_IPMI_OOPS_CONSOLE) += ipmi_oops_console.o
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/hwmon/ds1621.c linux-2.6.29.6.mod/drivers/hwmon/ds1621.c
--- linux-2.6.29.6.orig/drivers/hwmon/ds1621.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/hwmon/ds1621.c	2009-07-21 11:28:18.000000000 -0700
@@ -31,6 +31,7 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
+
 #include "lm75.h"
 
 /* Addresses to scan */
@@ -144,6 +145,7 @@
 	
 	/* start conversion */
 	i2c_smbus_write_byte(client, DS1621_COM_START);
+
 }
 
 static ssize_t show_temp(struct device *dev, struct device_attribute *da,
@@ -171,6 +173,7 @@
 	return count;
 }
 
+
 static ssize_t show_alarms(struct device *dev, struct device_attribute *da,
 			   char *buf)
 {
@@ -271,6 +274,9 @@
 		err = PTR_ERR(data->hwmon_dev);
 		goto exit_remove_files;
 	}
+	data = ds1621_update_client(&client->dev);
+	printk("ds1621: the current temperature is %d C\n", 
+		       LM75_TEMP_FROM_REG(data->temp[0]) / 1000);
 
 	return 0;
 
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/hwmon/lm90.c linux-2.6.29.6.mod/drivers/hwmon/lm90.c
--- linux-2.6.29.6.orig/drivers/hwmon/lm90.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/hwmon/lm90.c	2009-07-21 11:28:18.000000000 -0700
@@ -76,6 +76,14 @@
 #include <linux/err.h>
 #include <linux/mutex.h>
 #include <linux/sysfs.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#ifdef CONFIG_MVME7100
+#include <platforms/86xx/mvme7100.h>
+#endif
+#ifdef CONFIG_MVME4100
+#include <platforms/85xx/mvme4100.h>
+#endif
 
 /*
  * Addresses to scan
@@ -221,6 +229,35 @@
 	u8 alarms; /* bitvector */
 };
 
+#if defined(CONFIG_MVME7100) || defined(CONFIG_MVME4100)
+static struct tasklet_struct maxim6649_bh_task;
+#endif
+
+static struct i2c_client *save_client;
+
+#ifdef CONFIG_MVME7100
+
+#define BOARD_TSTAT_MASK        MVME7100_TEMP_MASK
+#define BOARD_TSTAT_REG         MVME7100_INTERRUPT_REG_2
+
+#endif
+
+#ifdef CONFIG_MVME4100
+
+#define BOARD_TSTAT_MASK        MVME4100_TEMP_MASK
+#define BOARD_TSTAT_REG         MVME4100_INTERRUPT_REG_2
+
+#endif
+
+
+#if defined(CONFIG_MVME7100) || defined(CONFIG_MVME4100)
+
+extern int maxim6649_irq;
+static void __iomem *control_reg_mapped_addr;
+static int control_reg_mapped;
+
+#endif
+
 /*
  * Conversions
  * For local temperatures and limits, critical limits and the hysteresis
@@ -529,6 +566,42 @@
 	return sprintf(buf, "%d\n", (data->alarms >> bitnr) & 1);
 }
 
+#if defined(CONFIG_MVME7100) || defined(CONFIG_MVME4100)
+
+static ssize_t show_irq_enable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+        u8      cr;
+
+        cr = readb(control_reg_mapped_addr);
+        return sprintf(buf, "%d\n", (!(cr & BOARD_TSTAT_MASK)));
+}
+
+static ssize_t set_irq_enable(struct device *dev, struct device_attribute *attr,                                 const char *buf, size_t count)
+{
+        ulong value;
+        u8  cr;
+        struct i2c_client *client = to_i2c_client(dev);
+        struct lm90_data *data = i2c_get_clientdata(client);
+
+        mutex_lock(&data->update_lock);
+        value = simple_strtoul(buf, NULL, 10);
+        cr = readb(control_reg_mapped_addr);
+        if (value == 1)  {
+                cr &= ~BOARD_TSTAT_MASK;
+        } else {
+
+                cr |= BOARD_TSTAT_MASK;
+        }
+        writeb(cr, control_reg_mapped_addr);
+        mutex_unlock(&data->update_lock);
+        return count;
+}
+
+static DEVICE_ATTR(irq_enable, S_IWUSR | S_IRUGO, show_irq_enable,
+        set_irq_enable);
+
+#endif
+
 static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, show_temp11, NULL, 4);
 static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, show_temp11, NULL, 0);
 static SENSOR_DEVICE_ATTR(temp1_min, S_IWUSR | S_IRUGO, show_temp8,
@@ -580,6 +653,9 @@
 	&sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
 	&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
 	&dev_attr_alarms.attr,
+#if defined(CONFIG_MVME7100) || defined(CONFIG_MVME4100)
+        &dev_attr_irq_enable.attr,
+#endif
 	NULL
 };
 
@@ -587,6 +663,67 @@
 	.attrs = lm90_attributes,
 };
 
+static int lm90_read_reg(struct i2c_client* client, u8 reg, u8 *value);
+
+#if defined(CONFIG_MVME7100) || defined(CONFIG_MVME4100)
+
+static void maxim6649_bh_handler(unsigned long data)
+{
+        struct lm90_data *lm_data;
+        struct i2c_client *client = (struct i2c_client *)data;
+
+	if (data != (unsigned long)save_client) 
+		return;
+
+	lm_data = i2c_get_clientdata(client);
+
+//        lm_data = lm90_update_device(&client->dev);
+
+        printk(KERN_ERR "Maxim6649: the current sensor temperature is %d C\n",
+		temp_from_u16(lm_data->temp11[4]));
+        printk(KERN_ERR "Maxim6649: the current remote sensor temperature is %d C\n",
+                temp_from_u16(lm_data->temp11[0]));
+
+        printk(KERN_ERR "Maxim6649: the sensor high temperature limit is set to %d C\n",
+                temp_from_u8(lm_data->temp8[1]));
+        printk(KERN_ERR "Maxim6649: the sensor temperature critical limit is set to %d C\n",
+                temp_from_u8(lm_data->temp8[2]));
+        printk(KERN_ERR "Maxim6649: the remote sensor temperature high limit is set to %d C\n",
+                temp_from_u16(lm_data->temp11[2]));
+        printk(KERN_ERR "Maxim6649: the remote sensor temperature low limit is set to %d C\n",
+                temp_from_u16(lm_data->temp11[1]));
+        printk(KERN_ERR "Maxim6649: the remote sensor temperature critical limit is set to %d C\n",
+                temp_from_u8(lm_data->temp8[3]));
+
+        return;
+}
+
+
+static irqreturn_t maxim6649_int_handler(int irq, void *dev_id)
+{
+        u16 value;
+        struct i2c_client *client = (struct i2c_client *)dev_id;
+        struct lm90_data *data;
+
+	if (dev_id != (void *)save_client) 
+		return IRQ_NONE;
+
+        printk(KERN_ERR "Maxim6649: Interrupt!\n");
+        printk(KERN_ERR "Maxim6649: Masking interrupt.\n");
+
+	data = i2c_get_clientdata(client);
+        value = readb(control_reg_mapped_addr);
+        value |= BOARD_TSTAT_MASK;
+        writeb(value, control_reg_mapped_addr);
+
+        tasklet_schedule(&maxim6649_bh_task);
+
+        return IRQ_HANDLED;
+}
+
+#endif
+
+
 /* pec used for ADM1032 only */
 static ssize_t show_pec(struct device *dev, struct device_attribute *dummy,
 			char *buf)
@@ -755,7 +892,7 @@
 			 && (reg_config1 & 0x1F) == (man_id & 0x0F)
 			 && reg_convrate <= 0x09) {
 			 	kind = max6657;
-			} else
+                        } else
 			/* The chip_id register of the MAX6680 and MAX6681
 			 * holds the revision of the chip.
 			 * the lowest bit of the config1 register is unused
@@ -827,6 +964,7 @@
 		goto exit;
 	}
 	i2c_set_clientdata(new_client, data);
+	data->valid = 0;
 	mutex_init(&data->update_lock);
 
 	/* Set the device type */
@@ -875,6 +1013,7 @@
 	u8 config, config_orig;
 	struct lm90_data *data = i2c_get_clientdata(client);
 
+	save_client = client;
 	/*
 	 * Start the conversions.
 	 */
@@ -904,6 +1043,48 @@
 	config &= 0xBF;	/* run */
 	if (config != config_orig) /* Only write if changed */
 		i2c_smbus_write_byte_data(client, LM90_REG_W_CONFIG1, config);
+
+#if defined(CONFIG_MVME7100) || defined(CONFIG_MVME4100)
+        {
+                struct lm90_data *data = i2c_get_clientdata(client);
+                int result;
+                u8  value;
+                long val;
+
+		tasklet_init(&maxim6649_bh_task, &maxim6649_bh_handler, 
+			(unsigned long) save_client);
+                control_reg_mapped_addr = ioremap(BOARD_TSTAT_REG, 1);
+                control_reg_mapped = 1;
+
+                data = lm90_update_device(&client->dev);
+                printk(KERN_INFO "maxim6649: Sensor Temperature is %2d C; Remote Sensor Temperature is %2d C\n",
+			temp_from_u16(data->temp11[4]) / 1000,
+                        temp_from_u16(data->temp11[0]) / 1000);
+
+                /* Set remote critical */
+                val = 120000;
+                data->temp8[4] = temp_to_u8(val);
+                i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_CRIT, data->temp8[4]);
+
+                /* Set remote high */
+                val = 105000;
+                data->temp11[2] = temp_to_u8(val) << 8;
+                i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_HIGHH, data->temp11[2] >> 8);
+                i2c_smbus_write_byte_data(client, LM90_REG_W_REMOTE_HIGHL, data->temp11[2] & 0xff);
+
+                result = request_irq(maxim6649_irq, maxim6649_int_handler,
+				IRQF_SHARED, "maxim6649", save_client);
+                if (result) {
+                        printk(KERN_ERR "maxim6649: Cannot get irq %d\n", maxim6649_irq);
+                        return;
+                }
+
+                /* Unmask MAXIM6649 temperature sensor thermostat output */
+                value = readb(control_reg_mapped_addr);
+                value &= ~BOARD_TSTAT_MASK;
+                writeb(value, control_reg_mapped_addr);
+        }
+#endif
 }
 
 static int lm90_remove(struct i2c_client *client)
@@ -917,6 +1098,23 @@
 		device_remove_file(&client->dev,
 				   &sensor_dev_attr_temp2_offset.dev_attr);
 
+#if defined(CONFIG_MVME7100) || defined(CONFIG_MVME4100)
+        {
+                u8 value;
+
+                if (control_reg_mapped) {
+                        /* Mask temperature sensor interrupt */
+                        value = readb(control_reg_mapped_addr);
+                        value |= BOARD_TSTAT_MASK;
+                        writeb(value, control_reg_mapped_addr);
+                        iounmap(control_reg_mapped_addr);
+                        control_reg_mapped = 0;
+                }
+                tasklet_kill(&maxim6649_bh_task);
+                free_irq(maxim6649_irq, save_client);
+        }
+#endif
+
 	kfree(data);
 	return 0;
 }
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/i2c/busses/i2c-mpc.c linux-2.6.29.6.mod/drivers/i2c/busses/i2c-mpc.c
--- linux-2.6.29.6.orig/drivers/i2c/busses/i2c-mpc.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/i2c/busses/i2c-mpc.c	2009-08-03 10:47:25.000000000 -0700
@@ -104,8 +104,8 @@
 	{
 		while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
 			schedule();
-			if (time_after(jiffies, orig_jiffies + timeout)) {
-				pr_debug("I2C: timeout\n");
+			if (time_after(jiffies, orig_jiffies + 5 * timeout)) {
+				pr_info("I2C: wait timeout\n");
 				writeccr(i2c, 0);
 				result = -EIO;
 				break;
@@ -116,7 +116,7 @@
 	} else {
 		/* Interrupt mode */
 		result = wait_event_interruptible_timeout(i2c->queue,
-			(i2c->interrupt & CSR_MIF), timeout * HZ);
+			(i2c->interrupt & CSR_MIF), timeout);
 
 		if (unlikely(result < 0)) {
 			pr_debug("I2C: wait interrupted\n");
@@ -311,7 +311,8 @@
 	.owner = THIS_MODULE,
 	.name = "MPC adapter",
 	.algo = &mpc_algo,
-	.timeout = 1,
+	.class = I2C_CLASS_HWMON | I2C_CLASS_SPD,
+	.timeout = HZ,
 };
 
 static int __devinit fsl_i2c_probe(struct of_device *op, const struct of_device_id *match)
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/i2c/busses/i2c-mpc-ipmi.c linux-2.6.29.6.mod/drivers/i2c/busses/i2c-mpc-ipmi.c
--- linux-2.6.29.6.orig/drivers/i2c/busses/i2c-mpc-ipmi.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/i2c/busses/i2c-mpc-ipmi.c	2009-09-02 10:32:39.000000000 -0700
@@ -0,0 +1,584 @@
+/*
+ * (C) Copyright 2003-2004
+ * Humboldt Solutions Ltd, adrian@humboldt.co.uk.
+
+ * This is a combined i2c adapter and algorithm driver for the
+ * MPC107/Tsi107 PowerPC northbridge and processors that include
+ * the same I2C unit (8240, 8245, 85xx).
+ *
+ * Release 0.8
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <linux/of_i2c.h>
+
+#include <asm/io.h>
+#include <linux/fsl_devices.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#define DRV_NAME "mpc-i2c-ipmi"
+
+#define MPC_I2C_FDR 	0x04
+#define MPC_I2C_CR	0x08
+#define MPC_I2C_SR	0x0c
+#define MPC_I2C_DR	0x10
+#define MPC_I2C_DFSRR 0x14
+
+#define CCR_MEN  0x80
+#define CCR_MIEN 0x40
+#define CCR_MSTA 0x20
+#define CCR_MTX  0x10
+#define CCR_TXAK 0x08
+#define CCR_RSTA 0x04
+
+#define CSR_MCF  0x80
+#define CSR_MAAS 0x40
+#define CSR_MBB  0x20
+#define CSR_MAL  0x10
+#define CSR_SRW  0x04
+#define CSR_MIF  0x02
+#define CSR_RXAK 0x01
+
+#define RETRY_TIME_US  500 /* Try every 500us minimum */
+#define MAX_TIMEOUT_US  500000 /* 500ms minimum */
+
+struct mpc_i2c_ipmi {
+	void __iomem *base;
+	u32 interrupt;
+	wait_queue_head_t queue;
+	struct i2c_adapter adap;
+	int irq;
+	u32 flags;
+};
+
+static __inline__ void writeccr(struct mpc_i2c_ipmi *i2c, u32 x)
+{
+	writeb(x, i2c->base + MPC_I2C_CR);
+}
+
+static irqreturn_t mpc_i2c_ipmi_isr(int irq, void *dev_id)
+{
+	struct mpc_i2c_ipmi *i2c = dev_id;
+	if (readb(i2c->base + MPC_I2C_SR) & CSR_MIF) {
+		/* Read again to allow register to stabilise */
+		i2c->interrupt = readb(i2c->base + MPC_I2C_SR);
+		writeb(0, i2c->base + MPC_I2C_SR);
+		wake_up_interruptible(&i2c->queue);
+	}
+	return IRQ_HANDLED;
+}
+
+/* Sometimes 9th clock pulse isn't generated, and slave doesn't release
+ * the bus, because it wants to send ACK.
+ * Following sequence of enabling/disabling and sending start/stop generates
+ * the pulse, so it's all OK.
+ */
+static void mpc_i2c_ipmi_fixup(struct mpc_i2c_ipmi *i2c)
+{
+	writeccr(i2c, 0);
+	udelay(30);
+	writeccr(i2c, CCR_MEN);
+	udelay(30);
+	writeccr(i2c, CCR_MSTA | CCR_MTX);
+	udelay(30);
+	writeccr(i2c, CCR_MSTA | CCR_MTX | CCR_MEN);
+	udelay(30);
+	writeccr(i2c, CCR_MEN);
+	udelay(30);
+}
+
+static int i2c_wait(struct mpc_i2c_ipmi *i2c, unsigned timeout, int writing)
+{
+	unsigned long orig_jiffies = jiffies;
+	u32 x;
+	int result = 0;
+
+	if (i2c->irq == NO_IRQ)
+	{
+		while (!(readb(i2c->base + MPC_I2C_SR) & CSR_MIF)) {
+#ifdef CONFIG_CPCI6200
+			udelay(2);
+#else
+			schedule();
+#endif
+			if (time_after(jiffies, orig_jiffies + timeout)) {
+				pr_debug("i2c_mpc_ipmi: i2c wait timeout\n");
+				writeccr(i2c, 0);
+				result = -EIO;
+				break;
+			}
+		}
+		x = readb(i2c->base + MPC_I2C_SR);
+		writeb(0, i2c->base + MPC_I2C_SR);
+	} else {
+		/* Interrupt mode */
+		result = wait_event_interruptible_timeout(i2c->queue,
+			(i2c->interrupt & CSR_MIF), timeout);
+
+		if (unlikely(result < 0)) {
+			pr_debug("i2c_mpc_ipmi: i2c wait interrupted\n");
+			writeccr(i2c, 0);
+		} else if (unlikely(!(i2c->interrupt & CSR_MIF))) {
+			pr_debug("i2c_mpc_ipmi: i2c wait timeout\n");
+			writeccr(i2c, 0);
+			result = -ETIMEDOUT;
+		}
+
+		x = i2c->interrupt;
+		i2c->interrupt = 0;
+	}
+
+	if (result < 0)
+		return result;
+
+	if (!(x & CSR_MCF)) {
+		pr_info("i2c_mpc_ipmi: unfinished\n");
+		return -EIO;
+	}
+
+	if (x & CSR_MAL) {
+		pr_info("i2c_mpc_ipmi: MAL - arbitration lost\n");
+		return -EIO;
+	}
+
+	if (writing && (x & CSR_RXAK)) {
+		pr_debug("i2c_mpc_ipmi: No RXAK\n");
+		/* generate stop */
+//		writeccr(i2c, CCR_MEN);
+		return -ENODEV;
+	}
+	return 0;
+}
+
+static void mpc_i2c_ipmi_setclock(struct mpc_i2c_ipmi *i2c)
+{
+	/* Set clock and filters */
+	if (i2c->flags & FSL_I2C_DEV_SEPARATE_DFSRR) {
+		writeb(0x31, i2c->base + MPC_I2C_FDR);
+		writeb(0x10, i2c->base + MPC_I2C_DFSRR);
+	} else if (i2c->flags & FSL_I2C_DEV_CLOCK_5200)
+		writeb(0x3f, i2c->base + MPC_I2C_FDR);
+	else
+		writel(0x1031, i2c->base + MPC_I2C_FDR);
+}
+
+static void mpc_i2c_ipmi_start(struct mpc_i2c_ipmi *i2c)
+{
+	/* Clear arbitration */
+	writeb(0, i2c->base + MPC_I2C_SR);
+	/* Start with MEN */
+	writeccr(i2c, CCR_MEN);
+}
+
+static void mpc_i2c_ipmi_stop(struct mpc_i2c_ipmi *i2c)
+{
+	writeccr(i2c, CCR_MEN);
+}
+
+static int mpc_ipmi_write(struct mpc_i2c_ipmi *i2c, int target,
+		     const u8 * data, int length, int restart)
+{
+	int i, result;
+	unsigned timeout = i2c->adap.timeout;
+	u32 flags = restart ? CCR_RSTA : 0;
+	int retries = 0;
+
+	/* Start with MEN */
+	if (!restart)
+		writeccr(i2c, CCR_MEN);
+	/* Start as master */
+	writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+	while (retries < 5) {
+		/* Write target byte */
+		writeb((target << 1), i2c->base + MPC_I2C_DR);
+
+		result = i2c_wait(i2c, timeout, 1);
+		if (result < 0) {
+			if (result == -ENODEV) {
+				udelay(30);
+				retries++;
+				continue;
+			} else {
+				return result;
+			}
+		}
+		break;
+	}
+	if (result < 0) { 
+		mpc_i2c_ipmi_stop(i2c);
+		return result;
+	}
+
+	for (i = 0; i < length; i++) {
+		/* Write data byte */
+		writeb(data[i], i2c->base + MPC_I2C_DR);
+
+		result = i2c_wait(i2c, timeout, 1);
+		if (result < 0)
+			return result;
+	}
+
+	return 0;
+}
+
+static int mpc_ipmi_read(struct mpc_i2c_ipmi *i2c, int target,
+		    u8 * data, int length, int restart, int m_recv_len)
+{
+	unsigned timeout = i2c->adap.timeout;
+	int i, result;
+	int retries = 0;
+	u32 flags = restart ? CCR_RSTA : 0;
+
+	/* Start with MEN */
+	if (!restart)
+		writeccr(i2c, CCR_MEN);
+	/* Switch to read - restart */
+	writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_MTX | flags);
+
+	while (retries < 5) {
+		/* Write target addr byte - this time with the read flag set */
+		writeb((target << 1) | 1, i2c->base + MPC_I2C_DR);
+
+		result = i2c_wait(i2c, timeout, 1);
+		if (result < 0) {
+			if (result == -ENODEV) {
+				udelay(30);
+				retries++;;
+				continue;
+			} else { 
+				return result;
+			}
+		}
+		break;
+	}
+	if (result < 0) {
+		mpc_i2c_ipmi_stop(i2c);
+		return result;
+	}
+
+	if (length) {
+		if ((length == 1) && !m_recv_len)
+			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+		else
+			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA);
+		/* Dummy read */
+		readb(i2c->base + MPC_I2C_DR);
+	}
+
+	if (m_recv_len) {
+		result = i2c_wait(i2c, timeout, 0);
+		if (result < 0)
+			return result;
+		data[0] = readb(i2c->base + MPC_I2C_DR);
+		/* sanity check */
+		if (data[0] > 64) {
+			/* Note: The ipmi_smb driver will accept only 32 bytes. Using 64 as a 
+                         *        check is a workaround for broken IPMI firmware */
+			printk(KERN_ERR "i2c-mpc-ipmi: Receive length (%d) is too large\n", data[0]);
+			return -EIO;
+		}
+		length = data[0];
+	}
+
+	for (i = 0; i < length; i++) {
+		result = i2c_wait(i2c, timeout, 0);
+		if (result < 0)
+			return result;
+
+		/* Generate txack on next to last byte */
+		if (i == length - 2)
+			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_MSTA | CCR_TXAK);
+		/* Generate stop on last byte */
+		if (i == length - 1)
+			writeccr(i2c, CCR_MIEN | CCR_MEN | CCR_TXAK);
+		if (m_recv_len)
+			data[i+1] = readb(i2c->base + MPC_I2C_DR);
+		else
+			data[i] = readb(i2c->base + MPC_I2C_DR);
+	}
+
+	if (m_recv_len) {
+		if (data[0] > 32) {
+			/* Fix for broken IPMI firmware that does not support muulti-part read */
+			printk(KERN_ERR "i2c-mpc-ipmi: Receive length (%d) is too large\n", data[0]);
+			data[0] = 32;
+			length = 32;
+		}
+	}
+	return length;
+}
+
+static int mpc_ipmi_start(struct i2c_adapter *adap, struct i2c_op_q_entry *e)
+{
+	struct i2c_msg *pmsg;
+	int ret = 0;
+	unsigned long orig_jiffies = jiffies;
+	struct mpc_i2c_ipmi *i2c = i2c_get_adapdata(adap);
+
+	pmsg = &e->i2c.msgs[0];
+	pr_debug("i2c_mpc_ipmi: mpc_start doing %s %d bytes to 0x%02x - %d messages\n",
+		 pmsg->flags & I2C_M_RD ? "read" : "write",
+		 pmsg->len, pmsg->addr, e->i2c.num);
+	if (!(pmsg->flags & I2C_M_RD) && (pmsg->len > 1)) { 
+		mpc_i2c_ipmi_start(i2c);
+		/* Allow bus up to 1s to become not busy */
+		while (readb(i2c->base + MPC_I2C_SR) & CSR_MBB) {
+			if (signal_pending(current)) {
+				pr_info("i2c_mpc_ipmi: mpc_start interrupted\n");
+				writeccr(i2c, 0);
+				return -EINTR;
+			}
+			if (time_after(jiffies, orig_jiffies + HZ)) {
+				pr_info("i2c_mpc_ipmi: mpc start timeout\n");
+				if (readb(i2c->base + MPC_I2C_SR) ==
+			    		(CSR_MCF | CSR_MBB | CSR_RXAK))
+					mpc_i2c_ipmi_fixup(i2c);
+				return -EIO;
+			}
+#ifdef CONFIG_CPCI6200
+			udelay(10);
+#else
+			schedule();
+#endif
+		}
+		ret = mpc_ipmi_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, 0);
+		mpc_i2c_ipmi_stop(i2c);
+	}
+	e->call_again_us = 2 * (1000000 / HZ);
+	e->time_left = MAX_TIMEOUT_US;
+
+	return (ret < 0) ? ret : 0;
+}
+
+
+static void mpc_ipmi_poll(struct i2c_adapter *adap, 
+			struct i2c_op_q_entry *e, 
+			unsigned int us_since_last_poll)
+{
+	u8 temp;
+	struct i2c_msg *pmsg;
+	int i;
+	int ret = 0;
+	unsigned long orig_jiffies = jiffies;
+	struct mpc_i2c_ipmi *i2c = i2c_get_adapdata(adap);
+
+	pmsg = &e->i2c.msgs[0];
+	if (!(pmsg->flags & I2C_M_RD) && (pmsg->len == 1)) { 
+		pr_debug("i2c_mpc_ipmi: poll doing %s %d bytes to 0x%02x - %d messages\n",
+			 pmsg->flags & I2C_M_RD ? "read" : "write",
+			 pmsg->len, pmsg->addr, e->i2c.num);
+		temp = readb(i2c->base + MPC_I2C_SR);
+		if (temp & CSR_MBB) {
+			e->time_left -= us_since_last_poll;
+			if (e->time_left <= 0) {
+				pr_info("i2c_mpc_ipmi: poll timeout!\n");
+				mpc_i2c_ipmi_fixup(i2c);
+				e->result = -EBUSY;
+				goto out_done;
+			} else {
+				pr_info("i2c_mpc_ipmi: poll bus busy!\n");
+				e->call_again_us = RETRY_TIME_US;
+				return;
+			}
+		}
+
+       		mpc_i2c_ipmi_start(i2c);
+		temp = readb(i2c->base + MPC_I2C_SR);
+			
+		/* Allow bus up to 1s to become not busy */
+		while (temp & CSR_MBB) {
+			if (signal_pending(current)) {
+				pr_info("i2c_mpc_ipmi: poll interrupted\n");
+				writeccr(i2c, 0);
+				e->result = -EINTR;
+				mpc_i2c_ipmi_stop(i2c);
+				goto out_done;
+			}
+			if (time_after(jiffies, orig_jiffies + HZ)) {
+				pr_info("i2c_mpc_ipmi: poll timeout on i2c start\n");
+				if (readb(i2c->base + MPC_I2C_SR) == 
+					(CSR_MCF | CSR_MBB | CSR_RXAK)) 
+					mpc_i2c_ipmi_fixup(i2c);
+				e->result = -EIO;
+				goto out_done;
+			}
+#ifdef CONFIG_CPCI6200
+			udelay(10);
+#else
+			schedule();
+#endif
+		}
+
+		for (i = 0; ret >= 0 && i < e->i2c.num; i++) {
+			pmsg = &e->i2c.msgs[i];
+			pr_debug("i2c_mpc_ipmi: poll doing %s %d bytes to 0x%02x - %d of %d messages\n",
+				 pmsg->flags & I2C_M_RD ? "read" : "write",
+				 pmsg->len, pmsg->addr, i + 1, e->i2c.num);
+			if (pmsg->flags & I2C_M_RD) { 
+				ret = mpc_ipmi_read(i2c, pmsg->addr, pmsg->buf, pmsg->len, i, 
+						pmsg->flags & I2C_M_RECV_LEN);
+				if (ret < 0)
+					e->result = ret;
+			} else if (e->i2c.num > 1) {
+				ret = mpc_ipmi_write(i2c, pmsg->addr, pmsg->buf, pmsg->len, i);
+				if (ret < 0)
+					e->result = ret;
+			}
+		}
+       		mpc_i2c_ipmi_stop(i2c);
+	}
+out_done:
+	e->call_again_us = 20 * (1000000 / HZ);
+	i2c_op_done(adap, e);
+	return;
+}
+
+
+static u32 mpc_ipmi_functionality(struct i2c_adapter *adap)
+{
+	return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm mpc_ipmi_algo = {
+	.master_start  = mpc_ipmi_start,
+	.poll	       = mpc_ipmi_poll,
+	.functionality = mpc_ipmi_functionality,
+};
+
+static struct i2c_adapter mpc_ipmi_ops = {
+	.owner = THIS_MODULE,
+	.name = "MPC IPMI adapter",
+	.algo = &mpc_ipmi_algo,
+	.timeout = HZ,
+};
+
+static int __devinit fsl_i2c_ipmi_probe(struct of_device *op, const struct of_device_id *match)
+{
+	int result = 0;
+	struct mpc_i2c_ipmi *i2c;
+
+	i2c = kzalloc(sizeof(*i2c), GFP_KERNEL);
+	if (!i2c)
+		return -ENOMEM;
+
+	if (of_get_property(op->node, "dfsrr", NULL))
+		i2c->flags |= FSL_I2C_DEV_SEPARATE_DFSRR;
+
+	if (of_device_is_compatible(op->node, "fsl,mpc5200-i2c") ||
+			of_device_is_compatible(op->node, "mpc5200-i2c"))
+		i2c->flags |= FSL_I2C_DEV_CLOCK_5200;
+
+	init_waitqueue_head(&i2c->queue);
+
+	i2c->base = of_iomap(op->node, 0);
+	if (!i2c->base) {
+		printk(KERN_ERR "i2c-mpc-ipmi - failed to map controller\n");
+		result = -ENOMEM;
+		goto fail_map;
+	}
+
+	i2c->irq = irq_of_parse_and_map(op->node, 0);
+	if (i2c->irq != NO_IRQ) { /* i2c->irq = NO_IRQ implies polling */
+		result = request_irq(i2c->irq, mpc_i2c_ipmi_isr,
+				     IRQF_SHARED, "i2c-mpc-ipmi", i2c);
+		if (result < 0) {
+			printk(KERN_ERR "i2c-mpc-ipmi - failed to attach interrupt\n");
+			goto fail_request;
+		}
+	}
+	
+	mpc_i2c_ipmi_setclock(i2c);
+
+	dev_set_drvdata(&op->dev, i2c);
+
+	i2c->adap = mpc_ipmi_ops;
+	i2c_set_adapdata(&i2c->adap, i2c);
+	i2c->adap.dev.parent = &op->dev;
+
+	result = i2c_add_adapter(&i2c->adap);
+	if (result < 0) {
+		printk(KERN_ERR "i2c-mpc-ipmi - failed to add adapter\n");
+		goto fail_add;
+	}
+	of_register_i2c_devices(&i2c->adap, op->node);
+
+	return result;
+
+ fail_add:
+	dev_set_drvdata(&op->dev, NULL);
+	free_irq(i2c->irq, i2c);
+ fail_request:
+	irq_dispose_mapping(i2c->irq);
+ 	iounmap(i2c->base);
+ fail_map:
+	kfree(i2c);
+	return result;
+};
+
+static int __devexit fsl_i2c_ipmi_remove(struct of_device *op)
+{
+	struct mpc_i2c_ipmi *i2c = dev_get_drvdata(&op->dev);
+
+	i2c_del_adapter(&i2c->adap);
+	dev_set_drvdata(&op->dev, NULL);
+
+	if (i2c->irq != NO_IRQ)
+		free_irq(i2c->irq, i2c);
+
+	irq_dispose_mapping(i2c->irq);
+	iounmap(i2c->base);
+	kfree(i2c);
+	return 0;
+};
+
+static const struct of_device_id mpc_i2c_ipmi_of_match[] = {
+	{.compatible = "fsl-i2c-ipmi",},
+	{},
+};
+MODULE_DEVICE_TABLE(of, mpc_i2c_ipmi_of_match);
+
+
+/* Structure for a device driver */
+static struct of_platform_driver mpc_i2c_ipmi_driver = {
+	.match_table	= mpc_i2c_ipmi_of_match,
+	.probe		= fsl_i2c_ipmi_probe,
+	.remove		= __devexit_p(fsl_i2c_ipmi_remove),
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= DRV_NAME,
+	},
+};
+
+static int __init fsl_i2c_ipmi_init(void)
+{
+	int rv;
+
+	rv = of_register_platform_driver(&mpc_i2c_ipmi_driver);
+	if (rv)
+		printk(KERN_ERR DRV_NAME 
+		       " of_register_platform_driver failed (%i)\n", rv);
+	return rv;
+}
+
+static void __exit fsl_i2c_ipmi_exit(void)
+{
+	of_unregister_platform_driver(&mpc_i2c_ipmi_driver);
+}
+
+module_init(fsl_i2c_ipmi_init);
+module_exit(fsl_i2c_ipmi_exit);
+
+MODULE_AUTHOR("Adrian Cox <adrian@humboldt.co.uk>");
+MODULE_DESCRIPTION
+    ("I2C-Bus adapter with blocking support");
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/i2c/busses/Kconfig linux-2.6.29.6.mod/drivers/i2c/busses/Kconfig
--- linux-2.6.29.6.orig/drivers/i2c/busses/Kconfig	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/i2c/busses/Kconfig	2009-07-21 11:28:18.000000000 -0700
@@ -391,6 +391,16 @@
 	  This driver can also be built as a module.  If so, the module
 	  will be called i2c-mpc.
 
+config I2C_MPC_IPMI
+	tristate "85xx IPMI"
+	depends on CPCI6200 
+	help
+	  If you say yes to this option, support will be included for the
+	  built-in I2C interface on the MPC85xx processor based CPCI6200. 
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called i2c-mpc-ipmi.
+
 config I2C_MV64XXX
 	tristate "Marvell mv64xxx I2C Controller"
 	depends on (MV64X60 || PLAT_ORION) && EXPERIMENTAL
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/i2c/busses/Makefile linux-2.6.29.6.mod/drivers/i2c/busses/Makefile
--- linux-2.6.29.6.orig/drivers/i2c/busses/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/i2c/busses/Makefile	2009-07-21 11:28:18.000000000 -0700
@@ -36,6 +36,7 @@
 obj-$(CONFIG_I2C_IOP3XX)	+= i2c-iop3xx.o
 obj-$(CONFIG_I2C_IXP2000)	+= i2c-ixp2000.o
 obj-$(CONFIG_I2C_MPC)		+= i2c-mpc.o
+obj-$(CONFIG_I2C_MPC_IPMI)	+= i2c-mpc-ipmi.o
 obj-$(CONFIG_I2C_MV64XXX)	+= i2c-mv64xxx.o
 obj-$(CONFIG_I2C_OCORES)	+= i2c-ocores.o
 obj-$(CONFIG_I2C_OMAP)		+= i2c-omap.o
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/i2c/i2c-core.c linux-2.6.29.6.mod/drivers/i2c/i2c-core.c
--- linux-2.6.29.6.orig/drivers/i2c/i2c-core.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/i2c/i2c-core.c	2009-07-21 11:28:18.000000000 -0700
@@ -38,6 +38,7 @@
 
 #include "i2c-core.h"
 
+#define USEC_PER_JIFFIE (1000000 / HZ)
 
 static DEFINE_MUTEX(core_lock);
 static DEFINE_IDR(i2c_adapter_idr);
@@ -446,7 +447,21 @@
 
 	mutex_init(&adap->bus_lock);
 	mutex_init(&adap->clist_lock);
+	spin_lock_init(&adap->q_lock);
+	INIT_LIST_HEAD(&adap->q);
 	INIT_LIST_HEAD(&adap->clients);
+	adap->timer = kmalloc(sizeof(*adap->timer), GFP_KERNEL);
+	if (!adap->timer) {
+		res = -ENOMEM;
+		goto out_unlock;
+	}
+
+	init_timer(&adap->timer->timer);
+	spin_lock_init(&adap->timer->lock);
+	adap->timer->deleted = 0;
+	adap->timer->running = 0;
+	adap->timer->next_call_time = 0;
+	adap->timer->adapter = adap;
 
 	mutex_lock(&core_lock);
 
@@ -651,6 +666,13 @@
 		}
 	}
 
+	/* Stop the timer and free its memory. */
+	adap->timer->deleted = 1;
+	/* Timer can no longer be started now. */
+	del_timer_sync(&adap->timer->timer);
+	kfree(adap->timer);
+	adap->timer = NULL;
+
 	/* clean up the sysfs representation */
 	init_completion(&adap->dev_released);
 	device_unregister(&adap->dev);
@@ -996,26 +1018,178 @@
 module_exit(i2c_exit);
 
 /* ----------------------------------------------------
- * the functional interface to the i2c busses.
+ * Timer operations
  * ----------------------------------------------------
  */
+static void i2c_handle_timer(unsigned long data);
 
-/**
- * i2c_transfer - execute a single or combined I2C message
- * @adap: Handle to I2C bus
- * @msgs: One or more messages to execute before STOP is issued to
- *	terminate the operation; each message begins with a START.
- * @num: Number of messages to be executed.
- *
- * Returns negative errno, else the number of messages executed.
- *
- * Note that there is no requirement that each message be sent to
- * the same slave address, although that is the most common model.
+static void i2c_start_timer(struct i2c_adapter *adap,
+			    struct i2c_op_q_entry *entry)
+{
+	unsigned int wait_jiffies;
+	struct i2c_timer *t = adap->timer;
+	unsigned long flags;
+
+	wait_jiffies = ((entry->call_again_us + USEC_PER_JIFFIE - 1)
+			/ USEC_PER_JIFFIE);
+	if (wait_jiffies == 0)
+		wait_jiffies = 1;
+	/*
+	 * This won't be polled from the user code, so
+	 * start a timer to poll it.
+	 */
+	spin_lock_irqsave(&t->lock, flags);
+	if (!t->deleted && !t->running) {
+		t->timer.expires = jiffies + wait_jiffies;
+		t->timer.data = (unsigned long) t;
+		t->timer.function = i2c_handle_timer;
+		t->running = 1;
+		t->next_call_time = wait_jiffies * USEC_PER_JIFFIE;
+		add_timer(&t->timer);
+	}
+	spin_unlock_irqrestore(&t->lock, flags);
+}
+
+static void i2c_handle_timer(unsigned long data)
+{
+	struct i2c_timer      *t = (void *) data;
+	struct i2c_adapter    *adap;
+	unsigned long         flags;
+	struct i2c_op_q_entry *entry;
+
+	spin_lock_irqsave(&t->lock, flags);
+	adap = t->adapter;
+	t->running = 0;
+	spin_unlock_irqrestore(&t->lock, flags);
+
+	entry = i2c_entry_get(adap);
+	pr_debug("i2c_handle_timer: %p %p\n", adap, entry);
+	if (entry) {
+		adap->algo->poll(adap, entry, t->next_call_time);
+
+		spin_lock_irqsave(&adap->q_lock, flags);
+		if (entry->use_timer)
+			i2c_start_timer(adap, entry);
+		spin_unlock_irqrestore(&adap->q_lock, flags);
+		i2c_entry_put(adap, entry);
+	}
+}
+
+/* ----------------------------------------------------
+ * the functional interface to the i2c busses.
+ * ----------------------------------------------------
  */
-int i2c_transfer(struct i2c_adapter * adap, struct i2c_msg *msgs, int num)
+
+/* Must be called with the q_lock held. */
+static int i2c_start_entry(struct i2c_adapter *adap,
+			   struct i2c_op_q_entry *entry)
 {
 	int ret;
 
+	entry->state = I2C_OP_INITIALIZED;
+	switch (entry->xfer_type) {
+	case I2C_OP_I2C:
+		ret = adap->algo->master_start(adap, entry);
+		break;
+	case I2C_OP_SMBUS:
+		ret = adap->algo->smbus_start(adap, entry);
+		break;
+	default:
+		ret = -EINVAL;
+	}
+
+	if (!ret && entry->use_timer)
+		i2c_start_timer(adap, entry);
+
+	return ret;
+}
+
+static void i2c_wait_complete(struct i2c_op_q_entry *entry)
+{
+	struct completion *done = entry->handler_data;
+	pr_debug("i2c_wait_complete %p\n", entry);
+	complete(done);
+}
+
+static void i2c_init_entry(struct i2c_op_q_entry *entry)
+{
+	entry->start = NULL;
+	entry->state = I2C_OP_QUEUED;
+	entry->result = 0;
+	entry->data = NULL;
+	kref_init(&entry->usecount);
+}
+
+static void i2c_perform_op_wait(struct i2c_adapter *adap,
+				struct i2c_op_q_entry *entry)
+{
+	struct completion done;
+	unsigned long flags;
+	const struct i2c_algorithm *algo = adap->algo;
+	int ret = 0;
+
+	pr_debug("i2c_perform_op_wait %p %p\n", adap, entry);
+	i2c_init_entry(entry);
+	entry->use_timer = 0; /* We poll it directly. */
+	init_completion(&done);
+	entry->handler = i2c_wait_complete;
+	entry->handler_data = &done;
+
+	spin_lock_irqsave(&adap->q_lock, flags);
+	list_add_tail(&entry->link, &adap->q);
+	if (adap->q.next == &entry->link) {
+		/* Added to the list head, start it */
+		ret = i2c_start_entry(adap, entry);
+		if (ret) {
+			entry->result = ret;
+			list_del(&entry->link);
+			spin_unlock_irqrestore(&adap->q_lock, flags);
+			return;
+		}
+		spin_unlock_irqrestore(&adap->q_lock, flags);
+	} else {
+		struct completion start;
+		init_completion(&start);
+		entry->start = &start;
+		spin_unlock_irqrestore(&adap->q_lock, flags);
+
+		wait_for_completion_interruptible(&start);
+
+		spin_lock_irqsave(&adap->q_lock, flags);
+		if (entry->state == I2C_OP_QUEUED) {
+			/*
+			 * Wait was interrupted before the entry was
+			 * started.
+			 */
+			entry->result = -ERESTARTSYS;
+			list_del(&entry->link);
+		}
+		spin_unlock_irqrestore(&adap->q_lock, flags);
+	}
+
+	/*
+	 * Once the operation is started, we will not
+	 * interrupt it.
+	 */
+	while (entry->state != I2C_OP_FINISHED) {
+		unsigned int timeout = entry->call_again_us;
+		timeout += (USEC_PER_JIFFIE - 1);
+		timeout /= USEC_PER_JIFFIE;
+		if (timeout == 0)
+			timeout = 1;
+		wait_for_completion_timeout(&done, timeout);
+		if (entry->state == I2C_OP_FINISHED)
+			break;
+		algo->poll(adap, entry, timeout * USEC_PER_JIFFIE);
+	}
+}
+
+static void i2c_transfer_entry(struct i2c_adapter *adap,
+			       struct i2c_op_q_entry *entry)
+{
+#ifdef DEBUG
+	int ret;
+#endif
 	/* REVISIT the fault reporting model here is weak:
 	 *
 	 *  - When we get an error after receiving N bytes from a slave,
@@ -1033,34 +1207,71 @@
 	 *    (discarding status on the first one).
 	 */
 
-	if (adap->algo->master_xfer) {
+	entry->xfer_type = I2C_OP_I2C;
 #ifdef DEBUG
-		for (ret = 0; ret < num; ret++) {
-			dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
-				"len=%d%s\n", ret, (msgs[ret].flags & I2C_M_RD)
-				? 'R' : 'W', msgs[ret].addr, msgs[ret].len,
-				(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
-		}
+	for (ret = 0; ret < entry->i2c.num; ret++) {
+		dev_dbg(&adap->dev, "master_xfer[%d] %c, addr=0x%02x, "
+			"len=%d%s\n", ret,
+			(entry->i2c.msgs[ret].flags & I2C_M_RD ?
+			 'R' : 'W'),
+			entry->i2c.msgs[ret].addr, entry->i2c.msgs[ret].len,
+			(msgs[ret].flags & I2C_M_RECV_LEN) ? "+" : "");
+	}
 #endif
-
+	if (adap->algo->master_start) {
+		i2c_perform_op_wait(adap, entry);
+	} else if (adap->algo->master_xfer) {
 		if (in_atomic() || irqs_disabled()) {
-			ret = mutex_trylock(&adap->bus_lock);
-			if (!ret)
+			if (!mutex_trylock(&adap->bus_lock)) {
 				/* I2C activity is ongoing. */
-				return -EAGAIN;
+				entry->result = -EAGAIN;
+				return;
+			}
 		} else {
 			mutex_lock_nested(&adap->bus_lock, adap->level);
 		}
 
-		ret = adap->algo->master_xfer(adap,msgs,num);
+		entry->result = adap->algo->master_xfer(adap, entry->i2c.msgs,
+							entry->i2c.num);
 		mutex_unlock(&adap->bus_lock);
-
-		return ret;
+		if (entry->complete)
+			entry->complete(adap, entry);
 	} else {
 		dev_dbg(&adap->dev, "I2C level transfers not supported\n");
-		return -EOPNOTSUPP;
+		entry->result = -EOPNOTSUPP;
 	}
 }
+
+/**
+ * i2c_transfer - execute a single or combined I2C message
+ * @adap: Handle to I2C bus
+ * @msgs: One or more messages to execute before STOP is issued to
+ *	terminate the operation; each message begins with a START.
+ * @num: Number of messages to be executed.
+ *
+ * Returns negative errno, else the number of messages executed.
+ *
+ * Note that there is no requirement that each message be sent to
+ * the same slave address, although that is the most common model.
+ */
+int i2c_transfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+	struct i2c_op_q_entry *entry;
+	int                   rv;
+
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
+
+	entry->i2c.msgs = msgs;
+	entry->i2c.num = num;
+	entry->complete = NULL;
+
+	i2c_transfer_entry(adap, entry);
+	rv = entry->result;
+	kfree(entry);
+	return rv;
+}
 EXPORT_SYMBOL(i2c_transfer);
 
 /**
@@ -1805,169 +2016,196 @@
 }
 EXPORT_SYMBOL(i2c_smbus_write_i2c_block_data);
 
-/* Simulate a SMBus command using the i2c protocol
-   No checking of parameters is done!  */
-static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
-                                   unsigned short flags,
-                                   char read_write, u8 command, int size,
-                                   union i2c_smbus_data * data)
-{
-	/* So we need to generate a series of msgs. In the case of writing, we
-	  need to use only one message; when reading, we need two. We initialize
-	  most things with sane defaults, to keep the code below somewhat
-	  simpler. */
-	unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX+3];
-	unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX+2];
-	int num = read_write == I2C_SMBUS_READ?2:1;
-	struct i2c_msg msg[2] = { { addr, flags, 1, msgbuf0 },
-	                          { addr, flags | I2C_M_RD, 0, msgbuf1 }
-	                        };
+static void i2c_smbus_emu_complete(struct i2c_adapter *adapter,
+				   struct i2c_op_q_entry *entry)
+{
+	unsigned char *msgbuf0 = entry->i2c.msgs[0].buf;
+	unsigned char *msgbuf1 = entry->i2c.msgs[1].buf;
+	int num = entry->smbus.read_write == I2C_SMBUS_READ ? 2 : 1;
 	int i;
-	u8 partial_pec = 0;
 	int status;
 
-	msgbuf0[0] = command;
-	switch(size) {
-	case I2C_SMBUS_QUICK:
-		msg[0].len = 0;
-		/* Special case: The read/write field is used as data */
-		msg[0].flags = flags | (read_write == I2C_SMBUS_READ ?
-					I2C_M_RD : 0);
-		num = 1;
-		break;
+	if (entry->result < 0)
+		return;
+
+	if (entry->smbus.read_write != I2C_SMBUS_READ)
+		return;
+
+	switch (entry->smbus.size) {
 	case I2C_SMBUS_BYTE:
-		if (read_write == I2C_SMBUS_READ) {
-			/* Special case: only a read! */
-			msg[0].flags = I2C_M_RD | flags;
-			num = 1;
-		}
+		entry->smbus.data->byte = msgbuf0[0];
 		break;
 	case I2C_SMBUS_BYTE_DATA:
-		if (read_write == I2C_SMBUS_READ)
-			msg[1].len = 1;
-		else {
-			msg[0].len = 2;
-			msgbuf0[1] = data->byte;
-		}
+		entry->smbus.data->byte = msgbuf1[0];
 		break;
 	case I2C_SMBUS_WORD_DATA:
-		if (read_write == I2C_SMBUS_READ)
-			msg[1].len = 2;
-		else {
-			msg[0].len=3;
-			msgbuf0[1] = data->word & 0xff;
-			msgbuf0[2] = data->word >> 8;
-		}
-		break;
 	case I2C_SMBUS_PROC_CALL:
-		num = 2; /* Special case */
-		read_write = I2C_SMBUS_READ;
-		msg[0].len = 3;
-		msg[1].len = 2;
-		msgbuf0[1] = data->word & 0xff;
-		msgbuf0[2] = data->word >> 8;
+		entry->smbus.data->word = msgbuf1[0] | (msgbuf1[1] << 8);
 		break;
-	case I2C_SMBUS_BLOCK_DATA:
-		if (read_write == I2C_SMBUS_READ) {
-			msg[1].flags |= I2C_M_RECV_LEN;
-			msg[1].len = 1; /* block length will be added by
-					   the underlying bus driver */
-		} else {
-			msg[0].len = data->block[0] + 2;
-			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
-				dev_err(&adapter->dev,
-					"Invalid block write size %d\n",
-					data->block[0]);
-				return -EINVAL;
-			}
-			for (i = 1; i < msg[0].len; i++)
-				msgbuf0[i] = data->block[i-1];
-		}
+	case I2C_SMBUS_I2C_BLOCK_DATA:
+		for (i = 0; i < entry->smbus.data->block[0]; i++)
+			entry->smbus.data->block[i + 1] = msgbuf1[i];
 		break;
+	case I2C_SMBUS_BLOCK_DATA:
 	case I2C_SMBUS_BLOCK_PROC_CALL:
-		num = 2; /* Another special case */
-		read_write = I2C_SMBUS_READ;
-		if (data->block[0] > I2C_SMBUS_BLOCK_MAX) {
-			dev_err(&adapter->dev,
-				"Invalid block write size %d\n",
-				data->block[0]);
-			return -EINVAL;
-		}
-		msg[0].len = data->block[0] + 2;
-		for (i = 1; i < msg[0].len; i++)
-			msgbuf0[i] = data->block[i-1];
-		msg[1].flags |= I2C_M_RECV_LEN;
-		msg[1].len = 1; /* block length will be added by
-				   the underlying bus driver */
-		break;
-	case I2C_SMBUS_I2C_BLOCK_DATA:
-		if (read_write == I2C_SMBUS_READ) {
-			msg[1].len = data->block[0];
-		} else {
-			msg[0].len = data->block[0] + 1;
-			if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
-				dev_err(&adapter->dev,
-					"Invalid block write size %d\n",
-					data->block[0]);
-				return -EINVAL;
-			}
-			for (i = 1; i <= data->block[0]; i++)
-				msgbuf0[i] = data->block[i];
-		}
+		for (i = 0; i < msgbuf1[0] + 1; i++)
+			entry->smbus.data->block[i] = msgbuf1[i];
 		break;
-	default:
-		dev_err(&adapter->dev, "Unsupported transaction %d\n", size);
-		return -EOPNOTSUPP;
 	}
 
-	i = ((flags & I2C_CLIENT_PEC) && size != I2C_SMBUS_QUICK
-				      && size != I2C_SMBUS_I2C_BLOCK_DATA);
-	if (i) {
-		/* Compute PEC if first message is a write */
-		if (!(msg[0].flags & I2C_M_RD)) {
-			if (num == 1) /* Write only */
-				i2c_smbus_add_pec(&msg[0]);
-			else /* Write followed by read */
-				partial_pec = i2c_smbus_msg_pec(0, &msg[0]);
-		}
-		/* Ask for PEC if last message is a read */
-		if (msg[num-1].flags & I2C_M_RD)
-			msg[num-1].len++;
-	}
-
-	status = i2c_transfer(adapter, msg, num);
-	if (status < 0)
-		return status;
-
 	/* Check PEC if last message is a read */
-	if (i && (msg[num-1].flags & I2C_M_RD)) {
-		status = i2c_smbus_check_pec(partial_pec, &msg[num-1]);
+	if (entry->pec && (entry->i2c.msgs[num - 1].flags & I2C_M_RD)) {
+		status = i2c_smbus_check_pec(entry->partial_pec,
+					     &entry->i2c.msgs[num - 1]);
 		if (status < 0)
-			return status;
+			entry->result = status;
 	}
+}
+
+static int i2c_smbus_emu_format(struct i2c_adapter *adapter,
+				struct i2c_op_q_entry *entry)
+{
+	/*
+	 * So we need to generate a series of msgs. In the case of
+	 * writing, we need to use only one message; when reading, we
+	 * need two. We initialize most things with sane defaults, to
+	 * keep the code below somewhat simpler.
+	 */
+
+        unsigned char *msgbuf0 = entry->msgbuf0;
+        int num = entry->smbus.read_write == I2C_SMBUS_READ ? 2 : 1;
+        struct i2c_msg *msg = entry->msg;
+        int i;
+
+        entry->i2c.msgs = msg;
+        entry->i2c.msgs[0].buf = msgbuf0;
+        entry->i2c.msgs[1].buf = entry->msgbuf1;
+
+        msg[0].addr = entry->smbus.addr;
+        msg[0].flags = entry->smbus.flags;
+        msg[0].len = 1;
+        msg[1].addr = entry->smbus.addr;
+        msg[1].flags = entry->smbus.flags | I2C_M_RD;
+        msg[1].len = 0;
+
+	msgbuf0[0] = entry->smbus.command;
+        switch (entry->smbus.size) {
+        case I2C_SMBUS_QUICK:
+                msg[0].len = 0;
+                /* Special case: The read/write field is used as data */
+                msg[0].flags = (entry->smbus.flags |
+                                ((entry->smbus.read_write == I2C_SMBUS_READ)
+                                 ? I2C_M_RD : 0));
+                num = 1;
+                break;
+        case I2C_SMBUS_BYTE:
+                if (entry->smbus.read_write == I2C_SMBUS_READ) {
+                        /* Special case: only a read! */
+                        msg[0].flags = I2C_M_RD | entry->smbus.flags;
+                        num = 1;
+                }
+                break;
+        case I2C_SMBUS_BYTE_DATA:
+                if (entry->smbus.read_write == I2C_SMBUS_READ)
+                        msg[1].len = 1;
+                else {
+                        msg[0].len = 2;
+                        msgbuf0[1] = entry->smbus.data->byte;
+                }
+                break;
+        case I2C_SMBUS_WORD_DATA:
+                if (entry->smbus.read_write == I2C_SMBUS_READ)
+                        msg[1].len = 2;
+                else {
+                        msg[0].len = 3;
+                        msgbuf0[1] = entry->smbus.data->word & 0xff;
+                        msgbuf0[2] = entry->smbus.data->word >> 8;
+                }
+                break;
+        case I2C_SMBUS_PROC_CALL:
+                num = 2; /* Special case */
+                entry->smbus.read_write = I2C_SMBUS_READ;
+                msg[0].len = 3;
+                msg[1].len = 2;
+                msgbuf0[1] = entry->smbus.data->word & 0xff;
+                msgbuf0[2] = entry->smbus.data->word >> 8;
+                break;
+        case I2C_SMBUS_BLOCK_DATA:
+                if (entry->smbus.read_write == I2C_SMBUS_READ) {
+                        msg[1].flags |= I2C_M_RECV_LEN;
+                        msg[1].len = 1; /* block length will be added by
+                                           the underlying bus driver */
+                } else {
+                        msg[0].len = entry->smbus.data->block[0] + 2;
+                        if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 2) {
+                                dev_err(&adapter->dev,
+                                        "Invalid block write size %d\n",
+                                        entry->smbus.data->block[0]);
+                                return -EINVAL;
+                        }
+                        for (i = 1; i < msg[0].len; i++)
+                                msgbuf0[i] = entry->smbus.data->block[i - 1];
+                }
+                break;
+        case I2C_SMBUS_BLOCK_PROC_CALL:
+                num = 2; /* Another special case */
+                entry->smbus.read_write = I2C_SMBUS_READ;
+                if (entry->smbus.data->block[0] > I2C_SMBUS_BLOCK_MAX) {
+                        dev_err(&adapter->dev,
+                                "Invalid block write size %d\n",
+                                entry->smbus.data->block[0]);
+                        return -EINVAL;
+                }
+                msg[0].len = entry->smbus.data->block[0] + 2;
+                for (i = 1; i < msg[0].len; i++)
+                        msgbuf0[i] = entry->smbus.data->block[i-1];
+                msg[1].flags |= I2C_M_RECV_LEN;
+                msg[1].len = 1; /* block length will be added by
+                                   the underlying bus driver */
+                break;
+        case I2C_SMBUS_I2C_BLOCK_DATA:
+                if (entry->smbus.read_write == I2C_SMBUS_READ) {
+                        msg[1].len = entry->smbus.data->block[0];
+                } else {
+                        msg[0].len = entry->smbus.data->block[0] + 1;
+                        if (msg[0].len > I2C_SMBUS_BLOCK_MAX + 1) {
+                                dev_err(&adapter->dev,
+                                        "Invalid block write size %d\n",
+                                        entry->smbus.data->block[0]);
+                                return -EINVAL;
+                        }
+                        for (i = 1; i <= entry->smbus.data->block[0]; i++)
+                                msgbuf0[i] = entry->smbus.data->block[i];
+                }
+                break;
+        default:
+                dev_err(&adapter->dev, "Unsupported transaction %d\n",
+                        entry->smbus.size);
+                return -EOPNOTSUPP;
+        }
+
+        entry->pec = ((entry->smbus.flags & I2C_CLIENT_PEC)
+                      && entry->smbus.size != I2C_SMBUS_QUICK
+                      && entry->smbus.size != I2C_SMBUS_I2C_BLOCK_DATA);
+        if (entry->pec) {
+                /* Compute PEC if first message is a write */
+                if (!(msg[0].flags & I2C_M_RD)) {
+                        if (num == 1) /* Write only */
+                                i2c_smbus_add_pec(&msg[0]);
+                        else /* Write followed by read */
+                                entry->partial_pec
+                                        = i2c_smbus_msg_pec(0, &msg[0]);
+                }
+                /* Ask for PEC if last message is a read */
+                if (msg[num - 1].flags & I2C_M_RD)
+                        msg[num - 1].len++;
+        }
+
+        entry->xfer_type = I2C_OP_I2C;
+        entry->i2c.msgs = msg;
+        entry->i2c.num = num;
+        entry->complete = i2c_smbus_emu_complete;
 
-	if (read_write == I2C_SMBUS_READ)
-		switch(size) {
-			case I2C_SMBUS_BYTE:
-				data->byte = msgbuf0[0];
-				break;
-			case I2C_SMBUS_BYTE_DATA:
-				data->byte = msgbuf1[0];
-				break;
-			case I2C_SMBUS_WORD_DATA:
-			case I2C_SMBUS_PROC_CALL:
-				data->word = msgbuf1[0] | (msgbuf1[1] << 8);
-				break;
-			case I2C_SMBUS_I2C_BLOCK_DATA:
-				for (i = 0; i < data->block[0]; i++)
-					data->block[i+1] = msgbuf1[i];
-				break;
-			case I2C_SMBUS_BLOCK_DATA:
-			case I2C_SMBUS_BLOCK_PROC_CALL:
-				for (i = 0; i < msgbuf1[0] + 1; i++)
-					data->block[i] = msgbuf1[i];
-				break;
-		}
 	return 0;
 }
 
@@ -1988,23 +2226,227 @@
 		   char read_write, u8 command, int protocol,
                    union i2c_smbus_data * data)
 {
+	struct i2c_op_q_entry *entry;
 	s32 res;
+	const struct i2c_algorithm *algo = adapter->algo;
 
-	flags &= I2C_M_TEN | I2C_CLIENT_PEC;
+	entry = kmalloc(sizeof(*entry), GFP_KERNEL);
+	if (!entry)
+		return -ENOMEM;
 
-	if (adapter->algo->smbus_xfer) {
+	entry->xfer_type = I2C_OP_SMBUS;
+	entry->smbus.addr = addr;
+	entry->smbus.flags = flags;
+	entry->smbus.read_write = read_write;
+	entry->smbus.command = command;
+	entry->smbus.size = protocol;
+	entry->smbus.data = data;
+	entry->complete = NULL;
+
+	if (algo->smbus_start) {
+		i2c_perform_op_wait(adapter, entry);
+	} else if (algo->smbus_xfer) {
 		mutex_lock(&adapter->bus_lock);
-		res = adapter->algo->smbus_xfer(adapter,addr,flags,read_write,
-						command, protocol, data);
+		entry->result = adapter->algo->smbus_xfer
+		  (adapter, entry->smbus.addr, entry->smbus.flags,
+		   entry->smbus.read_write, entry->smbus.command,
+		   entry->smbus.size, entry->smbus.data);
 		mutex_unlock(&adapter->bus_lock);
-	} else
-		res = i2c_smbus_xfer_emulated(adapter,addr,flags,read_write,
-					      command, protocol, data);
+		if (entry->complete)
+			entry->complete(adapter, entry);
+	} else {
+		if (i2c_smbus_emu_format(adapter, entry))
+			entry->result = -EINVAL;
+		else {
+			i2c_transfer_entry(adapter, entry);
+			/*
+			 * We get these back with the result being the
+			 * number of bytes transferred.  We want zero for
+			 * success for this routine.
+			 */
+			if (entry->result > 0)
+				entry->result = 0;
+		}
+	}
 
+	res = entry->result;
+	kfree(entry);
+	if (res > 0)
+		res = 0; /* Always return 0 on success */
 	return res;
 }
 EXPORT_SYMBOL(i2c_smbus_xfer);
 
+/* ----------------------------------------------------
+ * Entry handling
+ * ----------------------------------------------------
+ */
+
+/*
+ * Get the first entry off the head of the queue and lock it there.
+ * The entry is guaranteed to remain first in the list and the handler
+ * not be called until i2c_entry_put() is called.
+ */
+static struct i2c_op_q_entry *_i2c_entry_get(struct i2c_adapter *adap)
+{
+	struct i2c_op_q_entry *entry = NULL;
+
+	if (!list_empty(&adap->q)) {
+		struct list_head *link = adap->q.next;
+		entry = list_entry(link, struct i2c_op_q_entry, link);
+	}
+	pr_debug("_i2c_entry_get %p %p\n", adap, entry);
+	return entry;
+}
+
+struct i2c_op_q_entry *i2c_entry_get(struct i2c_adapter *adap)
+{
+	unsigned long flags;
+	struct i2c_op_q_entry *entry;
+
+	spin_lock_irqsave(&adap->q_lock, flags);
+	entry = _i2c_entry_get(adap);
+	if (entry) {
+		if (entry->state != I2C_OP_INITIALIZED)
+			entry = NULL;
+		else
+			kref_get(&entry->usecount);
+	}
+	spin_unlock_irqrestore(&adap->q_lock, flags);
+	return entry;
+}
+
+static void i2c_op_release(struct kref *ref)
+{
+	/*
+	 * Nothing to do here, all handling is from the kref_put
+	 * return code.
+	 */
+}
+
+static void _i2c_entry_put(struct i2c_adapter *adap,
+			   struct i2c_op_q_entry *entry,
+			   unsigned long *flags)
+{
+	if (entry == NULL)
+		return;
+
+	while (kref_put(&entry->usecount, i2c_op_release)) {
+		list_del(&entry->link);
+		spin_unlock_irqrestore(&adap->q_lock, *flags);
+
+		if (entry->complete)
+			entry->complete(adap, entry);
+
+		entry->handler(entry);
+
+		spin_lock_irqsave(&adap->q_lock, *flags);
+		entry = _i2c_entry_get(adap);
+		if (!entry)
+			break;
+		if (entry->state != I2C_OP_QUEUED)
+			/* Something else already started it. */
+			break;
+
+		entry->result = i2c_start_entry(adap, entry);
+		if (entry->start)
+			complete(entry->start);
+		if (!entry->result)
+			/* Successful start, we are done here. */
+			break;
+
+		/*
+		 * If we get here, the start failed and we need to
+		 * finish the entry.  We haven't incremented the
+		 * refcount, so looping again will cause it to be
+		 * completed.
+		 */
+	}
+}
+
+void i2c_entry_put(struct i2c_adapter *adap,
+		   struct i2c_op_q_entry *entry)
+{
+	unsigned long flags;
+
+	pr_debug("i2c_put %p %p\n", adap, entry);
+
+	spin_lock_irqsave(&adap->q_lock, flags);
+	_i2c_entry_put(adap, entry, &flags);
+	spin_unlock_irqrestore(&adap->q_lock, flags);
+}
+EXPORT_SYMBOL(i2c_entry_put);
+
+void i2c_op_done(struct i2c_adapter *adap, struct i2c_op_q_entry *entry)
+{
+	unsigned long flags;
+
+	pr_debug("i2c_op_done: %p %p\n", adap, entry);
+	spin_lock_irqsave(&adap->q_lock, flags);
+	/*
+	 * Guard against multiple calls to "done" for an entry.  This
+	 * can happen, for instance, if a timer poll and an interrupt
+	 * both discover that the operation is finished and both
+	 * report it.
+	 */
+	if (entry->state != I2C_OP_FINISHED) {
+		entry->state = I2C_OP_FINISHED;
+		_i2c_entry_put(adap, entry, &flags);
+	}
+	spin_unlock_irqrestore(&adap->q_lock, flags);
+}
+EXPORT_SYMBOL(i2c_op_done);
+
+void i2c_poll(struct i2c_client *client,
+	      unsigned int us_since_last_call)
+{
+	struct i2c_adapter *adap = client->adapter;
+	struct i2c_op_q_entry *entry;
+
+	entry = i2c_entry_get(adap);
+	if (!entry)
+		return;
+	adap->algo->poll(adap, entry, us_since_last_call);
+	i2c_entry_put(adap, entry);
+}
+EXPORT_SYMBOL(i2c_poll);
+
+int i2c_non_blocking_op(struct i2c_client *client,
+			struct i2c_op_q_entry *entry)
+{
+	unsigned long      flags;
+	struct i2c_adapter *adap = client->adapter;
+	int ret = 0;
+
+	if (!i2c_non_blocking_capable(adap))
+		return -ENOSYS;
+
+	entry->smbus.addr = client->addr;
+	entry->smbus.flags = client->flags;
+
+	if (entry->xfer_type == I2C_OP_SMBUS) {
+		if (!adap->algo->smbus_start) {
+			if (i2c_smbus_emu_format(adap, entry))
+				return -EINVAL;
+		}
+	}
+
+	i2c_init_entry(entry);
+	entry->use_timer = 1; /* Let the timer code poll it. */
+
+	spin_lock_irqsave(&adap->q_lock, flags);
+	list_add_tail(&entry->link, &adap->q);
+	if (adap->q.next == &entry->link) {
+		/* Added to the list head, start it */
+		ret = i2c_start_entry(adap, entry);
+		if (ret)
+			list_del(&entry->link);
+	}
+	spin_unlock_irqrestore(&adap->q_lock, flags);
+	return ret;
+}
+EXPORT_SYMBOL(i2c_non_blocking_op);
+
 MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
 MODULE_DESCRIPTION("I2C-Bus main module");
 MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/Kconfig linux-2.6.29.6.mod/drivers/Kconfig
--- linux-2.6.29.6.orig/drivers/Kconfig	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/Kconfig	2009-07-21 11:28:18.000000000 -0700
@@ -48,6 +48,8 @@
 
 source "drivers/char/Kconfig"
 
+source "drivers/vme/Kconfig"
+
 source "drivers/i2c/Kconfig"
 
 source "drivers/spi/Kconfig"
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/Makefile linux-2.6.29.6.mod/drivers/Makefile
--- linux-2.6.29.6.orig/drivers/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/Makefile	2009-07-21 11:28:18.000000000 -0700
@@ -69,6 +69,7 @@
 obj-$(CONFIG_GAMEPORT)		+= input/gameport/
 obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_I2O)		+= message/
+obj-$(CONFIG_VME_BRIDGE)        += vme/
 obj-$(CONFIG_RTC_LIB)		+= rtc/
 obj-y				+= i2c/
 obj-$(CONFIG_W1)		+= w1/
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/chips/cfi_cmdset_0002.c linux-2.6.29.6.mod/drivers/mtd/chips/cfi_cmdset_0002.c
--- linux-2.6.29.6.orig/drivers/mtd/chips/cfi_cmdset_0002.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/chips/cfi_cmdset_0002.c	2009-07-21 11:28:18.000000000 -0700
@@ -492,7 +492,7 @@
 
 	/* FIXME: erase-suspend-program is broken.  See
 	   http://lists.infradead.org/pipermail/linux-mtd/2003-December/009001.html */
-	printk(KERN_NOTICE "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");
+	printk(KERN_DEBUG "cfi_cmdset_0002: Disabling erase-suspend-program due to code brokenness.\n");
 
 	__module_get(THIS_MODULE);
 	return mtd;
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/maps/cpci6200_nor.c linux-2.6.29.6.mod/drivers/mtd/maps/cpci6200_nor.c
--- linux-2.6.29.6.orig/drivers/mtd/maps/cpci6200_nor.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/maps/cpci6200_nor.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,128 @@
+/*
+ * 
+ * Mapping for Motorola CPCI6200 flash
+ *
+ * Ajit Prem (ajit.prem@emerson.com)
+ *
+ * Copyright 2008 Emerson Network Power - Embedded Computing, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <platforms/85xx/cpci6200.h>
+
+static struct mtd_info *flash;
+
+static struct map_info cpci6200_map = {
+	.name =		"cpci6200-flash",
+	.size =		CPCI6200_FLASH_SIZE,
+	.bankwidth =	4,
+};
+
+static struct mtd_partition cpci6200_partitions[] = {
+	{
+		.name =   "Linux Kernel + INITRD",
+		.offset = 0x00000000,
+		.size =   0x01000000,
+	},
+	{
+		.name =   "Linux JFFS2 Filesystem",
+		.offset = 0x01000000,
+		.size =   0x06e00000,
+	},
+	{
+		.name	= "Bootloader Block B",
+		.offset	= 0x07e00000,
+		.size	= 0x00100000,
+	},
+	{
+		.name	= "Bootloader Block A",
+		.offset	= 0x07f00000,
+		.size	= 0x00100000,
+	}
+};
+
+int __init cpci6200_map_init(void)
+{
+	void __iomem *nor_ctrl_status_reg;
+	u8 value;
+
+	cpci6200_map.phys = CPCI6200_FLASH_BASE;
+	cpci6200_map.virt = ioremap(cpci6200_map.phys, cpci6200_map.size);
+
+	if (!cpci6200_map.virt) {
+		printk(KERN_ERR "cpci6200_flash: Failed to ioremap flash\n");
+		return -EIO;
+	}
+
+	simple_map_init(&cpci6200_map);
+
+	nor_ctrl_status_reg = ioremap(CPCI6200_NOR_FLASH_CTRL_STAT_REG, 1);
+	if (!nor_ctrl_status_reg) {
+		printk(KERN_ERR "cpci6200_flash: ioremap() failed\n");
+		iounmap((void *)cpci6200_map.virt);
+		return -EIO;
+	}
+
+	value = readb(nor_ctrl_status_reg);
+	iounmap(nor_ctrl_status_reg);
+
+	if (value & CPCI6200_NOR_FLASH_WP_HW) {
+		printk(KERN_INFO "cpci6200_flash: Flash HW write protected - mapping read-only\n");
+		flash = do_map_probe("map_rom", &cpci6200_map);
+	} else if (value & CPCI6200_NOR_FLASH_WP_SW) {
+		printk(KERN_INFO "cpci6200_flash: Flash SW write protected - mapping read-only\n");
+		flash = do_map_probe("map_rom", &cpci6200_map);
+	} else {
+		flash = do_map_probe("cfi_probe", &cpci6200_map);
+		if (!flash) {
+			flash = do_map_probe("jedec", &cpci6200_map);
+		}
+		if (!flash) {
+			flash = do_map_probe("map_rom", &cpci6200_map);
+		}
+	}
+	
+	if (flash) {
+		flash->owner = THIS_MODULE;
+		add_mtd_partitions(flash, cpci6200_partitions,
+					ARRAY_SIZE(cpci6200_partitions));
+	} else {
+		printk(KERN_ERR "cpci6200_flash: map probe failed for flash\n");
+		iounmap((void *)cpci6200_map.virt);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void __exit cpci6200_map_exit(void)
+{
+	if (flash) {
+		del_mtd_partitions(flash);
+		map_destroy(flash);
+	}
+
+	if (cpci6200_map.virt) {
+		iounmap((void *)cpci6200_map.virt);
+		cpci6200_map.virt = NULL;
+	}
+}
+
+module_init(cpci6200_map_init);
+module_exit(cpci6200_map_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ajit Prem <ajit.prem@emerson.com>");
+MODULE_DESCRIPTION("MTD map and partitions for the Emerson CPCI6200 board");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/maps/Kconfig linux-2.6.29.6.mod/drivers/mtd/maps/Kconfig
--- linux-2.6.29.6.orig/drivers/mtd/maps/Kconfig	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/maps/Kconfig	2009-07-21 11:28:18.000000000 -0700
@@ -551,5 +551,37 @@
 
 	  This selection automatically selects the map_ram driver.
 
+config MTD_MVME7100
+        tristate "Flash device mapped on the MVME7100 board"
+        depends on MVME7100 && MTD_CFI && MTD_PARTITIONS
+        help
+          This enables access to the Flash on Emerson Network Power
+          MVME7100 boards.
+          If you have such a board, say 'Y'.
+
+config MTD_MVME4100
+        tristate "Flash device mapped on the MVME4100 board"
+        depends on MVME4100 && MTD_CFI && MTD_PARTITIONS
+        help
+          This enables access to the Flash on Emerson Network Power
+          MVME4100 boards.
+          If you have such a board, say 'Y'.
+
+config MTD_MVME3100
+        tristate "Flash device mapped on the MVME3100 board"
+        depends on MVME3100 && MTD_CFI && MTD_PARTITIONS
+        help
+          This enables access to the Flash on Emerson Network Power
+          MVME3100 boards.
+          If you have such a board, say 'Y'.
+
+config MTD_CPCI6200
+        tristate "Flash device mapped on the CPCI6200 board"
+        depends on CPCI6200 && MTD_CFI && MTD_PARTITIONS
+        help
+          This enables access to the Flash on Emerson Network Power
+          CPCI6200 boards.
+          If you have such a board, say 'Y'.
+
 endmenu
 
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/maps/Makefile linux-2.6.29.6.mod/drivers/mtd/maps/Makefile
--- linux-2.6.29.6.orig/drivers/mtd/maps/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/maps/Makefile	2009-07-21 11:28:18.000000000 -0700
@@ -61,3 +61,7 @@
 obj-$(CONFIG_MTD_OMAP_NOR)	+= omap_nor.o
 obj-$(CONFIG_MTD_INTEL_VR_NOR)	+= intel_vr_nor.o
 obj-$(CONFIG_MTD_BFIN_ASYNC)	+= bfin-async-flash.o
+obj-$(CONFIG_MTD_MVME7100)      += mvme7100_nor.o
+obj-$(CONFIG_MTD_MVME4100)      += mvme4100_nor.o
+obj-$(CONFIG_MTD_MVME3100)      += mvme3100_nor.o
+obj-$(CONFIG_MTD_CPCI6200)      += cpci6200_nor.o
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/maps/mvme3100_nor.c linux-2.6.29.6.mod/drivers/mtd/maps/mvme3100_nor.c
--- linux-2.6.29.6.orig/drivers/mtd/maps/mvme3100_nor.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/maps/mvme3100_nor.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,164 @@
+/*
+ * 
+ * Mapping for Motorola MVME3100 flash
+ *
+ * Ajit Prem (Ajit.Prem@emerson.com)
+ *
+ * Copyright 2005-2007 Motorola Inc.
+ * Copyright 2008-2009 Emerson Network Power Embedded Computing Inc.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <platforms/85xx/mvme3100.h>
+
+static struct mtd_info *flash;
+
+static struct map_info mvme3100_128M_map = {
+	.name =		"mvme3100-flash",
+	.size =		MVME3100_FLASH_SIZE_128M,
+	.bankwidth =	4,
+};
+
+static struct map_info mvme3100_64M_map = {
+	.name =		"mvme3100-flash",
+	.size =		MVME3100_FLASH_SIZE_64M,
+	.bankwidth =	4,
+};
+
+static struct map_info mvme3100_map;
+ 
+static struct mtd_partition mvme3100_128M_partitions[] = {
+	{
+		.name =   "Linux Kernel + INITRD",
+		.offset = 0x00000000,
+		.size =   0x01000000,
+	},
+	{
+		.name =   "Linux JFFS2 Filesystem",
+		.offset = 0x01000000,
+		.size =   0x06e00000,
+	},
+	{
+		.name	= "Bootloader Block B",
+		.offset	= 0x07e00000,
+		.size	= 0x00100000,
+	},
+	{
+		.name	= "Bootloader Block A",
+		.offset	= 0x07f00000,
+		.size	= 0x00100000,
+	}
+};
+
+static struct mtd_partition mvme3100_64M_partitions[] = {
+	{
+		.name =   "Linux Kernel + INITRD",
+		.offset = 0x00000000,
+		.size =   0x01000000,
+	},
+	{
+		.name =   "Linux JFFS2 Filesystem",
+		.offset = 0x01000000,
+		.size =   0x02e00000,
+	},
+	{
+		.name	= "Bootloader Block B",
+		.offset	= 0x03e00000,
+		.size	= 0x00100000,
+	},
+	{
+		.name	= "Bootloader Block A",
+		.offset	= 0x03f00000,
+		.size	= 0x00100000,
+	}
+};
+
+
+int __init mvme3100_map_init(void)
+{
+	unsigned long mvme3100_flash_base;
+
+	mvme3100_flash_base = MVME3100_FLASH_BASE_128M;
+
+	mvme3100_map = mvme3100_128M_map;
+
+	mvme3100_map.phys = mvme3100_flash_base;
+	mvme3100_map.virt = ioremap(mvme3100_flash_base, 
+						mvme3100_map.size);
+
+	if (!mvme3100_map.virt) {
+		printk("Failed to ioremap flash\n");
+		return -EIO;
+	}
+
+	simple_map_init(&mvme3100_map);
+
+	flash = do_map_probe("cfi_probe", &mvme3100_map);
+	if (flash) {
+		flash->owner = THIS_MODULE;
+		add_mtd_partitions(flash, mvme3100_128M_partitions,
+					ARRAY_SIZE(mvme3100_128M_partitions));
+	} else {
+		iounmap((void *)mvme3100_map.virt);
+		mvme3100_map.virt = 0;
+
+		mvme3100_flash_base = MVME3100_FLASH_BASE_64M;
+		mvme3100_map = mvme3100_64M_map;
+
+		mvme3100_map.phys = mvme3100_flash_base;
+		mvme3100_map.virt = ioremap(mvme3100_flash_base, 
+					mvme3100_map.size);
+
+		if (!mvme3100_map.virt) {
+			printk("Failed to ioremap flash\n");
+			return -EIO;
+		}
+
+		simple_map_init(&mvme3100_map);
+
+		flash = do_map_probe("cfi_probe", &mvme3100_map);
+		if (flash) {
+			flash->owner = THIS_MODULE;
+			add_mtd_partitions(flash, mvme3100_64M_partitions,
+					ARRAY_SIZE(mvme3100_64M_partitions));
+		} else {
+			printk("map probe failed for flash\n");
+			iounmap((void *)mvme3100_map.virt);
+			return -ENXIO;
+		}
+	}
+
+	return 0;
+}
+
+static void __exit mvme3100_map_exit(void)
+{
+	if (flash) {
+		del_mtd_partitions(flash);
+		map_destroy(flash);
+	}
+
+	if (mvme3100_map.virt) {
+		iounmap((void *)mvme3100_map.virt);
+		mvme3100_map.virt = NULL;
+	}
+}
+
+module_init(mvme3100_map_init);
+module_exit(mvme3100_map_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ajit Prem <ajit.prem@emerson.com>");
+MODULE_DESCRIPTION("MTD map and partitions for Emerson MVME3100");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/maps/mvme4100_nor.c linux-2.6.29.6.mod/drivers/mtd/maps/mvme4100_nor.c
--- linux-2.6.29.6.orig/drivers/mtd/maps/mvme4100_nor.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/maps/mvme4100_nor.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,128 @@
+/*
+ * 
+ * Mapping for Motorola MVME4100 flash
+ *
+ * Ajit Prem (ajit.prem@emerson.com)
+ *
+ * Copyright 2008 Emerson Network Power - Embedded Computing, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <platforms/85xx/mvme4100.h>
+
+static struct mtd_info *flash;
+
+static struct map_info mvme4100_map = {
+	.name =		"mvme4100-flash",
+	.size =		MVME4100_FLASH_SIZE,
+	.bankwidth =	4,
+};
+
+static struct mtd_partition mvme4100_partitions[] = {
+	{
+		.name =   "Linux Kernel + INITRD",
+		.offset = 0x00000000,
+		.size =   0x01000000,
+	},
+	{
+		.name =   "Linux JFFS2 Filesystem",
+		.offset = 0x01000000,
+		.size =   0x06e00000,
+	},
+	{
+		.name	= "Bootloader Block B",
+		.offset	= 0x07e00000,
+		.size	= 0x00100000,
+	},
+	{
+		.name	= "Bootloader Block A",
+		.offset	= 0x07f00000,
+		.size	= 0x00100000,
+	}
+};
+
+int __init mvme4100_map_init(void)
+{
+	void __iomem *nor_ctrl_status_reg;
+	u8 value;
+
+	mvme4100_map.phys = MVME4100_FLASH_BASE;
+	mvme4100_map.virt = ioremap(mvme4100_map.phys, mvme4100_map.size);
+
+	if (!mvme4100_map.virt) {
+		printk(KERN_ERR "mvme4100_flash: Failed to ioremap flash\n");
+		return -EIO;
+	}
+
+	simple_map_init(&mvme4100_map);
+
+	nor_ctrl_status_reg = ioremap(MVME4100_NOR_FLASH_CTRL_STAT_REG, 1);
+	if (!nor_ctrl_status_reg) {
+		printk(KERN_ERR "mvme4100_flash: ioremap() failed\n");
+		iounmap((void *)mvme4100_map.virt);
+		return -EIO;
+	}
+
+	value = readb(nor_ctrl_status_reg);
+	iounmap(nor_ctrl_status_reg);
+
+	if (value & MVME4100_NOR_FLASH_WP_HW) {
+		printk(KERN_INFO "mvme4100_flash: Flash HW write protected - mapping read-only\n");
+		flash = do_map_probe("map_rom", &mvme4100_map);
+	} else if (value & MVME4100_NOR_FLASH_WP_SW) {
+		printk(KERN_INFO "mvme4100_flash: Flash SW write protected - mapping read-only\n");
+		flash = do_map_probe("map_rom", &mvme4100_map);
+	} else {
+		flash = do_map_probe("cfi_probe", &mvme4100_map);
+		if (!flash) {
+			flash = do_map_probe("jedec", &mvme4100_map);
+		}
+		if (!flash) {
+			flash = do_map_probe("map_rom", &mvme4100_map);
+		}
+	}
+	
+	if (flash) {
+		flash->owner = THIS_MODULE;
+		add_mtd_partitions(flash, mvme4100_partitions,
+					ARRAY_SIZE(mvme4100_partitions));
+	} else {
+		printk(KERN_ERR "mvme4100_flash: map probe failed for flash\n");
+		iounmap((void *)mvme4100_map.virt);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void __exit mvme4100_map_exit(void)
+{
+	if (flash) {
+		del_mtd_partitions(flash);
+		map_destroy(flash);
+	}
+
+	if (mvme4100_map.virt) {
+		iounmap((void *)mvme4100_map.virt);
+		mvme4100_map.virt = NULL;
+	}
+}
+
+module_init(mvme4100_map_init);
+module_exit(mvme4100_map_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ajit Prem <ajit.prem@emerson.com>");
+MODULE_DESCRIPTION("MTD map and partitions for the Emerson MVME4100 board");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/maps/mvme7100_nor.c linux-2.6.29.6.mod/drivers/mtd/maps/mvme7100_nor.c
--- linux-2.6.29.6.orig/drivers/mtd/maps/mvme7100_nor.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/maps/mvme7100_nor.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,128 @@
+/*
+ * 
+ * Mapping for Motorola MVME7100 flash
+ *
+ * Ajit Prem (ajit.prem@emerson.com)
+ *
+ * Copyright 2008 Emerson Network Power - Embedded Computing, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/map.h>
+#include <linux/mtd/partitions.h>
+#include <asm/io.h>
+#include <platforms/86xx/mvme7100.h>
+
+static struct mtd_info *flash;
+
+static struct map_info mvme7100_map = {
+	.name =		"mvme7100-flash",
+	.size =		MVME7100_FLASH_SIZE,
+	.bankwidth =	4,
+};
+
+static struct mtd_partition mvme7100_partitions[] = {
+	{
+		.name =   "Linux Kernel + INITRD",
+		.offset = 0x00000000,
+		.size =   0x01000000,
+	},
+	{
+		.name =   "Linux JFFS2 Filesystem",
+		.offset = 0x01000000,
+		.size =   0x06e00000,
+	},
+	{
+		.name	= "Bootloader Block B",
+		.offset	= 0x07e00000,
+		.size	= 0x00100000,
+	},
+	{
+		.name	= "Bootloader Block A",
+		.offset	= 0x07f00000,
+		.size	= 0x00100000,
+	}
+};
+
+int __init mvme7100_map_init(void)
+{
+	void __iomem *nor_ctrl_status_reg;
+	u8 value;
+
+	mvme7100_map.phys = MVME7100_FLASH_BASE;
+	mvme7100_map.virt = ioremap(mvme7100_map.phys, mvme7100_map.size);
+
+	if (!mvme7100_map.virt) {
+		printk(KERN_ERR "mvme7100_flash: Failed to ioremap flash\n");
+		return -EIO;
+	}
+
+	simple_map_init(&mvme7100_map);
+
+	nor_ctrl_status_reg = ioremap(MVME7100_NOR_FLASH_CTRL_STAT_REG, 1);
+	if (!nor_ctrl_status_reg) {
+		printk(KERN_ERR "mvme7100_flash: ioremap() failed\n");
+		iounmap((void *)mvme7100_map.virt);
+		return -EIO;
+	}
+
+	value = readb(nor_ctrl_status_reg);
+	iounmap(nor_ctrl_status_reg);
+
+	if (value & MVME7100_NOR_FLASH_WP_HW) {
+		printk(KERN_INFO "mvme7100_flash: Flash HW write protected - mapping read-only\n");
+		flash = do_map_probe("map_rom", &mvme7100_map);
+	} else if (value & MVME7100_NOR_FLASH_WP_SW) {
+		printk(KERN_INFO "mvme7100_flash: Flash SW write protected - mapping read-only\n");
+		flash = do_map_probe("map_rom", &mvme7100_map);
+	} else {
+		flash = do_map_probe("cfi_probe", &mvme7100_map);
+		if (!flash) {
+			flash = do_map_probe("jedec", &mvme7100_map);
+		}
+		if (!flash) {
+			flash = do_map_probe("map_rom", &mvme7100_map);
+		}
+	}
+	
+	if (flash) {
+		flash->owner = THIS_MODULE;
+		add_mtd_partitions(flash, mvme7100_partitions,
+					ARRAY_SIZE(mvme7100_partitions));
+	} else {
+		printk(KERN_ERR "mvme7100_flash: map probe failed for flash\n");
+		iounmap((void *)mvme7100_map.virt);
+		return -ENXIO;
+	}
+
+	return 0;
+}
+
+static void __exit mvme7100_map_exit(void)
+{
+	if (flash) {
+		del_mtd_partitions(flash);
+		map_destroy(flash);
+	}
+
+	if (mvme7100_map.virt) {
+		iounmap((void *)mvme7100_map.virt);
+		mvme7100_map.virt = NULL;
+	}
+}
+
+module_init(mvme7100_map_init);
+module_exit(mvme7100_map_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ajit Prem <ajit.prem@emerson.com>");
+MODULE_DESCRIPTION("MTD map and partitions for the Emerson MVME7100 board");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/nand/cpci6200_nand.c linux-2.6.29.6.mod/drivers/mtd/nand/cpci6200_nand.c
--- linux-2.6.29.6.orig/drivers/mtd/nand/cpci6200_nand.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/nand/cpci6200_nand.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,423 @@
+/*
+ * drivers/mtd/nand/cpci6200_nand.c
+ *
+ * A glue driver for the NAND chips on the CPCI6200 board
+ *
+ * Author: Ajit Prem (ajit.prem@emerson.com)
+ * Copyright 2008 Emerson Network Power Embedded Computing 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <platforms/85xx/cpci6200.h>
+
+static int n_physical_chips;
+
+struct cpci6200_nand_host {
+	struct nand_chip nand_chip;
+	struct mtd_info mtd;
+	void __iomem *io_ctrl;
+	void __iomem *io_select;
+	void __iomem *io_status;
+	void __iomem *io_data;
+	int chip;
+	int chip_enable;
+};
+
+static struct cpci6200_nand_host *chips[2];
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+
+/*
+ * Define static partitions for flash device
+ */
+static struct mtd_partition partition_info_4G[] = {
+	{
+	 .name = "Linux YAFFS 1",
+	 .offset = 0x00000000,
+	 .size   = 0x80000000,
+	}, 
+	{
+	 .name = "Linux YAFFS 2",
+	 .offset = 0x80000000,
+	 .size   = 0x80000000,
+	},
+};
+
+static struct mtd_partition partition_info_8G[] = {
+        {
+         .name = "Linux YAFFS 1",
+         .offset = 0x00000000,
+         .size   = 0x80000000,
+        },
+        {
+         .name = "Linux YAFFS 2",
+         .offset = 0x80000000,
+         .size   = 0x80000000,
+        },
+        {
+         .name = "Linux YAFFS 3",
+         .offset = 0x100000000LL,
+         .size   = 0x80000000,
+        },
+        {
+         .name = "Linux YAFFS 4",
+         .offset = 0x180000000LL,
+         .size   = 0x80000000,
+        },
+};
+
+#endif
+
+/*
+ *      hardware specific access to control-lines
+ *
+ *      ctrl:
+ *      NAND_NCE: bit 0 -> bits 4->7 (0xf0) in SELECT Reg
+ *      NAND_CLE: bit 1 -> bit 7 (0x80) in CONTROL Reg
+ *      NAND_ALE: bit 2 -> bit 6 (0x40) in CONTROL Reg
+ */
+
+static void cpci6200_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct cpci6200_nand_host *host = nand_chip->priv;
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		unsigned char bits;
+
+		bits = readb(host->io_ctrl);
+		bits &= 0x3f;
+		bits = (ctrl & NAND_CLE) << 6;
+		bits |= (ctrl & NAND_ALE) << 4;
+		writeb(bits, host->io_ctrl);
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, host->io_data);
+}
+
+static void cpci6200_select_chip(struct mtd_info *mtd, int chip)
+{
+        struct nand_chip *nand_chip = mtd->priv;
+        struct cpci6200_nand_host *host = nand_chip->priv;
+        unsigned char sel;
+
+	if (chip > 3)
+		return;
+
+        sel = readb(host->io_select);
+        sel &= ~(CPCI6200_NAND_FLASH_CE1 | CPCI6200_NAND_FLASH_CE2 |
+                 CPCI6200_NAND_FLASH_CE3 | CPCI6200_NAND_FLASH_CE4);
+
+        switch (chip) {
+        case 0:
+                sel |= CPCI6200_NAND_FLASH_CE1;
+                break;
+        case 1:
+                sel |= CPCI6200_NAND_FLASH_CE2;
+                break;
+        case 2:
+                sel |= CPCI6200_NAND_FLASH_CE3;
+                break;
+        case 3:
+                sel |= CPCI6200_NAND_FLASH_CE4;
+                break;
+	default:
+                break;
+        }
+	host->chip_enable = chip;
+        writeb(sel, host->io_select);
+}
+
+static int cpci6200_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct cpci6200_nand_host *host = nand_chip->priv;
+	u8 io_status;
+	int status;
+
+	io_status = readb(host->io_status);
+
+        switch (host->chip_enable) {
+        case 0:
+		status = io_status & CPCI6200_NAND_FLASH_RB1; 
+                break;
+        case 1:
+		status = io_status & CPCI6200_NAND_FLASH_RB2; 
+                break;
+        case 2:
+		status = io_status & CPCI6200_NAND_FLASH_RB3; 
+                break;
+        case 3:
+		status = io_status & CPCI6200_NAND_FLASH_RB4; 
+                break;
+	default:
+		status = 1;
+                break;
+        }
+	return status;
+}
+
+static int __init cpci6200_init_one(int chip)
+{
+	struct cpci6200_nand_host *host;
+	struct mtd_info *mtd;
+	struct nand_chip *nand_chip;
+	unsigned char reg;
+	int err = 0;
+#ifdef CONFIG_MTD_PARTITIONS
+	const char *part_type = 0;
+	int mtd_parts_nb = 0;
+	struct mtd_partition *mtd_parts = 0;
+#endif
+
+	/* Allocate memory for MTD device structure and private data */
+	host = kzalloc(sizeof(struct cpci6200_nand_host), GFP_KERNEL);
+	if (!host) {
+		printk(KERN_WARNING
+		       "cpci6200_nand: Unable to allocate device structure.\n");
+		return -ENOMEM;
+	}
+
+	if (chip == 1) {
+		host->io_ctrl = ioremap(CPCI6200_NAND_FLASH1_CONTROL_REG, 1);
+		if (!host->io_ctrl) {
+			printk(KERN_ERR "cpci6200_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_dhost;
+		}
+		host->io_select = ioremap(CPCI6200_NAND_FLASH1_SELECT_REG, 1);
+		if (!host->io_select) {
+			printk(KERN_ERR "cpci6200_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d1;
+		}
+		host->io_status = ioremap(CPCI6200_NAND_FLASH1_STATUS_REG, 1);
+		if (!host->io_status) {
+			printk(KERN_ERR "cpci6200_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d2;
+		}
+		host->io_data = ioremap(CPCI6200_NAND_FLASH1_DATA_REG, 1);
+		if (!host->io_data) {
+			printk(KERN_ERR "cpci6200_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d3;
+		}
+		chips[0] = host;
+	} else if (chip == 2) {
+		host->io_ctrl = ioremap(CPCI6200_NAND_FLASH2_CONTROL_REG, 1);
+		if (!host->io_ctrl) {
+			printk(KERN_ERR "cpci6200_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_dhost;
+		}
+		host->io_select = ioremap(CPCI6200_NAND_FLASH2_SELECT_REG, 1);
+		if (!host->io_select) {
+			printk(KERN_ERR "cpci6200_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d1;
+		}
+		host->io_status = ioremap(CPCI6200_NAND_FLASH2_STATUS_REG, 1);
+		if (!host->io_status) {
+			printk(KERN_ERR "cpci6200_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d2;
+		}
+		host->io_data = ioremap(CPCI6200_NAND_FLASH2_DATA_REG, 1);
+		if (!host->io_data) {
+			printk(KERN_ERR "cpci6200_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d3;
+		}
+		chips[1] = host;
+	} else {
+		err = -EINVAL;
+		goto init_dhost;
+	}
+
+	host->chip = chip;
+	reg = readb(host->io_ctrl);
+	reg &= ~CPCI6200_NAND_FLASH_WP;
+	writeb(reg, host->io_ctrl);
+	mtd = &host->mtd;
+	nand_chip = &host->nand_chip;
+
+	/* Link the private data with the MTD structure */
+	nand_chip->priv = host;
+	mtd->priv = nand_chip;
+	mtd->owner = THIS_MODULE;
+
+	/* Set address of NAND IO lines */
+	nand_chip->IO_ADDR_R = host->io_data;
+	nand_chip->IO_ADDR_W = host->io_data;
+
+	nand_chip->cmd_ctrl = cpci6200_hwcontrol;
+	nand_chip->select_chip = cpci6200_select_chip;
+	nand_chip->dev_ready = cpci6200_device_ready;
+	/* We'll let YAFFS do ECC*/
+	nand_chip->ecc.mode = NAND_ECC_NONE;
+	nand_chip->chip_delay = 20;
+
+	/* Enable for a flash based bad block table */
+ 	nand_chip->options = NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR;
+
+	/* Scan to find existence of the device */
+	if (nand_scan(mtd, 4)) {
+		err = -ENXIO;
+		goto init_d4;
+	}
+
+#ifdef CONFIG_MTD_PARTITIONS
+	if (chip == 1)
+		mtd->name = "CPCI6200 NAND Chip 1";
+	else if (chip == 2)
+		mtd->name = "CPCI6200 NAND Chip 2";
+	/* First look for partitions on the command line, these take
+	 * take precedence over statically defined partitions */
+	mtd_parts_nb = parse_mtd_partitions(mtd, part_probes, &mtd_parts, 0);
+	if (mtd_parts_nb > 0)
+		part_type = "command line";
+	else
+		mtd_parts_nb = 0;
+
+	if (mtd_parts_nb == 0) {
+		part_type = "static";
+		if (mtd->size == 0x100000000LL) {
+			mtd_parts = partition_info_4G;
+			mtd_parts_nb = 2;
+		} else if (mtd->size == 0x200000000LL) {
+			mtd_parts = partition_info_8G;
+			mtd_parts_nb = 4;
+		} else {
+                        printk(KERN_INFO "cpci6200_nand: Unexpected Flash Size\n");
+                        err = -ENXIO;
+                        goto init_d4;
+                }
+	}
+
+	/* Register the partitions */
+	printk(KERN_INFO "Using %s partition definition\n", part_type);
+        switch (mtd->size) {
+        case 0x100000000LL:
+                add_mtd_partitions(mtd, mtd_parts, mtd_parts_nb);
+                break;
+        case 0x200000000LL:
+                add_mtd_partitions(mtd, mtd_parts, mtd_parts_nb);
+                break;
+        }
+#else
+	add_mtd_device(mtd);
+#endif
+
+	goto init_ret;
+
+init_d4:
+	/* Set WP */
+	reg = readb(host->io_ctrl);
+	reg |= CPCI6200_NAND_FLASH_WP;
+	writeb(reg, host->io_ctrl);
+	iounmap(host->io_data);
+init_d3:
+	iounmap(host->io_status);
+init_d2:
+	iounmap(host->io_select);
+init_d1:
+	iounmap(host->io_ctrl);
+init_dhost:
+	kfree(host);
+init_ret:
+	return err;
+}
+
+static int __init cpci6200_init(void)
+{
+	int err = -ENXIO;
+	void __iomem *preg;
+
+	preg = ioremap(CPCI6200_NAND_FLASH1_PRESENCE_REG, 1);
+	if (!preg) {
+		printk(KERN_WARNING "cpci6200_nand: ioremap failed\n");
+
+		return -ENOMEM;
+	}
+	if (readb(preg) & CPCI6200_NAND_FLASH_CP) {
+		err = cpci6200_init_one(1);
+		if (err) {
+			iounmap(preg);
+			return err;
+		}
+		n_physical_chips++;
+	}
+	iounmap(preg);
+
+	preg = ioremap(CPCI6200_NAND_FLASH2_PRESENCE_REG, 1);
+	if (!preg) {
+		printk(KERN_WARNING "cpci6200_nand: ioremap failed\n");
+
+		return -ENOMEM;
+	}
+	if (readb(preg) & CPCI6200_NAND_FLASH_CP) {
+		err = cpci6200_init_one(2);
+		if (err) {
+			iounmap(preg);
+			return err;
+		}
+		n_physical_chips++;
+	}
+	iounmap(preg);
+
+	return err;
+}
+
+module_init(cpci6200_init);
+
+static void __exit cpci6200_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < n_physical_chips; i++) {
+		struct cpci6200_nand_host *host = chips[i];
+		struct mtd_info *mtd;
+		unsigned char reg;
+
+		if (host) {
+			mtd = &host->mtd;
+
+			if (mtd)
+				nand_release(mtd);
+			reg = readb(host->io_ctrl);
+			reg |= CPCI6200_NAND_FLASH_WP;
+			writeb(reg, host->io_ctrl);
+			iounmap(host->io_data);
+			iounmap(host->io_status);
+			iounmap(host->io_select);
+			iounmap(host->io_ctrl);
+
+			kfree(host);
+		}
+	}
+	return;
+}
+
+module_exit(cpci6200_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ajit Prem (ajit.prem@emerson.com");
+MODULE_DESCRIPTION("NAND driver for the nand chips on the CPCI6200");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/nand/Kconfig linux-2.6.29.6.mod/drivers/mtd/nand/Kconfig
--- linux-2.6.29.6.orig/drivers/mtd/nand/Kconfig	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/nand/Kconfig	2009-07-21 11:28:18.000000000 -0700
@@ -50,6 +50,27 @@
 	  This enables the driver for the Cirrus Logic EBD7312 evaluation
 	  board to access the onboard NAND Flash.
 
+config MTD_NAND_MVME7100
+        tristate "Support for the MVME7100 board"
+        depends on MTD_NAND && MVME7100
+        help
+          This enables the driver for the onboard NAND flash on
+          the Emerson Network Power MVME7100 board.
+
+config MTD_NAND_MVME4100
+        tristate "Support for the MVME4100 board"
+        depends on MTD_NAND && MVME4100
+        help
+          This enables the driver for the onboard NAND flash on
+          the Emerson Network Power MVME4100 board.
+
+config MTD_NAND_CPCI6200
+        tristate "Support for the CPCI6200 board"
+        depends on MTD_NAND && CPCI6200
+        help
+          This enables the driver for the onboard NAND flash on
+          the Emerson Network Power CPCI6200 board.
+
 config MTD_NAND_H1900
 	tristate "iPAQ H1900 flash"
 	depends on ARCH_PXA && MTD_PARTITIONS
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/nand/Makefile linux-2.6.29.6.mod/drivers/mtd/nand/Makefile
--- linux-2.6.29.6.orig/drivers/mtd/nand/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/nand/Makefile	2009-07-21 11:28:18.000000000 -0700
@@ -10,6 +10,9 @@
 obj-$(CONFIG_MTD_NAND_AMS_DELTA)	+= ams-delta.o
 obj-$(CONFIG_MTD_NAND_AUTCPU12)		+= autcpu12.o
 obj-$(CONFIG_MTD_NAND_EDB7312)		+= edb7312.o
+obj-$(CONFIG_MTD_NAND_MVME7100)         += mvme7100_nand.o
+obj-$(CONFIG_MTD_NAND_MVME4100)         += mvme4100_nand.o
+obj-$(CONFIG_MTD_NAND_CPCI6200)         += cpci6200_nand.o
 obj-$(CONFIG_MTD_NAND_AU1550)		+= au1550nd.o
 obj-$(CONFIG_MTD_NAND_BF5XX)		+= bf5xx_nand.o
 obj-$(CONFIG_MTD_NAND_PPCHAMELEONEVB)	+= ppchameleonevb.o
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/nand/mvme4100_nand.c linux-2.6.29.6.mod/drivers/mtd/nand/mvme4100_nand.c
--- linux-2.6.29.6.orig/drivers/mtd/nand/mvme4100_nand.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/nand/mvme4100_nand.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,423 @@
+/*
+ * drivers/mtd/nand/mvme4100_nand.c
+ *
+ * A glue driver for the NAND chips on the MVME4100 board
+ *
+ * Author: Ajit Prem (ajit.prem@emerson.com)
+ * Copyright 2008 Emerson Network Power Embedded Computing 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <platforms/85xx/mvme4100.h>
+
+static int n_physical_chips;
+
+struct mvme4100_nand_host {
+	struct nand_chip nand_chip;
+	struct mtd_info mtd;
+	void __iomem *io_ctrl;
+	void __iomem *io_select;
+	void __iomem *io_status;
+	void __iomem *io_data;
+	int chip;
+	int chip_enable;
+};
+
+static struct mvme4100_nand_host *chips[2];
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+
+/*
+ * Define static partitions for flash device
+ */
+static struct mtd_partition partition_info_4G[] = {
+	{
+	 .name = "Linux YAFFS 1",
+	 .offset = 0x00000000,
+	 .size   = 0x80000000,
+	}, 
+	{
+	 .name = "Linux YAFFS 2",
+	 .offset = 0x80000000,
+	 .size   = 0x80000000,
+	},
+};
+
+static struct mtd_partition partition_info_8G[] = {
+        {
+         .name = "Linux YAFFS 1",
+         .offset = 0x00000000,
+         .size   = 0x80000000,
+        },
+        {
+         .name = "Linux YAFFS 2",
+         .offset = 0x80000000,
+         .size   = 0x80000000,
+        },
+        {
+         .name = "Linux YAFFS 3",
+         .offset = 0x100000000LL,
+         .size   = 0x80000000,
+        },
+        {
+         .name = "Linux YAFFS 4",
+         .offset = 0x180000000LL,
+         .size   = 0x80000000,
+        },
+};
+
+#endif
+
+/*
+ *      hardware specific access to control-lines
+ *
+ *      ctrl:
+ *      NAND_NCE: bit 0 -> bits 4->7 (0xf0) in SELECT Reg
+ *      NAND_CLE: bit 1 -> bit 7 (0x80) in CONTROL Reg
+ *      NAND_ALE: bit 2 -> bit 6 (0x40) in CONTROL Reg
+ */
+
+static void mvme4100_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct mvme4100_nand_host *host = nand_chip->priv;
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		unsigned char bits;
+
+		bits = readb(host->io_ctrl);
+		bits &= 0x3f;
+		bits = (ctrl & NAND_CLE) << 6;
+		bits |= (ctrl & NAND_ALE) << 4;
+		writeb(bits, host->io_ctrl);
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, host->io_data);
+}
+
+static void mvme4100_select_chip(struct mtd_info *mtd, int chip)
+{
+        struct nand_chip *nand_chip = mtd->priv;
+        struct mvme4100_nand_host *host = nand_chip->priv;
+        unsigned char sel;
+
+	if (chip > 3)
+		return;
+
+        sel = readb(host->io_select);
+        sel &= ~(MVME4100_NAND_FLASH_CE1 | MVME4100_NAND_FLASH_CE2 |
+                 MVME4100_NAND_FLASH_CE3 | MVME4100_NAND_FLASH_CE4);
+
+        switch (chip) {
+        case 0:
+                sel |= MVME4100_NAND_FLASH_CE1;
+                break;
+        case 1:
+                sel |= MVME4100_NAND_FLASH_CE2;
+                break;
+        case 2:
+                sel |= MVME4100_NAND_FLASH_CE3;
+                break;
+        case 3:
+                sel |= MVME4100_NAND_FLASH_CE4;
+                break;
+        default:
+                break;
+        }
+	host->chip_enable = chip;
+        writeb(sel, host->io_select);
+}
+
+static int mvme4100_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct mvme4100_nand_host *host = nand_chip->priv;
+	u8 io_status;
+	int status;
+
+	io_status = readb(host->io_status);
+
+	switch (host->chip_enable) {
+	case 0:
+		status = io_status & MVME4100_NAND_FLASH_RB1;
+		break;
+	case 1:
+		status = io_status & MVME4100_NAND_FLASH_RB2;
+		break;
+	case 2:
+		status = io_status & MVME4100_NAND_FLASH_RB3;
+		break;
+	case 3:
+		status = io_status & MVME4100_NAND_FLASH_RB4;
+		break;
+	default:
+		status = 1;
+		break;
+        }
+	return status;
+}
+
+static int __init mvme4100_init_one(int chip)
+{
+	struct mvme4100_nand_host *host;
+	struct mtd_info *mtd;
+	struct nand_chip *nand_chip;
+	unsigned char reg;
+	int err = 0;
+#ifdef CONFIG_MTD_PARTITIONS
+	const char *part_type = 0;
+	int mtd_parts_nb = 0;
+	struct mtd_partition *mtd_parts = 0;
+#endif
+
+	/* Allocate memory for MTD device structure and private data */
+	host = kzalloc(sizeof(struct mvme4100_nand_host), GFP_KERNEL);
+	if (!host) {
+		printk(KERN_WARNING
+		       "mvme4100_nand: Unable to allocate device structure.\n");
+		return -ENOMEM;
+	}
+
+	if (chip == 1) {
+		host->io_ctrl = ioremap(MVME4100_NAND_FLASH1_CONTROL_REG, 1);
+		if (!host->io_ctrl) {
+			printk(KERN_ERR "mvme4100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_dhost;
+		}
+		host->io_select = ioremap(MVME4100_NAND_FLASH1_SELECT_REG, 1);
+		if (!host->io_select) {
+			printk(KERN_ERR "mvme4100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d1;
+		}
+		host->io_status = ioremap(MVME4100_NAND_FLASH1_STATUS_REG, 1);
+		if (!host->io_status) {
+			printk(KERN_ERR "mvme4100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d2;
+		}
+		host->io_data = ioremap(MVME4100_NAND_FLASH1_DATA_REG, 1);
+		if (!host->io_data) {
+			printk(KERN_ERR "mvme4100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d3;
+		}
+		chips[0] = host;
+	} else if (chip == 2) {
+		host->io_ctrl = ioremap(MVME4100_NAND_FLASH2_CONTROL_REG, 1);
+		if (!host->io_ctrl) {
+			printk(KERN_ERR "mvme4100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_dhost;
+		}
+		host->io_select = ioremap(MVME4100_NAND_FLASH2_SELECT_REG, 1);
+		if (!host->io_select) {
+			printk(KERN_ERR "mvme4100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d1;
+		}
+		host->io_status = ioremap(MVME4100_NAND_FLASH2_STATUS_REG, 1);
+		if (!host->io_status) {
+			printk(KERN_ERR "mvme4100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d2;
+		}
+		host->io_data = ioremap(MVME4100_NAND_FLASH2_DATA_REG, 1);
+		if (!host->io_data) {
+			printk(KERN_ERR "mvme4100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d3;
+		}
+		chips[1] = host;
+	} else {
+		err = -EINVAL;
+		goto init_dhost;
+	}
+
+	host->chip = chip;
+	reg = readb(host->io_ctrl);
+	reg &= ~MVME4100_NAND_FLASH_WP;
+	writeb(reg, host->io_ctrl);
+	mtd = &host->mtd;
+	nand_chip = &host->nand_chip;
+
+	/* Link the private data with the MTD structure */
+	nand_chip->priv = host;
+	mtd->priv = nand_chip;
+	mtd->owner = THIS_MODULE;
+
+	/* Set address of NAND IO lines */
+	nand_chip->IO_ADDR_R = host->io_data;
+	nand_chip->IO_ADDR_W = host->io_data;
+
+	nand_chip->cmd_ctrl = mvme4100_hwcontrol;
+	nand_chip->select_chip = mvme4100_select_chip;
+	nand_chip->dev_ready = mvme4100_device_ready;
+	/* We'll let YAFFS do ECC*/
+	nand_chip->ecc.mode = NAND_ECC_NONE;
+	nand_chip->chip_delay = 20;
+
+	/* Enable for a flash based bad block table */
+	nand_chip->options = NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR;
+
+	/* Scan to find existence of the device */
+	if (nand_scan(mtd, 4)) {
+		err = -ENXIO;
+		goto init_d4;
+	}
+
+#ifdef CONFIG_MTD_PARTITIONS
+	if (chip == 1)
+		mtd->name = "MVME4100 NAND Chip 1";
+	else if (chip == 2)
+		mtd->name = "MVME4100 NAND Chip 2";
+	/* First look for partitions on the command line, these take
+	 * take precedence over statically defined partitions */
+	mtd_parts_nb = parse_mtd_partitions(mtd, part_probes, &mtd_parts, 0);
+	if (mtd_parts_nb > 0)
+		part_type = "command line";
+	else
+		mtd_parts_nb = 0;
+
+	if (mtd_parts_nb == 0) {
+		part_type = "static";
+                if (mtd->size == 0x100000000LL) {
+                        mtd_parts = partition_info_4G;
+                        mtd_parts_nb = 2;
+                } else if (mtd->size == 0x200000000LL) {
+                        mtd_parts = partition_info_8G;
+                        mtd_parts_nb = 4;
+                } else {
+                        printk(KERN_INFO "mvme4100_nand: Unexpected Flash Size\n");
+                        err = -ENXIO;
+                        goto init_d4;
+                }
+	}
+
+	/* Register the partitions */
+	printk(KERN_INFO "Using %s partition definition\n", part_type);
+        switch (mtd->size) {
+        case 0x100000000LL:
+                add_mtd_partitions(mtd, mtd_parts, mtd_parts_nb);
+                break;
+        case 0x200000000LL:
+                add_mtd_partitions(mtd, mtd_parts, mtd_parts_nb);
+                break;
+        }
+#else
+	add_mtd_device(mtd);
+#endif
+
+	goto init_ret;
+
+init_d4:
+        /* Set WP */
+        reg = readb(host->io_ctrl);
+        reg |= MVME4100_NAND_FLASH_WP;
+        writeb(reg, host->io_ctrl);
+	iounmap(host->io_data);
+init_d3:
+	iounmap(host->io_status);
+init_d2:
+	iounmap(host->io_select);
+init_d1:
+	iounmap(host->io_ctrl);
+init_dhost:
+	kfree(host);
+init_ret:
+	return err;
+}
+
+static int __init mvme4100_init(void)
+{
+	int err = -ENXIO;
+	void __iomem *preg;
+
+	preg = ioremap(MVME4100_NAND_FLASH1_PRESENCE_REG, 1);
+	if (!preg) {
+		printk(KERN_WARNING "mvme4100_nand: ioremap failed\n");
+
+		return -ENOMEM;
+	}
+	if (readb(preg) & MVME4100_NAND_FLASH_CP) {
+		err = mvme4100_init_one(1);
+		if (err) {
+			iounmap(preg);
+			return err;
+		}
+		n_physical_chips++;
+	}
+	iounmap(preg);
+
+	preg = ioremap(MVME4100_NAND_FLASH2_PRESENCE_REG, 1);
+	if (!preg) {
+		printk(KERN_WARNING "mvme4100_nand: ioremap failed\n");
+
+		return -ENOMEM;
+	}
+	if (readb(preg) & MVME4100_NAND_FLASH_CP) {
+		err = mvme4100_init_one(2);
+		if (err) {
+			iounmap(preg);
+			return err;
+		}
+		n_physical_chips++;
+	}
+	iounmap(preg);
+
+	return err;
+}
+
+module_init(mvme4100_init);
+
+static void __exit mvme4100_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < n_physical_chips; i++) {
+		struct mvme4100_nand_host *host = chips[i];
+		struct mtd_info *mtd;
+		unsigned char reg;
+
+		if (host) {
+			mtd = &host->mtd;
+
+			if (mtd)
+				nand_release(mtd);
+			reg = readb(host->io_ctrl);
+			reg |= MVME4100_NAND_FLASH_WP;
+			writeb(reg, host->io_ctrl);
+			iounmap(host->io_data);
+			iounmap(host->io_status);
+			iounmap(host->io_select);
+			iounmap(host->io_ctrl);
+
+			kfree(host);
+		}
+	}
+	return;
+}
+
+module_exit(mvme4100_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ajit Prem (ajit.prem@emerson.com");
+MODULE_DESCRIPTION("NAND driver for the nand chips on the MVME4100");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/nand/mvme7100_nand.c linux-2.6.29.6.mod/drivers/mtd/nand/mvme7100_nand.c
--- linux-2.6.29.6.orig/drivers/mtd/nand/mvme7100_nand.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/nand/mvme7100_nand.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,420 @@
+/*
+ * drivers/mtd/nand/mvme7100_nand.c
+ *
+ * A glue driver for the NAND chips on the MVME7100 board
+ *
+ * Author: Ajit Prem (ajit.prem@emerson.com)
+ * Copyright 2008 Emerson Network Power Embedded Computing 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.
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/io.h>
+#include <platforms/86xx/mvme7100.h>
+
+static int n_physical_chips;
+
+struct mvme7100_nand_host {
+	struct nand_chip nand_chip;
+	struct mtd_info mtd;
+	void __iomem *io_ctrl;
+	void __iomem *io_select;
+	void __iomem *io_status;
+	void __iomem *io_data;
+	int chip;
+	int chip_enable;
+};
+
+static struct mvme7100_nand_host *chips[2];
+
+#ifdef CONFIG_MTD_PARTITIONS
+static const char *part_probes[] = { "cmdlinepart", NULL };
+
+/*
+ * Define static partitions for flash device
+ */
+static struct mtd_partition partition_info_4G[] = {
+	{
+	 .name = "Linux YAFFS 1",
+	 .offset = 0x00000000,
+	 .size =   0x80000000,
+	}, 
+	{
+	 .name = "Linux YAFFS 2",
+	 .offset = 0x80000000,
+	 .size =   0x80000000,
+	},
+};
+
+static struct mtd_partition partition_info_8G[] = {
+	{
+	 .name = "Linux YAFFS 1",
+	 .offset = 0x00000000,
+	 .size   = 0x80000000,
+	}, 
+	{
+	 .name = "Linux YAFFS 2",
+	 .offset = 0x80000000,
+	 .size   = 0x80000000,
+	},
+	{
+	 .name = "Linux YAFFS 3",
+	 .offset = 0x100000000LL,
+	 .size   = 0x80000000,
+	},
+	{
+	 .name = "Linux YAFFS 4",
+	 .offset = 0x180000000LL,
+	 .size   = 0x80000000,
+	},
+};
+#endif
+
+/*
+ *      hardware specific access to control-lines
+ *
+ *      ctrl:
+ *      NAND_NCE: bit 0 -> bits 4->7 (0xf0) in SELECT Reg
+ *      NAND_CLE: bit 1 -> bit 7 (0x80) in CONTROL Reg
+ *      NAND_ALE: bit 2 -> bit 6 (0x40) in CONTROL Reg
+ */
+
+static void mvme7100_hwcontrol(struct mtd_info *mtd, int cmd, unsigned int ctrl)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct mvme7100_nand_host *host = nand_chip->priv;
+
+	if (ctrl & NAND_CTRL_CHANGE) {
+		unsigned char bits;
+
+		bits = readb(host->io_ctrl);
+		bits &= 0x3f;
+		bits = (ctrl & NAND_CLE) << 6;
+		bits |= (ctrl & NAND_ALE) << 4;
+		writeb(bits, host->io_ctrl);
+	}
+
+	if (cmd != NAND_CMD_NONE)
+		writeb(cmd, host->io_data);
+}
+
+static void mvme7100_select_chip(struct mtd_info *mtd, int chip)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct mvme7100_nand_host *host = nand_chip->priv;
+	unsigned char sel;
+
+	if (chip > 3)
+		return;
+
+	sel = readb(host->io_select);
+	sel &= ~(MVME7100_NAND_FLASH_CE1 | MVME7100_NAND_FLASH_CE2 |
+		 MVME7100_NAND_FLASH_CE3 | MVME7100_NAND_FLASH_CE4);
+
+	switch (chip) {
+	case 0:
+		sel |= MVME7100_NAND_FLASH_CE1; 
+		break;
+	case 1:
+		sel |= MVME7100_NAND_FLASH_CE2; 
+		break;
+	case 2:
+		sel |= MVME7100_NAND_FLASH_CE3; 
+		break;
+	case 3:
+		sel |= MVME7100_NAND_FLASH_CE4; 
+		break;
+	default:
+		break;
+	}
+	host->chip_enable = chip;
+	writeb(sel, host->io_select);
+}
+
+static int mvme7100_device_ready(struct mtd_info *mtd)
+{
+	struct nand_chip *nand_chip = mtd->priv;
+	struct mvme7100_nand_host *host = nand_chip->priv;
+	u8 io_status;
+	int status;
+
+	io_status = readb(host->io_status);
+
+        switch (host->chip_enable) {
+        case 0:
+                status = io_status & MVME7100_NAND_FLASH_RB1;
+                break;
+        case 1:
+                status = io_status & MVME7100_NAND_FLASH_RB2;
+                break;
+        case 2:
+                status = io_status & MVME7100_NAND_FLASH_RB3;
+                break;
+        case 3:
+                status = io_status & MVME7100_NAND_FLASH_RB4;
+                break;
+        default:
+                status = 1;
+                break;
+        }
+        return status;
+}
+
+static int __init mvme7100_init_one(int chip)
+{
+	struct mvme7100_nand_host *host;
+	struct mtd_info *mtd;
+	struct nand_chip *nand_chip;
+	unsigned char reg;
+	int err = 0;
+#ifdef CONFIG_MTD_PARTITIONS
+	const char *part_type = 0;
+	int mtd_parts_nb = 0;
+	struct mtd_partition *mtd_parts = 0;
+#endif
+
+	/* Allocate memory for MTD device structure and private data */
+	host = kzalloc(sizeof(struct mvme7100_nand_host), GFP_KERNEL);
+	if (!host) {
+		printk(KERN_WARNING
+		       "mvme7100_nand: Unable to allocate device structure.\n");
+		return -ENOMEM;
+	}
+
+	if (chip == 1) {
+		host->io_ctrl = ioremap(MVME7100_NAND_FLASH1_CONTROL_REG, 1);
+		if (!host->io_ctrl) {
+			printk(KERN_ERR "mvme7100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_dhost;
+		}
+		host->io_select = ioremap(MVME7100_NAND_FLASH1_SELECT_REG, 1);
+		if (!host->io_select) {
+			printk(KERN_ERR "mvme7100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d1;
+		}
+		host->io_status = ioremap(MVME7100_NAND_FLASH1_STATUS_REG, 1);
+		if (!host->io_status) {
+			printk(KERN_ERR "mvme7100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d2;
+		}
+		host->io_data = ioremap(MVME7100_NAND_FLASH1_DATA_REG, 1);
+		if (!host->io_data) {
+			printk(KERN_ERR "mvme7100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d3;
+		}
+		chips[0] = host;
+	} else if (chip == 2) {
+		host->io_ctrl = ioremap(MVME7100_NAND_FLASH2_CONTROL_REG, 1);
+		if (!host->io_ctrl) {
+			printk(KERN_ERR "mvme7100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_dhost;
+		}
+		host->io_select = ioremap(MVME7100_NAND_FLASH2_SELECT_REG, 1);
+		if (!host->io_select) {
+			printk(KERN_ERR "mvme7100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d1;
+		}
+		host->io_status = ioremap(MVME7100_NAND_FLASH2_STATUS_REG, 1);
+		if (!host->io_status) {
+			printk(KERN_ERR "mvme7100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d2;
+		}
+		host->io_data = ioremap(MVME7100_NAND_FLASH2_DATA_REG, 1);
+		if (!host->io_data) {
+			printk(KERN_ERR "mvme7100_nand: Unable to ioremap()");
+			err = -ENOMEM;
+			goto init_d3;
+		}
+		chips[1] = host;
+	} else {
+		err = -EINVAL;
+		goto init_dhost;
+	}
+
+	host->chip = chip;
+	reg = readb(host->io_ctrl);
+	reg &= ~MVME7100_NAND_FLASH_WP;
+	writeb(reg, host->io_ctrl);
+	mtd = &host->mtd;
+	nand_chip = &host->nand_chip;
+
+	/* Link the private data with the MTD structure */
+	nand_chip->priv = host;
+	mtd->priv = nand_chip;
+	mtd->owner = THIS_MODULE;
+
+	/* Set address of NAND IO lines */
+	nand_chip->IO_ADDR_R = host->io_data;
+	nand_chip->IO_ADDR_W = host->io_data;
+
+	nand_chip->cmd_ctrl = mvme7100_hwcontrol;
+	nand_chip->select_chip = mvme7100_select_chip;
+	nand_chip->dev_ready = mvme7100_device_ready;
+	/* We'll let YAFFS do ECC*/
+	nand_chip->ecc.mode = NAND_ECC_NONE;
+	nand_chip->chip_delay = 20;
+
+	nand_chip->options = NAND_SAMSUNG_LP_OPTIONS | NAND_NO_AUTOINCR;
+
+	/* Scan to find existence of the device */
+	if (nand_scan(mtd, 4)) {
+		err = -ENXIO;
+		goto init_d4;
+	}
+
+#ifdef CONFIG_MTD_PARTITIONS
+	if (chip == 1)
+		mtd->name = "MVME7100 NAND Chip 1";
+	else if (chip == 2)
+		mtd->name = "MVME7100 NAND Chip 2";
+	/* First look for partitions on the command line, these take
+	 * take precedence over statically defined partitions */
+	mtd_parts_nb = parse_mtd_partitions(mtd, part_probes, &mtd_parts, 0);
+	if (mtd_parts_nb > 0)
+		part_type = "command line";
+	else
+		mtd_parts_nb = 0;
+
+	if (mtd_parts_nb == 0) {
+		part_type = "static";
+		if (mtd->size == 0x100000000LL) {
+			mtd_parts = partition_info_4G;
+			mtd_parts_nb = 2;
+		} else if (mtd->size == 0x200000000LL) {
+			mtd_parts = partition_info_8G;
+			mtd_parts_nb = 4;
+		} else {
+			printk(KERN_INFO "mvme7100_nand: Unexpected Flash Size\n");
+			err = -ENXIO;
+			goto init_d4;
+		}
+	}
+
+	/* Register the partitions */
+	printk(KERN_INFO "Using %s partition definition\n", part_type);
+	switch (mtd->size) {
+	case 0x100000000LL:
+		add_mtd_partitions(mtd, mtd_parts, mtd_parts_nb);
+		break;
+	case 0x200000000LL:
+		add_mtd_partitions(mtd, mtd_parts, mtd_parts_nb);
+		break;
+	}
+#else
+	add_mtd_device(mtd);
+#endif
+	goto init_ret;
+
+init_d4:
+        /* Set WP */
+        reg = readb(host->io_ctrl);
+        reg |= MVME7100_NAND_FLASH_WP;
+        writeb(reg, host->io_ctrl);
+	iounmap(host->io_data);
+init_d3:
+	iounmap(host->io_status);
+init_d2:
+	iounmap(host->io_select);
+init_d1:
+	iounmap(host->io_ctrl);
+init_dhost:
+	kfree(host);
+init_ret:
+	return err;
+}
+
+static int __init mvme7100_init(void)
+{
+	int err = -ENXIO;
+	void __iomem *preg;
+
+	preg = ioremap(MVME7100_NAND_FLASH1_PRESENCE_REG, 1);
+	if (!preg) {
+		printk(KERN_WARNING "mvme7100_nand: ioremap failed\n");
+
+		return -ENOMEM;
+	}
+	if (readb(preg) & MVME7100_NAND_FLASH_CP) {
+		err = mvme7100_init_one(1);
+		if (err) {
+			iounmap(preg);
+			return err;
+		}
+		n_physical_chips++;
+	}
+	iounmap(preg);
+
+	preg = ioremap(MVME7100_NAND_FLASH2_PRESENCE_REG, 1);
+	if (!preg) {
+		printk(KERN_WARNING "mvme7100_nand: ioremap failed\n");
+
+		return -ENOMEM;
+	}
+	if (readb(preg) & MVME7100_NAND_FLASH_CP) {
+		err = mvme7100_init_one(2);
+		if (err) {
+			iounmap(preg);
+			return err;
+		}
+		n_physical_chips++;
+	}
+	iounmap(preg);
+
+	return err;
+}
+
+module_init(mvme7100_init);
+
+static void __exit mvme7100_cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < n_physical_chips; i++) {
+		struct mvme7100_nand_host *host = chips[i];
+		struct mtd_info *mtd;
+		unsigned char reg;
+
+		if (host) {
+			mtd = &host->mtd;
+
+			if (mtd)
+				nand_release(mtd);
+                        reg = readb(host->io_ctrl);
+                        reg |= MVME7100_NAND_FLASH_WP;
+                        writeb(reg, host->io_ctrl);
+			iounmap(host->io_data);
+			iounmap(host->io_status);
+			iounmap(host->io_select);
+			iounmap(host->io_ctrl);
+
+			kfree(host);
+		}
+	}
+	return;
+}
+
+module_exit(mvme7100_cleanup);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Ajit Prem (ajit.prem@emerson.com");
+MODULE_DESCRIPTION("NAND driver for the nand chips on the MVME7100");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/nand/nand_base.c linux-2.6.29.6.mod/drivers/mtd/nand/nand_base.c
--- linux-2.6.29.6.orig/drivers/mtd/nand/nand_base.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/nand/nand_base.c	2009-07-21 11:28:18.000000000 -0700
@@ -82,6 +82,20 @@
 		 .length = 38}}
 };
 
+static struct nand_ecclayout nand_oob_128 = {
+        .eccbytes = 48,
+        .eccpos = {
+		80,  81,  82,  83,  84,  85,  86,  87,
+		88,  89,  90,  91,  92,  93,  94,  95,
+		96,  97,  98,  99, 100, 101, 102, 103,
+		104, 105, 106, 107, 108, 109, 110, 111,
+		112, 113, 114, 115, 116, 117, 118, 119,
+		120, 121, 122, 123, 124, 125, 126, 127},
+        .oobfree = {
+                {.offset = 2,
+                 .length = 78}}
+};
+
 static int nand_get_device(struct nand_chip *chip, struct mtd_info *mtd,
 			   int new_state);
 
@@ -2555,6 +2569,10 @@
 		case 64:
 			chip->ecc.layout = &nand_oob_64;
 			break;
+                case 128:
+                        chip->ecc.layout = &nand_oob_128;
+                        break;
+
 		default:
 			printk(KERN_WARNING "No oob scheme defined for "
 			       "oobsize %d\n", mtd->oobsize);
@@ -2627,8 +2645,8 @@
 		break;
 
 	case NAND_ECC_NONE:
-		printk(KERN_WARNING "NAND_ECC_NONE selected by board driver. "
-		       "This is not recommended !!\n");
+		printk(KERN_DEBUG "NAND_ECC_NONE selected by board driver. "
+		       "This is not recommended unless done elsewhere (YAFFS perhaps?)!!\n");
 		chip->ecc.read_page = nand_read_page_raw;
 		chip->ecc.write_page = nand_write_page_raw;
 		chip->ecc.read_oob = nand_read_oob_std;
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/nand/nand_bbt.c linux-2.6.29.6.mod/drivers/mtd/nand/nand_bbt.c
--- linux-2.6.29.6.orig/drivers/mtd/nand/nand_bbt.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/nand/nand_bbt.c	2009-07-21 11:28:18.000000000 -0700
@@ -428,7 +428,7 @@
 
 		if (ret) {
 			this->bbt[i >> 3] |= 0x03 << (i & 0x6);
-			printk(KERN_WARNING "Bad eraseblock %d at 0x%012llx\n",
+			printk(KERN_DEBUG "Bad eraseblock %d at 0x%012llx\n",
 			       i >> 1, (unsigned long long)from);
 			mtd->ecc_stats.badblocks++;
 		}
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/mtd/nand/nand_ids.c linux-2.6.29.6.mod/drivers/mtd/nand/nand_ids.c
--- linux-2.6.29.6.orig/drivers/mtd/nand/nand_ids.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/mtd/nand/nand_ids.c	2009-07-21 11:28:18.000000000 -0700
@@ -30,7 +30,7 @@
 	{"NAND 1MiB 3,3V 8-bit",	0xe8, 256, 1, 0x1000, 0},
 	{"NAND 1MiB 3,3V 8-bit",	0xec, 256, 1, 0x1000, 0},
 	{"NAND 2MiB 3,3V 8-bit",	0xea, 256, 2, 0x1000, 0},
-	{"NAND 4MiB 3,3V 8-bit",	0xd5, 512, 4, 0x2000, 0},
+//	{"NAND 4MiB 3,3V 8-bit",	0xd5, 512, 4, 0x2000, 0},
 	{"NAND 4MiB 3,3V 8-bit",	0xe3, 512, 4, 0x2000, 0},
 	{"NAND 4MiB 3,3V 8-bit",	0xe5, 512, 4, 0x2000, 0},
 	{"NAND 8MiB 3,3V 8-bit",	0xd6, 512, 8, 0x2000, 0},
@@ -106,6 +106,7 @@
 	/* 16 Gigabit */
 	{"NAND 2GiB 1,8V 8-bit",	0xA5, 0, 2048, 0, LP_OPTIONS},
 	{"NAND 2GiB 3,3V 8-bit",	0xD5, 0, 2048, 0, LP_OPTIONS},
+	{"NAND 4GiB 3,3V 8-bit",	0xD7, 0, 2048, 0, LP_OPTIONS},
 	{"NAND 2GiB 1,8V 16-bit",	0xB5, 0, 2048, 0, LP_OPTIONS16},
 	{"NAND 2GiB 3,3V 16-bit",	0xC5, 0, 2048, 0, LP_OPTIONS16},
 
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/net/phy/phy.c linux-2.6.29.6.mod/drivers/net/phy/phy.c
--- linux-2.6.29.6.orig/drivers/net/phy/phy.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/net/phy/phy.c	2009-07-21 11:28:18.000000000 -0700
@@ -600,7 +600,7 @@
 	atomic_set(&phydev->irq_disable, 0);
 	if (request_irq(phydev->irq, phy_interrupt,
 				IRQF_SHARED,
-				"phy_interrupt",
+				"phy",
 				phydev) < 0) {
 		printk(KERN_WARNING "%s: Can't get IRQ %d (PHY)\n",
 				phydev->bus->name,
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/of/of_i2c.c linux-2.6.29.6.mod/drivers/of/of_i2c.c
--- linux-2.6.29.6.orig/drivers/of/of_i2c.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/of/of_i2c.c	2009-07-21 11:28:18.000000000 -0700
@@ -71,6 +71,7 @@
         return dev_archdata_get_node(&dev->archdata) == data;
 }
 
+#if 0
 /* must call put_device() when done with returned i2c_client device */
 struct i2c_client *of_find_i2c_device_by_node(struct device_node *node)
 {
@@ -84,5 +85,6 @@
 	return to_i2c_client(dev);
 }
 EXPORT_SYMBOL(of_find_i2c_device_by_node);
+#endif
 
 MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/pci/pci.c linux-2.6.29.6.mod/drivers/pci/pci.c
--- linux-2.6.29.6.orig/drivers/pci/pci.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/pci/pci.c	2009-07-21 11:28:18.000000000 -0700
@@ -1096,7 +1096,7 @@
 
 	pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
 
-	dev_printk(KERN_INFO, &dev->dev, "PME# %s\n",
+	dev_printk(KERN_DEBUG, &dev->dev, "PME# %s\n",
 			enable ? "enabled" : "disabled");
 }
 
@@ -1296,12 +1296,12 @@
 
 	pmc &= PCI_PM_CAP_PME_MASK;
 	if (pmc) {
-		dev_info(&dev->dev, "PME# supported from%s%s%s%s%s\n",
-			 (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
-			 (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
-			 (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
-			 (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "",
-			 (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
+//		dev_info(&dev->dev, "PME# supported from%s%s%s%s%s\n",
+//			 (pmc & PCI_PM_CAP_PME_D0) ? " D0" : "",
+//			 (pmc & PCI_PM_CAP_PME_D1) ? " D1" : "",
+//			 (pmc & PCI_PM_CAP_PME_D2) ? " D2" : "",
+//			 (pmc & PCI_PM_CAP_PME_D3) ? " D3hot" : "",
+//			 (pmc & PCI_PM_CAP_PME_D3cold) ? " D3cold" : "");
 		dev->pme_support = pmc >> PCI_PM_CAP_PME_SHIFT;
 		/*
 		 * Make device's PM flags reflect the wake-up capability, but
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/pci/pcie/aer/aerdrv.c linux-2.6.29.6.mod/drivers/pci/pcie/aer/aerdrv.c
--- linux-2.6.29.6.orig/drivers/pci/pcie/aer/aerdrv.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/pci/pcie/aer/aerdrv.c	2009-07-21 11:28:18.000000000 -0700
@@ -220,7 +220,7 @@
 
 	/* Alloc rpc data structure */
 	if (!(rpc = aer_alloc_rpc(dev))) {
-		dev_printk(KERN_DEBUG, device, "alloc rpc failed\n");
+		dev_printk(KERN_ERR, device, "alloc rpc failed\n");
 		aer_remove(dev);
 		return -ENOMEM;
 	}
@@ -228,7 +228,7 @@
 	/* Request IRQ ISR */
 	if ((status = request_irq(dev->irq, aer_irq, IRQF_SHARED, "aerdrv",
 				dev))) {
-		dev_printk(KERN_DEBUG, device, "request IRQ failed\n");
+		dev_printk(KERN_ERR, device, "request IRQ %d failed\n", dev->irq);
 		aer_remove(dev);
 		return status;
 	}
@@ -272,7 +272,7 @@
 	 * to issue Configuration Requests to those devices.
 	 */
 	msleep(200);
-	dev_printk(KERN_DEBUG, &dev->dev, "Root Port link has been reset\n");
+	dev_printk(KERN_ERR, &dev->dev, "Root Port link has been reset\n");
 
 	/* Enable Root Port's interrupt in response to error messages */
 	pci_read_config_dword(dev, pos + PCI_ERR_ROOT_STATUS, &status);
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/pci/pcie/aer/aerdrv_core.c linux-2.6.29.6.mod/drivers/pci/pcie/aer/aerdrv_core.c
--- linux-2.6.29.6.orig/drivers/pci/pcie/aer/aerdrv_core.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/pci/pcie/aer/aerdrv_core.c	2009-07-21 11:28:18.000000000 -0700
@@ -91,7 +91,6 @@
 	return 0;
 }
 
-#if 0
 int pci_cleanup_aer_correct_error_status(struct pci_dev *dev)
 {
 	int pos;
@@ -106,7 +105,6 @@
 
 	return 0;
 }
-#endif  /*  0  */
 
 
 static void set_device_error_reporting(struct pci_dev *dev, void *data)
@@ -226,7 +224,7 @@
 			 * of a driver for this device is unaware of
 			 * its hw state.
 			 */
-			dev_printk(KERN_DEBUG, &dev->dev, "device has %s\n",
+			dev_printk(KERN_INFO, &dev->dev, "device has %s\n",
 				   dev->driver ?
 				   "no AER-aware driver" : "no driver");
 		}
@@ -309,7 +307,7 @@
 {
 	struct aer_broadcast_data result_data;
 
-	dev_printk(KERN_DEBUG, &dev->dev, "broadcast %s message\n", error_mesg);
+	dev_printk(KERN_INFO, &dev->dev, "broadcast %s message\n", error_mesg);
 	result_data.state = state;
 	if (cb == report_error_detected)
 		result_data.result = PCI_ERS_RESULT_CAN_RECOVER;
@@ -409,7 +407,7 @@
 			data.aer_driver =
 				to_service_driver(aerdev->device.driver);
 		} else {
-			dev_printk(KERN_DEBUG, &dev->dev, "no link-reset "
+			dev_printk(KERN_INFO, &dev->dev, "no link-reset "
 				   "support\n");
 			return PCI_ERS_RESULT_DISCONNECT;
 		}
@@ -417,7 +415,7 @@
 
 	status = data.aer_driver->reset_link(udev);
 	if (status != PCI_ERS_RESULT_RECOVERED) {
-		dev_printk(KERN_DEBUG, &dev->dev, "link reset at upstream "
+		dev_printk(KERN_INFO, &dev->dev, "link reset at upstream "
 			   "device %s failed\n", pci_name(udev));
 		return PCI_ERS_RESULT_DISCONNECT;
 	}
@@ -514,11 +512,11 @@
 	} else {
 		status = do_recovery(aerdev, dev, info.severity);
 		if (status == PCI_ERS_RESULT_RECOVERED) {
-			dev_printk(KERN_DEBUG, &dev->dev, "AER driver "
+			dev_printk(KERN_INFO, &dev->dev, "AER driver "
 				   "successfully recovered\n");
 		} else {
 			/* TODO: Should kernel panic here? */
-			dev_printk(KERN_DEBUG, &dev->dev, "AER driver didn't "
+			dev_printk(KERN_ERR, &dev->dev, "AER driver didn't "
 				   "recover\n");
 		}
 	}
@@ -697,7 +695,7 @@
 			 PCI_ERR_ROOT_MULTI_UNCOR_RCV))
 			e_info.flags |= AER_MULTI_ERROR_VALID_FLAG;
 		if (!(s_device = find_source_device(p_device->port, id))) {
-			printk(KERN_DEBUG "%s->can't find device of ID%04x\n",
+			printk(KERN_INFO "%s->can't find device of ID%04x\n",
 				__func__, id);
 			continue;
 		}
@@ -765,4 +763,4 @@
 EXPORT_SYMBOL_GPL(pci_enable_pcie_error_reporting);
 EXPORT_SYMBOL_GPL(pci_disable_pcie_error_reporting);
 EXPORT_SYMBOL_GPL(pci_cleanup_aer_uncorrect_error_status);
-
+EXPORT_SYMBOL_GPL(pci_cleanup_aer_correct_error_status);
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/pci/pcie/portdrv_core.c linux-2.6.29.6.mod/drivers/pci/pcie/portdrv_core.c
--- linux-2.6.29.6.orig/drivers/pci/pcie/portdrv_core.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/pci/pcie/portdrv_core.c	2009-07-21 11:28:18.000000000 -0700
@@ -215,7 +215,7 @@
 	pci_read_config_word(dev, pos + PCIE_CAPABILITIES_REG, &reg);
 	type = (reg >> 4) & PORT_TYPE_MASK;
 	if (	type == PCIE_RC_PORT || type == PCIE_SW_UPSTREAM_PORT ||
-		type == PCIE_SW_DOWNSTREAM_PORT )
+		type == PCIE_SW_DOWNSTREAM_PORT || type == PCIE_ANY_PORT )
 		return 0;
 
 	return -ENODEV;
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/pci/pcie/portdrv_pci.c linux-2.6.29.6.mod/drivers/pci/pcie/portdrv_pci.c
--- linux-2.6.29.6.orig/drivers/pci/pcie/portdrv_pci.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/pci/pcie/portdrv_pci.c	2009-07-21 11:28:18.000000000 -0700
@@ -32,6 +32,8 @@
 /* global data */
 static const char device_name[] = "pcieport-driver";
 
+extern int pci_cleanup_aer_correct_error_status(struct pci_dev *dev);
+
 static int pcie_portdrv_save_config(struct pci_dev *dev)
 {
 	return pci_save_state(dev);
@@ -97,6 +99,13 @@
 
 	pcie_portdrv_save_config(dev);
 
+	dev->error_state = pci_channel_io_normal;
+	pci_cleanup_aer_uncorrect_error_status(dev);
+	pci_cleanup_aer_correct_error_status(dev);
+	pci_enable_pcie_error_reporting(dev);
+	pci_cleanup_aer_uncorrect_error_status(dev);
+	pci_cleanup_aer_correct_error_status(dev);
+
 	return 0;
 }
 
@@ -257,10 +266,13 @@
 /*
  * LINUX Device Driver Model
  */
-static const struct pci_device_id port_pci_ids[] = { {
+static const struct pci_device_id port_pci_ids[] = { 
 	/* handle any PCI-Express port */
-	PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0),
-	}, { /* end: all zeroes */ }
+	{ PCI_DEVICE(0x1957, 0x7011),},
+	{ PCI_DEVICE(0x1957, 0x0041),},
+	{ PCI_DEVICE(0x1957, 0x0040),},
+	{ PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0), },
+	{ /* end: all zeroes */ }
 };
 MODULE_DEVICE_TABLE(pci, port_pci_ids);
 
@@ -273,7 +285,7 @@
 
 static struct pci_driver pcie_portdriver = {
 	.name		= (char *)device_name,
-	.id_table	= &port_pci_ids[0],
+	.id_table	= port_pci_ids,
 
 	.probe		= pcie_portdrv_probe,
 	.remove		= pcie_portdrv_remove,
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/rtc/Kconfig linux-2.6.29.6.mod/drivers/rtc/Kconfig
--- linux-2.6.29.6.orig/drivers/rtc/Kconfig	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/rtc/Kconfig	2009-07-21 11:28:18.000000000 -0700
@@ -156,6 +156,17 @@
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-ds1374.
 
+config RTC_DRV_DS1375
+	tristate "Dallas/Maxim DS1375"
+	depends on RTC_CLASS && I2C
+	help
+	  If you say yes here you get support for Dallas Semiconductor
+	  DS1375 real-time clock chips.  If an interrupt is associated
+	  with the device, the alarm functionality is supported.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called rtc-ds1375.
+
 config RTC_DRV_DS1672
 	tristate "Dallas/Maxim DS1672"
 	help
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/rtc/Makefile linux-2.6.29.6.mod/drivers/rtc/Makefile
--- linux-2.6.29.6.orig/drivers/rtc/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/rtc/Makefile	2009-07-21 11:28:18.000000000 -0700
@@ -30,6 +30,7 @@
 obj-$(CONFIG_RTC_DRV_DS1305)	+= rtc-ds1305.o
 obj-$(CONFIG_RTC_DRV_DS1307)	+= rtc-ds1307.o
 obj-$(CONFIG_RTC_DRV_DS1374)	+= rtc-ds1374.o
+obj-$(CONFIG_RTC_DRV_DS1375)	+= rtc-ds1375.o
 obj-$(CONFIG_RTC_DRV_DS1390)	+= rtc-ds1390.o
 obj-$(CONFIG_RTC_DRV_DS1511)	+= rtc-ds1511.o
 obj-$(CONFIG_RTC_DRV_DS1553)	+= rtc-ds1553.o
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/rtc/rtc-ds1375.c linux-2.6.29.6.mod/drivers/rtc/rtc-ds1375.c
--- linux-2.6.29.6.orig/drivers/rtc/rtc-ds1375.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/rtc/rtc-ds1375.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,276 @@
+/*
+ * drivers/rtc/ds1375.c
+ *
+ * RTC driver for the Maxim/Dallas DS1375 Real-Time Clock
+ *
+ * Author: Ajit Prem <ajit.prem@emerson.com>
+ *
+ * Based on various RTC drivers 
+ *
+ * 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.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#include <asm/time.h>
+
+#define DS1375_SECONDS_REGISTER       0x00
+#define DS1375_MINUTES_REGISTER       0x01
+#define DS1375_HOURS_REGISTER         0x02
+#define DS1375_DAY_REGISTER           0x03
+#define DS1375_DATE_REGISTER          0x04
+#define DS1375_MONTH_REGISTER         0x05
+#define DS1375_YEAR_REGISTER          0x06
+#define DS1375_CENTURY_REGISTER       0x05
+#define DS1375_CONTROL_REGISTER       0x0E
+#define DS1375_STATUS_REGISTER        0x0F
+
+#define DS1375_12HOUR_MODE_FLAG       0x40
+#define DS1375_PM_HOUR_FLAG           0x20
+#define DS1375_BIT_CENTURY            0x80
+
+#define DS1375_CLOCK_ENABLE		0x80
+
+#define	DS1375_DRV_NAME		"ds1375"
+
+
+static struct i2c_driver ds1375_driver;
+
+static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD_1(ds1375);
+
+struct ds1375_data {
+	u8	reg_addr;
+	u8	regs[8];
+	struct i2c_msg	  msg[2];
+	struct i2c_client client;
+	struct rtc_device *rtc;
+};
+
+int ds1375_get_rtc_time(struct device *dev, struct rtc_time *t)
+{
+        struct ds1375_data   *ds1375 = dev_get_drvdata(dev);
+        int             tmp;
+
+        /* read the RTC registers all at once */
+        ds1375->msg[1].flags = I2C_M_RD;
+        ds1375->msg[1].len = 7;
+
+        tmp = i2c_transfer(ds1375->client.adapter, ds1375->msg, 2);
+        if (tmp != 2) {
+                dev_err(dev, "%s error %d\n", "read", tmp);
+                return -EIO;
+        }
+
+        dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+                        "read",
+                        ds1375->regs[0], ds1375->regs[1],
+                        ds1375->regs[2], ds1375->regs[3],
+                        ds1375->regs[4], ds1375->regs[5],
+                        ds1375->regs[6]);
+
+        t->tm_sec = bcd2bin(ds1375->regs[DS1375_SECONDS_REGISTER] & 0x7f);
+        t->tm_min = bcd2bin(ds1375->regs[DS1375_MINUTES_REGISTER] & 0x7f);
+        tmp = ds1375->regs[DS1375_HOURS_REGISTER] & 0x3f;
+        t->tm_hour = bcd2bin(tmp);
+        t->tm_wday = bcd2bin(ds1375->regs[DS1375_DAY_REGISTER] & 0x07) - 1;
+        t->tm_mday = bcd2bin(ds1375->regs[DS1375_DATE_REGISTER] & 0x3f);
+        tmp = ds1375->regs[DS1375_MONTH_REGISTER] & 0x1f;
+        t->tm_mon = bcd2bin(tmp) - 1;
+
+        /* assume 20YY not 19YY, and ignore DS1375_BIT_CENTURY */
+        t->tm_year = bcd2bin(ds1375->regs[DS1375_YEAR_REGISTER]) + 100;
+
+        dev_dbg(dev, "%s secs=%d, mins=%d, "
+                "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+                "read", t->tm_sec, t->tm_min,
+                t->tm_hour, t->tm_mday,
+                t->tm_mon, t->tm_year, t->tm_wday);
+
+        return 0;
+}
+
+int ds1375_set_rtc_time(struct device *dev, struct rtc_time *t)
+{
+        struct ds1375_data   *ds1375 = dev_get_drvdata(dev);
+        int             result;
+        int             tmp;
+        u8              *buf = ds1375->regs;
+
+        dev_dbg(dev, "%s secs=%d, mins=%d, "
+                "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
+                "write", t->tm_sec, t->tm_min,
+                t->tm_hour, t->tm_mday,
+                t->tm_mon, t->tm_year, t->tm_wday);
+
+        *buf++ = 0;             /* first register addr */
+        buf[DS1375_SECONDS_REGISTER] = bin2bcd(t->tm_sec);
+        buf[DS1375_MINUTES_REGISTER] = bin2bcd(t->tm_min);
+        buf[DS1375_HOURS_REGISTER] = bin2bcd(t->tm_hour);
+        buf[DS1375_DAY_REGISTER] = bin2bcd(t->tm_wday + 1);
+        buf[DS1375_DATE_REGISTER] = bin2bcd(t->tm_mday);
+        buf[DS1375_MONTH_REGISTER] = bin2bcd(t->tm_mon + 1);
+
+        /* assume 20YY not 19YY */
+        tmp = t->tm_year - 100;
+        buf[DS1375_YEAR_REGISTER] = bin2bcd(tmp);
+
+        buf[DS1375_MONTH_REGISTER] |= DS1375_BIT_CENTURY;
+
+        ds1375->msg[1].flags = 0;
+        ds1375->msg[1].len = 8;
+
+        dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
+                "write", buf[0], buf[1], buf[2], buf[3],
+                buf[4], buf[5], buf[6]);
+
+        result = i2c_transfer(ds1375->client.adapter, &ds1375->msg[1], 1);
+
+        if (result != 1) {
+                dev_err(dev, "%s error %d\n", "write", tmp);
+                return -EIO;
+        }
+        return 0;
+}
+
+static void ds1375_init_client(struct i2c_client *client)
+{
+	s32 val;
+
+	/* Enable clock */
+	val = 0x84;
+	i2c_smbus_write_byte_data(client, DS1375_CONTROL_REGISTER, val);
+
+	/* Clear status */
+	val = 0;
+	i2c_smbus_write_byte_data(client, DS1375_STATUS_REGISTER, val);
+
+	/* Ensure that device is set in 24-hour mode */
+	val = i2c_smbus_read_byte_data(client, DS1375_HOURS_REGISTER);
+	if ((val >= 0) && (val & (1 << 6)))
+		i2c_smbus_write_byte_data(client, DS1375_HOURS_REGISTER,
+					  val & 0x3f);
+}
+
+static const struct rtc_class_ops ds1375_rtc_ops = {
+        .read_time      = ds1375_get_rtc_time,
+        .set_time       = ds1375_set_rtc_time,
+};
+
+static int __devinit ds1375_detect(struct i2c_adapter *adap, int addr, int kind)
+{
+	struct i2c_client *client;
+	struct ds1375_data *data;
+	struct rtc_device *rtc;
+	int rc = 0;
+
+	if (!i2c_check_functionality(adap, I2C_FUNC_I2C))
+		return 0;
+
+	if (!(data = kzalloc(sizeof(struct ds1375_data), GFP_KERNEL))) 
+		return -ENOMEM;
+	
+	client = &data->client;
+	client->addr = addr;
+	client->adapter = adap;
+	client->driver = &ds1375_driver;
+	strlcpy(client->name, DS1375_DRV_NAME, I2C_NAME_SIZE);
+	client->flags = 0;
+
+        data->msg[0].addr = client->addr;
+        data->msg[0].flags = 0;
+        data->msg[0].len = 1;
+        data->msg[0].buf = &data->reg_addr;
+
+        data->msg[1].addr = client->addr;
+        data->msg[1].flags = I2C_M_RD;
+        data->msg[1].len = sizeof(data->regs);
+        data->msg[1].buf = data->regs;
+
+	if (kind == 0) {
+		kind = ds1375;
+		data->reg_addr = 0; 
+	}
+
+	if ((rc = i2c_attach_client(client)) != 0)
+		goto exit_free;
+
+	rtc = rtc_device_register(client->name, &client->dev,
+				&ds1375_rtc_ops, THIS_MODULE);	
+
+        if (IS_ERR(rtc)) {
+                rc = PTR_ERR(rtc);
+                dev_err(&client->dev,
+                        "unable to register the class device\n");
+                goto exit_detach;
+        }
+
+	data->rtc = rtc;
+	i2c_set_clientdata(client, data);
+	ds1375_init_client(client);
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+exit_free:
+	kfree(data);
+	return rc;
+}
+
+static int __devinit ds1375_attach(struct i2c_adapter *adap)
+{
+	return i2c_probe(adap, &addr_data, ds1375_detect);
+}
+
+static int __devexit ds1375_detach(struct i2c_client *client)
+{
+	int rc;
+        struct ds1375_data   *ds1375 = i2c_get_clientdata(client);
+	struct rtc_device *rtc = ds1375->rtc;
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	if ((rc = i2c_detach_client(client)))
+		return rc;
+
+	kfree(ds1375);
+	return 0;
+}
+
+static struct i2c_driver ds1375_driver = {
+	.driver = {
+		.owner = THIS_MODULE,
+		.name = DS1375_DRV_NAME,
+	},
+	.attach_adapter = ds1375_attach,
+	.detach_client = __devexit_p(ds1375_detach),
+};
+
+static int __init ds1375_init(void)
+{
+	return i2c_add_driver(&ds1375_driver);
+}
+
+static void __exit ds1375_exit(void)
+{
+	i2c_del_driver(&ds1375_driver);
+}
+
+module_init(ds1375_init);
+module_exit(ds1375_exit);
+
+MODULE_AUTHOR("Ajit Prem <ajit.prem@emerson.com>");
+MODULE_DESCRIPTION("Maxim/Dallas DS1375 RTC I2C Client Driver");
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/rtc/rtc-m41t80.c linux-2.6.29.6.mod/drivers/rtc/rtc-m41t80.c
--- linux-2.6.29.6.orig/drivers/rtc/rtc-m41t80.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/rtc/rtc-m41t80.c	2009-07-21 11:28:18.000000000 -0700
@@ -67,6 +67,12 @@
 
 #define DRV_VERSION "0.05"
 
+static struct i2c_driver m41t80_driver;
+
+static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
+
+I2C_CLIENT_INSMOD_1(m41t80);
+
 static const struct i2c_device_id m41t80_id[] = {
 	{ "m41t65", M41T80_FEATURE_HT | M41T80_FEATURE_WD },
 	{ "m41t80", M41T80_FEATURE_SQ },
@@ -84,6 +90,7 @@
 struct m41t80_data {
 	u8 features;
 	struct rtc_device *rtc;
+	struct i2c_client client;
 };
 
 static int m41t80_get_datetime(struct i2c_client *client,
@@ -756,28 +763,56 @@
  *
  *****************************************************************************
  */
-static int m41t80_probe(struct i2c_client *client,
-			const struct i2c_device_id *id)
+
+static int m41t80_detect(struct i2c_adapter *adap, int addr, int kind);
+
+static int __devinit m41t80_attach(struct i2c_adapter *adap)
+{
+        int id = i2c_adapter_id(adap);
+
+#ifdef CONFIG_CPCI6200
+        if (id == 1)
+                return 0;
+#endif
+
+        return i2c_probe(adap, &addr_data, m41t80_detect);
+}
+
+static int m41t80_detect(struct i2c_adapter *adap, int addr, int kind)
 {
 	int rc = 0;
 	struct rtc_device *rtc = NULL;
 	struct rtc_time tm;
 	struct m41t80_data *clientdata = NULL;
+	struct i2c_client *client;
 
-	if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C
+	if (!i2c_check_functionality(adap, I2C_FUNC_I2C
 				     | I2C_FUNC_SMBUS_BYTE_DATA)) {
 		rc = -ENODEV;
 		goto exit;
 	}
 
-	dev_info(&client->dev,
-		 "chip found, driver version " DRV_VERSION "\n");
+//	dev_info(&client->dev,
+//		 "chip found, driver version " DRV_VERSION "\n");
 
 	clientdata = kzalloc(sizeof(*clientdata), GFP_KERNEL);
 	if (!clientdata) {
 		rc = -ENOMEM;
 		goto exit;
 	}
+        client = &clientdata->client;
+        client->addr = addr;
+        client->adapter = adap;
+        client->driver = &m41t80_driver;
+        strlcpy(client->name, "rtc-m41t80", I2C_NAME_SIZE);
+        client->flags = 0;
+
+       if (kind == 0) {
+                kind = m41t80;
+        }
+
+        if ((rc = i2c_attach_client(client)) != 0)
+                goto exit;
 
 	rtc = rtc_device_register(client->name, &client->dev,
 				  &m41t80_rtc_ops, THIS_MODULE);
@@ -788,7 +823,8 @@
 	}
 
 	clientdata->rtc = rtc;
-	clientdata->features = id->driver_data;
+//	clientdata->features = id->driver_data;
+	clientdata->features = M41T80_FEATURE_HT | M41T80_FEATURE_BL; 
 	i2c_set_clientdata(client, clientdata);
 
 	/* Make sure HT (Halt Update) bit is cleared */
@@ -859,10 +895,11 @@
 	return rc;
 }
 
-static int m41t80_remove(struct i2c_client *client)
+static int __devexit m41t80_detach(struct i2c_client *client)
 {
 	struct m41t80_data *clientdata = i2c_get_clientdata(client);
 	struct rtc_device *rtc = clientdata->rtc;
+	int rc;
 
 #ifdef CONFIG_RTC_DRV_M41T80_WDT
 	if (clientdata->features & M41T80_FEATURE_HT) {
@@ -872,6 +909,10 @@
 #endif
 	if (rtc)
 		rtc_device_unregister(rtc);
+
+      if ((rc = i2c_detach_client(client)))
+                return rc;
+
 	kfree(clientdata);
 
 	return 0;
@@ -879,11 +920,14 @@
 
 static struct i2c_driver m41t80_driver = {
 	.driver = {
+		.owner = THIS_MODULE,
 		.name = "rtc-m41t80",
 	},
-	.probe = m41t80_probe,
-	.remove = m41t80_remove,
-	.id_table = m41t80_id,
+//	.probe = m41t80_probe,
+//	.remove = m41t80_remove,
+//	.id_table = m41t80_id,
+	.attach_adapter = m41t80_attach,
+	.detach_client = __devexit_p(m41t80_detach),
 };
 
 static int __init m41t80_rtc_init(void)
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/scsi/Kconfig linux-2.6.29.6.mod/drivers/scsi/Kconfig
--- linux-2.6.29.6.orig/drivers/scsi/Kconfig	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/scsi/Kconfig	2009-07-21 11:28:18.000000000 -0700
@@ -257,7 +257,7 @@
 	  or async on the kernel's command line.
 
 config SCSI_WAIT_SCAN
-	tristate
+	tristate "Wait until the async scans are complete"
 	default m
 	depends on SCSI
 	depends on MODULES
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/vme/ca91c042.c linux-2.6.29.6.mod/drivers/vme/ca91c042.c
--- linux-2.6.29.6.orig/drivers/vme/ca91c042.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/vme/ca91c042.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,1931 @@
+/*
+ * ca91c042.c
+ *
+ * Support for the Tundra Universe I/II VME Bridge chips
+ *
+ * Authors: Tom Armistead, Ajit Prem 
+ * Copyright 2004-2007 Motorola Inc.
+ *
+ * Derived from ca91c042.c by Michael Wyrick
+ *
+ * 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.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/poll.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include "vmedrv.h"
+#include "ca91c042.h"
+
+//----------------------------------------------------------------------------
+// Prototypes
+//----------------------------------------------------------------------------
+extern struct vmeSharedData *vmechip_interboard_data;
+extern dma_addr_t vmechip_interboard_datap;
+extern const int vmechip_revision;
+extern const int vmechip_devid;
+extern const int vmechip_irq;
+extern int vmechip_irq_overhead_ticks;
+extern void __iomem *vmechip_baseaddr;
+extern const int vme_slotnum;
+extern int vme_syscon;
+extern char *in_image_ba[];
+extern int in_image_size[];
+extern int in_image_mapped[];
+extern dma_addr_t in_image_pa[];
+extern unsigned int out_image_va[];
+extern unsigned int vme_irqlog[8][0x100];
+extern struct pci_dev *vme_pci_dev;
+
+static int outCTL[] = { LSI0_CTL, LSI1_CTL, LSI2_CTL, LSI3_CTL,
+	LSI4_CTL, LSI5_CTL, LSI6_CTL, LSI7_CTL
+};
+
+static int outBS[] = { LSI0_BS, LSI1_BS, LSI2_BS, LSI3_BS,
+	LSI4_BS, LSI5_BS, LSI6_BS, LSI7_BS
+};
+
+static int outBD[] = { LSI0_BD, LSI1_BD, LSI2_BD, LSI3_BD,
+	LSI4_BD, LSI5_BD, LSI6_BD, LSI7_BD
+};
+
+static int outTO[] = { LSI0_TO, LSI1_TO, LSI2_TO, LSI3_TO,
+	LSI4_TO, LSI5_TO, LSI6_TO, LSI7_TO
+};
+
+static int inCTL[] = { VSI0_CTL, VSI1_CTL, VSI2_CTL, VSI3_CTL,
+	VSI4_CTL, VSI5_CTL, VSI6_CTL, VSI7_CTL
+};
+
+static int inBS[] = { VSI0_BS, VSI1_BS, VSI2_BS, VSI3_BS,
+	VSI4_BS, VSI5_BS, VSI6_BS, VSI7_BS
+};
+
+static int inBD[] = { VSI0_BD, VSI1_BD, VSI2_BD, VSI3_BD,
+	VSI4_BD, VSI5_BD, VSI6_BD, VSI7_BD
+};
+
+static int inTO[] = { VSI0_TO, VSI1_TO, VSI2_TO, VSI3_TO,
+	VSI4_TO, VSI5_TO, VSI6_TO, VSI7_TO
+};
+static int vmevec[7] = { V1_STATID, V2_STATID, V3_STATID, V4_STATID,
+	V5_STATID, V6_STATID, V7_STATID
+};
+
+struct interrupt_counters {
+	unsigned int acfail;
+	unsigned int sysfail;
+	unsigned int sw_int;
+	unsigned int sw_iack;
+	unsigned int verr;
+	unsigned int lerr;
+	unsigned int lm;
+	unsigned int mbox;
+	unsigned int dma;
+	unsigned int virq[7];
+	unsigned int vown;
+};
+
+extern wait_queue_head_t dma_queue[];
+extern wait_queue_head_t lm_queue;
+extern wait_queue_head_t mbox_queue;
+
+extern void vme_sync_data(void);
+extern void vme_flush_line(unsigned long);
+extern void vme_flush_range(unsigned long, unsigned long);
+extern int tb_speed;
+
+unsigned int uni_irq_time;
+unsigned int uni_dma_irq_time;
+unsigned int uni_lm_event;
+
+static spinlock_t lm_lock = SPIN_LOCK_UNLOCKED;
+
+static struct interrupt_counters Interrupt_counters = { 0, 0,
+	0, 0, 0, 0,
+	0, 0, 0,
+	{0, 0, 0, 0, 0, 0, 0},
+	0
+};
+
+#define read_register(offset) readl(vmechip_baseaddr + offset)
+#define write_register(value,offset) writel(value, vmechip_baseaddr + offset)
+#define read_register_word(offset) readw(vmechip_baseaddr + offset)
+#define write_register_word(value,offset) writew(value, vmechip_baseaddr + offset)
+
+//----------------------------------------------------------------------------
+//  uni_procinfo()
+//----------------------------------------------------------------------------
+int uni_procinfo(char *buf)
+{
+	char *p;
+
+	p = buf;
+
+	p += sprintf(p, "\n");
+	{
+		unsigned long misc_ctl;
+
+		misc_ctl = read_register(MISC_CTL);
+		p += sprintf(p, "MISC_CTL:\t\t\t0x%08lx\n", misc_ctl);
+		p += sprintf(p, "VME Bus Time Out:\t\t");
+		switch ((misc_ctl & UNIV_BM_MISC_CTL_VBTO) >>
+			UNIV_OF_MISC_CTL_VBTO) {
+		case 0x0:
+			p += sprintf(p, "Disabled\n");
+			break;
+		case 0x1:
+			p += sprintf(p, "16 us\n");
+			break;
+		case 0x2:
+			p += sprintf(p, "32 us\n");
+			break;
+		case 0x3:
+			p += sprintf(p, "64 us\n");
+			break;
+		case 0x4:
+			p += sprintf(p, "128 us\n");
+			break;
+		case 0x5:
+			p += sprintf(p, "256 us\n");
+			break;
+		case 0x6:
+			p += sprintf(p, "512 us\n");
+			break;
+		case 0x7:
+			p += sprintf(p, "1024 us\n");
+			break;
+		default:
+			p += sprintf(p, "Reserved Value, Undefined\n");
+		}
+		p += sprintf(p, "VME Arbitration Time Out:\t");
+		switch ((misc_ctl & UNIV_BM_MISC_CTL_VARBTO) >>
+			UNIV_OF_MISC_CTL_VARBTO) {
+		case 0x0:
+			p += sprintf(p, "Disabled");
+			break;
+		case 0x1:
+			p += sprintf(p, "16 us");
+			break;
+		case 0x2:
+			p += sprintf(p, "256 us");
+			break;
+		default:
+			p += sprintf(p, "Reserved Value, Undefined");
+		}
+		if (misc_ctl & UNIV_BM_MISC_CTL_VARB)
+			p += sprintf(p, ", Priority Arbitration\n");
+		else
+			p += sprintf(p, ", Round Robin Arbitration\n");
+		p += sprintf(p, "\n");
+	}
+
+	{
+		unsigned int lmisc;
+		unsigned int crt;
+		unsigned int cwt;
+
+		lmisc = read_register(LMISC);
+		p += sprintf(p, "LMISC:\t\t\t\t0x%08x\n", lmisc);
+		crt = (lmisc & UNIV_BM_LMISC_CRT) >> UNIV_OF_LMISC_CRT;
+		cwt = (lmisc & UNIV_BM_LMISC_CWT) >> UNIV_OF_LMISC_CWT;
+		p += sprintf(p, "Coupled Request Timer:\t\t");
+		switch (crt) {
+		case 0x0:
+			p += sprintf(p, "Disabled\n");
+			break;
+		case 0x1:
+			p += sprintf(p, "128 us\n");
+			break;
+		case 0x2:
+			p += sprintf(p, "256 us\n");
+			break;
+		case 0x3:
+			p += sprintf(p, "512 us\n");
+			break;
+		case 0x4:
+			p += sprintf(p, "1024 us\n");
+			break;
+		case 0x5:
+			p += sprintf(p, "2048 us\n");
+			break;
+		case 0x6:
+			p += sprintf(p, "4096 us\n");
+			break;
+		default:
+			p += sprintf(p, "Reserved\n");
+		}
+		p += sprintf(p, "Coupled Window Timer:\t\t");
+		switch (cwt) {
+		case 0x0:
+			p += sprintf(p, "Disabled\n");
+			break;
+		case 0x1:
+			p += sprintf(p, "16 PCI Clocks\n");
+			break;
+		case 0x2:
+			p += sprintf(p, "32 PCI Clocks\n");
+			break;
+		case 0x3:
+			p += sprintf(p, "64 PCI Clocks\n");
+			break;
+		case 0x4:
+			p += sprintf(p, "128 PCI Clocks\n");
+			break;
+		case 0x5:
+			p += sprintf(p, "256 PCI Clocks\n");
+			break;
+		case 0x6:
+			p += sprintf(p, "512 PCI Clocks\n");
+			break;
+		default:
+			p += sprintf(p, "Reserved\n");
+		}
+		p += sprintf(p, "\n");
+	}
+	{
+		unsigned int mast_ctl;
+
+		mast_ctl = read_register(MAST_CTL);
+		p += sprintf(p, "MAST_CTL:\t\t\t0x%08x\n", mast_ctl);
+		{
+			int retries;
+
+			retries = ((mast_ctl & UNIV_BM_MAST_CTL_MAXRTRY)
+				   >> UNIV_OF_MAST_CTL_MAXRTRY) * 64;
+			p += sprintf(p, "Max PCI Master Retries:\t\t");
+			if (retries)
+				p += sprintf(p, "%d\n", retries);
+			else
+				p += sprintf(p, "Forever\n");
+		}
+
+		p += sprintf(p, "Posted Write Transfer Count:\t");
+		switch ((mast_ctl & UNIV_BM_MAST_CTL_PWON) >>
+			UNIV_OF_MAST_CTL_PWON) {
+		case 0x0:
+			p += sprintf(p, "128 Bytes\n");
+			break;
+		case 0x1:
+			p += sprintf(p, "256 Bytes\n");
+			break;
+		case 0x2:
+			p += sprintf(p, "512 Bytes\n");
+			break;
+		case 0x3:
+			p += sprintf(p, "1024 Bytes\n");
+			break;
+		case 0x4:
+			p += sprintf(p, "2048 Bytes\n");
+			break;
+		case 0x5:
+			p += sprintf(p, "4096 Bytes\n");
+			break;
+		default:
+			p += sprintf(p, "Undefined\n");
+		}
+
+		p += sprintf(p, "VMEbus Request Level:\t\t");
+		switch ((mast_ctl & UNIV_BM_MAST_CTL_VRL) >>
+			UNIV_OF_MAST_CTL_VRL) {
+		case 0x0:
+			p += sprintf(p, "Level 0\n");
+		case 0x1:
+			p += sprintf(p, "Level 1\n");
+		case 0x2:
+			p += sprintf(p, "Level 2\n");
+		case 0x3:
+			p += sprintf(p, "Level 3\n");
+		}
+		p += sprintf(p, "VMEbus Request Mode:\t\t");
+		if (mast_ctl & UNIV_BM_MAST_CTL_VRM)
+			p += sprintf(p, "Fair Request Mode\n");
+		else
+			p += sprintf(p, "Demand Request Mode\n");
+		p += sprintf(p, "VMEbus Release Mode:\t\t");
+		if (mast_ctl & UNIV_BM_MAST_CTL_VREL)
+			p += sprintf(p, "Release on Request\n");
+		else
+			p += sprintf(p, "Release when Done\n");
+		p += sprintf(p, "VMEbus Ownership Bit:\t\t");
+		if (mast_ctl & UNIV_BM_MAST_CTL_VOWN)
+			p += sprintf(p, "Acquire and hold VMEbus\n");
+		else
+			p += sprintf(p, "Release VMEbus\n");
+		p += sprintf(p, "VMEbus Ownership Bit Ack:\t");
+		if (mast_ctl & UNIV_BM_MAST_CTL_VOWN_ACK)
+			p += sprintf(p, "Owning VMEbus\n");
+		else
+			p += sprintf(p, "Not Owning VMEbus\n");
+		p += sprintf(p, "\n");
+	}
+	{
+		unsigned int misc_stat;
+
+		misc_stat = read_register(MISC_STAT);
+		p += sprintf(p, "MISC_STAT:\t\t\t0x%08x\n", misc_stat);
+		p += sprintf(p, "Universe BBSY:\t\t\t");
+		if (misc_stat & UNIV_BM_MISC_STAT_MYBBSY)
+			p += sprintf(p, "Negated\n");
+		else
+			p += sprintf(p, "Asserted\n");
+		p += sprintf(p, "Transmit FIFO:\t\t\t");
+		if (misc_stat & UNIV_BM_MISC_STAT_TXFE)
+			p += sprintf(p, "Empty\n");
+		else
+			p += sprintf(p, "Not empty\n");
+		p += sprintf(p, "Receive FIFO:\t\t\t");
+		if (misc_stat & UNIV_BM_MISC_STAT_RXFE)
+			p += sprintf(p, "Empty\n");
+		else
+			p += sprintf(p, "Not Empty\n");
+		p += sprintf(p, "\n");
+	}
+
+	p += sprintf(p, "Latency Timer:\t\t\t%02d Clocks\n\n",
+		     (read_register(UNIV_PCI_MISC0) &
+		      UNIV_BM_PCI_MISC0_LTIMER) >> UNIV_OF_PCI_MISC0_LTIMER);
+
+	{
+		unsigned int lint_en;
+		unsigned int lint_stat;
+
+		lint_en = read_register(LINT_EN);
+		lint_stat = read_register(LINT_STAT);
+
+#define REPORT_IRQ(name,field)     \
+    p += sprintf(p, (lint_en & UNIV_BM_LINT_##name) ? "Enabled" : "Masked"); \
+    p += sprintf(p, ", triggered %d times", Interrupt_counters.field); \
+    p += sprintf(p, (lint_stat & UNIV_BM_LINT_##name) ? ", irq now active\n" : "\n");
+		p += sprintf(p, "ACFAIL Interrupt:\t\t");
+		REPORT_IRQ(ACFAIL, acfail);
+		p += sprintf(p, "SYSFAIL Interrupt:\t\t");
+		REPORT_IRQ(SYSFAIL, sysfail);
+		p += sprintf(p, "SW_INT Interrupt:\t\t");
+		REPORT_IRQ(SW_INT, sw_int);
+		p += sprintf(p, "SW_IACK Interrupt:\t\t");
+		REPORT_IRQ(SW_IACK, sw_iack);
+		p += sprintf(p, "VERR Interrupt:\t\t\t");
+		REPORT_IRQ(VERR, verr);
+		p += sprintf(p, "LERR Interrupt:\t\t\t");
+		REPORT_IRQ(LERR, lerr);
+		p += sprintf(p, "LM Interrupt:\t\t\t");
+		REPORT_IRQ(LM, lm);
+		p += sprintf(p, "MBOX Interrupt:\t\t\t");
+		REPORT_IRQ(MBOX, mbox);
+		p += sprintf(p, "DMA Interrupt:\t\t\t");
+		REPORT_IRQ(DMA, dma);
+		p += sprintf(p, "VIRQ7 Interrupt:\t\t");
+		REPORT_IRQ(VIRQ7, virq[7 - 1]);
+		p += sprintf(p, "VIRQ6 Interrupt:\t\t");
+		REPORT_IRQ(VIRQ6, virq[6 - 1]);
+		p += sprintf(p, "VIRQ5 Interrupt:\t\t");
+		REPORT_IRQ(VIRQ5, virq[5 - 1]);
+		p += sprintf(p, "VIRQ4 Interrupt:\t\t");
+		REPORT_IRQ(VIRQ4, virq[4 - 1]);
+		p += sprintf(p, "VIRQ3 Interrupt:\t\t");
+		REPORT_IRQ(VIRQ3, virq[3 - 1]);
+		p += sprintf(p, "VIRQ2 Interrupt:\t\t");
+		REPORT_IRQ(VIRQ2, virq[2 - 1]);
+		p += sprintf(p, "VIRQ1 Interrupt:\t\t");
+		REPORT_IRQ(VIRQ1, virq[1 - 1]);
+		p += sprintf(p, "VOWN Interrupt:\t\t\t");
+		REPORT_IRQ(VOWN, vown);
+		p += sprintf(p, "\n");
+#undef REPORT_IRQ
+	}
+	{
+		unsigned long vrai_ctl;
+
+		vrai_ctl = read_register(VRAI_CTL);
+		if (vrai_ctl & UNIV_BM_VRAI_CTL_EN) {
+			unsigned int vrai_bs;
+
+			vrai_bs = read_register(VRAI_BS);
+			p += sprintf(p,
+				     "VME Register Image:\t\tEnabled at VME-Address 0x%x\n",
+				     vrai_bs);
+		} else
+			p += sprintf(p, "VME Register Image:\t\tDisabled\n");
+	}
+	{
+		unsigned int slsi;
+
+		slsi = read_register(SLSI);
+		if (slsi & UNIV_BM_SLSI_EN) {
+			/* Not implemented */
+		} else {
+			p += sprintf(p, "Special PCI Slave Image:\tDisabled\n");
+		}
+	}
+	{
+		int i;
+
+		for (i = 0; i < (vmechip_revision > 0 ? 8 : 4); i++) {
+			unsigned int ctl, bs, bd, to, vstart, vend;
+
+			ctl = readl(vmechip_baseaddr + outCTL[i]);
+			bs = readl(vmechip_baseaddr + outBS[i]);
+			bd = readl(vmechip_baseaddr + outBD[i]);
+			to = readl(vmechip_baseaddr + outTO[i]);
+
+			vstart = bs + to;
+			vend = bd + to;
+
+			p += sprintf(p, "PCI Slave Image %d:\t\t", i);
+			if (ctl & UNIV_BM_LSI_CTL_EN) {
+				p += sprintf(p, "Enabled");
+				if (ctl & UNIV_BM_LSI_CTL_PWEN)
+					p += sprintf(p,
+						     ", Posted Write Enabled\n");
+				else
+					p += sprintf(p, "\n");
+				p += sprintf(p,
+					     "\t\t\t\tPCI Addresses from 0x%x to 0x%x\n",
+					     bs, bd);
+				p += sprintf(p,
+					     "\t\t\t\tVME Addresses from 0x%x to 0x%x\n",
+					     vstart, vend);
+			} else
+				p += sprintf(p, "Disabled\n");
+		}
+		p += sprintf(p, "\n");
+	}
+	{
+		int i;
+		for (i = 0; i < (vmechip_revision > 0 ? 8 : 4); i++) {
+			unsigned int ctl, bs, bd, to, vstart, vend;
+
+			ctl = readl(vmechip_baseaddr + inCTL[i]);
+			bs = readl(vmechip_baseaddr + inBS[i]);
+			bd = readl(vmechip_baseaddr + inBD[i]);
+			to = readl(vmechip_baseaddr + inTO[i]);
+			vstart = bs + to;
+			vend = bd + to;
+			p += sprintf(p, "VME Slave Image %d:\t\t", i);
+			if (ctl & UNIV_BM_LSI_CTL_EN) {
+				p += sprintf(p, "Enabled");
+				if (ctl & UNIV_BM_LSI_CTL_PWEN)
+					p += sprintf(p,
+						     ", Posted Write Enabled\n");
+				else
+					p += sprintf(p, "\n");
+				p += sprintf(p,
+					     "\t\t\t\tVME Addresses from 0x%x to 0x%x\n",
+					     bs, bd);
+				p += sprintf(p,
+					     "\t\t\t\tPCI Addresses from 0x%x to 0x%x\n",
+					     vstart, vend);
+			} else
+				p += sprintf(p, "Disabled\n");
+		}
+	}
+
+	return p - buf;
+}
+
+//----------------------------------------------------------------------------
+//  uni_bus_error_chk()
+//----------------------------------------------------------------------------
+int uni_bus_error_chk(int clrflag)
+{
+	int tmp;
+	tmp = readl(vmechip_baseaddr + PCI_COMMAND);
+	if (tmp & 0x08000000) {	// S_TA is Set
+		if (clrflag)
+			writel(tmp | 0x08000000,
+			       vmechip_baseaddr + PCI_COMMAND);
+		return (1);
+	}
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : DMA_uni_irqhandler
+// Inputs     : void
+// Outputs    : void
+// Description: Saves DMA completion timestamp and then wakes up DMA queue
+//-----------------------------------------------------------------------------
+static void DMA_uni_irqhandler(void)
+{
+	uni_dma_irq_time = uni_irq_time;
+	wake_up(&dma_queue[0]);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : LERR_uni_irqhandler
+// Inputs     : void
+// Outputs    : void
+// Description: 
+//-----------------------------------------------------------------------------
+static void LERR_uni_irqhandler(void)
+{
+	int val;
+
+	val = readl(vmechip_baseaddr + DGCS);
+
+	if (!(val & 0x00000800)) {
+		printk(KERN_ERR
+		       "ca91c042: LERR_uni_irqhandler DMA Read Error DGCS=%08X\n",
+		       val);
+
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Function   : VERR_uni_irqhandler
+// Inputs     : void
+// Outputs    : void
+// Description: 
+//-----------------------------------------------------------------------------
+static void VERR_uni_irqhandler(void)
+{
+	int val;
+
+	val = readl(vmechip_baseaddr + DGCS);
+
+	if (!(val & 0x00000800)) {
+		printk(KERN_ERR
+		       "ca91c042: VERR_uni_irqhandler DMA Read Error DGCS=%08X\n",
+		       val);
+	}
+
+}
+
+//-----------------------------------------------------------------------------
+// Function   : MB_uni_irqhandler
+// Inputs     : void
+// Outputs    : void
+// Description: 
+//-----------------------------------------------------------------------------
+static void MB_uni_irqhandler(int mbox_mask)
+{
+	if (vmechip_irq_overhead_ticks != 0) {
+		wake_up(&mbox_queue);
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Function   : LM_uni_irqhandler
+// Inputs     : void
+// Outputs    : void
+// Description: 
+//-----------------------------------------------------------------------------
+static void LM_uni_irqhandler(int lm_mask)
+{
+	uni_lm_event = lm_mask;
+	wake_up(&lm_queue);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : VIRQ_uni_irqhandler
+// Inputs     : void
+// Outputs    : void
+// Description: 
+//-----------------------------------------------------------------------------
+static void VIRQ_uni_irqhandler(int virq_mask)
+{
+	int iackvec, i;
+
+	for (i = 7; i > 0; i--) {
+		if (virq_mask & (1 << i)) {
+			Interrupt_counters.virq[i - 1]++;
+			iackvec = readl(vmechip_baseaddr + vmevec[i - 1]);
+			vme_irqlog[i][iackvec]++;
+		}
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_irqhandler
+// Inputs     : int irq, void *dev_id, struct pt_regs *regs
+// Outputs    : void
+// Description: 
+//-----------------------------------------------------------------------------
+static irqreturn_t uni_irqhandler(int irq, void *dev_id)
+{
+	long stat, enable;
+
+	if (dev_id != vmechip_baseaddr)
+		return IRQ_NONE;
+
+	uni_irq_time = get_tbl();
+
+	stat = readl(vmechip_baseaddr + LINT_STAT);
+	writel(stat, vmechip_baseaddr + LINT_STAT);	// Clear all pending ints
+	enable = readl(vmechip_baseaddr + LINT_EN);
+	stat = stat & enable;
+	if (stat & 0x0100) {
+		Interrupt_counters.dma++;
+		DMA_uni_irqhandler();
+	}
+	if (stat & 0x0200) {
+		Interrupt_counters.lerr++;
+		LERR_uni_irqhandler();
+	}
+	if (stat & 0x0400) {
+		Interrupt_counters.verr++;
+		VERR_uni_irqhandler();
+	}
+	if (stat & 0xF0000) {
+		Interrupt_counters.mbox++;
+		MB_uni_irqhandler((stat & 0xF0000) >> 16);
+	}
+	if (stat & 0xF00000) {
+		Interrupt_counters.lm++;
+		LM_uni_irqhandler((stat & 0xF00000) >> 20);
+	}
+	if (stat & 0x0000FE) {
+		VIRQ_uni_irqhandler(stat & 0x0000FE);
+	}
+	if (stat & UNIV_BM_LINT_ACFAIL) {
+		Interrupt_counters.acfail++;
+	}
+	if (stat & UNIV_BM_LINT_SYSFAIL) {
+		Interrupt_counters.sysfail++;
+	}
+	if (stat & UNIV_BM_LINT_SW_INT) {
+		Interrupt_counters.sw_int++;
+	}
+	if (stat & UNIV_BM_LINT_SW_IACK) {
+		Interrupt_counters.sw_iack++;
+	}
+	if (stat & UNIV_BM_LINT_VOWN) {
+		Interrupt_counters.vown++;
+	}
+
+	return IRQ_HANDLED;
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_generate_irq
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_generate_irq(virqInfo_t * vmeIrq)
+{
+	int timeout;
+	int looptimeout;
+
+	timeout = vmeIrq->waitTime;
+	if (timeout == 0) {
+		timeout++;	// Wait at least 1 tick...
+	}
+	looptimeout = HZ / 20;	// try for 1/20 second
+
+	vmeIrq->timeOutFlag = 0;
+
+	// Validate & setup vector register.
+	if (vmeIrq->vector & 1) {	// Universe can only generate even vectors
+		return (-EINVAL);
+	}
+	writel(vmeIrq->vector << 24, vmechip_baseaddr + STATID);
+
+	// Assert VMEbus IRQ
+	writel(1 << (vmeIrq->level + 24), vmechip_baseaddr + VINT_EN);
+
+	// Wait for syscon to do iack
+	while (readl(vmechip_baseaddr + VINT_STAT) &
+	       (1 << (vmeIrq->level + 24))) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(looptimeout);
+		timeout = timeout - looptimeout;
+		if (timeout <= 0) {
+			vmeIrq->timeOutFlag = 1;
+			break;
+		}
+	}
+
+	// Clear VMEbus IRQ bit
+	writel(0, vmechip_baseaddr + VINT_EN);
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_set_arbiter
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_set_arbiter(vmeArbiterCfg_t * vmeArb)
+{
+	int temp_ctl = 0;
+	int vbto = 0;
+
+	temp_ctl = readl(vmechip_baseaddr + MISC_CTL);
+	temp_ctl &= 0x00FFFFFF;
+
+	if (vmeArb->globalTimeoutTimer == 0xFFFFFFFF) {
+		vbto = 7;
+	} else if (vmeArb->globalTimeoutTimer > 1024) {
+		return (-EINVAL);
+	} else if (vmeArb->globalTimeoutTimer == 0) {
+		vbto = 0;
+	} else {
+		vbto = 1;
+		while ((16 * (1 << (vbto - 1))) < vmeArb->globalTimeoutTimer) {
+			vbto += 1;
+		}
+	}
+	temp_ctl |= (vbto << 28);
+
+	if (vmeArb->arbiterMode == VME_PRIORITY_MODE) {
+		temp_ctl |= 1 << 26;
+	}
+
+	if (vmeArb->arbiterTimeoutFlag) {
+		temp_ctl |= 2 << 24;
+	}
+
+	writel(temp_ctl, vmechip_baseaddr + MISC_CTL);
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_get_arbiter
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_get_arbiter(vmeArbiterCfg_t * vmeArb)
+{
+	int temp_ctl = 0;
+	int vbto = 0;
+
+	temp_ctl = readl(vmechip_baseaddr + MISC_CTL);
+
+	vbto = (temp_ctl >> 28) & 0xF;
+	if (vbto != 0) {
+		vmeArb->globalTimeoutTimer = (16 * (1 << (vbto - 1)));
+	}
+
+	if (temp_ctl & (1 << 26)) {
+		vmeArb->arbiterMode = VME_PRIORITY_MODE;
+	} else {
+		vmeArb->arbiterMode = VME_R_ROBIN_MODE;
+	}
+
+	if (temp_ctl & (3 << 24)) {
+		vmeArb->arbiterTimeoutFlag = 1;
+	}
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_set_requestor
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_set_requestor(vmeRequesterCfg_t * vmeReq)
+{
+	int temp_ctl = 0;
+
+	temp_ctl = readl(vmechip_baseaddr + MAST_CTL);
+	temp_ctl &= 0xFF0FFFFF;
+
+	if (vmeReq->releaseMode == 1) {
+		temp_ctl |= (1 << 20);
+	}
+
+	if (vmeReq->fairMode == 1) {
+		temp_ctl |= (1 << 21);
+	}
+
+	temp_ctl |= (vmeReq->requestLevel << 22);
+
+	writel(temp_ctl, vmechip_baseaddr + MAST_CTL);
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_get_requestor
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_get_requestor(vmeRequesterCfg_t * vmeReq)
+{
+	int temp_ctl = 0;
+
+	temp_ctl = readl(vmechip_baseaddr + MAST_CTL);
+
+	if (temp_ctl & (1 << 20)) {
+		vmeReq->releaseMode = 1;
+	}
+
+	if (temp_ctl & (1 << 21)) {
+		vmeReq->fairMode = 1;
+	}
+
+	vmeReq->requestLevel = (temp_ctl & 0xC00000) >> 22;
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_set_in_bound
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_set_in_bound(vmeInWindowCfg_t * vmeIn)
+{
+	int temp_ctl = 0;
+	unsigned int win;
+	struct page *page, *pend;
+
+	// Verify input data
+	win = vmeIn->windowNbr;
+
+	if (win > 7) 
+		 return -EINVAL;
+
+        /* Free previous allocation */
+#ifndef CONFIG_VME_BRIDGE_BOOTMEM
+        if (in_image_ba[win] != NULL) {
+#else
+        if ((win != 7) && (in_image_ba[win] != NULL)) {
+#endif
+		/* Undo marking the pages as reserved */
+		pend = virt_to_page(in_image_ba[win] + in_image_size[win] - 1);   
+		for (page = virt_to_page(in_image_ba[win]); page <= pend; page++)
+			ClearPageReserved(page);
+		dma_free_coherent(&vme_pci_dev->dev,
+					in_image_size[win],
+					in_image_ba[win],
+					in_image_pa[win]);
+		in_image_mapped[win] = 0;
+	}
+
+        if (vmeIn->windowEnable == 0) {
+		temp_ctl = readl(vmechip_baseaddr + inCTL[vmeIn->windowNbr]);
+		temp_ctl &= ~0x80000000;
+		writel(temp_ctl, vmechip_baseaddr + inCTL[vmeIn->windowNbr]);
+		return 0;
+	}
+
+#ifdef CONFIG_VME_BRIDGE_BOOTMEM
+        if (win == 7) {
+                vmeIn->windowSizeL = in_image_size[7];
+                vmeIn->windowSizeU = 0;
+        }
+#endif
+
+	if ((vmeIn->vmeAddrU) || (vmeIn->windowSizeU)) 
+		return (-EINVAL);
+
+	if ((vmeIn->vmeAddrL & 0xFFF) || (vmeIn->windowSizeL & 0xFFF)) 
+		return (-EINVAL);
+	
+#ifndef CONFIG_VME_BRIDGE_BOOTMEM
+	if (vmeIn->windowSizeL > 0x800000) 
+#else
+	if ((win != 7) && (vmeIn->windowSizeL > 0x800000))
+#endif
+		return (-EINVAL);
+
+	if (vmeIn->bcastRespond2esst) 
+		return (-EINVAL);
+
+	switch (vmeIn->addrSpace) {
+	case VME_A64:
+	case VME_CRCSR:
+	case VME_USER3:
+	case VME_USER4:
+		return (-EINVAL);
+	case VME_A16:
+		temp_ctl |= 0x00000;
+		break;
+	case VME_A24:
+		temp_ctl |= 0x10000;
+		break;
+	case VME_A32:
+		temp_ctl |= 0x20000;
+		break;
+	case VME_USER1:
+		temp_ctl |= 0x60000;
+		break;
+	case VME_USER2:
+		temp_ctl |= 0x70000;
+		break;
+	}
+
+#ifndef CONFIG_VME_BRIDGE_BOOTMEM
+        if (vmeIn->windowEnable == 1) {
+#else 
+        if ((win != 7) && (vmeIn->windowEnable == 1)) {
+#endif
+		in_image_ba[win] = (char *)dma_alloc_coherent((struct device *)
+					&vme_pci_dev->dev,
+					vmeIn->windowSizeL,
+					(dma_addr_t *)&in_image_pa[win],
+					GFP_KERNEL);
+		if (!in_image_ba[win]) {
+			printk("vmedrv: No memory for inbound window\n");
+			return -ENOMEM;
+		}
+		in_image_size[win] = vmeIn->windowSizeL;
+
+		/* now mark the pages as reserved; otherwise */
+		/* remap_pfn_range doesn't do what we want */
+		pend = virt_to_page(in_image_ba[win] + in_image_size[win] - 1);
+		for (page = virt_to_page(in_image_ba[win]); page <= pend; page++)
+			SetPageReserved(page);
+		memset(in_image_ba[win], 0, in_image_size[win]);
+		vme_flush_range((unsigned long)in_image_ba[win],
+			(unsigned long)(in_image_ba[win] + in_image_size[win]));
+		vmeIn->pciAddrL = (unsigned int)in_image_pa[win];
+		vmeIn->pciAddrU = 0;
+#ifndef CONFIG_VME_BRIDGE_BOOTMEM
+	}
+#else
+	} else if (win == 7)  {
+		vmeIn->pciAddrL = (unsigned int)in_image_pa[win];
+		vmeIn->pciAddrU = 0;
+	}
+#endif
+
+	// Disable while we are mucking around
+	writel(0x00000000, vmechip_baseaddr + inCTL[vmeIn->windowNbr]);
+	writel(vmeIn->vmeAddrL, vmechip_baseaddr + inBS[vmeIn->windowNbr]);
+	writel(vmeIn->vmeAddrL + vmeIn->windowSizeL,
+	       vmechip_baseaddr + inBD[vmeIn->windowNbr]);
+	writel(vmeIn->pciAddrL - vmeIn->vmeAddrL,
+	       vmechip_baseaddr + inTO[vmeIn->windowNbr]);
+
+	// Setup CTL register.
+	if (vmeIn->wrPostEnable)
+		temp_ctl |= 0x40000000;
+	if (vmeIn->prefetchEnable)
+		temp_ctl |= 0x20000000;
+	if (vmeIn->rmwLock)
+		temp_ctl |= 0x00000040;
+	if (vmeIn->data64BitCapable)
+		temp_ctl |= 0x00000080;
+	if (vmeIn->userAccessType & VME_USER)
+		temp_ctl |= 0x00100000;
+	if (vmeIn->userAccessType & VME_SUPER)
+		temp_ctl |= 0x00200000;
+	if (vmeIn->dataAccessType & VME_DATA)
+		temp_ctl |= 0x00400000;
+	if (vmeIn->dataAccessType & VME_PROG)
+		temp_ctl |= 0x00800000;
+
+	// Write ctl reg without enable
+	writel(temp_ctl, vmechip_baseaddr + inCTL[vmeIn->windowNbr]);
+
+	if (vmeIn->windowEnable)
+		temp_ctl |= 0x80000000;
+
+	writel(temp_ctl, vmechip_baseaddr + inCTL[vmeIn->windowNbr]);
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_get_in_bound
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_get_in_bound(vmeInWindowCfg_t * vmeIn)
+{
+	int temp_ctl = 0;
+
+	// Verify input data
+	if (vmeIn->windowNbr > 7) {
+		return (-EINVAL);
+	}
+	// Get Window mappings.
+	vmeIn->vmeAddrL = readl(vmechip_baseaddr + inBS[vmeIn->windowNbr]);
+	vmeIn->pciAddrL = vmeIn->vmeAddrL +
+	    readl(vmechip_baseaddr + inTO[vmeIn->windowNbr]);
+	vmeIn->windowSizeL = readl(vmechip_baseaddr + inBD[vmeIn->windowNbr]) -
+	    vmeIn->vmeAddrL;
+
+	temp_ctl = readl(vmechip_baseaddr + inCTL[vmeIn->windowNbr]);
+
+	// Get Control & BUS attributes
+	if (temp_ctl & 0x40000000)
+		vmeIn->wrPostEnable = 1;
+	if (temp_ctl & 0x20000000)
+		vmeIn->prefetchEnable = 1;
+	if (temp_ctl & 0x00000040)
+		vmeIn->rmwLock = 1;
+	if (temp_ctl & 0x00000080)
+		vmeIn->data64BitCapable = 1;
+	if (temp_ctl & 0x00100000)
+		vmeIn->userAccessType |= VME_USER;
+	if (temp_ctl & 0x00200000)
+		vmeIn->userAccessType |= VME_SUPER;
+	if (temp_ctl & 0x00400000)
+		vmeIn->dataAccessType |= VME_DATA;
+	if (temp_ctl & 0x00800000)
+		vmeIn->dataAccessType |= VME_PROG;
+	if (temp_ctl & 0x80000000)
+		vmeIn->windowEnable = 1;
+
+	switch ((temp_ctl & 0x70000) >> 16) {
+	case 0x0:
+		vmeIn->addrSpace = VME_A16;
+		break;
+	case 0x1:
+		vmeIn->addrSpace = VME_A24;
+		break;
+	case 0x2:
+		vmeIn->addrSpace = VME_A32;
+		break;
+	case 0x6:
+		vmeIn->addrSpace = VME_USER1;
+		break;
+	case 0x7:
+		vmeIn->addrSpace = VME_USER2;
+		break;
+	}
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_set_out_bound
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_set_out_bound(vmeOutWindowCfg_t * vmeOut)
+{
+	int temp_ctl = 0;
+
+	// Verify input data
+	if (vmeOut->windowNbr > 7) {
+		return (-EINVAL);
+	}
+
+	if (vmeOut->windowEnable == 0) {
+		temp_ctl = readl(vmechip_baseaddr + outCTL[vmeOut->windowNbr]);
+		temp_ctl &= ~0x80000000;
+		writel(temp_ctl, vmechip_baseaddr + outCTL[vmeOut->windowNbr]);
+	}
+
+	if ((vmeOut->xlatedAddrU) || (vmeOut->windowSizeU)
+	    || (vmeOut->pciBusAddrU)) {
+		return (-EINVAL);
+	}
+	switch (vmeOut->windowNbr) {
+	case 0:
+	case 4:
+		if ((vmeOut->xlatedAddrL & 0xFFF) ||
+	    		(vmeOut->windowSizeL & 0xFFF) || 
+			(vmeOut->pciBusAddrL & 0xFFF)) {
+			return (-EINVAL);
+		}
+		break;
+	case 1:
+	case 2:
+	case 3:
+	case 5:
+	case 6:
+	case 7:
+		if ((vmeOut->xlatedAddrL & 0xFFFF) ||
+	    		(vmeOut->windowSizeL & 0xFFFF) || 
+			(vmeOut->pciBusAddrL & 0xFFFF)) {
+			return (-EINVAL);
+		}
+		break;
+	default:
+		return (-EINVAL);
+		break;
+	}
+	if (vmeOut->bcastSelect2esst) {
+		return (-EINVAL);
+	}
+	switch (vmeOut->addrSpace) {
+	case VME_A64:
+	case VME_USER3:
+	case VME_USER4:
+		return (-EINVAL);
+	case VME_A16:
+		temp_ctl |= 0x00000;
+		break;
+	case VME_A24:
+		temp_ctl |= 0x10000;
+		break;
+	case VME_A32:
+		temp_ctl |= 0x20000;
+		break;
+	case VME_CRCSR:
+		temp_ctl |= 0x50000;
+		break;
+	case VME_USER1:
+		temp_ctl |= 0x60000;
+		break;
+	case VME_USER2:
+		temp_ctl |= 0x70000;
+		break;
+	}
+
+	// Disable while we are mucking around
+	writel(0x00000000, vmechip_baseaddr + outCTL[vmeOut->windowNbr]);
+	writel(vmeOut->pciBusAddrL,
+	       vmechip_baseaddr + outBS[vmeOut->windowNbr]);
+	writel(vmeOut->pciBusAddrL + vmeOut->windowSizeL,
+	       vmechip_baseaddr + outBD[vmeOut->windowNbr]);
+	writel(vmeOut->xlatedAddrL - vmeOut->pciBusAddrL,
+	       vmechip_baseaddr + outTO[vmeOut->windowNbr]);
+
+	// Sanity check.
+	if (vmeOut->pciBusAddrL !=
+	    readl(vmechip_baseaddr + outBS[vmeOut->windowNbr])) {
+		printk(KERN_ERR
+		       "ca91c042: out window: %x, failed to configure\n",
+		       vmeOut->windowNbr);
+		return (-EINVAL);
+	}
+
+	if (vmeOut->pciBusAddrL + vmeOut->windowSizeL !=
+	    readl(vmechip_baseaddr + outBD[vmeOut->windowNbr])) {
+		printk(KERN_ERR
+		       "ca91c042: out window: %x, failed to configure\n",
+		       vmeOut->windowNbr);
+		return (-EINVAL);
+	}
+
+	if (vmeOut->xlatedAddrL - vmeOut->pciBusAddrL !=
+	    readl(vmechip_baseaddr + outTO[vmeOut->windowNbr])) {
+		printk(KERN_ERR
+		       "ca91c042: out window: %x, failed to configure\n",
+		       vmeOut->windowNbr);
+		return (-EINVAL);
+	}
+	// Setup CTL register.
+	if (vmeOut->wrPostEnable)
+		temp_ctl |= 0x40000000;
+	if (vmeOut->userAccessType & VME_SUPER)
+		temp_ctl |= 0x001000;
+	if (vmeOut->dataAccessType & VME_PROG)
+		temp_ctl |= 0x004000;
+	if (vmeOut->maxDataWidth == VME_D16)
+		temp_ctl |= 0x00400000;
+	if (vmeOut->maxDataWidth == VME_D32)
+		temp_ctl |= 0x00800000;
+	if (vmeOut->maxDataWidth == VME_D64)
+		temp_ctl |= 0x00C00000;
+	if (vmeOut->xferProtocol & (VME_BLT | VME_MBLT))
+		temp_ctl |= 0x00000100;
+
+	// Write ctl reg without enable
+	writel(temp_ctl, vmechip_baseaddr + outCTL[vmeOut->windowNbr]);
+
+	if (vmeOut->windowEnable)
+		temp_ctl |= 0x80000000;
+
+	writel(temp_ctl, vmechip_baseaddr + outCTL[vmeOut->windowNbr]);
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_get_out_bound
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_get_out_bound(vmeOutWindowCfg_t * vmeOut)
+{
+	int temp_ctl = 0;
+
+	// Verify input data
+	if (vmeOut->windowNbr > 7) {
+		return (-EINVAL);
+	}
+	// Get Window mappings.
+	vmeOut->pciBusAddrL =
+	    readl(vmechip_baseaddr + outBS[vmeOut->windowNbr]);
+	vmeOut->xlatedAddrL =
+	    vmeOut->pciBusAddrL + readl(vmechip_baseaddr +
+					outTO[vmeOut->windowNbr]);
+	vmeOut->windowSizeL =
+	    readl(vmechip_baseaddr + outBD[vmeOut->windowNbr]) -
+	    vmeOut->pciBusAddrL;
+
+	temp_ctl = readl(vmechip_baseaddr + outCTL[vmeOut->windowNbr]);
+
+	// Get Control & BUS attributes
+	if (temp_ctl & 0x40000000)
+		vmeOut->wrPostEnable = 1;
+	if (temp_ctl & 0x001000)
+		vmeOut->userAccessType = VME_SUPER;
+	else
+		vmeOut->userAccessType = VME_USER;
+	if (temp_ctl & 0x004000)
+		vmeOut->dataAccessType = VME_PROG;
+	else
+		vmeOut->dataAccessType = VME_DATA;
+	if (temp_ctl & 0x80000000)
+		vmeOut->windowEnable = 1;
+
+	switch ((temp_ctl & 0x00C00000) >> 22) {
+	case 0:
+		vmeOut->maxDataWidth = VME_D8;
+		break;
+	case 1:
+		vmeOut->maxDataWidth = VME_D16;
+		break;
+	case 2:
+		vmeOut->maxDataWidth = VME_D32;
+		break;
+	case 3:
+		vmeOut->maxDataWidth = VME_D64;
+		break;
+	}
+	if (temp_ctl & 0x00000100)
+		vmeOut->xferProtocol = VME_BLT;
+	else
+		vmeOut->xferProtocol = VME_SCT;
+
+	switch ((temp_ctl & 0x70000) >> 16) {
+	case 0x0:
+		vmeOut->addrSpace = VME_A16;
+		break;
+	case 0x1:
+		vmeOut->addrSpace = VME_A24;
+		break;
+	case 0x2:
+		vmeOut->addrSpace = VME_A32;
+		break;
+	case 0x5:
+		vmeOut->addrSpace = VME_CRCSR;
+		break;
+	case 0x6:
+		vmeOut->addrSpace = VME_USER1;
+		break;
+	case 0x7:
+		vmeOut->addrSpace = VME_USER2;
+		break;
+	}
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_setup_lm
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_setup_lm(vmeLmCfg_t * vmeLm)
+{
+	int temp_ctl = 0;
+
+	if (vmeLm->addrU) {
+		return (-EINVAL);
+	}
+	switch (vmeLm->addrSpace) {
+	case VME_A64:
+	case VME_USER3:
+	case VME_USER4:
+		return (-EINVAL);
+	case VME_A16:
+		temp_ctl |= 0x00000;
+		break;
+	case VME_A24:
+		temp_ctl |= 0x10000;
+		break;
+	case VME_A32:
+		temp_ctl |= 0x20000;
+		break;
+	case VME_CRCSR:
+		temp_ctl |= 0x50000;
+		break;
+	case VME_USER1:
+		temp_ctl |= 0x60000;
+		break;
+	case VME_USER2:
+		temp_ctl |= 0x70000;
+		break;
+	}
+
+	// Disable while we are mucking around
+	writel(0x00000000, vmechip_baseaddr + LM_CTL);
+
+	writel(vmeLm->addr, vmechip_baseaddr + LM_BS);
+
+	// Setup CTL register.
+	if (vmeLm->userAccessType & VME_SUPER)
+		temp_ctl |= 0x00200000;
+	if (vmeLm->userAccessType & VME_USER)
+		temp_ctl |= 0x00100000;
+	if (vmeLm->dataAccessType & VME_PROG)
+		temp_ctl |= 0x00800000;
+	if (vmeLm->dataAccessType & VME_DATA)
+		temp_ctl |= 0x00400000;
+
+	uni_lm_event = 0;
+
+	// Write ctl reg and enable
+	writel(0x80000000 | temp_ctl, vmechip_baseaddr + LM_CTL);
+	temp_ctl = readl(vmechip_baseaddr + LM_CTL);
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_wait_lm
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_wait_lm(vmeLmCfg_t * vmeLm)
+{
+	unsigned long flags;
+	unsigned int tmp;
+
+	spin_lock_irqsave(&lm_lock, flags);
+	tmp = uni_lm_event;
+	spin_unlock_irqrestore(&lm_lock, flags);
+	if (tmp == 0) {
+		if (vmeLm->lmWait < 10)
+			vmeLm->lmWait = 10;
+		interruptible_sleep_on_timeout(&lm_queue, vmeLm->lmWait);
+	}
+	writel(0x00000000, vmechip_baseaddr + LM_CTL);
+	vmeLm->lmEvents = uni_lm_event;
+
+	return (0);
+}
+
+#define	SWIZZLE(X) ( ((X & 0xFF000000) >> 24) | ((X & 0x00FF0000) >>  8) | ((X & 0x0000FF00) <<  8) | ((X & 0x000000FF) << 24))
+
+//-----------------------------------------------------------------------------
+// Function   : uni_do_rmw
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_do_rmw(vmeRmwCfg_t * vmeRmw)
+{
+	int temp_ctl = 0;
+	int tempBS = 0;
+	int tempBD = 0;
+	int tempTO = 0;
+	int vmeBS = 0;
+	int vmeBD = 0;
+	int *rmw_pci_data_ptr = NULL;
+	int *vaDataPtr = NULL;
+	int i;
+	vmeOutWindowCfg_t vmeOut;
+	if (vmeRmw->maxAttempts < 1) {
+		return (-EINVAL);
+	}
+	if (vmeRmw->targetAddrU) {
+		return (-EINVAL);
+	}
+	// Find the PCI address that maps to the desired VME address 
+	for (i = 0; i < 8; i++) {
+		temp_ctl = readl(vmechip_baseaddr + outCTL[i]);
+		if ((temp_ctl & 0x80000000) == 0) {
+			continue;
+		}
+		memset(&vmeOut, 0, sizeof(vmeOut));
+		vmeOut.windowNbr = i;
+		uni_get_out_bound(&vmeOut);
+		if (vmeOut.addrSpace != vmeRmw->addrSpace) {
+			continue;
+		}
+		tempBS = readl(vmechip_baseaddr + outBS[i]);
+		tempBD = readl(vmechip_baseaddr + outBD[i]);
+		tempTO = readl(vmechip_baseaddr + outTO[i]);
+		vmeBS = tempBS + tempTO;
+		vmeBD = tempBD + tempTO;
+		if ((vmeRmw->targetAddr >= vmeBS) &&
+		    (vmeRmw->targetAddr < vmeBD)) {
+			rmw_pci_data_ptr =
+			    (int *)(tempBS + (vmeRmw->targetAddr - vmeBS));
+			vaDataPtr =
+			    (int *)(out_image_va[i] +
+				    (vmeRmw->targetAddr - vmeBS));
+			break;
+		}
+	}
+
+	// If no window - fail.
+	if (rmw_pci_data_ptr == NULL) {
+		return (-EINVAL);
+	}
+	// Setup the RMW registers.
+	writel(0, vmechip_baseaddr + SCYC_CTL);
+	writel(SWIZZLE(vmeRmw->enableMask), vmechip_baseaddr + SCYC_EN);
+	writel(SWIZZLE(vmeRmw->compareData), vmechip_baseaddr + SCYC_CMP);
+	writel(SWIZZLE(vmeRmw->swapData), vmechip_baseaddr + SCYC_SWP);
+	writel((int)rmw_pci_data_ptr, vmechip_baseaddr + SCYC_ADDR);
+	writel(1, vmechip_baseaddr + SCYC_CTL);
+
+	// Run the RMW cycle until either success or max attempts.
+	vmeRmw->numAttempts = 1;
+	while (vmeRmw->numAttempts <= vmeRmw->maxAttempts) {
+
+		if ((readl(vaDataPtr) & vmeRmw->enableMask) ==
+		    (vmeRmw->swapData & vmeRmw->enableMask)) {
+
+			writel(0, vmechip_baseaddr + SCYC_CTL);
+			break;
+
+		}
+		vmeRmw->numAttempts++;
+	}
+
+	// If no success, set num Attempts to be greater than max attempts
+	if (vmeRmw->numAttempts > vmeRmw->maxAttempts) {
+		vmeRmw->numAttempts = vmeRmw->maxAttempts + 1;
+	}
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uniSetupDctlReg
+// Description: 
+//-----------------------------------------------------------------------------
+int uniSetupDctlReg(vmeDmaPacket_t * vmeDma, int *dctlregreturn)
+{
+	unsigned int dctlreg = 0x80;
+	struct vmeAttr *vmeAttr;
+
+	if (vmeDma->srcBus == VME_DMA_VME) {
+		dctlreg = 0;
+		vmeAttr = &vmeDma->srcVmeAttr;
+	} else {
+		dctlreg = 0x80000000;
+		vmeAttr = &vmeDma->dstVmeAttr;
+	}
+
+	switch (vmeAttr->maxDataWidth) {
+	case VME_D8:
+		break;
+	case VME_D16:
+		dctlreg |= 0x00400000;
+		break;
+	case VME_D32:
+		dctlreg |= 0x00800000;
+		break;
+	case VME_D64:
+		dctlreg |= 0x00C00000;
+		break;
+	}
+
+	switch (vmeAttr->addrSpace) {
+	case VME_A16:
+		break;
+	case VME_A24:
+		dctlreg |= 0x00010000;
+		break;
+	case VME_A32:
+		dctlreg |= 0x00020000;
+		break;
+	case VME_USER1:
+		dctlreg |= 0x00060000;
+		break;
+	case VME_USER2:
+		dctlreg |= 0x00070000;
+		break;
+
+	case VME_A64:		// not supported in Universe DMA
+	case VME_CRCSR:
+	case VME_USER3:
+	case VME_USER4:
+		return (-EINVAL);
+		break;
+	}
+	if (vmeAttr->userAccessType == VME_PROG) {
+		dctlreg |= 0x00004000;
+	}
+	if (vmeAttr->dataAccessType == VME_SUPER) {
+		dctlreg |= 0x00001000;
+	}
+	if (vmeAttr->xferProtocol != VME_SCT) {
+		dctlreg |= 0x00000100;
+	}
+	*dctlregreturn = dctlreg;
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_start_dma
+// Description: 
+//-----------------------------------------------------------------------------
+unsigned int
+uni_start_dma(int channel, unsigned int dgcsreg, TDMA_Cmd_Packet * vmeLL)
+{
+	unsigned int val;
+
+	// Setup registers as needed for direct or chained.
+	if (dgcsreg & 0x8000000) {
+		writel(0, vmechip_baseaddr + DTBC);
+		writel((unsigned int)vmeLL, vmechip_baseaddr + DCPP);
+	} else {
+#if	0
+		printk("Starting: DGCS = %08x\n", dgcsreg);
+		printk("Starting: DVA  = %08x\n", readl(&vmeLL->dva));
+		printk("Starting: DLV  = %08x\n", readl(&vmeLL->dlv));
+		printk("Starting: DTBC = %08x\n", readl(&vmeLL->dtbc));
+		printk("Starting: DCTL = %08x\n", readl(&vmeLL->dctl));
+#endif
+		// Write registers 
+		writel(readl(&vmeLL->dva), vmechip_baseaddr + DVA);
+		writel(readl(&vmeLL->dlv), vmechip_baseaddr + DLA);
+		writel(readl(&vmeLL->dtbc), vmechip_baseaddr + DTBC);
+		writel(readl(&vmeLL->dctl), vmechip_baseaddr + DCTL);
+		writel(0, vmechip_baseaddr + DCPP);
+	}
+	vme_sync_data();
+
+	// Start the operation
+	writel(dgcsreg, vmechip_baseaddr + DGCS);
+	vme_sync_data();
+	val = get_tbl();
+	writel(dgcsreg | 0x8000000F, vmechip_baseaddr + DGCS);
+	vme_sync_data();
+	return (val);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_setup_dma
+// Description: 
+//-----------------------------------------------------------------------------
+TDMA_Cmd_Packet *uni_setup_dma(vmeDmaPacket_t * vmeDma)
+{
+	vmeDmaPacket_t *vmeCur;
+	int maxPerPage;
+	int currentLLcount;
+	TDMA_Cmd_Packet *startLL;
+	TDMA_Cmd_Packet *currentLL;
+	TDMA_Cmd_Packet *nextLL;
+	unsigned int dctlreg = 0;
+
+	maxPerPage = PAGE_SIZE / sizeof(TDMA_Cmd_Packet) - 1;
+	startLL = (TDMA_Cmd_Packet *) __get_free_pages(GFP_KERNEL, 0);
+	if (startLL == 0) {
+		return (startLL);
+	}
+	// First allocate pages for descriptors and create linked list
+	vmeCur = vmeDma;
+	currentLL = startLL;
+	currentLLcount = 0;
+	while (vmeCur != 0) {
+		if (vmeCur->pNextPacket != 0) {
+			currentLL->dcpp = (unsigned int)(currentLL + 1);
+			currentLLcount++;
+			if (currentLLcount >= maxPerPage) {
+				currentLL->dcpp =
+				    __get_free_pages(GFP_KERNEL, 0);
+				currentLLcount = 0;
+			}
+			currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
+		} else {
+			currentLL->dcpp = (unsigned int)0;
+		}
+		vmeCur = vmeCur->pNextPacket;
+	}
+
+	// Next fill in information for each descriptor
+	vmeCur = vmeDma;
+	currentLL = startLL;
+	while (vmeCur != 0) {
+		if (vmeCur->srcBus == VME_DMA_VME) {
+			writel(vmeCur->srcAddr, &currentLL->dva);
+			writel(vmeCur->dstAddr, &currentLL->dlv);
+		} else {
+			writel(vmeCur->srcAddr, &currentLL->dlv);
+			writel(vmeCur->dstAddr, &currentLL->dva);
+		}
+		uniSetupDctlReg(vmeCur, &dctlreg);
+		writel(dctlreg, &currentLL->dctl);
+		writel(vmeCur->byteCount, &currentLL->dtbc);
+
+		currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
+		vmeCur = vmeCur->pNextPacket;
+	}
+
+	// Convert Links to PCI addresses.
+	currentLL = startLL;
+	while (currentLL != 0) {
+		nextLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
+		if (nextLL == 0) {
+			writel(1, &currentLL->dcpp);
+		} else {
+			writel((unsigned int)virt_to_bus(nextLL),
+			       &currentLL->dcpp);
+		}
+		vme_flush_line((unsigned long)currentLL);
+		currentLL = nextLL;
+	}
+
+	// Return pointer to descriptors list 
+	return (startLL);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_free_dma
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_free_dma(TDMA_Cmd_Packet * startLL)
+{
+	TDMA_Cmd_Packet *currentLL;
+	TDMA_Cmd_Packet *prevLL;
+	TDMA_Cmd_Packet *nextLL;
+	unsigned int dcppreg;
+
+	// Convert Links to virtual addresses.
+	currentLL = startLL;
+	while (currentLL != 0) {
+		dcppreg = readl(&currentLL->dcpp);
+		dcppreg &= ~6;
+		if (dcppreg & 1) {
+			currentLL->dcpp = 0;
+		} else {
+			currentLL->dcpp = (unsigned int)bus_to_virt(dcppreg);
+		}
+		currentLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
+	}
+
+	// Free all pages associated with the descriptors.
+	currentLL = startLL;
+	prevLL = currentLL;
+	while (currentLL != 0) {
+		nextLL = (TDMA_Cmd_Packet *) currentLL->dcpp;
+		if (currentLL + 1 != nextLL) {
+			free_pages((int)prevLL, 0);
+			prevLL = nextLL;
+		}
+		currentLL = nextLL;
+	}
+
+	// Return pointer to descriptors list 
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_do_dma
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_do_dma(vmeDmaPacket_t * vmeDma)
+{
+	unsigned int dgcsreg = 0;
+	unsigned int dctlreg = 0;
+	int val;
+	int channel, x;
+	vmeDmaPacket_t *curDma;
+	TDMA_Cmd_Packet *dmaLL;
+
+	// Sanity check the VME chain.
+	channel = vmeDma->channel_number;
+	if (channel > 0) {
+		return (-EINVAL);
+	}
+	curDma = vmeDma;
+	while (curDma != 0) {
+		if (curDma->byteCount == 0) {
+			return (-EINVAL);
+		}
+		if (curDma->byteCount >= 0x1000000) {
+			return (-EINVAL);
+		}
+		if ((curDma->srcAddr & 7) != (curDma->dstAddr & 7)) {
+			return (-EINVAL);
+		}
+		switch (curDma->srcBus) {
+		case VME_DMA_PCI:
+			if (curDma->dstBus != VME_DMA_VME) {
+				return (-EINVAL);
+			}
+			break;
+		case VME_DMA_VME:
+			if (curDma->dstBus != VME_DMA_PCI) {
+				return (-EINVAL);
+			}
+			break;
+		default:
+			return (-EINVAL);
+			break;
+		}
+		if (uniSetupDctlReg(curDma, &dctlreg) < 0) {
+			return (-EINVAL);
+		}
+
+		curDma = curDma->pNextPacket;
+		if (curDma == vmeDma) {	// Endless Loop!
+			return (-EINVAL);
+		}
+	}
+
+	// calculate control register
+	if (vmeDma->pNextPacket != 0) {
+		dgcsreg = 0x8000000;
+	} else {
+		dgcsreg = 0;
+	}
+
+	for (x = 0; x < 8; x++) {	// vme block size
+		if ((256 << x) >= vmeDma->maxVmeBlockSize) {
+			break;
+		}
+	}
+	if (x == 8)
+		x = 7;
+	dgcsreg |= (x << 20);
+
+	if (vmeDma->vmeBackOffTimer) {
+		for (x = 1; x < 8; x++) {	// vme timer
+			if ((16 << (x - 1)) >= vmeDma->vmeBackOffTimer) {
+				break;
+			}
+		}
+		if (x == 8)
+			x = 7;
+		dgcsreg |= (x << 16);
+	}
+	// Setup the dma chain
+	dmaLL = uni_setup_dma(vmeDma);
+
+	// Start the DMA
+	if (dgcsreg & 0x8000000) {
+		vmeDma->vmeDmaStartTick =
+		    uni_start_dma(channel, dgcsreg,
+				  (TDMA_Cmd_Packet *) virt_to_phys(dmaLL));
+	} else {
+		vmeDma->vmeDmaStartTick =
+		    uni_start_dma(channel, dgcsreg, dmaLL);
+	}
+
+	wait_event_interruptible(dma_queue[0],
+				 readl(vmechip_baseaddr + DGCS) & 0x800);
+
+	val = readl(vmechip_baseaddr + DGCS);
+	writel(val | 0xF00, vmechip_baseaddr + DGCS);
+
+	vmeDma->vmeDmaStatus = 0;
+	vmeDma->vmeDmaStopTick = uni_dma_irq_time;
+	if (vmeDma->vmeDmaStopTick < vmeDma->vmeDmaStartTick) {
+		vmeDma->vmeDmaElapsedTime =
+		    (0xFFFFFFFF - vmeDma->vmeDmaStartTick) +
+		    vmeDma->vmeDmaStopTick;
+	} else {
+		vmeDma->vmeDmaElapsedTime =
+		    vmeDma->vmeDmaStopTick - vmeDma->vmeDmaStartTick;
+	}
+	vmeDma->vmeDmaElapsedTime -= vmechip_irq_overhead_ticks;
+	vmeDma->vmeDmaElapsedTime /= (tb_speed / 1000000);
+
+	if (!(val & 0x00000800)) {
+		vmeDma->vmeDmaStatus = val & 0x700;
+		printk(KERN_ERR
+		       "ca91c042: DMA Error in DMA_uni_irqhandler DGCS=%08X\n",
+		       val);
+		val = readl(vmechip_baseaddr + DCPP);
+		printk(KERN_ERR "ca91c042: DCPP=%08X\n", val);
+		val = readl(vmechip_baseaddr + DCTL);
+		printk(KERN_ERR "ca91c042: DCTL=%08X\n", val);
+		val = readl(vmechip_baseaddr + DTBC);
+		printk(KERN_ERR "ca91c042: DTBC=%08X\n", val);
+		val = readl(vmechip_baseaddr + DLA);
+		printk(KERN_ERR "ca91c042: DLA=%08X\n", val);
+		val = readl(vmechip_baseaddr + DVA);
+		printk(KERN_ERR "ca91c042: DVA=%08X\n", val);
+
+	}
+	// Free the dma chain
+	uni_free_dma(dmaLL);
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_shutdown
+// Description: Put VME bridge in quiescent state.
+//-----------------------------------------------------------------------------
+void uni_shutdown(void)
+{
+	writel(0, vmechip_baseaddr + LINT_EN);	// Turn off Ints
+
+	// Turn off the windows
+	writel(0x00800000, vmechip_baseaddr + LSI0_CTL);
+	writel(0x00800000, vmechip_baseaddr + LSI1_CTL);
+	writel(0x00800000, vmechip_baseaddr + LSI2_CTL);
+	writel(0x00800000, vmechip_baseaddr + LSI3_CTL);
+	writel(0x00F00000, vmechip_baseaddr + VSI0_CTL);
+	writel(0x00F00000, vmechip_baseaddr + VSI1_CTL);
+	writel(0x00F00000, vmechip_baseaddr + VSI2_CTL);
+	writel(0x00F00000, vmechip_baseaddr + VSI3_CTL);
+	if (vmechip_revision >= 2) {
+		writel(0x00800000, vmechip_baseaddr + LSI4_CTL);
+		writel(0x00800000, vmechip_baseaddr + LSI5_CTL);
+		writel(0x00800000, vmechip_baseaddr + LSI6_CTL);
+		writel(0x00800000, vmechip_baseaddr + LSI7_CTL);
+		writel(0x00F00000, vmechip_baseaddr + VSI4_CTL);
+		writel(0x00F00000, vmechip_baseaddr + VSI5_CTL);
+		writel(0x00F00000, vmechip_baseaddr + VSI6_CTL);
+		writel(0x00F00000, vmechip_baseaddr + VSI7_CTL);
+	}
+}
+
+//-----------------------------------------------------------------------------
+// Function   : uni_init()
+// Description: 
+//-----------------------------------------------------------------------------
+int uni_init(void)
+{
+	int result;
+	unsigned int tmp;
+	unsigned int crcsr_addr;
+	unsigned int irqOverHeadStart;
+	int overHeadTicks;
+
+	uni_shutdown();
+
+	// Write to Misc Register
+	// Set VME Bus Time-out
+	//   Arbitration Mode
+	//   DTACK Enable
+	tmp = readl(vmechip_baseaddr + MISC_CTL) & 0x0832BFFF;
+	tmp |= 0x76040000;
+	writel(tmp, vmechip_baseaddr + MISC_CTL);
+	if (tmp & 0x20000) {
+		vme_syscon = 1;
+	} else {
+		vme_syscon = 0;
+	}
+
+	// Clear DMA status log
+	writel(0x00000F00, vmechip_baseaddr + DGCS);
+	// Clear and enable error log
+	writel(0x00800000, vmechip_baseaddr + L_CMDERR);
+	// Turn off location monitor
+	writel(0x00000000, vmechip_baseaddr + LM_CTL);
+
+	// Initialize crcsr map
+	if (vme_slotnum != -1) {
+		writel(vme_slotnum << 27, vmechip_baseaddr + VCSR_BS);
+	}
+	crcsr_addr = readl(vmechip_baseaddr + VCSR_BS) >> 8;
+	writel((unsigned int)vmechip_interboard_datap - crcsr_addr,
+	       vmechip_baseaddr + VCSR_TO);
+	if (vme_slotnum != -1) {
+		writel(0x80000000, vmechip_baseaddr + VCSR_CTL);
+	}
+	// Turn off interrupts
+	writel(0x00000000, vmechip_baseaddr + LINT_EN);	// Disable interrupts in the Universe first
+	writel(0x00FFFFFF, vmechip_baseaddr + LINT_STAT);	// Clear Any Pending Interrupts
+	writel(0x00000000, vmechip_baseaddr + VINT_EN);	// Disable interrupts in the Universe first
+
+	result =
+	    request_irq(vmechip_irq, uni_irqhandler, IRQF_SHARED,
+			"VMEBus (ca91c042)", vmechip_baseaddr);
+	if (result) {
+		printk(KERN_ERR
+		       "ca91c042: can't get assigned pci irq vector %02X\n",
+		       vmechip_irq);
+		return (0);
+	} else {
+		writel(0x0000, vmechip_baseaddr + LINT_MAP0);	// Map all ints to 0
+		writel(0x0000, vmechip_baseaddr + LINT_MAP1);	// Map all ints to 0
+		writel(0x0000, vmechip_baseaddr + LINT_MAP2);	// Map all ints to 0
+	}
+
+	// Enable DMA, mailbox, VIRQ & LM Interrupts
+	if (vme_syscon)
+		tmp = 0x00FF07FE;
+	else
+		tmp = 0x00FF0700;
+	writel(tmp, vmechip_baseaddr + LINT_EN);
+
+	// Do a quick sanity test of the bridge
+	if (readl(vmechip_baseaddr + LINT_EN) != tmp) {
+		return (0);
+	}
+	if (readl(vmechip_baseaddr + PCI_CLASS_REVISION) != 0x06800002) {
+		return (0);
+	}
+	for (tmp = 1; tmp < 0x80000000; tmp = tmp << 1) {
+		writel(tmp, vmechip_baseaddr + SCYC_EN);
+		writel(~tmp, vmechip_baseaddr + SCYC_CMP);
+		if (readl(vmechip_baseaddr + SCYC_EN) != tmp) {
+			return (0);
+		}
+		if (readl(vmechip_baseaddr + SCYC_CMP) != ~tmp) {
+			return (0);
+		}
+	}
+
+	// do a mail box interrupt to calibrate the interrupt overhead.
+
+	irqOverHeadStart = get_tbl();
+	writel(0, vmechip_baseaddr + MBOX1);
+	for (tmp = 0; tmp < 10; tmp++) {
+		vme_sync_data();
+	}
+
+	irqOverHeadStart = get_tbl();
+	writel(0, vmechip_baseaddr + MBOX1);
+	for (tmp = 0; tmp < 10; tmp++) {
+		vme_sync_data();
+	}
+
+	overHeadTicks = uni_irq_time - irqOverHeadStart;
+	if (overHeadTicks > 0) {
+		vmechip_irq_overhead_ticks = overHeadTicks;
+	} else {
+		vmechip_irq_overhead_ticks = 1;
+	}
+	return (1);
+}
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/vme/ca91c042.h linux-2.6.29.6.mod/drivers/vme/ca91c042.h
--- linux-2.6.29.6.orig/drivers/vme/ca91c042.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/vme/ca91c042.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,390 @@
+/*
+ * ca91c042.h
+ *
+ * Support for the Tundra Universe 1 and Universe II VME bridge chips
+ *
+ * Authors: Tom Armistead, Ajit Prem 
+ * Copyright 2004-2007 Motorola Inc.
+ *
+ * Derived from ca91c042.h by Michael Wyrick
+ *
+ * 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.
+ */
+
+#ifndef _ca91c042_h
+#define _ca91c042_h
+
+//-----------------------------------------------------------------------------
+// Public Functions
+//-----------------------------------------------------------------------------
+// This is the typedef for a VmeIrqHandler
+typedef void (*TirqHandler) (int vmeirq, int vector, void *dev_id,
+			     struct pt_regs * regs);
+// This is the typedef for a DMA Transfer Callback function
+typedef void (*TDMAcallback) (int status);
+
+//  Returns the PCI baseaddress of the Universe chip
+char *Universe_BaseAddr(void);
+//  Returns the PCI IRQ That the universe is using
+int Universe_IRQ(void);
+
+char *mapvme(unsigned int pci, unsigned int vme, unsigned int size,
+	     int image, int ctl);
+void unmapvme(char *ptr, int image);
+
+// Interrupt Stuff
+void enable_vmeirq(unsigned int irq);
+void disable_vmeirq(unsigned int irq);
+int request_vmeirq(unsigned int irq, TirqHandler);
+void free_vmeirq(unsigned int irq);
+
+// DMA Stuff
+
+int VME_Bus_Error(void);
+int uni_procinfo(char *);
+
+#define IRQ_VOWN    0x0001
+#define IRQ_VIRQ1   0x0002
+#define IRQ_VIRQ2   0x0004
+#define IRQ_VIRQ3   0x0008
+#define IRQ_VIRQ4   0x0010
+#define IRQ_VIRQ5   0x0020
+#define IRQ_VIRQ6   0x0040
+#define IRQ_VIRQ7   0x0080
+#define IRQ_DMA     0x0100
+#define IRQ_LERR    0x0200
+#define IRQ_VERR    0x0400
+#define IRQ_res     0x0800
+#define IRQ_IACK    0x1000
+#define IRQ_SWINT   0x2000
+#define IRQ_SYSFAIL 0x4000
+#define IRQ_ACFAIL  0x8000
+
+// See Page 2-77 in the Universe User Manual
+typedef struct {
+	unsigned int dctl;	// DMA Control
+	unsigned int dtbc;	// Transfer Byte Count
+	unsigned int dlv;	// PCI Address
+	unsigned int res1;	// Reserved
+	unsigned int dva;	// Vme Address
+	unsigned int res2;	// Reserved
+	unsigned int dcpp;	// Pointer to Numed Cmd Packet with rPN
+	unsigned int res3;	// Reserved
+} TDMA_Cmd_Packet;
+
+/*
+ * Below here is normaly not used by a user module
+ */
+#define  DMATIMEOUT 2*HZ;
+
+#define CONFIG_REG_SPACE        0xA0000000
+
+/* Universe Register Offsets */
+/* general PCI configuration registers */
+#define UNIV_PCI_ID             0x000
+#define UNIV_PCI_CSR            0x004
+#define UNIV_PCI_CLASS          0x008
+#define UNIV_BM_PCI_CLASS_BASE          0xFF000000
+#define UNIV_OF_PCI_CLASS_BASE          24
+#define UNIV_BM_PCI_CLASS_SUB           0x00FF0000
+#define UNIV_OF_PCI_CLASS_SUB           16
+#define UNIV_BM_PCI_CLASS_PROG          0x0000FF00
+#define UNIV_OF_PCI_CLASS_PROG          8
+#define UNIV_BM_PCI_CLASS_RID           0x000000FF
+#define UNIV_OF_PCI_CLASS_RID           0
+
+#define UNIV_OF_PCI_CLASS_RID_UNIVERSE_I 0
+#define UNIV_OF_PCI_CLASS_RID_UNIVERSE_II 1
+
+#define UNIV_PCI_MISC0          0x00C
+#define UNIV_BM_PCI_MISC0_BISTC         0x80000000
+#define UNIV_BM_PCI_MISC0_SBIST         0x60000000
+#define UNIV_BM_PCI_MISC0_CCODE         0x0F000000
+#define UNIV_BM_PCI_MISC0_MFUNCT        0x00800000
+#define UNIV_BM_PCI_MISC0_LAYOUT        0x007F0000
+#define UNIV_BM_PCI_MISC0_LTIMER        0x0000FF00
+#define UNIV_OF_PCI_MISC0_LTIMER        8
+#define UNIV_PCI_BS             0x010
+#define UNIV_PCI_MISC1          0x03C
+
+#define UNIV_BM_LSI_CTL_EN      0x80000000
+#define UNIV_BM_LSI_CTL_PWEN    0x40000000
+#define UNIV_BM_LSI_CTL_VDW     0x00C00000
+#define UNIV_OF_LSI_CTL_VDW     22
+#define UNIV_BM_LSI_CTL_VAS     0x00070000
+#define UNIV_OF_LSI_CTL_VAS     16
+#define UNIV_BM_LSI_CTL_PGM     0x0000C000
+#define UNIV_OF_LSI_CTL_PGM     14
+#define UNIV_BM_LSI_CTL_SUPER   0x00003000
+#define UNIV_OF_LSI_CTL_SUPER   12
+#define UNIV_BM_LSI_CTL_VCT     0x00000100
+#define UNIV_BM_LSI_CTL_LAS     0x00000003
+#define UNIV_OF_LSI_CTL_LAS     0
+#define UNIV_BM_LSI_CTL_RESERVED (~ (UNIV_BM_LSI_CTL_EN | UNIV_BM_LSI_CTL_PWEN | UNIV_BM_LSI_CTL_VDW | UNIV_BM_LSI_CTL_VAS | UNIV_BM_LSI_CTL_PGM | UNIV_BM_LSI_CTL_SUPER | UNIV_BM_LSI_CTL_VCT | UNIV_BM_LSI_CTL_LAS))
+
+#define PCI_SIZE_8	    0x0001
+#define PCI_SIZE_16	    0x0002
+#define PCI_SIZE_32	    0x0003
+
+#define IOCTL_SET_CTL 	0xF001
+#define IOCTL_SET_BS	0xF002
+#define IOCTL_SET_BD	0xF003
+#define IOCTL_SET_TO	0xF004
+#define IOCTL_PCI_SIZE  0xF005
+#define IOCTL_SET_MODE 	0xF006
+#define IOCTL_SET_WINT  0xF007	// Wait for interrupt before read
+
+#define LSI0_CTL	0x0100
+#define LSI0_BS		0x0104
+#define LSI0_BD		0x0108
+#define LSI0_TO		0x010C
+
+#define LSI1_CTL	      0x0114
+#define LSI1_BS		      0x0118
+#define LSI1_BD		      0x011C
+#define LSI1_TO		      0x0120
+
+#define LSI2_CTL	      0x0128
+#define LSI2_BS		      0x012C
+#define LSI2_BD		      0x0130
+#define LSI2_TO		      0x0134
+
+#define LSI3_CTL	      0x013C
+#define LSI3_BS		      0x0140
+#define LSI3_BD		      0x0144
+#define LSI3_TO		      0x0148
+
+#define LSI4_CTL	      0x01A0
+#define LSI4_BS		      0x01A4
+#define LSI4_BD		      0x01A8
+#define LSI4_TO		      0x01AC
+
+#define LSI5_CTL	      0x01B4
+#define LSI5_BS		      0x01B8
+#define LSI5_BD		      0x01BC
+#define LSI5_TO		      0x01C0
+
+#define LSI6_CTL	      0x01C8
+#define LSI6_BS		      0x01CC
+#define LSI6_BD		      0x01D0
+#define LSI6_TO		      0x01D4
+
+#define LSI7_CTL	      0x01DC
+#define LSI7_BS		      0x01E0
+#define LSI7_BD		      0x01E4
+#define LSI7_TO		      0x01E8
+
+#define SCYC_CTL		0x0170
+#define SCYC_ADDR		0x0174
+#define SCYC_EN			0x0178
+#define SCYC_CMP		0x017C
+#define SCYC_SWP		0x0180
+#define LMISC			0x0184
+#define UNIV_BM_LMISC_CRT               0xF0000000
+#define UNIV_OF_LMISC_CRT               28
+#define UNIV_BM_LMISC_CWT               0x0F000000
+#define UNIV_OF_LMISC_CWT               24
+#define SLSI		        0x0188
+#define UNIV_BM_SLSI_EN                 0x80000000
+#define UNIV_BM_SLSI_PWEN               0x40000000
+#define UNIV_BM_SLSI_VDW                0x00F00000
+#define UNIV_OF_SLSI_VDW                20
+#define UNIV_BM_SLSI_PGM                0x0000F000
+#define UNIV_OF_SLSI_PGM                12
+#define UNIV_BM_SLSI_SUPER              0x00000F00
+#define UNIV_OF_SLSI_SUPER              8
+#define UNIV_BM_SLSI_BS                 0x000000F6
+#define UNIV_OF_SLSI_BS                 2
+#define UNIV_BM_SLSI_LAS                0x00000003
+#define UNIV_OF_SLSI_LAS                0
+#define UNIV_BM_SLSI_RESERVED           0x3F0F0000
+#define L_CMDERR		0x018C
+#define LAERR		        0x0190
+
+#define DCTL		        0x0200
+#define DTBC		        0x0204
+#define DLA			0x0208
+#define DVA			0x0210
+#define DCPP		        0x0218
+#define DGCS		        0x0220
+#define D_LLUE			0x0224
+
+#define LINT_EN		      0x0300
+#define UNIV_BM_LINT_ACFAIL             0x00008000
+#define UNIV_BM_LINT_SYSFAIL            0x00004000
+#define UNIV_BM_LINT_SW_INT             0x00002000
+#define UNIV_BM_LINT_SW_IACK            0x00001000
+#define UNIV_BM_LINT_VERR               0x00000400
+#define UNIV_BM_LINT_LERR               0x00000200
+#define UNIV_BM_LINT_DMA                0x00000100
+#define UNIV_BM_LINT_LM                 0x00F00000
+#define UNIV_BM_LINT_MBOX               0x000F0000
+#define UNIV_BM_LINT_VIRQ               0x000000FE
+#define UNIV_BM_LINT_VIRQ7              0x00000080
+#define UNIV_BM_LINT_VIRQ6              0x00000040
+#define UNIV_BM_LINT_VIRQ5              0x00000020
+#define UNIV_BM_LINT_VIRQ4              0x00000010
+#define UNIV_BM_LINT_VIRQ3              0x00000008
+#define UNIV_BM_LINT_VIRQ2              0x00000004
+#define UNIV_BM_LINT_VIRQ1              0x00000002
+#define UNIV_BM_LINT_VOWN               0x00000001
+#define LINT_STAT	      0x0304
+#define LINT_MAP0	      0x0308
+#define LINT_MAP1	      0x030C
+#define VINT_EN		      0x0310
+#define VINT_STAT	      0x0314
+#define VINT_MAP0	      0x0318
+#define VINT_MAP1	      0x031C
+#define STATID		      0x0320
+#define V1_STATID	      0x0324
+#define V2_STATID	      0x0328
+#define V3_STATID	      0x032C
+#define V4_STATID	      0x0330
+#define V5_STATID	      0x0334
+#define V6_STATID	      0x0338
+#define V7_STATID	      0x033C
+#define LINT_MAP2	      0x0340
+#define VINT_MAP2	      0x0344
+
+#define MBOX0	              0x0348
+#define MBOX1	              0x034C
+#define MBOX2		      0x0350
+#define MBOX3		      0x0354
+#define SEMA0		      0x0358
+#define SEMA1		      0x035C
+
+#define MAST_CTL	      0x0400
+#define UNIV_BM_MAST_CTL_MAXRTRY        0xF0000000
+#define UNIV_OF_MAST_CTL_MAXRTRY        28
+#define UNIV_BM_MAST_CTL_PWON           0x0F000000
+#define UNIV_OF_MAST_CTL_PWON           24
+#define UNIV_BM_MAST_CTL_VRL            0x00C00000
+#define UNIV_OF_MAST_CTL_VRL            22
+#define UNIV_BM_MAST_CTL_VRM            0x00200000
+#define UNIV_BM_MAST_CTL_VREL           0x00100000
+#define UNIV_BM_MAST_CTL_VOWN           0x00080000
+#define UNIV_BM_MAST_CTL_VOWN_ACK       0x00040000
+#define UNIV_BM_MAST_CTL_PABS           0x00001000
+#define UNIV_BM_MAST_CTL_BUS_NO         0x0000000F
+#define UNIV_OF_MAST_CTL_BUS_NO         0
+
+#define MISC_CTL	      0x0404
+#define UNIV_BM_MISC_CTL_VBTO           0xF0000000
+#define UNIV_OF_MISC_CTL_VBTO           28
+#define UNIV_BM_MISC_CTL_VARB           0x04000000
+#define UNIV_BM_MISC_CTL_VARBTO         0x03000000
+#define UNIV_OF_MISC_CTL_VARBTO         24
+#define UNIV_BM_MISC_CTL_SW_LRST        0x00800000
+#define UNIV_BM_MISC_CTL_SW_SRST        0x00400000
+#define UNIV_BM_MISC_CTL_BI             0x00100000
+#define UNIV_BM_MISC_CTL_ENGBI          0x00080000
+#define UNIV_BM_MISC_CTL_RESCIND        0x00040000
+#define UNIV_BM_MISC_CTL_SYSCON         0x00020000
+#define UNIV_BM_MISC_CTL_V64AUTO        0x00010000
+#define UNIV_BM_MISC_CTL_RESERVED       0x0820FFFF
+
+#define MISC_STAT	      0x0408
+#define UNIV_BM_MISC_STAT_ENDIAN        0x80000000
+#define UNIV_BM_MISC_STAT_LCLSIZE       0x40000000
+#define UNIV_BM_MISC_STAT_DY4AUTO       0x08000000
+#define UNIV_BM_MISC_STAT_MYBBSY        0x00200000
+#define UNIV_BM_MISC_STAT_DY4DONE       0x00080000
+#define UNIV_BM_MISC_STAT_TXFE          0x00040000
+#define UNIV_BM_MISC_STAT_RXFE          0x00020000
+#define UNIV_BM_MISC_STAT_DY4AUTOID     0x0000FF00
+#define UNIV_OF_MISC_STAT_DY4AUTOID     8
+
+#define USER_AM		      0x040C
+
+#define VSI0_CTL	      0x0F00
+#define VSI0_BS		      0x0F04
+#define VSI0_BD		      0x0F08
+#define VSI0_TO		      0x0F0C
+
+#define VSI1_CTL	      0x0F14
+#define VSI1_BS		      0x0F18
+#define VSI1_BD		      0x0F1C
+#define VSI1_TO		      0x0F20
+
+#define VSI2_CTL	      0x0F28
+#define VSI2_BS		      0x0F2C
+#define VSI2_BD		      0x0F30
+#define VSI2_TO		      0x0F34
+
+#define VSI3_CTL	      0x0F3C
+#define VSI3_BS		      0x0F40
+#define VSI3_BD		      0x0F44
+#define VSI3_TO		      0x0F48
+
+#define LM_CTL		      0x0F64
+#define LM_BS		      0x0F68
+
+#define VRAI_CTL	      0x0F70
+#define UNIV_BM_VRAI_CTL_EN             0x80000000
+#define UNIV_BM_VRAI_CTL_PGM            0x00C00000
+#define UNIV_OF_VRAI_CTL_PGM            22
+#define UNIV_BM_VRAI_CTL_SUPER          0x00300000
+#define UNIV_OF_VRAI_CTL_SUPER          20
+#define UNIV_BM_VRAI_CTL_VAS            0x00030000
+#define UNIV_OF_VRAI_CTL_VAS            16
+
+#define VRAI_BS		      0x0F74
+#define VCSR_CTL	      0x0F80
+#define VCSR_TO		      0x0F84
+#define V_AMERR		      0x0F88
+#define VAERR			0x0F8C
+
+#define VSI4_CTL	      0x0F90
+#define VSI4_BS		      0x0F94
+#define VSI4_BD		      0x0F98
+#define VSI4_TO		      0x0F9C
+
+#define VSI5_CTL	      0x0FA4
+#define VSI5_BS		      0x0FA8
+#define VSI5_BD		      0x0FAC
+#define VSI5_TO		      0x0FB0
+
+#define VSI6_CTL	      0x0FB8
+#define VSI6_BS		      0x0FBC
+#define VSI6_BD		      0x0FC0
+#define VSI6_TO		      0x0FC4
+
+#define VSI7_CTL	      0x0FCC
+#define VSI7_BS		      0x0FD0
+#define VSI7_BD		      0x0FD4
+#define VSI7_TO		      0x0FD8
+
+#define VCSR_CLR	      0x0FF4
+#define VCSR_SET	      0x0FF8
+#define VCSR_BS		      0x0FFC
+
+// DMA General Control/Status Register DGCS (0x220)
+// 32-24 ||  GO   | STOPR | HALTR |   0   || CHAIN |   0   |   0   |   0   ||
+// 23-16 ||              VON              ||             VOFF              ||
+// 15-08 ||  ACT  | STOP  | HALT  |   0   || DONE  | LERR  | VERR  | P_ERR ||
+// 07-00 ||   0   | INT_S | INT_H |   0   || I_DNE | I_LER | I_VER | I_PER ||
+
+// VON - Length Per DMA VMEBus Transfer
+//  0000 = None
+//  0001 = 256 Bytes
+//  0010 = 512 
+//  0011 = 1024
+//  0100 = 2048
+//  0101 = 4096
+//  0110 = 8192
+//  0111 = 16384
+
+// VOFF - wait between DMA tenures
+//  0000 = 0    us
+//  0001 = 16   
+//  0010 = 32   
+//  0011 = 64   
+//  0100 = 128  
+//  0101 = 256  
+//  0110 = 512  
+//  0111 = 1024 
+
+#endif				/* _ca91c042_h */
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/vme/Kconfig linux-2.6.29.6.mod/drivers/vme/Kconfig
--- linux-2.6.29.6.orig/drivers/vme/Kconfig	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/vme/Kconfig	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,69 @@
+#
+# VME bridge device configuration
+#
+
+menu "VME Bridge devices"
+	depends on (MVME5100 || MVME5500 || MVME6100 || MVME3100 || MVME7100 || MVME4100) 
+
+config VME_BRIDGE
+	tristate "VME Bridge Support"
+	depends on (MVME5100 || MVME5500 || MVME6100 || MVME3100 || MVME7100 || MVME4100)
+	help
+	  If you say Y here you get support for the CA91C042 (Universe I/II)
+          and Tundra TSI148 VME bridge chips. If you have "udev" correctly 
+          configured in your root file system the required device nodes will 
+	  get created automatically. Otherwise, create the following character 
+          special files with major number 221 using mknod ("man mknod"). 
+          For details, refer to the VME Driver User's Guide.
+
+		mknod /dev/vme_m0  c 221 0
+		mknod /dev/vme_m1  c 221 1
+		mknod /dev/vme_m2  c 221 2
+		mknod /dev/vme_m3  c 221 3
+		mknod /dev/vme_m4  c 221 4
+		mknod /dev/vme_m5  c 221 5
+		mknod /dev/vme_m6  c 221 6
+		mknod /dev/vme_m7  c 221 7
+		mknod /dev/vme_s0  c 221 8
+		mknod /dev/vme_s1  c 221 9
+		mknod /dev/vme_s2  c 221 10
+		mknod /dev/vme_s3  c 221 11
+		mknod /dev/vme_s4  c 221 12
+		mknod /dev/vme_s5  c 221 13
+		mknod /dev/vme_s6  c 221 14
+		mknod /dev/vme_s7  c 221 15
+		mknod /dev/vme_dma0 c 221 16
+		mknod /dev/vme_dma1 c 221 17
+		mknod /dev/vme_ctl  c 221 32
+		mknod /dev/vme_regs c 221 33
+		mknod /dev/vme_rmw0 c 221 34
+		mknod /dev/vme_lm0  c 221 35
+
+	  If unsure, say N.
+
+config VME_BRIDGE_BOOTMEM
+	bool "VME Bridge bootmem"
+	depends on VME_BRIDGE
+	default n
+	help
+	  If you say Y here, the VME bridge driver will get memory for 
+	  inbound window 7 using the alloc_bootmem* API instead of the 
+	  standard DMA API. You want to say Y here if you want 
+	  a huge window opened up where you would run into a -ENOMEM error 
+          if you tried to get this memory dynamically. Memory for other 
+          inbound windows will still get dynamically allocated, when 
+          requested, using the DMA API.
+
+config VME_BRIDGE_BOOTMEM_SIZE
+	int "VME Bridge bootmem size"
+	depends on VME_BRIDGE_BOOTMEM
+	range 8 512
+	default "8"
+	help
+	  The amount of boot memory, in megabytes, to be permanently 
+          allocated for inbound window 7. While this parameter allows 
+          you to ask for upto 512M, the amount of memory that will be 
+          allocated is capped at half the total physical memory or 
+          the maximum that the alloc_bootmem() call makes available.
+
+endmenu
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/vme/Makefile linux-2.6.29.6.mod/drivers/vme/Makefile
--- linux-2.6.29.6.orig/drivers/vme/Makefile	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/vme/Makefile	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,8 @@
+#
+# Makefile for the VME bridge device drivers.
+#
+
+vmemod-objs		:= vmelinux.o vmedrv.o tsi148.o ca91c042.o
+
+obj-$(CONFIG_VME_BRIDGE) += vmemod.o 
+
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/vme/tsi148.c linux-2.6.29.6.mod/drivers/vme/tsi148.c
--- linux-2.6.29.6.orig/drivers/vme/tsi148.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/vme/tsi148.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,1858 @@
+/*
+ * tsi148.c
+ *
+ * Support for the Tundra TSI148 VME Bridge Chip
+ *
+ * Authors: Tom Armistead, Ajit Prem
+ * Copyright 2004-2007 Motorola Inc.
+ * Copyright 2008 Emerson Network Power Embedded Computing, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <asm/time.h>
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include "vmedrv.h"
+#include "tsi148.h"
+
+extern struct vmeSharedData *vmechip_interboard_data;
+extern dma_addr_t vmechip_interboard_datap;
+extern const int vmechip_revision;
+extern const int vmechip_devid;
+extern const int vmechip_irq;
+extern int vmechip_irq_overhead_ticks;
+extern void __iomem *vmechip_baseaddr;
+extern const int vme_slotnum;
+extern int vme_syscon;
+extern char *in_image_ba[];
+extern int in_image_size[];
+extern int in_image_mapped[];
+extern dma_addr_t in_image_pa[];
+extern unsigned int out_image_va[];
+extern unsigned int vme_irqlog[8][0x100];
+extern struct pci_dev *vme_pci_dev;
+
+extern wait_queue_head_t dma_queue[];
+extern wait_queue_head_t lm_queue;
+extern wait_queue_head_t mbox_queue;
+extern wait_queue_head_t vmeint_queue[];
+
+extern void vme_sync_data(void);
+extern void vme_flush_range(unsigned long, unsigned long);
+extern int tb_speed;
+
+unsigned int tempe_irq_time;
+unsigned int tempe_dma_irq_time[2];
+unsigned int tempe_lm_event;
+
+static spinlock_t lm_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ *  add64hi - calculate upper 32 bits of 64 bit addition operation.
+ */
+
+static unsigned int
+add64hi(unsigned int lo0, unsigned int hi0, unsigned int lo1, unsigned int hi1)
+{
+	if ((lo1 + lo0) < lo1) {
+		return (hi0 + hi1 + 1);
+	}
+	return (hi0 + hi1);
+}
+
+/*
+ *  sub64hi - calculate upper 32 bits of 64 bit subtraction operation.
+ */
+
+static int
+sub64hi(unsigned int lo0, unsigned int hi0, unsigned int lo1, unsigned int hi1)
+{
+	if (lo0 < lo1) {
+		return (hi0 - hi1 - 1);
+	}
+	return (hi0 - hi1);
+}
+
+/*
+ *  tsi148_procinfo()
+ */
+
+int tsi148_procinfo(char *buf)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	char *p;
+	unsigned int i;
+
+	p = buf;
+
+	p += sprintf(p, "\n");
+	/* Display outbound decoders */
+	p += sprintf(p, "Local Control and Status Register Group (LCSR):\n");
+	p += sprintf(p, "\nOutbound Translations:\n");
+
+	p += sprintf(p,
+		     "No. otat         otsau:otsal        oteau:oteal         otofu:otofl\n");
+	for (i = 0; i < 8; i += 1) {
+		p += sprintf(p, "O%d: %08X  %08X:%08X  %08X:%08X  %08X:%08X\n",
+			     i,
+			     p_tempe->lcsr.outboundTranslation[i].otat,
+			     p_tempe->lcsr.outboundTranslation[i].otsau,
+			     p_tempe->lcsr.outboundTranslation[i].otsal,
+			     p_tempe->lcsr.outboundTranslation[i].oteau,
+			     p_tempe->lcsr.outboundTranslation[i].oteal,
+			     p_tempe->lcsr.outboundTranslation[i].otofu,
+			     p_tempe->lcsr.outboundTranslation[i].otofl);
+	}
+
+	/* Display inbound decoders */
+	p += sprintf(p, "\nInbound Translations:\n");
+	p += sprintf(p,
+		     "No. itat         itsau:itsal        iteau:iteal         itofu:itofl\n");
+	for (i = 0; i < 8; i += 1) {
+		p += sprintf(p, "O%d: %08X  %08X:%08X  %08X:%08X  %08X:%08X\n",
+			     i,
+			     p_tempe->lcsr.inboundTranslation[i].itat,
+			     p_tempe->lcsr.inboundTranslation[i].itsau,
+			     p_tempe->lcsr.inboundTranslation[i].itsal,
+			     p_tempe->lcsr.inboundTranslation[i].iteau,
+			     p_tempe->lcsr.inboundTranslation[i].iteal,
+			     p_tempe->lcsr.inboundTranslation[i].itofu,
+			     p_tempe->lcsr.inboundTranslation[i].itofl);
+	}
+	p += sprintf(p, "\nVME Bus Control:\n");
+	p += sprintf(p, "\tvmctrl  0x%08x\n", p_tempe->lcsr.vmctrl);
+	p += sprintf(p, "\tvctrl   0x%08x\n", p_tempe->lcsr.vctrl);
+	p += sprintf(p, "\tvstat   0x%08x\n", p_tempe->lcsr.vstat);
+	p += sprintf(p, "PCI Status:\n");
+	p += sprintf(p, "\tpstat 0x%08x\n", p_tempe->lcsr.pstat);
+	p += sprintf(p, "VME Exception Status:\n");
+	p += sprintf(p, "\tveau:veal 0x%08x:0x%08x\n", p_tempe->lcsr.veau,
+		     p_tempe->lcsr.veal);
+	p += sprintf(p, "\tveat 0x%08x\n", p_tempe->lcsr.veat);
+	p += sprintf(p, "PCI Error Status:\n");
+	p += sprintf(p, "\tedpau:edpal 0x%08x:0x%08x\n", p_tempe->lcsr.edpau,
+		     p_tempe->lcsr.edpal);
+	p += sprintf(p, "\tedpxa 0x%08x\n", p_tempe->lcsr.edpxa);
+	p += sprintf(p, "\tedpxs 0x%08x\n", p_tempe->lcsr.edpxs);
+	p += sprintf(p, "\tedpat 0x%08x\n", p_tempe->lcsr.edpat);
+	p += sprintf(p, "Inbound Translation GCSR:\n");
+	p += sprintf(p, "\tgbau:gbal 0x%08x:0x%08x\n", p_tempe->lcsr.gbau,
+		     p_tempe->lcsr.gbal);
+	p += sprintf(p, "\tgcsrat 0x%08x\n", p_tempe->lcsr.gcsrat);
+	p += sprintf(p, "Inbound Translation CRG:\n");
+	p += sprintf(p, "\tcbau:cbal 0x%08x:0x%08x\n", p_tempe->lcsr.cbau,
+		     p_tempe->lcsr.cbal);
+	p += sprintf(p, "\tcsrat 0x%08x\n", p_tempe->lcsr.csrat);
+	p += sprintf(p, "Inbound Translation CR/CSR:\n");
+	p += sprintf(p, "\tcrou:crol 0x%08x:0x%08x\n", p_tempe->lcsr.crou,
+		     p_tempe->lcsr.crol);
+	p += sprintf(p, "\tcrat 0x%08x\n", p_tempe->lcsr.crat);
+	p += sprintf(p, "Inbound Translation Location Monitor:\n");
+	p += sprintf(p, "\tlmbau:lmbal 0x%08x:0x%08x:\n", p_tempe->lcsr.lmbau,
+		     p_tempe->lcsr.lmbal);
+	p += sprintf(p, "\tlmat 0x%08x\n", p_tempe->lcsr.lmat);
+	p += sprintf(p, "Interrupt Control:\n");
+	p += sprintf(p, "\tvicr  0x%08x\n", p_tempe->lcsr.vicr);
+	p += sprintf(p, "\tinten 0x%08x\n", p_tempe->lcsr.inten);
+	p += sprintf(p, "\tinteo 0x%08x\n", p_tempe->lcsr.inteo);
+	p += sprintf(p, "\tints  0x%08x\n", p_tempe->lcsr.ints);
+	p += sprintf(p, "\tintc  0x%08x\n", p_tempe->lcsr.intc);
+	p += sprintf(p, "\tintm1 0x%08x\n", p_tempe->lcsr.intm1);
+	p += sprintf(p, "\tintm2 0x%08x\n", p_tempe->lcsr.intm2);
+
+	p += sprintf(p, "DMA Control:\n");
+	p += sprintf(p, "\tdctl0  0x%08x\n", p_tempe->lcsr.dma[0].dctl);
+	p += sprintf(p, "\tdctl1  0x%08x\n", p_tempe->lcsr.dma[1].dctl);
+
+	p += sprintf(p, "\nPCFS Register Group:\n");
+	p += sprintf(p, "\tpciveni  0x%04x\n", swab16(p_tempe->pcfs.veni));
+	p += sprintf(p, "\tpcidevi  0x%04x\n", swab16(p_tempe->pcfs.devi));
+	p += sprintf(p, "\tpcicmd   0x%04x\n", swab16(p_tempe->pcfs.cmmd));
+	p += sprintf(p, "\tpcistat  0x%04x\n", swab16(p_tempe->pcfs.stat));
+	p += sprintf(p, "\tpcirev   0x%02x\n",
+		     (p_tempe->pcfs.reviAndClas >> 24));
+	p += sprintf(p, "\tpciclass 0x%06x\n",
+		     ((p_tempe->pcfs.reviAndClas << 24) >> 8) |
+		     swab16((p_tempe->pcfs.reviAndClas << 8) >> 16));
+	p += sprintf(p, "\tpciclsz  0x%02x\n", p_tempe->pcfs.clsz);
+	p += sprintf(p, "\tpcimlat  0x%02x\n", p_tempe->pcfs.mlat);
+	p += sprintf(p, "\tpcisubv  0x%04x\n", swab16(p_tempe->pcfs.subv));
+	p += sprintf(p, "\tpcisubi  0x%04x\n", swab16(p_tempe->pcfs.subi));
+	p += sprintf(p, "\tpcixcap  0x%08x\n", p_tempe->pcfs.msiCapID);
+	p += sprintf(p, "\tpcixstat 0x%08x\n",
+		     swab32(p_tempe->pcfs.msiMsgAddrL));
+
+	p += sprintf(p, "\nGlobal Control and Status Register Group (GCSR):\n");
+	p += sprintf(p, "\tctrl  0x%04x%02x%02x\n", p_tempe->gcsr.ctrl,
+		     p_tempe->gcsr.ga, p_tempe->gcsr.revid);
+
+	p += sprintf(p, "\nCR/CSR Register Group:\n");
+	p += sprintf(p, "\tbcr   0x%08x\n", p_tempe->crcsr.csrbcr);
+	p += sprintf(p, "\tbsr   0x%08x\n", p_tempe->crcsr.csrbsr);
+
+	return p - buf;
+}
+
+/*
+ * Function   : tempe_setup_attribute
+ *
+ * Description: helper function for calculating attribute register contents.
+ *
+ */
+static int
+tempe_setup_attribute(addressMode_t addrSpace,
+		      int userAccessType,
+		      int dataAccessType,
+		      dataWidth_t maxDataWidth,
+		      int xferProtocol, vme2esstRate_t xferRate2esst)
+{
+	int temp_ctl = 0;
+
+	/* Validate & initialize address space field */
+	switch (addrSpace) {
+	case VME_A16:
+		temp_ctl |= 0x0;
+		break;
+	case VME_A24:
+		temp_ctl |= 0x1;
+		break;
+	case VME_A32:
+		temp_ctl |= 0x2;
+		break;
+	case VME_A64:
+		temp_ctl |= 0x4;
+		break;
+	case VME_CRCSR:
+		temp_ctl |= 0x5;
+		break;
+	case VME_USER1:
+		temp_ctl |= 0x8;
+		break;
+	case VME_USER2:
+		temp_ctl |= 0x9;
+		break;
+	case VME_USER3:
+		temp_ctl |= 0xA;
+		break;
+	case VME_USER4:
+		temp_ctl |= 0xB;
+		break;
+	default:
+		return (-EINVAL);
+	}
+
+	/* Setup CTL register */
+	if (userAccessType & VME_SUPER)
+		temp_ctl |= 0x0020;
+	if (dataAccessType & VME_PROG)
+		temp_ctl |= 0x0010;
+	if (maxDataWidth == VME_D16)
+		temp_ctl |= 0x0000;
+	if (maxDataWidth == VME_D32)
+		temp_ctl |= 0x0040;
+	switch (xferProtocol) {
+	case VME_SCT:
+		temp_ctl |= 0x000;
+		break;
+	case VME_BLT:
+		temp_ctl |= 0x100;
+		break;
+	case VME_MBLT:
+		temp_ctl |= 0x200;
+		break;
+	case VME_2eVME:
+		temp_ctl |= 0x300;
+		break;
+	case VME_2eSST:
+		temp_ctl |= 0x400;
+		break;
+	case VME_2eSSTB:
+		temp_ctl |= 0x500;
+		break;
+	}
+	switch (xferRate2esst) {
+	case VME_SSTNONE:
+	case VME_SST160:
+		temp_ctl |= 0x0000;
+		break;
+	case VME_SST267:
+		temp_ctl |= 0x800;
+		break;
+	case VME_SST320:
+		temp_ctl |= 0x1000;
+		break;
+	}
+
+	return (temp_ctl);
+}
+
+/*
+ *  tempe_bus_error_chk()
+ *  Return zero if no VME bus error has occured, 1 otherwise.
+ *  Optionally, clear bus error status.
+ */
+
+int tempe_bus_error_chk(int clrflag)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int tmp;
+
+	tmp = p_tempe->lcsr.veat;
+	if (tmp & 0x80000000) {	/* VES is Set */
+		if (clrflag)
+			p_tempe->lcsr.veat = 0x20000000;
+		return (1);
+	}
+	return (0);
+}
+
+/*
+ * Function:    DMA_tempe_irqhandler
+ * Description: Saves DMA completion timestamp and then wakes up DMA queue
+ */
+
+static void DMA_tempe_irqhandler(int channel_mask)
+{
+
+	if (channel_mask & 1) {
+		tempe_dma_irq_time[0] = tempe_irq_time;
+		wake_up(&dma_queue[0]);
+	}
+	if (channel_mask & 2) {
+		tempe_dma_irq_time[1] = tempe_irq_time;
+		wake_up(&dma_queue[1]);
+	}
+}
+
+/*
+ * Function   : LERR_tempe_irqhandler
+ * Description: Display error & status message when LERR (PCI) exception
+ *              interrupt occurs.
+ *
+ */
+
+static void LERR_tempe_irqhandler(void)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+
+	/* 
+	 * Only print a message if this is a real error.  
+	 * Dummy errors can sometimes happen here. 
+   	 * A real error is indicated if the EDPST bit 
+	 * is set in the EDPAT register.
+	 */
+	if (p_tempe->lcsr.edpat & 0x80000000) {
+		printk(KERN_ERR
+			 "tsi148: VME PCI Exception at address: 0x%08x:%08x, attributes: 0x%08x\n",
+			p_tempe->lcsr.edpau, p_tempe->lcsr.edpal, 
+			p_tempe->lcsr.edpat);
+		printk(KERN_ERR
+			"tsi148: PCI-X attribute reg: 0x%08x, PCI-X split completion reg: 0x%08x\n",
+			p_tempe->lcsr.edpxa, p_tempe->lcsr.edpxs);
+	}
+	/* Clear the PCI error by writing the EDPCL bit in the EDPAT register */
+	p_tempe->lcsr.edpat = 0x20000000;
+	vme_sync_data();
+
+	/* Also clear the PCI error interrupt (PERRC) in the INTC register */
+	p_tempe->lcsr.intc = 0x00002000;
+	vme_sync_data();
+}
+
+/*
+ * Function:     VERR_tempe_irqhandler
+ * Description:  Display error & status when VME error interrupt occurs.
+ * Not normally enabled or used.  tempe_bus_error_chk() is used instead.
+ */
+
+static void VERR_tempe_irqhandler(void)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+
+	printk(KERN_ERR
+	       "tsi148: VME Exception at address: 0x%08x:%08x, attributes: %08x\n",
+	       p_tempe->lcsr.veau, p_tempe->lcsr.veal, p_tempe->lcsr.veat);
+	p_tempe->lcsr.veat = 0x20000000;
+	vme_sync_data();
+}
+
+/*
+ * Function   : MB_tempe_irqhandler
+ * Description: Wake up mail box queue.
+ */
+
+static void MB_tempe_irqhandler(int mboxMask)
+{
+	if (vmechip_irq_overhead_ticks != 0) {
+		wake_up(&mbox_queue);
+	}
+}
+
+/*
+ * Function   : LM_tempe_irqhandler
+ * Description: Wake up location monitor queue
+ */
+
+static void LM_tempe_irqhandler(int lm_mask)
+{
+	tempe_lm_event = lm_mask;
+	wake_up(&lm_queue);
+}
+
+/*
+ * Function:    VIRQ_tempe_irqhandler
+ * Description: Record the level & vector from the VME bus interrupt.
+ */
+
+static void VIRQ_tempe_irqhandler(int virq_mask)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int iackvec, i;
+
+	for (i = 7; i > 0; i--) {
+		if (virq_mask & (1 << i)) {
+			iackvec = p_tempe->lcsr.viack[(i * 4) + 3];
+			vme_irqlog[i][iackvec]++;
+			wake_up(&vmeint_queue[i]);
+		}
+	}
+	wake_up(&vmeint_queue[0]);
+}
+
+/*
+ * Function   : tempe_irqhandler
+ * Description: Top level interrupt handler.  Clears appropriate interrupt
+ *              status bits and then calls appropriate sub handler(s).
+ */
+
+static irqreturn_t tempe_irqhandler(int irq, void *dev_id)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	long stat, enable;
+
+	if (dev_id != p_tempe)
+		return IRQ_NONE;
+
+	/* Save time that this IRQ occurred at */
+	tempe_irq_time = get_tbl();
+
+	/* Determine which interrupts are unmasked and active */
+	enable = p_tempe->lcsr.inteo;
+	stat = p_tempe->lcsr.ints;
+	stat = stat & enable;
+
+	/* Clear them */
+	p_tempe->lcsr.intc = stat;
+	vme_sync_data();
+
+	/* Call subhandlers as appropriate */
+	if (stat & 0x03000000)	/* DMA irqs */
+		DMA_tempe_irqhandler((stat & 0x03000000) >> 24);
+	if (stat & 0x00002000)	/* PCI bus error */
+		LERR_tempe_irqhandler();
+	if (stat & 0x00001000)	/* VME bus error */
+		VERR_tempe_irqhandler();
+	if (stat & 0x000F0000)	/* Mail box irqs */
+		MB_tempe_irqhandler((stat & 0xF0000) >> 16);
+	if (stat & 0x00F00000)	/* Location monitor irqs */
+		LM_tempe_irqhandler((stat & 0xF00000) >> 20);
+	if (stat & 0x000000FE)	/* VME bus irqs */
+		VIRQ_tempe_irqhandler(stat & 0x0000FE);
+
+	stat = p_tempe->lcsr.ints;
+	
+	return IRQ_HANDLED;
+}
+
+/*
+ * Function   : tempe_generate_irq
+ * Description: Generate a VME bus interrupt at the requested level & vector.
+ *              Wait for system controller to ack the interrupt.
+ */
+int tempe_generate_irq(virqInfo_t * vmeIrq)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int timeout;
+	int looptimeout;
+	unsigned int tmp;
+
+	timeout = vmeIrq->waitTime;
+	if (timeout < (HZ / 20)) 
+		timeout = HZ / 20;	
+	
+	looptimeout = HZ / 20;	/* try for 1/20 second */
+
+	vmeIrq->timeOutFlag = 0;
+
+	/* Validate & setup vector register */
+	tmp = p_tempe->lcsr.vicr;
+	tmp &= ~0xFF;
+	p_tempe->lcsr.vicr = tmp | vmeIrq->vector;
+	vme_sync_data();
+
+	/* Assert VMEbus IRQ */
+	p_tempe->lcsr.vicr = tmp | (vmeIrq->level << 8) | vmeIrq->vector;
+	vme_sync_data();
+
+	/* Wait for syscon to do iack */
+	while (p_tempe->lcsr.vicr & 0x800) {
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(looptimeout);
+		timeout = timeout - looptimeout;
+		if (timeout < 0) {
+			vmeIrq->timeOutFlag = 1;
+			break;
+		}
+	}
+
+	return (0);
+}
+
+/*
+ * Function:    tempe_set_arbiter
+ * Description: Set the VME bus arbiter with the requested attributes
+ */
+
+int tempe_set_arbiter(vmeArbiterCfg_t * vmeArb)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int temp_ctl = 0;
+	int gto = 0;
+
+	temp_ctl = p_tempe->lcsr.vctrl;
+	temp_ctl &= 0xFFEFFF00;
+
+	if (vmeArb->globalTimeoutTimer == 0xFFFFFFFF) {
+		gto = 8;
+	} else if (vmeArb->globalTimeoutTimer > 2048) {
+		return (-EINVAL);
+	} else if (vmeArb->globalTimeoutTimer == 0) {
+		gto = 0;
+	} else {
+		gto = 1;
+		while ((16 * (1 << (gto - 1))) < vmeArb->globalTimeoutTimer) {
+			gto += 1;
+		}
+	}
+	temp_ctl |= gto;
+
+	if (vmeArb->arbiterMode != VME_PRIORITY_MODE) {
+		temp_ctl |= 1 << 6;
+	}
+
+	if (vmeArb->arbiterTimeoutFlag) {
+		temp_ctl |= 1 << 7;
+	}
+
+	if (vmeArb->noEarlyReleaseFlag) {
+		temp_ctl |= 1 << 20;
+	}
+	p_tempe->lcsr.vctrl = temp_ctl;
+	vme_sync_data();
+
+	return (0);
+}
+
+/*
+ * Function:    tempe_get_arbiter
+ * Description: Return the attributes of the VME bus arbiter.
+ */
+
+int tempe_get_arbiter(vmeArbiterCfg_t * vmeArb)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int temp_ctl = 0;
+	int gto = 0;
+
+	temp_ctl = p_tempe->lcsr.vctrl;
+
+	gto = temp_ctl & 0xF;
+	if (gto != 0) {
+		vmeArb->globalTimeoutTimer = (16 * (1 << (gto - 1)));
+	}
+
+	if (temp_ctl & (1 << 6)) {
+		vmeArb->arbiterMode = VME_R_ROBIN_MODE;
+	} else {
+		vmeArb->arbiterMode = VME_PRIORITY_MODE;
+	}
+
+	if (temp_ctl & (1 << 7)) {
+		vmeArb->arbiterTimeoutFlag = 1;
+	}
+
+	if (temp_ctl & (1 << 20)) {
+		vmeArb->noEarlyReleaseFlag = 1;
+	}
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : tempe_set_requestor
+// Description: Set the VME bus requestor with the requested attributes
+//-----------------------------------------------------------------------------
+int tempe_set_requestor(vmeRequesterCfg_t * vmeReq)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int temp_ctl = 0;
+
+	temp_ctl = p_tempe->lcsr.vmctrl;
+	temp_ctl &= 0xFFFF0000;
+
+	if (vmeReq->releaseMode == 1) {
+		temp_ctl |= (1 << 3);
+	}
+
+	if (vmeReq->fairMode == 1) {
+		temp_ctl |= (1 << 2);
+	}
+
+	temp_ctl |= (vmeReq->timeonTimeoutTimer & 7) << 8;
+	temp_ctl |= (vmeReq->timeoffTimeoutTimer & 7) << 12;
+	temp_ctl |= vmeReq->requestLevel;
+
+	p_tempe->lcsr.vmctrl = temp_ctl;
+	vme_sync_data();
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : tempe_get_requestor
+// Description: Return the attributes of the VME bus requestor
+//-----------------------------------------------------------------------------
+int tempe_get_requestor(vmeRequesterCfg_t * vmeReq)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int temp_ctl = 0;
+
+	temp_ctl = p_tempe->lcsr.vmctrl;
+
+	if (temp_ctl & 0x18) {
+		vmeReq->releaseMode = 1;
+	}
+
+	if (temp_ctl & (1 << 2)) {
+		vmeReq->fairMode = 1;
+	}
+
+	vmeReq->requestLevel = temp_ctl & 3;
+	vmeReq->timeonTimeoutTimer = (temp_ctl >> 8) & 7;
+	vmeReq->timeoffTimeoutTimer = (temp_ctl >> 12) & 7;
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : tempe_set_in_bound
+// Description: Initialize an inbound window with the requested attributes.
+//-----------------------------------------------------------------------------
+int tempe_set_in_bound(vmeInWindowCfg_t * vmeIn)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int temp_ctl = 0;
+	unsigned int win, x, granularity = 0x10000;
+	struct page *page, *pend;
+
+	/* Verify input data */
+	if (vmeIn->windowNbr > 7) {
+		return (-EINVAL);
+	}
+	win = vmeIn->windowNbr;
+
+	/* Free previous allocation */
+#ifndef CONFIG_VME_BRIDGE_BOOTMEM
+	if (in_image_ba[win] != NULL) {
+#else
+	if ((win != 7) && (in_image_ba[win] != NULL)) {
+#endif
+             	 /* Undo marking the pages as reserved */
+              	 pend = virt_to_page(in_image_ba[win] + in_image_size[win] - 1);
+              	 for (page = virt_to_page(in_image_ba[win]); page <= pend; page++)
+              	         ClearPageReserved(page);
+              	 dma_free_coherent(&vme_pci_dev->dev,
+              	                         in_image_size[win],
+              	                         in_image_ba[win],
+              	                         in_image_pa[win]);
+              	 in_image_mapped[win] = 0;
+       	}
+
+	if (vmeIn->windowEnable == 0) {
+		temp_ctl = p_tempe->lcsr.inboundTranslation[win].itat;
+		temp_ctl &= ~0x80000000;
+		p_tempe->lcsr.inboundTranslation[win].itat = temp_ctl;
+		vme_sync_data();
+		return 0;
+	}
+
+	switch (vmeIn->addrSpace) {
+	case VME_CRCSR:
+	case VME_USER1:
+	case VME_USER2:
+	case VME_USER3:
+	case VME_USER4:
+		return (-EINVAL);
+	case VME_A16:
+		granularity = 0x10;
+		temp_ctl |= 0x00;
+		break;
+	case VME_A24:
+		granularity = 0x1000;
+		temp_ctl |= 0x10;
+		break;
+	case VME_A32:
+		granularity = 0x10000;
+		temp_ctl |= 0x20;
+		break;
+	case VME_A64:
+		granularity = 0x10000;
+		temp_ctl |= 0x40;
+		break;
+	}
+
+#ifdef CONFIG_VME_BRIDGE_BOOTMEM
+	if (win == 7) {
+		vmeIn->windowSizeL = in_image_size[7];
+		vmeIn->windowSizeU = 0;
+	}
+#endif 
+	if ((vmeIn->vmeAddrL & (granularity - 1)) || 
+		(vmeIn->windowSizeL & (granularity - 1)))  
+		return (-EINVAL);
+
+#ifndef CONFIG_VME_BRIDGE_BOOTMEM
+	if ((vmeIn->windowSizeL < 0x10) || (vmeIn->windowSizeL > 0x800000)) 
+#else
+	if ((win != 7) && 
+		((vmeIn->windowSizeL < 0x10) || (vmeIn->windowSizeL > 0x800000))) 
+#endif
+		return (-EINVAL);
+
+#ifndef CONFIG_VME_BRIDGE_BOOTMEM
+	if (vmeIn->windowEnable == 1) {
+#else
+	if ((win != 7) && (vmeIn->windowEnable == 1)) {
+#endif
+		in_image_ba[win] = (char *)dma_alloc_coherent((struct device *)
+				&vme_pci_dev->dev, 
+				vmeIn->windowSizeL,
+				(dma_addr_t *)&in_image_pa[win],
+				GFP_KERNEL);
+                if (!in_image_ba[win]) {
+                        printk(KERN_ERR "vmedrv: No memory for inbound window\n");
+                        return -ENOMEM;
+                }
+		in_image_size[win] = vmeIn->windowSizeL;
+
+		/* now mark the pages as reserved; otherwise */
+		/* remap_pfn_range doesn't do what we want */
+		pend = virt_to_page(in_image_ba[win] + in_image_size[win] - 1);
+                for (page = virt_to_page(in_image_ba[win]); page <= pend; page++)
+			SetPageReserved(page);
+		memset(in_image_ba[win], 0, in_image_size[win]);
+		vme_flush_range((unsigned long)in_image_ba[win],
+					(unsigned long)(in_image_ba[win] + in_image_size[win]));
+		vmeIn->pciAddrL = (unsigned int)in_image_pa[win];
+		vmeIn->pciAddrU = 0;
+#ifndef CONFIG_VME_BRIDGE_BOOTMEM
+        }
+#else
+	} else if (win == 7)  {
+		vmeIn->pciAddrL = (unsigned int)in_image_pa[win];
+		vmeIn->pciAddrU = 0;
+	}
+#endif
+
+	// Disable while we are mucking around
+	p_tempe->lcsr.inboundTranslation[win].itat = 0;
+	vme_sync_data();
+
+	p_tempe->lcsr.inboundTranslation[win].itsal = vmeIn->vmeAddrL;
+	p_tempe->lcsr.inboundTranslation[win].itsau = vmeIn->vmeAddrU;
+	p_tempe->lcsr.inboundTranslation[win].iteal =
+	    vmeIn->vmeAddrL + vmeIn->windowSizeL - granularity;
+
+	p_tempe->lcsr.inboundTranslation[win].iteau =
+	    add64hi(vmeIn->vmeAddrL, vmeIn->vmeAddrU,
+		    vmeIn->windowSizeL - granularity, vmeIn->windowSizeU);
+	p_tempe->lcsr.inboundTranslation[win].itofl =
+	    vmeIn->pciAddrL - vmeIn->vmeAddrL;
+	p_tempe->lcsr.inboundTranslation[win].itofu =
+	    sub64hi(vmeIn->pciAddrL, vmeIn->pciAddrU, vmeIn->vmeAddrL,
+		    vmeIn->vmeAddrU);
+
+	/* Setup CTL register */
+	temp_ctl |= (vmeIn->xferProtocol & 0x3E) << 6;
+	for (x = 0; x < 4; x++) {
+		if ((64 << x) >= vmeIn->prefetchSize) {
+			break;
+		}
+	}
+	if (x == 4)
+		x--;
+	temp_ctl |= (x << 16);
+
+	if (vmeIn->prefetchThreshold)
+
+		if (vmeIn->prefetchThreshold)
+			temp_ctl |= 0x40000;
+
+	switch (vmeIn->xferRate2esst) {
+	case VME_SSTNONE:
+		break;
+	case VME_SST160:
+		temp_ctl |= 0x0400;
+		break;
+	case VME_SST267:
+		temp_ctl |= 0x1400;
+		break;
+	case VME_SST320:
+		temp_ctl |= 0x2400;
+		break;
+	}
+
+	if (vmeIn->userAccessType & VME_USER)
+		temp_ctl |= 0x4;
+	if (vmeIn->userAccessType & VME_SUPER)
+		temp_ctl |= 0x8;
+	if (vmeIn->dataAccessType & VME_DATA)
+		temp_ctl |= 0x1;
+	if (vmeIn->dataAccessType & VME_PROG)
+		temp_ctl |= 0x2;
+
+	/* Write ctl reg without enable */
+	p_tempe->lcsr.inboundTranslation[win].itat = temp_ctl;
+	vme_sync_data();
+
+	if (vmeIn->windowEnable)
+		temp_ctl |= 0x80000000;
+
+	p_tempe->lcsr.inboundTranslation[win].itat = temp_ctl;
+	vme_sync_data();
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : tempe_get_in_bound
+// Description: Return the attributes of an inbound window.
+//-----------------------------------------------------------------------------
+int tempe_get_in_bound(vmeInWindowCfg_t * vmeIn)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int temp_ctl = 0;
+	unsigned int i, vme_end_u, vme_end_l;
+
+	/* Verify input data */
+	if (vmeIn->windowNbr > 7) {
+		return (-EINVAL);
+	}
+	i = vmeIn->windowNbr;
+
+	temp_ctl = p_tempe->lcsr.inboundTranslation[i].itat;
+
+	// Get Control & BUS attributes
+	if (temp_ctl & 0x80000000)
+		vmeIn->windowEnable = 1;
+	vmeIn->xferProtocol = ((temp_ctl & 0xF80) >> 6) | VME_SCT;
+	vmeIn->prefetchSize = 64 << ((temp_ctl >> 16) & 3);
+	vmeIn->wrPostEnable = 1;
+	vmeIn->prefetchEnable = 1;
+	if (temp_ctl & 0x40000)
+		vmeIn->prefetchThreshold = 1;
+	if (temp_ctl & 0x4)
+		vmeIn->userAccessType |= VME_USER;
+	if (temp_ctl & 0x8)
+		vmeIn->userAccessType |= VME_SUPER;
+	if (temp_ctl & 0x1)
+		vmeIn->dataAccessType |= VME_DATA;
+	if (temp_ctl & 0x2)
+		vmeIn->dataAccessType |= VME_PROG;
+
+	switch ((temp_ctl & 0x70) >> 4) {
+	case 0x0:
+		vmeIn->addrSpace = VME_A16;
+		break;
+	case 0x1:
+		vmeIn->addrSpace = VME_A24;
+		break;
+	case 0x2:
+		vmeIn->addrSpace = VME_A32;
+		break;
+	case 0x4:
+		vmeIn->addrSpace = VME_A64;
+		break;
+	}
+
+	switch ((temp_ctl & 0x7000) >> 12) {
+	case 0x0:
+		vmeIn->xferRate2esst = VME_SST160;
+		break;
+	case 0x1:
+		vmeIn->xferRate2esst = VME_SST267;
+		break;
+	case 0x2:
+		vmeIn->xferRate2esst = VME_SST320;
+		break;
+	}
+
+	// Get VME inbound start & end addresses
+	vmeIn->vmeAddrL = p_tempe->lcsr.inboundTranslation[i].itsal;
+	vmeIn->vmeAddrU = p_tempe->lcsr.inboundTranslation[i].itsau;
+	vme_end_l = p_tempe->lcsr.inboundTranslation[i].iteal;
+	vme_end_u = p_tempe->lcsr.inboundTranslation[i].iteau;
+
+	// Adjust addresses for window granularity
+	switch (vmeIn->addrSpace) {
+	case VME_A16:
+		vmeIn->vmeAddrU = 0;
+		vmeIn->vmeAddrL &= 0x0000FFF0;
+		vme_end_u = 0;
+		vme_end_l &= 0x0000FFF0;
+		vme_end_l += 0x10;
+		break;
+	case VME_A24:
+		vmeIn->vmeAddrU = 0;
+		vmeIn->vmeAddrL &= 0x00FFF000;
+		vme_end_u = 0;
+		vme_end_l &= 0x00FFF000;
+		vme_end_l += 0x1000;
+		break;
+	case VME_A32:
+		vmeIn->vmeAddrU = 0;
+		vmeIn->vmeAddrL &= 0xFFFF0000;
+		vme_end_u = 0;
+		vme_end_l &= 0xFFFF0000;
+		vme_end_l += 0x10000;
+		break;
+	default:
+		vmeIn->vmeAddrL &= 0xFFFF0000;
+		vme_end_l &= 0xFFFF0000;
+		vme_end_l += 0x10000;
+		break;
+	}
+
+	/* Calculate size of window */
+	vmeIn->windowSizeL = vme_end_l - vmeIn->vmeAddrL;
+	vmeIn->windowSizeU = sub64hi(vme_end_l, vme_end_u,
+				     vmeIn->vmeAddrL, vmeIn->vmeAddrU);
+
+	/* Calculate corresponding PCI bus address */
+	vmeIn->pciAddrL =
+	    vmeIn->vmeAddrL + p_tempe->lcsr.inboundTranslation[i].itofl;
+	vmeIn->pciAddrU =
+	    add64hi(vmeIn->vmeAddrL, vmeIn->vmeAddrU,
+		    p_tempe->lcsr.inboundTranslation[i].itofl,
+		    p_tempe->lcsr.inboundTranslation[i].itofu);
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : tempe_set_out_bound
+// Description: Set the attributes of an outbound window.
+//-----------------------------------------------------------------------------
+int tempe_set_out_bound(vmeOutWindowCfg_t * vmeOut)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int temp_ctl = 0;
+	unsigned int i, x;
+
+	/* Verify input data */
+	if (vmeOut->windowNbr > 7) {
+		return (-EINVAL);
+	}
+	i = vmeOut->windowNbr;
+
+	if (vmeOut->windowEnable == 0) {
+		temp_ctl = p_tempe->lcsr.outboundTranslation[i].otat;
+		temp_ctl &= ~0x80000000;
+		p_tempe->lcsr.outboundTranslation[i].otat = temp_ctl;
+		vme_sync_data();
+		return 0;
+	}
+
+	if ((vmeOut->xlatedAddrL & 0xFFFF) ||
+	    (vmeOut->windowSizeL & 0xFFFF) || (vmeOut->pciBusAddrL & 0xFFFF)) {
+		return (-EINVAL);
+	}
+
+	temp_ctl = tempe_setup_attribute(vmeOut->addrSpace,
+					 vmeOut->userAccessType,
+					 vmeOut->dataAccessType,
+					 vmeOut->maxDataWidth,
+					 vmeOut->xferProtocol,
+					 vmeOut->xferRate2esst);
+
+	if (vmeOut->prefetchEnable) {
+		for (x = 0; x < 4; x++) {
+			if ((2 << x) >= vmeOut->prefetchSize)
+				break;
+		}
+		if (x == 4)
+			x = 3;
+		temp_ctl |= (x << 16);
+	} else {
+		temp_ctl |= 0x40000;
+	}
+	// Disable while we are mucking around
+	p_tempe->lcsr.outboundTranslation[i].otat = 0;
+	vme_sync_data();
+
+	p_tempe->lcsr.outboundTranslation[i].otbs = vmeOut->bcastSelect2esst;
+	p_tempe->lcsr.outboundTranslation[i].otsal = vmeOut->pciBusAddrL;
+	p_tempe->lcsr.outboundTranslation[i].otsau = vmeOut->pciBusAddrU;
+	p_tempe->lcsr.outboundTranslation[i].oteal =
+	    vmeOut->pciBusAddrL + (vmeOut->windowSizeL - 0x10000);
+	p_tempe->lcsr.outboundTranslation[i].oteau =
+	    add64hi(vmeOut->pciBusAddrL, vmeOut->pciBusAddrU,
+		    vmeOut->windowSizeL - 0x10000, vmeOut->windowSizeU);
+	p_tempe->lcsr.outboundTranslation[i].otofl =
+	    vmeOut->xlatedAddrL - vmeOut->pciBusAddrL;
+	if (vmeOut->addrSpace == VME_A64) {
+		p_tempe->lcsr.outboundTranslation[i].otofu =
+		    sub64hi(vmeOut->xlatedAddrL, vmeOut->xlatedAddrU,
+			    vmeOut->pciBusAddrL, vmeOut->pciBusAddrU);
+	} else {
+		p_tempe->lcsr.outboundTranslation[i].otofu = 0;
+	}
+
+	// Write ctl reg without enable
+	p_tempe->lcsr.outboundTranslation[i].otat = temp_ctl;
+	vme_sync_data();
+
+	if (vmeOut->windowEnable)
+		temp_ctl |= 0x80000000;
+
+	p_tempe->lcsr.outboundTranslation[i].otat = temp_ctl;
+	vme_sync_data();
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : tempe_get_out_bound
+// Description: Return the attributes of an outbound window.
+//-----------------------------------------------------------------------------
+int tempe_get_out_bound(vmeOutWindowCfg_t * vmeOut)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int temp_ctl = 0;
+	unsigned int i;
+
+	// Verify input data
+	if (vmeOut->windowNbr > 7) {
+		return (-EINVAL);
+	}
+	i = vmeOut->windowNbr;
+
+	// Get Control & BUS attributes
+	temp_ctl = p_tempe->lcsr.outboundTranslation[i].otat;
+	vmeOut->wrPostEnable = 1;
+	if (temp_ctl & 0x0020)
+		vmeOut->userAccessType = VME_SUPER;
+	else
+		vmeOut->userAccessType = VME_USER;
+	if (temp_ctl & 0x0010)
+		vmeOut->dataAccessType = VME_PROG;
+	else
+		vmeOut->dataAccessType = VME_DATA;
+	if (temp_ctl & 0x80000000)
+		vmeOut->windowEnable = 1;
+
+	switch ((temp_ctl & 0xC0) >> 6) {
+	case 0:
+		vmeOut->maxDataWidth = VME_D16;
+		break;
+	case 1:
+		vmeOut->maxDataWidth = VME_D32;
+		break;
+	}
+	vmeOut->xferProtocol = 1 << ((temp_ctl >> 8) & 7);
+
+	switch (temp_ctl & 0xF) {
+	case 0x0:
+		vmeOut->addrSpace = VME_A16;
+		break;
+	case 0x1:
+		vmeOut->addrSpace = VME_A24;
+		break;
+	case 0x2:
+		vmeOut->addrSpace = VME_A32;
+		break;
+	case 0x4:
+		vmeOut->addrSpace = VME_A64;
+		break;
+	case 0x5:
+		vmeOut->addrSpace = VME_CRCSR;
+		break;
+	case 0x8:
+		vmeOut->addrSpace = VME_USER1;
+		break;
+	case 0x9:
+		vmeOut->addrSpace = VME_USER2;
+		break;
+	case 0xA:
+		vmeOut->addrSpace = VME_USER3;
+		break;
+	case 0xB:
+		vmeOut->addrSpace = VME_USER4;
+		break;
+	}
+
+	vmeOut->xferRate2esst = VME_SSTNONE;
+	if (vmeOut->xferProtocol == VME_2eSST) {
+
+		switch (temp_ctl & 0x1800) {
+		case 0x000:
+			vmeOut->xferRate2esst = VME_SST160;
+			break;
+		case 0x800:
+			vmeOut->xferRate2esst = VME_SST267;
+			break;
+		case 0x1000:
+			vmeOut->xferRate2esst = VME_SST320;
+			break;
+		}
+
+	}
+	/* Get Window mappings */
+
+	vmeOut->bcastSelect2esst = p_tempe->lcsr.outboundTranslation[i].otbs;
+	vmeOut->pciBusAddrL = p_tempe->lcsr.outboundTranslation[i].otsal;
+	vmeOut->pciBusAddrU = p_tempe->lcsr.outboundTranslation[i].otsau;
+
+	vmeOut->windowSizeL =
+	    (p_tempe->lcsr.outboundTranslation[i].oteal + 0x10000) -
+	    vmeOut->pciBusAddrL;
+	vmeOut->windowSizeU =
+	    sub64hi(p_tempe->lcsr.outboundTranslation[i].oteal + 0x10000,
+		    p_tempe->lcsr.outboundTranslation[i].oteau,
+		    vmeOut->pciBusAddrL, vmeOut->pciBusAddrU);
+	vmeOut->xlatedAddrL =
+	    p_tempe->lcsr.outboundTranslation[i].otofl + vmeOut->pciBusAddrL;
+	if (vmeOut->addrSpace == VME_A64) {
+		vmeOut->xlatedAddrU =
+		    add64hi(p_tempe->lcsr.outboundTranslation[i].otofl,
+			    p_tempe->lcsr.outboundTranslation[i].otofu,
+			    vmeOut->pciBusAddrL, vmeOut->pciBusAddrU);
+	} else {
+		vmeOut->xlatedAddrU = 0;
+	}
+
+	return (0);
+}
+
+/*
+ * Function   : tempe_setup_lm
+ * Description: Set the attributes of the location monitor
+ */
+
+int tempe_setup_lm(vmeLmCfg_t * vmeLm)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int temp_ctl = 0;
+
+	/* Setup CTL register */
+	switch (vmeLm->addrSpace) {
+	case VME_A16:
+		temp_ctl |= 0x00;
+		break;
+	case VME_A24:
+		temp_ctl |= 0x10;
+		break;
+	case VME_A32:
+		temp_ctl |= 0x20;
+		break;
+	case VME_A64:
+		temp_ctl |= 0x40;
+		break;
+	default:
+		return (-EINVAL);
+	}
+	if (vmeLm->userAccessType & VME_USER)
+		temp_ctl |= 0x4;
+	if (vmeLm->userAccessType & VME_SUPER)
+		temp_ctl |= 0x8;
+	if (vmeLm->dataAccessType & VME_DATA)
+		temp_ctl |= 0x1;
+	if (vmeLm->dataAccessType & VME_PROG)
+		temp_ctl |= 0x2;
+
+	/* Disable while we are mucking around */
+	p_tempe->lcsr.lmat = 0;
+	vme_sync_data();
+
+	p_tempe->lcsr.lmbal = vmeLm->addr;
+	p_tempe->lcsr.lmbau = vmeLm->addrU;
+
+	tempe_lm_event = 0;
+
+	/* Write ctl reg and enable */
+	p_tempe->lcsr.lmat = temp_ctl | 0x80;
+	vme_sync_data();
+
+	return (0);
+}
+
+/*
+ * Function:    tempe_wait_lm
+ * Description: Wait for location monitor to be triggered.
+ */
+
+int tempe_wait_lm(vmeLmCfg_t * vmeLm)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	unsigned long flags;
+	unsigned int tmp;
+
+	spin_lock_irqsave(&lm_lock, flags);
+	tmp = tempe_lm_event;
+	spin_unlock_irqrestore(&lm_lock, flags);
+	if (tmp == 0) {
+		if (vmeLm->lmWait < 10)
+			vmeLm->lmWait = 10;
+		interruptible_sleep_on_timeout(&lm_queue, vmeLm->lmWait);
+	}
+	p_tempe->lcsr.lmat = 0;
+	vme_sync_data();
+	vmeLm->lmEvents = tempe_lm_event;
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : tempe_do_rmw
+// Description: Perform an RMW cycle on the VME bus.
+//    A VME outbound window must already be setup which maps to the desired 
+//    RMW address.
+//-----------------------------------------------------------------------------
+int tempe_do_rmw(vmeRmwCfg_t * vmeRmw)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int temp_ctl = 0;
+	unsigned int vme_end_u, vme_end_l;
+	int *rmw_pci_data_ptr = NULL;
+	int *va_data_ptr = NULL;
+	int i;
+	vmeOutWindowCfg_t vmeOut;
+
+	if (vmeRmw->maxAttempts < 1) {
+		return (-EINVAL);
+	}
+	// Find the PCI address that maps to the desired VME address 
+	for (i = 0; i < 7; i++) {
+		temp_ctl = p_tempe->lcsr.outboundTranslation[i].otat;
+		if ((temp_ctl & 0x80000000) == 0) {
+			continue;
+		}
+		memset(&vmeOut, 0, sizeof(vmeOut));
+		vmeOut.windowNbr = i;
+		tempe_get_out_bound(&vmeOut);
+		if (vmeOut.addrSpace != vmeRmw->addrSpace) {
+			continue;
+		}
+		if (vmeOut.xlatedAddrU > vmeRmw->targetAddrU) {
+			continue;
+		}
+		if (vmeOut.xlatedAddrU == vmeRmw->targetAddrU) {
+			if (vmeOut.xlatedAddrL > vmeRmw->targetAddr) {
+				continue;
+			}
+		}
+		vme_end_l = vmeOut.xlatedAddrL + vmeOut.windowSizeL;
+		vme_end_u = add64hi(vmeOut.xlatedAddrL, vmeOut.xlatedAddrU,
+				    vmeOut.windowSizeL, vmeOut.windowSizeU);
+		if (sub64hi(vme_end_l, vme_end_u,
+			    vmeRmw->targetAddr, vmeRmw->targetAddrU) >= 0) {
+			rmw_pci_data_ptr =
+			    (int *)(vmeOut.pciBusAddrL +
+				    (vmeRmw->targetAddr - vmeOut.xlatedAddrL));
+			va_data_ptr =
+			    (int *)(out_image_va[i] +
+				    (vmeRmw->targetAddr - vmeOut.xlatedAddrL));
+			break;
+		}
+	}
+
+	// If no window - fail.
+	if (rmw_pci_data_ptr == NULL) {
+		return (-EINVAL);
+	}
+	// Setup the RMW registers.
+	p_tempe->lcsr.vmctrl &= ~0x100000;
+	vme_sync_data();
+	p_tempe->lcsr.rmwen = vmeRmw->enableMask;
+	p_tempe->lcsr.rmwc = vmeRmw->compareData;
+	p_tempe->lcsr.rmws = vmeRmw->swapData;
+	p_tempe->lcsr.rmwau = 0;
+	p_tempe->lcsr.rmwal = (int)rmw_pci_data_ptr;
+	p_tempe->lcsr.vmctrl |= 0x100000;
+	vme_sync_data();
+
+	// Run the RMW cycle until either success or max attempts.
+	vmeRmw->numAttempts = 1;
+	while (vmeRmw->numAttempts <= vmeRmw->maxAttempts) {
+
+		if ((*va_data_ptr & vmeRmw->enableMask) ==
+		    (vmeRmw->swapData & vmeRmw->enableMask)) {
+
+			break;
+
+		}
+		vmeRmw->numAttempts++;
+	}
+
+	p_tempe->lcsr.vmctrl &= ~0x100000;
+	vme_sync_data();
+
+	// If no success, set num Attempts to be greater than max attempts
+	if (vmeRmw->numAttempts > vmeRmw->maxAttempts) {
+		vmeRmw->numAttempts = vmeRmw->maxAttempts + 1;
+	}
+
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : dma_src_attr, dma_dst_attr
+// Description: Helper functions which setup common portions of the 
+//      DMA source and destination attribute registers.
+//-----------------------------------------------------------------------------
+static int dma_src_attr(vmeDmaPacket_t *vmeCur)
+{
+
+	int dsatreg = 0;
+	// calculate source attribute register
+	switch (vmeCur->srcBus) {
+	case VME_DMA_PATTERN_BYTE:
+		dsatreg = 0x23000000;
+		break;
+	case VME_DMA_PATTERN_BYTE_INCREMENT:
+		dsatreg = 0x22000000;
+		break;
+	case VME_DMA_PATTERN_WORD:
+		dsatreg = 0x21000000;
+		break;
+	case VME_DMA_PATTERN_WORD_INCREMENT:
+		dsatreg = 0x20000000;
+		break;
+	case VME_DMA_PCI:
+		dsatreg = 0x00000000;
+		break;
+	case VME_DMA_VME:
+		dsatreg = 0x10000000;
+		dsatreg |= tempe_setup_attribute(vmeCur->srcVmeAttr.addrSpace,
+						 vmeCur->srcVmeAttr.
+						 userAccessType,
+						 vmeCur->srcVmeAttr.
+						 dataAccessType,
+						 vmeCur->srcVmeAttr.
+						 maxDataWidth,
+						 vmeCur->srcVmeAttr.
+						 xferProtocol,
+						 vmeCur->srcVmeAttr.
+						 xferRate2esst);
+		break;
+	default:
+		dsatreg = -EINVAL;
+		break;
+	}
+	return (dsatreg);
+}
+
+static int dma_dst_attr(vmeDmaPacket_t * vmeCur)
+{
+	int ddatreg = 0;
+	// calculate destination attribute register
+	switch (vmeCur->dstBus) {
+	case VME_DMA_PCI:
+		ddatreg = 0x00000000;
+		break;
+	case VME_DMA_VME:
+		ddatreg = 0x10000000;
+		ddatreg |= tempe_setup_attribute(vmeCur->dstVmeAttr.addrSpace,
+						 vmeCur->dstVmeAttr.
+						 userAccessType,
+						 vmeCur->dstVmeAttr.
+						 dataAccessType,
+						 vmeCur->dstVmeAttr.
+						 maxDataWidth,
+						 vmeCur->dstVmeAttr.
+						 xferProtocol,
+						 vmeCur->dstVmeAttr.
+						 xferRate2esst);
+		break;
+	default:
+		ddatreg = -EINVAL;
+		break;
+	}
+	return (ddatreg);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : tempe_start_dma
+// Description: Write the DMA controller registers with the contents
+//    needed to actually start the DMA operation.
+//    returns starting time stamp.
+//
+//    Starts either direct or chained mode as appropriate (based on dctlreg)
+//-----------------------------------------------------------------------------
+static unsigned int
+tempe_start_dma(int channel,
+		unsigned int dctlreg, tsi148DmaDescriptor_t * vmeLL)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	unsigned int val;
+
+	// Setup registers as needed for direct or chained.
+	if (dctlreg & 0x800000) {
+
+		// Write registers 
+		p_tempe->lcsr.dma[channel].dsau = vmeLL->dsau;
+		p_tempe->lcsr.dma[channel].dsal = vmeLL->dsal;
+		p_tempe->lcsr.dma[channel].ddau = vmeLL->ddau;
+		p_tempe->lcsr.dma[channel].ddal = vmeLL->ddal;
+		p_tempe->lcsr.dma[channel].dsat = vmeLL->dsat;
+		p_tempe->lcsr.dma[channel].ddat = vmeLL->ddat;
+		p_tempe->lcsr.dma[channel].dcnt = vmeLL->dcnt;
+		p_tempe->lcsr.dma[channel].ddbs = vmeLL->ddbs;
+	} else {
+		p_tempe->lcsr.dma[channel].dnlau = 0;
+		p_tempe->lcsr.dma[channel].dnlal = (unsigned int)vmeLL;
+	}
+	vme_sync_data();
+
+	// Start the operation
+	p_tempe->lcsr.dma[channel].dctl = dctlreg | 0x2000000;
+	val = get_tbl();
+	vme_sync_data();
+	return (val);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : tempe_setup_dma
+// Description: Create a linked list (possibly only 1 element long) of 
+//   Tempe DMA descriptors which will perform the DMA operation described
+//   by the DMA packet.  Flush descriptors from cache.
+//   Return pointer to beginning of list (or 0 on failure.).
+//-----------------------------------------------------------------------------
+static tsi148DmaDescriptor_t *tempe_setup_dma(vmeDmaPacket_t * vmeDma)
+{
+	vmeDmaPacket_t *vme_cur;
+	int max_per_page;
+	int currentLLcount;
+	tsi148DmaDescriptor_t *startLL;
+	tsi148DmaDescriptor_t *currentLL;
+	tsi148DmaDescriptor_t *nextLL;
+
+	max_per_page = PAGE_SIZE / sizeof(tsi148DmaDescriptor_t) - 1;
+	startLL = (tsi148DmaDescriptor_t *) __get_free_pages(GFP_KERNEL, 0);
+	if (startLL == 0) {
+		return (startLL);
+	}
+	// First allocate pages for descriptors and create linked list
+	vme_cur = vmeDma;
+	currentLL = startLL;
+	currentLLcount = 0;
+	while (vme_cur != 0) {
+		if (vme_cur->pNextPacket != 0) {
+			currentLL->dnlau = (unsigned int)0;
+			currentLL->dnlal = (unsigned int)(currentLL + 1);
+			currentLLcount++;
+			if (currentLLcount >= max_per_page) {
+				currentLL->dnlal =
+				    __get_free_pages(GFP_KERNEL, 0);
+				currentLLcount = 0;
+			}
+			currentLL = (tsi148DmaDescriptor_t *) currentLL->dnlal;
+		} else {
+			currentLL->dnlau = (unsigned int)0;
+			currentLL->dnlal = (unsigned int)0;
+		}
+		vme_cur = vme_cur->pNextPacket;
+	}
+
+	// Next fill in information for each descriptor
+	vme_cur = vmeDma;
+	currentLL = startLL;
+	while (vme_cur != 0) {
+		currentLL->dsau = vme_cur->srcAddrU;
+		currentLL->dsal = vme_cur->srcAddr;
+		currentLL->ddau = vme_cur->dstAddrU;
+		currentLL->ddal = vme_cur->dstAddr;
+		currentLL->dsat = dma_src_attr(vme_cur);
+		currentLL->ddat = dma_dst_attr(vme_cur);
+		currentLL->dcnt = vme_cur->byteCount;
+		currentLL->ddbs = vme_cur->bcastSelect2esst;
+
+		currentLL = (tsi148DmaDescriptor_t *) currentLL->dnlal;
+		vme_cur = vme_cur->pNextPacket;
+	}
+
+	// Convert Links to PCI addresses.
+	currentLL = startLL;
+	while (currentLL != 0) {
+		nextLL = (tsi148DmaDescriptor_t *) currentLL->dnlal;
+		currentLL->dnlal = (unsigned int)virt_to_bus(nextLL);
+		if (nextLL == 0)
+			currentLL->dnlal |= 1;
+		vme_flush_range((unsigned long)currentLL, 
+			(unsigned long)(currentLL + sizeof(tsi148DmaDescriptor_t)));
+		currentLL = nextLL;
+	}
+
+	// Return pointer to descriptors list 
+	return (startLL);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : tempe_free_dma
+// Description: Free all memory that is used to hold the DMA 
+//    descriptor linked list.  
+//
+//-----------------------------------------------------------------------------
+static int tempe_free_dma(tsi148DmaDescriptor_t * startLL)
+{
+	tsi148DmaDescriptor_t *currentLL;
+	tsi148DmaDescriptor_t *prevLL;
+	tsi148DmaDescriptor_t *nextLL;
+
+	// Convert Links to virtual addresses.
+	currentLL = startLL;
+	while (currentLL != 0) {
+		if (currentLL->dnlal & 1) {
+			currentLL->dnlal = 0;
+		} else {
+			currentLL->dnlal =
+			    (unsigned int)bus_to_virt(currentLL->dnlal);
+		}
+		currentLL = (tsi148DmaDescriptor_t *) currentLL->dnlal;
+	}
+
+	// Free all pages associated with the descriptors.
+	currentLL = startLL;
+	prevLL = currentLL;
+	while (currentLL != 0) {
+		nextLL = (tsi148DmaDescriptor_t *) currentLL->dnlal;
+		if (currentLL + 1 != nextLL) {
+			free_pages((int)prevLL, 0);
+			prevLL = nextLL;
+		}
+		currentLL = nextLL;
+	}
+
+	// Return pointer to descriptors list 
+	return (0);
+}
+
+/*
+ * Function   : tempe_do_dma
+ * Description:  
+ *  Sanity check the DMA request. 
+ *  Setup DMA attribute register. 
+ *  Create linked list of DMA descriptors.
+ *  Invoke actual DMA operation.
+ *  Wait for completion.  Record ending time.
+ *  Free the linked list of DMA descriptors.
+ */
+
+int tempe_do_dma(vmeDmaPacket_t * vmeDma)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	unsigned int dctlreg = 0;
+	int val;
+	int channel, x;
+	vmeDmaPacket_t *cur_dma;
+	tsi148DmaDescriptor_t *dmaLL;
+
+	/* Sanity check the VME chain */
+	channel = vmeDma->channel_number;
+	if (channel > 1) {
+		return (-EINVAL);
+	}
+	cur_dma = vmeDma;
+	while (cur_dma != 0) {
+		if (cur_dma->byteCount == 0) {
+			return (-EINVAL);
+		}
+		if (dma_src_attr(cur_dma) < 0) {
+			return (-EINVAL);
+		}
+		if (dma_dst_attr(cur_dma) < 0) {
+			return (-EINVAL);
+		}
+
+		cur_dma = cur_dma->pNextPacket;
+		if (cur_dma == vmeDma) {	// Endless Loop!
+			return (-EINVAL);
+		}
+	}
+
+	/* calculate control register */
+	if (vmeDma->pNextPacket != 0) {
+		dctlreg = 0;
+	} else {
+		dctlreg = 0x800000;
+	}
+
+	for (x = 0; x < 8; x++) {	// vme block size
+		if ((32 << x) >= vmeDma->maxVmeBlockSize) {
+			break;
+		}
+	}
+	if (x == 8)
+		x = 7;
+	dctlreg |= (x << 12);
+
+	for (x = 0; x < 8; x++) {	// pci block size
+		if ((32 << x) >= vmeDma->maxPciBlockSize) {
+			break;
+		}
+	}
+	if (x == 8)
+		x = 7;
+	dctlreg |= (x << 4);
+
+	if (vmeDma->vmeBackOffTimer) {
+		for (x = 1; x < 8; x++) {	// vme timer
+			if ((1 << (x - 1)) >= vmeDma->vmeBackOffTimer) {
+				break;
+			}
+		}
+		if (x == 8)
+			x = 7;
+		dctlreg |= (x << 8);
+	}
+
+	if (vmeDma->pciBackOffTimer) {
+		for (x = 1; x < 8; x++) {	// pci timer
+			if ((1 << (x - 1)) >= vmeDma->pciBackOffTimer) {
+				break;
+			}
+		}
+		if (x == 8)
+			x = 7;
+		dctlreg |= (x << 0);
+	}
+	/* Setup the dma chain */
+	dmaLL = tempe_setup_dma(vmeDma);
+
+	/* Start the DMA */
+	if (dctlreg & 0x800000) {
+		vmeDma->vmeDmaStartTick =
+		    tempe_start_dma(channel, dctlreg, dmaLL);
+	} else {
+		vmeDma->vmeDmaStartTick =
+		    tempe_start_dma(channel, dctlreg, (tsi148DmaDescriptor_t *)
+				    virt_to_phys(dmaLL));
+	}
+
+	wait_event_interruptible(dma_queue[channel],
+				 (p_tempe->lcsr.dma[channel].
+				  dsta & 0x1000000) == 0);
+	val = p_tempe->lcsr.dma[channel].dsta;
+
+	vmeDma->vmeDmaStopTick = tempe_dma_irq_time[channel];
+	vmeDma->vmeDmaStatus = val;
+	if (vmeDma->vmeDmaStopTick < vmeDma->vmeDmaStartTick) {
+		vmeDma->vmeDmaElapsedTime =
+		    (0xFFFFFFFF - vmeDma->vmeDmaStartTick) +
+		    vmeDma->vmeDmaStopTick;
+	} else {
+		vmeDma->vmeDmaElapsedTime =
+		    vmeDma->vmeDmaStopTick - vmeDma->vmeDmaStartTick;
+	}
+	vmeDma->vmeDmaElapsedTime -= vmechip_irq_overhead_ticks;
+	vmeDma->vmeDmaElapsedTime /= (tb_speed / 1000000);
+
+	vmeDma->vmeDmaStatus = 0;
+	if (val & 0x10000000) {
+		printk(KERN_ERR
+		       "tsi148: DMA Error in DMA_tempe_irqhandler DSTA=%08X\n",
+		       val);
+		vmeDma->vmeDmaStatus = val;
+
+	}
+	/* Free the dma chain */
+	tempe_free_dma(dmaLL);
+
+	return (0);
+}
+
+/*
+ * Function:    tsi148_shutdown
+ * Description: Put VME bridge in quiescent state.  Disable all decoders,
+ * clear all interrupts.
+ */
+
+void tsi148_shutdown(void)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int i;
+
+	/*
+	 *  Shutdown all inbound and outbound windows.
+	 */
+	for (i = 0; i < 8; i++) {
+		p_tempe->lcsr.inboundTranslation[i].itat = 0;
+		p_tempe->lcsr.outboundTranslation[i].otat = 0;
+	}
+
+	/*
+	 *  Shutdown Location monitor.
+	 */
+	p_tempe->lcsr.lmat = 0;
+
+	/*
+	 *  Shutdown CRG map.
+	 */
+	p_tempe->lcsr.csrat = 0;
+
+	/*
+	 *  Clear error status.
+	 */
+	p_tempe->lcsr.edpat = 0xFFFFFFFF;
+	p_tempe->lcsr.veat = 0xFFFFFFFF;
+	p_tempe->lcsr.pstat = 0x07000700;
+
+	/*
+	 *  Remove VIRQ interrupt (if any)
+	 */
+	if (p_tempe->lcsr.vicr & 0x800) {
+		p_tempe->lcsr.vicr = 0x8000;
+	}
+
+	/*
+	 *  Disable and clear all interrupts.
+	 */
+	p_tempe->lcsr.inteo = 0;
+	vme_sync_data();
+	p_tempe->lcsr.intc = 0xFFFFFFFF;
+	vme_sync_data();
+	p_tempe->lcsr.inten = 0xFFFFFFFF;
+
+	/*
+	 *  Map all Interrupts to PCI INTA
+	 */
+	p_tempe->lcsr.intm1 = 0;
+	p_tempe->lcsr.intm2 = 0;
+
+	vme_sync_data();
+}
+
+/*
+ * Function:    tempe_init()
+ * Description: Initialize the VME chip as needed by the driver.
+ *    Quiesce VME bridge.
+ *    Setup default decoders.
+ *    Connect IRQ handler and enable interrupts.
+ *    Conduct quick sanity check of bridge.
+ */
+
+int tempe_init(void)
+{
+	tsi148_t *p_tempe = (tsi148_t *) vmechip_baseaddr;
+	int result;
+	unsigned int tmp;
+	unsigned int crcsr_addr;
+	u32 vme_stat_reg;
+//	int overhead_ticks;
+//	unsigned int irq_overhead_start;
+
+	tsi148_shutdown();
+
+	/* Determine syscon and slot number */
+	tmp = p_tempe->lcsr.vstat;
+	if (tmp & 0x100) {
+		vme_syscon = 1;
+	} else {
+		vme_syscon = 0;
+	}
+
+	/* Initialize crcsr map */
+	if (vme_slotnum != -1) {
+		p_tempe->crcsr.cbar = vme_slotnum << 3;
+		crcsr_addr = vme_slotnum * 512 * 1024;
+		p_tempe->lcsr.crol = (unsigned long)vmechip_interboard_datap;
+		p_tempe->lcsr.crou = 0;
+		vme_sync_data();
+		p_tempe->lcsr.crat = 0xFFFFFFFF;
+	}
+
+	result = request_irq(vmechip_irq,
+				tempe_irqhandler,
+				IRQF_SHARED,
+				"VMEBus (Tsi148)", 
+				vmechip_baseaddr);
+	if (result) {
+		printk(KERN_ERR
+		       "tsi148: can't get assigned pci irq vector %02X\n",
+		       vmechip_irq);
+		return (0);
+	}
+	/* Enable DMA, mailbox, VIRQ (syscon only) & LM Interrupts */
+	if (vme_syscon)
+		tmp = 0x03FF20FE;
+	else
+		tmp = 0x03FF2000;
+	p_tempe->lcsr.inteo = tmp;
+	p_tempe->lcsr.inten = tmp;
+
+	/* Do a quick sanity test of the bridge */
+	if (p_tempe->lcsr.inteo != tmp) {
+		return (0);
+	}
+	/* Sanity check register access */
+	for (tmp = 1; tmp < 0x80000000; tmp = tmp << 1) {
+		p_tempe->lcsr.rmwen = tmp;
+		p_tempe->lcsr.rmwc = ~tmp;
+		vme_sync_data();
+		if (p_tempe->lcsr.rmwen != tmp) {
+			return (0);
+		}
+		if (p_tempe->lcsr.rmwc != ~tmp) {
+			return (0);
+		}
+	}
+
+	/* Calculate IRQ overhead */
+#if 0
+	irq_overhead_start = get_tbl();
+	p_tempe->gcsr.mbox[0] = 0;
+	vme_sync_data();
+	for (tmp = 0; tmp < 10; tmp++) {
+		vme_sync_data();
+	}
+
+	overhead_ticks = tempe_irq_time - irq_overhead_start;
+	if (overhead_ticks > 0) {
+		vmechip_irq_overhead_ticks = overhead_ticks;
+	} else {
+		vmechip_irq_overhead_ticks = 1;
+	}
+#endif
+	vmechip_irq_overhead_ticks = 2;
+
+	/* Clear board fail, and power-up reset */
+	vme_stat_reg = p_tempe->lcsr.vstat;
+	vme_stat_reg &= ~TSI148_LCSR_VSTAT_BRDFL;
+	vme_stat_reg |= TSI148_LCSR_VSTAT_CPURST;
+	p_tempe->lcsr.vstat = vme_stat_reg;
+
+	return (1);
+}
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/vme/tsi148.h linux-2.6.29.6.mod/drivers/vme/tsi148.h
--- linux-2.6.29.6.orig/drivers/vme/tsi148.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/vme/tsi148.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,1190 @@
+/*
+ * tsi148.h
+ *
+ * Support for the Tundra TSI148 VME Bridge chip
+ *
+ * Authors: Tom Armistead, Ajit Prem 
+ * Copyright 2004-2007 Motorola Inc.
+ *
+ * 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.
+ */
+
+#ifndef TSI148_H
+#define TSI148_H
+
+/*
+ *  Define the number of each that the Tsi148 supports.
+ */
+#define TSI148_MAX_OUT_WINDOWS        8	/* Max Outbound Windows */
+#define TSI148_MAX_IN_WINDOWS         8	/* Max Inbound Windows */
+#define TSI148_MAX_DMA_CNTRLS         2	/* Max DMA Controllers */
+#define TSI148_MAX_MAILBOXES          4	/* Max Mail Box registers */
+#define TSI148_MAX_SEMAPHORES         8	/* Max Semaphores */
+
+    /*
+     * Misc Structs that are used as part of the larger structs
+     */
+
+    /*
+     * Outbound Functions used in LCSR
+     */
+typedef struct {
+	unsigned int otsau;	/* Starting address */
+	unsigned int otsal;
+	unsigned int oteau;	/* Ending address */
+	unsigned int oteal;
+	unsigned int otofu;	/* Translation offset */
+	unsigned int otofl;
+	unsigned int otbs;	/* 2eSST broadcast select */
+	unsigned int otat;	/* Attributes */
+} tsi148OutboundTranslation_t;
+
+    /*
+     * Inbound Functions used in LCSR
+     */
+typedef struct {
+	unsigned int itsau;	/* Starting address */
+	unsigned int itsal;
+	unsigned int iteau;	/* Ending address */
+	unsigned int iteal;
+	unsigned int itofu;	/* Translation offset */
+	unsigned int itofl;
+	unsigned int itat;	/* Attributes */
+	unsigned char reserved10[4];
+} tsi148InboundTranslation_t;
+
+    /*
+     * DMA Controller used in LCSR
+     */
+typedef struct {
+	unsigned int dctl;	/* Control */
+	unsigned int dsta;	/* Status */
+	unsigned int dcsau;	/* RO Current Source address */
+	unsigned int dcsal;
+	unsigned int dcdau;	/* RO Current Destination address */
+	unsigned int dcdal;
+	unsigned int dclau;	/* RO Current Link address */
+	unsigned int dclal;
+	unsigned int dsau;	/* Source Address */
+	unsigned int dsal;
+	unsigned int ddau;	/* Destination Address */
+	unsigned int ddal;
+	unsigned int dsat;	/* Source attributes */
+	unsigned int ddat;	/* Destination attributes */
+	unsigned int dnlau;	/* Next link address */
+	unsigned int dnlal;
+	unsigned int dcnt;	/* Byte count */
+	unsigned int ddbs;	/* 2eSST Broadcast select */
+	unsigned char reserved12[0x38];
+} tsi148Dma_t;
+
+    /*
+     *  Layout of a DMAC Linked-List Descriptor
+     */
+struct tsi148DmaDescriptor {
+	unsigned int dsau;	/* Source Address */
+	unsigned int dsal;
+	unsigned int ddau;	/* Destination Address */
+	unsigned int ddal;
+	unsigned int dsat;	/* Source attributes */
+	unsigned int ddat;	/* Destination attributes */
+	unsigned int dnlau;	/* Next link address */
+	unsigned int dnlal;
+	unsigned int dcnt;	/* Byte count */
+	unsigned int ddbs;	/* 2eSST Broadcast select */
+};
+typedef struct tsi148DmaDescriptor tsi148DmaDescriptor_t;
+
+    /*
+     * PCFS Configuration - includes memory base address register MBAR
+     */
+typedef struct {
+	unsigned short veni;	/* PCI header VENI/DEVI */
+	unsigned short devi;
+	unsigned short cmmd;	/* PCI header CMMD/STAT */
+	unsigned short stat;
+	unsigned int reviAndClas;	/* PCI header REVI/CLAS */
+	unsigned char clsz;	/* PCI header CLSZ/MLAT/HEAD/reserved */
+	unsigned char mlat;
+	unsigned char head;
+	unsigned char reserved0[1];
+	unsigned int mbarl;	/* PCI header MBARL */
+	unsigned int mbaru;	/* PCI header MBARU */
+	unsigned char reserved1[20];
+	unsigned short subv;	/* PCI header SUBV/SUBI */
+	unsigned short subi;
+	unsigned char reserved2[4];	/* PCI header reserved */
+	unsigned char capp;	/* PCI header CAPP/reserved */
+	unsigned char reserved3[7];	/* PCI header reserved */
+	unsigned char intl;	/* PCI header INTL/INTP/MNGM/MXLA */
+	unsigned char intp;
+	unsigned char mngn;
+	unsigned char mxla;
+
+	/*
+	 * offset 40  040 - MSI Capp MSICD/NCAPP/MSCI
+	 * offset 44  044 - MSI Capp MSIAL
+	 * offset 48  048 - MSI Capp MSIAU
+	 * offset 4C  04C - MSI Capp MSIMD/reserved
+	 */
+	unsigned char msiCapID;
+	unsigned char msiNextCapPtr;
+	unsigned short msiControl;
+	unsigned int msiMsgAddrL;
+	unsigned int msiMsgAddrU;
+	unsigned short msiMsgData;
+	unsigned char reserved4[2];
+
+	/*
+	 * offset 50  050 - PCI-X Capp PCIXCD/NCAPP/PCIXCAP
+	 * offset 54  054 - PCI-X Capp PCIXSTAT
+	 */
+	unsigned char pcixCapID;
+	unsigned char pcixNextCapPtr;
+	unsigned short pcixCommand;
+	unsigned int pcixStatus;
+
+	/*
+	 * offset 58  058  Reserved
+	 * ...
+	 * offset FF  0FF  Reserved
+	 */
+	unsigned char reserved5[167];
+
+} tsi148Pcfs_t;
+
+    /*
+     * LCSR definitions
+     */
+typedef struct {
+
+	/*
+	 *    Outbound Translations
+	 */
+	tsi148OutboundTranslation_t outboundTranslation[TSI148_MAX_OUT_WINDOWS];
+
+	/*
+	 * VMEbus interupt ack
+	 * offset  200
+	 *
+	 *      Note:   Even though the registers are defined
+	 *              as 32-bits in the spec, we only want
+	 *              to issue 8-bit IACK cycles on the bus.
+	 */
+	unsigned char viack[8 * 4];
+
+	/*
+	 * RMW
+	 * offset    220
+	 */
+	unsigned int rmwau;
+	unsigned int rmwal;
+	unsigned int rmwen;
+	unsigned int rmwc;
+	unsigned int rmws;
+
+	/*
+	 * VMEbus control
+	 * offset    234
+	 */
+	unsigned int vmctrl;
+	unsigned int vctrl;
+	unsigned int vstat;
+
+	/*
+	 * PCI status
+	 * offset  240
+	 */
+	unsigned int pstat;
+	unsigned char pstatrsvd[0xc];
+
+	/*
+	 * VME filter.
+	 * offset  250
+	 */
+	unsigned int vmefl;
+	unsigned char vmeflrsvd[0xc];
+
+	/*
+	 * VME exception.
+	 * offset  260
+	 */
+	unsigned int veau;
+	unsigned int veal;
+	unsigned int veat;
+	unsigned char vearsvd[0x4];
+
+	/*
+	 * PCI error
+	 * offset  270
+	 */
+	unsigned int edpau;
+	unsigned int edpal;
+	unsigned int edpxa;
+	unsigned int edpxs;
+	unsigned int edpat;
+	unsigned char edparsvd[0x7c];
+
+	/*
+	 * Inbound Translations
+	 * offset  300
+	 */
+	tsi148InboundTranslation_t inboundTranslation[TSI148_MAX_IN_WINDOWS];
+
+	/*
+	 * Inbound Translation GCSR
+	 * offset  400 
+	 */
+	unsigned int gbau;
+	unsigned int gbal;
+	unsigned int gcsrat;
+
+	/*
+	 * Inbound Translation CRG
+	 * offset  40C 
+	 */
+	unsigned int cbau;
+	unsigned int cbal;
+	unsigned int csrat;
+
+	/*
+	 * Inbound Translation CR/CSR
+	 *         CRG
+	 * offset  418
+	 */
+	unsigned int crou;
+	unsigned int crol;
+	unsigned int crat;
+
+	/*
+	 * Inbound Translation Location Monitor
+	 * offset  424 
+	 */
+	unsigned int lmbau;
+	unsigned int lmbal;
+	unsigned int lmat;
+
+	/*
+	 * VMEbus Interrupt Control.
+	 * offset  430
+	 */
+	unsigned int bcu;
+	unsigned int bcl;
+	unsigned int bpgtr;
+	unsigned int bpctr;
+	unsigned int vicr;
+
+	unsigned char vicrsvd[0x4];
+
+	/*
+	 * Local Bus Interrupt Control.
+	 * offset  448
+	 */
+	unsigned int inten;
+	unsigned int inteo;
+	unsigned int ints;
+	unsigned int intc;
+	unsigned int intm1;
+	unsigned int intm2;
+
+	unsigned char reserved7[0xa0];
+
+	/*
+	 * DMA Controllers
+	 * offset 500
+	 */
+	tsi148Dma_t dma[TSI148_MAX_DMA_CNTRLS];
+
+} tsi148Lcsr_t;
+
+    /*
+     * GCSR Register Group
+     */
+typedef struct {
+	/*
+	 * Header
+	 *         GCSR    CRG
+	 * offset   00     600 - DEVI/VENI
+	 */
+	unsigned short devi;
+	unsigned short veni;
+
+	/*
+	 * Control
+	 *         GCSR    CRG
+	 * offset   04     604 - CTRL/GA/REVID
+	 */
+	unsigned short ctrl;
+	unsigned char ga;
+	unsigned char revid;
+
+	/*
+	 * Semaphore
+	 *         GCSR    CRG
+	 * offset   08     608 - Semaphore3/2/1/0
+	 * offset   0C     60C - Seamphore7/6/5/4
+	 */
+	unsigned char semaphore[TSI148_MAX_SEMAPHORES];
+
+	/*
+	 * Mail Box
+	 *         GCSR    CRG
+	 * offset   10     610 - Mailbox0
+	 */
+	unsigned int mbox[TSI148_MAX_MAILBOXES];
+
+} tsi148Gcsr_t;
+
+    /*
+     * CR/CSR
+     */
+typedef struct {
+	/*
+	 *        CR/CSR   CRG
+	 * offset  7FFF4   FF4 - CSRBCR
+	 * offset  7FFF8   FF8 - CSRBSR
+	 * offset  7FFFC   FFC - CBAR
+	 */
+	unsigned int csrbcr;
+	unsigned int csrbsr;
+	unsigned int cbar;
+} tsi148Crcsr_t;
+
+    /*
+     *  TSI148 ASIC register structure overlays and bit field definitions.
+     *
+     *      Note:   Tsi148 Register Group (CRG) consists of the following
+     *              combination of registers:
+     *                      PCFS    - PCI Configuration Space Registers
+     *                      LCSR    - Local Control and Status Registers
+     *                      GCSR    - Global Control and Status Registers
+     *                      CR/CSR  - Subset of Configuration ROM /
+     *                                Control and Status Registers
+     */
+
+    /*
+     *  Combined Register Group (CRG)
+     */
+typedef struct {
+	/*
+	 * PCFS
+	 */
+	tsi148Pcfs_t pcfs;
+
+	/*
+	 * LCSR
+	 */
+	tsi148Lcsr_t lcsr;
+
+	/*
+	 * GCSR
+	 */
+	tsi148Gcsr_t gcsr;
+
+	/*
+	 * Fill Space
+	 */
+	unsigned char reserved9[0xFF4 - 0x61C - 4];
+
+	/*
+	 * CR/CSR
+	 */
+	tsi148Crcsr_t crcsr;
+
+} tsi148_t;
+
+    /*
+     *  TSI148 Register Bit Definitions
+     */
+
+    /*
+     *  PFCS Register Set
+     */
+
+    /*
+     *  Command/Status Registers (CRG + $004)
+     */
+#define TSI148_PCFS_CMMD_SERR          (1<<8)	/* SERR_L out pin ssys err */
+#define TSI148_PCFS_CMMD_PERR          (1<<6)	/* PERR_L out pin  parity */
+#define TSI148_PCFS_CMMD_MSTR          (1<<2)	/* PCI bus master */
+#define TSI148_PCFS_CMMD_MEMSP         (1<<1)	/* PCI mem space access  */
+#define TSI148_PCFS_CMMD_IOSP          (1<<0)	/* PCI I/O space enable */
+
+#define TSI148_PCFS_STAT_RCPVE         (1<<15)	/* Detected Parity Error */
+#define TSI148_PCFS_STAT_SIGSE         (1<<14)	/* Signalled System Error */
+#define TSI148_PCFS_STAT_RCVMA         (1<<13)	/* Received Master Abort */
+#define TSI148_PCFS_STAT_RCVTA         (1<<12)	/* Received Target Abort */
+#define TSI148_PCFS_STAT_SIGTA         (1<<11)	/* Signalled Target Abort */
+#define TSI148_PCFS_STAT_SELTIM        (3<<9)	/* DELSEL Timing */
+#define TSI148_PCFS_STAT_DPAR          (1<<8)	/* Data Parity Err Reported */
+#define TSI148_PCFS_STAT_FAST          (1<<7)	/* Fast back-to-back Cap */
+#define TSI148_PCFS_STAT_P66M          (1<<5)	/* 66 MHz Capable */
+#define TSI148_PCFS_STAT_CAPL          (1<<4)	/* Capab List - address $34 */
+
+    /*
+     *  Revision ID/Class Code Registers   (CRG +$008)
+     */
+#define TSI148_PCFS_CLAS_M             (0xFF<<24)	/* Class ID */
+#define TSI148_PCFS_SUBCLAS_M          (0xFF<<16)	/* Sub-Class ID */
+#define TSI148_PCFS_PROGIF_M           (0xFF<<8)	/* Sub-Class ID */
+#define TSI148_PCFS_REVID_M            (0xFF<<0)	/* Rev ID */
+
+    /*
+     * Cache Line Size/ Master Latency Timer/ Header Type Registers (CRG + $00C)
+     */
+#define TSI148_PCFS_HEAD_M             (0xFF<<16)	/* Master Lat Timer */
+#define TSI148_PCFS_MLAT_M             (0xFF<<8)	/* Master Lat Timer */
+#define TSI148_PCFS_CLSZ_M             (0xFF<<0)	/* Cache Line Size */
+
+    /*
+     *  Memory Base Address Lower Reg (CRG + $010)
+     */
+#define TSI148_PCFS_MBARL_BASEL_M      (0xFFFFF<<12)	/* Base Addr Lower Mask */
+#define TSI148_PCFS_MBARL_PRE          (1<<3)	/* Prefetch */
+#define TSI148_PCFS_MBARL_MTYPE_M      (3<<1)	/* Memory Type Mask */
+#define TSI148_PCFS_MBARL_IOMEM        (1<<0)	/* I/O Space Indicator */
+
+    /*
+     *  Message Signaled Interrupt Capabilities Register (CRG + $040)
+     */
+#define TSI148_PCFS_MSICAP_64BAC       (1<<7)	/* 64-bit Address Capable */
+#define TSI148_PCFS_MSICAP_MME_M       (7<<4)	/* Multiple Msg Enable Mask */
+#define TSI148_PCFS_MSICAP_MMC_M       (7<<1)	/* Multiple Msg Capable Mask */
+#define TSI148_PCFS_MSICAP_MSIEN       (1<<0)	/* Msg signaled INT Enable */
+
+    /*
+     *  Message Address Lower Register (CRG +$044)
+     */
+#define TSI148_PCFS_MSIAL_M            (0x3FFFFFFF<<2)	/* Mask */
+
+    /*
+     *  Message Data Register (CRG + 4C)
+     */
+#define TSI148_PCFS_MSIMD_M            (0xFFFF<<0)	/* Mask */
+
+    /*
+     *  PCI-X Capabilities Register (CRG + $050)
+     */
+#define TSI148_PCFS_PCIXCAP_MOST_M     (7<<4)	/* Max outstanding Split Tran */
+#define TSI148_PCFS_PCIXCAP_MMRBC_M    (3<<2)	/* Max Mem Read byte cnt */
+#define TSI148_PCFS_PCIXCAP_ERO        (1<<1)	/* Enable Relaxed Ordering */
+#define TSI148_PCFS_PCIXCAP_DPERE      (1<<0)	/* Data Parity Recover Enable */
+
+    /*
+     *  PCI-X Status Register (CRG +$054)
+     */
+#define TSI148_PCFS_PCIXSTAT_RSCEM     (1<<29)	/* Recieved Split Comp Error */
+#define TSI148_PCFS_PCIXSTAT_DMCRS_M   (7<<26)	/* max Cumulative Read Size */
+#define TSI148_PCFS_PCIXSTAT_DMOST_M   (7<<23)	/* max outstanding Split Trans */
+#define TSI148_PCFS_PCIXSTAT_DMMRC_M   (3<<21)	/* max mem read byte count */
+#define TSI148_PCFS_PCIXSTAT_DC        (1<<20)	/* Device Complexity */
+#define TSI148_PCFS_PCIXSTAT_USC       (1<<19)	/* Unexpected Split comp */
+#define TSI148_PCFS_PCIXSTAT_SCD       (1<<18)	/* Split completion discard */
+#define TSI148_PCFS_PCIXSTAT_133C      (1<<17)	/* 133MHz capable */
+#define TSI148_PCFS_PCIXSTAT_64D       (1<<16)	/* 64 bit device */
+#define TSI148_PCFS_PCIXSTAT_BN_M      (0xFF<<8)	/* Bus number */
+#define TSI148_PCFS_PCIXSTAT_DN_M      (0x1F<<3)	/* Device number */
+#define TSI148_PCFS_PCIXSTAT_FN_M      (7<<0)	/* Function Number */
+
+    /*
+     *  LCSR Registers
+     */
+
+    /*
+     *  Outbound Translation Starting Address Lower
+     */
+#define TSI148_LCSR_OTSAL_M            (0xFFFF<<16)	/* Mask */
+
+    /*
+     *  Outbound Translation Ending Address Lower
+     */
+#define TSI148_LCSR_OTEAL_M            (0xFFFF<<16)	/* Mask */
+
+    /*
+     *  Outbound Translation Offset Lower
+     */
+#define TSI148_LCSR_OTOFFL_M           (0xFFFF<<16)	/* Mask */
+
+    /*
+     *  Outbound Translation 2eSST Broadcast Select
+     */
+#define TSI148_LCSR_OTBS_M             (0xFFFFF<<0)	/* Mask */
+
+    /*
+     *  Outbound Translation Attribute
+     */
+#define TSI148_LCSR_OTAT_EN            (1<<31)	/* Window Enable */
+#define TSI148_LCSR_OTAT_MRPFD         (1<<18)	/* Prefetch Disable */
+
+#define TSI148_LCSR_OTAT_PFS_M         (3<<16)	/* Prefetch Size Mask */
+#define TSI148_LCSR_OTAT_PFS_2         (0<<16)	/* 2 Cache Lines P Size */
+#define TSI148_LCSR_OTAT_PFS_4         (1<<16)	/* 4 Cache Lines P Size */
+#define TSI148_LCSR_OTAT_PFS_8         (2<<16)	/* 8 Cache Lines P Size */
+#define TSI148_LCSR_OTAT_PFS_16        (3<<16)	/* 16 Cache Lines P Size */
+
+#define TSI148_LCSR_OTAT_2eSSTM_M      (3<<11)	/* 2eSST Xfer Rate Mask */
+#define TSI148_LCSR_OTAT_2eSSTM_160    (0<<11)	/* 160MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_OTAT_2eSSTM_267    (1<<11)	/* 267MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_OTAT_2eSSTM_320    (2<<11)	/* 320MB/s 2eSST Xfer Rate */
+
+#define TSI148_LCSR_OTAT_TM_M          (7<<8)	/* Xfer Protocol Mask */
+#define TSI148_LCSR_OTAT_TM_SCT        (0<<8)	/* SCT Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_BLT        (1<<8)	/* BLT Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_MBLT       (2<<8)	/* MBLT Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_2eVME      (3<<8)	/* 2eVME Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_2eSST      (4<<8)	/* 2eSST Xfer Protocol */
+#define TSI148_LCSR_OTAT_TM_2eSSTB     (5<<8)	/* 2eSST Bcast Xfer Protocol */
+
+#define TSI148_LCSR_OTAT_DBW_M         (3<<6)	/* Max Data Width */
+#define TSI148_LCSR_OTAT_DBW_16        (0<<6)	/* 16-bit Data Width */
+#define TSI148_LCSR_OTAT_DBW_32        (1<<6)	/* 32-bit Data Width */
+
+#define TSI148_LCSR_OTAT_SUP           (1<<5)	/* Supervisory Access */
+#define TSI148_LCSR_OTAT_PGM           (1<<4)	/* Program Access */
+
+#define TSI148_LCSR_OTAT_AMODE_M       (0xf<<0)	/* Address Mode Mask */
+#define TSI148_LCSR_OTAT_AMODE_A16     (0<<0)	/* A16 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_A24     (1<<0)	/* A24 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_A32     (2<<0)	/* A32 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_A64     (4<<0)	/* A32 Address Space */
+#define TSI148_LCSR_OTAT_AMODE_CRCSR   (5<<0)	/* CR/CSR Address Space */
+
+    /*
+     *  VME Master Control Register  CRG+$234
+     */
+#define TSI148_LCSR_VMCTRL_VSA         (1<<27)	/* VMEbus Stop Ack */
+#define TSI148_LCSR_VMCTRL_VS          (1<<26)	/* VMEbus Stop */
+#define TSI148_LCSR_VMCTRL_DHB         (1<<25)	/* Device Has Bus */
+#define TSI148_LCSR_VMCTRL_DWB         (1<<24)	/* Device Wants Bus */
+
+#define TSI148_LCSR_VMCTRL_RMWEN       (1<<20)	/* RMW Enable */
+
+#define TSI148_LCSR_VMCTRL_ATO_M       (7<<16)	/* Master Access Time-out Mask */
+#define TSI148_LCSR_VMCTRL_ATO_32      (0<<16)	/* 32 us */
+#define TSI148_LCSR_VMCTRL_ATO_128     (1<<16)	/* 128 us */
+#define TSI148_LCSR_VMCTRL_ATO_512     (2<<16)	/* 512 us */
+#define TSI148_LCSR_VMCTRL_ATO_2M      (3<<16)	/* 2 ms */
+#define TSI148_LCSR_VMCTRL_ATO_8M      (4<<16)	/* 8 ms */
+#define TSI148_LCSR_VMCTRL_ATO_32M     (5<<16)	/* 32 ms */
+#define TSI148_LCSR_VMCTRL_ATO_128M    (6<<16)	/* 128 ms */
+#define TSI148_LCSR_VMCTRL_ATO_DIS     (7<<16)	/* Disabled */
+
+#define TSI148_LCSR_VMCTRL_VTOFF_M     (7<<12)	/* VMEbus Master Time off */
+#define TSI148_LCSR_VMCTRL_VTOFF_0     (0<<12)	/* 0us */
+#define TSI148_LCSR_VMCTRL_VTOFF_1     (1<<12)	/* 1us */
+#define TSI148_LCSR_VMCTRL_VTOFF_2     (2<<12)	/* 2us */
+#define TSI148_LCSR_VMCTRL_VTOFF_4     (3<<12)	/* 4us */
+#define TSI148_LCSR_VMCTRL_VTOFF_8     (4<<12)	/* 8us */
+#define TSI148_LCSR_VMCTRL_VTOFF_16    (5<<12)	/* 16us */
+#define TSI148_LCSR_VMCTRL_VTOFF_32    (6<<12)	/* 32us */
+#define TSI148_LCSR_VMCTRL_VTOFF_64    (7<<12)	/* 64us */
+
+#define TSI148_LCSR_VMCTRL_VTON_M      (7<<8)	/* VMEbus Master Time On */
+#define TSI148_LCSR_VMCTRL_VTON_4      (0<<8)	/* 8us */
+#define TSI148_LCSR_VMCTRL_VTON_8      (1<<8)	/* 8us */
+#define TSI148_LCSR_VMCTRL_VTON_16     (2<<8)	/* 16us */
+#define TSI148_LCSR_VMCTRL_VTON_32     (3<<8)	/* 32us */
+#define TSI148_LCSR_VMCTRL_VTON_64     (4<<8)	/* 64us */
+#define TSI148_LCSR_VMCTRL_VTON_128    (5<<8)	/* 128us */
+#define TSI148_LCSR_VMCTRL_VTON_256    (6<<8)	/* 256us */
+#define TSI148_LCSR_VMCTRL_VTON_512    (7<<8)	/* 512us */
+
+#define TSI148_LCSR_VMCTRL_VREL_M      (3<<3)	/* VMEbus Master Rel Mode Mask */
+#define TSI148_LCSR_VMCTRL_VREL_T_D    (0<<3)	/* Time on or Done */
+#define TSI148_LCSR_VMCTRL_VREL_T_R_D  (1<<3)	/* Time on and REQ or Done */
+#define TSI148_LCSR_VMCTRL_VREL_T_B_D  (2<<3)	/* Time on and BCLR or Done */
+#define TSI148_LCSR_VMCTRL_VREL_T_D_R  (3<<3)	/* Time on or Done and REQ */
+
+#define TSI148_LCSR_VMCTRL_VFAIR       (1<<2)	/* VMEbus Master Fair Mode */
+#define TSI148_LCSR_VMCTRL_VREQL_M     (3<<0)	/* VMEbus Master Req Level Mask */
+
+    /*
+     *  VMEbus Control Register CRG+$238
+     */
+#define TSI148_LCSR_VCTRL_LRE          (1<<31)	/* Late Retry Enable */
+
+#define TSI148_LCSR_VCTRL_DLT_M        (0xF<<24)	/* Deadlock Timer */
+#define TSI148_LCSR_VCTRL_DLT_OFF      (0<<24)	/* Deadlock Timer Off */
+#define TSI148_LCSR_VCTRL_DLT_16       (1<<24)	/* 16 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_32       (2<<24)	/* 32 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_64       (3<<24)	/* 64 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_128      (4<<24)	/* 128 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_256      (5<<24)	/* 256 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_512      (6<<24)	/* 512 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_1024     (7<<24)	/* 1024 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_2048     (8<<24)	/* 2048 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_4096     (9<<24)	/* 4096 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_8192     (0xA<<24)	/* 8192 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_16384    (0xB<<24)	/* 16384 VCLKS */
+#define TSI148_LCSR_VCTRL_DLT_32768    (0xC<<24)	/* 32768 VCLKS */
+
+#define TSI148_LCSR_VCTRL_NERBB        (1<<20)	/* No Early Release of Bus Busy */
+
+#define TSI148_LCSR_VCTRL_SRESET       (1<<17)	/* System Reset */
+#define TSI148_LCSR_VCTRL_LRESET       (1<<16)	/* Local Reset */
+
+#define TSI148_LCSR_VCTRL_SFAILAI      (1<<15)	/* SYSFAIL Auto Slot ID */
+#define TSI148_LCSR_VCTRL_BID_M        (0x1F<<8)	/* Broadcast ID Mask */
+
+#define TSI148_LCSR_VCTRL_ATOEN        (1<<7)	/* Arbiter Time-out Enable */
+#define TSI148_LCSR_VCTRL_ROBIN        (1<<6)	/* VMEbus Round Robin */
+
+#define TSI148_LCSR_VCTRL_GTO_M        (7<<0)	/* VMEbus Global Time-out Mask */
+#define TSI148_LCSR_VCTRL_GTO_8	      (0<<0)	/* 8 us */
+#define TSI148_LCSR_VCTRL_GTO_16	      (1<<0)	/* 16 us */
+#define TSI148_LCSR_VCTRL_GTO_32	      (2<<0)	/* 32 us */
+#define TSI148_LCSR_VCTRL_GTO_64	      (3<<0)	/* 64 us */
+#define TSI148_LCSR_VCTRL_GTO_128      (4<<0)	/* 128 us */
+#define TSI148_LCSR_VCTRL_GTO_256      (5<<0)	/* 256 us */
+#define TSI148_LCSR_VCTRL_GTO_512      (6<<0)	/* 512 us */
+#define TSI148_LCSR_VCTRL_GTO_DIS      (7<<0)	/* Disabled */
+
+    /*
+     *  VMEbus Status Register  CRG + $23C
+     */
+#define TSI148_LCSR_VSTAT_CPURST       (1<<15)	/* Clear power up reset */
+#define TSI148_LCSR_VSTAT_BRDFL        (1<<14)	/* Board fail */
+#define TSI148_LCSR_VSTAT_PURSTS       (1<<12)	/* Power up reset status */
+#define TSI148_LCSR_VSTAT_BDFAILS      (1<<11)	/* Board Fail Status */
+#define TSI148_LCSR_VSTAT_SYSFAILS     (1<<10)	/* System Fail Status */
+#define TSI148_LCSR_VSTAT_ACFAILS      (1<<9)	/* AC fail status */
+#define TSI148_LCSR_VSTAT_SCONS        (1<<8)	/* System Cont Status */
+#define TSI148_LCSR_VSTAT_GAP          (1<<5)	/* Geographic Addr Parity */
+#define TSI148_LCSR_VSTAT_GA_M         (0x1F<<0)	/* Geographic Addr Mask */
+
+    /*
+     *  PCI Configuration Status Register CRG+$240
+     */
+#define TSI148_LCSR_PSTAT_REQ64S       (1<<6)	/* Request 64 status set */
+#define TSI148_LCSR_PSTAT_M66ENS       (1<<5)	/* M66ENS 66Mhz enable */
+#define TSI148_LCSR_PSTAT_FRAMES       (1<<4)	/* Frame Status */
+#define TSI148_LCSR_PSTAT_IRDYS        (1<<3)	/* IRDY status */
+#define TSI148_LCSR_PSTAT_DEVSELS      (1<<2)	/* DEVL status */
+#define TSI148_LCSR_PSTAT_STOPS        (1<<1)	/* STOP status */
+#define TSI148_LCSR_PSTAT_TRDYS        (1<<0)	/* TRDY status */
+
+    /*
+     *  Inbound Translation Starting Address Lower
+     */
+#define TSI148_LCSR_ITSAL6432_M        (0xFFFF<<16)	/* Mask */
+#define TSI148_LCSR_ITSAL24_M          (0x00FFF<<12)	/* Mask */
+#define TSI148_LCSR_ITSAL16_M          (0x0000FFF<<4)	/* Mask */
+
+    /*
+     *  Inbound Translation Ending Address Lower
+     */
+#define TSI148_LCSR_ITEAL6432_M        (0xFFFF<<16)	/* Mask */
+#define TSI148_LCSR_ITEAL24_M          (0x00FFF<<12)	/* Mask */
+#define TSI148_LCSR_ITEAL16_M          (0x0000FFF<<4)	/* Mask */
+
+    /*
+     *  Inbound Translation Offset Lower
+     */
+#define TSI148_LCSR_ITOFFL6432_M       (0xFFFF<<16)	/* Mask */
+#define TSI148_LCSR_ITOFFL24_M         (0xFFFFF<<12)	/* Mask */
+#define TSI148_LCSR_ITOFFL16_M         (0xFFFFFFF<<4)	/* Mask */
+
+    /*
+     *  Inbound Translation Attribute
+     */
+#define TSI148_LCSR_ITAT_EN            (1<<31)	/* Window Enable */
+#define TSI148_LCSR_ITAT_TH            (1<<18)	/* Prefetch Threshold */
+
+#define TSI148_LCSR_ITAT_VFS_M         (3<<16)	/* Virtual FIFO Size Mask */
+#define TSI148_LCSR_ITAT_VFS_64        (0<<16)	/* 64 bytes Virtual FIFO Size */
+#define TSI148_LCSR_ITAT_VFS_128       (1<<16)	/* 128 bytes Virtual FIFO Sz */
+#define TSI148_LCSR_ITAT_VFS_256       (2<<16)	/* 256 bytes Virtual FIFO Sz */
+#define TSI148_LCSR_ITAT_VFS_512       (3<<16)	/* 512 bytes Virtual FIFO Sz */
+
+#define TSI148_LCSR_ITAT_2eSSTM_M      (7<<12)	/* 2eSST Xfer Rate Mask */
+#define TSI148_LCSR_ITAT_2eSSTM_160    (0<<12)	/* 160MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_ITAT_2eSSTM_267    (1<<12)	/* 267MB/s 2eSST Xfer Rate */
+#define TSI148_LCSR_ITAT_2eSSTM_320    (2<<12)	/* 320MB/s 2eSST Xfer Rate */
+
+#define TSI148_LCSR_ITAT_2eSSTB        (1<<11)	/* 2eSST Bcast Xfer Protocol */
+#define TSI148_LCSR_ITAT_2eSST         (1<<10)	/* 2eSST Xfer Protocol */
+#define TSI148_LCSR_ITAT_2eVME         (1<<9)	/* 2eVME Xfer Protocol */
+#define TSI148_LCSR_ITAT_MBLT          (1<<8)	/* MBLT Xfer Protocol */
+#define TSI148_LCSR_ITAT_BLT           (1<<7)	/* BLT Xfer Protocol */
+
+#define TSI148_LCSR_ITAT_AS_M          (7<<4)	/* Address Space Mask */
+#define TSI148_LCSR_ITAT_AS_A16        (0<<4)	/* A16 Address Space */
+#define TSI148_LCSR_ITAT_AS_A24        (1<<4)	/* A24 Address Space */
+#define TSI148_LCSR_ITAT_AS_A32        (2<<4)	/* A32 Address Space */
+#define TSI148_LCSR_ITAT_AS_A64        (4<<4)	/* A64 Address Space */
+
+#define TSI148_LCSR_ITAT_SUPR          (1<<3)	/* Supervisor Access */
+#define TSI148_LCSR_ITAT_NPRIV         (1<<2)	/* Non-Priv (User) Access */
+#define TSI148_LCSR_ITAT_PGM           (1<<1)	/* Program Access */
+#define TSI148_LCSR_ITAT_DATA          (1<<0)	/* Data Access */
+
+    /*
+     *  GCSR Base Address Lower Address  CRG +$404
+     */
+#define TSI148_LCSR_GBAL_M             (0x7FFFFFF<<5)	/* Mask */
+
+    /*
+     *  GCSR Attribute Register CRG + $408
+     */
+#define TSI148_LCSR_GCSRAT_EN          (1<<7)	/* Enable access to GCSR */
+
+#define TSI148_LCSR_GCSRAT_AS_M        (7<<4)	/* Address Space Mask */
+#define TSI148_LCSR_GCSRAT_AS_16       (0<<4)	/* Address Space 16 */
+#define TSI148_LCSR_GCSRAT_AS_24       (1<<4)	/* Address Space 24 */
+#define TSI148_LCSR_GCSRAT_AS_32       (2<<4)	/* Address Space 32 */
+#define TSI148_LCSR_GCSRAT_AS_64       (4<<4)	/* Address Space 64 */
+
+#define TSI148_LCSR_GCSRAT_SUPR        (1<<3)	/* Sup set -GCSR decoder */
+#define TSI148_LCSR_GCSRAT_NPRIV       (1<<2)	/* Non-Privliged set - CGSR */
+#define TSI148_LCSR_GCSRAT_PGM         (1<<1)	/* Program set - GCSR decoder */
+#define TSI148_LCSR_GCSRAT_DATA        (1<<0)	/* DATA set GCSR decoder */
+
+    /*
+     *  CRG Base Address Lower Address  CRG + $410
+     */
+#define TSI148_LCSR_CBAL_M             (0xFFFFF<<12)
+
+    /*
+     *  CRG Attribute Register  CRG + $414
+     */
+#define TSI148_LCSR_CRGAT_EN           (1<<7)	/* Enable PRG Access */
+
+#define TSI148_LCSR_CRGAT_AS_M         (7<<4)	/* Address Space */
+#define TSI148_LCSR_CRGAT_AS_16        (0<<4)	/* Address Space 16 */
+#define TSI148_LCSR_CRGAT_AS_24        (1<<4)	/* Address Space 24 */
+#define TSI148_LCSR_CRGAT_AS_32        (2<<4)	/* Address Space 32 */
+#define TSI148_LCSR_CRGAT_AS_64        (4<<4)	/* Address Space 64 */
+
+#define TSI148_LCSR_CRGAT_SUPR         (1<<3)	/* Supervisor Access */
+#define TSI148_LCSR_CRGAT_NPRIV        (1<<2)	/* Non-Privliged(User) Access */
+#define TSI148_LCSR_CRGAT_PGM          (1<<1)	/* Program Access */
+#define TSI148_LCSR_CRGAT_DATA         (1<<0)	/* Data Access */
+
+    /*
+     *  CR/CSR Offset Lower Register  CRG + $41C
+     */
+#define TSI148_LCSR_CROL_M             (0x1FFF<<19)	/* Mask */
+
+    /*
+     *  CR/CSR Attribute register  CRG + $420
+     */
+#define TSI148_LCSR_CRAT_EN            (1<<7)	/* Enable access to CR/CSR */
+
+    /*
+     *  Location Monitor base address lower register  CRG + $428
+     */
+#define TSI148_LCSR_LMBAL_M            (0x7FFFFFF<<5)	/* Mask */
+
+    /*
+     *  Location Monitor Attribute Register  CRG + $42C
+     */
+#define TSI148_LCSR_LMAT_EN            (1<<7)	/* Enable Location Monitor */
+
+#define TSI148_LCSR_LMAT_AS_M          (7<<4)	/* Address Space MASK  */
+#define TSI148_LCSR_LMAT_AS_16         (0<<4)	/* A16 */
+#define TSI148_LCSR_LMAT_AS_24         (1<<4)	/* A24 */
+#define TSI148_LCSR_LMAT_AS_32         (2<<4)	/* A32 */
+#define TSI148_LCSR_LMAT_AS_64         (4<<4)	/* A64 */
+
+#define TSI148_LCSR_LMAT_SUPR          (1<<3)	/* Supervisor Access */
+#define TSI148_LCSR_LMAT_NPRIV         (1<<2)	/* Non-Priv (User) Access */
+#define TSI148_LCSR_LMAT_PGM           (1<<1)	/* Program Access */
+#define TSI148_LCSR_LMAT_DATA          (1<<0)	/* Data Access  */
+
+    /*
+     *  Broadcast Pulse Generator Timer Register  CRG + $438
+     */
+#define TSI148_LCSR_BPGTR_BPGT_M       (0xFFFF<<0)	/* Mask */
+
+    /*
+     *  Broadcast Programmable Clock Timer Register  CRG + $43C
+     */
+#define TSI148_LCSR_BPCTR_BPCT_M       (0xFFFFFF<<0)	/* Mask */
+
+    /*
+     *  VMEbus Interrupt Control Register           CRG + $43C
+     */
+#define TSI148_LCSR_VICR_CNTS_M        (3<<22)	/* Cntr Source MASK */
+#define TSI148_LCSR_VICR_CNTS_DIS      (1<<22)	/* Cntr Disable */
+#define TSI148_LCSR_VICR_CNTS_IRQ1     (2<<22)	/* IRQ1 to Cntr */
+#define TSI148_LCSR_VICR_CNTS_IRQ2     (3<<22)	/* IRQ2 to Cntr */
+
+#define TSI148_LCSR_VICR_EDGIS_M       (3<<20)	/* Edge interupt MASK */
+#define TSI148_LCSR_VICR_EDGIS_DIS     (1<<20)	/* Edge interupt Disable */
+#define TSI148_LCSR_VICR_EDGIS_IRQ1    (2<<20)	/* IRQ1 to Edge */
+#define TSI148_LCSR_VICR_EDGIS_IRQ2    (3<<20)	/* IRQ2 to Edge */
+
+#define TSI148_LCSR_VICR_IRQIF_M       (3<<18)	/* IRQ1* Function MASK */
+#define TSI148_LCSR_VICR_IRQIF_NORM    (1<<18)	/* Normal */
+#define TSI148_LCSR_VICR_IRQIF_PULSE   (2<<18)	/* Pulse Generator */
+#define TSI148_LCSR_VICR_IRQIF_PROG    (3<<18)	/* Programmable Clock */
+#define TSI148_LCSR_VICR_IRQIF_1U      (4<<18)	/* 1us Clock */
+
+#define TSI148_LCSR_VICR_IRQ2F_M       (3<<16)	/* IRQ2* Function MASK */
+#define TSI148_LCSR_VICR_IRQ2F_NORM    (1<<16)	/* Normal */
+#define TSI148_LCSR_VICR_IRQ2F_PULSE   (2<<16)	/* Pulse Generator */
+#define TSI148_LCSR_VICR_IRQ2F_PROG    (3<<16)	/* Programmable Clock */
+#define TSI148_LCSR_VICR_IRQ2F_1U      (4<<16)	/* 1us Clock */
+
+#define TSI148_LCSR_VICR_BIP           (1<<15)	/* Broadcast Interrupt Pulse */
+
+#define TSI148_LCSR_VICR_IRQC          (1<<12)	/* VMEbus IRQ Clear */
+#define TSI148_LCSR_VICR_IRQS          (1<<11)	/* VMEbus IRQ Status */
+
+#define TSI148_LCSR_VICR_IRQL_M        (7<<8)	/* VMEbus SW IRQ Level Mask */
+#define TSI148_LCSR_VICR_IRQL_1        (1<<8)	/* VMEbus SW IRQ Level 1 */
+#define TSI148_LCSR_VICR_IRQL_2        (2<<8)	/* VMEbus SW IRQ Level 2 */
+#define TSI148_LCSR_VICR_IRQL_3        (3<<8)	/* VMEbus SW IRQ Level 3 */
+#define TSI148_LCSR_VICR_IRQL_4        (4<<8)	/* VMEbus SW IRQ Level 4 */
+#define TSI148_LCSR_VICR_IRQL_5        (5<<8)	/* VMEbus SW IRQ Level 5 */
+#define TSI148_LCSR_VICR_IRQL_6        (6<<8)	/* VMEbus SW IRQ Level 6 */
+#define TSI148_LCSR_VICR_IRQL_7        (7<<8)	/* VMEbus SW IRQ Level 7 */
+
+#define TSI148_LCSR_VICR_STID_M        (0xFF<<0)	/* Status/ID Mask */
+
+    /*
+     *  Interrupt Enable Register   CRG + $440
+     */
+#define TSI148_LCSR_INTEN_DMA1EN       (1<<25)	/* DMAC 1 */
+#define TSI148_LCSR_INTEN_DMA0EN       (1<<24)	/* DMAC 0 */
+#define TSI148_LCSR_INTEN_LM3EN        (1<<23)	/* Location Monitor 3 */
+#define TSI148_LCSR_INTEN_LM2EN        (1<<22)	/* Location Monitor 2 */
+#define TSI148_LCSR_INTEN_LM1EN        (1<<21)	/* Location Monitor 1 */
+#define TSI148_LCSR_INTEN_LM0EN        (1<<20)	/* Location Monitor 0 */
+#define TSI148_LCSR_INTEN_MB3EN        (1<<19)	/* Mail Box 3 */
+#define TSI148_LCSR_INTEN_MB2EN        (1<<18)	/* Mail Box 2 */
+#define TSI148_LCSR_INTEN_MB1EN        (1<<17)	/* Mail Box 1 */
+#define TSI148_LCSR_INTEN_MB0EN        (1<<16)	/* Mail Box 0 */
+#define TSI148_LCSR_INTEN_VBEREN       (1<<13)	/* VMEbus Error */
+#define TSI148_LCSR_INTEN_VATOEN       (1<<12)	/* VMEbus Access Time-out */
+#define TSI148_LCSR_INTEN_VIEEN        (1<<11)	/* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTEN_IACKEN       (1<<10)	/* IACK */
+#define TSI148_LCSR_INTEN_SYSFLEN      (1<<9)	/* System Fail */
+#define TSI148_LCSR_INTEN_ACFLEN       (1<<8)	/* AC Fail */
+#define TSI148_LCSR_INTEN_IRQ7EN       (1<<7)	/* IRQ7 */
+#define TSI148_LCSR_INTEN_IRQ6EN       (1<<6)	/* IRQ6 */
+#define TSI148_LCSR_INTEN_IRQ5EN       (1<<5)	/* IRQ5 */
+#define TSI148_LCSR_INTEN_IRQ4EN       (1<<4)	/* IRQ4 */
+#define TSI148_LCSR_INTEN_IRQ3EN       (1<<3)	/* IRQ3 */
+#define TSI148_LCSR_INTEN_IRQ2EN       (1<<2)	/* IRQ2 */
+#define TSI148_LCSR_INTEN_IRQ1EN       (1<<1)	/* IRQ1 */
+
+    /*
+     *  Interrupt Enable Out Register CRG + $444
+     */
+#define TSI148_LCSR_INTEO_DMA1EO       (1<<25)	/* DMAC 1 */
+#define TSI148_LCSR_INTEO_DMA0EO       (1<<24)	/* DMAC 0 */
+#define TSI148_LCSR_INTEO_LM3EO        (1<<23)	/* Loc Monitor 3 */
+#define TSI148_LCSR_INTEO_LM2EO        (1<<22)	/* Loc Monitor 2 */
+#define TSI148_LCSR_INTEO_LM1EO        (1<<21)	/* Loc Monitor 1 */
+#define TSI148_LCSR_INTEO_LM0EO        (1<<20)	/* Location Monitor 0 */
+#define TSI148_LCSR_INTEO_MB3EO        (1<<19)	/* Mail Box 3 */
+#define TSI148_LCSR_INTEO_MB2EO        (1<<18)	/* Mail Box 2 */
+#define TSI148_LCSR_INTEO_MB1EO        (1<<17)	/* Mail Box 1 */
+#define TSI148_LCSR_INTEO_MB0EO        (1<<16)	/* Mail Box 0 */
+#define TSI148_LCSR_INTEO_VBEREO       (1<<13)	/* VMEbus Error */
+#define TSI148_LCSR_INTEO_VATOEO       (1<<12)	/* VMEbus Access Time-out */
+#define TSI148_LCSR_INTEO_VIEEO        (1<<11)	/* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTEO_IACKEO       (1<<10)	/* IACK */
+#define TSI148_LCSR_INTEO_SYSFLEO      (1<<9)	/* System Fail */
+#define TSI148_LCSR_INTEO_ACFLEO       (1<<8)	/* AC Fail */
+#define TSI148_LCSR_INTEO_IRQ7EO       (1<<7)	/* IRQ7 */
+#define TSI148_LCSR_INTEO_IRQ6EO       (1<<6)	/* IRQ6 */
+#define TSI148_LCSR_INTEO_IRQ5EO       (1<<5)	/* IRQ5 */
+#define TSI148_LCSR_INTEO_IRQ4EO       (1<<4)	/* IRQ4 */
+#define TSI148_LCSR_INTEO_IRQ3EO       (1<<3)	/* IRQ3 */
+#define TSI148_LCSR_INTEO_IRQ2EO       (1<<2)	/* IRQ2 */
+#define TSI148_LCSR_INTEO_IRQ1EO       (1<<1)	/* IRQ1 */
+
+    /*
+     *  Interrupt Status Register CRG + $448
+     */
+#define TSI148_LCSR_INTS_DMA1S         (1<<25)	/* DMA 1 */
+#define TSI148_LCSR_INTS_DMA0S         (1<<24)	/* DMA 0 */
+#define TSI148_LCSR_INTS_LM3S          (1<<23)	/* Location Monitor 3 */
+#define TSI148_LCSR_INTS_LM2S          (1<<22)	/* Location Monitor 2 */
+#define TSI148_LCSR_INTS_LM1S          (1<<21)	/* Location Monitor 1 */
+#define TSI148_LCSR_INTS_LM0S          (1<<20)	/* Location Monitor 0 */
+#define TSI148_LCSR_INTS_MB3S          (1<<19)	/* Mail Box 3 */
+#define TSI148_LCSR_INTS_MB2S          (1<<18)	/* Mail Box 2 */
+#define TSI148_LCSR_INTS_MB1S          (1<<17)	/* Mail Box 1 */
+#define TSI148_LCSR_INTS_MB0S          (1<<16)	/* Mail Box 0 */
+#define TSI148_LCSR_INTS_VBERS         (1<<13)	/* VMEbus Error */
+#define TSI148_LCSR_INTS_VATOS         (1<<12)	/* VMEbus Access Time-out */
+#define TSI148_LCSR_INTS_VIES          (1<<11)	/* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTS_IACKS         (1<<10)	/* IACK */
+#define TSI148_LCSR_INTS_SYSFLS        (1<<9)	/* System Fail */
+#define TSI148_LCSR_INTS_ACFLS         (1<<8)	/* AC Fail */
+#define TSI148_LCSR_INTS_IRQ7S         (1<<7)	/* IRQ7 */
+#define TSI148_LCSR_INTS_IRQ6S         (1<<6)	/* IRQ6 */
+#define TSI148_LCSR_INTS_IRQ5S         (1<<5)	/* IRQ5 */
+#define TSI148_LCSR_INTS_IRQ4S         (1<<4)	/* IRQ4 */
+#define TSI148_LCSR_INTS_IRQ3S         (1<<3)	/* IRQ3 */
+#define TSI148_LCSR_INTS_IRQ2S         (1<<2)	/* IRQ2 */
+#define TSI148_LCSR_INTS_IRQ1S         (1<<1)	/* IRQ1 */
+
+    /*
+     *  Interrupt Clear Register CRG + $44C
+     */
+#define TSI148_LCSR_INTC_DMA1C         (1<<25)	/* DMA 1 */
+#define TSI148_LCSR_INTC_DMA0C         (1<<24)	/* DMA 0 */
+#define TSI148_LCSR_INTC_LM3C          (1<<23)	/* Location Monitor 3 */
+#define TSI148_LCSR_INTC_LM2C          (1<<22)	/* Location Monitor 2 */
+#define TSI148_LCSR_INTC_LM1C          (1<<21)	/* Location Monitor 1 */
+#define TSI148_LCSR_INTC_LM0C          (1<<20)	/* Location Monitor 0 */
+#define TSI148_LCSR_INTC_MB3C          (1<<19)	/* Mail Box 3 */
+#define TSI148_LCSR_INTC_MB2C          (1<<18)	/* Mail Box 2 */
+#define TSI148_LCSR_INTC_MB1C          (1<<17)	/* Mail Box 1 */
+#define TSI148_LCSR_INTC_MB0C          (1<<16)	/* Mail Box 0 */
+#define TSI148_LCSR_INTC_VBERC         (1<<13)	/* VMEbus Error */
+#define TSI148_LCSR_INTC_VATOC         (1<<12)	/* VMEbus Access Time-out */
+#define TSI148_LCSR_INTC_VIEC          (1<<11)	/* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTC_IACKC         (1<<10)	/* IACK */
+#define TSI148_LCSR_INTC_SYSFLC        (1<<9)	/* System Fail */
+#define TSI148_LCSR_INTC_ACFLC         (1<<8)	/* AC Fail */
+
+    /*
+     *  Interrupt Map Register 1 CRG + $458
+     */
+#define TSI148_LCSR_INTM1_DMA1M_M      (3<<18)	/* DMA 1 */
+#define TSI148_LCSR_INTM1_DMA0M_M      (3<<16)	/* DMA 0 */
+#define TSI148_LCSR_INTM1_LM3M_M       (3<<14)	/* Location Monitor 3 */
+#define TSI148_LCSR_INTM1_LM2M_M       (3<<12)	/* Location Monitor 2 */
+#define TSI148_LCSR_INTM1_LM1M_M       (3<<10)	/* Location Monitor 1 */
+#define TSI148_LCSR_INTM1_LM0M_M       (3<<8)	/* Location Monitor 0 */
+#define TSI148_LCSR_INTM1_MB3M_M       (3<<6)	/* Mail Box 3 */
+#define TSI148_LCSR_INTM1_MB2M_M       (3<<4)	/* Mail Box 2 */
+#define TSI148_LCSR_INTM1_MB1M_M       (3<<2)	/* Mail Box 1 */
+#define TSI148_LCSR_INTM1_MB0M_M       (3<<0)	/* Mail Box 0 */
+
+    /*
+     *  Interrupt Map Register 2 CRG + $45C
+     */
+#define TSI148_LCSR_INTM2_PERRM_M      (3<<26)	/* PCI Bus Error */
+#define TSI148_LCSR_INTM2_VERRM_M      (3<<24)	/* VMEbus Error */
+#define TSI148_LCSR_INTM2_VIEM_M       (3<<22)	/* VMEbus IRQ Edge */
+#define TSI148_LCSR_INTM2_IACKM_M      (3<<20)	/* IACK */
+#define TSI148_LCSR_INTM2_SYSFLM_M     (3<<18)	/* System Fail */
+#define TSI148_LCSR_INTM2_ACFLM_M      (3<<16)	/* AC Fail */
+#define TSI148_LCSR_INTM2_IRQ7M_M      (3<<14)	/* IRQ7 */
+#define TSI148_LCSR_INTM2_IRQ6M_M      (3<<12)	/* IRQ6 */
+#define TSI148_LCSR_INTM2_IRQ5M_M      (3<<10)	/* IRQ5 */
+#define TSI148_LCSR_INTM2_IRQ4M_M      (3<<8)	/* IRQ4 */
+#define TSI148_LCSR_INTM2_IRQ3M_M      (3<<6)	/* IRQ3 */
+#define TSI148_LCSR_INTM2_IRQ2M_M      (3<<4)	/* IRQ2 */
+#define TSI148_LCSR_INTM2_IRQ1M_M      (3<<2)	/* IRQ1 */
+
+    /*
+     *  DMA Control (0-1) Registers CRG + $500
+     */
+#define TSI148_LCSR_DCTL_ABT           (1<<27)	/* Abort */
+#define TSI148_LCSR_DCTL_PAU           (1<<26)	/* Pause */
+#define TSI148_LCSR_DCTL_DGO           (1<<25)	/* DMA Go */
+
+#define TSI148_LCSR_DCTL_MOD           (1<<23)	/* Mode */
+
+#define TSI148_LCSR_DCTL_VBKS_M        (7<<12)	/* VMEbus block Size MASK */
+#define TSI148_LCSR_DCTL_VBKS_32       (0<<12)	/* VMEbus block Size 32 */
+#define TSI148_LCSR_DCTL_VBKS_64       (1<<12)	/* VMEbus block Size 64 */
+#define TSI148_LCSR_DCTL_VBKS_128      (2<<12)	/* VMEbus block Size 128 */
+#define TSI148_LCSR_DCTL_VBKS_256      (3<<12)	/* VMEbus block Size 256 */
+#define TSI148_LCSR_DCTL_VBKS_512      (4<<12)	/* VMEbus block Size 512 */
+#define TSI148_LCSR_DCTL_VBKS_1024     (5<<12)	/* VMEbus block Size 1024 */
+#define TSI148_LCSR_DCTL_VBKS_2048     (6<<12)	/* VMEbus block Size 2048 */
+#define TSI148_LCSR_DCTL_VBKS_4096     (7<<12)	/* VMEbus block Size 4096 */
+
+#define TSI148_LCSR_DCTL_VBOT_M        (7<<8)	/* VMEbus back-off MASK */
+#define TSI148_LCSR_DCTL_VBOT_0        (0<<8)	/* VMEbus back-off  0us */
+#define TSI148_LCSR_DCTL_VBOT_1        (1<<8)	/* VMEbus back-off 1us */
+#define TSI148_LCSR_DCTL_VBOT_2        (2<<8)	/* VMEbus back-off 2us */
+#define TSI148_LCSR_DCTL_VBOT_4        (3<<8)	/* VMEbus back-off 4us */
+#define TSI148_LCSR_DCTL_VBOT_8        (4<<8)	/* VMEbus back-off 8us */
+#define TSI148_LCSR_DCTL_VBOT_16       (5<<8)	/* VMEbus back-off 16us */
+#define TSI148_LCSR_DCTL_VBOT_32       (6<<8)	/* VMEbus back-off 32us */
+#define TSI148_LCSR_DCTL_VBOT_64       (7<<8)	/* VMEbus back-off 64us */
+
+#define TSI148_LCSR_DCTL_PBKS_M        (7<<4)	/* PCI block size MASK */
+#define TSI148_LCSR_DCTL_PBKS_32       (0<<4)	/* PCI block size 32 bytes */
+#define TSI148_LCSR_DCTL_PBKS_64       (1<<4)	/* PCI block size 64 bytes */
+#define TSI148_LCSR_DCTL_PBKS_128      (2<<4)	/* PCI block size 128 bytes */
+#define TSI148_LCSR_DCTL_PBKS_256      (3<<4)	/* PCI block size 256 bytes */
+#define TSI148_LCSR_DCTL_PBKS_512      (4<<4)	/* PCI block size 512 bytes */
+#define TSI148_LCSR_DCTL_PBKS_1024     (5<<4)	/* PCI block size 1024 bytes */
+#define TSI148_LCSR_DCTL_PBKS_2048     (6<<4)	/* PCI block size 2048 bytes */
+#define TSI148_LCSR_DCTL_PBKS_4096     (7<<4)	/* PCI block size 4096 bytes */
+
+#define TSI148_LCSR_DCTL_PBOT_M        (7<<0)	/* PCI back off MASK */
+#define TSI148_LCSR_DCTL_PBOT_0        (0<<0)	/* PCI back off 0us */
+#define TSI148_LCSR_DCTL_PBOT_1        (1<<0)	/* PCI back off 1us */
+#define TSI148_LCSR_DCTL_PBOT_2        (2<<0)	/* PCI back off 2us */
+#define TSI148_LCSR_DCTL_PBOT_4        (3<<0)	/* PCI back off 3us */
+#define TSI148_LCSR_DCTL_PBOT_8        (4<<0)	/* PCI back off 4us */
+#define TSI148_LCSR_DCTL_PBOT_16       (5<<0)	/* PCI back off 8us */
+#define TSI148_LCSR_DCTL_PBOT_32       (6<<0)	/* PCI back off 16us */
+#define TSI148_LCSR_DCTL_PBOT_64       (7<<0)	/* PCI back off 32us */
+
+    /*
+     *  DMA Status Registers (0-1)  CRG + $504
+     */
+#define TSI148_LCSR_DSTA_SMA           (1<<31)	/* PCI Signalled Master Abt */
+#define TSI148_LCSR_DSTA_RTA           (1<<30)	/* PCI Received Target Abt */
+#define TSI148_LCSR_DSTA_MRC           (1<<29)	/* PCI Max Retry Count */
+#define TSI148_LCSR_DSTA_VBE           (1<<28)	/* VMEbus error */
+#define TSI148_LCSR_DSTA_ABT           (1<<27)	/* Abort */
+#define TSI148_LCSR_DSTA_PAU           (1<<26)	/* Pause */
+#define TSI148_LCSR_DSTA_DON           (1<<25)	/* Done */
+#define TSI148_LCSR_DSTA_BSY           (1<<24)	/* Busy */
+
+    /*
+     *  DMA Current Link Address Lower (0-1)
+     */
+#define TSI148_LCSR_DCLAL_M            (0x3FFFFFF<<6)	/* Mask */
+
+    /*
+     *  DMA Source Attribute (0-1) Reg
+     */
+#define TSI148_LCSR_DSAT_TYP_M         (3<<28)	/* Source Bus Type */
+#define TSI148_LCSR_DSAT_TYP_PCI       (0<<28)	/* PCI Bus */
+#define TSI148_LCSR_DSAT_TYP_VME       (1<<28)	/* VMEbus */
+#define TSI148_LCSR_DSAT_TYP_PAT       (2<<28)	/* Data Pattern */
+
+#define TSI148_LCSR_DSAT_PSZ           (1<<25)	/* Pattern Size */
+#define TSI148_LCSR_DSAT_NIN           (1<<24)	/* No Increment */
+
+#define TSI148_LCSR_DSAT_2eSSTM_M      (3<<11)	/* 2eSST Trans Rate Mask */
+#define TSI148_LCSR_DSAT_2eSSTM_160    (0<<11)	/* 160 MB/s */
+#define TSI148_LCSR_DSAT_2eSSTM_267    (1<<11)	/* 267 MB/s */
+#define TSI148_LCSR_DSAT_2eSSTM_320    (2<<11)	/* 320 MB/s */
+
+#define TSI148_LCSR_DSAT_TM_M          (7<<8)	/* Bus Transfer Protocol Mask */
+#define TSI148_LCSR_DSAT_TM_SCT        (0<<8)	/* SCT */
+#define TSI148_LCSR_DSAT_TM_BLT        (1<<8)	/* BLT */
+#define TSI148_LCSR_DSAT_TM_MBLT       (2<<8)	/* MBLT */
+#define TSI148_LCSR_DSAT_TM_2eVME      (3<<8)	/* 2eVME */
+#define TSI148_LCSR_DSAT_TM_2eSST      (4<<8)	/* 2eSST */
+#define TSI148_LCSR_DSAT_TM_2eSSTB     (5<<8)	/* 2eSST Broadcast */
+
+#define TSI148_LCSR_DSAT_DBW_M         (3<<6)	/* Max Data Width MASK */
+#define TSI148_LCSR_DSAT_DBW_16        (0<<6)	/* 16 Bits */
+#define TSI148_LCSR_DSAT_DBW_32        (1<<6)	/* 32 Bits */
+
+#define TSI148_LCSR_DSAT_SUP           (1<<5)	/* Supervisory Mode */
+#define TSI148_LCSR_DSAT_PGM           (1<<4)	/* Program Mode */
+
+#define TSI148_LCSR_DSAT_AMODE_M       (0xf<<0)	/* Address Space Mask */
+#define TSI148_LCSR_DSAT_AMODE_16      (0<<0)	/* A16 */
+#define TSI148_LCSR_DSAT_AMODE_24      (1<<0)	/* A24 */
+#define TSI148_LCSR_DSAT_AMODE_32      (2<<0)	/* A32 */
+#define TSI148_LCSR_DSAT_AMODE_64      (4<<0)	/* A64 */
+#define TSI148_LCSR_DSAT_AMODE_CRCSR   (5<<0)	/* CR/CSR */
+#define TSI148_LCSR_DSAT_AMODE_USER1   (8<<0)	/* User1 */
+#define TSI148_LCSR_DSAT_AMODE_USER2   (9<<0)	/* User2 */
+#define TSI148_LCSR_DSAT_AMODE_USER3   (0xa<<0)	/* User3 */
+#define TSI148_LCSR_DSAT_AMODE_USER4   (0xb<<0)	/* User4 */
+
+    /*
+     *  DMA Destination Attribute Registers (0-1)
+     */
+#define TSI148_LCSR_DDAT_TYP_VME       (1<<28)	/* Destination VMEbus */
+#define TSI148_LCSR_DDAT_TYP_PCI       (0<<28)	/* Destination PCI Bus  */
+
+#define TSI148_LCSR_DDAT_NIN           (1<<24)	/* No Increment */
+
+#define TSI148_LCSR_DDAT_2eSSTM_M      (3<<11)	/* 2eSST Transfer Rate Mask */
+#define TSI148_LCSR_DDAT_2eSSTM_160    (0<<11)	/* 160 MB/s */
+#define TSI148_LCSR_DDAT_2eSSTM_267    (1<<11)	/* 267 MB/s */
+#define TSI148_LCSR_DDAT_2eSSTM_320    (2<<11)	/* 320 MB/s */
+
+#define TSI148_LCSR_DDAT_TM_M          (7<<8)	/* Bus Transfer Protocol Mask */
+#define TSI148_LCSR_DDAT_TM_SCT        (0<<8)	/* SCT */
+#define TSI148_LCSR_DDAT_TM_BLT        (1<<8)	/* BLT */
+#define TSI148_LCSR_DDAT_TM_MBLT       (2<<8)	/* MBLT */
+#define TSI148_LCSR_DDAT_TM_2eVME      (3<<8)	/* 2eVME */
+#define TSI148_LCSR_DDAT_TM_2eSST      (4<<8)	/* 2eSST */
+#define TSI148_LCSR_DDAT_TM_2eSSTB     (5<<8)	/* 2eSST Broadcast */
+
+#define TSI148_LCSR_DDAT_DBW_M         (3<<6)	/* Max Data Width MASK */
+#define TSI148_LCSR_DDAT_DBW_16        (0<<6)	/* 16 Bits */
+#define TSI148_LCSR_DDAT_DBW_32        (1<<6)	/* 32 Bits */
+
+#define TSI148_LCSR_DDAT_SUP           (1<<5)	/* Supervisory/User Access */
+#define TSI148_LCSR_DDAT_PGM           (1<<4)	/* Program/Data Access */
+
+#define TSI148_LCSR_DDAT_AMODE_M       (0xf<<0)	/* Address Space Mask */
+#define TSI148_LCSR_DDAT_AMODE_16      (0<<0)	/* A16 */
+#define TSI148_LCSR_DDAT_AMODE_24      (1<<0)	/* A24 */
+#define TSI148_LCSR_DDAT_AMODE_32      (2<<0)	/* A32 */
+#define TSI148_LCSR_DDAT_AMODE_64      (4<<0)	/* A64 */
+#define TSI148_LCSR_DDAT_AMODE_CRCSR   (5<<0)	/* CRC/SR */
+#define TSI148_LCSR_DDAT_AMODE_USER1   (8<<0)	/* User1 */
+#define TSI148_LCSR_DDAT_AMODE_USER2   (9<<0)	/* User2 */
+#define TSI148_LCSR_DDAT_AMODE_USER3   (0xA<<0)	/* User3 */
+#define TSI148_LCSR_DDAT_AMODE_USER4   (0xB<<0)	/* User4 */
+
+    /*
+     *  DMA Next Link Address Lower
+     */
+#define TSI148_LCSR_DNLAL_DNLAL_M      (0x3FFFFFF<<6)	/* Address Mask */
+#define TSI148_LCSR_DNLAL_LLA          (1<<0)	/* Last Link Address Indicator */
+
+    /*
+     *  DMA 2eSST Broadcast Select
+     */
+#define TSI148_LCSR_DBS_M              (0x1FFFFF<<0)	/* Mask */
+
+    /*
+     *  GCSR Register Group
+     */
+
+    /*
+     *  GCSR Control and Status Register  CRG + $604
+     */
+#define TSI148_GCSR_GCTRL_LRST         (1<<15)	/* Local Reset */
+#define TSI148_GCSR_GCTRL_SFAILEN      (1<<14)	/* System Fail enable */
+#define TSI148_GCSR_GCTRL_BDFAILS      (1<<13)	/* Board Fail Status */
+#define TSI148_GCSR_GCTRL_SCON         (1<<12)	/* System Copntroller */
+#define TSI148_GCSR_GCTRL_MEN          (1<<11)	/* Module Enable (READY) */
+
+#define TSI148_GCSR_GCTRL_LMI3S        (1<<7)	/* Loc Monitor 3 Int Status */
+#define TSI148_GCSR_GCTRL_LMI2S        (1<<6)	/* Loc Monitor 2 Int Status */
+#define TSI148_GCSR_GCTRL_LMI1S        (1<<5)	/* Loc Monitor 1 Int Status */
+#define TSI148_GCSR_GCTRL_LMI0S        (1<<4)	/* Loc Monitor 0 Int Status */
+#define TSI148_GCSR_GCTRL_MBI3S        (1<<3)	/* Mail box 3 Int Status */
+#define TSI148_GCSR_GCTRL_MBI2S        (1<<2)	/* Mail box 2 Int Status */
+#define TSI148_GCSR_GCTRL_MBI1S        (1<<1)	/* Mail box 1 Int Status */
+#define TSI148_GCSR_GCTRL_MBI0S        (1<<0)	/* Mail box 0 Int Status */
+
+#define TSI148_GCSR_GAP                (1<<5)	/* Geographic Addr Parity */
+#define TSI148_GCSR_GA_M               (0x1F<<0)	/* Geographic Address Mask */
+
+    /*
+     *  CR/CSR Register Group
+     */
+
+    /*
+     *  CR/CSR Bit Clear Register CRG + $FF4
+     */
+#define TSI148_CRCSR_CSRBCR_LRSTC      (1<<7)	/* Local Reset Clear */
+#define TSI148_CRCSR_CSRBCR_SFAILC     (1<<6)	/* System Fail Enable Clear */
+#define TSI148_CRCSR_CSRBCR_BDFAILS    (1<<5)	/* Board Fail Status */
+#define TSI148_CRCSR_CSRBCR_MENC       (1<<4)	/* Module Enable Clear */
+#define TSI148_CRCSR_CSRBCR_BERRSC     (1<<3)	/* Bus Error Status Clear */
+
+    /*
+     *  CR/CSR Bit Set Register CRG+$FF8
+     */
+#define TSI148_CRCSR_CSRBSR_LISTS      (1<<7)	/* Local Reset Clear */
+#define TSI148_CRCSR_CSRBSR_SFAILS     (1<<6)	/* System Fail Enable Clear */
+#define TSI148_CRCSR_CSRBSR_BDFAILS    (1<<5)	/* Board Fail Status */
+#define TSI148_CRCSR_CSRBSR_MENS       (1<<4)	/* Module Enable Clear */
+#define TSI148_CRCSR_CSRBSR_BERRS      (1<<3)	/* Bus Error Status Clear */
+
+    /*
+     *  CR/CSR Base Address Register CRG + FFC
+     */
+#define TSI148_CRCSR_CBAR_M            (0x1F<<3)	/* Mask */
+
+#endif				/* TSI148_H */
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/vme/vmedrv.c linux-2.6.29.6.mod/drivers/vme/vmedrv.c
--- linux-2.6.29.6.orig/drivers/vme/vmedrv.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/vme/vmedrv.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,774 @@
+/*
+ * vmedrv.c
+ *
+ * Provided generic (non bridge specific) entry-points. The entry-points
+ * call CA91C042 or TSI148 specific routines and return the result. 
+ *
+ * Authors: Tom Armistead, Ajit Prem
+ *
+ * Copyright 2004-2007 Motorola Inc.
+ * Copyright 2008 Emerson Network Power - Embedded Computing, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+
+#include "vmedrv.h"
+#include "ca91c042.h"
+
+extern struct resource *vmepcimem;
+extern struct pci_dev *vme_pci_dev;
+
+/* Global VME controller information */
+int vmechip_irq;		// PCI irq
+int vmechip_irq_overhead_ticks;	// Interrupt overhead
+int vmechip_devid;		// PCI devID
+int vmeparent_devid;		// VME bridge parent ID
+int vmechip_revision;		// PCI revision
+int vmechip_bus;		// PCI bus number.
+void __iomem *vmechip_baseaddr;		// virtual address of chip registers
+int vme_slotnum = -1;		// VME slot num (-1 = unknown)
+int vme_syscon = -1;		// VME sys controller (-1 = unknown)
+
+/* address of board data */
+extern struct vmeSharedData *vmechip_interboard_data;
+
+extern struct resource out_resource[VME_MAX_WINDOWS];
+unsigned int out_image_va[VME_MAX_WINDOWS];	// Base virtual address
+
+/*
+ * External functions 
+ */
+extern int uni_init(void *);
+extern void uni_shutdown(void);
+extern int uni_set_arbiter(vmeArbiterCfg_t * vmeArb);
+extern int uni_get_arbiter(vmeArbiterCfg_t * vmeArb);
+extern int uni_set_requestor(vmeRequesterCfg_t * vmeReq);
+extern int uni_get_requestor(vmeRequesterCfg_t * vmeReq);
+extern int uni_set_in_bound(vmeInWindowCfg_t * vmeIn);
+extern int uni_get_in_bound(vmeInWindowCfg_t * vmeIn);
+extern int uni_set_out_bound(vmeOutWindowCfg_t * vmeOut);
+extern int uni_get_out_bound(vmeOutWindowCfg_t * vmeOut);
+extern int uni_setup_lm(vmeLmCfg_t * vmeLm);
+extern int uni_wait_lm(vmeLmCfg_t * vmeLm);
+extern int uni_do_rmw(vmeRmwCfg_t * vmeRmw);
+extern int uni_do_dma(vmeDmaPacket_t * vmeDma);
+extern int uni_generate_irq(virqInfo_t *);
+extern int uni_bus_error_chk(int);
+
+extern int tempe_init(void *);
+extern void tempe_shutdown(void);
+extern int tempe_set_arbiter(vmeArbiterCfg_t * vmeArb);
+extern int tempe_get_arbiter(vmeArbiterCfg_t * vmeArb);
+extern int tempe_set_requestor(vmeRequesterCfg_t * vmeReq);
+extern int tempe_get_requestor(vmeRequesterCfg_t * vmeReq);
+extern int tempe_set_in_bound(vmeInWindowCfg_t * vmeIn);
+extern int tempe_get_in_bound(vmeInWindowCfg_t * vmeIn);
+extern int tempe_set_out_bound(vmeOutWindowCfg_t * vmeOut);
+extern int tempe_get_out_bound(vmeOutWindowCfg_t * vmeOut);
+extern int tempe_setup_lm(vmeLmCfg_t * vmeLm);
+extern int tempe_wait_lm(vmeLmCfg_t * vmeLm);
+extern int tempe_do_rmw(vmeRmwCfg_t * vmeRmw);
+extern int tempe_do_dma(vmeDmaPacket_t * vmeDma);
+extern int tempe_generate_irq(virqInfo_t *);
+extern int tempe_bus_error_chk(int);
+
+extern wait_queue_head_t vmeint_queue[];
+
+int vme_irqlog[8][0x100];
+
+//----------------------------------------------------------------------------
+//  Some kernels don't supply pci_bus_mem_base_phys()... this subroutine
+//  provides that functionality.
+//----------------------------------------------------------------------------
+
+unsigned long vme_pci_bus_mem_base_phys(struct pci_bus *bus)
+{
+	struct pci_controller *hose;	
+	
+	hose = bus->sysdata;
+	if (!hose)
+		return 0;
+	return hose->pci_mem_offset;
+}
+
+//----------------------------------------------------------------------------
+//  vme_sync_data()
+//    Ensure completion of all previously issued loads/stores
+//----------------------------------------------------------------------------
+void vme_sync_data(void)
+{
+	asm("sync");		// PPC specific.
+	asm("eieio");
+}
+
+//----------------------------------------------------------------------------
+//  vme_flush_line(void *ptr)
+//    Flush & invalidate a cache line 
+//----------------------------------------------------------------------------
+extern void flush_dcache_range(unsigned long, unsigned long );
+
+#ifdef CONFIG_MVME6100
+void vme_flush_line(unsigned long start)
+{
+	flush_dcache_range(start, start + L1_CACHE_BYTES);
+}
+#else
+void vme_flush_line(unsigned long start) { }
+#endif
+
+//----------------------------------------------------------------------------
+//  vme_flush_range()
+//    Flush & invalidate a range of memory
+//----------------------------------------------------------------------------
+
+#ifdef CONFIG_MVME6100
+void vme_flush_range(unsigned long start, unsigned long end)
+{
+	flush_dcache_range(start, end);
+}
+#else
+void vme_flush_range(unsigned long start, unsigned long end) {}
+#endif
+
+//----------------------------------------------------------------------------
+//  vme_bus_error_chk()
+//     Return 1 if VME bus error occured, 0 otherwise.
+//     Optionally clear VME bus error status.
+//----------------------------------------------------------------------------
+int vme_bus_error_chk(int clrflag)
+{
+	vme_sync_data();
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_bus_error_chk(clrflag));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_bus_error_chk(clrflag));
+		break;
+	}
+	return (0);
+}
+
+//----------------------------------------------------------------------------
+//  vme_get_slot_num
+//    Determine the slot number that we are in.  Uses CR/CSR base 
+//    address reg if it contains a valid value.  If not, obtains
+//    slot number from board level register.
+//----------------------------------------------------------------------------
+int vme_get_slot_num(void)
+{
+	int slotnum = 0;
+
+	// get slot num from VME chip reg if it is set.
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		slotnum = readl(vmechip_baseaddr + VCSR_BS);
+		slotnum = (slotnum >> 27) & 0x1F;
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		slotnum = *(int *)(vmechip_baseaddr + 0x23C);
+		slotnum = slotnum & 0x1F;
+		return (slotnum);
+		break;
+	}
+
+	// Following is board specific!!
+
+#ifdef	MCG_MVME2600
+	if (slotnum == 0)
+		slotnum = ~inb(0x1006) & 0x1F;	// Genesis2 slot register
+#endif
+#ifdef	MCG_MVME2400
+	if (slotnum == 0)
+		slotnum = ~inb(0x1006) & 0x1F;	// Genesis2 slot register
+#endif
+#ifdef	MCG_MVME2300
+	if (slotnum == 0)
+		slotnum = ~inb(0x1006) & 0x1F;	// Genesis2 slot register
+#endif
+
+	return (slotnum);
+}
+
+//----------------------------------------------------------------------------
+//  vme_get_out_bound
+//    Return attributes of an outbound window.
+//----------------------------------------------------------------------------
+int vme_get_out_bound(vmeOutWindowCfg_t * vmeOut)
+{
+	int window_number;
+
+	window_number = vmeOut->windowNbr;
+	memset(vmeOut, 0, sizeof(vmeOutWindowCfg_t));
+	vmeOut->windowNbr = window_number;
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_get_out_bound(vmeOut));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_get_out_bound(vmeOut));
+		break;
+	}
+	return (0);
+}
+
+//----------------------------------------------------------------------------
+//  vme_set_out_bound
+//    Set attributes of an outbound window.
+//----------------------------------------------------------------------------
+int vme_set_out_bound(vmeOutWindowCfg_t * vmeOut)
+{
+	int window_number = vmeOut->windowNbr;
+	unsigned int existing_size;
+	char *res_name = NULL;
+
+        if (vmeOut->windowNbr > 7) 
+                return (-EINVAL);
+
+	if (vmepcimem == 0)
+		return (-ENOMEM);
+
+	// Allocate and map PCI memory space for this window.
+	existing_size =
+	    out_resource[window_number].end - out_resource[window_number].start;
+
+	if ((vmeOut->windowEnable == 0) || 
+			(existing_size != vmeOut->windowSizeL)) {
+		if (existing_size != 0) {
+			if (out_image_va[window_number] != 0) 
+				iounmap((char *)out_image_va[window_number]);
+			if (out_resource[window_number].name != NULL)
+				kfree(out_resource[window_number].name);
+			release_resource(&out_resource[window_number]);
+			memset(&out_resource[window_number], 0, sizeof(struct resource));
+		}
+	}
+
+	if ((vmeOut->windowEnable) && 
+			(existing_size != vmeOut->windowSizeL)) {
+
+		if (vmeOut->windowSizeL == 0)
+			return (-EINVAL);
+
+		res_name = kmalloc(32, GFP_KERNEL);
+		if (!res_name)
+			printk(KERN_ERR "vmedrv: kmalloc() failed!\n");
+		else
+			sprintf(res_name, "VME Window %01x", window_number);
+		out_resource[window_number].name = (char *)res_name;
+		out_resource[window_number].start = 0;
+		out_resource[window_number].end = vmeOut->windowSizeL;
+#ifdef CONFIG_MVME7100
+		out_resource[window_number].flags = IORESOURCE_MEM | IORESOURCE_PREFETCH;
+#else
+		out_resource[window_number].flags = IORESOURCE_MEM;
+#endif
+
+		if (pci_bus_alloc_resource(vme_pci_dev->bus,
+				   &out_resource[window_number],
+				   vmeOut->windowSizeL,
+				   vmeOut->windowSizeL,
+				   PCIBIOS_MIN_MEM, 
+#ifdef CONFIG_MVME7100
+				   IORESOURCE_PREFETCH,
+#else
+				   0, 
+#endif
+				   NULL, 
+			           NULL)) {
+			printk(KERN_ERR
+			       "vmedrv: Failed to allocate mem resource for window %d size 0x%x start 0x%x\n",
+			       window_number, vmeOut->windowSizeL,
+			       out_resource[window_number].start);
+			if (out_resource[window_number].name != NULL)
+				kfree(out_resource[window_number].name);
+			memset(&out_resource[window_number], 0, sizeof(struct resource));
+			return (-ENOMEM);
+		}
+
+		out_image_va[window_number] = (int)ioremap(out_resource[window_number].start,
+				 vmeOut->windowSizeL);
+		if (out_image_va[window_number] == 0) {
+			printk(KERN_ERR
+		       	"vmedrv: No memory for outbound window\n");
+			if (out_resource[window_number].name != NULL)
+				kfree(out_resource[window_number].name);
+			release_resource(&out_resource[window_number]);
+			memset(&out_resource[window_number], 0, sizeof(struct resource));
+			return (-ENOMEM);
+		}
+		vmeOut->pciBusAddrL = out_resource[window_number].start
+	    		- vme_pci_bus_mem_base_phys(vme_pci_dev->bus);
+	}
+
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_set_out_bound(vmeOut));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_set_out_bound(vmeOut));
+		break;
+	}
+	return (-ENODEV);
+}
+
+/*
+ *  vme_get_in_bound
+ *    Return attributes of an inbound window.
+ */
+
+int vme_get_in_bound(vmeInWindowCfg_t * vmeIn)
+{
+	int window_number;
+
+	window_number = vmeIn->windowNbr;
+	memset(vmeIn, 0, sizeof(vmeInWindowCfg_t));
+	vmeIn->windowNbr = window_number;
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_get_in_bound(vmeIn));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_get_in_bound(vmeIn));
+		break;
+	}
+	return (-ENODEV);
+}
+
+//----------------------------------------------------------------------------
+//  vme_set_in_bound
+//    Set attributes of an inbound window.
+//----------------------------------------------------------------------------
+int vme_set_in_bound(vmeInWindowCfg_t * vmeIn)
+{
+	int status = -ENODEV;
+
+	// Mask off VME address bits per address space.
+	switch (vmeIn->addrSpace) {
+	case VME_A16:
+		vmeIn->vmeAddrU = 0;
+		vmeIn->vmeAddrL &= 0xFFFF;
+		break;
+	case VME_A24:
+	case VME_CRCSR:
+		vmeIn->vmeAddrU = 0;
+		vmeIn->vmeAddrL &= 0xFFFFFF;
+		break;
+	case VME_A32:
+		vmeIn->vmeAddrU = 0;
+		break;
+	case VME_A64:
+	case VME_USER1:
+	case VME_USER2:
+	case VME_USER3:
+	case VME_USER4:
+		break;
+	}
+
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		status = uni_set_in_bound(vmeIn);
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		status = tempe_set_in_bound(vmeIn);
+		break;
+	}
+
+	if (!status) {
+		vmechip_interboard_data->inBoundVmeSize[vmeIn->windowNbr] =
+		    vmeIn->windowSizeL;
+		vme_flush_line((unsigned long)(&vmechip_interboard_data->
+			       inBoundVmeSize[vmeIn->windowNbr]));
+
+		vmechip_interboard_data->inBoundVmeAddrHi[vmeIn->windowNbr] =
+		    vmeIn->vmeAddrU;
+		vme_flush_line((unsigned long)(&vmechip_interboard_data->
+			       inBoundVmeAddrHi[vmeIn->windowNbr]));
+
+		vmechip_interboard_data->inBoundVmeAddrLo[vmeIn->windowNbr] =
+		    vmeIn->vmeAddrL;
+		vme_flush_line((unsigned long)(&vmechip_interboard_data->
+			       inBoundVmeAddrLo[vmeIn->windowNbr]));
+
+		vmechip_interboard_data->inBoundVmeAM[vmeIn->windowNbr] =
+		    vmeIn->addrSpace;
+		vme_flush_line((unsigned long)(&vmechip_interboard_data->
+			       inBoundVmeAM[vmeIn->windowNbr]));
+	}
+
+	return (status);
+}
+
+//----------------------------------------------------------------------------
+//  vme_do_dma()
+//     Perform the requested DMA operation.
+//     Caller must assure exclusive access to the DMA channel.  
+//----------------------------------------------------------------------------
+int vme_do_dma(vmeDmaPacket_t * vmeDma)
+{
+	int retval = -ENODEV;
+
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		retval = uni_do_dma(vmeDma);
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		retval = tempe_do_dma(vmeDma);
+		break;
+	}
+
+	return (retval);
+}
+
+//----------------------------------------------------------------------------
+//  vme_get_slot_info()
+//     Obtain information about the board (if any) that is present in
+//     a specified VME bus slot.   
+//
+//     (Note VME slot numbers start at 1, not 0).
+//     Depends on board mapping in CS/CSR space.  Boards which do not 
+//     support or are not configured to respond in CS/CSR space will 
+//     not be detected by this routine.
+//----------------------------------------------------------------------------
+int vme_get_slot_info(vmeInfoCfg_t * vmeInfo)
+{
+	int slot_of_interest;
+	unsigned int temp;
+	int i;
+
+	struct vmeSharedData *remote_data;
+	unsigned int *remote_csr;
+
+	slot_of_interest = vmeInfo->vmeSlotNum;
+	memset(vmeInfo, 0, sizeof(vmeInfoCfg_t));
+
+	if (slot_of_interest > 21) {
+		return (-EINVAL);
+	}
+	// Fill in information for our own board.
+	if ((slot_of_interest == 0) || (slot_of_interest == vme_slotnum)) {
+		vmeInfo->vmeSlotNum = vme_slotnum;
+		vmeInfo->boardResponded = 1;
+		vmeInfo->sysConFlag = vme_syscon;
+		vmeInfo->vmeControllerID =
+		    PCI_VENDOR_ID_TUNDRA | (vmechip_devid << 16);
+		vmeInfo->vmeControllerRev = vmechip_revision;
+		strcpy(vmeInfo->osName, "Linux");
+		vmeInfo->vmeDriverRev = VMEDRV_REV;
+		return (0);
+	}
+	// Fill in information for another board in the chassis.
+	vmeInfo->vmeSlotNum = slot_of_interest;
+	if (out_image_va[7] == 0) {
+		return (-ENODEV);
+	}
+	// See if something responds at that slot.
+	remote_data = (struct vmeSharedData *)
+	    (vmeInfo->vmeSlotNum * 512 * 1024 + out_image_va[7]);
+
+	remote_csr = (unsigned int *)remote_data;
+	temp = remote_csr[0x7FFFC / 4];
+	if (vme_bus_error_chk(1)) {
+		return (0);	// no response.
+	}
+	if (temp != (slot_of_interest << 3)) {
+		return (0);	// non-sensical response.
+	}
+	vmeInfo->boardResponded = 1;
+	vmeInfo->vmeControllerID = readl(&remote_csr[0x7F000 / 4]);
+	vmeInfo->vmeControllerRev = readl(&remote_csr[0x7F008 / 4]) & 0xFF;
+
+	// If there is no valid driver data structure there, 
+	// nothing left to do
+
+	if (strcmp("VME", remote_data->validity1) ||
+	    strcmp("RDY", remote_data->validity2)) {
+		return (0);
+	}
+	// Copy information from struct 
+	vmeInfo->vmeSharedDataValid = 1;
+	vmeInfo->vmeDriverRev = remote_data->driverRev;
+	strncpy(vmeInfo->osName, remote_data->osname, 8);
+	for (i = 0; i < 8; i++) {
+		vmeInfo->vmeAddrHi[i] = remote_data->inBoundVmeAddrHi[i];
+		vmeInfo->vmeAddrLo[i] = remote_data->inBoundVmeAddrLo[i];
+		vmeInfo->vmeAm[i] = remote_data->inBoundVmeAM[i];
+		vmeInfo->vmeSize[i] = remote_data->inBoundVmeSize[i];
+	}
+
+	return (0);
+}
+
+//----------------------------------------------------------------------------
+//  vme_get_requestor
+//    Return current VME bus requestor attributes.
+//----------------------------------------------------------------------------
+int vme_get_requestor(vmeRequesterCfg_t * vmeReq)
+{
+	memset(vmeReq, 0, sizeof(vmeRequesterCfg_t));
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_get_requestor(vmeReq));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_get_requestor(vmeReq));
+		break;
+	}
+	return (-ENODEV);
+}
+
+//----------------------------------------------------------------------------
+//  vme_set_requestor
+//    Set VME bus requestor attributes.
+//----------------------------------------------------------------------------
+int vme_set_requestor(vmeRequesterCfg_t * vmeReq)
+{
+	if (vmeReq->requestLevel > 3) {
+		return (-EINVAL);
+	}
+
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_set_requestor(vmeReq));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_set_requestor(vmeReq));
+		break;
+	}
+	return (-ENODEV);
+}
+
+//----------------------------------------------------------------------------
+//  vme_get_arbiter
+//    Return VME bus arbiter attributes.
+//----------------------------------------------------------------------------
+int vme_get_arbiter(vmeArbiterCfg_t * vmeArb)
+{
+	// Only valid for system controller.
+	if (vme_syscon == 0) {
+		return (-EINVAL);
+	}
+	memset(vmeArb, 0, sizeof(vmeArbiterCfg_t));
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_get_arbiter(vmeArb));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_get_arbiter(vmeArb));
+		break;
+	}
+	return (-ENODEV);
+}
+
+//----------------------------------------------------------------------------
+//  vme_set_arbiter
+//    Set VME bus arbiter attributes.
+//----------------------------------------------------------------------------
+int vme_set_arbiter(vmeArbiterCfg_t * vmeArb)
+{
+	// Only valid for system controller.
+	if (vme_syscon == 0) {
+		return (-EINVAL);
+	}
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_set_arbiter(vmeArb));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_set_arbiter(vmeArb));
+		break;
+	}
+	return (-ENODEV);
+}
+
+//----------------------------------------------------------------------------
+//  vme_generate_irq
+//    Generate a VME bus interrupt at the specified level & vector.
+//
+//  Caller must assure exclusive access to the VIRQ generator.
+//----------------------------------------------------------------------------
+int vme_generate_irq(virqInfo_t * vmeIrq)
+{
+	int status = -ENODEV;
+
+	// Only valid for non system controller.
+	if (vme_syscon != 0) {
+		return (-EINVAL);
+	}
+	if ((vmeIrq->level < 1) || (vmeIrq->level > 7)) {
+		return (-EINVAL);
+	}
+	if ((vmeIrq->vector < 0) || (vmeIrq->vector > 0xFF)) {
+		return (-EINVAL);
+	}
+
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		status = uni_generate_irq(vmeIrq);
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		status = tempe_generate_irq(vmeIrq);
+		break;
+	}
+
+	return (status);
+}
+
+//----------------------------------------------------------------------------
+//  vme_get_irq_status()
+//    Wait for a specific or any VME bus interrupt to occur.
+//----------------------------------------------------------------------------
+int vme_get_irq_status(virqInfo_t * vmeIrq)
+{
+	int i, j;
+
+	// Only valid for system controller.
+	if (vme_syscon == 0) {
+		return (-EINVAL);
+	}
+	if ((vmeIrq->level >= 8) || (vmeIrq->vector > 0xFF)) {
+		return (-EINVAL);
+	}
+	if ((vmeIrq->level == 0) && (vmeIrq->vector != 0)) {
+		return (-EINVAL);
+	}
+
+	vmeIrq->timeOutFlag = 0;
+
+	if (vmeIrq->level == 0) {
+		if (interruptible_sleep_on_timeout(&vmeint_queue[0],
+			vmeIrq->waitTime) != 0) {
+			for (i = 1; i < 8; i++) {
+				for (j = 0; j <= 0xFF; j++) {
+					if (vme_irqlog[i][j] != 0) {
+						vmeIrq->level = i;
+						vmeIrq->vector = j;
+						return (0);
+					}
+				}
+			}
+		} else 
+			vmeIrq->timeOutFlag = 1;
+	} else {
+		if (wait_event_interruptible(vmeint_queue[vmeIrq->level],
+			(vme_irqlog[vmeIrq->level][vmeIrq->vector] != 0)) == 0) {
+				vmeIrq->timeOutFlag = 1;
+		}
+	}
+ 
+	return (0);
+}
+
+//----------------------------------------------------------------------------
+//  vme_clr_irq_status()
+//    Clear irq log of a specific or all VME interrupts.
+//----------------------------------------------------------------------------
+int vme_clr_irq_status(virqInfo_t * vmeIrq)
+{
+	int i, j;
+
+	// Only valid for system controller.
+	if (vme_syscon == 0) {
+		return (-EINVAL);
+	}
+	// Sanity check input
+	if ((vmeIrq->level >= 8) || (vmeIrq->vector > 0xFF)) {
+		return (-EINVAL);
+	}
+	if ((vmeIrq->level == 0) && (vmeIrq->vector != 0)) {
+		return (-EINVAL);
+	}
+
+	if ((vmeIrq->level == 0) && (vmeIrq->vector == 0)) {
+		// Clear all irqs.
+		for (i = 1; i < 8; i++) {
+			for (j = 0; j <= 0xFF; j++) {
+				vme_irqlog[i][j] = 0;
+			}
+		}
+	}
+	// Clear a single irq.
+	vme_irqlog[vmeIrq->level][vmeIrq->vector] = 0;
+	return (0);
+}
+
+//----------------------------------------------------------------------------
+//  vme_do_rmw()
+//    Perform a RMW operation on the VME bus.
+//----------------------------------------------------------------------------
+int vme_do_rmw(vmeRmwCfg_t * vmeRmw)
+{
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_do_rmw(vmeRmw));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_do_rmw(vmeRmw));
+		break;
+	}
+	return (-ENODEV);
+}
+
+//----------------------------------------------------------------------------
+//  vme_setup_lm()
+//    Setup the VME bus location monitor to detect the specified access.
+//----------------------------------------------------------------------------
+int vme_setup_lm(vmeLmCfg_t * vmeLm)
+{
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_setup_lm(vmeLm));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_setup_lm(vmeLm));
+		break;
+	}
+	return (-ENODEV);
+}
+
+//----------------------------------------------------------------------------
+//  vme_wait_lm()
+//    Wait for the location monitor to trigger.
+//----------------------------------------------------------------------------
+int vme_wait_lm(vmeLmCfg_t * vmeLm)
+{
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_wait_lm(vmeLm));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_wait_lm(vmeLm));
+		break;
+	}
+	return (-ENODEV);
+}
+
+//----------------------------------------------------------------------------
+//  vme_init()
+//    Initialize the VME bridge.
+//----------------------------------------------------------------------------
+int vme_init(void *driverdata)
+{
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (uni_init(driverdata));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		return (tempe_init(driverdata));
+		break;
+	}
+	return (0);
+}
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/vme/vmedrv.h linux-2.6.29.6.mod/drivers/vme/vmedrv.h
--- linux-2.6.29.6.orig/drivers/vme/vmedrv.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/vme/vmedrv.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,447 @@
+/*
+ * vmedrv.h
+ *
+ * Application interface to VME device nodes
+ *
+ * Authors: Tom Armistead, Ajit Prem
+ * Copyright 2004-2007 Motorola Inc.
+ *
+ * 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.
+ */
+
+/*
+ * The reserved elements in the following structures are 
+ * intended to allow future versions of the driver to 
+ * maintain backwards compatibility.  Applications should 
+ * initialize reserved locations to zero.
+ */
+
+#ifndef	VMEDRV_H
+#define	VMEDRV_H
+
+#define	VMEDRV_REV	0x0301
+
+#define	VME_MINOR_TYPE_MASK	0xF0
+#define	VME_MINOR_OUT	0x00
+#define	VME_MINOR_DMA	0x10
+#define	VME_MINOR_MISC	0x20
+#define	VME_MINOR_SLOTS1	0x30
+#define	VME_MINOR_SLOTS2	0x40
+
+#define	VME_MINOR_CTL	0x20
+#define	VME_MINOR_REGS	0x21
+#define	VME_MINOR_RMW	0x22
+#define	VME_MINOR_LM	0x23
+#define	VME_MAX_WINDOWS	8
+
+#ifndef	PCI_DEVICE_ID_TUNDRA_TSI148
+#define	PCI_DEVICE_ID_TUNDRA_TSI148 0x148
+#endif
+
+#ifndef	PCI_DEVICE_ID_TUNDRA_TEMPE
+#define	PCI_DEVICE_ID_TUNDRA_TEMPE 0x148
+#endif
+
+/*
+ *  VME access type definitions
+ */
+#define	VME_DATA		1
+#define	VME_PROG		2
+#define	VME_USER		4
+#define	VME_SUPER		8
+
+/*
+ *  VME address type definitions
+ */
+typedef enum {
+	VME_A16,
+	VME_A24,
+	VME_A32,
+	VME_A64,
+	VME_CRCSR,
+	VME_USER1,
+	VME_USER2,
+	VME_USER3,
+	VME_USER4
+} addressMode_t;
+
+/*
+ *  VME Transfer Protocol Definitions
+ */
+#define	VME_SCT			0x1
+#define	VME_BLT			0x2
+#define	VME_MBLT		0x4
+#define	VME_2eVME		0x8
+#define	VME_2eSST		0x10
+#define	VME_2eSSTB		0x20
+
+/*
+ *  Data Widths 
+ */
+typedef enum {
+	VME_D8 = 8,
+	VME_D16 = 16,
+	VME_D32 = 32,
+	VME_D64 = 64
+} dataWidth_t;
+
+/*
+ *  2eSST Data Transfer Rate Codes
+ */
+typedef enum {
+	VME_SSTNONE = 0,
+	VME_SST160 = 160,
+	VME_SST267 = 267,
+	VME_SST320 = 320
+} vme2esstRate_t;
+
+/*
+ *  Arbitration Scheduling Modes
+ */
+typedef enum {
+	VME_R_ROBIN_MODE,
+	VME_PRIORITY_MODE
+} vme2ArbMode_t;
+
+/*
+ *  /dev/vme_m* Outbound Window Ioctl Commands
+ */
+#define	VME_IOCTL_SET_OUTBOUND		0x10
+#define	VME_IOCTL_GET_OUTBOUND		0x11
+/*
+ *  VMEbus OutBound Window Arg Structure
+ *  NOTE:
+ *	If pciBusAddr[U,L] are 0, then kernel will dynamically assign
+ *	pci start address on PCI bus.
+ */
+struct vmeOutWindowCfg {
+	int windowNbr;		/*  Window Number */
+	char windowEnable;	/*  State of Window */
+	unsigned int pciBusAddrU;	/*  Start Address on the PCI Bus */
+	unsigned int pciBusAddrL;	/*  Start Address on the PCI Bus */
+	unsigned int windowSizeU;	/*  Window Size */
+	unsigned int windowSizeL;	/*  Window Size */
+	unsigned int xlatedAddrU;	/*  Starting Address on the VMEbus */
+	unsigned int xlatedAddrL;	/*  Starting Address on the VMEbus */
+	int bcastSelect2esst;	/*  2eSST Broadcast Select */
+	char wrPostEnable;	/*  Write Post State */
+	char prefetchEnable;	/*  Prefetch Read Enable State */
+	int prefetchSize;	/*  Prefetch Read Size (in Cache Lines) */
+	vme2esstRate_t xferRate2esst;	/*  2eSST Transfer Rate */
+	addressMode_t addrSpace;	/*  Address Space */
+	dataWidth_t maxDataWidth;	/*  Maximum Data Width */
+	int xferProtocol;	/*  Transfer Protocol */
+	int userAccessType;	/*  User/Supervisor Access Type */
+	int dataAccessType;	/*  Data/Program Access Type */
+	int reserved;		/* For future use */
+};
+typedef struct vmeOutWindowCfg vmeOutWindowCfg_t;
+
+/*
+ *  /dev/vme_dma* DMA commands
+ */
+#define	VME_IOCTL_START_DMA		0x30
+#define	VME_IOCTL_PAUSE_DMA		0x31
+#define	VME_IOCTL_CONTINUE_DMA		0x32
+#define	VME_IOCTL_ABORT_DMA		0x33
+#define	VME_IOCTL_WAIT_DMA		0x34
+
+typedef enum {
+	/* NOTE: PATTERN entries only valid as source of data */
+	VME_DMA_PATTERN_BYTE,
+	VME_DMA_PATTERN_BYTE_INCREMENT,
+	VME_DMA_PATTERN_WORD,
+	VME_DMA_PATTERN_WORD_INCREMENT,
+	VME_DMA_USER,
+	VME_DMA_KERNEL,
+	VME_DMA_PCI,
+	VME_DMA_VME
+} dmaData_t;
+
+/*
+ *  VMEbus Transfer Attributes 
+ */
+struct vmeAttr {
+	dataWidth_t maxDataWidth;	/*  Maximum Data Width */
+	vme2esstRate_t xferRate2esst;	/*  2eSST Transfer Rate */
+	int bcastSelect2esst;	/*  2eSST Broadcast Select */
+	addressMode_t addrSpace;	/*  Address Space */
+	int userAccessType;	/*  User/Supervisor Access Type */
+	int dataAccessType;	/*  Data/Program Access Type */
+	int xferProtocol;	/*  Transfer Protocol */
+	int reserved;		/* For future use */
+};
+typedef struct vmeAttr vmeAttr_t;
+
+/*
+ *  DMA arg info
+ *  NOTE: 
+ *	structure contents relating to VME are don't care for 
+ *       PCI transactions
+ *	structure contents relating to PCI are don't care for 
+ *       VME transactions
+ *	If source or destination is user memory and transaction
+ *	will cross page boundary, the DMA request will be split
+ *	into multiple DMA transactions.
+ */
+typedef struct vmeDmaPacket {
+	int vmeDmaToken;	/*  Token for driver use */
+	int vmeDmaWait;		/*  Time to wait for completion */
+	unsigned int vmeDmaStartTick;	/*  Time DMA started */
+	unsigned int vmeDmaStopTick;	/*  Time DMA stopped */
+	unsigned int vmeDmaElapsedTime;	/*  Elapsed time */
+	int vmeDmaStatus;	/*  DMA completion status */
+
+	int byteCount;		/*  Byte Count */
+	int bcastSelect2esst;	/*  2eSST Broadcast Select */
+
+	/*
+	 *  DMA Source Data
+	 */
+	dmaData_t srcBus;
+	unsigned int srcAddrU;
+	unsigned int srcAddr;
+	int pciReadCmd;
+	struct vmeAttr srcVmeAttr;
+	char srcfifoEnable;
+
+	/*
+	 *  DMA Destination Data
+	 */
+	dmaData_t dstBus;
+	unsigned int dstAddrU;
+	unsigned int dstAddr;
+	int pciWriteCmd;
+	struct vmeAttr dstVmeAttr;
+	char dstfifoEnable;
+
+	/*
+	 *  BUS usage control
+	 */
+	int maxCpuBusBlkSz;	/*  CPU Bus Maximum Block Size */
+	int maxPciBlockSize;	/* PCI Bus Maximum Block Size */
+	int pciBackOffTimer;	/* PCI Bus Back-Off Timer */
+	int maxVmeBlockSize;	/* VMEbus Maximum Block Size */
+	int vmeBackOffTimer;	/* VMEbus Back-Off Timer */
+
+	int channel_number;	/* Channel number */
+	int reserved;		/* For future use */
+	/*
+	 *      Ptr to next Packet
+	 *      (NULL == No more Packets)
+	 */
+	struct vmeDmaPacket *pNextPacket;
+
+} vmeDmaPacket_t;
+
+/*
+ *  /dev/vme_ctl ioctl Commands
+ */
+#define	VME_IOCTL_GET_SLOT_VME_INFO	0x41
+/*
+ *  VMEbus GET INFO Arg Structure
+ */
+struct vmeInfoCfg {
+	int vmeSlotNum;		/*  VME slot number of interest */
+	int boardResponded;	/* Board responded */
+	char sysConFlag;	/*  System controller flag */
+	int vmeControllerID;	/*  Vendor/device ID of VME bridge */
+	int vmeControllerRev;	/*  Revision of VME bridge */
+	char osName[8];		/*  Name of OS e.g. "Linux" */
+	int vmeSharedDataValid;	/*  Validity of data struct */
+	int vmeDriverRev;	/*  Revision of VME driver */
+	unsigned int vmeAddrHi[8];	/* Address on VME bus */
+	unsigned int vmeAddrLo[8];	/* Address on VME bus */
+	unsigned int vmeSize[8];	/* Size on VME bus */
+	unsigned int vmeAm[8];	/* Address modifier on VME bus */
+	int reserved;		/* For future use */
+};
+typedef struct vmeInfoCfg vmeInfoCfg_t;
+
+#define	VME_IOCTL_SET_REQUESTOR		0x42
+#define	VME_IOCTL_GET_REQUESTOR		0x43
+/*
+ *  VMEbus Requester Arg Structure
+ */
+struct vmeRequesterCfg {
+	int requestLevel;	/*  Requester Bus Request Level */
+	char fairMode;		/*  Requester Fairness Mode Indicator */
+	int releaseMode;	/*  Requester Bus Release Mode */
+	int timeonTimeoutTimer;	/*  Master Time-on Time-out Timer */
+	int timeoffTimeoutTimer;	/*  Master Time-off Time-out Timer */
+	int reserved;		/* For future use */
+};
+typedef struct vmeRequesterCfg vmeRequesterCfg_t;
+
+#define	VME_IOCTL_SET_CONTROLLER	0x44
+#define	VME_IOCTL_GET_CONTROLLER	0x45
+
+/*
+ *  VMEbus Arbiter Arg Structure
+ */
+struct vmeArbiterCfg {
+	vme2ArbMode_t arbiterMode;	/*  Arbitration Scheduling Algorithm */
+	char arbiterTimeoutFlag;	/*  Arbiter Time-out Timer Indicator */
+	int globalTimeoutTimer;	/*  VMEbus Global Time-out Timer */
+	char noEarlyReleaseFlag;	/*  No Early Release on BBUSY */
+	int reserved;		/* For future use */
+};
+typedef struct vmeArbiterCfg vmeArbiterCfg_t;
+
+#define	VME_IOCTL_GENERATE_IRQ		0x46
+#define	VME_IOCTL_GET_IRQ_STATUS	0x47
+#define	VME_IOCTL_CLR_IRQ_STATUS	0x48
+
+/*
+ *  VMEbus IRQ Info
+ */
+typedef struct virqInfo {
+	/*
+	 *  Time to wait for Event to occur (in clock ticks)
+	 */
+	short waitTime;
+	short timeOutFlag;
+
+	/*
+	 *  VMEbus Interrupt Level and Vector Data
+	 */
+	int level;
+	int vector;
+	int reserved;		/* For future use */
+
+} virqInfo_t;
+
+#define	VME_IOCTL_SET_INBOUND		0x49
+#define	VME_IOCTL_GET_INBOUND		0x50
+
+/*
+ *  VMEbus InBound Window Arg Structure
+ *  NOTE:
+ *	If pciBusAddr[U,L] and windowSize[U,L] are 0, then kernel 
+ *      will dynamically assign inbound window to map to a kernel
+ *	supplied buffer.
+ */
+struct vmeInWindowCfg {
+	int windowNbr;		/*  Window Number */
+	char windowEnable;	/*  State of Window */
+	unsigned int vmeAddrU;	/*  Start Address responded to on the VMEbus */
+	unsigned int vmeAddrL;	/*  Start Address responded to on the VMEbus */
+	unsigned int windowSizeU;	/*  Window Size */
+	unsigned int windowSizeL;	/*  Window Size */
+	unsigned int pciAddrU;	/*  Start Address appearing on the PCI Bus */
+	unsigned int pciAddrL;	/*  Start Address appearing on the PCI Bus */
+	char wrPostEnable;	/*  Write Post State */
+	char prefetchEnable;	/*  Prefetch Read State */
+	char prefetchThreshold;	/*  Prefetch Read Threshold State */
+	int prefetchSize;	/*  Prefetch Read Size */
+	char rmwLock;		/*  Lock PCI during RMW Cycles */
+	char data64BitCapable;	/*  non-VMEbus capable of 64-bit Data */
+	addressMode_t addrSpace;	/*  Address Space */
+	int userAccessType;	/*  User/Supervisor Access Type */
+	int dataAccessType;	/*  Data/Program Access Type */
+	int xferProtocol;	/*  Transfer Protocol */
+	vme2esstRate_t xferRate2esst;	/*  2eSST Transfer Rate */
+	char bcastRespond2esst;	/*  Respond to 2eSST Broadcast */
+	int reserved;		/* For future use */
+
+};
+typedef struct vmeInWindowCfg vmeInWindowCfg_t;
+
+/*
+ *  /dev/vme_rmw RMW Ioctl Commands
+ */
+#define	VME_IOCTL_DO_RMW		0x60
+/*
+ *  VMEbus RMW Configuration Data
+ */
+struct vmeRmwCfg {
+	unsigned int targetAddrU;	/*  VME Address (Upper) to trigger RMW cycle */
+	unsigned int targetAddr;	/*  VME Address (Lower) to trigger RMW cycle */
+	addressMode_t addrSpace;	/*  VME Address Space */
+	int enableMask;		/*  Bit mask defining the bits of interest */
+	int compareData;	/*  Data to be compared with the data read */
+	int swapData;		/*  Data written to the VMEbus on success */
+	int maxAttempts;	/*  Maximum times to try */
+	int numAttempts;	/*  Number of attempts before success */
+	int reserved;		/* For future use */
+
+};
+typedef struct vmeRmwCfg vmeRmwCfg_t;
+
+/*
+ *  /dev/vme_lm location Monitor Ioctl Commands
+ */
+#define	VME_IOCTL_SETUP_LM		0x70
+#define	VME_IOCTL_WAIT_LM		0x71
+/*
+ *  VMEbus Location Monitor Arg Structure
+ */
+struct vmeLmCfg {
+	unsigned int addrU;	/*  Location Monitor Address upper */
+	unsigned int addr;	/*  Location Monitor Address lower */
+	addressMode_t addrSpace;	/*  Address Space */
+	int userAccessType;	/*  User/Supervisor Access Type */
+	int dataAccessType;	/*  Data/Program Access Type */
+	int lmWait;		/* Time to wait for access */
+	int lmEvents;		/* Lm event mask */
+	int reserved;		/* For future use */
+};
+typedef struct vmeLmCfg vmeLmCfg_t;
+
+/*
+ *  Data structure created for each board in CS/CSR space.  
+ */
+struct vmeSharedData {
+	/*
+	 * Public elements
+	 */
+	char validity1[4];	/* "VME" when contents are valid */
+	char validity2[4];	/* "RDY" when contents are valid */
+	int structureRev;	/* Revision of this structure */
+	int reserved1;
+
+	char osname[8];		/* OS name string */
+	int driverRev;		/* Revision of VME driver */
+	int reserved2;
+
+	char boardString[16];	/* type of board */
+
+	int vmeControllerType;
+	int vmeControllerRev;
+	int boardSemaphore[8];	/* for use by remote */
+	unsigned int inBoundVmeAddrHi[8];	/* This boards VME windows */
+	unsigned int inBoundVmeAddrLo[8];	/* This boards VME windows */
+	addressMode_t inBoundVmeAM[8];	/* Address modifier */
+	int inBoundVmeSize[8];	/* size available to remotes */
+	char reserved3[0x1000 - 248];	/* Pad to 4k boundary */
+
+	int readTestPatterns[1024];
+	int remoteScratchArea[24][256];	/* 1k scratch for each remote */
+	/*
+	 * Private areas for use by driver only.
+	 */
+	char driverScratch[4096];
+	struct {
+		char Eye[4];
+		int Offset;
+		int Head;
+		int Tail;
+		int Size;
+		int Reserved1;
+		int Reserved2;
+		int Reserved3;
+		char Data[4096 - 32];
+	} boardFifo[23];
+};
+
+/*
+ *  Driver errors reported back to the Application (other than the
+ *  standard Linux errnos...).
+ */
+#define	VME_ERR_VERR		1	/* VME bus error detected */
+#define	VME_ERR_PERR		2	/* PCI bus error detected */
+
+#endif				/* VMEDRV_H */
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/vme/vmelinux.c linux-2.6.29.6.mod/drivers/vme/vmelinux.c
--- linux-2.6.29.6.orig/drivers/vme/vmelinux.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/vme/vmelinux.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,1907 @@
+/*
+ * vmelinux.c
+ *
+ * Provides the device node interface from the user space programs to 
+ * the VME bridge.  Primary purpose is to convert user space
+ * data to kernel and back.
+ *                                  
+ * This driver supports both the Tempe, and the Universe/Universe II chips.
+ * 
+ * Authors: Tom Armistead, Ajit Prem
+ * Copyright 2004-2007 Motorola Inc.
+ * Copyright 2008 Emerson Network Power - Embedded Computing, Inc.
+ *
+ * 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.
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/mm.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/poll.h>
+#include <linux/highmem.h>
+#include <linux/interrupt.h>
+#include <linux/pagemap.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mv643xx.h>
+#include <asm/io.h>
+#include <asm/page.h>
+#include <asm/uaccess.h>
+#include "vmedrv.h"
+
+static char Version[] = "4.0 5/23/2008";
+
+static int vme_open(struct inode *, struct file *);
+static int vme_release(struct inode *, struct file *);
+static ssize_t vme_read(struct file *, char *, size_t, loff_t *);
+static ssize_t vme_write(struct file *, const char *, size_t, loff_t *);
+static unsigned int vme_poll(struct file *, poll_table *);
+static int vme_ioctl(struct inode *, struct file *, unsigned int,
+		     unsigned long);
+static int vme_mmap(struct file *file, struct vm_area_struct *vma);
+static int vme_procinfo(char *, char **, off_t, int, int *, void *);
+static struct class *vme_class;
+
+void vmemod_setup_options(char *cmd_line);
+
+extern unsigned tb_ticks_per_jiffy;
+
+static struct proc_dir_entry *vme_procdir;
+
+static struct file_operations vme_fops = {
+	.owner = THIS_MODULE,
+	.read = vme_read,
+	.write = vme_write,
+	.poll = vme_poll,
+	.ioctl = vme_ioctl,
+	.mmap = vme_mmap,
+	.open = vme_open,
+	.release = vme_release
+};
+
+#define VME_MAJOR	221
+#define MAX_MINOR	0xFF
+
+#define DMATYPE_SINGLE  1
+#define DMATYPE_LLIST   2
+
+#define INTERBOARD_BUFFER_SIZE 			512 * 1024
+#define DEFAULT_INBOUND_WINDOW_BUFFER_SIZE	4 * 1024 * 1024
+
+static unsigned long opened[MAX_MINOR + 1];
+struct semaphore devinuse[MAX_MINOR + 1];
+
+// Global VME controller information
+extern int vmechip_irq;		// PCI irq
+extern int vmechip_devid;	// PCI devID of VME bridge
+extern int vmeparent_devid;	// PCI devID of VME bridge parent
+extern int vmechip_revision;	// PCI revision
+extern void __iomem *vmechip_baseaddr;	// virtual address of chip registers
+extern int vme_slotnum;		// VME slot num (-1 = unknown)
+extern int vme_syscon;		// VME sys controller (-1 = unknown)
+
+#ifdef CONFIG_VME_BRIDGE_BOOTMEM
+extern void *vme_driver_bootmem;
+extern unsigned int vme_bootmem_size;
+#endif
+
+char *in_image_ba[0x8];		// Virtual Address
+dma_addr_t in_image_pa[0x8];	// Physical Address
+int in_image_size[0x8];		// Size
+int in_image_mapped[0x8];
+static int out_image_mapped[0x8];
+static struct semaphore in_image_sem[0x8];
+static struct semaphore out_image_sem[0x8];
+
+struct resource out_resource[0x8];
+extern unsigned int out_image_va[8];	// Base virtual address
+extern unsigned int out_image_valid[8];	// validity
+
+/*
+ * External functions
+ */
+extern void uni_shutdown(void);
+extern void tsi148_shutdown(void);
+
+extern int vme_init(void *);
+extern int vme_bus_error_chk(int);
+extern int vme_get_slot_num(void);
+extern int vme_get_out_bound(vmeOutWindowCfg_t *);
+extern int vme_set_out_bound(vmeOutWindowCfg_t *);
+extern int vme_do_dma(vmeDmaPacket_t *);
+extern int vme_get_slot_info(vmeInfoCfg_t *);
+extern int vme_get_requestor(vmeRequesterCfg_t *);
+extern int vme_set_requestor(vmeRequesterCfg_t *);
+extern int vme_get_arbiter(vmeArbiterCfg_t *);
+extern int vme_set_arbiter(vmeArbiterCfg_t *);
+extern int vme_generate_irq(virqInfo_t *);
+extern int vme_get_irq_status(virqInfo_t *);
+extern int vme_clr_irq_status(virqInfo_t *);
+extern int vme_get_in_bound(vmeInWindowCfg_t *);
+extern int vme_set_in_bound(vmeInWindowCfg_t *);
+extern int vme_do_rmw(vmeRmwCfg_t *);
+extern int vme_setup_lm(vmeLmCfg_t *);
+extern int vme_wait_lm(vmeLmCfg_t *);
+
+extern void vme_sync_data(void);
+extern void vme_flush_range(unsigned long, unsigned long);
+
+extern int uni_procinfo(char *);
+extern int tsi148_procinfo(char *);
+
+extern unsigned long vme_pci_bus_mem_base_phys(struct pci_bus *bus);
+
+#define	DEV_VALID	1
+#define	DEV_EXCLUSIVE	2
+#define	DEV_RW		4
+
+static char vme_minor_dev_flags[] = {
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_m0 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_m1 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_m2 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_m3 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_m4 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_m5 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_m6 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_m7 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_s0 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_s1 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_s2 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_s3 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_s4 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_s5 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_s6 */
+	DEV_VALID | DEV_EXCLUSIVE | DEV_RW,	/* /dev/vme_s7 */
+	DEV_VALID,		/* /dev/vme_dma0 */
+	DEV_VALID,		/* /dev/vme_dma1 */
+	0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	DEV_VALID,		/* /dev/vme_ctl */
+	DEV_VALID | DEV_RW,	/* /dev/vme_regs */
+	DEV_VALID | DEV_EXCLUSIVE,	/* /dev/vme_rmw0 */
+	DEV_VALID | DEV_EXCLUSIVE,	/* /dev/vme_lm0 */
+	0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0,
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot0 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot1 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot2 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot3 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot4 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot5 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot6 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot7 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot8 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot9 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot10 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot11 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot12 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot13 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot14 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot15 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot16 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot17 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot18 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot19 */
+	DEV_VALID | DEV_RW,	/* /dev/vme_slot20 */
+	DEV_VALID | DEV_RW	/* /dev/vme_slot21 */
+};
+
+static unsigned int reads;
+static unsigned int writes;
+static unsigned int ioctls;
+
+/* Shared global */
+wait_queue_head_t dma_queue[2];
+wait_queue_head_t lm_queue;
+wait_queue_head_t mbox_queue;
+wait_queue_head_t vmeint_queue[8];
+struct vmeSharedData *vmechip_interboard_data;	// vaddress of board data
+dma_addr_t vmechip_interboard_datap;	// paddress of board data
+struct resource *vmepcimem;
+int tb_speed;
+struct semaphore virq_inuse;
+struct pci_dev *vme_pci_dev;
+
+MODULE_PARM_DESC(vmechip_irq, "VME chip irq in the range 1-255");
+module_param(vmechip_irq, int, 0);
+MODULE_PARM_DESC(vme_slotnum, "Slot Number in the range 1-21");
+module_param(vme_slotnum, int, 0);
+MODULE_LICENSE("GPL");
+
+static int vme_minor_type(int minor)
+{
+	if (minor > sizeof(vme_minor_dev_flags)) {
+		return (0);
+	}
+	return (vme_minor_dev_flags[minor]);
+}
+
+/*
+ * vme_alloc_buffers()
+ *
+ * Obtain a buffer for the data structure that will be 
+ * advertized through CS/CSR space. The CS/CSR decoder only
+ * allows remapping on 512K boundaries so this buffer must be
+ * aligned on a 512K byte boundary. 
+ *
+ */
+
+static int vme_alloc_buffers(void)
+{
+	if (vmechip_interboard_data == NULL) {
+		vmechip_interboard_data = (struct vmeSharedData *)
+		    dma_alloc_coherent((struct device *)&vme_pci_dev->dev,
+				       INTERBOARD_BUFFER_SIZE,
+				       (dma_addr_t *)&vmechip_interboard_datap,
+					GFP_DMA);
+		if (!vmechip_interboard_data) {
+			printk("tsi148: No memory for interboard data\n");
+			return -ENOMEM;
+		}
+		if (((int)vmechip_interboard_data & 0x7FFFF) != 0) {
+			printk
+			    ("tsi148: Unable to get DMA buffer with required alignment\n");
+			return -1;
+		}
+	}
+#ifdef CONFIG_VME_BRIDGE_BOOTMEM
+	{
+		struct page *page, *pend;
+
+		in_image_size[7] = vme_bootmem_size;
+		if (vme_driver_bootmem != NULL) {
+			in_image_ba[7] = (char *) vme_driver_bootmem;
+			in_image_pa[7] = __pa(in_image_ba[7]);
+			/* now mark the pages as reserved; otherwise */
+			/* remap_pfn_range doesn't do what we want */
+			pend = virt_to_page(in_image_ba[7] + in_image_size[7] - 1);
+			for (page = virt_to_page(in_image_ba[7]); 
+				page <= pend; page++)
+				SetPageReserved(page);
+		}
+	}
+#endif
+	return (0);
+}
+
+//----------------------------------------------------------------------------
+//  vme_free_buffers()
+//   Free all buffers allocated by this driver.
+//----------------------------------------------------------------------------
+static void vme_free_buffers(void)
+{
+	int i;
+	struct page *page, *pend;
+
+	/* 
+	 * clear valid flags of interboard data and free it
+	 */
+	if (vmechip_interboard_data != NULL) {
+		strcpy(vmechip_interboard_data->validity1, "OFF");
+		strcpy(vmechip_interboard_data->validity2, "OFF");
+		dma_free_coherent(&vme_pci_dev->dev,
+				  INTERBOARD_BUFFER_SIZE,
+				  vmechip_interboard_data,
+				  vmechip_interboard_datap);
+	}
+	// free inbound buffers
+	for (i = 0; i < 8; i++) {
+		if (in_image_ba[i] != NULL) {
+			/* undo marking the pages as reserved */
+			pend = virt_to_page(in_image_ba[i] + in_image_size[i] - 1);
+			for (page = virt_to_page(in_image_ba[i]); page <= pend; page++)
+				ClearPageReserved(page);
+
+			if (i == 7) {
+#ifndef CONFIG_VME_BRIDGE_BOOTMEM
+				dma_free_coherent(&vme_pci_dev->dev,
+					  in_image_size[i],
+					  in_image_ba[i], in_image_pa[i]);
+#endif
+				in_image_mapped[i] = 0;
+			} else {
+				dma_free_coherent(&vme_pci_dev->dev,
+					  in_image_size[i],
+					  in_image_ba[i], in_image_pa[i]);
+				in_image_mapped[i] = 0;
+			}
+		}
+	}
+}
+
+//----------------------------------------------------------------------------
+//  vme_init_test_data()
+//   Initialize the test area of the interboard data structure 
+//   with the expected data patterns.
+//----------------------------------------------------------------------------
+static void vme_init_test_data(int testdata[])
+{
+	int i;
+
+	// walking 1 & walking 0
+	for (i = 0; i < 32; i++) {
+		testdata[i * 2] = 1 << i;
+		testdata[i * 2 + 1] = ~(1 << i);
+	}
+
+	// all 0, all 1's, 55's and AA's
+	testdata[64] = 0x0;
+	testdata[65] = 0xFFFFFFFF;
+	testdata[66] = 0x55555555;
+	testdata[67] = 0xAAAAAAAA;
+
+	// Incrementing data.
+	for (i = 68; i < 1024; i++) {
+		testdata[i] = i;
+	}
+}
+
+//----------------------------------------------------------------------------
+//  vme_init_interboard_data()
+//    Initialize the interboard data structure.
+//----------------------------------------------------------------------------
+static void vme_init_interboard_data(struct vmeSharedData *ptr)
+{
+	if (ptr == NULL)
+		return;
+
+	memset(ptr, 0, sizeof(struct vmeSharedData));
+	vme_init_test_data(&ptr->readTestPatterns[0]);
+
+	ptr->structureRev = 1;
+	strcpy(&ptr->osname[0], "linux");
+
+	ptr->driverRev = 1;
+
+#ifdef CONFIG_MVME4100
+	strcpy(&ptr->boardString[0], "MVME4100");
+#endif
+#ifdef CONFIG_MVME7100
+	strcpy(&ptr->boardString[0], "MVME7100");
+#endif
+#ifdef CONFIG_MVME3100
+	strcpy(&ptr->boardString[0], "MVME3100");
+#endif
+#ifdef CONFIG_MVME6100
+	strcpy(&ptr->boardString[0], "MVME6100");
+#endif
+#ifdef CONFIG_MVME5500
+	strcpy(&ptr->boardString[0], "MVME5500");
+#endif
+#ifdef CONFIG_MVME5100
+	strcpy(&ptr->boardString[0], "MVME5100");
+#endif
+	ptr->vmeControllerType = vmechip_devid;
+	ptr->vmeControllerRev = vmechip_revision;
+
+	/* Set valid strings "VME", "RDY" */
+	strcpy(ptr->validity1, "VME");
+	strcpy(ptr->validity2, "RDY");
+	vme_flush_range((unsigned long)ptr, (unsigned long)ptr + sizeof(struct vmeSharedData));
+}
+
+/*
+ *  vme_procinfo()
+ *     /proc interface into this driver
+ */
+
+static int vme_procinfo(char *buf, char **start, off_t fpos, int length,
+			int *eof, void *data)
+{
+	char *p;
+
+	p = buf;
+	p += sprintf(p, "VME driver %s\n\n", Version);
+
+	p += sprintf(p, "vmechip baseaddr = %08X\n", (int)vmechip_baseaddr);
+	p += sprintf(p, "vmechip device   = %08X\n", (int)vmechip_devid);
+	p += sprintf(p, "vmechip revision = %08X\n", (int)vmechip_revision);
+	p += sprintf(p, "vme slot number  = %2d\n", (int)vme_slotnum);
+	if (vme_syscon)
+		p += sprintf(p, "vme system controller = TRUE\n");
+	else
+		p += sprintf(p, "vme system controller = FALSE\n");
+
+	if (vmechip_devid == PCI_DEVICE_ID_TUNDRA_TSI148) {
+		p += tsi148_procinfo(p);
+	}
+
+	if (vmechip_devid == PCI_DEVICE_ID_TUNDRA_CA91C042) {
+		p += uni_procinfo(p);
+	}
+
+	p += sprintf(p, "\n");
+	p += sprintf(p, "statistics:  reads = %i  writes = %i  ioctls = %i\n\n",
+		     reads, writes, ioctls);
+	p += sprintf(p, "\n");
+
+	*eof = 1;
+	return p - buf;
+}
+
+/*
+  register_proc()
+*/
+static void register_proc(void)
+{
+	vme_procdir = create_proc_entry("vmeinfo", S_IFREG | S_IRUGO, 0);
+	vme_procdir->read_proc = vme_procinfo;
+}
+
+/*
+  unregister_proc()
+*/
+static void unregister_proc(void)
+{
+	remove_proc_entry("vmeinfo", 0);
+}
+
+//----------------------------------------------------------------------------
+//  vme_chip_reg_read
+//    Read a VME chip register.
+//
+//    Note that Tempe swizzles registers at offsets > 0x100 on its own.
+//----------------------------------------------------------------------------
+unsigned int vme_chip_reg_read(unsigned int *ptr)
+{
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		return (readl(ptr));
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		if (((char *)ptr) - ((char *)vmechip_baseaddr) > 0x100) {
+			return (*ptr);
+		}
+		return (readl(ptr));
+		break;
+	}
+	return (0);
+}
+
+/*
+  vme_chip_reg_write
+    Write a VME chip register.
+
+    Note that Tempe swizzles registers at offsets > 0x100 on its own.
+*/
+void vme_chip_reg_write(unsigned int *ptr, unsigned int value)
+{
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		writel(value, ptr);
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		if (((char *)ptr) - ((char *)vmechip_baseaddr) > 0x100) {
+			*ptr = value;
+		} else {
+			writel(value, ptr);
+		}
+		break;
+	}
+}
+
+/*
+ Function   : vme_ioctl_free_dma
+ Description: Free the pages associated with the linked list of DMA packets.
+*/
+static int vme_ioctl_free_dma(vmeDmaPacket_t *start_pkt)
+{
+        vmeDmaPacket_t *current_pkt;
+        vmeDmaPacket_t *previous_pkt;
+        vmeDmaPacket_t *next_pkt;
+
+        /* Free all pages associated with the packets. */
+        current_pkt = start_pkt;
+        previous_pkt = current_pkt;
+        while (current_pkt != 0) {
+                next_pkt = current_pkt->pNextPacket;
+                if (current_pkt + 1 != next_pkt) {
+                        free_pages((int)previous_pkt, 0);
+                        previous_pkt = next_pkt;
+                }
+                current_pkt = next_pkt;
+        }
+        return (0);
+}
+
+
+/*
+ Function   : vme_ioctl_setup_dma
+ Description:
+    Read descriptors from user space and create a linked list
+    of DMA packets.
+*/
+static vmeDmaPacket_t *vme_ioctl_setup_dma(vmeDmaPacket_t *vme_dma,
+                                    int *return_status)
+{
+        vmeDmaPacket_t *vme_current;
+        int max_per_page;
+        int current_pktcount;
+        vmeDmaPacket_t *start_pkt;
+        vmeDmaPacket_t *current_pkt;
+
+        max_per_page = PAGE_SIZE / sizeof(vmeDmaPacket_t) - 1;
+        start_pkt = (vmeDmaPacket_t *) __get_free_pages(GFP_KERNEL, 0);
+        if (start_pkt == 0) {
+                *return_status = -ENOMEM;
+                return (0);
+        }
+        /* First allocate pages for packets and create linked list */
+        vme_current = vme_dma;
+        current_pkt = start_pkt;
+        current_pktcount = 0;
+
+        while (vme_current != 0) {
+                if (copy_from_user
+                    (current_pkt, vme_current, sizeof(vmeDmaPacket_t))) {
+                        current_pkt->pNextPacket = 0;
+                        vme_ioctl_free_dma(start_pkt);
+                        *return_status = -EFAULT;
+                        return (0);
+                }
+                if ((current_pkt->srcBus == VME_DMA_USER) ||
+                    (current_pkt->dstBus == VME_DMA_USER) || 
+                    (current_pkt->srcBus == VME_DMA_KERNEL) ||
+                    (current_pkt->dstBus == VME_DMA_KERNEL)) {
+                                current_pkt->pNextPacket = 0;
+                                vme_ioctl_free_dma(start_pkt);
+                                *return_status = -EINVAL;
+                                return (0);
+                }
+
+                if (current_pkt->pNextPacket == NULL) {
+                        break;
+                }
+                vme_current = current_pkt->pNextPacket;
+
+                current_pkt->pNextPacket = current_pkt + 1;
+                current_pktcount++;
+                if (current_pktcount >= max_per_page) {
+                        current_pkt->pNextPacket =
+                            (vmeDmaPacket_t *) __get_free_pages(GFP_KERNEL, 0);
+                        current_pktcount = 0;
+                }
+                current_pkt = current_pkt->pNextPacket;
+        }
+
+        /* Return to packets list */
+        *return_status = 0;
+        return (start_pkt);
+}
+
+
+//-----------------------------------------------------------------------------
+// Function   : vme_ioctl_dma()
+// Inputs     : 
+//   User pointer to DMA packet (possibly chained)
+//   DMA channel number.
+// Outputs    : returns 0 on success, error code on failure.
+// Description: 
+//   Copy DMA chain into kernel space.
+//   Verify validity of chain.
+//   Wait, if needed, for DMA channel to be available.
+//   Do the DMA operation.
+//   Free the DMA channel.
+//   Copy the DMA packet with status back to user space.
+//   Free resources allocated by this operation.
+// Remarks    : 
+//    Note, due to complexity, DMA to/from a user space buffer is dealt with 
+//    via a separate routine.
+// History    : 
+//-----------------------------------------------------------------------------
+static int vme_ioctl_dma(vmeDmaPacket_t *vme_dma, int channel)
+{
+
+	vmeDmaPacket_t *start_pkt;
+	int status = 0;
+
+	// Read the (possibly linked) descriptors from the user
+	start_pkt = vme_ioctl_setup_dma(vme_dma, &status);
+	if (status < 0) {
+		return (status);
+	}
+
+	start_pkt->channel_number = channel;
+	if (start_pkt->byteCount <= 0) {
+		vme_ioctl_free_dma(start_pkt);
+		return (-EINVAL);
+	}
+
+	// Wait for DMA channel to be available.
+	if (down_interruptible(&devinuse[channel + VME_MINOR_DMA])) {
+		vme_ioctl_free_dma(start_pkt);
+		return (-ERESTARTSYS);
+	}
+
+	// Do the DMA.
+	status = vme_do_dma(start_pkt);
+
+	// Free the DMA channel.
+	up(&devinuse[channel + VME_MINOR_DMA]);
+
+	// Copy the result back to the user.
+	if (copy_to_user(vme_dma, start_pkt, sizeof(vmeDmaPacket_t))) {
+		vme_ioctl_free_dma(start_pkt);
+		return (-EFAULT);
+	}
+	// Free the linked list.
+	vme_ioctl_free_dma(start_pkt);
+	return (status);
+}
+
+//----------------------------------------------------------------------------
+//
+//  vme_poll()
+//  Place holder - this driver function not implemented.
+//
+//----------------------------------------------------------------------------
+static unsigned int vme_poll(struct file *file, poll_table * wait)
+{
+	return 0;
+}
+
+static int vme_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	int minor;
+	int ret = 0;
+
+	if ((!file) || (!vma))
+		return -ENXIO;
+	minor = MINOR(file->f_dentry->d_inode->i_rdev);
+
+	if ((minor < 0) || (minor > 15))
+		return -EINVAL;
+
+	if (minor > 7) {
+		/* Inbound windows */
+		minor -= 8;
+
+		if (vma->vm_pgoff)
+			return -EINVAL;	/* want no offset */
+
+		/*
+		 * Lock a read or write against an mmap.
+		 */
+		down(&in_image_sem[minor]);
+		ret = -EAGAIN;
+		if (remap_pfn_range(vma,
+				    vma->vm_start,
+				    in_image_pa[minor] >> PAGE_SHIFT,
+				    vma->vm_end - vma->vm_start,
+				    vma->vm_page_prot))
+			goto mmap_in;
+		in_image_mapped[minor] = 1;
+		ret = 0;
+mmap_in:
+		up(&in_image_sem[minor]);
+		return ret;
+	} else {
+		unsigned long vsize = vma->vm_end - vma->vm_start;
+		unsigned long psize;
+
+		/* Outbound windows */
+		if (out_image_va[minor] == 0)
+			return (-EINVAL);
+
+		psize = out_resource[minor].end - out_resource[minor].start + 1;
+		psize -= vma->vm_pgoff * PAGE_SIZE;
+
+		if (vsize > psize)
+			return -EINVAL;
+
+		/*
+		 * Lock a read or write against an mmap.
+		 */
+		down(&out_image_sem[minor]);
+		ret = -EAGAIN;
+		vma->vm_page_prot |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+		if (io_remap_pfn_range(vma,
+			vma->vm_start,
+			((out_resource[minor].start -
+				vme_pci_bus_mem_base_phys(vme_pci_dev->bus)) >> 
+					PAGE_SHIFT) + vma->vm_pgoff, 
+			vma->vm_end - vma->vm_start,
+			vma->vm_page_prot))
+			goto mmap_out;
+		out_image_mapped[minor] = 1;
+		ret = 0;
+mmap_out:
+		up(&out_image_sem[minor]);
+		return ret;
+	}
+}
+
+/*
+ Function   : vme_open()
+ Inputs     : standard Linux device driver open arguments.
+ Outputs    : returns 0 on success, error code on failure.
+ Description: 
+   Verify device is valid,
+   If device is exclusive use and already open, return -EBUSY
+   Increment device use count.
+*/
+static int vme_open(struct inode *inode, struct file *file)
+{
+	unsigned int minor = iminor(inode);
+	int minor_flags;
+
+	/* Check for valid minor num */
+	minor_flags = vme_minor_type(minor);
+	if (!minor_flags)
+		return -ENODEV;
+
+	/* Restrict exclusive use devices to one open */
+	if ((minor_flags & DEV_EXCLUSIVE) &&
+	    test_and_set_bit(0, &opened[minor]))
+		return -EBUSY;
+	return (0);
+}
+
+/*
+ Function   : vme_release()
+ Inputs     : standard Linux device driver release arguments.
+ Outputs    : returns 0.
+ Description: 
+    Decrement use count and return.
+*/
+static int vme_release(struct inode *inode, struct file *file)
+{
+	unsigned int minor = iminor(inode);
+	int minor_flags;
+
+	minor_flags = vme_minor_type(minor);
+	if ((minor & VME_MINOR_TYPE_MASK) == VME_MINOR_OUT) {
+		int decoder_num;
+
+		decoder_num = minor & 0xF;	/* Get outbound window num */
+
+		if (decoder_num < 8) 
+			out_image_mapped[decoder_num] = 0;
+		 else 
+			in_image_mapped[decoder_num - 8] = 0;
+	}
+	clear_bit(0, &opened[minor]);
+
+	return 0;
+}
+
+//-----------------------------------------------------------------------------
+// Function   : vme_read()
+// Inputs     : standard linux device driver read() arguments.
+// Outputs    : count of bytes read or error code.
+// Description: 
+//    Sanity check inputs,
+//    If register read,  write user buffer from chip registers
+//    If VME window read, find the outbound window and read data
+//    through the window.  Return number of bytes successfully read.
+// Remarks    : 
+// History    : 
+//-----------------------------------------------------------------------------
+static ssize_t vme_read(struct file *file, char *buf, size_t count,
+			loff_t * ppos)
+{
+	int x = 0;
+	int decoder_num;
+	int okcount = 0;
+	char *image_p;
+	unsigned int v, numt, remain;
+	char *temp = buf;
+	unsigned int minor = iminor(file->f_dentry->d_inode);
+	unsigned int foffset;
+
+	unsigned char vc;
+	unsigned short vs;
+	unsigned int vl;
+	int minor_flags;
+	int image_size;
+
+	minor_flags = vme_minor_type(minor);
+	if (!(minor_flags & DEV_RW)) {
+		return (-EINVAL);
+	}
+
+	if (*ppos > 0xFFFFFFFF) {
+		return (-EINVAL);
+	}
+	foffset = *ppos;
+
+	if (minor == VME_MINOR_REGS) {
+		if ((count != 4) || (foffset & (4 - 1))) {	/* word access only */
+			return (-EINVAL);
+		}
+		if (foffset >= 0x1000) {	/* Truncate at end of reg image */
+			return (0);
+		}
+		v = vme_chip_reg_read((unsigned int *)(vmechip_baseaddr +
+						       foffset));
+		__copy_to_user(temp, &v, 4);
+	}
+
+	if ((minor & VME_MINOR_TYPE_MASK) == VME_MINOR_OUT) {
+
+		decoder_num = minor & 0xF;	/* Get outbound window num */
+
+		if (decoder_num < 8) {
+			if (out_image_va[decoder_num] == 0) {
+				return (-EINVAL);
+			}
+			if (out_image_mapped[decoder_num])
+				return -ENXIO;
+			image_size =
+			    out_resource[decoder_num].end -
+			    out_resource[decoder_num].start + 1;
+			if (foffset >= image_size) {
+				return (0);
+			}
+			down(&out_image_sem[decoder_num]);
+			if ((foffset + count) > image_size) {
+				count = image_size - foffset;
+			}
+			reads++;
+			image_p = (char *)(out_image_va[decoder_num] + foffset);
+
+			// Calc the number of longs we need
+			numt = count / 4;
+			remain = count % 4;
+			for (x = 0; x < numt; x++) {
+				vl = *(int *)(image_p);
+
+				// Lets Check for a Bus Error
+				if (vme_bus_error_chk(1)) {
+					up(&out_image_sem[decoder_num]);
+					return (okcount);
+				}
+				okcount += 4;
+
+				__copy_to_user(temp, &vl, 4);
+				image_p += 4;
+				temp += 4;
+			}
+
+			// Calc the number of Words we need
+			numt = remain / 2;
+			remain = remain % 2;
+			for (x = 0; x < numt; x++) {
+				vs = *(short *)(image_p);
+
+				// Lets Check for a Bus Error
+				if (vme_bus_error_chk(1)) {
+					up(&out_image_sem[decoder_num]);
+					return (okcount);
+				}
+				okcount += 2;
+
+				__copy_to_user(temp, &vs, 2);
+				image_p += 2;
+				temp += 2;
+			}
+
+			for (x = 0; x < remain; x++) {
+				vc = readb(image_p);
+
+				// Lets Check for a Bus Error
+				if (vme_bus_error_chk(1)) {
+					up(&out_image_sem[decoder_num]);
+					return (okcount);
+				}
+				okcount++;
+
+				__copy_to_user(temp, &vc, 1);
+				image_p += 1;
+				temp += 1;
+			}
+			up(&out_image_sem[decoder_num]);
+		} else {	/* inbound windows */
+			decoder_num -= 8;
+			if (in_image_ba[decoder_num] == 0)
+				return -EINVAL;
+			if (in_image_mapped[decoder_num])
+				return -ENXIO;
+			image_size = in_image_size[decoder_num];
+			if (foffset >= image_size) {
+				return (0);
+			}
+			down(&in_image_sem[decoder_num]);
+			if ((foffset + count) > image_size) {
+				count = image_size - foffset;
+			}
+			reads++;
+			image_p = (char *)(in_image_ba[decoder_num] + foffset);
+
+			// Calc the number of longs we need
+			numt = count / 4;
+			remain = count % 4;
+			for (x = 0; x < numt; x++) {
+				vl = *(int *)(image_p);
+				__copy_to_user(temp, &vl, 4);
+				image_p += 4;
+				temp += 4;
+			}
+
+			// Calc the number of Words we need
+			numt = remain / 2;
+			remain = remain % 2;
+			for (x = 0; x < numt; x++) {
+				vs = *(short *)(image_p);
+				__copy_to_user(temp, &vs, 2);
+				image_p += 2;
+				temp += 2;
+			}
+
+			for (x = 0; x < remain; x++) {
+				vc = *(char *)(image_p);
+				__copy_to_user(temp, &vc, 1);
+				image_p += 1;
+				temp += 1;
+			}
+			up(&in_image_sem[decoder_num]);
+		}
+	}
+
+	if (((minor & VME_MINOR_TYPE_MASK) == VME_MINOR_SLOTS1) ||
+	    ((minor & VME_MINOR_TYPE_MASK) == VME_MINOR_SLOTS2)) {
+		return (-EINVAL);	/* Not implemented yet */
+	}
+	*ppos += count;
+	return (count);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : vme_write()
+// Inputs     : standard linux device driver write() arguments.
+// Outputs    : count of bytes written or error code.
+// Description: 
+//    Sanity check inputs,
+//    If register write,  write VME chip registers with the user data
+//    If VME window write, find the outbound window and write user data
+//    through the window.  Return number of bytes successfully written.
+// Remarks    : 
+// History    : 
+//-----------------------------------------------------------------------------
+static ssize_t vme_write(struct file *file, const char *buf, size_t count,
+			 loff_t * ppos)
+{
+	int x;
+	int decoder_num;
+	char *image_p;
+	int okcount = 0;
+	unsigned int numt, remain;
+	char *temp = (char *)buf;
+	unsigned int minor = iminor(file->f_dentry->d_inode);
+	unsigned int foffset;
+
+	unsigned char vc;
+	unsigned short vs;
+	unsigned int vl;
+	int minor_flags;
+	int image_size;
+
+	minor_flags = vme_minor_type(minor);
+	if (!(minor_flags & DEV_RW)) {
+		return (-EINVAL);
+	}
+
+	if (*ppos > 0xFFFFFFFF) {
+		return (-EINVAL);
+	}
+	foffset = *ppos;
+
+	writes++;
+	if (minor == VME_MINOR_REGS) {
+		if ((count != 4) || (foffset & (4 - 1))) {	/* word access only */
+			return (-EINVAL);
+		}
+		if (foffset >= 0x1000) {	/* Truncate at end of reg image */
+			return (0);
+		}
+		__copy_from_user(&vl, temp, 4);
+		vme_chip_reg_write((unsigned int *)(vmechip_baseaddr + foffset),
+				   vl);
+	}
+
+	if ((minor & VME_MINOR_TYPE_MASK) == VME_MINOR_OUT) {
+
+		decoder_num = minor & 0xF;	/* Get outbound window num */
+		if (decoder_num < 8) {
+			if (out_image_va[decoder_num] == 0) {
+				return (-EINVAL);
+			}
+			if (out_image_mapped[decoder_num])
+				return -ENXIO;
+
+			image_size =
+			    out_resource[decoder_num].end -
+			    out_resource[decoder_num].start;
+
+			if (foffset >= image_size) {
+				return (0);
+			}
+			down(&out_image_sem[decoder_num]);
+			if ((foffset + count) > image_size) {
+				count = image_size - foffset;
+			}
+			// Calc the number of longs we need
+			numt = count / 4;
+			remain = count % 4;
+			image_p = (char *)(out_image_va[decoder_num] + foffset);
+
+			for (x = 0; x < numt; x++) {
+				__copy_from_user(&vl, temp, 4);
+				*(int *)image_p = vl;
+
+				// Lets Check for a Bus Error
+				if (vme_bus_error_chk(1)) {
+					up(&out_image_sem[decoder_num]);
+					return (okcount);
+				} else
+					okcount += 4;
+
+				image_p += 4;
+				temp += 4;
+			}
+
+			// Calc the number of Words we need
+			numt = remain / 2;
+			remain = remain % 2;
+
+			for (x = 0; x < numt; x++) {
+				__copy_from_user(&vs, temp, 2);
+				*(short *)image_p = vs;
+
+				// Lets Check for a Bus Error
+				if (vme_bus_error_chk(1)) {
+					up(&out_image_sem[decoder_num]);
+					return (okcount);
+				} else
+					okcount += 2;
+
+				image_p += 2;
+				temp += 2;
+			}
+
+			for (x = 0; x < remain; x++) {
+				__copy_from_user(&vc, temp, 1);
+				writeb(vc, image_p);
+
+				// Lets Check for a Bus Error
+				if (vme_bus_error_chk(1)) {
+					up(&out_image_sem[decoder_num]);
+					return (okcount);
+				} else
+					okcount += 2;
+
+				image_p += 1;
+				temp += 1;
+			}
+			up(&out_image_sem[decoder_num]);
+		} else {	/* inbound windows */
+			decoder_num -= 8;
+			if (in_image_ba[decoder_num] == 0)
+				return -EINVAL;
+			if (in_image_mapped[decoder_num])
+				return -ENXIO;
+
+			image_size = in_image_size[decoder_num];
+
+			if (foffset >= image_size) {
+				return (0);
+			}
+			down(&in_image_sem[decoder_num]);
+			if ((foffset + count) > image_size) {
+				count = image_size - foffset;
+			}
+			// Calc the number of longs we need
+			numt = count / 4;
+			remain = count % 4;
+			image_p = (char *)(in_image_ba[decoder_num] + foffset);
+
+			for (x = 0; x < numt; x++) {
+				__copy_from_user(&vl, temp, 4);
+				*(int *)image_p = vl;
+				image_p += 4;
+				temp += 4;
+			}
+
+			// Calc the number of Words we need
+			numt = remain / 2;
+			remain = remain % 2;
+
+			for (x = 0; x < numt; x++) {
+				__copy_from_user(&vs, temp, 2);
+				*(short *)image_p = vs;
+				image_p += 2;
+				temp += 2;
+			}
+
+			for (x = 0; x < remain; x++) {
+				__copy_from_user(&vc, temp, 1);
+				*(char *)image_p = vc;
+				image_p += 1;
+				temp += 1;
+			}
+			up(&in_image_sem[decoder_num]);
+		}
+	}
+
+	if (((minor & VME_MINOR_TYPE_MASK) == VME_MINOR_SLOTS1) ||
+	    ((minor & VME_MINOR_TYPE_MASK) == VME_MINOR_SLOTS2)) {
+		return (-EINVAL);	/* Not implemented yet */
+	}
+
+	*ppos += count;
+	return (count);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : vme_ioctl()
+// Inputs     : 
+//    cmd -> the IOCTL command
+//    arg -> pointer (if any) to the user ioctl buffer 
+// Outputs    : 0 for sucess or errorcode for failure.
+// Description: 
+//    Copy in, if needed, the user input buffer pointed to by arg.
+//    Call vme driver to perform actual ioctl
+//    Copy out, if needed, the user output buffer pointed to be arg.
+// Remarks    : 
+// History    : 
+//-----------------------------------------------------------------------------
+static int vme_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
+		     unsigned long arg)
+{
+	unsigned int minor = iminor(inode);
+	vmeOutWindowCfg_t vme_out;
+	vmeInfoCfg_t vme_info;
+	vmeRequesterCfg_t vme_req;
+	vmeArbiterCfg_t vme_arb;
+	vmeInWindowCfg_t vme_in;
+	virqInfo_t vme_irq;
+	vmeRmwCfg_t vme_rmw;
+	vmeLmCfg_t vme_lm;
+	int status;
+
+	ioctls++;
+
+	switch (minor & VME_MINOR_TYPE_MASK) {
+	case VME_MINOR_OUT:
+		switch (cmd) {
+		case VME_IOCTL_GET_OUTBOUND:
+			if (copy_from_user
+			    (&vme_out, (void *)arg, sizeof(vme_out)))
+				return -EFAULT;
+			status = vme_get_out_bound(&vme_out);
+			if (status != 0)
+				return (status);
+			if (copy_to_user
+			    ((void *)arg, &vme_out, sizeof(vme_out)))
+				return -EFAULT;
+			break;
+		case VME_IOCTL_SET_OUTBOUND:
+			if (copy_from_user
+			    (&vme_out, (void *)arg, sizeof(vme_out)))
+				return -EFAULT;
+			if ((vme_out.windowNbr < 0) || (vme_out.windowNbr > 7))
+				return -EINVAL;
+			if (out_image_mapped[vme_out.windowNbr])
+				return -ENXIO;
+
+			status = vme_set_out_bound(&vme_out);
+			if (status != 0)
+				return (status);
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case VME_MINOR_DMA:
+		switch (cmd) {
+		case VME_IOCTL_PAUSE_DMA:
+		case VME_IOCTL_CONTINUE_DMA:
+		case VME_IOCTL_ABORT_DMA:
+		case VME_IOCTL_WAIT_DMA:
+			return (-EINVAL);	/* Not supported for now. */
+			break;
+		case VME_IOCTL_START_DMA:
+			status =
+			    vme_ioctl_dma((vmeDmaPacket_t *) arg,
+					  minor - VME_MINOR_DMA);
+			if (status != 0)
+				return (status);
+			break;
+		default:
+			return (-EINVAL);
+		}
+		break;
+
+	case VME_MINOR_MISC:
+		switch (minor) {
+		case VME_MINOR_CTL:
+			switch (cmd) {
+			case VME_IOCTL_GET_SLOT_VME_INFO:
+				if (copy_from_user
+				    (&vme_info, (void *)arg, sizeof(vme_info)))
+					return (-EFAULT);
+				status = vme_get_slot_info(&vme_info);
+				if (status != 0)
+					return (status);
+				if (copy_to_user
+				    ((void *)arg, &vme_info, sizeof(vme_info)))
+					return (-EFAULT);
+				break;
+			case VME_IOCTL_SET_REQUESTOR:
+				if (copy_from_user
+				    (&vme_req, (void *)arg, sizeof(vme_req)))
+					return (-EFAULT);
+				status = vme_set_requestor(&vme_req);
+				if (status != 0)
+					return (status);
+				break;
+			case VME_IOCTL_GET_REQUESTOR:
+				if (copy_from_user
+				    (&vme_req, (void *)arg, sizeof(vme_req)))
+					return (-EFAULT);
+				status = vme_get_requestor(&vme_req);
+				if (status != 0)
+					return (status);
+				if (copy_to_user
+				    ((void *)arg, &vme_req, sizeof(vme_req)))
+					return (-EFAULT);
+				break;
+			case VME_IOCTL_SET_CONTROLLER:
+				if (copy_from_user
+				    (&vme_arb, (void *)arg, sizeof(vme_arb)))
+					return (-EFAULT);
+				status = vme_set_arbiter(&vme_arb);
+				if (status != 0)
+					return (status);
+				if (copy_to_user
+				    ((void *)arg, &vme_arb, sizeof(vme_arb)))
+					return (-EFAULT);
+				break;
+			case VME_IOCTL_GET_CONTROLLER:
+				status = vme_get_arbiter(&vme_arb);
+				if (status != 0)
+					return (status);
+				if (copy_to_user
+				    ((void *)arg, &vme_arb, sizeof(vme_arb)))
+					return (-EFAULT);
+				break;
+				/* For legacy purposes, VME_IOCTL_GET_INBOUND 
+				 * and VME_IOCTL_SET_INBOUND are done here
+				 */
+			case VME_IOCTL_SET_INBOUND:
+				if (copy_from_user
+				    (&vme_in, (void *)arg, sizeof(vme_in)))
+					return -EFAULT;
+				if ((vme_in.windowNbr < 0) ||
+					 (vme_in.windowNbr > 7))
+					return -EINVAL;
+				if (in_image_mapped[vme_in.windowNbr])
+					return -ENXIO;
+				status = vme_set_in_bound(&vme_in);
+				if (status != 0)
+					return (status);
+				break;
+			case VME_IOCTL_GET_INBOUND:
+				if (copy_from_user
+				    (&vme_in, (void *)arg, sizeof(vme_in)))
+					return -EFAULT;
+				status = vme_get_in_bound(&vme_in);
+				if (status != 0)
+					return (status);
+				if (copy_to_user
+				    ((void *)arg, &vme_in, sizeof(vme_in)))
+					return (-EFAULT);
+				break;
+			case VME_IOCTL_GENERATE_IRQ:
+
+				if (copy_from_user
+				    (&vme_irq, (void *)arg, sizeof(vme_irq)))
+					return (-EFAULT);
+
+				// Obtain access to VIRQ generator.
+				if (down_interruptible(&virq_inuse))
+					return (-ERESTARTSYS);
+				status = vme_generate_irq(&vme_irq);
+				up(&virq_inuse);	// Release VIRQ generator.
+
+				if (status != 0)
+					return (status);
+				if (copy_to_user
+				    ((void *)arg, &vme_irq, sizeof(vme_irq)))
+					return (-EFAULT);
+				break;
+
+			case VME_IOCTL_GET_IRQ_STATUS:
+				if (copy_from_user
+				    (&vme_irq, (void *)arg, sizeof(vme_irq)))
+					return (-EFAULT);
+				status = vme_get_irq_status(&vme_irq);
+				if (status != 0)
+					return (status);
+				if (copy_to_user
+				    ((void *)arg, &vme_irq, sizeof(vme_irq)))
+					return (-EFAULT);
+				break;
+			case VME_IOCTL_CLR_IRQ_STATUS:
+				if (copy_from_user
+				    (&vme_irq, (void *)arg, sizeof(vme_irq)))
+					return (-EFAULT);
+				status = vme_clr_irq_status(&vme_irq);
+				if (status != 0)
+					return (status);
+				break;
+			default:
+				return (-EINVAL);
+			}
+			break;
+		case VME_MINOR_REGS:
+			return (-EINVAL);
+		case VME_MINOR_RMW:
+			if (copy_from_user
+			    (&vme_rmw, (void *)arg, sizeof(vme_rmw)))
+				return (-EFAULT);
+			switch (cmd) {
+			case VME_IOCTL_DO_RMW:
+				status = vme_do_rmw(&vme_rmw);
+				if (status != 0)
+					return (status);
+				break;
+			default:
+				return (-EINVAL);
+			}
+			if (copy_to_user
+			    ((void *)arg, &vme_rmw, sizeof(vme_rmw)))
+				return (-EFAULT);
+			break;
+
+		case VME_MINOR_LM:
+			if (copy_from_user
+			    (&vme_lm, (void *)arg, sizeof(vme_lm)))
+				return (-EFAULT);
+			switch (cmd) {
+			case VME_IOCTL_SETUP_LM:
+				status = vme_setup_lm(&vme_lm);
+				if (status != 0)
+					return (status);
+				break;
+			case VME_IOCTL_WAIT_LM:
+				status = vme_wait_lm(&vme_lm);
+				if (status != 0)
+					return (status);
+				break;
+			default:
+				return (-EINVAL);
+			}
+			if (copy_to_user((void *)arg, &vme_lm, sizeof(vme_lm)))
+				return (-EFAULT);
+			break;
+
+		default:
+			return (-EINVAL);
+		}
+		break;
+
+#if	0			// interboard data channels not implemented yet
+	case VME_MINOR_SLOTS1:
+	case VME_MINOR_SLOTS3:
+		break;
+#endif
+	default:
+		return (-EINVAL);
+	}			// masked minor
+	return (status);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : find_vme_bridge()
+// Inputs     : void
+// Outputs    : failed flag.
+// Description: 
+//    Search for a supported VME bridge chip.  
+//    Initialize VME config registers.
+// Remarks    : 
+// History    : 
+//-----------------------------------------------------------------------------
+static struct pci_dev *find_vme_bridge(void)
+{
+	struct pci_dev *vme_pci_dev = NULL;
+
+	if ((vme_pci_dev = pci_get_device(PCI_VENDOR_ID_TUNDRA,
+					   PCI_DEVICE_ID_TUNDRA_CA91C042,
+					   vme_pci_dev))) {
+		vmechip_devid = PCI_DEVICE_ID_TUNDRA_CA91C042;
+	}
+	if (vme_pci_dev == NULL) {
+		if ((vme_pci_dev = pci_get_device(PCI_VENDOR_ID_TUNDRA,
+						   PCI_DEVICE_ID_TUNDRA_TSI148,
+						   vme_pci_dev))) {
+			vmechip_devid = PCI_DEVICE_ID_TUNDRA_TSI148;
+		}
+	}
+	if (vme_pci_dev == NULL) {
+		printk(KERN_ERR "vmemod: VME bridge not found on PCI Bus.\n");
+		return (vme_pci_dev);
+	}
+	// read revision.
+	pci_read_config_dword(vme_pci_dev, PCI_CLASS_REVISION,
+			      &vmechip_revision);
+	printk(KERN_DEBUG "vmemod: PCI_CLASS_REVISION = %08x\n",
+	       vmechip_revision);
+	vmechip_revision &= 0xFF;
+
+	// Unless user has already specified it, 
+	// determine the VMEchip IRQ number.
+	if (vmechip_irq == 0) {
+		vmechip_irq = vme_pci_dev->irq;
+		printk(KERN_DEBUG "vme: irq  = %08x\n", vmechip_irq);
+		vmechip_irq &= 0x000000FF;	// Only a byte in size
+		if (vmechip_irq == 0)
+			vmechip_irq = 0x00000050;	// Only a byte in size
+	}
+	if ((vmechip_irq == 0) || (vmechip_irq == 0xFF)) {
+		printk(KERN_ERR "vmemod: Bad VME IRQ number: %02x\n",
+		       vmechip_irq);
+		return (NULL);
+	}
+
+	return (vme_pci_dev);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : map_in_vme_bridge()
+// Inputs     : void
+// Outputs    : failed flag.
+// Description: 
+//    Map VME chip registers in.  Perform basic sanity check of chip ID.
+// Remarks    : 
+// History    : 
+//-----------------------------------------------------------------------------
+static int map_in_vme_bridge(struct pci_dev *vme_pci_dev)
+{
+	unsigned int temp, ba;
+
+	// Setup VME Bridge Register Space
+	// This is a 4k wide memory area that need to be mapped into the kernel
+	// virtual memory space so we can access it.
+	ba = pci_resource_start(vme_pci_dev, 0);
+	vmechip_baseaddr = ioremap(ba, 4096);
+	if (!vmechip_baseaddr) {
+		printk("ioremap failed to map VMEchip to Kernel Space.\n");
+		return 1;
+	}
+	// Check to see if the Mapping Worked out
+	temp = readl(vmechip_baseaddr) & 0x0000FFFF;
+	if (temp != PCI_VENDOR_ID_TUNDRA) {
+		printk("VME Chip Failed to Return PCI_ID in Memory Map.\n");
+		iounmap(vmechip_baseaddr);
+		return 1;
+	}
+	return (0);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : vme_driver_setup_windows()
+// Inputs     : void
+// Outputs    : void
+// Description: 
+//    Creates initial inbound & outbound VME windows.
+// Remarks    : 
+// History    : 
+//-----------------------------------------------------------------------------
+static void vme_driver_setup_windows(void)
+{
+	vmeOutWindowCfg_t vme_driver_window;
+
+	// Setup the outbound CRCSR window for use by the driver.
+	memset(&vme_driver_window, 0, sizeof(vme_driver_window));
+	vme_driver_window.windowNbr = 7;
+	vme_driver_window.windowEnable = 1;
+	vme_driver_window.windowSizeL = (512 * 1024) * 32;
+	vme_driver_window.xlatedAddrL = 0;
+	vme_driver_window.wrPostEnable = 1;
+	vme_driver_window.addrSpace = VME_CRCSR;
+	vme_driver_window.maxDataWidth = VME_D32;
+	vme_driver_window.xferProtocol = 0;
+	vme_driver_window.dataAccessType = VME_DATA;
+	vme_driver_window.userAccessType = VME_SUPER;
+	vme_set_out_bound(&vme_driver_window);
+
+#if 0
+	/* Setup the inbound windows */
+	if (vme_slotnum > 0) {
+        	vmeInWindowCfg_t vme_in_window;
+        	unsigned int x;
+
+		memset(&vme_in_window, 0, sizeof(vme_in_window));
+		if (in_image_size[x] != 0) {
+			memset(in_image_ba[x], 0, in_image_size[x]);
+			vme_flush_range(in_image_ba[x], in_image_ba[x] + in_image_size[x]);
+			vme_in_window.windowNbr = x;
+			vme_in_window.windowEnable = 1;
+			vme_in_window.windowSizeL = in_image_size[x];
+			vme_in_window.pciAddrL = (unsigned int)in_image_pa[x];
+			vme_in_window.vmeAddrL =
+			    0x80000000 + (vme_slotnum * 0x02000000) + (0x400000 * x);
+			vme_in_window.wrPostEnable = 1;
+			vme_in_window.addrSpace = VME_A32;
+			vme_in_window.xferProtocol =
+				    VME_SCT | VME_BLT | VME_MBLT | VME_2eVME | VME_2eSST;
+			/*  2eSST Transfer Rate */
+			vme_in_window.xferRate2esst = VME_SST320;
+			vme_in_window.dataAccessType = VME_DATA | VME_PROG;
+			vme_in_window.userAccessType = VME_SUPER | VME_USER;
+			vme_set_in_bound(&vme_in_window);
+
+		}
+	}
+#endif
+}
+
+void __init vmemod_setup_options(char *cmdline)
+{
+	char *options;
+
+	/* 
+	 * Look for vme=option on command line 
+	 * Accept something like: 
+	 *      vme=vme_slotnum=<num>
+	 *      vme=vme_slotnum=<num>,vmechip_irq=<num>
+	 */
+
+	options = strstr(cmdline, "vme=");
+	if (!options)
+		return;
+	options = strchr(options, '=') + 1;
+	if (options && !strncmp(options, "vme_slotnum=", 12)) {
+		vme_slotnum = simple_strtoul(options + 12, NULL, 0);
+		options = strchr(options, ',');
+		if (!options)
+			return;
+		if (!strncmp(options + 1, "vmechip_irq=", 12)) {
+			vmechip_irq = simple_strtoul(options + 13, NULL, 0);
+		}
+	} else if (options && !strncmp(options, "vmechip_irq=", 12)) {
+		vmechip_irq = simple_strtoul(options + 12, NULL, 0);
+		options = strchr(options, ',');
+		if (!options)
+			return;
+		if (!strncmp(options + 1, "vme_slotnum=", 12)) {
+			vme_slotnum = simple_strtoul(options + 13, NULL, 0);
+		}
+	}
+	return;
+}
+
+//-----------------------------------------------------------------------------
+// Function   : cleanup_module
+// Inputs     : void
+// Outputs    : void
+// Description: 
+//    Initialize VME chip to quiescent state.
+//    Free driver resources.
+// Remarks    : 
+// History    : 
+//-----------------------------------------------------------------------------
+static void __exit vme_bridge_exit(void)
+{
+	int x;
+
+	// Quiesce the hardware.
+	switch (vmechip_devid) {
+	case PCI_DEVICE_ID_TUNDRA_CA91C042:
+		uni_shutdown();
+		break;
+	case PCI_DEVICE_ID_TUNDRA_TSI148:
+		tsi148_shutdown();
+		break;
+	}
+
+	// Free  & unmap resources
+	free_irq(vmechip_irq, vmechip_baseaddr);
+	iounmap(vmechip_baseaddr);
+	vme_free_buffers();
+
+	for (x = 0; x < 8; x++) {
+		if (out_image_va[x] != 0) {
+			iounmap((void *)out_image_va[x]);
+			out_image_va[x] = 0;
+			out_image_mapped[x] = 0;
+		}
+		if (out_resource[x].end - out_resource[x].start) {
+			iounmap((void *)out_image_va[x]);
+			if (out_resource[x].name != NULL)
+				kfree(out_resource[x].name);
+			release_resource(&out_resource[x]);
+			memset(&out_resource[x], 0, sizeof(struct resource));
+		}
+	}
+
+	unregister_proc();
+	unregister_chrdev(VME_MAJOR, "vme");
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 0));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 1));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 2));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 3));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 4));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 5));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 6));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 7));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 8));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 9));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 10));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 11));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 12));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 13));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 14));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 15));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 16));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 17));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 32));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 33));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 34));
+	device_destroy(vme_class, MKDEV(VME_MAJOR, 35));
+	class_destroy(vme_class);
+}
+
+//-----------------------------------------------------------------------------
+// Function   : init_module()
+// Inputs     : void
+// Outputs    : module initialization fail flag
+// Description: 
+//  top level module initialization.
+//  find VME bridge
+//  initialize VME bridge chip.
+//  Sanity check bridge chip.
+//  allocate and initialize driver resources.
+// Remarks    : 
+// History    : 
+//-----------------------------------------------------------------------------
+
+static int __init vme_bridge_init(void)
+{
+	int x;
+	unsigned int temp;
+	struct resource pcimemres;
+#ifdef CONFIG_MVME5500
+	struct pci_dev *vme_ptp_pci_dev = NULL;
+#endif
+#ifdef CONFIG_MVME6100
+	void __iomem *mv64360;
+	u32  pci_acc_cntl_reg;
+#endif
+
+	printk("Tundra TSI148/CA91C042 PCI-VME Bridge Driver %s\n", Version);
+
+	// find VME bridge
+	vme_pci_dev = find_vme_bridge();
+	if (vme_pci_dev == NULL) {
+		return -ENODEV;
+	}
+#ifdef CONFIG_MVME6100
+#undef	DISABLE_MV64360_SNOOP_WORKAROUND 
+#ifdef	DISABLE_MV64360_SNOOP_WORKAROUND
+	// This is ugly but needed for now.  Disable snoop at 64360.
+	if (vmechip_devid == PCI_DEVICE_ID_TUNDRA_TSI148) {
+		mv64360 = ioremap(CONFIG_MV64X60_NEW_BASE, 0x100000);
+		if (!mv64360) {
+			printk("ioremap failed to map MV64360 regs.\n");
+			return -ENOMEM;
+		}
+		pci_acc_cntl_reg = readl(mv64360 + 
+			MV64x60_PCI0_ACC_CNTL_0_BASE_LO);
+	        if (pci_acc_cntl_reg & 0x00000001) {	
+			pci_acc_cntl_reg = MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+			MV64360_PCI_ACC_CNTL_SWAP_NONE |
+			MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+			MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES | 1;
+			writel(pci_acc_cntl_reg,
+				mv64360 + MV64x60_PCI0_ACC_CNTL_0_BASE_LO);
+		}
+		pci_acc_cntl_reg = readl(mv64360 + 
+			MV64x60_PCI0_ACC_CNTL_1_BASE_LO);
+	        if (pci_acc_cntl_reg & 0x00000001) {	
+			pci_acc_cntl_reg = MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+			MV64360_PCI_ACC_CNTL_SWAP_NONE |
+			MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+			MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES | 1;
+			writel(pci_acc_cntl_reg,
+				mv64360 + MV64x60_PCI0_ACC_CNTL_1_BASE_LO);
+		}
+		pci_acc_cntl_reg = readl(mv64360 + 
+			MV64x60_PCI0_ACC_CNTL_2_BASE_LO);
+	        if (pci_acc_cntl_reg & 0x00000001) {	
+			pci_acc_cntl_reg = MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+			MV64360_PCI_ACC_CNTL_SWAP_NONE |
+			MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+			MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES | 1;
+			writel(pci_acc_cntl_reg,
+				mv64360 + MV64x60_PCI0_ACC_CNTL_2_BASE_LO);
+		}
+		pci_acc_cntl_reg = readl(mv64360 + 
+			MV64x60_PCI0_ACC_CNTL_3_BASE_LO);
+	        if (pci_acc_cntl_reg & 0x00000001) {	
+			pci_acc_cntl_reg = MV64360_PCI_ACC_CNTL_SNOOP_NONE |
+			MV64360_PCI_ACC_CNTL_SWAP_NONE |
+			MV64360_PCI_ACC_CNTL_MBURST_128_BYTES |
+			MV64360_PCI_ACC_CNTL_RDSIZE_256_BYTES | 1;
+			writel(pci_acc_cntl_reg,
+				mv64360 + MV64x60_PCI0_ACC_CNTL_3_BASE_LO);
+		}
+		vme_sync_data();
+		iounmap(mv64360);
+	}
+#endif
+#endif
+
+	// Get parent PCI resource & verify enough space is available.
+	memset(&pcimemres, 0, sizeof(pcimemres));
+	pcimemres.flags = IORESOURCE_MEM;
+	vmepcimem = pci_find_parent_resource(vme_pci_dev, &pcimemres);
+	if (vmepcimem == 0) {
+		printk(KERN_ERR
+		       "vmemod: cannot get VME parent device PCI resource\n");
+		return -ENODEV;
+	}
+#ifdef CONFIG_MVME5500
+#define	VME_BEHIND_BRIDGE_WORKAROUND 1
+#ifdef	VME_BEHIND_BRIDGE_WORKAROUND
+	// If the VME bridge is behind a PCI bridge, only a meg of PCI MEM space
+	// has been allocated.  Bump it up.  This is ugly too but is needed
+	// esp on the MVME5500.
+	if ((vmepcimem->end - vmepcimem->start + 1) == 0x100000) {
+		// find bridge VME is under info
+		vme_ptp_pci_dev = vme_pci_dev->bus->self;
+		pci_write_config_word(vme_ptp_pci_dev, PCI_MEMORY_BASE, 0x8000);
+		vmepcimem->start = 0x80000000;
+	}
+#endif
+#endif
+
+#ifndef CONFIG_MVME7100
+	if ((vmepcimem->end - vmepcimem->start) < 0x2000000) {
+		printk("Not enough PCI memory space available %08x\n",
+		       (unsigned int)(vmepcimem->end - vmepcimem->start));
+		return -ENOMEM;
+	}
+#endif
+	// Map in VME Bridge registers.
+	if (map_in_vme_bridge(vme_pci_dev)) {
+		return -ENODEV;
+	}
+	// Unless, user has already specified it, 
+	// determine the VME slot that we are in.
+	if (vme_slotnum == -1) {
+		vme_slotnum = vme_get_slot_num();
+	}
+	if (vme_slotnum <= 0) {
+		printk(KERN_ERR "Bad VME slot #%02d\n", vme_slotnum);
+		iounmap(vmechip_baseaddr);
+		return -ENODEV;
+	}
+	// Initialize wait queues & mutual exclusion flags
+	init_waitqueue_head(&dma_queue[0]);
+	init_waitqueue_head(&dma_queue[1]);
+	init_waitqueue_head(&lm_queue);
+	init_waitqueue_head(&mbox_queue);
+	for (x = 0; x < 8; x++) {
+		init_waitqueue_head(&vmeint_queue[x]);
+	}
+	sema_init(&virq_inuse, 1);
+	for (x = 0; x < MAX_MINOR + 1; x++) {
+		sema_init(&devinuse[x], 1);
+	}
+	for (x = 0; x < 8; x++) {
+		init_MUTEX(&in_image_sem[x]);
+	}
+	for (x = 0; x < 8; x++) {
+		init_MUTEX(&out_image_sem[x]);
+	}
+
+	// allocate buffers needed by the driver.
+	if (vme_alloc_buffers() != 0)
+		return -ENODEV;
+
+	// Initialize the interboard data structure.
+	if (vmechip_interboard_data != NULL) {
+		vme_init_interboard_data(vmechip_interboard_data);
+	}
+	// Display VME information  
+	printk(KERN_DEBUG
+	       "Vendor = %04X  Device = %04X  Revision = %02X\n",
+	       vme_pci_dev->vendor, vme_pci_dev->device, vmechip_revision);
+	printk(KERN_DEBUG "Class = %08X\n", vme_pci_dev->class);
+
+	pci_read_config_dword(vme_pci_dev, PCI_CACHE_LINE_SIZE, &temp);
+	printk(KERN_DEBUG "Misc0 = %08X\n", temp);
+	printk(KERN_DEBUG "Irq = %04X\n", vmechip_irq);
+	if (vme_slotnum == -1) {
+		printk("VME slot number: unknown\n");
+	} else {
+		printk("VME slot number: %d\n", vme_slotnum);
+	}
+
+	// Initialize chip registers and register module.
+	if (!vme_init(vmechip_interboard_data)) {
+		printk(KERN_ERR "vmemod: VME Chip Initialization failed.\n");
+		iounmap(vmechip_baseaddr);
+		vme_free_buffers();
+		return -ENODEV;
+	}
+	if (register_chrdev(VME_MAJOR, "vme", &vme_fops)) {
+		printk(KERN_ERR "vmemod: Unable to get major number.\n");
+		iounmap(vmechip_baseaddr);
+		vme_free_buffers();
+		return -ENODEV;
+	}
+	vme_class = class_create(THIS_MODULE, "vme");
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 0), NULL, "vme_m0");
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 1), NULL, "vme_m1");
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 2), NULL, "vme_m2");
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 3), NULL, "vme_m3");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 4), NULL, "vme_m4");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 5), NULL, "vme_m5");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 6), NULL, "vme_m6");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 7), NULL, "vme_m7");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 8), NULL, "vme_s0");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 9), NULL, "vme_s1");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 10), NULL, "vme_s2");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 11), NULL, "vme_s3");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 12), NULL, "vme_s4");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 13), NULL, "vme_s5");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 14), NULL, "vme_s6");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 15), NULL, "vme_s7");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 16), NULL, "vme_dma0");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 17), NULL, "vme_dma1");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 32), NULL, "vme_ctl");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 33), NULL, "vme_regs");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 34), NULL, "vme_rmw0");
+
+	device_create(vme_class, NULL, MKDEV(VME_MAJOR, 35), NULL, "vme_lm0");
+
+	if (vme_syscon == 0) {
+		printk("Board is not the VME system controller\n");
+	}
+	if (vme_syscon == 1) {
+		printk("Board is the VME system controller\n");
+	}
+
+	register_proc();
+
+	// Get time base speed.  Needed to support DMA throughput measurements
+	tb_speed = tb_ticks_per_jiffy * HZ;
+
+	// Open up the default VME windows.
+	vme_driver_setup_windows();
+
+	return 0;
+}
+
+module_init(vme_bridge_init)
+module_exit(vme_bridge_exit)
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/watchdog/cpci6200_wdt.c linux-2.6.29.6.mod/drivers/watchdog/cpci6200_wdt.c
--- linux-2.6.29.6.orig/drivers/watchdog/cpci6200_wdt.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/watchdog/cpci6200_wdt.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,449 @@
+/*
+ *	CPCI6200 Watchdog Support
+ *
+ *	Author: Ajit Prem <ajit.prem@emerson.com>
+ *   
+ *	Copyright 2008 Emerson Network Power - Embedded Computing, Inc.
+ *
+ *	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.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <platforms/85xx/cpci6200.h>
+
+#define WDT_INTERVAL	(HZ/2 + 1)
+
+static unsigned long cpci6200_wdt_is_open;
+static char cpci6200_expect_close;
+static struct timer_list cpci6200_wd_timer;
+static unsigned long next_heartbeat;
+
+#define WD_LOAD_REG_OFFSET		0
+#define WD_CONTROL_REG_OFFSET		4
+#define WD_RESOLUTION_REG_OFFSET	5
+#define WD_COUNT_REG_OFFSET		6
+
+#define WD_LOAD_MAGIC_VALUE			0xDB
+#define WD_ENABLE				0x80
+
+#define WD_COUNTER_RES_4_MICROSEC		0x1
+#define WD_COUNTER_RES_8_MICROSEC		0x2
+#define WD_COUNTER_RES_16_MICROSEC		0x3
+#define WD_COUNTER_RES_32_MICROSEC		0x4
+#define WD_COUNTER_RES_64_MICROSEC		0x5
+#define WD_COUNTER_RES_128_MICROSEC		0x6
+#define WD_COUNTER_RES_256_MICROSEC		0x7
+#define WD_COUNTER_RES_512_MICROSEC		0x8
+#define WD_COUNTER_RES_1024_MICROSEC		0x9
+#define WD_COUNTER_RES_2048_MICROSEC		0xa
+#define WD_COUNTER_RES_4096_MICROSEC		0xb
+#define WD_COUNTER_RES_8192_MICROSEC		0xc
+#define WD_COUNTER_RES_16384_MICROSEC		0xd
+#define WD_COUNTER_RES_32768_MICROSEC		0xe
+#define WD_COUNTER_RES_65536_MICROSEC		0xf
+
+
+/* Module parameters */
+
+#define WD_TIM0 60			/* Default heartbeat = 60 seconds */
+
+static int heartbeat = WD_TIM0;
+static int wd_heartbeat = (WD_TIM0 * 1000) >> 6;
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<3600, default=" __MODULE_STRING(WD_TIMO) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+
+static void __iomem *cpci6200_wdt_regs;
+
+/* Start the watchdog driver */
+
+static int cpci6200_wdt_start(void)
+{
+	u8 ctrl_reg;
+	u16 count_reg;
+
+	/* Disable watchdog */
+	ctrl_reg = readb(cpci6200_wdt_regs + WD_CONTROL_REG_OFFSET);
+	if (ctrl_reg & WD_ENABLE)
+		writeb(ctrl_reg & ~WD_ENABLE, cpci6200_wdt_regs + WD_CONTROL_REG_OFFSET);
+
+	/* Load counter */
+	count_reg = wd_heartbeat;
+	writew(swab16(count_reg), cpci6200_wdt_regs + WD_COUNT_REG_OFFSET);
+
+	/* Start the kernel timer */
+	next_heartbeat = jiffies + (heartbeat * HZ);
+	mod_timer(&cpci6200_wd_timer, jiffies + WDT_INTERVAL); 
+
+	/* Enable watchdog */
+	ctrl_reg = readb(cpci6200_wdt_regs + WD_CONTROL_REG_OFFSET);
+	writeb(ctrl_reg | WD_ENABLE, cpci6200_wdt_regs + WD_CONTROL_REG_OFFSET);
+
+	return 0;
+}
+
+/*
+ *	cpci6200_wdt_stop:
+ *
+ *	Stop the watchdog driver.
+ */
+
+static int cpci6200_wdt_stop(void)
+{
+	u8 ctrl_reg;
+
+	printk(KERN_INFO "cpci6200_wdt: Stopping watchdog timer\n");
+	del_timer(&cpci6200_wd_timer);
+
+	/* Turn the watchdog off */
+	ctrl_reg = readb(cpci6200_wdt_regs + WD_CONTROL_REG_OFFSET);
+	ctrl_reg &= ~WD_ENABLE;
+	writeb(ctrl_reg, cpci6200_wdt_regs + WD_CONTROL_REG_OFFSET);
+
+	return 0;
+}
+
+/*
+ *	cpci6200_wdt_ping:
+ *
+ *	Reload counter with the watchdog heartbeat. 
+ */
+
+static void cpci6200_wdt_ping(unsigned long data)
+{
+	if(time_before(jiffies, next_heartbeat)) {
+		/* Write the magic value  to the LOAD Register */
+		writeb(WD_LOAD_MAGIC_VALUE, cpci6200_wdt_regs + WD_LOAD_REG_OFFSET);
+		mod_timer(&cpci6200_wd_timer, jiffies + WDT_INTERVAL);
+	} else {
+		printk(KERN_WARNING "Heartbeat lost! Will not ping the watchdog.\n");
+	}
+	return;
+}
+
+
+static int cpci6200_wdt_keepalive(void)
+{
+	/* userland ping */
+	next_heartbeat = jiffies + (heartbeat * HZ);
+	return 0;
+}
+
+
+/*
+ *	cpci6200_wdt_set_heartbeat:
+ *	@t:		the new heartbeat value that needs to be set.
+ *
+ *	Set a new heartbeat value for the watchdog device. If the heartbeat 
+ *      value is incorrect we keep the old value and return -EINVAL. 
+ *      If successfull we return 0.
+ */
+static int cpci6200_wdt_set_heartbeat(int t)
+{
+	if ((t < 1) || (t > 3600))
+		return -EINVAL;
+
+	heartbeat = t;
+	/* heartbeat is in seconds. The watchdog resolution has been 
+         * set to countdown every 65536 microseconds */
+	wd_heartbeat = ((t * 1000) >> 6) & 0xffff;
+	return 0;
+}
+
+/**
+ *	cpci6200_wdt_write:
+ *	@file: file handle to the watchdog
+ *	@buf: buffer to write (unused as data does not matter here
+ *	@count: count of bytes
+ *	@ppos: pointer to the position to write. No seeks allowed
+ *
+ *	A write to a watchdog device is defined as a keepalive signal. Any
+ *	write of data will do, as we we don't define content meaning.
+ */
+
+static ssize_t cpci6200_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+	if(count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			cpci6200_expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					cpci6200_expect_close = 42;
+			}
+		}
+		cpci6200_wdt_keepalive();
+	}
+	return count;
+}
+
+/**
+ *	cpci6200_wdt_ioctl:
+ *	@inode: inode of the device
+ *	@file: file handle to the device
+ *	@cmd: watchdog command
+ *	@arg: argument pointer
+ *
+ *	The watchdog API defines a common set of functions for all watchdogs
+ *	according to their available features. We only actually usefully support
+ *	querying capabilities and current status.
+ */
+
+static int cpci6200_wdt_ioctl(struct inode *inode, struct file *file, 
+		              unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_heartbeat;
+	int options;
+
+	static struct watchdog_info ident = {
+		.options =		WDIOF_SETTIMEOUT |
+					WDIOF_MAGICCLOSE |
+					WDIOF_KEEPALIVEPING,
+		.firmware_version =	1,
+		.identity =		"CPCI6200_WDT",
+	};
+
+	switch(cmd)
+	{
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+		case WDIOC_KEEPALIVE:
+			cpci6200_wdt_keepalive();
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_heartbeat, p))
+				return -EFAULT;
+
+			if (cpci6200_wdt_set_heartbeat(new_heartbeat))
+				return -EINVAL;
+
+			cpci6200_wdt_keepalive();
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(heartbeat, p);
+		case WDIOC_SETOPTIONS:
+			if (get_user(options, p))
+				return -EFAULT;
+			if (options & WDIOS_DISABLECARD) {
+				cpci6200_wdt_stop();
+				return 0;
+			}
+
+			if (options & WDIOS_ENABLECARD) {
+				cpci6200_wdt_start();
+				return 0;
+			}
+			break;
+		default:
+			return -ENOTTY;
+
+	}
+	return 0;
+}
+
+/*
+ *	cpci6200_wdt_open:
+ *	@inode: inode of device
+ *	@file: file handle to device
+ *
+ */
+
+static int cpci6200_wdt_open(struct inode *inode, struct file *file)
+{
+	if(test_and_set_bit(0, &cpci6200_wdt_is_open))
+		return -EBUSY;
+
+	/* Activate */
+	printk(KERN_INFO "cpci6200_wdt: Starting watchdog timer\n");
+	cpci6200_wdt_start();
+
+	return nonseekable_open(inode, file);
+}
+
+/*
+ *	cpci6200_wdt_release:
+ *	@inode: inode to board
+ *	@file: file handle to board
+ *
+ *	The watchdog has a configurable API. There is a religious dispute
+ *	between people who want their watchdog to be able to shut down and
+ *	those who want to be sure if the watchdog manager dies the machine
+ *	reboots. In the former case we disable the watchdog timer, in the 
+ *      latter case you have to open it again very soon.
+ */
+
+static int cpci6200_wdt_release(struct inode *inode, struct file *file)
+{
+	if (cpci6200_expect_close == 42) {
+		cpci6200_wdt_stop();
+	} else {
+		printk(KERN_CRIT "cpci6200_wdt:  watchdog device closed unexpectedly - watchdog will not stop!\n");
+		cpci6200_wdt_keepalive();
+	}
+	cpci6200_expect_close = 0;
+	clear_bit(0, &cpci6200_wdt_is_open);
+	return 0;
+}
+
+/**
+ *	notify_sys:
+ *	@this: our notifier block
+ *	@code: the event being reported
+ *	@unused: unused
+ *
+ *	Our notifier is called on system shutdowns. We want to turn the 
+ *      watchdog off at reboot.
+ */
+
+static int cpci6200_wdt_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the card off */
+		cpci6200_wdt_stop();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+
+static const struct file_operations cpci6200_wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= cpci6200_wdt_write,
+	.ioctl		= cpci6200_wdt_ioctl,
+	.open		= cpci6200_wdt_open,
+	.release	= cpci6200_wdt_release,
+};
+
+static struct miscdevice cpci6200_wdt_miscdev = {
+	.minor	= WATCHDOG_MINOR,
+	.name	= "watchdog",
+	.fops	= &cpci6200_wdt_fops,
+};
+
+/*
+ *	The watchdog timer needs to be stopped on reboots/shutdowns 
+ */
+
+static struct notifier_block cpci6200_wdt_notifier = {
+	.notifier_call = cpci6200_wdt_notify_sys,
+};
+
+/*
+ *	cleanup_module:
+ *
+ *	Unload the watchdog. You cannot do this with any file handles open.
+ *	If your watchdog is set to continue ticking on close and you unload
+ *	it, well it keeps ticking.  You just have to load a new
+ *	module in 60 seconds or reboot.
+ */
+
+static void __devexit cpci6200_wdt_exit(void)
+{
+	if (!nowayout) 
+		cpci6200_wdt_stop();
+	iounmap(cpci6200_wdt_regs);	
+	misc_deregister(&cpci6200_wdt_miscdev);
+	unregister_reboot_notifier(&cpci6200_wdt_notifier);
+}
+
+/*
+ * 	cpci6200_wdt_init:
+ *
+ *	Set up the CPCI6200 watchdog. 
+ *	The open() function will actually kick the watchdog.
+ */
+
+static int __devinit cpci6200_wdt_init(void)
+{
+	int ret = 0;
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (cpci6200_wdt_set_heartbeat(heartbeat)) {
+		cpci6200_wdt_set_heartbeat(WD_TIM0);
+		printk(KERN_INFO "wdt: heartbeat value must be 0<heartbeat<3600 secs, using %d secs\n",
+			WD_TIM0);
+	}
+
+	cpci6200_wdt_regs = ioremap(CPCI6200_WATCHDOG_TIMER_LOAD_REG, 8);
+	if (cpci6200_wdt_regs == NULL) {
+		printk(KERN_ERR "cpci6200_wdt: ioremap() failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	writeb(WD_COUNTER_RES_65536_MICROSEC, cpci6200_wdt_regs + WD_RESOLUTION_REG_OFFSET);
+
+	init_timer(&cpci6200_wd_timer);
+	cpci6200_wd_timer.function = cpci6200_wdt_ping;
+	cpci6200_wd_timer.data = 0;
+
+	ret = register_reboot_notifier(&cpci6200_wdt_notifier);
+	if(ret) {
+		printk(KERN_ERR "cpci6200_wdt: cannot register reboot notifier (err=%d)\n", ret);
+		goto out;
+	}
+
+	ret = misc_register(&cpci6200_wdt_miscdev);
+	if (ret) {
+		printk(KERN_ERR "cpci6200_wdt: cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto outmisc;
+	}
+
+	printk(KERN_INFO "cpci6200 watchdog driver ver 1.0: (heartbeat=%d sec, nowayout=%d)\n",
+		heartbeat, nowayout);
+out:
+	return ret;
+
+outmisc:
+	unregister_reboot_notifier(&cpci6200_wdt_notifier);
+	goto out;
+}
+
+module_init(cpci6200_wdt_init);
+module_exit(cpci6200_wdt_exit);
+
+MODULE_AUTHOR("Ajit Prem");
+MODULE_DESCRIPTION("Watchdog Driver for the CPCI6200 watchdog");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/watchdog/Kconfig linux-2.6.29.6.mod/drivers/watchdog/Kconfig
--- linux-2.6.29.6.orig/drivers/watchdog/Kconfig	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/watchdog/Kconfig	2009-07-21 11:28:18.000000000 -0700
@@ -811,6 +811,35 @@
 	  Please see Documentation/watchdog/watchdog-api.txt for
 	  more information.
 
+config MVME7100_WDT
+        tristate "MVME7100 Watchdog Timer"
+        depends on WATCHDOG && MVME7100
+        ---help---
+          If you have an MVME7100 board, say Y here, otherwise N.
+
+          To compile this driver as a module, choose M here: the
+          module will be called mvme7100_wdt.
+ 
+config MVME4100_WDT
+        tristate "MVME4100 Watchdog Timer"
+        depends on WATCHDOG && MVME4100
+        ---help---
+          If you have an MVME4100 board, say Y here, otherwise N.
+
+          To compile this driver as a module, choose M here: the
+          module will be called mvme4100_wdt.
+ 
+config CPCI6200_WDT
+        tristate "CPCI6200 Watchdog Timer"
+        depends on WATCHDOG && CPCI6200
+        ---help---
+          If you have an CPCI6200 board, say Y here, otherwise N.
+
+          To compile this driver as a module, choose M here: the
+          module will be called cpci6200_wdt.
+
+# PPC64 Architecture
+
 # PPC64 Architecture
 
 config WATCHDOG_RTAS
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/watchdog/Makefile linux-2.6.29.6.mod/drivers/watchdog/Makefile
--- linux-2.6.29.6.orig/drivers/watchdog/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/watchdog/Makefile	2009-07-21 11:28:18.000000000 -0700
@@ -117,6 +117,9 @@
 obj-$(CONFIG_MV64X60_WDT) += mv64x60_wdt.o
 obj-$(CONFIG_PIKA_WDT) += pika_wdt.o
 obj-$(CONFIG_BOOKE_WDT) += booke_wdt.o
+obj-$(CONFIG_MVME7100_WDT) += mvme7100_wdt.o
+obj-$(CONFIG_MVME4100_WDT) += mvme4100_wdt.o
+obj-$(CONFIG_CPCI6200_WDT) += cpci6200_wdt.o
 
 # PPC64 Architecture
 obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/watchdog/mvme4100_wdt.c linux-2.6.29.6.mod/drivers/watchdog/mvme4100_wdt.c
--- linux-2.6.29.6.orig/drivers/watchdog/mvme4100_wdt.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/watchdog/mvme4100_wdt.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,450 @@
+/*
+ *	MVME4100 Watchdog Support
+ *
+ *	Author: Ajit Prem <ajit.prem@emerson.com>
+ *   
+ *	Copyright 2008 Emerson Network Power - Embedded Computing, Inc.
+ *
+ *	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.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <platforms/85xx/mvme4100.h>
+
+#define WDT_INTERVAL	(HZ/2 + 1)
+
+static unsigned long mvme4100_wdt_is_open;
+static char mvme4100_expect_close;
+static struct timer_list mvme4100_wd_timer;
+static unsigned long next_heartbeat;
+
+#define WD_LOAD_REG_OFFSET		0
+#define WD_CONTROL_REG_OFFSET		4
+#define WD_RESOLUTION_REG_OFFSET	5
+#define WD_COUNT_REG_OFFSET		6
+
+#define WD_LOAD_MAGIC_VALUE			0xDB
+#define WD_ENABLE				0x80
+#define WD_VMEBUS_SYS_RESET			0x40
+
+#define WD_COUNTER_RES_4_MICROSEC		0x1
+#define WD_COUNTER_RES_8_MICROSEC		0x2
+#define WD_COUNTER_RES_16_MICROSEC		0x3
+#define WD_COUNTER_RES_32_MICROSEC		0x4
+#define WD_COUNTER_RES_64_MICROSEC		0x5
+#define WD_COUNTER_RES_128_MICROSEC		0x6
+#define WD_COUNTER_RES_256_MICROSEC		0x7
+#define WD_COUNTER_RES_512_MICROSEC		0x8
+#define WD_COUNTER_RES_1024_MICROSEC		0x9
+#define WD_COUNTER_RES_2048_MICROSEC		0xa
+#define WD_COUNTER_RES_4096_MICROSEC		0xb
+#define WD_COUNTER_RES_8192_MICROSEC		0xc
+#define WD_COUNTER_RES_16384_MICROSEC		0xd
+#define WD_COUNTER_RES_32768_MICROSEC		0xe
+#define WD_COUNTER_RES_65536_MICROSEC		0xf
+
+
+/* Module parameters */
+
+#define WD_TIM0 60			/* Default heartbeat = 60 seconds */
+
+static int heartbeat = WD_TIM0;
+static int wd_heartbeat = (WD_TIM0 * 1000) >> 6;
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<3600, default=" __MODULE_STRING(WD_TIMO) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+
+static void __iomem *mvme4100_wdt_regs;
+
+/* Start the watchdog driver */
+
+static int mvme4100_wdt_start(void)
+{
+	u8 ctrl_reg;
+	u16 count_reg;
+
+	/* Disable watchdog */
+	ctrl_reg = readb(mvme4100_wdt_regs + WD_CONTROL_REG_OFFSET);
+	if (ctrl_reg & WD_ENABLE)
+		writeb(ctrl_reg & ~WD_ENABLE, mvme4100_wdt_regs + WD_CONTROL_REG_OFFSET);
+
+	/* Load counter */
+	count_reg = wd_heartbeat;
+	writew(swab16(count_reg), mvme4100_wdt_regs + WD_COUNT_REG_OFFSET);
+
+	/* Start the kernel timer */
+	next_heartbeat = jiffies + (heartbeat * HZ);
+	mod_timer(&mvme4100_wd_timer, jiffies + WDT_INTERVAL); 
+
+	/* Enable watchdog */
+	ctrl_reg = readb(mvme4100_wdt_regs + WD_CONTROL_REG_OFFSET);
+	writeb(ctrl_reg | WD_ENABLE, mvme4100_wdt_regs + WD_CONTROL_REG_OFFSET);
+
+	return 0;
+}
+
+/*
+ *	mvme4100_wdt_stop:
+ *
+ *	Stop the watchdog driver.
+ */
+
+static int mvme4100_wdt_stop(void)
+{
+	u8 ctrl_reg;
+
+	printk(KERN_INFO "mvme4100_wdt: Stopping watchdog timer\n");
+	del_timer(&mvme4100_wd_timer);
+
+	/* Turn the watchdog off */
+	ctrl_reg = readb(mvme4100_wdt_regs + WD_CONTROL_REG_OFFSET);
+	ctrl_reg &= ~WD_ENABLE;
+	writeb(ctrl_reg, mvme4100_wdt_regs + WD_CONTROL_REG_OFFSET);
+
+	return 0;
+}
+
+/*
+ *	mvme4100_wdt_ping:
+ *
+ *	Reload counter with the watchdog heartbeat. 
+ */
+
+static void mvme4100_wdt_ping(unsigned long data)
+{
+	if(time_before(jiffies, next_heartbeat)) {
+		/* Write the magic value  to the LOAD Register */
+		writeb(WD_LOAD_MAGIC_VALUE, mvme4100_wdt_regs + WD_LOAD_REG_OFFSET);
+		mod_timer(&mvme4100_wd_timer, jiffies + WDT_INTERVAL);
+	} else {
+		printk(KERN_WARNING "Heartbeat lost! Will not ping the watchdog.\n");
+	}
+	return;
+}
+
+
+static int mvme4100_wdt_keepalive(void)
+{
+	/* userland ping */
+	next_heartbeat = jiffies + (heartbeat * HZ);
+	return 0;
+}
+
+
+/*
+ *	mvme4100_wdt_set_heartbeat:
+ *	@t:		the new heartbeat value that needs to be set.
+ *
+ *	Set a new heartbeat value for the watchdog device. If the heartbeat 
+ *      value is incorrect we keep the old value and return -EINVAL. 
+ *      If successfull we return 0.
+ */
+static int mvme4100_wdt_set_heartbeat(int t)
+{
+	if ((t < 1) || (t > 3600))
+		return -EINVAL;
+
+	heartbeat = t;
+	/* heartbeat is in seconds. The watchdog resolution has been 
+         * set to countdown every 65536 microseconds */
+	wd_heartbeat = ((t * 1000) >> 6) & 0xffff;
+	return 0;
+}
+
+/**
+ *	mvme4100_wdt_write:
+ *	@file: file handle to the watchdog
+ *	@buf: buffer to write (unused as data does not matter here
+ *	@count: count of bytes
+ *	@ppos: pointer to the position to write. No seeks allowed
+ *
+ *	A write to a watchdog device is defined as a keepalive signal. Any
+ *	write of data will do, as we we don't define content meaning.
+ */
+
+static ssize_t mvme4100_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+	if(count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			mvme4100_expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					mvme4100_expect_close = 42;
+			}
+		}
+		mvme4100_wdt_keepalive();
+	}
+	return count;
+}
+
+/**
+ *	mvme4100_wdt_ioctl:
+ *	@inode: inode of the device
+ *	@file: file handle to the device
+ *	@cmd: watchdog command
+ *	@arg: argument pointer
+ *
+ *	The watchdog API defines a common set of functions for all watchdogs
+ *	according to their available features. We only actually usefully support
+ *	querying capabilities and current status.
+ */
+
+static int mvme4100_wdt_ioctl(struct inode *inode, struct file *file, 
+		              unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_heartbeat;
+	int options;
+
+	static struct watchdog_info ident = {
+		.options =		WDIOF_SETTIMEOUT |
+					WDIOF_MAGICCLOSE |
+					WDIOF_KEEPALIVEPING,
+		.firmware_version =	1,
+		.identity =		"MVME4100_WDT",
+	};
+
+	switch(cmd)
+	{
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+		case WDIOC_KEEPALIVE:
+			mvme4100_wdt_keepalive();
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_heartbeat, p))
+				return -EFAULT;
+
+			if (mvme4100_wdt_set_heartbeat(new_heartbeat))
+				return -EINVAL;
+
+			mvme4100_wdt_keepalive();
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(heartbeat, p);
+		case WDIOC_SETOPTIONS:
+			if (get_user(options, p))
+				return -EFAULT;
+			if (options & WDIOS_DISABLECARD) {
+				mvme4100_wdt_stop();
+				return 0;
+			}
+
+			if (options & WDIOS_ENABLECARD) {
+				mvme4100_wdt_start();
+				return 0;
+			}
+			break;
+		default:
+			return -ENOTTY;
+
+	}
+	return 0;
+}
+
+/*
+ *	mvme4100_wdt_open:
+ *	@inode: inode of device
+ *	@file: file handle to device
+ *
+ */
+
+static int mvme4100_wdt_open(struct inode *inode, struct file *file)
+{
+	if(test_and_set_bit(0, &mvme4100_wdt_is_open))
+		return -EBUSY;
+
+	/* Activate */
+	printk(KERN_INFO "mvme4100_wdt: Starting watchdog timer\n");
+	mvme4100_wdt_start();
+
+	return nonseekable_open(inode, file);
+}
+
+/*
+ *	mvme4100_wdt_release:
+ *	@inode: inode to board
+ *	@file: file handle to board
+ *
+ *	The watchdog has a configurable API. There is a religious dispute
+ *	between people who want their watchdog to be able to shut down and
+ *	those who want to be sure if the watchdog manager dies the machine
+ *	reboots. In the former case we disable the watchdog timer, in the 
+ *      latter case you have to open it again very soon.
+ */
+
+static int mvme4100_wdt_release(struct inode *inode, struct file *file)
+{
+	if (mvme4100_expect_close == 42) {
+		mvme4100_wdt_stop();
+	} else {
+		printk(KERN_CRIT "mvme4100_wdt:  watchdog device closed unexpectedly - watchdog will not stop!\n");
+		mvme4100_wdt_keepalive();
+	}
+	mvme4100_expect_close = 0;
+	clear_bit(0, &mvme4100_wdt_is_open);
+	return 0;
+}
+
+/**
+ *	notify_sys:
+ *	@this: our notifier block
+ *	@code: the event being reported
+ *	@unused: unused
+ *
+ *	Our notifier is called on system shutdowns. We want to turn the 
+ *      watchdog off at reboot.
+ */
+
+static int mvme4100_wdt_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the card off */
+		mvme4100_wdt_stop();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+
+static const struct file_operations mvme4100_wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= mvme4100_wdt_write,
+	.ioctl		= mvme4100_wdt_ioctl,
+	.open		= mvme4100_wdt_open,
+	.release	= mvme4100_wdt_release,
+};
+
+static struct miscdevice mvme4100_wdt_miscdev = {
+	.minor	= WATCHDOG_MINOR,
+	.name	= "watchdog",
+	.fops	= &mvme4100_wdt_fops,
+};
+
+/*
+ *	The watchdog timer needs to be stopped on reboots/shutdowns 
+ */
+
+static struct notifier_block mvme4100_wdt_notifier = {
+	.notifier_call = mvme4100_wdt_notify_sys,
+};
+
+/*
+ *	cleanup_module:
+ *
+ *	Unload the watchdog. You cannot do this with any file handles open.
+ *	If your watchdog is set to continue ticking on close and you unload
+ *	it, well it keeps ticking.  You just have to load a new
+ *	module in 60 seconds or reboot.
+ */
+
+static void __devexit mvme4100_wdt_exit(void)
+{
+	if (!nowayout) 
+		mvme4100_wdt_stop();
+	iounmap(mvme4100_wdt_regs);	
+	misc_deregister(&mvme4100_wdt_miscdev);
+	unregister_reboot_notifier(&mvme4100_wdt_notifier);
+}
+
+/*
+ * 	mvme4100_wdt_init:
+ *
+ *	Set up the MVME4100 watchdog. 
+ *	The open() function will actually kick the watchdog.
+ */
+
+static int __devinit mvme4100_wdt_init(void)
+{
+	int ret = 0;
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (mvme4100_wdt_set_heartbeat(heartbeat)) {
+		mvme4100_wdt_set_heartbeat(WD_TIM0);
+		printk(KERN_INFO "wdt: heartbeat value must be 0<heartbeat<3600 secs, using %d secs\n",
+			WD_TIM0);
+	}
+
+	mvme4100_wdt_regs = ioremap(MVME4100_WATCHDOG_TIMER_LOAD_REG, 8);
+	if (mvme4100_wdt_regs == NULL) {
+		printk(KERN_ERR "mvme4100_wdt: ioremap() failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	writeb(WD_COUNTER_RES_65536_MICROSEC, mvme4100_wdt_regs + WD_RESOLUTION_REG_OFFSET);
+
+	init_timer(&mvme4100_wd_timer);
+	mvme4100_wd_timer.function = mvme4100_wdt_ping;
+	mvme4100_wd_timer.data = 0;
+
+	ret = register_reboot_notifier(&mvme4100_wdt_notifier);
+	if(ret) {
+		printk(KERN_ERR "mvme4100_wdt: cannot register reboot notifier (err=%d)\n", ret);
+		goto out;
+	}
+
+	ret = misc_register(&mvme4100_wdt_miscdev);
+	if (ret) {
+		printk(KERN_ERR "mvme4100_wdt: cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto outmisc;
+	}
+
+	printk(KERN_INFO "mvme4100 watchdog driver ver 1.0: (heartbeat=%d sec, nowayout=%d)\n",
+		heartbeat, nowayout);
+out:
+	return ret;
+
+outmisc:
+	unregister_reboot_notifier(&mvme4100_wdt_notifier);
+	goto out;
+}
+
+module_init(mvme4100_wdt_init);
+module_exit(mvme4100_wdt_exit);
+
+MODULE_AUTHOR("Ajit Prem");
+MODULE_DESCRIPTION("Watchdog Driver for the MVME4100 watchdog");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/drivers/watchdog/mvme7100_wdt.c linux-2.6.29.6.mod/drivers/watchdog/mvme7100_wdt.c
--- linux-2.6.29.6.orig/drivers/watchdog/mvme7100_wdt.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/drivers/watchdog/mvme7100_wdt.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,450 @@
+/*
+ *	MVME7100 Watchdog Support
+ *
+ *	Author: Ajit Prem <ajit.prem@emerson.com>
+ *   
+ *	Copyright 2008 Emerson Network Power - Embedded Computing, Inc.
+ *
+ *	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.
+ *
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/types.h>
+#include <linux/miscdevice.h>
+#include <linux/watchdog.h>
+#include <linux/fs.h>
+#include <linux/ioport.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/init.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <platforms/86xx/mvme7100.h>
+
+#define WDT_INTERVAL	(HZ/2 + 1)
+
+static unsigned long mvme7100_wdt_is_open;
+static char mvme7100_expect_close;
+static struct timer_list mvme7100_wd_timer;
+static unsigned long next_heartbeat;
+
+#define WD_LOAD_REG_OFFSET		0
+#define WD_CONTROL_REG_OFFSET		4
+#define WD_RESOLUTION_REG_OFFSET	5
+#define WD_COUNT_REG_OFFSET		6
+
+#define WD_LOAD_MAGIC_VALUE			0xDB
+#define WD_ENABLE				0x80
+#define WD_VMEBUS_SYS_RESET			0x40
+
+#define WD_COUNTER_RES_4_MICROSEC		0x1
+#define WD_COUNTER_RES_8_MICROSEC		0x2
+#define WD_COUNTER_RES_16_MICROSEC		0x3
+#define WD_COUNTER_RES_32_MICROSEC		0x4
+#define WD_COUNTER_RES_64_MICROSEC		0x5
+#define WD_COUNTER_RES_128_MICROSEC		0x6
+#define WD_COUNTER_RES_256_MICROSEC		0x7
+#define WD_COUNTER_RES_512_MICROSEC		0x8
+#define WD_COUNTER_RES_1024_MICROSEC		0x9
+#define WD_COUNTER_RES_2048_MICROSEC		0xa
+#define WD_COUNTER_RES_4096_MICROSEC		0xb
+#define WD_COUNTER_RES_8192_MICROSEC		0xc
+#define WD_COUNTER_RES_16384_MICROSEC		0xd
+#define WD_COUNTER_RES_32768_MICROSEC		0xe
+#define WD_COUNTER_RES_65536_MICROSEC		0xf
+
+
+/* Module parameters */
+
+#define WD_TIM0 60			/* Default heartbeat = 60 seconds */
+
+static int heartbeat = WD_TIM0;
+static int wd_heartbeat = (WD_TIM0 * 1000) >> 6;
+
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds. (0<heartbeat<3600, default=" __MODULE_STRING(WD_TIMO) ")");
+
+static int nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, int, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=CONFIG_WATCHDOG_NOWAYOUT)");
+
+
+static void __iomem *mvme7100_wdt_regs;
+
+/* Start the watchdog driver */
+
+static int mvme7100_wdt_start(void)
+{
+	u8 ctrl_reg;
+	u16 count_reg;
+
+	/* Disable watchdog */
+	ctrl_reg = readb(mvme7100_wdt_regs + WD_CONTROL_REG_OFFSET);
+	if (ctrl_reg & WD_ENABLE)
+		writeb(ctrl_reg & ~WD_ENABLE, mvme7100_wdt_regs + WD_CONTROL_REG_OFFSET);
+
+	/* Load counter */
+	count_reg = wd_heartbeat;
+	writew(swab16(count_reg), mvme7100_wdt_regs + WD_COUNT_REG_OFFSET);
+
+	/* Start the kernel timer */
+	next_heartbeat = jiffies + (heartbeat * HZ);
+	mod_timer(&mvme7100_wd_timer, jiffies + WDT_INTERVAL); 
+
+	/* Enable watchdog */
+	ctrl_reg = readb(mvme7100_wdt_regs + WD_CONTROL_REG_OFFSET);
+	writeb(ctrl_reg | WD_ENABLE, mvme7100_wdt_regs + WD_CONTROL_REG_OFFSET);
+
+	return 0;
+}
+
+/*
+ *	mvme7100_wdt_stop:
+ *
+ *	Stop the watchdog driver.
+ */
+
+static int mvme7100_wdt_stop(void)
+{
+	u8 ctrl_reg;
+
+	printk(KERN_INFO "mvme7100_wdt: Stopping watchdog timer\n");
+	del_timer(&mvme7100_wd_timer);
+
+	/* Turn the watchdog off */
+	ctrl_reg = readb(mvme7100_wdt_regs + WD_CONTROL_REG_OFFSET);
+	ctrl_reg &= ~WD_ENABLE;
+	writeb(ctrl_reg, mvme7100_wdt_regs + WD_CONTROL_REG_OFFSET);
+
+	return 0;
+}
+
+/*
+ *	mvme7100_wdt_ping:
+ *
+ *	Reload counter with the watchdog heartbeat. 
+ */
+
+static void mvme7100_wdt_ping(unsigned long data)
+{
+	if(time_before(jiffies, next_heartbeat)) {
+		/* Write the magic value  to the LOAD Register */
+		writeb(WD_LOAD_MAGIC_VALUE, mvme7100_wdt_regs + WD_LOAD_REG_OFFSET);
+		mod_timer(&mvme7100_wd_timer, jiffies + WDT_INTERVAL);
+	} else {
+		printk(KERN_WARNING "Heartbeat lost! Will not ping the watchdog.\n");
+	}
+	return;
+}
+
+
+static int mvme7100_wdt_keepalive(void)
+{
+	/* userland ping */
+	next_heartbeat = jiffies + (heartbeat * HZ);
+	return 0;
+}
+
+
+/*
+ *	mvme7100_wdt_set_heartbeat:
+ *	@t:		the new heartbeat value that needs to be set.
+ *
+ *	Set a new heartbeat value for the watchdog device. If the heartbeat 
+ *      value is incorrect we keep the old value and return -EINVAL. 
+ *      If successfull we return 0.
+ */
+static int mvme7100_wdt_set_heartbeat(int t)
+{
+	if ((t < 1) || (t > 3600))
+		return -EINVAL;
+
+	heartbeat = t;
+	/* heartbeat is in seconds. The watchdog resolution has been 
+         * set to countdown every 65536 microseconds */
+	wd_heartbeat = ((t * 1000) >> 6) & 0xffff;
+	return 0;
+}
+
+/**
+ *	mvme7100_wdt_write:
+ *	@file: file handle to the watchdog
+ *	@buf: buffer to write (unused as data does not matter here
+ *	@count: count of bytes
+ *	@ppos: pointer to the position to write. No seeks allowed
+ *
+ *	A write to a watchdog device is defined as a keepalive signal. Any
+ *	write of data will do, as we we don't define content meaning.
+ */
+
+static ssize_t mvme7100_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
+{
+	if(count) {
+		if (!nowayout) {
+			size_t i;
+
+			/* In case it was set long ago */
+			mvme7100_expect_close = 0;
+
+			for (i = 0; i != count; i++) {
+				char c;
+				if (get_user(c, buf + i))
+					return -EFAULT;
+				if (c == 'V')
+					mvme7100_expect_close = 42;
+			}
+		}
+		mvme7100_wdt_keepalive();
+	}
+	return count;
+}
+
+/**
+ *	mvme7100_wdt_ioctl:
+ *	@inode: inode of the device
+ *	@file: file handle to the device
+ *	@cmd: watchdog command
+ *	@arg: argument pointer
+ *
+ *	The watchdog API defines a common set of functions for all watchdogs
+ *	according to their available features. We only actually usefully support
+ *	querying capabilities and current status.
+ */
+
+static int mvme7100_wdt_ioctl(struct inode *inode, struct file *file, 
+		              unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	int __user *p = argp;
+	int new_heartbeat;
+	int options;
+
+	static struct watchdog_info ident = {
+		.options =		WDIOF_SETTIMEOUT |
+					WDIOF_MAGICCLOSE |
+					WDIOF_KEEPALIVEPING,
+		.firmware_version =	1,
+		.identity =		"MVME7100_WDT",
+	};
+
+	switch(cmd)
+	{
+		case WDIOC_GETSUPPORT:
+			return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0;
+
+		case WDIOC_GETSTATUS:
+		case WDIOC_GETBOOTSTATUS:
+			return put_user(0, p);
+		case WDIOC_KEEPALIVE:
+			mvme7100_wdt_keepalive();
+			return 0;
+		case WDIOC_SETTIMEOUT:
+			if (get_user(new_heartbeat, p))
+				return -EFAULT;
+
+			if (mvme7100_wdt_set_heartbeat(new_heartbeat))
+				return -EINVAL;
+
+			mvme7100_wdt_keepalive();
+			/* Fall */
+		case WDIOC_GETTIMEOUT:
+			return put_user(heartbeat, p);
+		case WDIOC_SETOPTIONS:
+			if (get_user(options, p))
+				return -EFAULT;
+			if (options & WDIOS_DISABLECARD) {
+				mvme7100_wdt_stop();
+				return 0;
+			}
+
+			if (options & WDIOS_ENABLECARD) {
+				mvme7100_wdt_start();
+				return 0;
+			}
+			break;
+		default:
+			return -ENOTTY;
+
+	}
+	return 0;
+}
+
+/*
+ *	mvme7100_wdt_open:
+ *	@inode: inode of device
+ *	@file: file handle to device
+ *
+ */
+
+static int mvme7100_wdt_open(struct inode *inode, struct file *file)
+{
+	if(test_and_set_bit(0, &mvme7100_wdt_is_open))
+		return -EBUSY;
+
+	/* Activate */
+	printk(KERN_INFO "mvme7100_wdt: Starting watchdog timer\n");
+	mvme7100_wdt_start();
+
+	return nonseekable_open(inode, file);
+}
+
+/*
+ *	mvme7100_wdt_release:
+ *	@inode: inode to board
+ *	@file: file handle to board
+ *
+ *	The watchdog has a configurable API. There is a religious dispute
+ *	between people who want their watchdog to be able to shut down and
+ *	those who want to be sure if the watchdog manager dies the machine
+ *	reboots. In the former case we disable the watchdog timer, in the 
+ *      latter case you have to open it again very soon.
+ */
+
+static int mvme7100_wdt_release(struct inode *inode, struct file *file)
+{
+	if (mvme7100_expect_close == 42) {
+		mvme7100_wdt_stop();
+	} else {
+		printk(KERN_CRIT "mvme7100_wdt:  watchdog device closed unexpectedly - watchdog will not stop!\n");
+		mvme7100_wdt_keepalive();
+	}
+	mvme7100_expect_close = 0;
+	clear_bit(0, &mvme7100_wdt_is_open);
+	return 0;
+}
+
+/**
+ *	notify_sys:
+ *	@this: our notifier block
+ *	@code: the event being reported
+ *	@unused: unused
+ *
+ *	Our notifier is called on system shutdowns. We want to turn the 
+ *      watchdog off at reboot.
+ */
+
+static int mvme7100_wdt_notify_sys(struct notifier_block *this, unsigned long code,
+	void *unused)
+{
+	if(code==SYS_DOWN || code==SYS_HALT) {
+		/* Turn the card off */
+		mvme7100_wdt_stop();
+	}
+	return NOTIFY_DONE;
+}
+
+/*
+ *	Kernel Interfaces
+ */
+
+
+static const struct file_operations mvme7100_wdt_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.write		= mvme7100_wdt_write,
+	.ioctl		= mvme7100_wdt_ioctl,
+	.open		= mvme7100_wdt_open,
+	.release	= mvme7100_wdt_release,
+};
+
+static struct miscdevice mvme7100_wdt_miscdev = {
+	.minor	= WATCHDOG_MINOR,
+	.name	= "watchdog",
+	.fops	= &mvme7100_wdt_fops,
+};
+
+/*
+ *	The watchdog timer needs to be stopped on reboots/shutdowns 
+ */
+
+static struct notifier_block mvme7100_wdt_notifier = {
+	.notifier_call = mvme7100_wdt_notify_sys,
+};
+
+/*
+ *	cleanup_module:
+ *
+ *	Unload the watchdog. You cannot do this with any file handles open.
+ *	If your watchdog is set to continue ticking on close and you unload
+ *	it, well it keeps ticking.  You just have to load a new
+ *	module in 60 seconds or reboot.
+ */
+
+static void __devexit mvme7100_wdt_exit(void)
+{
+	if (!nowayout) 
+		mvme7100_wdt_stop();
+	iounmap(mvme7100_wdt_regs);	
+	misc_deregister(&mvme7100_wdt_miscdev);
+	unregister_reboot_notifier(&mvme7100_wdt_notifier);
+}
+
+/*
+ * 	mvme7100_wdt_init:
+ *
+ *	Set up the MVME7100 watchdog. 
+ *	The open() function will actually kick the watchdog.
+ */
+
+static int __devinit mvme7100_wdt_init(void)
+{
+	int ret = 0;
+
+	/* Check that the heartbeat value is within it's range ; if not reset to the default */
+	if (mvme7100_wdt_set_heartbeat(heartbeat)) {
+		mvme7100_wdt_set_heartbeat(WD_TIM0);
+		printk(KERN_INFO "wdt: heartbeat value must be 0<heartbeat<3600 secs, using %d secs\n",
+			WD_TIM0);
+	}
+
+	mvme7100_wdt_regs = ioremap(MVME7100_WATCHDOG_TIMER_LOAD_REG, 8);
+	if (mvme7100_wdt_regs == NULL) {
+		printk(KERN_ERR "mvme7100_wdt: ioremap() failed\n");
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	writeb(WD_COUNTER_RES_65536_MICROSEC, mvme7100_wdt_regs + WD_RESOLUTION_REG_OFFSET);
+
+	init_timer(&mvme7100_wd_timer);
+	mvme7100_wd_timer.function = mvme7100_wdt_ping;
+	mvme7100_wd_timer.data = 0;
+
+	ret = register_reboot_notifier(&mvme7100_wdt_notifier);
+	if(ret) {
+		printk(KERN_ERR "mvme7100_wdt: cannot register reboot notifier (err=%d)\n", ret);
+		goto out;
+	}
+
+	ret = misc_register(&mvme7100_wdt_miscdev);
+	if (ret) {
+		printk(KERN_ERR "mvme7100_wdt: cannot register miscdev on minor=%d (err=%d)\n",
+			WATCHDOG_MINOR, ret);
+		goto outmisc;
+	}
+
+	printk(KERN_INFO "mvme7100 watchdog driver ver 1.0: (heartbeat=%d sec, nowayout=%d)\n",
+		heartbeat, nowayout);
+out:
+	return ret;
+
+outmisc:
+	unregister_reboot_notifier(&mvme7100_wdt_notifier);
+	goto out;
+}
+
+module_init(mvme7100_wdt_init);
+module_exit(mvme7100_wdt_exit);
+
+MODULE_AUTHOR("Ajit Prem");
+MODULE_DESCRIPTION("Watchdog Driver for the MVME7100 watchdog");
+MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/Kconfig linux-2.6.29.6.mod/fs/Kconfig
--- linux-2.6.29.6.orig/fs/Kconfig	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/fs/Kconfig	2009-07-21 11:28:18.000000000 -0700
@@ -210,6 +210,7 @@
 source "fs/bfs/Kconfig"
 source "fs/efs/Kconfig"
 source "fs/jffs2/Kconfig"
+source "fs/yaffs2/Kconfig"
 # UBIFS File system configuration
 source "fs/ubifs/Kconfig"
 source "fs/cramfs/Kconfig"
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/Makefile linux-2.6.29.6.mod/fs/Makefile
--- linux-2.6.29.6.orig/fs/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/fs/Makefile	2009-07-21 11:28:18.000000000 -0700
@@ -124,3 +124,4 @@
 obj-$(CONFIG_OCFS2_FS)		+= ocfs2/
 obj-$(CONFIG_BTRFS_FS)		+= btrfs/
 obj-$(CONFIG_GFS2_FS)           += gfs2/
+obj-$(CONFIG_YAFFS_FS)          += yaffs2/
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/devextras.h linux-2.6.29.6.mod/fs/yaffs2/devextras.h
--- linux-2.6.29.6.orig/fs/yaffs2/devextras.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/devextras.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,196 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * This file is just holds extra declarations of macros that would normally
+ * be providesd in the Linux kernel. These macros have been written from
+ * scratch but are functionally equivalent to the Linux ones.
+ *
+ */
+
+#ifndef __EXTRAS_H__
+#define __EXTRAS_H__
+
+
+#if !(defined __KERNEL__)
+
+/* Definition of types */
+typedef unsigned char __u8;
+typedef unsigned short __u16;
+typedef unsigned __u32;
+
+#endif
+
+/*
+ * This is a simple doubly linked list implementation that matches the
+ * way the Linux kernel doubly linked list implementation works.
+ */
+
+struct ylist_head {
+	struct ylist_head *next; /* next in chain */
+	struct ylist_head *prev; /* previous in chain */
+};
+
+
+/* Initialise a static list */
+#define YLIST_HEAD(name) \
+struct ylist_head name = { &(name), &(name)}
+
+
+
+/* Initialise a list head to an empty list */
+#define YINIT_LIST_HEAD(p) \
+do { \
+	(p)->next = (p);\
+	(p)->prev = (p); \
+} while (0)
+
+
+/* Add an element to a list */
+static __inline__ void ylist_add(struct ylist_head *newEntry,
+				struct ylist_head *list)
+{
+	struct ylist_head *listNext = list->next;
+
+	list->next = newEntry;
+	newEntry->prev = list;
+	newEntry->next = listNext;
+	listNext->prev = newEntry;
+
+}
+
+static __inline__ void ylist_add_tail(struct ylist_head *newEntry,
+				 struct ylist_head *list)
+{
+	struct ylist_head *listPrev = list->prev;
+
+	list->prev = newEntry;
+	newEntry->next = list;
+	newEntry->prev = listPrev;
+	listPrev->next = newEntry;
+
+}
+
+
+/* Take an element out of its current list, with or without
+ * reinitialising the links.of the entry*/
+static __inline__ void ylist_del(struct ylist_head *entry)
+{
+	struct ylist_head *listNext = entry->next;
+	struct ylist_head *listPrev = entry->prev;
+
+	listNext->prev = listPrev;
+	listPrev->next = listNext;
+
+}
+
+static __inline__ void ylist_del_init(struct ylist_head *entry)
+{
+	ylist_del(entry);
+	entry->next = entry->prev = entry;
+}
+
+
+/* Test if the list is empty */
+static __inline__ int ylist_empty(struct ylist_head *entry)
+{
+	return (entry->next == entry);
+}
+
+
+/* ylist_entry takes a pointer to a list entry and offsets it to that
+ * we can find a pointer to the object it is embedded in.
+ */
+
+
+#define ylist_entry(entry, type, member) \
+	((type *)((char *)(entry)-(unsigned long)(&((type *)NULL)->member)))
+
+
+/* ylist_for_each and list_for_each_safe  iterate over lists.
+ * ylist_for_each_safe uses temporary storage to make the list delete safe
+ */
+
+#define ylist_for_each(itervar, list) \
+	for (itervar = (list)->next; itervar != (list); itervar = itervar->next)
+
+#define ylist_for_each_safe(itervar, saveVar, list) \
+	for (itervar = (list)->next, saveVar = (list)->next->next; \
+		itervar != (list); itervar = saveVar, saveVar = saveVar->next)
+
+
+#if !(defined __KERNEL__)
+
+
+#ifndef WIN32
+#include <sys/stat.h>
+#endif
+
+
+#ifdef CONFIG_YAFFS_PROVIDE_DEFS
+/* File types */
+
+
+#define DT_UNKNOWN	0
+#define DT_FIFO		1
+#define DT_CHR		2
+#define DT_DIR		4
+#define DT_BLK		6
+#define DT_REG		8
+#define DT_LNK		10
+#define DT_SOCK		12
+#define DT_WHT		14
+
+
+#ifndef WIN32
+#include <sys/stat.h>
+#endif
+
+/*
+ * Attribute flags.  These should be or-ed together to figure out what
+ * has been changed!
+ */
+#define ATTR_MODE	1
+#define ATTR_UID	2
+#define ATTR_GID	4
+#define ATTR_SIZE	8
+#define ATTR_ATIME	16
+#define ATTR_MTIME	32
+#define ATTR_CTIME	64
+
+struct iattr {
+	unsigned int ia_valid;
+	unsigned ia_mode;
+	unsigned ia_uid;
+	unsigned ia_gid;
+	unsigned ia_size;
+	unsigned ia_atime;
+	unsigned ia_mtime;
+	unsigned ia_ctime;
+	unsigned int ia_attr_flags;
+};
+
+#endif
+
+#else
+
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+
+#endif
+
+
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/Kconfig linux-2.6.29.6.mod/fs/yaffs2/Kconfig
--- linux-2.6.29.6.orig/fs/yaffs2/Kconfig	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/Kconfig	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,156 @@
+#
+# YAFFS file system configurations
+#
+
+config YAFFS_FS
+	tristate "YAFFS2 file system support"
+	default n
+	depends on MTD_BLOCK
+	select YAFFS_YAFFS1
+	select YAFFS_YAFFS2
+	help
+	  YAFFS2, or Yet Another Flash Filing System, is a filing system
+	  optimised for NAND Flash chips.
+
+	  To compile the YAFFS2 file system support as a module, choose M
+	  here: the module will be called yaffs2.
+
+	  If unsure, say N.
+
+	  Further information on YAFFS2 is available at
+	  <http://www.aleph1.co.uk/yaffs/>.
+
+config YAFFS_YAFFS1
+	bool "512 byte / page devices"
+	depends on YAFFS_FS
+	default y
+	help
+	  Enable YAFFS1 support -- yaffs for 512 byte / page devices
+
+	  Not needed for 2K-page devices.
+
+	  If unsure, say Y.
+
+config YAFFS_9BYTE_TAGS
+	bool "Use older-style on-NAND data format with pageStatus byte"
+	depends on YAFFS_YAFFS1
+	default n
+	help
+
+	  Older-style on-NAND data format has a "pageStatus" byte to record
+	  chunk/page state.  This byte is zero when the page is discarded.
+	  Choose this option if you have existing on-NAND data using this
+	  format that you need to continue to support.  New data written
+	  also uses the older-style format.  Note: Use of this option
+	  generally requires that MTD's oob layout be adjusted to use the
+	  older-style format.  See notes on tags formats and MTD versions
+	  in yaffs_mtdif1.c.
+
+	  If unsure, say N.
+
+config YAFFS_DOES_ECC
+	bool "Lets Yaffs do its own ECC"
+	depends on YAFFS_FS && YAFFS_YAFFS1 && !YAFFS_9BYTE_TAGS
+	default n
+	help
+	  This enables Yaffs to use its own ECC functions instead of using
+	  the ones from the generic MTD-NAND driver.
+
+	  If unsure, say N.
+
+config YAFFS_ECC_WRONG_ORDER
+	bool "Use the same ecc byte order as Steven Hill's nand_ecc.c"
+	depends on YAFFS_FS && YAFFS_DOES_ECC && !YAFFS_9BYTE_TAGS
+	default n
+	help
+	  This makes yaffs_ecc.c use the same ecc byte order as Steven
+	  Hill's nand_ecc.c. If not set, then you get the same ecc byte
+	  order as SmartMedia.
+
+	  If unsure, say N.
+
+config YAFFS_YAFFS2
+	bool "2048 byte (or larger) / page devices"
+	depends on YAFFS_FS
+	default y
+	help
+	  Enable YAFFS2 support -- yaffs for >= 2K bytes per page devices
+
+	  If unsure, say Y.
+
+config YAFFS_AUTO_YAFFS2
+	bool "Autoselect yaffs2 format"
+	depends on YAFFS_YAFFS2
+	default y
+	help
+	  Without this, you need to explicitely use yaffs2 as the file
+	  system type. With this, you can say "yaffs" and yaffs or yaffs2
+	  will be used depending on the device page size (yaffs on
+	  512-byte page devices, yaffs2 on 2K page devices).
+
+	  If unsure, say Y.
+
+config YAFFS_DISABLE_LAZY_LOAD
+	bool "Disable lazy loading"
+	depends on YAFFS_YAFFS2
+	default n
+	help
+	  "Lazy loading" defers loading file details until they are
+	  required. This saves mount time, but makes the first look-up
+	  a bit longer.
+
+	  Lazy loading will only happen if enabled by this option being 'n'
+	  and if the appropriate tags are available, else yaffs2 will
+	  automatically fall back to immediate loading and do the right
+	  thing.
+
+	  Lazy laoding will be required by checkpointing.
+
+	  Setting this to 'y' will disable lazy loading.
+
+	  If unsure, say N.
+
+
+config YAFFS_DISABLE_WIDE_TNODES
+	bool "Turn off wide tnodes"
+	depends on YAFFS_FS
+	default n
+	help
+	  Wide tnodes are only used for NAND arrays >=32MB for 512-byte
+	  page devices and >=128MB for 2k page devices. They use slightly
+	  more RAM but are faster since they eliminate chunk group
+	  searching.
+
+	  Setting this to 'y' will force tnode width to 16 bits and save
+	  memory but make large arrays slower.
+
+	  If unsure, say N.
+
+config YAFFS_ALWAYS_CHECK_CHUNK_ERASED
+	bool "Force chunk erase check"
+	depends on YAFFS_FS
+	default n
+	help
+          Normally YAFFS only checks chunks before writing until an erased
+	  chunk is found. This helps to detect any partially written
+	  chunks that might have happened due to power loss.
+
+	  Enabling this forces on the test that chunks are erased in flash
+	  before writing to them. This takes more time but is potentially
+	  a bit more secure.
+
+	  Suggest setting Y during development and ironing out driver
+	  issues etc. Suggest setting to N if you want faster writing.
+
+	  If unsure, say Y.
+
+config YAFFS_SHORT_NAMES_IN_RAM
+	bool "Cache short names in RAM"
+	depends on YAFFS_FS
+	default y
+	help
+	  If this config is set, then short names are stored with the
+	  yaffs_Object.  This costs an extra 16 bytes of RAM per object,
+	  but makes look-ups faster.
+
+	  If unsure, say Y.
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/Makefile linux-2.6.29.6.mod/fs/yaffs2/Makefile
--- linux-2.6.29.6.orig/fs/yaffs2/Makefile	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/Makefile	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,12 @@
+#
+# Makefile for the linux YAFFS filesystem routines.
+#
+
+obj-$(CONFIG_YAFFS_FS) += yaffs.o
+
+yaffs-y := yaffs_mtdif.o yaffs_mtdif2.o
+yaffs-y += yaffs_mtdif1.o yaffs_packedtags1.o
+yaffs-y += yaffs_ecc.o yaffs_fs.o yaffs_guts.o
+yaffs-y += yaffs_packedtags2.o yaffs_qsort.o
+yaffs-y += yaffs_tagscompat.o yaffs_tagsvalidity.o
+yaffs-y += yaffs_checkptrw.o yaffs_nand.o
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/moduleconfig.h linux-2.6.29.6.mod/fs/yaffs2/moduleconfig.h
--- linux-2.6.29.6.orig/fs/yaffs2/moduleconfig.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/moduleconfig.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,65 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Martin Fouts <Martin.Fouts@palmsource.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_CONFIG_H__
+#define __YAFFS_CONFIG_H__
+
+#ifdef YAFFS_OUT_OF_TREE
+
+/* DO NOT UNSET THESE THREE. YAFFS2 will not compile if you do. */
+#define CONFIG_YAFFS_FS
+#define CONFIG_YAFFS_YAFFS1
+#define CONFIG_YAFFS_YAFFS2
+
+/* These options are independent of each other.  Select those that matter. */
+
+/* Default: Not selected */
+/* Meaning: Yaffs does its own ECC, rather than using MTD ECC */
+/* #define CONFIG_YAFFS_DOES_ECC */
+
+/* Default: Not selected */
+/* Meaning: ECC byte order is 'wrong'.  Only meaningful if */
+/*          CONFIG_YAFFS_DOES_ECC is set */
+/* #define CONFIG_YAFFS_ECC_WRONG_ORDER */
+
+/* Default: Selected */
+/* Meaning: Disables testing whether chunks are erased before writing to them*/
+#define CONFIG_YAFFS_DISABLE_CHUNK_ERASED_CHECK
+
+/* Default: Selected */
+/* Meaning: Cache short names, taking more RAM, but faster look-ups */
+#define CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+
+/* Default: 10 */
+/* Meaning: set the count of blocks to reserve for checkpointing */
+#define CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS 10
+
+/*
+Older-style on-NAND data format has a "pageStatus" byte to record
+chunk/page state.  This byte is zeroed when the page is discarded.
+Choose this option if you have existing on-NAND data in this format
+that you need to continue to support.  New data written also uses the
+older-style format.
+Note: Use of this option generally requires that MTD's oob layout be
+adjusted to use the older-style format.  See notes on tags formats and
+MTD versions in yaffs_mtdif1.c.
+*/
+/* Default: Not selected */
+/* Meaning: Use older-style on-NAND data format with pageStatus byte */
+/* #define CONFIG_YAFFS_9BYTE_TAGS */
+
+#endif /* YAFFS_OUT_OF_TREE */
+
+#endif /* __YAFFS_CONFIG_H__ */
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_checkptrw.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_checkptrw.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_checkptrw.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_checkptrw.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,397 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+const char *yaffs_checkptrw_c_version =
+	"$Id: yaffs_checkptrw.c,v 1.19 2009-06-19 01:35:46 charles Exp $";
+
+
+#include "yaffs_checkptrw.h"
+#include "yaffs_getblockinfo.h"
+
+static int yaffs_CheckpointSpaceOk(yaffs_Device *dev)
+{
+	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
+
+	T(YAFFS_TRACE_CHECKPOINT,
+		(TSTR("checkpt blocks available = %d" TENDSTR),
+		blocksAvailable));
+
+	return (blocksAvailable <= 0) ? 0 : 1;
+}
+
+
+static int yaffs_CheckpointErase(yaffs_Device *dev)
+{
+	int i;
+
+	if (!dev->eraseBlockInNAND)
+		return 0;
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checking blocks %d to %d"TENDSTR),
+		dev->internalStartBlock, dev->internalEndBlock));
+
+	for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
+		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
+		if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
+			T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
+			if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
+				bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
+				dev->nErasedBlocks++;
+				dev->nFreeChunks += dev->nChunksPerBlock;
+			} else {
+				dev->markNANDBlockBad(dev, i);
+				bi->blockState = YAFFS_BLOCK_STATE_DEAD;
+			}
+		}
+	}
+
+	dev->blocksInCheckpoint = 0;
+
+	return 1;
+}
+
+
+static void yaffs_CheckpointFindNextErasedBlock(yaffs_Device *dev)
+{
+	int  i;
+	int blocksAvailable = dev->nErasedBlocks - dev->nReservedBlocks;
+	T(YAFFS_TRACE_CHECKPOINT,
+		(TSTR("allocating checkpt block: erased %d reserved %d avail %d next %d "TENDSTR),
+		dev->nErasedBlocks, dev->nReservedBlocks, blocksAvailable, dev->checkpointNextBlock));
+
+	if (dev->checkpointNextBlock >= 0 &&
+			dev->checkpointNextBlock <= dev->internalEndBlock &&
+			blocksAvailable > 0) {
+
+		for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
+			yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
+			if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
+				dev->checkpointNextBlock = i + 1;
+				dev->checkpointCurrentBlock = i;
+				T(YAFFS_TRACE_CHECKPOINT, (TSTR("allocating checkpt block %d"TENDSTR), i));
+				return;
+			}
+		}
+	}
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("out of checkpt blocks"TENDSTR)));
+
+	dev->checkpointNextBlock = -1;
+	dev->checkpointCurrentBlock = -1;
+}
+
+static void yaffs_CheckpointFindNextCheckpointBlock(yaffs_Device *dev)
+{
+	int  i;
+	yaffs_ExtendedTags tags;
+
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: start:  blocks %d next %d" TENDSTR),
+		dev->blocksInCheckpoint, dev->checkpointNextBlock));
+
+	if (dev->blocksInCheckpoint < dev->checkpointMaxBlocks)
+		for (i = dev->checkpointNextBlock; i <= dev->internalEndBlock; i++) {
+			int chunk = i * dev->nChunksPerBlock;
+			int realignedChunk = chunk - dev->chunkOffset;
+
+			dev->readChunkWithTagsFromNAND(dev, realignedChunk,
+					NULL, &tags);
+			T(YAFFS_TRACE_CHECKPOINT, (TSTR("find next checkpt block: search: block %d oid %d seq %d eccr %d" TENDSTR),
+				i, tags.objectId, tags.sequenceNumber, tags.eccResult));
+
+			if (tags.sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA) {
+				/* Right kind of block */
+				dev->checkpointNextBlock = tags.objectId;
+				dev->checkpointCurrentBlock = i;
+				dev->checkpointBlockList[dev->blocksInCheckpoint] = i;
+				dev->blocksInCheckpoint++;
+				T(YAFFS_TRACE_CHECKPOINT, (TSTR("found checkpt block %d"TENDSTR), i));
+				return;
+			}
+		}
+
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("found no more checkpt blocks"TENDSTR)));
+
+	dev->checkpointNextBlock = -1;
+	dev->checkpointCurrentBlock = -1;
+}
+
+
+int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
+{
+
+	/* Got the functions we need? */
+	if (!dev->writeChunkWithTagsToNAND ||
+			!dev->readChunkWithTagsFromNAND ||
+			!dev->eraseBlockInNAND ||
+			!dev->markNANDBlockBad)
+		return 0;
+
+	if (forWriting && !yaffs_CheckpointSpaceOk(dev))
+		return 0;
+
+	if (!dev->checkpointBuffer)
+		dev->checkpointBuffer = YMALLOC_DMA(dev->totalBytesPerChunk);
+	if (!dev->checkpointBuffer)
+		return 0;
+
+
+	dev->checkpointPageSequence = 0;
+
+	dev->checkpointOpenForWrite = forWriting;
+
+	dev->checkpointByteCount = 0;
+	dev->checkpointSum = 0;
+	dev->checkpointXor = 0;
+	dev->checkpointCurrentBlock = -1;
+	dev->checkpointCurrentChunk = -1;
+	dev->checkpointNextBlock = dev->internalStartBlock;
+
+	/* Erase all the blocks in the checkpoint area */
+	if (forWriting) {
+		memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
+		dev->checkpointByteOffset = 0;
+		return yaffs_CheckpointErase(dev);
+	} else {
+		int i;
+		/* Set to a value that will kick off a read */
+		dev->checkpointByteOffset = dev->nDataBytesPerChunk;
+		/* A checkpoint block list of 1 checkpoint block per 16 block is (hopefully)
+		 * going to be way more than we need */
+		dev->blocksInCheckpoint = 0;
+		dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
+		dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
+		if(!dev->checkpointBlockList)
+			return 0;
+
+		for (i = 0; i < dev->checkpointMaxBlocks; i++)
+			dev->checkpointBlockList[i] = -1;
+	}
+
+	return 1;
+}
+
+int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum)
+{
+	__u32 compositeSum;
+	compositeSum =  (dev->checkpointSum << 8) | (dev->checkpointXor & 0xFF);
+	*sum = compositeSum;
+	return 1;
+}
+
+static int yaffs_CheckpointFlushBuffer(yaffs_Device *dev)
+{
+	int chunk;
+	int realignedChunk;
+
+	yaffs_ExtendedTags tags;
+
+	if (dev->checkpointCurrentBlock < 0) {
+		yaffs_CheckpointFindNextErasedBlock(dev);
+		dev->checkpointCurrentChunk = 0;
+	}
+
+	if (dev->checkpointCurrentBlock < 0)
+		return 0;
+
+	tags.chunkDeleted = 0;
+	tags.objectId = dev->checkpointNextBlock; /* Hint to next place to look */
+	tags.chunkId = dev->checkpointPageSequence + 1;
+	tags.sequenceNumber =  YAFFS_SEQUENCE_CHECKPOINT_DATA;
+	tags.byteCount = dev->nDataBytesPerChunk;
+	if (dev->checkpointCurrentChunk == 0) {
+		/* First chunk we write for the block? Set block state to
+		   checkpoint */
+		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointCurrentBlock);
+		bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
+		dev->blocksInCheckpoint++;
+	}
+
+	chunk = dev->checkpointCurrentBlock * dev->nChunksPerBlock + dev->checkpointCurrentChunk;
+
+
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint wite buffer nand %d(%d:%d) objid %d chId %d" TENDSTR),
+		chunk, dev->checkpointCurrentBlock, dev->checkpointCurrentChunk, tags.objectId, tags.chunkId));
+
+	realignedChunk = chunk - dev->chunkOffset;
+
+	dev->writeChunkWithTagsToNAND(dev, realignedChunk,
+			dev->checkpointBuffer, &tags);
+	dev->checkpointByteOffset = 0;
+	dev->checkpointPageSequence++;
+	dev->checkpointCurrentChunk++;
+	if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock) {
+		dev->checkpointCurrentChunk = 0;
+		dev->checkpointCurrentBlock = -1;
+	}
+	memset(dev->checkpointBuffer, 0, dev->nDataBytesPerChunk);
+
+	return 1;
+}
+
+
+int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes)
+{
+	int i = 0;
+	int ok = 1;
+
+
+	__u8 * dataBytes = (__u8 *)data;
+
+
+
+	if (!dev->checkpointBuffer)
+		return 0;
+
+	if (!dev->checkpointOpenForWrite)
+		return -1;
+
+	while (i < nBytes && ok) {
+		dev->checkpointBuffer[dev->checkpointByteOffset] = *dataBytes;
+		dev->checkpointSum += *dataBytes;
+		dev->checkpointXor ^= *dataBytes;
+
+		dev->checkpointByteOffset++;
+		i++;
+		dataBytes++;
+		dev->checkpointByteCount++;
+
+
+		if (dev->checkpointByteOffset < 0 ||
+		   dev->checkpointByteOffset >= dev->nDataBytesPerChunk)
+			ok = yaffs_CheckpointFlushBuffer(dev);
+	}
+
+	return i;
+}
+
+int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes)
+{
+	int i = 0;
+	int ok = 1;
+	yaffs_ExtendedTags tags;
+
+
+	int chunk;
+	int realignedChunk;
+
+	__u8 *dataBytes = (__u8 *)data;
+
+	if (!dev->checkpointBuffer)
+		return 0;
+
+	if (dev->checkpointOpenForWrite)
+		return -1;
+
+	while (i < nBytes && ok) {
+
+
+		if (dev->checkpointByteOffset < 0 ||
+			dev->checkpointByteOffset >= dev->nDataBytesPerChunk) {
+
+			if (dev->checkpointCurrentBlock < 0) {
+				yaffs_CheckpointFindNextCheckpointBlock(dev);
+				dev->checkpointCurrentChunk = 0;
+			}
+
+			if (dev->checkpointCurrentBlock < 0)
+				ok = 0;
+			else {
+				chunk = dev->checkpointCurrentBlock *
+					dev->nChunksPerBlock +
+					dev->checkpointCurrentChunk;
+
+				realignedChunk = chunk - dev->chunkOffset;
+
+				/* read in the next chunk */
+				/* printf("read checkpoint page %d\n",dev->checkpointPage); */
+				dev->readChunkWithTagsFromNAND(dev,
+						realignedChunk,
+						dev->checkpointBuffer,
+						&tags);
+
+				if (tags.chunkId != (dev->checkpointPageSequence + 1) ||
+					tags.eccResult > YAFFS_ECC_RESULT_FIXED ||
+					tags.sequenceNumber != YAFFS_SEQUENCE_CHECKPOINT_DATA)
+					ok = 0;
+
+				dev->checkpointByteOffset = 0;
+				dev->checkpointPageSequence++;
+				dev->checkpointCurrentChunk++;
+
+				if (dev->checkpointCurrentChunk >= dev->nChunksPerBlock)
+					dev->checkpointCurrentBlock = -1;
+			}
+		}
+
+		if (ok) {
+			*dataBytes = dev->checkpointBuffer[dev->checkpointByteOffset];
+			dev->checkpointSum += *dataBytes;
+			dev->checkpointXor ^= *dataBytes;
+			dev->checkpointByteOffset++;
+			i++;
+			dataBytes++;
+			dev->checkpointByteCount++;
+		}
+	}
+
+	return 	i;
+}
+
+int yaffs_CheckpointClose(yaffs_Device *dev)
+{
+
+	if (dev->checkpointOpenForWrite) {
+		if (dev->checkpointByteOffset != 0)
+			yaffs_CheckpointFlushBuffer(dev);
+	} else {
+		int i;
+		for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
+			yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
+			if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
+				bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
+			else {
+				/* Todo this looks odd... */
+			}
+		}
+		YFREE(dev->checkpointBlockList);
+		dev->checkpointBlockList = NULL;
+	}
+
+	dev->nFreeChunks -= dev->blocksInCheckpoint * dev->nChunksPerBlock;
+	dev->nErasedBlocks -= dev->blocksInCheckpoint;
+
+
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint byte count %d" TENDSTR),
+			dev->checkpointByteCount));
+
+	if (dev->checkpointBuffer) {
+		/* free the buffer */
+		YFREE(dev->checkpointBuffer);
+		dev->checkpointBuffer = NULL;
+		return 1;
+	} else
+		return 0;
+}
+
+int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
+{
+	/* Erase the first checksum block */
+
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
+
+	if (!yaffs_CheckpointSpaceOk(dev))
+		return 0;
+
+	return yaffs_CheckpointErase(dev);
+}
+
+
+
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_checkptrw.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_checkptrw.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_checkptrw.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_checkptrw.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,35 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_CHECKPTRW_H__
+#define __YAFFS_CHECKPTRW_H__
+
+#include "yaffs_guts.h"
+
+int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting);
+
+int yaffs_CheckpointWrite(yaffs_Device *dev, const void *data, int nBytes);
+
+int yaffs_CheckpointRead(yaffs_Device *dev, void *data, int nBytes);
+
+int yaffs_GetCheckpointSum(yaffs_Device *dev, __u32 *sum);
+
+int yaffs_CheckpointClose(yaffs_Device *dev);
+
+int yaffs_CheckpointInvalidateStream(yaffs_Device *dev);
+
+
+#endif
+
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_ecc.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_ecc.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_ecc.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_ecc.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,326 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 code implements the ECC algorithm used in SmartMedia.
+ *
+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
+ * The two unused bit are set to 1.
+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
+ * blocks are used on a 512-byte NAND page.
+ *
+ */
+
+/* Table generated by gen-ecc.c
+ * Using a table means we do not have to calculate p1..p4 and p1'..p4'
+ * for each byte of data. These are instead provided in a table in bits7..2.
+ * Bit 0 of each entry indicates whether the entry has an odd or even parity, and therefore
+ * this bytes influence on the line parity.
+ */
+
+const char *yaffs_ecc_c_version =
+	"$Id: yaffs_ecc.c,v 1.11 2009-03-06 17:20:50 wookey Exp $";
+
+#include "yportenv.h"
+
+#include "yaffs_ecc.h"
+
+static const unsigned char column_parity_table[] = {
+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+	0xa9, 0xfc, 0xf0, 0xa5, 0xcc, 0x99, 0x95, 0xc0,
+	0xc0, 0x95, 0x99, 0xcc, 0xa5, 0xf0, 0xfc, 0xa9,
+	0x3c, 0x69, 0x65, 0x30, 0x59, 0x0c, 0x00, 0x55,
+	0x55, 0x00, 0x0c, 0x59, 0x30, 0x65, 0x69, 0x3c,
+	0x30, 0x65, 0x69, 0x3c, 0x55, 0x00, 0x0c, 0x59,
+	0x59, 0x0c, 0x00, 0x55, 0x3c, 0x69, 0x65, 0x30,
+	0xa5, 0xf0, 0xfc, 0xa9, 0xc0, 0x95, 0x99, 0xcc,
+	0xcc, 0x99, 0x95, 0xc0, 0xa9, 0xfc, 0xf0, 0xa5,
+	0x0c, 0x59, 0x55, 0x00, 0x69, 0x3c, 0x30, 0x65,
+	0x65, 0x30, 0x3c, 0x69, 0x00, 0x55, 0x59, 0x0c,
+	0x99, 0xcc, 0xc0, 0x95, 0xfc, 0xa9, 0xa5, 0xf0,
+	0xf0, 0xa5, 0xa9, 0xfc, 0x95, 0xc0, 0xcc, 0x99,
+	0x95, 0xc0, 0xcc, 0x99, 0xf0, 0xa5, 0xa9, 0xfc,
+	0xfc, 0xa9, 0xa5, 0xf0, 0x99, 0xcc, 0xc0, 0x95,
+	0x00, 0x55, 0x59, 0x0c, 0x65, 0x30, 0x3c, 0x69,
+	0x69, 0x3c, 0x30, 0x65, 0x0c, 0x59, 0x55, 0x00,
+};
+
+/* Count the bits in an unsigned char or a U32 */
+
+static int yaffs_CountBits(unsigned char x)
+{
+	int r = 0;
+	while (x) {
+		if (x & 1)
+			r++;
+		x >>= 1;
+	}
+	return r;
+}
+
+static int yaffs_CountBits32(unsigned x)
+{
+	int r = 0;
+	while (x) {
+		if (x & 1)
+			r++;
+		x >>= 1;
+	}
+	return r;
+}
+
+/* Calculate the ECC for a 256-byte block of data */
+void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc)
+{
+	unsigned int i;
+
+	unsigned char col_parity = 0;
+	unsigned char line_parity = 0;
+	unsigned char line_parity_prime = 0;
+	unsigned char t;
+	unsigned char b;
+
+	for (i = 0; i < 256; i++) {
+		b = column_parity_table[*data++];
+		col_parity ^= b;
+
+		if (b & 0x01) {		/* odd number of bits in the byte */
+			line_parity ^= i;
+			line_parity_prime ^= ~i;
+		}
+	}
+
+	ecc[2] = (~col_parity) | 0x03;
+
+	t = 0;
+	if (line_parity & 0x80)
+		t |= 0x80;
+	if (line_parity_prime & 0x80)
+		t |= 0x40;
+	if (line_parity & 0x40)
+		t |= 0x20;
+	if (line_parity_prime & 0x40)
+		t |= 0x10;
+	if (line_parity & 0x20)
+		t |= 0x08;
+	if (line_parity_prime & 0x20)
+		t |= 0x04;
+	if (line_parity & 0x10)
+		t |= 0x02;
+	if (line_parity_prime & 0x10)
+		t |= 0x01;
+	ecc[1] = ~t;
+
+	t = 0;
+	if (line_parity & 0x08)
+		t |= 0x80;
+	if (line_parity_prime & 0x08)
+		t |= 0x40;
+	if (line_parity & 0x04)
+		t |= 0x20;
+	if (line_parity_prime & 0x04)
+		t |= 0x10;
+	if (line_parity & 0x02)
+		t |= 0x08;
+	if (line_parity_prime & 0x02)
+		t |= 0x04;
+	if (line_parity & 0x01)
+		t |= 0x02;
+	if (line_parity_prime & 0x01)
+		t |= 0x01;
+	ecc[0] = ~t;
+
+#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
+	/* Swap the bytes into the wrong order */
+	t = ecc[0];
+	ecc[0] = ecc[1];
+	ecc[1] = t;
+#endif
+}
+
+
+/* Correct the ECC on a 256 byte block of data */
+
+int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
+		     const unsigned char *test_ecc)
+{
+	unsigned char d0, d1, d2;	/* deltas */
+
+	d0 = read_ecc[0] ^ test_ecc[0];
+	d1 = read_ecc[1] ^ test_ecc[1];
+	d2 = read_ecc[2] ^ test_ecc[2];
+
+	if ((d0 | d1 | d2) == 0)
+		return 0; /* no error */
+
+	if (((d0 ^ (d0 >> 1)) & 0x55) == 0x55 &&
+	    ((d1 ^ (d1 >> 1)) & 0x55) == 0x55 &&
+	    ((d2 ^ (d2 >> 1)) & 0x54) == 0x54) {
+		/* Single bit (recoverable) error in data */
+
+		unsigned byte;
+		unsigned bit;
+
+#ifdef CONFIG_YAFFS_ECC_WRONG_ORDER
+		/* swap the bytes to correct for the wrong order */
+		unsigned char t;
+
+		t = d0;
+		d0 = d1;
+		d1 = t;
+#endif
+
+		bit = byte = 0;
+
+		if (d1 & 0x80)
+			byte |= 0x80;
+		if (d1 & 0x20)
+			byte |= 0x40;
+		if (d1 & 0x08)
+			byte |= 0x20;
+		if (d1 & 0x02)
+			byte |= 0x10;
+		if (d0 & 0x80)
+			byte |= 0x08;
+		if (d0 & 0x20)
+			byte |= 0x04;
+		if (d0 & 0x08)
+			byte |= 0x02;
+		if (d0 & 0x02)
+			byte |= 0x01;
+
+		if (d2 & 0x80)
+			bit |= 0x04;
+		if (d2 & 0x20)
+			bit |= 0x02;
+		if (d2 & 0x08)
+			bit |= 0x01;
+
+		data[byte] ^= (1 << bit);
+
+		return 1; /* Corrected the error */
+	}
+
+	if ((yaffs_CountBits(d0) +
+	     yaffs_CountBits(d1) +
+	     yaffs_CountBits(d2)) ==  1) {
+		/* Reccoverable error in ecc */
+
+		read_ecc[0] = test_ecc[0];
+		read_ecc[1] = test_ecc[1];
+		read_ecc[2] = test_ecc[2];
+
+		return 1; /* Corrected the error */
+	}
+
+	/* Unrecoverable error */
+
+	return -1;
+
+}
+
+
+/*
+ * ECCxxxOther does ECC calcs on arbitrary n bytes of data
+ */
+void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
+				yaffs_ECCOther *eccOther)
+{
+	unsigned int i;
+
+	unsigned char col_parity = 0;
+	unsigned line_parity = 0;
+	unsigned line_parity_prime = 0;
+	unsigned char b;
+
+	for (i = 0; i < nBytes; i++) {
+		b = column_parity_table[*data++];
+		col_parity ^= b;
+
+		if (b & 0x01)	 {
+			/* odd number of bits in the byte */
+			line_parity ^= i;
+			line_parity_prime ^= ~i;
+		}
+
+	}
+
+	eccOther->colParity = (col_parity >> 2) & 0x3f;
+	eccOther->lineParity = line_parity;
+	eccOther->lineParityPrime = line_parity_prime;
+}
+
+int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
+			yaffs_ECCOther *read_ecc,
+			const yaffs_ECCOther *test_ecc)
+{
+	unsigned char cDelta;	/* column parity delta */
+	unsigned lDelta;	/* line parity delta */
+	unsigned lDeltaPrime;	/* line parity delta */
+	unsigned bit;
+
+	cDelta = read_ecc->colParity ^ test_ecc->colParity;
+	lDelta = read_ecc->lineParity ^ test_ecc->lineParity;
+	lDeltaPrime = read_ecc->lineParityPrime ^ test_ecc->lineParityPrime;
+
+	if ((cDelta | lDelta | lDeltaPrime) == 0)
+		return 0; /* no error */
+
+	if (lDelta == ~lDeltaPrime &&
+	    (((cDelta ^ (cDelta >> 1)) & 0x15) == 0x15)) {
+		/* Single bit (recoverable) error in data */
+
+		bit = 0;
+
+		if (cDelta & 0x20)
+			bit |= 0x04;
+		if (cDelta & 0x08)
+			bit |= 0x02;
+		if (cDelta & 0x02)
+			bit |= 0x01;
+
+		if (lDelta >= nBytes)
+			return -1;
+
+		data[lDelta] ^= (1 << bit);
+
+		return 1; /* corrected */
+	}
+
+	if ((yaffs_CountBits32(lDelta) + yaffs_CountBits32(lDeltaPrime) +
+			yaffs_CountBits(cDelta)) == 1) {
+		/* Reccoverable error in ecc */
+
+		*read_ecc = *test_ecc;
+		return 1; /* corrected */
+	}
+
+	/* Unrecoverable error */
+
+	return -1;
+}
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_ecc.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_ecc.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_ecc.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_ecc.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,44 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/*
+ * This code implements the ECC algorithm used in SmartMedia.
+ *
+ * The ECC comprises 22 bits of parity information and is stuffed into 3 bytes.
+ * The two unused bit are set to 1.
+ * The ECC can correct single bit errors in a 256-byte page of data. Thus, two such ECC
+ * blocks are used on a 512-byte NAND page.
+ *
+ */
+
+#ifndef __YAFFS_ECC_H__
+#define __YAFFS_ECC_H__
+
+typedef struct {
+	unsigned char colParity;
+	unsigned lineParity;
+	unsigned lineParityPrime;
+} yaffs_ECCOther;
+
+void yaffs_ECCCalculate(const unsigned char *data, unsigned char *ecc);
+int yaffs_ECCCorrect(unsigned char *data, unsigned char *read_ecc,
+		const unsigned char *test_ecc);
+
+void yaffs_ECCCalculateOther(const unsigned char *data, unsigned nBytes,
+			yaffs_ECCOther *ecc);
+int yaffs_ECCCorrectOther(unsigned char *data, unsigned nBytes,
+			yaffs_ECCOther *read_ecc,
+			const yaffs_ECCOther *test_ecc);
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_fs.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_fs.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_fs.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_fs.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,2542 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2009 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ * Acknowledgements:
+ * Luc van OostenRyck for numerous patches.
+ * Nick Bane for numerous patches.
+ * Nick Bane for 2.5/2.6 integration.
+ * Andras Toth for mknod rdev issue.
+ * Michael Fischer for finding the problem with inode inconsistency.
+ * Some code bodily lifted from JFFS
+ *
+ * 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 is the file system front-end to YAFFS that hooks it up to
+ * the VFS.
+ *
+ * Special notes:
+ * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
+ *         this superblock
+ * >> 2.6: sb->s_fs_info  points to the yaffs_Device associated with this
+ *         superblock
+ * >> inode->u.generic_ip points to the associated yaffs_Object.
+ */
+
+const char *yaffs_fs_c_version =
+    "$Id: yaffs_fs.c,v 1.81 2009-05-26 01:22:44 charles Exp $";
+extern const char *yaffs_guts_c_version;
+
+#include <linux/version.h>
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
+#include <linux/config.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/smp_lock.h>
+#include <linux/pagemap.h>
+#include <linux/mtd/mtd.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+
+#include "asm/div64.h"
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+
+#include <linux/statfs.h>	/* Added NCB 15-8-2003 */
+#include <linux/statfs.h>
+#define UnlockPage(p) unlock_page(p)
+#define Page_Uptodate(page)	test_bit(PG_uptodate, &(page)->flags)
+
+/* FIXME: use sb->s_id instead ? */
+#define yaffs_devname(sb, buf)	bdevname(sb->s_bdev, buf)
+
+#else
+
+#include <linux/locks.h>
+#define	BDEVNAME_SIZE		0
+#define	yaffs_devname(sb, buf)	kdevname(sb->s_dev)
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
+/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
+#define __user
+#endif
+
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
+#define YPROC_ROOT  (&proc_root)
+#else
+#define YPROC_ROOT  NULL
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+#define WRITE_SIZE_STR "writesize"
+#define WRITE_SIZE(mtd) ((mtd)->writesize)
+#else
+#define WRITE_SIZE_STR "oobblock"
+#define WRITE_SIZE(mtd) ((mtd)->oobblock)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
+#define YAFFS_USE_WRITE_BEGIN_END 1
+#else
+#define YAFFS_USE_WRITE_BEGIN_END 0
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
+static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
+{
+	uint64_t result = partition_size;
+	do_div(result, block_size);
+	return (uint32_t)result;
+}
+#else
+#define YCALCBLOCKS(s, b) ((s)/(b))
+#endif
+
+#include <linux/uaccess.h>
+
+#include "yportenv.h"
+#include "yaffs_guts.h"
+
+#include <linux/mtd/mtd.h>
+#include "yaffs_mtdif.h"
+#include "yaffs_mtdif1.h"
+#include "yaffs_mtdif2.h"
+
+unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
+unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
+unsigned int yaffs_auto_checkpoint = 1;
+
+/* Module Parameters */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+module_param(yaffs_traceMask, uint, 0644);
+module_param(yaffs_wr_attempts, uint, 0644);
+module_param(yaffs_auto_checkpoint, uint, 0644);
+#else
+MODULE_PARM(yaffs_traceMask, "i");
+MODULE_PARM(yaffs_wr_attempts, "i");
+MODULE_PARM(yaffs_auto_checkpoint, "i");
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
+/* use iget and read_inode */
+#define Y_IGET(sb, inum) iget((sb), (inum))
+static void yaffs_read_inode(struct inode *inode);
+
+#else
+/* Call local equivalent */
+#define YAFFS_USE_OWN_IGET
+#define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
+
+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
+#endif
+
+/*#define T(x) printk x */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+#define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
+#else
+#define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
+#endif
+
+#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
+#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#define yaffs_SuperToDevice(sb)	((yaffs_Device *)sb->s_fs_info)
+#else
+#define yaffs_SuperToDevice(sb)	((yaffs_Device *)sb->u.generic_sbp)
+#endif
+
+
+#define update_dir_time(dir) do {\
+			(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
+		} while(0)
+		
+static void yaffs_put_super(struct super_block *sb);
+
+static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
+				loff_t *pos);
+static ssize_t yaffs_hold_space(struct file *f);
+static void yaffs_release_space(struct file *f);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_file_flush(struct file *file, fl_owner_t id);
+#else
+static int yaffs_file_flush(struct file *file);
+#endif
+
+static int yaffs_sync_object(struct file *file, struct dentry *dentry,
+				int datasync);
+
+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
+			struct nameidata *n);
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+					struct nameidata *n);
+#else
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
+#endif
+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
+			struct dentry *dentry);
+static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
+static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
+			const char *symname);
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+			dev_t dev);
+#else
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+			int dev);
+#endif
+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
+			struct inode *new_dir, struct dentry *new_dentry);
+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_sync_fs(struct super_block *sb, int wait);
+static void yaffs_write_super(struct super_block *sb);
+#else
+static int yaffs_sync_fs(struct super_block *sb);
+static int yaffs_write_super(struct super_block *sb);
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
+#else
+static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
+#endif
+
+#ifdef YAFFS_HAS_PUT_INODE
+static void yaffs_put_inode(struct inode *inode);
+#endif
+
+static void yaffs_delete_inode(struct inode *);
+static void yaffs_clear_inode(struct inode *);
+
+static int yaffs_readpage(struct file *file, struct page *page);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
+#else
+static int yaffs_writepage(struct page *page);
+#endif
+
+
+#if (YAFFS_USE_WRITE_BEGIN_END != 0)
+static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
+				loff_t pos, unsigned len, unsigned flags,
+				struct page **pagep, void **fsdata);
+static int yaffs_write_end(struct file *filp, struct address_space *mapping,
+				loff_t pos, unsigned len, unsigned copied,
+				struct page *pg, void *fsdadata);
+#else
+static int yaffs_prepare_write(struct file *f, struct page *pg,
+				unsigned offset, unsigned to);
+static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
+				unsigned to);
+
+#endif
+
+static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
+				int buflen);
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
+#else
+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
+#endif
+
+static struct address_space_operations yaffs_file_address_operations = {
+	.readpage = yaffs_readpage,
+	.writepage = yaffs_writepage,
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+	.write_begin = yaffs_write_begin,
+	.write_end = yaffs_write_end,
+#else
+	.prepare_write = yaffs_prepare_write,
+	.commit_write = yaffs_commit_write,
+#endif
+};
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
+static const struct file_operations yaffs_file_operations = {
+	.read = do_sync_read,
+	.write = do_sync_write,
+	.aio_read = generic_file_aio_read,
+	.aio_write = generic_file_aio_write,
+	.mmap = generic_file_mmap,
+	.flush = yaffs_file_flush,
+	.fsync = yaffs_sync_object,
+	.splice_read = generic_file_splice_read,
+	.splice_write = generic_file_splice_write,
+	.llseek = generic_file_llseek,
+};
+
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
+
+static const struct file_operations yaffs_file_operations = {
+	.read = do_sync_read,
+	.write = do_sync_write,
+	.aio_read = generic_file_aio_read,
+	.aio_write = generic_file_aio_write,
+	.mmap = generic_file_mmap,
+	.flush = yaffs_file_flush,
+	.fsync = yaffs_sync_object,
+	.sendfile = generic_file_sendfile,
+};
+
+#else
+
+static const struct file_operations yaffs_file_operations = {
+	.read = generic_file_read,
+	.write = generic_file_write,
+	.mmap = generic_file_mmap,
+	.flush = yaffs_file_flush,
+	.fsync = yaffs_sync_object,
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+	.sendfile = generic_file_sendfile,
+#endif
+};
+#endif
+
+static const struct inode_operations yaffs_file_inode_operations = {
+	.setattr = yaffs_setattr,
+};
+
+static const struct inode_operations yaffs_symlink_inode_operations = {
+	.readlink = yaffs_readlink,
+	.follow_link = yaffs_follow_link,
+	.setattr = yaffs_setattr,
+};
+
+static const struct inode_operations yaffs_dir_inode_operations = {
+	.create = yaffs_create,
+	.lookup = yaffs_lookup,
+	.link = yaffs_link,
+	.unlink = yaffs_unlink,
+	.symlink = yaffs_symlink,
+	.mkdir = yaffs_mkdir,
+	.rmdir = yaffs_unlink,
+	.mknod = yaffs_mknod,
+	.rename = yaffs_rename,
+	.setattr = yaffs_setattr,
+};
+
+static const struct file_operations yaffs_dir_operations = {
+	.read = generic_read_dir,
+	.readdir = yaffs_readdir,
+	.fsync = yaffs_sync_object,
+};
+
+static const struct super_operations yaffs_super_ops = {
+	.statfs = yaffs_statfs,
+
+#ifndef YAFFS_USE_OWN_IGET
+	.read_inode = yaffs_read_inode,
+#endif
+#ifdef YAFFS_HAS_PUT_INODE
+	.put_inode = yaffs_put_inode,
+#endif
+	.put_super = yaffs_put_super,
+	.delete_inode = yaffs_delete_inode,
+	.clear_inode = yaffs_clear_inode,
+	.sync_fs = yaffs_sync_fs,
+	.write_super = yaffs_write_super,
+};
+
+static void yaffs_GrossLock(yaffs_Device *dev)
+{
+	T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current));
+	down(&dev->grossLock);
+	T(YAFFS_TRACE_OS, ("yaffs locked %p\n", current));
+}
+
+static void yaffs_GrossUnlock(yaffs_Device *dev)
+{
+	T(YAFFS_TRACE_OS, ("yaffs unlocking %p\n", current));
+	up(&dev->grossLock);
+}
+
+static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
+			int buflen)
+{
+	unsigned char *alias;
+	int ret;
+
+	yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+
+	yaffs_GrossLock(dev);
+
+	alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
+
+	yaffs_GrossUnlock(dev);
+
+	if (!alias)
+		return -ENOMEM;
+
+	ret = vfs_readlink(dentry, buffer, buflen, alias);
+	kfree(alias);
+	return ret;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+#else
+static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
+#endif
+{
+	unsigned char *alias;
+	int ret;
+	yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+
+	yaffs_GrossLock(dev);
+
+	alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
+
+	yaffs_GrossUnlock(dev);
+
+	if (!alias) {
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	ret = vfs_follow_link(nd, alias);
+	kfree(alias);
+out:
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+	return ERR_PTR(ret);
+#else
+	return ret;
+#endif
+}
+
+struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
+				yaffs_Object *obj);
+
+/*
+ * Lookup is used to find objects in the fs
+ */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
+				struct nameidata *n)
+#else
+static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
+#endif
+{
+	yaffs_Object *obj;
+	struct inode *inode = NULL;	/* NCB 2.5/2.6 needs NULL here */
+
+	yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
+
+	yaffs_GrossLock(dev);
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_lookup for %d:%s\n",
+		yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
+
+	obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
+					dentry->d_name.name);
+
+	obj = yaffs_GetEquivalentObject(obj);	/* in case it was a hardlink */
+
+	/* Can't hold gross lock when calling yaffs_get_inode() */
+	yaffs_GrossUnlock(dev);
+
+	if (obj) {
+		T(YAFFS_TRACE_OS,
+			("yaffs_lookup found %d\n", obj->objectId));
+
+		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+
+		if (inode) {
+			T(YAFFS_TRACE_OS,
+				("yaffs_loookup dentry \n"));
+/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
+ * d_add even if NULL inode */
+#if 0
+			/*dget(dentry); // try to solve directory bug */
+			d_add(dentry, inode);
+
+			/* return dentry; */
+			return NULL;
+#endif
+		}
+
+	} else {
+		T(YAFFS_TRACE_OS, ("yaffs_lookup not found\n"));
+
+	}
+
+/* added NCB for 2.5/6 compatability - forces add even if inode is
+ * NULL which creates dentry hash */
+	d_add(dentry, inode);
+
+	return NULL;
+}
+
+
+#ifdef YAFFS_HAS_PUT_INODE
+
+/* For now put inode is just for debugging
+ * Put inode is called when the inode **structure** is put.
+ */
+static void yaffs_put_inode(struct inode *inode)
+{
+	T(YAFFS_TRACE_OS,
+		("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
+		atomic_read(&inode->i_count)));
+
+}
+#endif
+
+/* clear is called to tell the fs to release any per-inode data it holds */
+static void yaffs_clear_inode(struct inode *inode)
+{
+	yaffs_Object *obj;
+	yaffs_Device *dev;
+
+	obj = yaffs_InodeToObject(inode);
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
+		atomic_read(&inode->i_count),
+		obj ? "object exists" : "null object"));
+
+	if (obj) {
+		dev = obj->myDev;
+		yaffs_GrossLock(dev);
+
+		/* Clear the association between the inode and
+		 * the yaffs_Object.
+		 */
+		obj->myInode = NULL;
+		yaffs_InodeToObjectLV(inode) = NULL;
+
+		/* If the object freeing was deferred, then the real
+		 * free happens now.
+		 * This should fix the inode inconsistency problem.
+		 */
+
+		yaffs_HandleDeferedFree(obj);
+
+		yaffs_GrossUnlock(dev);
+	}
+
+}
+
+/* delete is called when the link count is zero and the inode
+ * is put (ie. nobody wants to know about it anymore, time to
+ * delete the file).
+ * NB Must call clear_inode()
+ */
+static void yaffs_delete_inode(struct inode *inode)
+{
+	yaffs_Object *obj = yaffs_InodeToObject(inode);
+	yaffs_Device *dev;
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
+		atomic_read(&inode->i_count),
+		obj ? "object exists" : "null object"));
+
+	if (obj) {
+		dev = obj->myDev;
+		yaffs_GrossLock(dev);
+		yaffs_DeleteObject(obj);
+		yaffs_GrossUnlock(dev);
+	}
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
+	truncate_inode_pages(&inode->i_data, 0);
+#endif
+	clear_inode(inode);
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_file_flush(struct file *file, fl_owner_t id)
+#else
+static int yaffs_file_flush(struct file *file)
+#endif
+{
+	yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
+
+	yaffs_Device *dev = obj->myDev;
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_file_flush object %d (%s)\n", obj->objectId,
+		obj->dirty ? "dirty" : "clean"));
+
+	yaffs_GrossLock(dev);
+
+	yaffs_FlushFile(obj, 1);
+
+	yaffs_GrossUnlock(dev);
+
+	return 0;
+}
+
+static int yaffs_readpage_nolock(struct file *f, struct page *pg)
+{
+	/* Lifted from jffs2 */
+
+	yaffs_Object *obj;
+	unsigned char *pg_buf;
+	int ret;
+
+	yaffs_Device *dev;
+
+	T(YAFFS_TRACE_OS, ("yaffs_readpage at %08x, size %08x\n",
+			(unsigned)(pg->index << PAGE_CACHE_SHIFT),
+			(unsigned)PAGE_CACHE_SIZE));
+
+	obj = yaffs_DentryToObject(f->f_dentry);
+
+	dev = obj->myDev;
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+	BUG_ON(!PageLocked(pg));
+#else
+	if (!PageLocked(pg))
+		PAGE_BUG(pg);
+#endif
+
+	pg_buf = kmap(pg);
+	/* FIXME: Can kmap fail? */
+
+	yaffs_GrossLock(dev);
+
+	ret = yaffs_ReadDataFromFile(obj, pg_buf,
+				pg->index << PAGE_CACHE_SHIFT,
+				PAGE_CACHE_SIZE);
+
+	yaffs_GrossUnlock(dev);
+
+	if (ret >= 0)
+		ret = 0;
+
+	if (ret) {
+		ClearPageUptodate(pg);
+		SetPageError(pg);
+	} else {
+		SetPageUptodate(pg);
+		ClearPageError(pg);
+	}
+
+	flush_dcache_page(pg);
+	kunmap(pg);
+
+	T(YAFFS_TRACE_OS, ("yaffs_readpage done\n"));
+	return ret;
+}
+
+static int yaffs_readpage_unlock(struct file *f, struct page *pg)
+{
+	int ret = yaffs_readpage_nolock(f, pg);
+	UnlockPage(pg);
+	return ret;
+}
+
+static int yaffs_readpage(struct file *f, struct page *pg)
+{
+	return yaffs_readpage_unlock(f, pg);
+}
+
+/* writepage inspired by/stolen from smbfs */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
+#else
+static int yaffs_writepage(struct page *page)
+#endif
+{
+	struct address_space *mapping = page->mapping;
+	loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
+	struct inode *inode;
+	unsigned long end_index;
+	char *buffer;
+	yaffs_Object *obj;
+	int nWritten = 0;
+	unsigned nBytes;
+
+	if (!mapping)
+		BUG();
+	inode = mapping->host;
+	if (!inode)
+		BUG();
+
+	if (offset > inode->i_size) {
+		T(YAFFS_TRACE_OS,
+			("yaffs_writepage at %08x, inode size = %08x!!!\n",
+			(unsigned)(page->index << PAGE_CACHE_SHIFT),
+			(unsigned)inode->i_size));
+		T(YAFFS_TRACE_OS,
+			("                -> don't care!!\n"));
+		unlock_page(page);
+		return 0;
+	}
+
+	end_index = inode->i_size >> PAGE_CACHE_SHIFT;
+
+	/* easy case */
+	if (page->index < end_index)
+		nBytes = PAGE_CACHE_SIZE;
+	else
+		nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
+
+	get_page(page);
+
+	buffer = kmap(page);
+
+	obj = yaffs_InodeToObject(inode);
+	yaffs_GrossLock(obj->myDev);
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_writepage at %08x, size %08x\n",
+		(unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
+	T(YAFFS_TRACE_OS,
+		("writepag0: obj = %05x, ino = %05x\n",
+		(int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
+
+	nWritten = yaffs_WriteDataToFile(obj, buffer,
+			page->index << PAGE_CACHE_SHIFT, nBytes, 0);
+
+	T(YAFFS_TRACE_OS,
+		("writepag1: obj = %05x, ino = %05x\n",
+		(int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
+
+	yaffs_GrossUnlock(obj->myDev);
+
+	kunmap(page);
+	SetPageUptodate(page);
+	UnlockPage(page);
+	put_page(page);
+
+	return (nWritten == nBytes) ? 0 : -ENOSPC;
+}
+
+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
+				loff_t pos, unsigned len, unsigned flags,
+				struct page **pagep, void **fsdata)
+{
+	struct page *pg = NULL;
+	pgoff_t index = pos >> PAGE_CACHE_SHIFT;
+	uint32_t offset = pos & (PAGE_CACHE_SIZE - 1);
+	uint32_t to = offset + len;
+
+	int ret = 0;
+	int space_held = 0;
+
+	T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n"));
+	/* Get a page */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28)
+	pg = grab_cache_page_write_begin(mapping, index, flags);
+#else
+	pg = __grab_cache_page(mapping, index);
+#endif
+
+	*pagep = pg;
+	if (!pg) {
+		ret =  -ENOMEM;
+		goto out;
+	}
+	/* Get fs space */
+	space_held = yaffs_hold_space(filp);
+
+	if (!space_held) {
+		ret = -ENOSPC;
+		goto out;
+	}
+
+	/* Update page if required */
+
+	if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
+		ret = yaffs_readpage_nolock(filp, pg);
+
+	if (ret)
+		goto out;
+
+	/* Happy path return */
+	T(YAFFS_TRACE_OS, ("end yaffs_write_begin - ok\n"));
+
+	return 0;
+
+out:
+	T(YAFFS_TRACE_OS, ("end yaffs_write_begin fail returning %d\n", ret));
+	if (space_held)
+		yaffs_release_space(filp);
+	if (pg) {
+		unlock_page(pg);
+		page_cache_release(pg);
+	}
+	return ret;
+}
+
+#else
+
+static int yaffs_prepare_write(struct file *f, struct page *pg,
+				unsigned offset, unsigned to)
+{
+	T(YAFFS_TRACE_OS, ("yaffs_prepair_write\n"));
+
+	if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
+		return yaffs_readpage_nolock(f, pg);
+	return 0;
+}
+#endif
+
+#if (YAFFS_USE_WRITE_BEGIN_END > 0)
+static int yaffs_write_end(struct file *filp, struct address_space *mapping,
+				loff_t pos, unsigned len, unsigned copied,
+				struct page *pg, void *fsdadata)
+{
+	int ret = 0;
+	void *addr, *kva;
+	uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
+
+	kva = kmap(pg);
+	addr = kva + offset_into_page;
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_write_end addr %x pos %x nBytes %d\n",
+		(unsigned) addr,
+		(int)pos, copied));
+
+	ret = yaffs_file_write(filp, addr, copied, &pos);
+
+	if (ret != copied) {
+		T(YAFFS_TRACE_OS,
+			("yaffs_write_end not same size ret %d  copied %d\n",
+			ret, copied));
+		SetPageError(pg);
+		ClearPageUptodate(pg);
+	} else {
+		SetPageUptodate(pg);
+	}
+
+	kunmap(pg);
+
+	yaffs_release_space(filp);
+	unlock_page(pg);
+	page_cache_release(pg);
+	return ret;
+}
+#else
+
+static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
+				unsigned to)
+{
+	void *addr, *kva;
+
+	loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
+	int nBytes = to - offset;
+	int nWritten;
+
+	unsigned spos = pos;
+	unsigned saddr;
+
+	kva = kmap(pg);
+	addr = kva + offset;
+
+	saddr = (unsigned) addr;
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_commit_write addr %x pos %x nBytes %d\n",
+		saddr, spos, nBytes));
+
+	nWritten = yaffs_file_write(f, addr, nBytes, &pos);
+
+	if (nWritten != nBytes) {
+		T(YAFFS_TRACE_OS,
+			("yaffs_commit_write not same size nWritten %d  nBytes %d\n",
+			nWritten, nBytes));
+		SetPageError(pg);
+		ClearPageUptodate(pg);
+	} else {
+		SetPageUptodate(pg);
+	}
+
+	kunmap(pg);
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_commit_write returning %d\n",
+		nWritten == nBytes ? 0 : nWritten));
+
+	return nWritten == nBytes ? 0 : nWritten;
+}
+#endif
+
+
+static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
+{
+	if (inode && obj) {
+
+
+		/* Check mode against the variant type and attempt to repair if broken. */
+		__u32 mode = obj->yst_mode;
+		switch (obj->variantType) {
+		case YAFFS_OBJECT_TYPE_FILE:
+			if (!S_ISREG(mode)) {
+				obj->yst_mode &= ~S_IFMT;
+				obj->yst_mode |= S_IFREG;
+			}
+
+			break;
+		case YAFFS_OBJECT_TYPE_SYMLINK:
+			if (!S_ISLNK(mode)) {
+				obj->yst_mode &= ~S_IFMT;
+				obj->yst_mode |= S_IFLNK;
+			}
+
+			break;
+		case YAFFS_OBJECT_TYPE_DIRECTORY:
+			if (!S_ISDIR(mode)) {
+				obj->yst_mode &= ~S_IFMT;
+				obj->yst_mode |= S_IFDIR;
+			}
+
+			break;
+		case YAFFS_OBJECT_TYPE_UNKNOWN:
+		case YAFFS_OBJECT_TYPE_HARDLINK:
+		case YAFFS_OBJECT_TYPE_SPECIAL:
+		default:
+			/* TODO? */
+			break;
+		}
+
+		inode->i_flags |= S_NOATIME;
+
+		inode->i_ino = obj->objectId;
+		inode->i_mode = obj->yst_mode;
+		inode->i_uid = obj->yst_uid;
+		inode->i_gid = obj->yst_gid;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
+		inode->i_blksize = inode->i_sb->s_blocksize;
+#endif
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+
+		inode->i_rdev = old_decode_dev(obj->yst_rdev);
+		inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
+		inode->i_atime.tv_nsec = 0;
+		inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
+		inode->i_mtime.tv_nsec = 0;
+		inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
+		inode->i_ctime.tv_nsec = 0;
+#else
+		inode->i_rdev = obj->yst_rdev;
+		inode->i_atime = obj->yst_atime;
+		inode->i_mtime = obj->yst_mtime;
+		inode->i_ctime = obj->yst_ctime;
+#endif
+		inode->i_size = yaffs_GetObjectFileLength(obj);
+		inode->i_blocks = (inode->i_size + 511) >> 9;
+
+		inode->i_nlink = yaffs_GetObjectLinkCount(obj);
+
+		T(YAFFS_TRACE_OS,
+			("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
+			inode->i_mode, inode->i_uid, inode->i_gid,
+			(int)inode->i_size, atomic_read(&inode->i_count)));
+
+		switch (obj->yst_mode & S_IFMT) {
+		default:	/* fifo, device or socket */
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+			init_special_inode(inode, obj->yst_mode,
+					old_decode_dev(obj->yst_rdev));
+#else
+			init_special_inode(inode, obj->yst_mode,
+					(dev_t) (obj->yst_rdev));
+#endif
+			break;
+		case S_IFREG:	/* file */
+			inode->i_op = &yaffs_file_inode_operations;
+			inode->i_fop = &yaffs_file_operations;
+			inode->i_mapping->a_ops =
+				&yaffs_file_address_operations;
+			break;
+		case S_IFDIR:	/* directory */
+			inode->i_op = &yaffs_dir_inode_operations;
+			inode->i_fop = &yaffs_dir_operations;
+			break;
+		case S_IFLNK:	/* symlink */
+			inode->i_op = &yaffs_symlink_inode_operations;
+			break;
+		}
+
+		yaffs_InodeToObjectLV(inode) = obj;
+
+		obj->myInode = inode;
+
+	} else {
+		T(YAFFS_TRACE_OS,
+			("yaffs_FileInode invalid parameters\n"));
+	}
+
+}
+
+struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
+				yaffs_Object *obj)
+{
+	struct inode *inode;
+
+	if (!sb) {
+		T(YAFFS_TRACE_OS,
+			("yaffs_get_inode for NULL super_block!!\n"));
+		return NULL;
+
+	}
+
+	if (!obj) {
+		T(YAFFS_TRACE_OS,
+			("yaffs_get_inode for NULL object!!\n"));
+		return NULL;
+
+	}
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_get_inode for object %d\n", obj->objectId));
+
+	inode = Y_IGET(sb, obj->objectId);
+	if (IS_ERR(inode))
+		return NULL;
+
+	/* NB Side effect: iget calls back to yaffs_read_inode(). */
+	/* iget also increments the inode's i_count */
+	/* NB You can't be holding grossLock or deadlock will happen! */
+
+	return inode;
+}
+
+static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
+				loff_t *pos)
+{
+	yaffs_Object *obj;
+	int nWritten, ipos;
+	struct inode *inode;
+	yaffs_Device *dev;
+
+	obj = yaffs_DentryToObject(f->f_dentry);
+
+	dev = obj->myDev;
+
+	yaffs_GrossLock(dev);
+
+	inode = f->f_dentry->d_inode;
+
+	if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
+		ipos = inode->i_size;
+	else
+		ipos = *pos;
+
+	if (!obj)
+		T(YAFFS_TRACE_OS,
+			("yaffs_file_write: hey obj is null!\n"));
+	else
+		T(YAFFS_TRACE_OS,
+			("yaffs_file_write about to write writing %zu bytes"
+			"to object %d at %d\n",
+			n, obj->objectId, ipos));
+
+	nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_file_write writing %zu bytes, %d written at %d\n",
+		n, nWritten, ipos));
+
+	if (nWritten > 0) {
+		ipos += nWritten;
+		*pos = ipos;
+		if (ipos > inode->i_size) {
+			inode->i_size = ipos;
+			inode->i_blocks = (ipos + 511) >> 9;
+
+			T(YAFFS_TRACE_OS,
+				("yaffs_file_write size updated to %d bytes, "
+				"%d blocks\n",
+				ipos, (int)(inode->i_blocks)));
+		}
+
+	}
+	yaffs_GrossUnlock(dev);
+	return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
+}
+
+/* Space holding and freeing is done to ensure we have space available for write_begin/end */
+/* For now we just assume few parallel writes and check against a small number. */
+/* Todo: need to do this with a counter to handle parallel reads better */
+
+static ssize_t yaffs_hold_space(struct file *f)
+{
+	yaffs_Object *obj;
+	yaffs_Device *dev;
+
+	int nFreeChunks;
+
+
+	obj = yaffs_DentryToObject(f->f_dentry);
+
+	dev = obj->myDev;
+
+	yaffs_GrossLock(dev);
+
+	nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
+
+	yaffs_GrossUnlock(dev);
+
+	return (nFreeChunks > 20) ? 1 : 0;
+}
+
+static void yaffs_release_space(struct file *f)
+{
+	yaffs_Object *obj;
+	yaffs_Device *dev;
+
+
+	obj = yaffs_DentryToObject(f->f_dentry);
+
+	dev = obj->myDev;
+
+	yaffs_GrossLock(dev);
+
+
+	yaffs_GrossUnlock(dev);
+}
+
+static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
+{
+	yaffs_Object *obj;
+	yaffs_Device *dev;
+	struct inode *inode = f->f_dentry->d_inode;
+	unsigned long offset, curoffs;
+	struct ylist_head *i;
+	yaffs_Object *l;
+
+	char name[YAFFS_MAX_NAME_LENGTH + 1];
+
+	obj = yaffs_DentryToObject(f->f_dentry);
+	dev = obj->myDev;
+
+	yaffs_GrossLock(dev);
+
+	offset = f->f_pos;
+
+	T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
+
+	if (offset == 0) {
+		T(YAFFS_TRACE_OS,
+			("yaffs_readdir: entry . ino %d \n",
+			(int)inode->i_ino));
+		if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
+			goto out;
+		offset++;
+		f->f_pos++;
+	}
+	if (offset == 1) {
+		T(YAFFS_TRACE_OS,
+			("yaffs_readdir: entry .. ino %d \n",
+			(int)f->f_dentry->d_parent->d_inode->i_ino));
+		if (filldir(dirent, "..", 2, offset,
+			f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
+			goto out;
+		offset++;
+		f->f_pos++;
+	}
+
+	curoffs = 1;
+
+	/* If the directory has changed since the open or last call to
+	   readdir, rewind to after the 2 canned entries. */
+
+	if (f->f_version != inode->i_version) {
+		offset = 2;
+		f->f_pos = offset;
+		f->f_version = inode->i_version;
+	}
+
+	ylist_for_each(i, &obj->variant.directoryVariant.children) {
+		curoffs++;
+		if (curoffs >= offset) {
+			l = ylist_entry(i, yaffs_Object, siblings);
+
+			yaffs_GetObjectName(l, name,
+					    YAFFS_MAX_NAME_LENGTH + 1);
+			T(YAFFS_TRACE_OS,
+			  ("yaffs_readdir: %s inode %d\n", name,
+			   yaffs_GetObjectInode(l)));
+
+			if (filldir(dirent,
+					name,
+					strlen(name),
+					offset,
+					yaffs_GetObjectInode(l),
+					yaffs_GetObjectType(l)) < 0)
+				goto up_and_out;
+
+			offset++;
+			f->f_pos++;
+		}
+	}
+
+up_and_out:
+out:
+	yaffs_GrossUnlock(dev);
+
+	return 0;
+}
+
+/*
+ * File creation. Allocate an inode, and we're done..
+ */
+
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+#define YCRED(x) x
+#else
+#define YCRED(x) (x->cred)
+#endif
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+			dev_t rdev)
+#else
+static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
+			int rdev)
+#endif
+{
+	struct inode *inode;
+
+	yaffs_Object *obj = NULL;
+	yaffs_Device *dev;
+
+	yaffs_Object *parent = yaffs_InodeToObject(dir);
+
+	int error = -ENOSPC;
+	uid_t uid = YCRED(current)->fsuid;
+	gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+
+	if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
+		mode |= S_ISGID;
+
+	if (parent) {
+		T(YAFFS_TRACE_OS,
+			("yaffs_mknod: parent object %d type %d\n",
+			parent->objectId, parent->variantType));
+	} else {
+		T(YAFFS_TRACE_OS,
+			("yaffs_mknod: could not get parent object\n"));
+		return -EPERM;
+	}
+
+	T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
+			"mode %x dev %x\n",
+			dentry->d_name.name, mode, rdev));
+
+	dev = parent->myDev;
+
+	yaffs_GrossLock(dev);
+
+	switch (mode & S_IFMT) {
+	default:
+		/* Special (socket, fifo, device...) */
+		T(YAFFS_TRACE_OS, ("yaffs_mknod: making special\n"));
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+		obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
+				gid, old_encode_dev(rdev));
+#else
+		obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
+				gid, rdev);
+#endif
+		break;
+	case S_IFREG:		/* file          */
+		T(YAFFS_TRACE_OS, ("yaffs_mknod: making file\n"));
+		obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
+				gid);
+		break;
+	case S_IFDIR:		/* directory */
+		T(YAFFS_TRACE_OS,
+			("yaffs_mknod: making directory\n"));
+		obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
+					uid, gid);
+		break;
+	case S_IFLNK:		/* symlink */
+		T(YAFFS_TRACE_OS, ("yaffs_mknod: making symlink\n"));
+		obj = NULL;	/* Do we ever get here? */
+		break;
+	}
+
+	/* Can not call yaffs_get_inode() with gross lock held */
+	yaffs_GrossUnlock(dev);
+
+	if (obj) {
+		inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
+		d_instantiate(dentry, inode);
+		update_dir_time(dir);
+		T(YAFFS_TRACE_OS,
+			("yaffs_mknod created object %d count = %d\n",
+			obj->objectId, atomic_read(&inode->i_count)));
+		error = 0;
+	} else {
+		T(YAFFS_TRACE_OS,
+			("yaffs_mknod failed making object\n"));
+		error = -ENOMEM;
+	}
+
+	return error;
+}
+
+static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	int retVal;
+	T(YAFFS_TRACE_OS, ("yaffs_mkdir\n"));
+	retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
+	return retVal;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
+			struct nameidata *n)
+#else
+static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
+#endif
+{
+	T(YAFFS_TRACE_OS, ("yaffs_create\n"));
+	return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
+{
+	int retVal;
+
+	yaffs_Device *dev;
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_unlink %d:%s\n", (int)(dir->i_ino),
+		dentry->d_name.name));
+
+	dev = yaffs_InodeToObject(dir)->myDev;
+
+	yaffs_GrossLock(dev);
+
+	retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
+
+	if (retVal == YAFFS_OK) {
+		dentry->d_inode->i_nlink--;
+		dir->i_version++;
+		yaffs_GrossUnlock(dev);
+		mark_inode_dirty(dentry->d_inode);
+		update_dir_time(dir);
+		return 0;
+	}
+	yaffs_GrossUnlock(dev);
+	return -ENOTEMPTY;
+}
+
+/*
+ * Create a link...
+ */
+static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
+			struct dentry *dentry)
+{
+	struct inode *inode = old_dentry->d_inode;
+	yaffs_Object *obj = NULL;
+	yaffs_Object *link = NULL;
+	yaffs_Device *dev;
+
+	T(YAFFS_TRACE_OS, ("yaffs_link\n"));
+
+	obj = yaffs_InodeToObject(inode);
+	dev = obj->myDev;
+
+	yaffs_GrossLock(dev);
+
+	if (!S_ISDIR(inode->i_mode))		/* Don't link directories */
+		link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
+			obj);
+
+	if (link) {
+		old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
+		d_instantiate(dentry, old_dentry->d_inode);
+		atomic_inc(&old_dentry->d_inode->i_count);
+		T(YAFFS_TRACE_OS,
+			("yaffs_link link count %d i_count %d\n",
+			old_dentry->d_inode->i_nlink,
+			atomic_read(&old_dentry->d_inode->i_count)));
+	}
+
+	yaffs_GrossUnlock(dev);
+
+	if (link){
+		update_dir_time(dir);
+		return 0;
+	}
+
+	return -EPERM;
+}
+
+static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
+				const char *symname)
+{
+	yaffs_Object *obj;
+	yaffs_Device *dev;
+	uid_t uid = YCRED(current)->fsuid;
+	gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
+
+	T(YAFFS_TRACE_OS, ("yaffs_symlink\n"));
+
+	dev = yaffs_InodeToObject(dir)->myDev;
+	yaffs_GrossLock(dev);
+	obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
+				S_IFLNK | S_IRWXUGO, uid, gid, symname);
+	yaffs_GrossUnlock(dev);
+
+	if (obj) {
+		struct inode *inode;
+
+		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
+		d_instantiate(dentry, inode);
+		update_dir_time(dir);
+		T(YAFFS_TRACE_OS, ("symlink created OK\n"));
+		return 0;
+	} else {
+		T(YAFFS_TRACE_OS, ("symlink not created\n"));
+	}
+
+	return -ENOMEM;
+}
+
+static int yaffs_sync_object(struct file *file, struct dentry *dentry,
+				int datasync)
+{
+
+	yaffs_Object *obj;
+	yaffs_Device *dev;
+
+	obj = yaffs_DentryToObject(dentry);
+
+	dev = obj->myDev;
+
+	T(YAFFS_TRACE_OS, ("yaffs_sync_object\n"));
+	yaffs_GrossLock(dev);
+	yaffs_FlushFile(obj, 1);
+	yaffs_GrossUnlock(dev);
+	return 0;
+}
+
+/*
+ * The VFS layer already does all the dentry stuff for rename.
+ *
+ * NB: POSIX says you can rename an object over an old object of the same name
+ */
+static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
+			struct inode *new_dir, struct dentry *new_dentry)
+{
+	yaffs_Device *dev;
+	int retVal = YAFFS_FAIL;
+	yaffs_Object *target;
+
+	T(YAFFS_TRACE_OS, ("yaffs_rename\n"));
+	dev = yaffs_InodeToObject(old_dir)->myDev;
+
+	yaffs_GrossLock(dev);
+
+	/* Check if the target is an existing directory that is not empty. */
+	target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
+				new_dentry->d_name.name);
+
+
+
+	if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+		!ylist_empty(&target->variant.directoryVariant.children)) {
+
+		T(YAFFS_TRACE_OS, ("target is non-empty dir\n"));
+
+		retVal = YAFFS_FAIL;
+	} else {
+		/* Now does unlinking internally using shadowing mechanism */
+		T(YAFFS_TRACE_OS, ("calling yaffs_RenameObject\n"));
+
+		retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
+				old_dentry->d_name.name,
+				yaffs_InodeToObject(new_dir),
+				new_dentry->d_name.name);
+	}
+	yaffs_GrossUnlock(dev);
+
+	if (retVal == YAFFS_OK) {
+		if (target) {
+			new_dentry->d_inode->i_nlink--;
+			mark_inode_dirty(new_dentry->d_inode);
+		}
+		
+		update_dir_time(old_dir);
+		if(old_dir != new_dir)
+			update_dir_time(new_dir);
+		return 0;
+	} else {
+		return -ENOTEMPTY;
+	}
+}
+
+static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	struct inode *inode = dentry->d_inode;
+	int error;
+	yaffs_Device *dev;
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_setattr of object %d\n",
+		yaffs_InodeToObject(inode)->objectId));
+
+	error = inode_change_ok(inode, attr);
+	if (error == 0) {
+		dev = yaffs_InodeToObject(inode)->myDev;
+		yaffs_GrossLock(dev);
+		if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
+				YAFFS_OK) {
+			error = 0;
+		} else {
+			error = -EPERM;
+		}
+		yaffs_GrossUnlock(dev);
+		if (!error)
+			error = inode_setattr(inode, attr);
+	}
+	return error;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+	yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
+	struct super_block *sb = dentry->d_sb;
+#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
+{
+	yaffs_Device *dev = yaffs_SuperToDevice(sb);
+#else
+static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
+{
+	yaffs_Device *dev = yaffs_SuperToDevice(sb);
+#endif
+
+	T(YAFFS_TRACE_OS, ("yaffs_statfs\n"));
+
+	yaffs_GrossLock(dev);
+
+	buf->f_type = YAFFS_MAGIC;
+	buf->f_bsize = sb->s_blocksize;
+	buf->f_namelen = 255;
+
+	if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
+		/* Do this if chunk size is not a power of 2 */
+
+		uint64_t bytesInDev;
+		uint64_t bytesFree;
+
+		bytesInDev = ((uint64_t)((dev->endBlock - dev->startBlock + 1))) *
+			((uint64_t)(dev->nChunksPerBlock * dev->nDataBytesPerChunk));
+
+		do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
+		buf->f_blocks = bytesInDev;
+
+		bytesFree  = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
+			((uint64_t)(dev->nDataBytesPerChunk));
+
+		do_div(bytesFree, sb->s_blocksize);
+
+		buf->f_bfree = bytesFree;
+
+	} else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
+
+		buf->f_blocks =
+			(dev->endBlock - dev->startBlock + 1) *
+			dev->nChunksPerBlock /
+			(sb->s_blocksize / dev->nDataBytesPerChunk);
+		buf->f_bfree =
+			yaffs_GetNumberOfFreeChunks(dev) /
+			(sb->s_blocksize / dev->nDataBytesPerChunk);
+	} else {
+		buf->f_blocks =
+			(dev->endBlock - dev->startBlock + 1) *
+			dev->nChunksPerBlock *
+			(dev->nDataBytesPerChunk / sb->s_blocksize);
+
+		buf->f_bfree =
+			yaffs_GetNumberOfFreeChunks(dev) *
+			(dev->nDataBytesPerChunk / sb->s_blocksize);
+	}
+
+	buf->f_files = 0;
+	buf->f_ffree = 0;
+	buf->f_bavail = buf->f_bfree;
+
+	yaffs_GrossUnlock(dev);
+	return 0;
+}
+
+
+static int yaffs_do_sync_fs(struct super_block *sb)
+{
+
+	yaffs_Device *dev = yaffs_SuperToDevice(sb);
+	T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n"));
+
+	if (sb->s_dirt) {
+		yaffs_GrossLock(dev);
+
+		if (dev) {
+			yaffs_FlushEntireDeviceCache(dev);
+			yaffs_CheckpointSave(dev);
+		}
+
+		yaffs_GrossUnlock(dev);
+
+		sb->s_dirt = 0;
+	}
+	return 0;
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static void yaffs_write_super(struct super_block *sb)
+#else
+static int yaffs_write_super(struct super_block *sb)
+#endif
+{
+
+	T(YAFFS_TRACE_OS, ("yaffs_write_super\n"));
+	if (yaffs_auto_checkpoint >= 2)
+		yaffs_do_sync_fs(sb);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
+	return 0;
+#endif
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_sync_fs(struct super_block *sb, int wait)
+#else
+static int yaffs_sync_fs(struct super_block *sb)
+#endif
+{
+	T(YAFFS_TRACE_OS, ("yaffs_sync_fs\n"));
+
+	if (yaffs_auto_checkpoint >= 1)
+		yaffs_do_sync_fs(sb);
+
+	return 0;
+}
+
+#ifdef YAFFS_USE_OWN_IGET
+
+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
+{
+	struct inode *inode;
+	yaffs_Object *obj;
+	yaffs_Device *dev = yaffs_SuperToDevice(sb);
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_iget for %lu\n", ino));
+
+	inode = iget_locked(sb, ino);
+	if (!inode)
+		return ERR_PTR(-ENOMEM);
+	if (!(inode->i_state & I_NEW))
+		return inode;
+
+	/* NB This is called as a side effect of other functions, but
+	 * we had to release the lock to prevent deadlocks, so
+	 * need to lock again.
+	 */
+
+	yaffs_GrossLock(dev);
+
+	obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
+
+	yaffs_FillInodeFromObject(inode, obj);
+
+	yaffs_GrossUnlock(dev);
+
+	unlock_new_inode(inode);
+	return inode;
+}
+
+#else
+
+static void yaffs_read_inode(struct inode *inode)
+{
+	/* NB This is called as a side effect of other functions, but
+	 * we had to release the lock to prevent deadlocks, so
+	 * need to lock again.
+	 */
+
+	yaffs_Object *obj;
+	yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
+
+	T(YAFFS_TRACE_OS,
+		("yaffs_read_inode for %d\n", (int)inode->i_ino));
+
+	yaffs_GrossLock(dev);
+
+	obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
+
+	yaffs_FillInodeFromObject(inode, obj);
+
+	yaffs_GrossUnlock(dev);
+}
+
+#endif
+
+static YLIST_HEAD(yaffs_dev_list);
+
+#if 0 /* not used */
+static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
+{
+	yaffs_Device    *dev = yaffs_SuperToDevice(sb);
+
+	if (*flags & MS_RDONLY) {
+		struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
+
+		T(YAFFS_TRACE_OS,
+			("yaffs_remount_fs: %s: RO\n", dev->name));
+
+		yaffs_GrossLock(dev);
+
+		yaffs_FlushEntireDeviceCache(dev);
+
+		yaffs_CheckpointSave(dev);
+
+		if (mtd->sync)
+			mtd->sync(mtd);
+
+		yaffs_GrossUnlock(dev);
+	} else {
+		T(YAFFS_TRACE_OS,
+			("yaffs_remount_fs: %s: RW\n", dev->name));
+	}
+
+	return 0;
+}
+#endif
+
+static void yaffs_put_super(struct super_block *sb)
+{
+	yaffs_Device *dev = yaffs_SuperToDevice(sb);
+
+	T(YAFFS_TRACE_OS, ("yaffs_put_super\n"));
+
+	yaffs_GrossLock(dev);
+
+	yaffs_FlushEntireDeviceCache(dev);
+
+	yaffs_CheckpointSave(dev);
+
+	if (dev->putSuperFunc)
+		dev->putSuperFunc(sb);
+
+	yaffs_Deinitialise(dev);
+
+	yaffs_GrossUnlock(dev);
+
+	/* we assume this is protected by lock_kernel() in mount/umount */
+	ylist_del(&dev->devList);
+
+	if (dev->spareBuffer) {
+		YFREE(dev->spareBuffer);
+		dev->spareBuffer = NULL;
+	}
+
+	kfree(dev);
+}
+
+
+static void yaffs_MTDPutSuper(struct super_block *sb)
+{
+	struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
+
+	if (mtd->sync)
+		mtd->sync(mtd);
+
+	put_mtd_device(mtd);
+}
+
+
+static void yaffs_MarkSuperBlockDirty(void *vsb)
+{
+	struct super_block *sb = (struct super_block *)vsb;
+
+	T(YAFFS_TRACE_OS, ("yaffs_MarkSuperBlockDirty() sb = %p\n", sb));
+	if (sb)
+		sb->s_dirt = 1;
+}
+
+typedef struct {
+	int inband_tags;
+	int skip_checkpoint_read;
+	int skip_checkpoint_write;
+	int no_cache;
+} yaffs_options;
+
+#define MAX_OPT_LEN 20
+static int yaffs_parse_options(yaffs_options *options, const char *options_str)
+{
+	char cur_opt[MAX_OPT_LEN + 1];
+	int p;
+	int error = 0;
+
+	/* Parse through the options which is a comma seperated list */
+
+	while (options_str && *options_str && !error) {
+		memset(cur_opt, 0, MAX_OPT_LEN + 1);
+		p = 0;
+
+		while (*options_str && *options_str != ',') {
+			if (p < MAX_OPT_LEN) {
+				cur_opt[p] = *options_str;
+				p++;
+			}
+			options_str++;
+		}
+
+		if (!strcmp(cur_opt, "inband-tags"))
+			options->inband_tags = 1;
+		else if (!strcmp(cur_opt, "no-cache"))
+			options->no_cache = 1;
+		else if (!strcmp(cur_opt, "no-checkpoint-read"))
+			options->skip_checkpoint_read = 1;
+		else if (!strcmp(cur_opt, "no-checkpoint-write"))
+			options->skip_checkpoint_write = 1;
+		else if (!strcmp(cur_opt, "no-checkpoint")) {
+			options->skip_checkpoint_read = 1;
+			options->skip_checkpoint_write = 1;
+		} else {
+			printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
+					cur_opt);
+			error = 1;
+		}
+	}
+
+	return error;
+}
+
+static struct super_block *yaffs_internal_read_super(int yaffsVersion,
+						struct super_block *sb,
+						void *data, int silent)
+{
+	int nBlocks;
+	struct inode *inode = NULL;
+	struct dentry *root;
+	yaffs_Device *dev = 0;
+	char devname_buf[BDEVNAME_SIZE + 1];
+	struct mtd_info *mtd;
+	int err;
+	char *data_str = (char *)data;
+
+	yaffs_options options;
+
+	sb->s_magic = YAFFS_MAGIC;
+	sb->s_op = &yaffs_super_ops;
+	sb->s_flags |= MS_NOATIME;
+
+	if (!sb)
+		printk(KERN_INFO "yaffs: sb is NULL\n");
+	else if (!sb->s_dev)
+		printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
+	else if (!yaffs_devname(sb, devname_buf))
+		printk(KERN_INFO "yaffs: devname is NULL\n");
+	else
+		printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
+		       sb->s_dev,
+		       yaffs_devname(sb, devname_buf));
+
+	if (!data_str)
+		data_str = "";
+
+	printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
+
+	memset(&options, 0, sizeof(options));
+
+	if (yaffs_parse_options(&options, data_str)) {
+		/* Option parsing failed */
+		return NULL;
+	}
+
+
+	sb->s_blocksize = PAGE_CACHE_SIZE;
+	sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+	T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
+	T(YAFFS_TRACE_OS,
+	  ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
+
+#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
+	T(YAFFS_TRACE_OS,
+	  ("yaffs: Write verification disabled. All guarantees "
+	   "null and void\n"));
+#endif
+
+	T(YAFFS_TRACE_OS, ("yaffs: Attempting MTD mount on %u.%u, "
+			       "\"%s\"\n",
+			       MAJOR(sb->s_dev), MINOR(sb->s_dev),
+			       yaffs_devname(sb, devname_buf)));
+
+	/* Check it's an mtd device..... */
+	if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
+		return NULL;	/* This isn't an mtd device */
+
+	/* Get the device */
+	mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
+	if (!mtd) {
+		T(YAFFS_TRACE_ALWAYS,
+		  ("yaffs: MTD device #%u doesn't appear to exist\n",
+		   MINOR(sb->s_dev)));
+		return NULL;
+	}
+	/* Check it's NAND */
+	if (mtd->type != MTD_NANDFLASH) {
+		T(YAFFS_TRACE_ALWAYS,
+		  ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
+		return NULL;
+	}
+
+	T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
+	T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
+	T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
+	T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
+	T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
+	T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
+	T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
+	T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
+	T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
+	T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+	T(YAFFS_TRACE_OS, (" size %u\n", mtd->size));
+#else
+	T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
+#endif
+
+#ifdef CONFIG_YAFFS_AUTO_YAFFS2
+
+	if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
+		T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs2\n"));
+		yaffsVersion = 2;
+	}
+
+	/* Added NCB 26/5/2006 for completeness */
+	if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
+		T(YAFFS_TRACE_ALWAYS, ("yaffs: auto selecting yaffs1\n"));
+		yaffsVersion = 1;
+	}
+
+#endif
+
+	if (yaffsVersion == 2) {
+		/* Check for version 2 style functions */
+		if (!mtd->erase ||
+		    !mtd->block_isbad ||
+		    !mtd->block_markbad ||
+		    !mtd->read ||
+		    !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+		    !mtd->read_oob || !mtd->write_oob) {
+#else
+		    !mtd->write_ecc ||
+		    !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
+			T(YAFFS_TRACE_ALWAYS,
+			  ("yaffs: MTD device does not support required "
+			   "functions\n"));;
+			return NULL;
+		}
+
+		if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
+		    mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
+		    !options.inband_tags) {
+			T(YAFFS_TRACE_ALWAYS,
+			  ("yaffs: MTD device does not have the "
+			   "right page sizes\n"));
+			return NULL;
+		}
+	} else {
+		/* Check for V1 style functions */
+		if (!mtd->erase ||
+		    !mtd->read ||
+		    !mtd->write ||
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+		    !mtd->read_oob || !mtd->write_oob) {
+#else
+		    !mtd->write_ecc ||
+		    !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
+#endif
+			T(YAFFS_TRACE_ALWAYS,
+			  ("yaffs: MTD device does not support required "
+			   "functions\n"));;
+			return NULL;
+		}
+
+		if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
+		    mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
+			T(YAFFS_TRACE_ALWAYS,
+			  ("yaffs: MTD device does not support have the "
+			   "right page sizes\n"));
+			return NULL;
+		}
+	}
+
+	/* OK, so if we got here, we have an MTD that's NAND and looks
+	 * like it has the right capabilities
+	 * Set the yaffs_Device up for mtd
+	 */
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+	sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
+#else
+	sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
+#endif
+	if (!dev) {
+		/* Deep shit could not allocate device structure */
+		T(YAFFS_TRACE_ALWAYS,
+		  ("yaffs_read_super: Failed trying to allocate "
+		   "yaffs_Device. \n"));
+		return NULL;
+	}
+
+	memset(dev, 0, sizeof(yaffs_Device));
+	dev->genericDevice = mtd;
+	dev->name = mtd->name;
+
+	/* Set up the memory size parameters.... */
+
+	nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
+
+	dev->startBlock = 0;
+	dev->endBlock = nBlocks - 1;
+	dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
+	dev->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
+	dev->nReservedBlocks = 5;
+	dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
+	dev->inbandTags = options.inband_tags;
+
+	/* ... and the functions. */
+	if (yaffsVersion == 2) {
+		dev->writeChunkWithTagsToNAND =
+		    nandmtd2_WriteChunkWithTagsToNAND;
+		dev->readChunkWithTagsFromNAND =
+		    nandmtd2_ReadChunkWithTagsFromNAND;
+		dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
+		dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
+		dev->spareBuffer = YMALLOC(mtd->oobsize);
+		dev->isYaffs2 = 1;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+		dev->totalBytesPerChunk = mtd->writesize;
+		dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
+#else
+		dev->totalBytesPerChunk = mtd->oobblock;
+		dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
+#endif
+		nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
+
+		dev->startBlock = 0;
+		dev->endBlock = nBlocks - 1;
+	} else {
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+		/* use the MTD interface in yaffs_mtdif1.c */
+		dev->writeChunkWithTagsToNAND =
+			nandmtd1_WriteChunkWithTagsToNAND;
+		dev->readChunkWithTagsFromNAND =
+			nandmtd1_ReadChunkWithTagsFromNAND;
+		dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
+		dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
+#else
+		dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
+		dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
+#endif
+		dev->isYaffs2 = 0;
+	}
+	/* ... and common functions */
+	dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
+	dev->initialiseNAND = nandmtd_InitialiseNAND;
+
+	dev->putSuperFunc = yaffs_MTDPutSuper;
+
+	dev->superBlock = (void *)sb;
+	dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
+
+
+#ifndef CONFIG_YAFFS_DOES_ECC
+	dev->useNANDECC = 1;
+#endif
+
+#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
+	dev->wideTnodesDisabled = 1;
+#endif
+
+	dev->skipCheckpointRead = options.skip_checkpoint_read;
+	dev->skipCheckpointWrite = options.skip_checkpoint_write;
+
+	/* we assume this is protected by lock_kernel() in mount/umount */
+	ylist_add_tail(&dev->devList, &yaffs_dev_list);
+
+	init_MUTEX(&dev->grossLock);
+
+	yaffs_GrossLock(dev);
+
+	err = yaffs_GutsInitialise(dev);
+
+	T(YAFFS_TRACE_OS,
+	  ("yaffs_read_super: guts initialised %s\n",
+	   (err == YAFFS_OK) ? "OK" : "FAILED"));
+
+	/* Release lock before yaffs_get_inode() */
+	yaffs_GrossUnlock(dev);
+
+	/* Create root inode */
+	if (err == YAFFS_OK)
+		inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
+					yaffs_Root(dev));
+
+	if (!inode)
+		return NULL;
+
+	inode->i_op = &yaffs_dir_inode_operations;
+	inode->i_fop = &yaffs_dir_operations;
+
+	T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
+
+	root = d_alloc_root(inode);
+
+	T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
+
+	if (!root) {
+		iput(inode);
+		return NULL;
+	}
+	sb->s_root = root;
+	sb->s_dirt = !dev->isCheckpointed;
+	T(YAFFS_TRACE_CHECKPOINT,
+	  ("yaffs_read_super: isCheckpointed %d\n", dev->isCheckpointed));
+
+	T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
+	return sb;
+}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
+					 int silent)
+{
+	return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs_read_super(struct file_system_type *fs,
+			    int flags, const char *dev_name,
+			    void *data, struct vfsmount *mnt)
+{
+
+	return get_sb_bdev(fs, flags, dev_name, data,
+			   yaffs_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs_read_super(struct file_system_type *fs,
+					    int flags, const char *dev_name,
+					    void *data)
+{
+
+	return get_sb_bdev(fs, flags, dev_name, data,
+			   yaffs_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "yaffs",
+	.get_sb = yaffs_read_super,
+	.kill_sb = kill_block_super,
+	.fs_flags = FS_REQUIRES_DEV,
+};
+#else
+static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
+					    int silent)
+{
+	return yaffs_internal_read_super(1, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
+		      FS_REQUIRES_DEV);
+#endif
+
+
+#ifdef CONFIG_YAFFS_YAFFS2
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
+					  int silent)
+{
+	return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+static int yaffs2_read_super(struct file_system_type *fs,
+			int flags, const char *dev_name, void *data,
+			struct vfsmount *mnt)
+{
+	return get_sb_bdev(fs, flags, dev_name, data,
+			yaffs2_internal_read_super_mtd, mnt);
+}
+#else
+static struct super_block *yaffs2_read_super(struct file_system_type *fs,
+					     int flags, const char *dev_name,
+					     void *data)
+{
+
+	return get_sb_bdev(fs, flags, dev_name, data,
+			   yaffs2_internal_read_super_mtd);
+}
+#endif
+
+static struct file_system_type yaffs2_fs_type = {
+	.owner = THIS_MODULE,
+	.name = "yaffs2",
+	.get_sb = yaffs2_read_super,
+	.kill_sb = kill_block_super,
+	.fs_flags = FS_REQUIRES_DEV,
+};
+#else
+static struct super_block *yaffs2_read_super(struct super_block *sb,
+					     void *data, int silent)
+{
+	return yaffs_internal_read_super(2, sb, data, silent);
+}
+
+static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
+		      FS_REQUIRES_DEV);
+#endif
+
+#endif				/* CONFIG_YAFFS_YAFFS2 */
+
+static struct proc_dir_entry *my_proc_entry;
+
+static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
+{
+	buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
+	buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
+	buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->totalBytesPerChunk);
+	buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
+	buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
+	buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
+	buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
+	buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
+	buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
+	buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
+	buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
+	buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
+	buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
+	buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
+	buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
+	buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
+	buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
+	buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
+	buf += sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
+	buf += sprintf(buf, "passiveGCs......... %d\n",
+		    dev->passiveGarbageCollections);
+	buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
+	buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
+	buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
+	buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
+	buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
+	buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
+	buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
+	buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
+	buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
+	buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
+	buf +=
+	    sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
+	buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
+	buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
+	buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags);
+
+	return buf;
+}
+
+static int yaffs_proc_read(char *page,
+			   char **start,
+			   off_t offset, int count, int *eof, void *data)
+{
+	struct ylist_head *item;
+	char *buf = page;
+	int step = offset;
+	int n = 0;
+
+	/* Get proc_file_read() to step 'offset' by one on each sucessive call.
+	 * We use 'offset' (*ppos) to indicate where we are in devList.
+	 * This also assumes the user has posted a read buffer large
+	 * enough to hold the complete output; but that's life in /proc.
+	 */
+
+	*(int *)start = 1;
+
+	/* Print header first */
+	if (step == 0) {
+		buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
+			       "\n%s\n%s\n", yaffs_fs_c_version,
+			       yaffs_guts_c_version);
+	}
+
+	/* hold lock_kernel while traversing yaffs_dev_list */
+	lock_kernel();
+
+	/* Locate and print the Nth entry.  Order N-squared but N is small. */
+	ylist_for_each(item, &yaffs_dev_list) {
+		yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList);
+		if (n < step) {
+			n++;
+			continue;
+		}
+		buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
+		buf = yaffs_dump_dev(buf, dev);
+		break;
+	}
+	unlock_kernel();
+
+	return buf - page < count ? buf - page : count;
+}
+
+/**
+ * Set the verbosity of the warnings and error messages.
+ *
+ * Note that the names can only be a..z or _ with the current code.
+ */
+
+static struct {
+	char *mask_name;
+	unsigned mask_bitfield;
+} mask_flags[] = {
+	{"allocate", YAFFS_TRACE_ALLOCATE},
+	{"always", YAFFS_TRACE_ALWAYS},
+	{"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
+	{"buffers", YAFFS_TRACE_BUFFERS},
+	{"bug", YAFFS_TRACE_BUG},
+	{"checkpt", YAFFS_TRACE_CHECKPOINT},
+	{"deletion", YAFFS_TRACE_DELETION},
+	{"erase", YAFFS_TRACE_ERASE},
+	{"error", YAFFS_TRACE_ERROR},
+	{"gc_detail", YAFFS_TRACE_GC_DETAIL},
+	{"gc", YAFFS_TRACE_GC},
+	{"mtd", YAFFS_TRACE_MTD},
+	{"nandaccess", YAFFS_TRACE_NANDACCESS},
+	{"os", YAFFS_TRACE_OS},
+	{"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
+	{"scan", YAFFS_TRACE_SCAN},
+	{"tracing", YAFFS_TRACE_TRACING},
+
+	{"verify", YAFFS_TRACE_VERIFY},
+	{"verify_nand", YAFFS_TRACE_VERIFY_NAND},
+	{"verify_full", YAFFS_TRACE_VERIFY_FULL},
+	{"verify_all", YAFFS_TRACE_VERIFY_ALL},
+
+	{"write", YAFFS_TRACE_WRITE},
+	{"all", 0xffffffff},
+	{"none", 0},
+	{NULL, 0},
+};
+
+#define MAX_MASK_NAME_LENGTH 40
+static int yaffs_proc_write(struct file *file, const char *buf,
+					 unsigned long count, void *data)
+{
+	unsigned rg = 0, mask_bitfield;
+	char *end;
+	char *mask_name;
+	const char *x;
+	char substring[MAX_MASK_NAME_LENGTH + 1];
+	int i;
+	int done = 0;
+	int add, len = 0;
+	int pos = 0;
+
+	rg = yaffs_traceMask;
+
+	while (!done && (pos < count)) {
+		done = 1;
+		while ((pos < count) && isspace(buf[pos]))
+			pos++;
+
+		switch (buf[pos]) {
+		case '+':
+		case '-':
+		case '=':
+			add = buf[pos];
+			pos++;
+			break;
+
+		default:
+			add = ' ';
+			break;
+		}
+		mask_name = NULL;
+
+		mask_bitfield = simple_strtoul(buf + pos, &end, 0);
+
+		if (end > buf + pos) {
+			mask_name = "numeral";
+			len = end - (buf + pos);
+			pos += len;
+			done = 0;
+		} else {
+			for (x = buf + pos, i = 0;
+			    (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
+			    i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
+				substring[i] = *x;
+			substring[i] = '\0';
+
+			for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+				if (strcmp(substring, mask_flags[i].mask_name) == 0) {
+					mask_name = mask_flags[i].mask_name;
+					mask_bitfield = mask_flags[i].mask_bitfield;
+					done = 0;
+					break;
+				}
+			}
+		}
+
+		if (mask_name != NULL) {
+			done = 0;
+			switch (add) {
+			case '-':
+				rg &= ~mask_bitfield;
+				break;
+			case '+':
+				rg |= mask_bitfield;
+				break;
+			case '=':
+				rg = mask_bitfield;
+				break;
+			default:
+				rg |= mask_bitfield;
+				break;
+			}
+		}
+	}
+
+	yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
+
+	printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
+
+	if (rg & YAFFS_TRACE_ALWAYS) {
+		for (i = 0; mask_flags[i].mask_name != NULL; i++) {
+			char flag;
+			flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
+			printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
+		}
+	}
+
+	return count;
+}
+
+/* Stuff to handle installation of file systems */
+struct file_system_to_install {
+	struct file_system_type *fst;
+	int installed;
+};
+
+static struct file_system_to_install fs_to_install[] = {
+	{&yaffs_fs_type, 0},
+	{&yaffs2_fs_type, 0},
+	{NULL, 0}
+};
+
+static int __init init_yaffs_fs(void)
+{
+	int error = 0;
+	struct file_system_to_install *fsinst;
+
+	T(YAFFS_TRACE_ALWAYS,
+	  ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
+
+	/* Install the proc_fs entry */
+	my_proc_entry = create_proc_entry("yaffs",
+					       S_IRUGO | S_IFREG,
+					       YPROC_ROOT);
+
+	if (my_proc_entry) {
+		my_proc_entry->write_proc = yaffs_proc_write;
+		my_proc_entry->read_proc = yaffs_proc_read;
+		my_proc_entry->data = NULL;
+	} else
+		return -ENOMEM;
+
+	/* Now add the file system entries */
+
+	fsinst = fs_to_install;
+
+	while (fsinst->fst && !error) {
+		error = register_filesystem(fsinst->fst);
+		if (!error)
+			fsinst->installed = 1;
+		fsinst++;
+	}
+
+	/* Any errors? uninstall  */
+	if (error) {
+		fsinst = fs_to_install;
+
+		while (fsinst->fst) {
+			if (fsinst->installed) {
+				unregister_filesystem(fsinst->fst);
+				fsinst->installed = 0;
+			}
+			fsinst++;
+		}
+	}
+
+	return error;
+}
+
+static void __exit exit_yaffs_fs(void)
+{
+
+	struct file_system_to_install *fsinst;
+
+	T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
+			       " removing. \n"));
+
+	remove_proc_entry("yaffs", YPROC_ROOT);
+
+	fsinst = fs_to_install;
+
+	while (fsinst->fst) {
+		if (fsinst->installed) {
+			unregister_filesystem(fsinst->fst);
+			fsinst->installed = 0;
+		}
+		fsinst++;
+	}
+}
+
+module_init(init_yaffs_fs)
+module_exit(exit_yaffs_fs)
+
+MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
+MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
+MODULE_LICENSE("GPL");
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_getblockinfo.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_getblockinfo.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_getblockinfo.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_getblockinfo.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,34 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_GETBLOCKINFO_H__
+#define __YAFFS_GETBLOCKINFO_H__
+
+#include "yaffs_guts.h"
+
+/* Function to manipulate block info */
+static Y_INLINE yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device * dev, int blk)
+{
+	if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
+		T(YAFFS_TRACE_ERROR,
+		  (TSTR
+		   ("**>> yaffs: getBlockInfo block %d is not valid" TENDSTR),
+		   blk));
+		YBUG();
+	}
+	return &dev->blockInfo[blk - dev->internalStartBlock];
+}
+
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_guts.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_guts.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_guts.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_guts.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,7580 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+const char *yaffs_guts_c_version =
+    "$Id: yaffs_guts.c,v 1.85 2009-06-08 23:50:44 charles Exp $";
+
+#include "yportenv.h"
+
+#include "yaffsinterface.h"
+#include "yaffs_guts.h"
+#include "yaffs_tagsvalidity.h"
+#include "yaffs_getblockinfo.h"
+
+#include "yaffs_tagscompat.h"
+#ifndef CONFIG_YAFFS_USE_OWN_SORT
+#include "yaffs_qsort.h"
+#endif
+#include "yaffs_nand.h"
+
+#include "yaffs_checkptrw.h"
+
+#include "yaffs_nand.h"
+#include "yaffs_packedtags2.h"
+
+
+#define YAFFS_PASSIVE_GC_CHUNKS 2
+
+#include "yaffs_ecc.h"
+
+
+/* Robustification (if it ever comes about...) */
+static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND);
+static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
+		int erasedOk);
+static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
+				const __u8 *data,
+				const yaffs_ExtendedTags *tags);
+static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
+				const yaffs_ExtendedTags *tags);
+
+/* Other local prototypes */
+static void yaffs_UpdateParent(yaffs_Object *obj);
+static int yaffs_UnlinkObject(yaffs_Object *obj);
+static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
+
+static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList);
+
+static int yaffs_WriteNewChunkWithTagsToNAND(yaffs_Device *dev,
+					const __u8 *buffer,
+					yaffs_ExtendedTags *tags,
+					int useReserve);
+static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
+				int chunkInNAND, int inScan);
+
+static yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
+					yaffs_ObjectType type);
+static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
+				yaffs_Object *obj);
+static int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name,
+				int force, int isShrink, int shadows);
+static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj);
+static int yaffs_CheckStructures(void);
+static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
+			int chunkOffset, int *limit);
+static int yaffs_DoGenericObjectDeletion(yaffs_Object *in);
+
+static yaffs_BlockInfo *yaffs_GetBlockInfo(yaffs_Device *dev, int blockNo);
+
+
+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
+				int chunkInNAND);
+
+static int yaffs_UnlinkWorker(yaffs_Object *obj);
+
+static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
+			int chunkInObject);
+
+static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
+				yaffs_BlockInfo **blockUsedPtr);
+
+static void yaffs_VerifyFreeChunks(yaffs_Device *dev);
+
+static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in);
+
+static void yaffs_VerifyDirectory(yaffs_Object *directory);
+#ifdef YAFFS_PARANOID
+static int yaffs_CheckFileSanity(yaffs_Object *in);
+#else
+#define yaffs_CheckFileSanity(in)
+#endif
+
+static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in);
+static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId);
+
+static void yaffs_InvalidateCheckpoint(yaffs_Device *dev);
+
+static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
+				yaffs_ExtendedTags *tags);
+
+static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
+		unsigned pos);
+static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
+					yaffs_FileStructure *fStruct,
+					__u32 chunkId);
+
+
+/* Function to calculate chunk and offset */
+
+static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
+		__u32 *offsetOut)
+{
+	int chunk;
+	__u32 offset;
+
+	chunk  = (__u32)(addr >> dev->chunkShift);
+
+	if (dev->chunkDiv == 1) {
+		/* easy power of 2 case */
+		offset = (__u32)(addr & dev->chunkMask);
+	} else {
+		/* Non power-of-2 case */
+
+		loff_t chunkBase;
+
+		chunk /= dev->chunkDiv;
+
+		chunkBase = ((loff_t)chunk) * dev->nDataBytesPerChunk;
+		offset = (__u32)(addr - chunkBase);
+	}
+
+	*chunkOut = chunk;
+	*offsetOut = offset;
+}
+
+/* Function to return the number of shifts for a power of 2 greater than or
+ * equal to the given number
+ * Note we don't try to cater for all possible numbers and this does not have to
+ * be hellishly efficient.
+ */
+
+static __u32 ShiftsGE(__u32 x)
+{
+	int extraBits;
+	int nShifts;
+
+	nShifts = extraBits = 0;
+
+	while (x > 1) {
+		if (x & 1)
+			extraBits++;
+		x >>= 1;
+		nShifts++;
+	}
+
+	if (extraBits)
+		nShifts++;
+
+	return nShifts;
+}
+
+/* Function to return the number of shifts to get a 1 in bit 0
+ */
+
+static __u32 Shifts(__u32 x)
+{
+	int nShifts;
+
+	nShifts =  0;
+
+	if (!x)
+		return 0;
+
+	while (!(x&1)) {
+		x >>= 1;
+		nShifts++;
+	}
+
+	return nShifts;
+}
+
+
+
+/*
+ * Temporary buffer manipulations.
+ */
+
+static int yaffs_InitialiseTempBuffers(yaffs_Device *dev)
+{
+	int i;
+	__u8 *buf = (__u8 *)1;
+
+	memset(dev->tempBuffer, 0, sizeof(dev->tempBuffer));
+
+	for (i = 0; buf && i < YAFFS_N_TEMP_BUFFERS; i++) {
+		dev->tempBuffer[i].line = 0;	/* not in use */
+		dev->tempBuffer[i].buffer = buf =
+		    YMALLOC_DMA(dev->totalBytesPerChunk);
+	}
+
+	return buf ? YAFFS_OK : YAFFS_FAIL;
+}
+
+__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo)
+{
+	int i, j;
+
+	dev->tempInUse++;
+	if (dev->tempInUse > dev->maxTemp)
+		dev->maxTemp = dev->tempInUse;
+
+	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+		if (dev->tempBuffer[i].line == 0) {
+			dev->tempBuffer[i].line = lineNo;
+			if ((i + 1) > dev->maxTemp) {
+				dev->maxTemp = i + 1;
+				for (j = 0; j <= i; j++)
+					dev->tempBuffer[j].maxLine =
+					    dev->tempBuffer[j].line;
+			}
+
+			return dev->tempBuffer[i].buffer;
+		}
+	}
+
+	T(YAFFS_TRACE_BUFFERS,
+	  (TSTR("Out of temp buffers at line %d, other held by lines:"),
+	   lineNo));
+	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
+		T(YAFFS_TRACE_BUFFERS, (TSTR(" %d "), dev->tempBuffer[i].line));
+
+	T(YAFFS_TRACE_BUFFERS, (TSTR(" " TENDSTR)));
+
+	/*
+	 * If we got here then we have to allocate an unmanaged one
+	 * This is not good.
+	 */
+
+	dev->unmanagedTempAllocations++;
+	return YMALLOC(dev->nDataBytesPerChunk);
+
+}
+
+void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer,
+				    int lineNo)
+{
+	int i;
+
+	dev->tempInUse--;
+
+	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+		if (dev->tempBuffer[i].buffer == buffer) {
+			dev->tempBuffer[i].line = 0;
+			return;
+		}
+	}
+
+	if (buffer) {
+		/* assume it is an unmanaged one. */
+		T(YAFFS_TRACE_BUFFERS,
+		  (TSTR("Releasing unmanaged temp buffer in line %d" TENDSTR),
+		   lineNo));
+		YFREE(buffer);
+		dev->unmanagedTempDeallocations++;
+	}
+
+}
+
+/*
+ * Determine if we have a managed buffer.
+ */
+int yaffs_IsManagedTempBuffer(yaffs_Device *dev, const __u8 *buffer)
+{
+	int i;
+
+	for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++) {
+		if (dev->tempBuffer[i].buffer == buffer)
+			return 1;
+	}
+
+	for (i = 0; i < dev->nShortOpCaches; i++) {
+		if (dev->srCache[i].data == buffer)
+			return 1;
+	}
+
+	if (buffer == dev->checkpointBuffer)
+		return 1;
+
+	T(YAFFS_TRACE_ALWAYS,
+		(TSTR("yaffs: unmaged buffer detected.\n" TENDSTR)));
+	return 0;
+}
+
+
+
+/*
+ * Chunk bitmap manipulations
+ */
+
+static Y_INLINE __u8 *yaffs_BlockBits(yaffs_Device *dev, int blk)
+{
+	if (blk < dev->internalStartBlock || blk > dev->internalEndBlock) {
+		T(YAFFS_TRACE_ERROR,
+			(TSTR("**>> yaffs: BlockBits block %d is not valid" TENDSTR),
+			blk));
+		YBUG();
+	}
+	return dev->chunkBits +
+		(dev->chunkBitmapStride * (blk - dev->internalStartBlock));
+}
+
+static Y_INLINE void yaffs_VerifyChunkBitId(yaffs_Device *dev, int blk, int chunk)
+{
+	if (blk < dev->internalStartBlock || blk > dev->internalEndBlock ||
+			chunk < 0 || chunk >= dev->nChunksPerBlock) {
+		T(YAFFS_TRACE_ERROR,
+		(TSTR("**>> yaffs: Chunk Id (%d:%d) invalid"TENDSTR),
+			blk, chunk));
+		YBUG();
+	}
+}
+
+static Y_INLINE void yaffs_ClearChunkBits(yaffs_Device *dev, int blk)
+{
+	__u8 *blkBits = yaffs_BlockBits(dev, blk);
+
+	memset(blkBits, 0, dev->chunkBitmapStride);
+}
+
+static Y_INLINE void yaffs_ClearChunkBit(yaffs_Device *dev, int blk, int chunk)
+{
+	__u8 *blkBits = yaffs_BlockBits(dev, blk);
+
+	yaffs_VerifyChunkBitId(dev, blk, chunk);
+
+	blkBits[chunk / 8] &= ~(1 << (chunk & 7));
+}
+
+static Y_INLINE void yaffs_SetChunkBit(yaffs_Device *dev, int blk, int chunk)
+{
+	__u8 *blkBits = yaffs_BlockBits(dev, blk);
+
+	yaffs_VerifyChunkBitId(dev, blk, chunk);
+
+	blkBits[chunk / 8] |= (1 << (chunk & 7));
+}
+
+static Y_INLINE int yaffs_CheckChunkBit(yaffs_Device *dev, int blk, int chunk)
+{
+	__u8 *blkBits = yaffs_BlockBits(dev, blk);
+	yaffs_VerifyChunkBitId(dev, blk, chunk);
+
+	return (blkBits[chunk / 8] & (1 << (chunk & 7))) ? 1 : 0;
+}
+
+static Y_INLINE int yaffs_StillSomeChunkBits(yaffs_Device *dev, int blk)
+{
+	__u8 *blkBits = yaffs_BlockBits(dev, blk);
+	int i;
+	for (i = 0; i < dev->chunkBitmapStride; i++) {
+		if (*blkBits)
+			return 1;
+		blkBits++;
+	}
+	return 0;
+}
+
+static int yaffs_CountChunkBits(yaffs_Device *dev, int blk)
+{
+	__u8 *blkBits = yaffs_BlockBits(dev, blk);
+	int i;
+	int n = 0;
+	for (i = 0; i < dev->chunkBitmapStride; i++) {
+		__u8 x = *blkBits;
+		while (x) {
+			if (x & 1)
+				n++;
+			x >>= 1;
+		}
+
+		blkBits++;
+	}
+	return n;
+}
+
+/*
+ * Verification code
+ */
+
+static int yaffs_SkipVerification(yaffs_Device *dev)
+{
+	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY | YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_SkipFullVerification(yaffs_Device *dev)
+{
+	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_FULL));
+}
+
+static int yaffs_SkipNANDVerification(yaffs_Device *dev)
+{
+	return !(yaffs_traceMask & (YAFFS_TRACE_VERIFY_NAND));
+}
+
+static const char *blockStateName[] = {
+"Unknown",
+"Needs scanning",
+"Scanning",
+"Empty",
+"Allocating",
+"Full",
+"Dirty",
+"Checkpoint",
+"Collecting",
+"Dead"
+};
+
+static void yaffs_VerifyBlock(yaffs_Device *dev, yaffs_BlockInfo *bi, int n)
+{
+	int actuallyUsed;
+	int inUse;
+
+	if (yaffs_SkipVerification(dev))
+		return;
+
+	/* Report illegal runtime states */
+	if (bi->blockState >= YAFFS_NUMBER_OF_BLOCK_STATES)
+		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has undefined state %d"TENDSTR), n, bi->blockState));
+
+	switch (bi->blockState) {
+	case YAFFS_BLOCK_STATE_UNKNOWN:
+	case YAFFS_BLOCK_STATE_SCANNING:
+	case YAFFS_BLOCK_STATE_NEEDS_SCANNING:
+		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has bad run-state %s"TENDSTR),
+		n, blockStateName[bi->blockState]));
+	}
+
+	/* Check pages in use and soft deletions are legal */
+
+	actuallyUsed = bi->pagesInUse - bi->softDeletions;
+
+	if (bi->pagesInUse < 0 || bi->pagesInUse > dev->nChunksPerBlock ||
+	   bi->softDeletions < 0 || bi->softDeletions > dev->nChunksPerBlock ||
+	   actuallyUsed < 0 || actuallyUsed > dev->nChunksPerBlock)
+		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has illegal values pagesInUsed %d softDeletions %d"TENDSTR),
+		n, bi->pagesInUse, bi->softDeletions));
+
+
+	/* Check chunk bitmap legal */
+	inUse = yaffs_CountChunkBits(dev, n);
+	if (inUse != bi->pagesInUse)
+		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has inconsistent values pagesInUse %d counted chunk bits %d"TENDSTR),
+			n, bi->pagesInUse, inUse));
+
+	/* Check that the sequence number is valid.
+	 * Ten million is legal, but is very unlikely
+	 */
+	if (dev->isYaffs2 &&
+	   (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING || bi->blockState == YAFFS_BLOCK_STATE_FULL) &&
+	   (bi->sequenceNumber < YAFFS_LOWEST_SEQUENCE_NUMBER || bi->sequenceNumber > 10000000))
+		T(YAFFS_TRACE_VERIFY, (TSTR("Block %d has suspect sequence number of %d"TENDSTR),
+		n, bi->sequenceNumber));
+}
+
+static void yaffs_VerifyCollectedBlock(yaffs_Device *dev, yaffs_BlockInfo *bi,
+		int n)
+{
+	yaffs_VerifyBlock(dev, bi, n);
+
+	/* After collection the block should be in the erased state */
+	/* This will need to change if we do partial gc */
+
+	if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING &&
+			bi->blockState != YAFFS_BLOCK_STATE_EMPTY) {
+		T(YAFFS_TRACE_ERROR, (TSTR("Block %d is in state %d after gc, should be erased"TENDSTR),
+			n, bi->blockState));
+	}
+}
+
+static void yaffs_VerifyBlocks(yaffs_Device *dev)
+{
+	int i;
+	int nBlocksPerState[YAFFS_NUMBER_OF_BLOCK_STATES];
+	int nIllegalBlockStates = 0;
+
+	if (yaffs_SkipVerification(dev))
+		return;
+
+	memset(nBlocksPerState, 0, sizeof(nBlocksPerState));
+
+	for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
+		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
+		yaffs_VerifyBlock(dev, bi, i);
+
+		if (bi->blockState < YAFFS_NUMBER_OF_BLOCK_STATES)
+			nBlocksPerState[bi->blockState]++;
+		else
+			nIllegalBlockStates++;
+	}
+
+	T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
+	T(YAFFS_TRACE_VERIFY, (TSTR("Block summary"TENDSTR)));
+
+	T(YAFFS_TRACE_VERIFY, (TSTR("%d blocks have illegal states"TENDSTR), nIllegalBlockStates));
+	if (nBlocksPerState[YAFFS_BLOCK_STATE_ALLOCATING] > 1)
+		T(YAFFS_TRACE_VERIFY, (TSTR("Too many allocating blocks"TENDSTR)));
+
+	for (i = 0; i < YAFFS_NUMBER_OF_BLOCK_STATES; i++)
+		T(YAFFS_TRACE_VERIFY,
+		  (TSTR("%s %d blocks"TENDSTR),
+		  blockStateName[i], nBlocksPerState[i]));
+
+	if (dev->blocksInCheckpoint != nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT])
+		T(YAFFS_TRACE_VERIFY,
+		 (TSTR("Checkpoint block count wrong dev %d count %d"TENDSTR),
+		 dev->blocksInCheckpoint, nBlocksPerState[YAFFS_BLOCK_STATE_CHECKPOINT]));
+
+	if (dev->nErasedBlocks != nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY])
+		T(YAFFS_TRACE_VERIFY,
+		 (TSTR("Erased block count wrong dev %d count %d"TENDSTR),
+		 dev->nErasedBlocks, nBlocksPerState[YAFFS_BLOCK_STATE_EMPTY]));
+
+	if (nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING] > 1)
+		T(YAFFS_TRACE_VERIFY,
+		 (TSTR("Too many collecting blocks %d (max is 1)"TENDSTR),
+		 nBlocksPerState[YAFFS_BLOCK_STATE_COLLECTING]));
+
+	T(YAFFS_TRACE_VERIFY, (TSTR(""TENDSTR)));
+
+}
+
+/*
+ * Verify the object header. oh must be valid, but obj and tags may be NULL in which
+ * case those tests will not be performed.
+ */
+static void yaffs_VerifyObjectHeader(yaffs_Object *obj, yaffs_ObjectHeader *oh, yaffs_ExtendedTags *tags, int parentCheck)
+{
+	if (obj && yaffs_SkipVerification(obj->myDev))
+		return;
+
+	if (!(tags && obj && oh)) {
+		T(YAFFS_TRACE_VERIFY,
+				(TSTR("Verifying object header tags %x obj %x oh %x"TENDSTR),
+				(__u32)tags, (__u32)obj, (__u32)oh));
+		return;
+	}
+
+	if (oh->type <= YAFFS_OBJECT_TYPE_UNKNOWN ||
+			oh->type > YAFFS_OBJECT_TYPE_MAX)
+		T(YAFFS_TRACE_VERIFY,
+			(TSTR("Obj %d header type is illegal value 0x%x"TENDSTR),
+			tags->objectId, oh->type));
+
+	if (tags->objectId != obj->objectId)
+		T(YAFFS_TRACE_VERIFY,
+			(TSTR("Obj %d header mismatch objectId %d"TENDSTR),
+			tags->objectId, obj->objectId));
+
+
+	/*
+	 * Check that the object's parent ids match if parentCheck requested.
+	 *
+	 * Tests do not apply to the root object.
+	 */
+
+	if (parentCheck && tags->objectId > 1 && !obj->parent)
+		T(YAFFS_TRACE_VERIFY,
+			(TSTR("Obj %d header mismatch parentId %d obj->parent is NULL"TENDSTR),
+			tags->objectId, oh->parentObjectId));
+
+	if (parentCheck && obj->parent &&
+			oh->parentObjectId != obj->parent->objectId &&
+			(oh->parentObjectId != YAFFS_OBJECTID_UNLINKED ||
+			obj->parent->objectId != YAFFS_OBJECTID_DELETED))
+		T(YAFFS_TRACE_VERIFY,
+			(TSTR("Obj %d header mismatch parentId %d parentObjectId %d"TENDSTR),
+			tags->objectId, oh->parentObjectId, obj->parent->objectId));
+
+	if (tags->objectId > 1 && oh->name[0] == 0) /* Null name */
+		T(YAFFS_TRACE_VERIFY,
+			(TSTR("Obj %d header name is NULL"TENDSTR),
+			obj->objectId));
+
+	if (tags->objectId > 1 && ((__u8)(oh->name[0])) == 0xff) /* Trashed name */
+		T(YAFFS_TRACE_VERIFY,
+			(TSTR("Obj %d header name is 0xFF"TENDSTR),
+			obj->objectId));
+}
+
+
+
+static int yaffs_VerifyTnodeWorker(yaffs_Object *obj, yaffs_Tnode *tn,
+					__u32 level, int chunkOffset)
+{
+	int i;
+	yaffs_Device *dev = obj->myDev;
+	int ok = 1;
+
+	if (tn) {
+		if (level > 0) {
+
+			for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
+				if (tn->internal[i]) {
+					ok = yaffs_VerifyTnodeWorker(obj,
+							tn->internal[i],
+							level - 1,
+							(chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
+				}
+			}
+		} else if (level == 0) {
+			yaffs_ExtendedTags tags;
+			__u32 objectId = obj->objectId;
+
+			chunkOffset <<=  YAFFS_TNODES_LEVEL0_BITS;
+
+			for (i = 0; i < YAFFS_NTNODES_LEVEL0; i++) {
+				__u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
+
+				if (theChunk > 0) {
+					/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),tags.objectId,tags.chunkId,theChunk)); */
+					yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
+					if (tags.objectId != objectId || tags.chunkId != chunkOffset) {
+						T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
+							objectId, chunkOffset, theChunk,
+							tags.objectId, tags.chunkId));
+					}
+				}
+				chunkOffset++;
+			}
+		}
+	}
+
+	return ok;
+
+}
+
+
+static void yaffs_VerifyFile(yaffs_Object *obj)
+{
+	int requiredTallness;
+	int actualTallness;
+	__u32 lastChunk;
+	__u32 x;
+	__u32 i;
+	yaffs_Device *dev;
+	yaffs_ExtendedTags tags;
+	yaffs_Tnode *tn;
+	__u32 objectId;
+
+	if (!obj)
+		return;
+
+	if (yaffs_SkipVerification(obj->myDev))
+		return;
+
+	dev = obj->myDev;
+	objectId = obj->objectId;
+
+	/* Check file size is consistent with tnode depth */
+	lastChunk =  obj->variant.fileVariant.fileSize / dev->nDataBytesPerChunk + 1;
+	x = lastChunk >> YAFFS_TNODES_LEVEL0_BITS;
+	requiredTallness = 0;
+	while (x > 0) {
+		x >>= YAFFS_TNODES_INTERNAL_BITS;
+		requiredTallness++;
+	}
+
+	actualTallness = obj->variant.fileVariant.topLevel;
+
+	if (requiredTallness > actualTallness)
+		T(YAFFS_TRACE_VERIFY,
+		(TSTR("Obj %d had tnode tallness %d, needs to be %d"TENDSTR),
+		 obj->objectId, actualTallness, requiredTallness));
+
+
+	/* Check that the chunks in the tnode tree are all correct.
+	 * We do this by scanning through the tnode tree and
+	 * checking the tags for every chunk match.
+	 */
+
+	if (yaffs_SkipNANDVerification(dev))
+		return;
+
+	for (i = 1; i <= lastChunk; i++) {
+		tn = yaffs_FindLevel0Tnode(dev, &obj->variant.fileVariant, i);
+
+		if (tn) {
+			__u32 theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
+			if (theChunk > 0) {
+				/* T(~0,(TSTR("verifying (%d:%d) %d"TENDSTR),objectId,i,theChunk)); */
+				yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL, &tags);
+				if (tags.objectId != objectId || tags.chunkId != i) {
+					T(~0, (TSTR("Object %d chunkId %d NAND mismatch chunk %d tags (%d:%d)"TENDSTR),
+						objectId, i, theChunk,
+						tags.objectId, tags.chunkId));
+				}
+			}
+		}
+	}
+}
+
+
+static void yaffs_VerifyHardLink(yaffs_Object *obj)
+{
+	if (obj && yaffs_SkipVerification(obj->myDev))
+		return;
+
+	/* Verify sane equivalent object */
+}
+
+static void yaffs_VerifySymlink(yaffs_Object *obj)
+{
+	if (obj && yaffs_SkipVerification(obj->myDev))
+		return;
+
+	/* Verify symlink string */
+}
+
+static void yaffs_VerifySpecial(yaffs_Object *obj)
+{
+	if (obj && yaffs_SkipVerification(obj->myDev))
+		return;
+}
+
+static void yaffs_VerifyObject(yaffs_Object *obj)
+{
+	yaffs_Device *dev;
+
+	__u32 chunkMin;
+	__u32 chunkMax;
+
+	__u32 chunkIdOk;
+	__u32 chunkInRange;
+	__u32 chunkShouldNotBeDeleted;
+	__u32 chunkValid;
+
+	if (!obj)
+		return;
+
+	if (obj->beingCreated)
+		return;
+
+	dev = obj->myDev;
+
+	if (yaffs_SkipVerification(dev))
+		return;
+
+	/* Check sane object header chunk */
+
+	chunkMin = dev->internalStartBlock * dev->nChunksPerBlock;
+	chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
+
+	chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
+	chunkIdOk = chunkInRange || obj->hdrChunk == 0;
+	chunkValid = chunkInRange &&
+			yaffs_CheckChunkBit(dev,
+					obj->hdrChunk / dev->nChunksPerBlock,
+					obj->hdrChunk % dev->nChunksPerBlock);
+	chunkShouldNotBeDeleted = chunkInRange && !chunkValid;
+
+	if (!obj->fake &&
+			(!chunkIdOk || chunkShouldNotBeDeleted)) {
+		T(YAFFS_TRACE_VERIFY,
+			(TSTR("Obj %d has chunkId %d %s %s"TENDSTR),
+			obj->objectId, obj->hdrChunk,
+			chunkIdOk ? "" : ",out of range",
+			chunkShouldNotBeDeleted ? ",marked as deleted" : ""));
+	}
+
+	if (chunkValid && !yaffs_SkipNANDVerification(dev)) {
+		yaffs_ExtendedTags tags;
+		yaffs_ObjectHeader *oh;
+		__u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
+
+		oh = (yaffs_ObjectHeader *)buffer;
+
+		yaffs_ReadChunkWithTagsFromNAND(dev, obj->hdrChunk, buffer,
+				&tags);
+
+		yaffs_VerifyObjectHeader(obj, oh, &tags, 1);
+
+		yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+	}
+
+	/* Verify it has a parent */
+	if (obj && !obj->fake &&
+			(!obj->parent || obj->parent->myDev != dev)) {
+		T(YAFFS_TRACE_VERIFY,
+			(TSTR("Obj %d has parent pointer %p which does not look like an object"TENDSTR),
+			obj->objectId, obj->parent));
+	}
+
+	/* Verify parent is a directory */
+	if (obj->parent && obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		T(YAFFS_TRACE_VERIFY,
+			(TSTR("Obj %d's parent is not a directory (type %d)"TENDSTR),
+			obj->objectId, obj->parent->variantType));
+	}
+
+	switch (obj->variantType) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		yaffs_VerifyFile(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		yaffs_VerifySymlink(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		yaffs_VerifyDirectory(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		yaffs_VerifyHardLink(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		yaffs_VerifySpecial(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+	default:
+		T(YAFFS_TRACE_VERIFY,
+		(TSTR("Obj %d has illegaltype %d"TENDSTR),
+		obj->objectId, obj->variantType));
+		break;
+	}
+}
+
+static void yaffs_VerifyObjects(yaffs_Device *dev)
+{
+	yaffs_Object *obj;
+	int i;
+	struct ylist_head *lh;
+
+	if (yaffs_SkipVerification(dev))
+		return;
+
+	/* Iterate through the objects in each hash entry */
+
+	for (i = 0; i <  YAFFS_NOBJECT_BUCKETS; i++) {
+		ylist_for_each(lh, &dev->objectBucket[i].list) {
+			if (lh) {
+				obj = ylist_entry(lh, yaffs_Object, hashLink);
+				yaffs_VerifyObject(obj);
+			}
+		}
+	}
+}
+
+
+/*
+ *  Simple hash function. Needs to have a reasonable spread
+ */
+
+static Y_INLINE int yaffs_HashFunction(int n)
+{
+	n = abs(n);
+	return n % YAFFS_NOBJECT_BUCKETS;
+}
+
+/*
+ * Access functions to useful fake objects.
+ * Note that root might have a presence in NAND if permissions are set.
+ */
+
+yaffs_Object *yaffs_Root(yaffs_Device *dev)
+{
+	return dev->rootDir;
+}
+
+yaffs_Object *yaffs_LostNFound(yaffs_Device *dev)
+{
+	return dev->lostNFoundDir;
+}
+
+
+/*
+ *  Erased NAND checking functions
+ */
+
+int yaffs_CheckFF(__u8 *buffer, int nBytes)
+{
+	/* Horrible, slow implementation */
+	while (nBytes--) {
+		if (*buffer != 0xFF)
+			return 0;
+		buffer++;
+	}
+	return 1;
+}
+
+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
+				int chunkInNAND)
+{
+	int retval = YAFFS_OK;
+	__u8 *data = yaffs_GetTempBuffer(dev, __LINE__);
+	yaffs_ExtendedTags tags;
+	int result;
+
+	result = yaffs_ReadChunkWithTagsFromNAND(dev, chunkInNAND, data, &tags);
+
+	if (tags.eccResult > YAFFS_ECC_RESULT_NO_ERROR)
+		retval = YAFFS_FAIL;
+
+	if (!yaffs_CheckFF(data, dev->nDataBytesPerChunk) || tags.chunkUsed) {
+		T(YAFFS_TRACE_NANDACCESS,
+		  (TSTR("Chunk %d not erased" TENDSTR), chunkInNAND));
+		retval = YAFFS_FAIL;
+	}
+
+	yaffs_ReleaseTempBuffer(dev, data, __LINE__);
+
+	return retval;
+
+}
+
+static int yaffs_WriteNewChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
+					const __u8 *data,
+					yaffs_ExtendedTags *tags,
+					int useReserve)
+{
+	int attempts = 0;
+	int writeOk = 0;
+	int chunk;
+
+	yaffs_InvalidateCheckpoint(dev);
+
+	do {
+		yaffs_BlockInfo *bi = 0;
+		int erasedOk = 0;
+
+		chunk = yaffs_AllocateChunk(dev, useReserve, &bi);
+		if (chunk < 0) {
+			/* no space */
+			break;
+		}
+
+		/* First check this chunk is erased, if it needs
+		 * checking.  The checking policy (unless forced
+		 * always on) is as follows:
+		 *
+		 * Check the first page we try to write in a block.
+		 * If the check passes then we don't need to check any
+		 * more.	If the check fails, we check again...
+		 * If the block has been erased, we don't need to check.
+		 *
+		 * However, if the block has been prioritised for gc,
+		 * then we think there might be something odd about
+		 * this block and stop using it.
+		 *
+		 * Rationale: We should only ever see chunks that have
+		 * not been erased if there was a partially written
+		 * chunk due to power loss.  This checking policy should
+		 * catch that case with very few checks and thus save a
+		 * lot of checks that are most likely not needed.
+		 */
+		if (bi->gcPrioritise) {
+			yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
+			/* try another chunk */
+			continue;
+		}
+
+		/* let's give it a try */
+		attempts++;
+
+#ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
+		bi->skipErasedCheck = 0;
+#endif
+		if (!bi->skipErasedCheck) {
+			erasedOk = yaffs_CheckChunkErased(dev, chunk);
+			if (erasedOk != YAFFS_OK) {
+				T(YAFFS_TRACE_ERROR,
+				(TSTR("**>> yaffs chunk %d was not erased"
+				TENDSTR), chunk));
+
+				/* try another chunk */
+				continue;
+			}
+			bi->skipErasedCheck = 1;
+		}
+
+		writeOk = yaffs_WriteChunkWithTagsToNAND(dev, chunk,
+				data, tags);
+		if (writeOk != YAFFS_OK) {
+			yaffs_HandleWriteChunkError(dev, chunk, erasedOk);
+			/* try another chunk */
+			continue;
+		}
+
+		/* Copy the data into the robustification buffer */
+		yaffs_HandleWriteChunkOk(dev, chunk, data, tags);
+
+	} while (writeOk != YAFFS_OK &&
+		(yaffs_wr_attempts <= 0 || attempts <= yaffs_wr_attempts));
+
+	if (!writeOk)
+		chunk = -1;
+
+	if (attempts > 1) {
+		T(YAFFS_TRACE_ERROR,
+			(TSTR("**>> yaffs write required %d attempts" TENDSTR),
+			attempts));
+
+		dev->nRetriedWrites += (attempts - 1);
+	}
+
+	return chunk;
+}
+
+/*
+ * Block retiring for handling a broken block.
+ */
+
+static void yaffs_RetireBlock(yaffs_Device *dev, int blockInNAND)
+{
+	yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
+
+	yaffs_InvalidateCheckpoint(dev);
+
+	if (yaffs_MarkBlockBad(dev, blockInNAND) != YAFFS_OK) {
+		if (yaffs_EraseBlockInNAND(dev, blockInNAND) != YAFFS_OK) {
+			T(YAFFS_TRACE_ALWAYS, (TSTR(
+				"yaffs: Failed to mark bad and erase block %d"
+				TENDSTR), blockInNAND));
+		} else {
+			yaffs_ExtendedTags tags;
+			int chunkId = blockInNAND * dev->nChunksPerBlock;
+
+			__u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
+
+			memset(buffer, 0xff, dev->nDataBytesPerChunk);
+			yaffs_InitialiseTags(&tags);
+			tags.sequenceNumber = YAFFS_SEQUENCE_BAD_BLOCK;
+			if (dev->writeChunkWithTagsToNAND(dev, chunkId -
+				dev->chunkOffset, buffer, &tags) != YAFFS_OK)
+				T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Failed to "
+					TCONT("write bad block marker to block %d")
+					TENDSTR), blockInNAND));
+
+			yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+		}
+	}
+
+	bi->blockState = YAFFS_BLOCK_STATE_DEAD;
+	bi->gcPrioritise = 0;
+	bi->needsRetiring = 0;
+
+	dev->nRetiredBlocks++;
+}
+
+/*
+ * Functions for robustisizing TODO
+ *
+ */
+
+static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
+				const __u8 *data,
+				const yaffs_ExtendedTags *tags)
+{
+}
+
+static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
+				const yaffs_ExtendedTags *tags)
+{
+}
+
+void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi)
+{
+	if (!bi->gcPrioritise) {
+		bi->gcPrioritise = 1;
+		dev->hasPendingPrioritisedGCs = 1;
+		bi->chunkErrorStrikes++;
+
+		if (bi->chunkErrorStrikes > 3) {
+			bi->needsRetiring = 1; /* Too many stikes, so retire this */
+			T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Block struck out" TENDSTR)));
+
+		}
+	}
+}
+
+static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND,
+		int erasedOk)
+{
+	int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
+	yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockInNAND);
+
+	yaffs_HandleChunkError(dev, bi);
+
+	if (erasedOk) {
+		/* Was an actual write failure, so mark the block for retirement  */
+		bi->needsRetiring = 1;
+		T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+		  (TSTR("**>> Block %d needs retiring" TENDSTR), blockInNAND));
+	}
+
+	/* Delete the chunk */
+	yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
+}
+
+
+/*---------------- Name handling functions ------------*/
+
+static __u16 yaffs_CalcNameSum(const YCHAR *name)
+{
+	__u16 sum = 0;
+	__u16 i = 1;
+
+	const YUCHAR *bname = (const YUCHAR *) name;
+	if (bname) {
+		while ((*bname) && (i < (YAFFS_MAX_NAME_LENGTH/2))) {
+
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+			sum += yaffs_toupper(*bname) * i;
+#else
+			sum += (*bname) * i;
+#endif
+			i++;
+			bname++;
+		}
+	}
+	return sum;
+}
+
+static void yaffs_SetObjectName(yaffs_Object *obj, const YCHAR *name)
+{
+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+	memset(obj->shortName, 0, sizeof(YCHAR) * (YAFFS_SHORT_NAME_LENGTH+1));
+	if (name && yaffs_strlen(name) <= YAFFS_SHORT_NAME_LENGTH)
+		yaffs_strcpy(obj->shortName, name);
+	else
+		obj->shortName[0] = _Y('\0');
+#endif
+	obj->sum = yaffs_CalcNameSum(name);
+}
+
+/*-------------------- TNODES -------------------
+
+ * List of spare tnodes
+ * The list is hooked together using the first pointer
+ * in the tnode.
+ */
+
+/* yaffs_CreateTnodes creates a bunch more tnodes and
+ * adds them to the tnode free list.
+ * Don't use this function directly
+ */
+
+static int yaffs_CreateTnodes(yaffs_Device *dev, int nTnodes)
+{
+	int i;
+	int tnodeSize;
+	yaffs_Tnode *newTnodes;
+	__u8 *mem;
+	yaffs_Tnode *curr;
+	yaffs_Tnode *next;
+	yaffs_TnodeList *tnl;
+
+	if (nTnodes < 1)
+		return YAFFS_OK;
+
+	/* Calculate the tnode size in bytes for variable width tnode support.
+	 * Must be a multiple of 32-bits  */
+	tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
+
+	if (tnodeSize < sizeof(yaffs_Tnode))
+		tnodeSize = sizeof(yaffs_Tnode);
+
+	/* make these things */
+
+	newTnodes = YMALLOC(nTnodes * tnodeSize);
+	mem = (__u8 *)newTnodes;
+
+	if (!newTnodes) {
+		T(YAFFS_TRACE_ERROR,
+			(TSTR("yaffs: Could not allocate Tnodes" TENDSTR)));
+		return YAFFS_FAIL;
+	}
+
+	/* Hook them into the free list */
+#if 0
+	for (i = 0; i < nTnodes - 1; i++) {
+		newTnodes[i].internal[0] = &newTnodes[i + 1];
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+		newTnodes[i].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
+#endif
+	}
+
+	newTnodes[nTnodes - 1].internal[0] = dev->freeTnodes;
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+	newTnodes[nTnodes - 1].internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
+#endif
+	dev->freeTnodes = newTnodes;
+#else
+	/* New hookup for wide tnodes */
+	for (i = 0; i < nTnodes - 1; i++) {
+		curr = (yaffs_Tnode *) &mem[i * tnodeSize];
+		next = (yaffs_Tnode *) &mem[(i+1) * tnodeSize];
+		curr->internal[0] = next;
+	}
+
+	curr = (yaffs_Tnode *) &mem[(nTnodes - 1) * tnodeSize];
+	curr->internal[0] = dev->freeTnodes;
+	dev->freeTnodes = (yaffs_Tnode *)mem;
+
+#endif
+
+
+	dev->nFreeTnodes += nTnodes;
+	dev->nTnodesCreated += nTnodes;
+
+	/* Now add this bunch of tnodes to a list for freeing up.
+	 * NB If we can't add this to the management list it isn't fatal
+	 * but it just means we can't free this bunch of tnodes later.
+	 */
+
+	tnl = YMALLOC(sizeof(yaffs_TnodeList));
+	if (!tnl) {
+		T(YAFFS_TRACE_ERROR,
+		  (TSTR
+		   ("yaffs: Could not add tnodes to management list" TENDSTR)));
+		   return YAFFS_FAIL;
+	} else {
+		tnl->tnodes = newTnodes;
+		tnl->next = dev->allocatedTnodeList;
+		dev->allocatedTnodeList = tnl;
+	}
+
+	T(YAFFS_TRACE_ALLOCATE, (TSTR("yaffs: Tnodes added" TENDSTR)));
+
+	return YAFFS_OK;
+}
+
+/* GetTnode gets us a clean tnode. Tries to make allocate more if we run out */
+
+static yaffs_Tnode *yaffs_GetTnodeRaw(yaffs_Device *dev)
+{
+	yaffs_Tnode *tn = NULL;
+
+	/* If there are none left make more */
+	if (!dev->freeTnodes)
+		yaffs_CreateTnodes(dev, YAFFS_ALLOCATION_NTNODES);
+
+	if (dev->freeTnodes) {
+		tn = dev->freeTnodes;
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+		if (tn->internal[YAFFS_NTNODES_INTERNAL] != (void *)1) {
+			/* Hoosterman, this thing looks like it isn't in the list */
+			T(YAFFS_TRACE_ALWAYS,
+			  (TSTR("yaffs: Tnode list bug 1" TENDSTR)));
+		}
+#endif
+		dev->freeTnodes = dev->freeTnodes->internal[0];
+		dev->nFreeTnodes--;
+	}
+
+	dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
+
+	return tn;
+}
+
+static yaffs_Tnode *yaffs_GetTnode(yaffs_Device *dev)
+{
+	yaffs_Tnode *tn = yaffs_GetTnodeRaw(dev);
+	int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
+
+	if (tnodeSize < sizeof(yaffs_Tnode))
+		tnodeSize = sizeof(yaffs_Tnode);
+
+	if (tn)
+		memset(tn, 0, tnodeSize);
+
+	return tn;
+}
+
+/* FreeTnode frees up a tnode and puts it back on the free list */
+static void yaffs_FreeTnode(yaffs_Device *dev, yaffs_Tnode *tn)
+{
+	if (tn) {
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+		if (tn->internal[YAFFS_NTNODES_INTERNAL] != 0) {
+			/* Hoosterman, this thing looks like it is already in the list */
+			T(YAFFS_TRACE_ALWAYS,
+			  (TSTR("yaffs: Tnode list bug 2" TENDSTR)));
+		}
+		tn->internal[YAFFS_NTNODES_INTERNAL] = (void *)1;
+#endif
+		tn->internal[0] = dev->freeTnodes;
+		dev->freeTnodes = tn;
+		dev->nFreeTnodes++;
+	}
+	dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
+}
+
+static void yaffs_DeinitialiseTnodes(yaffs_Device *dev)
+{
+	/* Free the list of allocated tnodes */
+	yaffs_TnodeList *tmp;
+
+	while (dev->allocatedTnodeList) {
+		tmp = dev->allocatedTnodeList->next;
+
+		YFREE(dev->allocatedTnodeList->tnodes);
+		YFREE(dev->allocatedTnodeList);
+		dev->allocatedTnodeList = tmp;
+
+	}
+
+	dev->freeTnodes = NULL;
+	dev->nFreeTnodes = 0;
+}
+
+static void yaffs_InitialiseTnodes(yaffs_Device *dev)
+{
+	dev->allocatedTnodeList = NULL;
+	dev->freeTnodes = NULL;
+	dev->nFreeTnodes = 0;
+	dev->nTnodesCreated = 0;
+}
+
+
+void yaffs_PutLevel0Tnode(yaffs_Device *dev, yaffs_Tnode *tn, unsigned pos,
+		unsigned val)
+{
+	__u32 *map = (__u32 *)tn;
+	__u32 bitInMap;
+	__u32 bitInWord;
+	__u32 wordInMap;
+	__u32 mask;
+
+	pos &= YAFFS_TNODES_LEVEL0_MASK;
+	val >>= dev->chunkGroupBits;
+
+	bitInMap = pos * dev->tnodeWidth;
+	wordInMap = bitInMap / 32;
+	bitInWord = bitInMap & (32 - 1);
+
+	mask = dev->tnodeMask << bitInWord;
+
+	map[wordInMap] &= ~mask;
+	map[wordInMap] |= (mask & (val << bitInWord));
+
+	if (dev->tnodeWidth > (32 - bitInWord)) {
+		bitInWord = (32 - bitInWord);
+		wordInMap++;;
+		mask = dev->tnodeMask >> (/*dev->tnodeWidth -*/ bitInWord);
+		map[wordInMap] &= ~mask;
+		map[wordInMap] |= (mask & (val >> bitInWord));
+	}
+}
+
+static __u32 yaffs_GetChunkGroupBase(yaffs_Device *dev, yaffs_Tnode *tn,
+		unsigned pos)
+{
+	__u32 *map = (__u32 *)tn;
+	__u32 bitInMap;
+	__u32 bitInWord;
+	__u32 wordInMap;
+	__u32 val;
+
+	pos &= YAFFS_TNODES_LEVEL0_MASK;
+
+	bitInMap = pos * dev->tnodeWidth;
+	wordInMap = bitInMap / 32;
+	bitInWord = bitInMap & (32 - 1);
+
+	val = map[wordInMap] >> bitInWord;
+
+	if	(dev->tnodeWidth > (32 - bitInWord)) {
+		bitInWord = (32 - bitInWord);
+		wordInMap++;;
+		val |= (map[wordInMap] << bitInWord);
+	}
+
+	val &= dev->tnodeMask;
+	val <<= dev->chunkGroupBits;
+
+	return val;
+}
+
+/* ------------------- End of individual tnode manipulation -----------------*/
+
+/* ---------Functions to manipulate the look-up tree (made up of tnodes) ------
+ * The look up tree is represented by the top tnode and the number of topLevel
+ * in the tree. 0 means only the level 0 tnode is in the tree.
+ */
+
+/* FindLevel0Tnode finds the level 0 tnode, if one exists. */
+static yaffs_Tnode *yaffs_FindLevel0Tnode(yaffs_Device *dev,
+					yaffs_FileStructure *fStruct,
+					__u32 chunkId)
+{
+	yaffs_Tnode *tn = fStruct->top;
+	__u32 i;
+	int requiredTallness;
+	int level = fStruct->topLevel;
+
+	/* Check sane level and chunk Id */
+	if (level < 0 || level > YAFFS_TNODES_MAX_LEVEL)
+		return NULL;
+
+	if (chunkId > YAFFS_MAX_CHUNK_ID)
+		return NULL;
+
+	/* First check we're tall enough (ie enough topLevel) */
+
+	i = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
+	requiredTallness = 0;
+	while (i) {
+		i >>= YAFFS_TNODES_INTERNAL_BITS;
+		requiredTallness++;
+	}
+
+	if (requiredTallness > fStruct->topLevel)
+		return NULL; /* Not tall enough, so we can't find it */
+
+	/* Traverse down to level 0 */
+	while (level > 0 && tn) {
+		tn = tn->internal[(chunkId >>
+			(YAFFS_TNODES_LEVEL0_BITS +
+				(level - 1) *
+				YAFFS_TNODES_INTERNAL_BITS)) &
+			YAFFS_TNODES_INTERNAL_MASK];
+		level--;
+	}
+
+	return tn;
+}
+
+/* AddOrFindLevel0Tnode finds the level 0 tnode if it exists, otherwise first expands the tree.
+ * This happens in two steps:
+ *  1. If the tree isn't tall enough, then make it taller.
+ *  2. Scan down the tree towards the level 0 tnode adding tnodes if required.
+ *
+ * Used when modifying the tree.
+ *
+ *  If the tn argument is NULL, then a fresh tnode will be added otherwise the specified tn will
+ *  be plugged into the ttree.
+ */
+
+static yaffs_Tnode *yaffs_AddOrFindLevel0Tnode(yaffs_Device *dev,
+					yaffs_FileStructure *fStruct,
+					__u32 chunkId,
+					yaffs_Tnode *passedTn)
+{
+	int requiredTallness;
+	int i;
+	int l;
+	yaffs_Tnode *tn;
+
+	__u32 x;
+
+
+	/* Check sane level and page Id */
+	if (fStruct->topLevel < 0 || fStruct->topLevel > YAFFS_TNODES_MAX_LEVEL)
+		return NULL;
+
+	if (chunkId > YAFFS_MAX_CHUNK_ID)
+		return NULL;
+
+	/* First check we're tall enough (ie enough topLevel) */
+
+	x = chunkId >> YAFFS_TNODES_LEVEL0_BITS;
+	requiredTallness = 0;
+	while (x) {
+		x >>= YAFFS_TNODES_INTERNAL_BITS;
+		requiredTallness++;
+	}
+
+
+	if (requiredTallness > fStruct->topLevel) {
+		/* Not tall enough, gotta make the tree taller */
+		for (i = fStruct->topLevel; i < requiredTallness; i++) {
+
+			tn = yaffs_GetTnode(dev);
+
+			if (tn) {
+				tn->internal[0] = fStruct->top;
+				fStruct->top = tn;
+			} else {
+				T(YAFFS_TRACE_ERROR,
+				  (TSTR("yaffs: no more tnodes" TENDSTR)));
+			}
+		}
+
+		fStruct->topLevel = requiredTallness;
+	}
+
+	/* Traverse down to level 0, adding anything we need */
+
+	l = fStruct->topLevel;
+	tn = fStruct->top;
+
+	if (l > 0) {
+		while (l > 0 && tn) {
+			x = (chunkId >>
+			     (YAFFS_TNODES_LEVEL0_BITS +
+			      (l - 1) * YAFFS_TNODES_INTERNAL_BITS)) &
+			    YAFFS_TNODES_INTERNAL_MASK;
+
+
+			if ((l > 1) && !tn->internal[x]) {
+				/* Add missing non-level-zero tnode */
+				tn->internal[x] = yaffs_GetTnode(dev);
+
+			} else if (l == 1) {
+				/* Looking from level 1 at level 0 */
+				if (passedTn) {
+					/* If we already have one, then release it.*/
+					if (tn->internal[x])
+						yaffs_FreeTnode(dev, tn->internal[x]);
+					tn->internal[x] = passedTn;
+
+				} else if (!tn->internal[x]) {
+					/* Don't have one, none passed in */
+					tn->internal[x] = yaffs_GetTnode(dev);
+				}
+			}
+
+			tn = tn->internal[x];
+			l--;
+		}
+	} else {
+		/* top is level 0 */
+		if (passedTn) {
+			memcpy(tn, passedTn, (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8);
+			yaffs_FreeTnode(dev, passedTn);
+		}
+	}
+
+	return tn;
+}
+
+static int yaffs_FindChunkInGroup(yaffs_Device *dev, int theChunk,
+				yaffs_ExtendedTags *tags, int objectId,
+				int chunkInInode)
+{
+	int j;
+
+	for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
+		if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
+				theChunk % dev->nChunksPerBlock)) {
+			yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
+							tags);
+			if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
+				/* found it; */
+				return theChunk;
+			}
+		}
+		theChunk++;
+	}
+	return -1;
+}
+
+
+/* DeleteWorker scans backwards through the tnode tree and deletes all the
+ * chunks and tnodes in the file
+ * Returns 1 if the tree was deleted.
+ * Returns 0 if it stopped early due to hitting the limit and the delete is incomplete.
+ */
+
+static int yaffs_DeleteWorker(yaffs_Object *in, yaffs_Tnode *tn, __u32 level,
+			      int chunkOffset, int *limit)
+{
+	int i;
+	int chunkInInode;
+	int theChunk;
+	yaffs_ExtendedTags tags;
+	int foundChunk;
+	yaffs_Device *dev = in->myDev;
+
+	int allDone = 1;
+
+	if (tn) {
+		if (level > 0) {
+			for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
+			     i--) {
+				if (tn->internal[i]) {
+					if (limit && (*limit) < 0) {
+						allDone = 0;
+					} else {
+						allDone =
+							yaffs_DeleteWorker(in,
+								tn->
+								internal
+								[i],
+								level -
+								1,
+								(chunkOffset
+									<<
+									YAFFS_TNODES_INTERNAL_BITS)
+								+ i,
+								limit);
+					}
+					if (allDone) {
+						yaffs_FreeTnode(dev,
+								tn->
+								internal[i]);
+						tn->internal[i] = NULL;
+					}
+				}
+			}
+			return (allDone) ? 1 : 0;
+		} else if (level == 0) {
+			int hitLimit = 0;
+
+			for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0 && !hitLimit;
+					i--) {
+				theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
+				if (theChunk) {
+
+					chunkInInode = (chunkOffset <<
+						YAFFS_TNODES_LEVEL0_BITS) + i;
+
+					foundChunk =
+						yaffs_FindChunkInGroup(dev,
+								theChunk,
+								&tags,
+								in->objectId,
+								chunkInInode);
+
+					if (foundChunk > 0) {
+						yaffs_DeleteChunk(dev,
+								  foundChunk, 1,
+								  __LINE__);
+						in->nDataChunks--;
+						if (limit) {
+							*limit = *limit - 1;
+							if (*limit <= 0)
+								hitLimit = 1;
+						}
+
+					}
+
+					yaffs_PutLevel0Tnode(dev, tn, i, 0);
+				}
+
+			}
+			return (i < 0) ? 1 : 0;
+
+		}
+
+	}
+
+	return 1;
+
+}
+
+static void yaffs_SoftDeleteChunk(yaffs_Device *dev, int chunk)
+{
+	yaffs_BlockInfo *theBlock;
+
+	T(YAFFS_TRACE_DELETION, (TSTR("soft delete chunk %d" TENDSTR), chunk));
+
+	theBlock = yaffs_GetBlockInfo(dev, chunk / dev->nChunksPerBlock);
+	if (theBlock) {
+		theBlock->softDeletions++;
+		dev->nFreeChunks++;
+	}
+}
+
+/* SoftDeleteWorker scans backwards through the tnode tree and soft deletes all the chunks in the file.
+ * All soft deleting does is increment the block's softdelete count and pulls the chunk out
+ * of the tnode.
+ * Thus, essentially this is the same as DeleteWorker except that the chunks are soft deleted.
+ */
+
+static int yaffs_SoftDeleteWorker(yaffs_Object *in, yaffs_Tnode *tn,
+				  __u32 level, int chunkOffset)
+{
+	int i;
+	int theChunk;
+	int allDone = 1;
+	yaffs_Device *dev = in->myDev;
+
+	if (tn) {
+		if (level > 0) {
+
+			for (i = YAFFS_NTNODES_INTERNAL - 1; allDone && i >= 0;
+			     i--) {
+				if (tn->internal[i]) {
+					allDone =
+					    yaffs_SoftDeleteWorker(in,
+								   tn->
+								   internal[i],
+								   level - 1,
+								   (chunkOffset
+								    <<
+								    YAFFS_TNODES_INTERNAL_BITS)
+								   + i);
+					if (allDone) {
+						yaffs_FreeTnode(dev,
+								tn->
+								internal[i]);
+						tn->internal[i] = NULL;
+					} else {
+						/* Hoosterman... how could this happen? */
+					}
+				}
+			}
+			return (allDone) ? 1 : 0;
+		} else if (level == 0) {
+
+			for (i = YAFFS_NTNODES_LEVEL0 - 1; i >= 0; i--) {
+				theChunk = yaffs_GetChunkGroupBase(dev, tn, i);
+				if (theChunk) {
+					/* Note this does not find the real chunk, only the chunk group.
+					 * We make an assumption that a chunk group is not larger than
+					 * a block.
+					 */
+					yaffs_SoftDeleteChunk(dev, theChunk);
+					yaffs_PutLevel0Tnode(dev, tn, i, 0);
+				}
+
+			}
+			return 1;
+
+		}
+
+	}
+
+	return 1;
+
+}
+
+static void yaffs_SoftDeleteFile(yaffs_Object *obj)
+{
+	if (obj->deleted &&
+	    obj->variantType == YAFFS_OBJECT_TYPE_FILE && !obj->softDeleted) {
+		if (obj->nDataChunks <= 0) {
+			/* Empty file with no duplicate object headers, just delete it immediately */
+			yaffs_FreeTnode(obj->myDev,
+					obj->variant.fileVariant.top);
+			obj->variant.fileVariant.top = NULL;
+			T(YAFFS_TRACE_TRACING,
+			  (TSTR("yaffs: Deleting empty file %d" TENDSTR),
+			   obj->objectId));
+			yaffs_DoGenericObjectDeletion(obj);
+		} else {
+			yaffs_SoftDeleteWorker(obj,
+					       obj->variant.fileVariant.top,
+					       obj->variant.fileVariant.
+					       topLevel, 0);
+			obj->softDeleted = 1;
+		}
+	}
+}
+
+/* Pruning removes any part of the file structure tree that is beyond the
+ * bounds of the file (ie that does not point to chunks).
+ *
+ * A file should only get pruned when its size is reduced.
+ *
+ * Before pruning, the chunks must be pulled from the tree and the
+ * level 0 tnode entries must be zeroed out.
+ * Could also use this for file deletion, but that's probably better handled
+ * by a special case.
+ */
+
+static yaffs_Tnode *yaffs_PruneWorker(yaffs_Device *dev, yaffs_Tnode *tn,
+				__u32 level, int del0)
+{
+	int i;
+	int hasData;
+
+	if (tn) {
+		hasData = 0;
+
+		for (i = 0; i < YAFFS_NTNODES_INTERNAL; i++) {
+			if (tn->internal[i] && level > 0) {
+				tn->internal[i] =
+				    yaffs_PruneWorker(dev, tn->internal[i],
+						      level - 1,
+						      (i == 0) ? del0 : 1);
+			}
+
+			if (tn->internal[i])
+				hasData++;
+		}
+
+		if (hasData == 0 && del0) {
+			/* Free and return NULL */
+
+			yaffs_FreeTnode(dev, tn);
+			tn = NULL;
+		}
+
+	}
+
+	return tn;
+
+}
+
+static int yaffs_PruneFileStructure(yaffs_Device *dev,
+				yaffs_FileStructure *fStruct)
+{
+	int i;
+	int hasData;
+	int done = 0;
+	yaffs_Tnode *tn;
+
+	if (fStruct->topLevel > 0) {
+		fStruct->top =
+		    yaffs_PruneWorker(dev, fStruct->top, fStruct->topLevel, 0);
+
+		/* Now we have a tree with all the non-zero branches NULL but the height
+		 * is the same as it was.
+		 * Let's see if we can trim internal tnodes to shorten the tree.
+		 * We can do this if only the 0th element in the tnode is in use
+		 * (ie all the non-zero are NULL)
+		 */
+
+		while (fStruct->topLevel && !done) {
+			tn = fStruct->top;
+
+			hasData = 0;
+			for (i = 1; i < YAFFS_NTNODES_INTERNAL; i++) {
+				if (tn->internal[i])
+					hasData++;
+			}
+
+			if (!hasData) {
+				fStruct->top = tn->internal[0];
+				fStruct->topLevel--;
+				yaffs_FreeTnode(dev, tn);
+			} else {
+				done = 1;
+			}
+		}
+	}
+
+	return YAFFS_OK;
+}
+
+/*-------------------- End of File Structure functions.-------------------*/
+
+/* yaffs_CreateFreeObjects creates a bunch more objects and
+ * adds them to the object free list.
+ */
+static int yaffs_CreateFreeObjects(yaffs_Device *dev, int nObjects)
+{
+	int i;
+	yaffs_Object *newObjects;
+	yaffs_ObjectList *list;
+
+	if (nObjects < 1)
+		return YAFFS_OK;
+
+	/* make these things */
+	newObjects = YMALLOC(nObjects * sizeof(yaffs_Object));
+	list = YMALLOC(sizeof(yaffs_ObjectList));
+
+	if (!newObjects || !list) {
+		if (newObjects)
+			YFREE(newObjects);
+		if (list)
+			YFREE(list);
+		T(YAFFS_TRACE_ALLOCATE,
+		  (TSTR("yaffs: Could not allocate more objects" TENDSTR)));
+		return YAFFS_FAIL;
+	}
+
+	/* Hook them into the free list */
+	for (i = 0; i < nObjects - 1; i++) {
+		newObjects[i].siblings.next =
+				(struct ylist_head *)(&newObjects[i + 1]);
+	}
+
+	newObjects[nObjects - 1].siblings.next = (void *)dev->freeObjects;
+	dev->freeObjects = newObjects;
+	dev->nFreeObjects += nObjects;
+	dev->nObjectsCreated += nObjects;
+
+	/* Now add this bunch of Objects to a list for freeing up. */
+
+	list->objects = newObjects;
+	list->next = dev->allocatedObjectList;
+	dev->allocatedObjectList = list;
+
+	return YAFFS_OK;
+}
+
+
+/* AllocateEmptyObject gets us a clean Object. Tries to make allocate more if we run out */
+static yaffs_Object *yaffs_AllocateEmptyObject(yaffs_Device *dev)
+{
+	yaffs_Object *tn = NULL;
+
+#ifdef VALGRIND_TEST
+	tn = YMALLOC(sizeof(yaffs_Object));
+#else
+	/* If there are none left make more */
+	if (!dev->freeObjects)
+		yaffs_CreateFreeObjects(dev, YAFFS_ALLOCATION_NOBJECTS);
+
+	if (dev->freeObjects) {
+		tn = dev->freeObjects;
+		dev->freeObjects =
+			(yaffs_Object *) (dev->freeObjects->siblings.next);
+		dev->nFreeObjects--;
+	}
+#endif
+	if (tn) {
+		/* Now sweeten it up... */
+
+		memset(tn, 0, sizeof(yaffs_Object));
+		tn->beingCreated = 1;
+
+		tn->myDev = dev;
+		tn->hdrChunk = 0;
+		tn->variantType = YAFFS_OBJECT_TYPE_UNKNOWN;
+		YINIT_LIST_HEAD(&(tn->hardLinks));
+		YINIT_LIST_HEAD(&(tn->hashLink));
+		YINIT_LIST_HEAD(&tn->siblings);
+
+
+		/* Now make the directory sane */
+		if (dev->rootDir) {
+			tn->parent = dev->rootDir;
+			ylist_add(&(tn->siblings), &dev->rootDir->variant.directoryVariant.children);
+		}
+
+		/* Add it to the lost and found directory.
+		 * NB Can't put root or lostNFound in lostNFound so
+		 * check if lostNFound exists first
+		 */
+		if (dev->lostNFoundDir)
+			yaffs_AddObjectToDirectory(dev->lostNFoundDir, tn);
+
+		tn->beingCreated = 0;
+	}
+
+	dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
+
+	return tn;
+}
+
+static yaffs_Object *yaffs_CreateFakeDirectory(yaffs_Device *dev, int number,
+					       __u32 mode)
+{
+
+	yaffs_Object *obj =
+	    yaffs_CreateNewObject(dev, number, YAFFS_OBJECT_TYPE_DIRECTORY);
+	if (obj) {
+		obj->fake = 1;		/* it is fake so it might have no NAND presence... */
+		obj->renameAllowed = 0;	/* ... and we're not allowed to rename it... */
+		obj->unlinkAllowed = 0;	/* ... or unlink it */
+		obj->deleted = 0;
+		obj->unlinked = 0;
+		obj->yst_mode = mode;
+		obj->myDev = dev;
+		obj->hdrChunk = 0;	/* Not a valid chunk. */
+	}
+
+	return obj;
+
+}
+
+static void yaffs_UnhashObject(yaffs_Object *tn)
+{
+	int bucket;
+	yaffs_Device *dev = tn->myDev;
+
+	/* If it is still linked into the bucket list, free from the list */
+	if (!ylist_empty(&tn->hashLink)) {
+		ylist_del_init(&tn->hashLink);
+		bucket = yaffs_HashFunction(tn->objectId);
+		dev->objectBucket[bucket].count--;
+	}
+}
+
+/*  FreeObject frees up a Object and puts it back on the free list */
+static void yaffs_FreeObject(yaffs_Object *tn)
+{
+	yaffs_Device *dev = tn->myDev;
+
+#ifdef __KERNEL__
+	T(YAFFS_TRACE_OS, (TSTR("FreeObject %p inode %p"TENDSTR), tn, tn->myInode));
+#endif
+
+	if (tn->parent)
+		YBUG();
+	if (!ylist_empty(&tn->siblings))
+		YBUG();
+
+
+#ifdef __KERNEL__
+	if (tn->myInode) {
+		/* We're still hooked up to a cached inode.
+		 * Don't delete now, but mark for later deletion
+		 */
+		tn->deferedFree = 1;
+		return;
+	}
+#endif
+
+	yaffs_UnhashObject(tn);
+
+#ifdef VALGRIND_TEST
+	YFREE(tn);
+#else
+	/* Link into the free list. */
+	tn->siblings.next = (struct ylist_head *)(dev->freeObjects);
+	dev->freeObjects = tn;
+	dev->nFreeObjects++;
+#endif
+	dev->nCheckpointBlocksRequired = 0; /* force recalculation*/
+}
+
+#ifdef __KERNEL__
+
+void yaffs_HandleDeferedFree(yaffs_Object *obj)
+{
+	if (obj->deferedFree)
+		yaffs_FreeObject(obj);
+}
+
+#endif
+
+static void yaffs_DeinitialiseObjects(yaffs_Device *dev)
+{
+	/* Free the list of allocated Objects */
+
+	yaffs_ObjectList *tmp;
+
+	while (dev->allocatedObjectList) {
+		tmp = dev->allocatedObjectList->next;
+		YFREE(dev->allocatedObjectList->objects);
+		YFREE(dev->allocatedObjectList);
+
+		dev->allocatedObjectList = tmp;
+	}
+
+	dev->freeObjects = NULL;
+	dev->nFreeObjects = 0;
+}
+
+static void yaffs_InitialiseObjects(yaffs_Device *dev)
+{
+	int i;
+
+	dev->allocatedObjectList = NULL;
+	dev->freeObjects = NULL;
+	dev->nFreeObjects = 0;
+
+	for (i = 0; i < YAFFS_NOBJECT_BUCKETS; i++) {
+		YINIT_LIST_HEAD(&dev->objectBucket[i].list);
+		dev->objectBucket[i].count = 0;
+	}
+}
+
+static int yaffs_FindNiceObjectBucket(yaffs_Device *dev)
+{
+	static int x;
+	int i;
+	int l = 999;
+	int lowest = 999999;
+
+	/* First let's see if we can find one that's empty. */
+
+	for (i = 0; i < 10 && lowest > 0; i++) {
+		x++;
+		x %= YAFFS_NOBJECT_BUCKETS;
+		if (dev->objectBucket[x].count < lowest) {
+			lowest = dev->objectBucket[x].count;
+			l = x;
+		}
+
+	}
+
+	/* If we didn't find an empty list, then try
+	 * looking a bit further for a short one
+	 */
+
+	for (i = 0; i < 10 && lowest > 3; i++) {
+		x++;
+		x %= YAFFS_NOBJECT_BUCKETS;
+		if (dev->objectBucket[x].count < lowest) {
+			lowest = dev->objectBucket[x].count;
+			l = x;
+		}
+
+	}
+
+	return l;
+}
+
+static int yaffs_CreateNewObjectNumber(yaffs_Device *dev)
+{
+	int bucket = yaffs_FindNiceObjectBucket(dev);
+
+	/* Now find an object value that has not already been taken
+	 * by scanning the list.
+	 */
+
+	int found = 0;
+	struct ylist_head *i;
+
+	__u32 n = (__u32) bucket;
+
+	/* yaffs_CheckObjectHashSanity();  */
+
+	while (!found) {
+		found = 1;
+		n += YAFFS_NOBJECT_BUCKETS;
+		if (1 || dev->objectBucket[bucket].count > 0) {
+			ylist_for_each(i, &dev->objectBucket[bucket].list) {
+				/* If there is already one in the list */
+				if (i && ylist_entry(i, yaffs_Object,
+						hashLink)->objectId == n) {
+					found = 0;
+				}
+			}
+		}
+	}
+
+	return n;
+}
+
+static void yaffs_HashObject(yaffs_Object *in)
+{
+	int bucket = yaffs_HashFunction(in->objectId);
+	yaffs_Device *dev = in->myDev;
+
+	ylist_add(&in->hashLink, &dev->objectBucket[bucket].list);
+	dev->objectBucket[bucket].count++;
+}
+
+yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number)
+{
+	int bucket = yaffs_HashFunction(number);
+	struct ylist_head *i;
+	yaffs_Object *in;
+
+	ylist_for_each(i, &dev->objectBucket[bucket].list) {
+		/* Look if it is in the list */
+		if (i) {
+			in = ylist_entry(i, yaffs_Object, hashLink);
+			if (in->objectId == number) {
+#ifdef __KERNEL__
+				/* Don't tell the VFS about this one if it is defered free */
+				if (in->deferedFree)
+					return NULL;
+#endif
+
+				return in;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+yaffs_Object *yaffs_CreateNewObject(yaffs_Device *dev, int number,
+				    yaffs_ObjectType type)
+{
+	yaffs_Object *theObject;
+	yaffs_Tnode *tn = NULL;
+
+	if (number < 0)
+		number = yaffs_CreateNewObjectNumber(dev);
+
+	theObject = yaffs_AllocateEmptyObject(dev);
+	if (!theObject)
+		return NULL;
+
+	if (type == YAFFS_OBJECT_TYPE_FILE) {
+		tn = yaffs_GetTnode(dev);
+		if (!tn) {
+			yaffs_FreeObject(theObject);
+			return NULL;
+		}
+	}
+
+	if (theObject) {
+		theObject->fake = 0;
+		theObject->renameAllowed = 1;
+		theObject->unlinkAllowed = 1;
+		theObject->objectId = number;
+		yaffs_HashObject(theObject);
+		theObject->variantType = type;
+#ifdef CONFIG_YAFFS_WINCE
+		yfsd_WinFileTimeNow(theObject->win_atime);
+		theObject->win_ctime[0] = theObject->win_mtime[0] =
+		    theObject->win_atime[0];
+		theObject->win_ctime[1] = theObject->win_mtime[1] =
+		    theObject->win_atime[1];
+
+#else
+
+		theObject->yst_atime = theObject->yst_mtime =
+		    theObject->yst_ctime = Y_CURRENT_TIME;
+#endif
+		switch (type) {
+		case YAFFS_OBJECT_TYPE_FILE:
+			theObject->variant.fileVariant.fileSize = 0;
+			theObject->variant.fileVariant.scannedFileSize = 0;
+			theObject->variant.fileVariant.shrinkSize = 0xFFFFFFFF;	/* max __u32 */
+			theObject->variant.fileVariant.topLevel = 0;
+			theObject->variant.fileVariant.top = tn;
+			break;
+		case YAFFS_OBJECT_TYPE_DIRECTORY:
+			YINIT_LIST_HEAD(&theObject->variant.directoryVariant.
+					children);
+			break;
+		case YAFFS_OBJECT_TYPE_SYMLINK:
+		case YAFFS_OBJECT_TYPE_HARDLINK:
+		case YAFFS_OBJECT_TYPE_SPECIAL:
+			/* No action required */
+			break;
+		case YAFFS_OBJECT_TYPE_UNKNOWN:
+			/* todo this should not happen */
+			break;
+		}
+	}
+
+	return theObject;
+}
+
+static yaffs_Object *yaffs_FindOrCreateObjectByNumber(yaffs_Device *dev,
+						      int number,
+						      yaffs_ObjectType type)
+{
+	yaffs_Object *theObject = NULL;
+
+	if (number > 0)
+		theObject = yaffs_FindObjectByNumber(dev, number);
+
+	if (!theObject)
+		theObject = yaffs_CreateNewObject(dev, number, type);
+
+	return theObject;
+
+}
+
+
+static YCHAR *yaffs_CloneString(const YCHAR *str)
+{
+	YCHAR *newStr = NULL;
+
+	if (str && *str) {
+		newStr = YMALLOC((yaffs_strlen(str) + 1) * sizeof(YCHAR));
+		if (newStr)
+			yaffs_strcpy(newStr, str);
+	}
+
+	return newStr;
+
+}
+
+/*
+ * Mknod (create) a new object.
+ * equivalentObject only has meaning for a hard link;
+ * aliasString only has meaning for a sumlink.
+ * rdev only has meaning for devices (a subset of special objects)
+ */
+
+static yaffs_Object *yaffs_MknodObject(yaffs_ObjectType type,
+				       yaffs_Object *parent,
+				       const YCHAR *name,
+				       __u32 mode,
+				       __u32 uid,
+				       __u32 gid,
+				       yaffs_Object *equivalentObject,
+				       const YCHAR *aliasString, __u32 rdev)
+{
+	yaffs_Object *in;
+	YCHAR *str = NULL;
+
+	yaffs_Device *dev = parent->myDev;
+
+	/* Check if the entry exists. If it does then fail the call since we don't want a dup.*/
+	if (yaffs_FindObjectByName(parent, name))
+		return NULL;
+
+	in = yaffs_CreateNewObject(dev, -1, type);
+
+	if (!in)
+		return YAFFS_FAIL;
+
+	if (type == YAFFS_OBJECT_TYPE_SYMLINK) {
+		str = yaffs_CloneString(aliasString);
+		if (!str) {
+			yaffs_FreeObject(in);
+			return NULL;
+		}
+	}
+
+
+
+	if (in) {
+		in->hdrChunk = 0;
+		in->valid = 1;
+		in->variantType = type;
+
+		in->yst_mode = mode;
+
+#ifdef CONFIG_YAFFS_WINCE
+		yfsd_WinFileTimeNow(in->win_atime);
+		in->win_ctime[0] = in->win_mtime[0] = in->win_atime[0];
+		in->win_ctime[1] = in->win_mtime[1] = in->win_atime[1];
+
+#else
+		in->yst_atime = in->yst_mtime = in->yst_ctime = Y_CURRENT_TIME;
+
+		in->yst_rdev = rdev;
+		in->yst_uid = uid;
+		in->yst_gid = gid;
+#endif
+		in->nDataChunks = 0;
+
+		yaffs_SetObjectName(in, name);
+		in->dirty = 1;
+
+		yaffs_AddObjectToDirectory(parent, in);
+
+		in->myDev = parent->myDev;
+
+		switch (type) {
+		case YAFFS_OBJECT_TYPE_SYMLINK:
+			in->variant.symLinkVariant.alias = str;
+			break;
+		case YAFFS_OBJECT_TYPE_HARDLINK:
+			in->variant.hardLinkVariant.equivalentObject =
+				equivalentObject;
+			in->variant.hardLinkVariant.equivalentObjectId =
+				equivalentObject->objectId;
+			ylist_add(&in->hardLinks, &equivalentObject->hardLinks);
+			break;
+		case YAFFS_OBJECT_TYPE_FILE:
+		case YAFFS_OBJECT_TYPE_DIRECTORY:
+		case YAFFS_OBJECT_TYPE_SPECIAL:
+		case YAFFS_OBJECT_TYPE_UNKNOWN:
+			/* do nothing */
+			break;
+		}
+
+		if (yaffs_UpdateObjectHeader(in, name, 0, 0, 0) < 0) {
+			/* Could not create the object header, fail the creation */
+			yaffs_DeleteObject(in);
+			in = NULL;
+		}
+
+		yaffs_UpdateParent(parent);
+	}
+
+	return in;
+}
+
+yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
+			__u32 mode, __u32 uid, __u32 gid)
+{
+	return yaffs_MknodObject(YAFFS_OBJECT_TYPE_FILE, parent, name, mode,
+				uid, gid, NULL, NULL, 0);
+}
+
+yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
+				__u32 mode, __u32 uid, __u32 gid)
+{
+	return yaffs_MknodObject(YAFFS_OBJECT_TYPE_DIRECTORY, parent, name,
+				 mode, uid, gid, NULL, NULL, 0);
+}
+
+yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
+				__u32 mode, __u32 uid, __u32 gid, __u32 rdev)
+{
+	return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SPECIAL, parent, name, mode,
+				 uid, gid, NULL, NULL, rdev);
+}
+
+yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
+				__u32 mode, __u32 uid, __u32 gid,
+				const YCHAR *alias)
+{
+	return yaffs_MknodObject(YAFFS_OBJECT_TYPE_SYMLINK, parent, name, mode,
+				uid, gid, NULL, alias, 0);
+}
+
+/* yaffs_Link returns the object id of the equivalent object.*/
+yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
+			yaffs_Object *equivalentObject)
+{
+	/* Get the real object in case we were fed a hard link as an equivalent object */
+	equivalentObject = yaffs_GetEquivalentObject(equivalentObject);
+
+	if (yaffs_MknodObject
+	    (YAFFS_OBJECT_TYPE_HARDLINK, parent, name, 0, 0, 0,
+	     equivalentObject, NULL, 0)) {
+		return equivalentObject;
+	} else {
+		return NULL;
+	}
+
+}
+
+static int yaffs_ChangeObjectName(yaffs_Object *obj, yaffs_Object *newDir,
+				const YCHAR *newName, int force, int shadows)
+{
+	int unlinkOp;
+	int deleteOp;
+
+	yaffs_Object *existingTarget;
+
+	if (newDir == NULL)
+		newDir = obj->parent;	/* use the old directory */
+
+	if (newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR
+		   ("tragedy: yaffs_ChangeObjectName: newDir is not a directory"
+		    TENDSTR)));
+		YBUG();
+	}
+
+	/* TODO: Do we need this different handling for YAFFS2 and YAFFS1?? */
+	if (obj->myDev->isYaffs2)
+		unlinkOp = (newDir == obj->myDev->unlinkedDir);
+	else
+		unlinkOp = (newDir == obj->myDev->unlinkedDir
+			    && obj->variantType == YAFFS_OBJECT_TYPE_FILE);
+
+	deleteOp = (newDir == obj->myDev->deletedDir);
+
+	existingTarget = yaffs_FindObjectByName(newDir, newName);
+
+	/* If the object is a file going into the unlinked directory,
+	 *   then it is OK to just stuff it in since duplicate names are allowed.
+	 *   else only proceed if the new name does not exist and if we're putting
+	 *   it into a directory.
+	 */
+	if ((unlinkOp ||
+	     deleteOp ||
+	     force ||
+	     (shadows > 0) ||
+	     !existingTarget) &&
+	    newDir->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) {
+		yaffs_SetObjectName(obj, newName);
+		obj->dirty = 1;
+
+		yaffs_AddObjectToDirectory(newDir, obj);
+
+		if (unlinkOp)
+			obj->unlinked = 1;
+
+		/* If it is a deletion then we mark it as a shrink for gc purposes. */
+		if (yaffs_UpdateObjectHeader(obj, newName, 0, deleteOp, shadows) >= 0)
+			return YAFFS_OK;
+	}
+
+	return YAFFS_FAIL;
+}
+
+int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
+		yaffs_Object *newDir, const YCHAR *newName)
+{
+	yaffs_Object *obj = NULL;
+	yaffs_Object *existingTarget = NULL;
+	int force = 0;
+
+
+	if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+		YBUG();
+	if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+		YBUG();
+
+#ifdef CONFIG_YAFFS_CASE_INSENSITIVE
+	/* Special case for case insemsitive systems (eg. WinCE).
+	 * While look-up is case insensitive, the name isn't.
+	 * Therefore we might want to change x.txt to X.txt
+	*/
+	if (oldDir == newDir && yaffs_strcmp(oldName, newName) == 0)
+		force = 1;
+#endif
+
+	else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
+		/* ENAMETOOLONG */
+		return YAFFS_FAIL;
+
+	obj = yaffs_FindObjectByName(oldDir, oldName);
+
+	if (obj && obj->renameAllowed) {
+
+		/* Now do the handling for an existing target, if there is one */
+
+		existingTarget = yaffs_FindObjectByName(newDir, newName);
+		if (existingTarget &&
+			existingTarget->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+			!ylist_empty(&existingTarget->variant.directoryVariant.children)) {
+			/* There is a target that is a non-empty directory, so we fail */
+			return YAFFS_FAIL;	/* EEXIST or ENOTEMPTY */
+		} else if (existingTarget && existingTarget != obj) {
+			/* Nuke the target first, using shadowing,
+			 * but only if it isn't the same object
+			 */
+			yaffs_ChangeObjectName(obj, newDir, newName, force,
+						existingTarget->objectId);
+			yaffs_UnlinkObject(existingTarget);
+		}
+		yaffs_UpdateParent(oldDir);
+		if(newDir != oldDir)
+			yaffs_UpdateParent(newDir);
+
+		return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+	}
+	return YAFFS_FAIL;
+}
+
+/*------------------------- Block Management and Page Allocation ----------------*/
+
+static int yaffs_InitialiseBlocks(yaffs_Device *dev)
+{
+	int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
+
+	dev->blockInfo = NULL;
+	dev->chunkBits = NULL;
+
+	dev->allocationBlock = -1;	/* force it to get a new one */
+
+	/* If the first allocation strategy fails, thry the alternate one */
+	dev->blockInfo = YMALLOC(nBlocks * sizeof(yaffs_BlockInfo));
+	if (!dev->blockInfo) {
+		dev->blockInfo = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockInfo));
+		dev->blockInfoAlt = 1;
+	} else
+		dev->blockInfoAlt = 0;
+
+	if (dev->blockInfo) {
+		/* Set up dynamic blockinfo stuff. */
+		dev->chunkBitmapStride = (dev->nChunksPerBlock + 7) / 8; /* round up bytes */
+		dev->chunkBits = YMALLOC(dev->chunkBitmapStride * nBlocks);
+		if (!dev->chunkBits) {
+			dev->chunkBits = YMALLOC_ALT(dev->chunkBitmapStride * nBlocks);
+			dev->chunkBitsAlt = 1;
+		} else
+			dev->chunkBitsAlt = 0;
+	}
+
+	if (dev->blockInfo && dev->chunkBits) {
+		memset(dev->blockInfo, 0, nBlocks * sizeof(yaffs_BlockInfo));
+		memset(dev->chunkBits, 0, dev->chunkBitmapStride * nBlocks);
+		return YAFFS_OK;
+	}
+
+	return YAFFS_FAIL;
+}
+
+static void yaffs_DeinitialiseBlocks(yaffs_Device *dev)
+{
+	if (dev->blockInfoAlt && dev->blockInfo)
+		YFREE_ALT(dev->blockInfo);
+	else if (dev->blockInfo)
+		YFREE(dev->blockInfo);
+
+	dev->blockInfoAlt = 0;
+
+	dev->blockInfo = NULL;
+
+	if (dev->chunkBitsAlt && dev->chunkBits)
+		YFREE_ALT(dev->chunkBits);
+	else if (dev->chunkBits)
+		YFREE(dev->chunkBits);
+	dev->chunkBitsAlt = 0;
+	dev->chunkBits = NULL;
+}
+
+static int yaffs_BlockNotDisqualifiedFromGC(yaffs_Device *dev,
+					yaffs_BlockInfo *bi)
+{
+	int i;
+	__u32 seq;
+	yaffs_BlockInfo *b;
+
+	if (!dev->isYaffs2)
+		return 1;	/* disqualification only applies to yaffs2. */
+
+	if (!bi->hasShrinkHeader)
+		return 1;	/* can gc */
+
+	/* Find the oldest dirty sequence number if we don't know it and save it
+	 * so we don't have to keep recomputing it.
+	 */
+	if (!dev->oldestDirtySequence) {
+		seq = dev->sequenceNumber;
+
+		for (i = dev->internalStartBlock; i <= dev->internalEndBlock;
+				i++) {
+			b = yaffs_GetBlockInfo(dev, i);
+			if (b->blockState == YAFFS_BLOCK_STATE_FULL &&
+			    (b->pagesInUse - b->softDeletions) <
+			    dev->nChunksPerBlock && b->sequenceNumber < seq) {
+				seq = b->sequenceNumber;
+			}
+		}
+		dev->oldestDirtySequence = seq;
+	}
+
+	/* Can't do gc of this block if there are any blocks older than this one that have
+	 * discarded pages.
+	 */
+	return (bi->sequenceNumber <= dev->oldestDirtySequence);
+}
+
+/* FindDiretiestBlock is used to select the dirtiest block (or close enough)
+ * for garbage collection.
+ */
+
+static int yaffs_FindBlockForGarbageCollection(yaffs_Device *dev,
+					int aggressive)
+{
+	int b = dev->currentDirtyChecker;
+
+	int i;
+	int iterations;
+	int dirtiest = -1;
+	int pagesInUse = 0;
+	int prioritised = 0;
+	yaffs_BlockInfo *bi;
+	int pendingPrioritisedExist = 0;
+
+	/* First let's see if we need to grab a prioritised block */
+	if (dev->hasPendingPrioritisedGCs) {
+		for (i = dev->internalStartBlock; i < dev->internalEndBlock && !prioritised; i++) {
+
+			bi = yaffs_GetBlockInfo(dev, i);
+			/* yaffs_VerifyBlock(dev,bi,i); */
+
+			if (bi->gcPrioritise) {
+				pendingPrioritisedExist = 1;
+				if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
+				   yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
+					pagesInUse = (bi->pagesInUse - bi->softDeletions);
+					dirtiest = i;
+					prioritised = 1;
+					aggressive = 1; /* Fool the non-aggressive skip logiv below */
+				}
+			}
+		}
+
+		if (!pendingPrioritisedExist) /* None found, so we can clear this */
+			dev->hasPendingPrioritisedGCs = 0;
+	}
+
+	/* If we're doing aggressive GC then we are happy to take a less-dirty block, and
+	 * search harder.
+	 * else (we're doing a leasurely gc), then we only bother to do this if the
+	 * block has only a few pages in use.
+	 */
+
+	dev->nonAggressiveSkip--;
+
+	if (!aggressive && (dev->nonAggressiveSkip > 0))
+		return -1;
+
+	if (!prioritised)
+		pagesInUse =
+			(aggressive) ? dev->nChunksPerBlock : YAFFS_PASSIVE_GC_CHUNKS + 1;
+
+	if (aggressive)
+		iterations =
+		    dev->internalEndBlock - dev->internalStartBlock + 1;
+	else {
+		iterations =
+		    dev->internalEndBlock - dev->internalStartBlock + 1;
+		iterations = iterations / 16;
+		if (iterations > 200)
+			iterations = 200;
+	}
+
+	for (i = 0; i <= iterations && pagesInUse > 0 && !prioritised; i++) {
+		b++;
+		if (b < dev->internalStartBlock || b > dev->internalEndBlock)
+			b = dev->internalStartBlock;
+
+		if (b < dev->internalStartBlock || b > dev->internalEndBlock) {
+			T(YAFFS_TRACE_ERROR,
+			  (TSTR("**>> Block %d is not valid" TENDSTR), b));
+			YBUG();
+		}
+
+		bi = yaffs_GetBlockInfo(dev, b);
+
+		if (bi->blockState == YAFFS_BLOCK_STATE_FULL &&
+			(bi->pagesInUse - bi->softDeletions) < pagesInUse &&
+				yaffs_BlockNotDisqualifiedFromGC(dev, bi)) {
+			dirtiest = b;
+			pagesInUse = (bi->pagesInUse - bi->softDeletions);
+		}
+	}
+
+	dev->currentDirtyChecker = b;
+
+	if (dirtiest > 0) {
+		T(YAFFS_TRACE_GC,
+		  (TSTR("GC Selected block %d with %d free, prioritised:%d" TENDSTR), dirtiest,
+		   dev->nChunksPerBlock - pagesInUse, prioritised));
+	}
+
+	dev->oldestDirtySequence = 0;
+
+	if (dirtiest > 0)
+		dev->nonAggressiveSkip = 4;
+
+	return dirtiest;
+}
+
+static void yaffs_BlockBecameDirty(yaffs_Device *dev, int blockNo)
+{
+	yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, blockNo);
+
+	int erasedOk = 0;
+
+	/* If the block is still healthy erase it and mark as clean.
+	 * If the block has had a data failure, then retire it.
+	 */
+
+	T(YAFFS_TRACE_GC | YAFFS_TRACE_ERASE,
+		(TSTR("yaffs_BlockBecameDirty block %d state %d %s"TENDSTR),
+		blockNo, bi->blockState, (bi->needsRetiring) ? "needs retiring" : ""));
+
+	bi->blockState = YAFFS_BLOCK_STATE_DIRTY;
+
+	if (!bi->needsRetiring) {
+		yaffs_InvalidateCheckpoint(dev);
+		erasedOk = yaffs_EraseBlockInNAND(dev, blockNo);
+		if (!erasedOk) {
+			dev->nErasureFailures++;
+			T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+			  (TSTR("**>> Erasure failed %d" TENDSTR), blockNo));
+		}
+	}
+
+	if (erasedOk &&
+	    ((yaffs_traceMask & YAFFS_TRACE_ERASE) || !yaffs_SkipVerification(dev))) {
+		int i;
+		for (i = 0; i < dev->nChunksPerBlock; i++) {
+			if (!yaffs_CheckChunkErased
+			    (dev, blockNo * dev->nChunksPerBlock + i)) {
+				T(YAFFS_TRACE_ERROR,
+				  (TSTR
+				   (">>Block %d erasure supposedly OK, but chunk %d not erased"
+				    TENDSTR), blockNo, i));
+			}
+		}
+	}
+
+	if (erasedOk) {
+		/* Clean it up... */
+		bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
+		dev->nErasedBlocks++;
+		bi->pagesInUse = 0;
+		bi->softDeletions = 0;
+		bi->hasShrinkHeader = 0;
+		bi->skipErasedCheck = 1;  /* This is clean, so no need to check */
+		bi->gcPrioritise = 0;
+		yaffs_ClearChunkBits(dev, blockNo);
+
+		T(YAFFS_TRACE_ERASE,
+		  (TSTR("Erased block %d" TENDSTR), blockNo));
+	} else {
+		dev->nFreeChunks -= dev->nChunksPerBlock;	/* We lost a block of free space */
+
+		yaffs_RetireBlock(dev, blockNo);
+		T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+		  (TSTR("**>> Block %d retired" TENDSTR), blockNo));
+	}
+}
+
+static int yaffs_FindBlockForAllocation(yaffs_Device *dev)
+{
+	int i;
+
+	yaffs_BlockInfo *bi;
+
+	if (dev->nErasedBlocks < 1) {
+		/* Hoosterman we've got a problem.
+		 * Can't get space to gc
+		 */
+		T(YAFFS_TRACE_ERROR,
+		  (TSTR("yaffs tragedy: no more erased blocks" TENDSTR)));
+
+		return -1;
+	}
+
+	/* Find an empty block. */
+
+	for (i = dev->internalStartBlock; i <= dev->internalEndBlock; i++) {
+		dev->allocationBlockFinder++;
+		if (dev->allocationBlockFinder < dev->internalStartBlock
+		    || dev->allocationBlockFinder > dev->internalEndBlock) {
+			dev->allocationBlockFinder = dev->internalStartBlock;
+		}
+
+		bi = yaffs_GetBlockInfo(dev, dev->allocationBlockFinder);
+
+		if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY) {
+			bi->blockState = YAFFS_BLOCK_STATE_ALLOCATING;
+			dev->sequenceNumber++;
+			bi->sequenceNumber = dev->sequenceNumber;
+			dev->nErasedBlocks--;
+			T(YAFFS_TRACE_ALLOCATE,
+			  (TSTR("Allocated block %d, seq  %d, %d left" TENDSTR),
+			   dev->allocationBlockFinder, dev->sequenceNumber,
+			   dev->nErasedBlocks));
+			return dev->allocationBlockFinder;
+		}
+	}
+
+	T(YAFFS_TRACE_ALWAYS,
+	  (TSTR
+	   ("yaffs tragedy: no more erased blocks, but there should have been %d"
+	    TENDSTR), dev->nErasedBlocks));
+
+	return -1;
+}
+
+
+
+static int yaffs_CalcCheckpointBlocksRequired(yaffs_Device *dev)
+{
+	if (!dev->nCheckpointBlocksRequired &&
+	   dev->isYaffs2) {
+		/* Not a valid value so recalculate */
+		int nBytes = 0;
+		int nBlocks;
+		int devBlocks = (dev->endBlock - dev->startBlock + 1);
+		int tnodeSize;
+
+		tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
+
+		if (tnodeSize < sizeof(yaffs_Tnode))
+			tnodeSize = sizeof(yaffs_Tnode);
+
+		nBytes += sizeof(yaffs_CheckpointValidity);
+		nBytes += sizeof(yaffs_CheckpointDevice);
+		nBytes += devBlocks * sizeof(yaffs_BlockInfo);
+		nBytes += devBlocks * dev->chunkBitmapStride;
+		nBytes += (sizeof(yaffs_CheckpointObject) + sizeof(__u32)) * (dev->nObjectsCreated - dev->nFreeObjects);
+		nBytes += (tnodeSize + sizeof(__u32)) * (dev->nTnodesCreated - dev->nFreeTnodes);
+		nBytes += sizeof(yaffs_CheckpointValidity);
+		nBytes += sizeof(__u32); /* checksum*/
+
+		/* Round up and add 2 blocks to allow for some bad blocks, so add 3 */
+
+		nBlocks = (nBytes/(dev->nDataBytesPerChunk * dev->nChunksPerBlock)) + 3;
+
+		dev->nCheckpointBlocksRequired = nBlocks;
+	}
+
+	return dev->nCheckpointBlocksRequired;
+}
+
+/*
+ * Check if there's space to allocate...
+ * Thinks.... do we need top make this ths same as yaffs_GetFreeChunks()?
+ */
+static int yaffs_CheckSpaceForAllocation(yaffs_Device *dev)
+{
+	int reservedChunks;
+	int reservedBlocks = dev->nReservedBlocks;
+	int checkpointBlocks;
+
+	if (dev->isYaffs2) {
+		checkpointBlocks =  yaffs_CalcCheckpointBlocksRequired(dev) -
+				    dev->blocksInCheckpoint;
+		if (checkpointBlocks < 0)
+			checkpointBlocks = 0;
+	} else {
+		checkpointBlocks = 0;
+	}
+
+	reservedChunks = ((reservedBlocks + checkpointBlocks) * dev->nChunksPerBlock);
+
+	return (dev->nFreeChunks > reservedChunks);
+}
+
+static int yaffs_AllocateChunk(yaffs_Device *dev, int useReserve,
+		yaffs_BlockInfo **blockUsedPtr)
+{
+	int retVal;
+	yaffs_BlockInfo *bi;
+
+	if (dev->allocationBlock < 0) {
+		/* Get next block to allocate off */
+		dev->allocationBlock = yaffs_FindBlockForAllocation(dev);
+		dev->allocationPage = 0;
+	}
+
+	if (!useReserve && !yaffs_CheckSpaceForAllocation(dev)) {
+		/* Not enough space to allocate unless we're allowed to use the reserve. */
+		return -1;
+	}
+
+	if (dev->nErasedBlocks < dev->nReservedBlocks
+			&& dev->allocationPage == 0) {
+		T(YAFFS_TRACE_ALLOCATE, (TSTR("Allocating reserve" TENDSTR)));
+	}
+
+	/* Next page please.... */
+	if (dev->allocationBlock >= 0) {
+		bi = yaffs_GetBlockInfo(dev, dev->allocationBlock);
+
+		retVal = (dev->allocationBlock * dev->nChunksPerBlock) +
+			dev->allocationPage;
+		bi->pagesInUse++;
+		yaffs_SetChunkBit(dev, dev->allocationBlock,
+				dev->allocationPage);
+
+		dev->allocationPage++;
+
+		dev->nFreeChunks--;
+
+		/* If the block is full set the state to full */
+		if (dev->allocationPage >= dev->nChunksPerBlock) {
+			bi->blockState = YAFFS_BLOCK_STATE_FULL;
+			dev->allocationBlock = -1;
+		}
+
+		if (blockUsedPtr)
+			*blockUsedPtr = bi;
+
+		return retVal;
+	}
+
+	T(YAFFS_TRACE_ERROR,
+			(TSTR("!!!!!!!!! Allocator out !!!!!!!!!!!!!!!!!" TENDSTR)));
+
+	return -1;
+}
+
+static int yaffs_GetErasedChunks(yaffs_Device *dev)
+{
+	int n;
+
+	n = dev->nErasedBlocks * dev->nChunksPerBlock;
+
+	if (dev->allocationBlock > 0)
+		n += (dev->nChunksPerBlock - dev->allocationPage);
+
+	return n;
+
+}
+
+static int yaffs_GarbageCollectBlock(yaffs_Device *dev, int block,
+		int wholeBlock)
+{
+	int oldChunk;
+	int newChunk;
+	int markNAND;
+	int retVal = YAFFS_OK;
+	int cleanups = 0;
+	int i;
+	int isCheckpointBlock;
+	int matchingChunk;
+	int maxCopies;
+
+	int chunksBefore = yaffs_GetErasedChunks(dev);
+	int chunksAfter;
+
+	yaffs_ExtendedTags tags;
+
+	yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, block);
+
+	yaffs_Object *object;
+
+	isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
+
+	bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
+
+	T(YAFFS_TRACE_TRACING,
+			(TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
+			 block,
+			 bi->pagesInUse,
+			 bi->hasShrinkHeader,
+			 wholeBlock));
+
+	/*yaffs_VerifyFreeChunks(dev); */
+
+	bi->hasShrinkHeader = 0;	/* clear the flag so that the block can erase */
+
+	/* Take off the number of soft deleted entries because
+	 * they're going to get really deleted during GC.
+	 */
+	if(dev->gcChunk == 0) /* first time through for this block */
+		dev->nFreeChunks -= bi->softDeletions;
+
+	dev->isDoingGC = 1;
+
+	if (isCheckpointBlock ||
+			!yaffs_StillSomeChunkBits(dev, block)) {
+		T(YAFFS_TRACE_TRACING,
+				(TSTR
+				 ("Collecting block %d that has no chunks in use" TENDSTR),
+				 block));
+		yaffs_BlockBecameDirty(dev, block);
+	} else {
+
+		__u8 *buffer = yaffs_GetTempBuffer(dev, __LINE__);
+
+		yaffs_VerifyBlock(dev, bi, block);
+
+		maxCopies = (wholeBlock) ? dev->nChunksPerBlock : 10;
+		oldChunk = block * dev->nChunksPerBlock + dev->gcChunk;
+
+		for (/* init already done */;
+		     retVal == YAFFS_OK &&
+		     dev->gcChunk < dev->nChunksPerBlock &&
+		     (bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) &&
+		     maxCopies > 0;
+		     dev->gcChunk++, oldChunk++) {
+			if (yaffs_CheckChunkBit(dev, block, dev->gcChunk)) {
+
+				/* This page is in use and might need to be copied off */
+
+				maxCopies--;
+
+				markNAND = 1;
+
+				yaffs_InitialiseTags(&tags);
+
+				yaffs_ReadChunkWithTagsFromNAND(dev, oldChunk,
+								buffer, &tags);
+
+				object =
+				    yaffs_FindObjectByNumber(dev,
+							     tags.objectId);
+
+				T(YAFFS_TRACE_GC_DETAIL,
+				  (TSTR
+				   ("Collecting chunk in block %d, %d %d %d " TENDSTR),
+				   dev->gcChunk, tags.objectId, tags.chunkId,
+				   tags.byteCount));
+
+				if (object && !yaffs_SkipVerification(dev)) {
+					if (tags.chunkId == 0)
+						matchingChunk = object->hdrChunk;
+					else if (object->softDeleted)
+						matchingChunk = oldChunk; /* Defeat the test */
+					else
+						matchingChunk = yaffs_FindChunkInFile(object, tags.chunkId, NULL);
+
+					if (oldChunk != matchingChunk)
+						T(YAFFS_TRACE_ERROR,
+						  (TSTR("gc: page in gc mismatch: %d %d %d %d"TENDSTR),
+						  oldChunk, matchingChunk, tags.objectId, tags.chunkId));
+
+				}
+
+				if (!object) {
+					T(YAFFS_TRACE_ERROR,
+					  (TSTR
+					   ("page %d in gc has no object: %d %d %d "
+					    TENDSTR), oldChunk,
+					    tags.objectId, tags.chunkId, tags.byteCount));
+				}
+
+				if (object &&
+				    object->deleted &&
+				    object->softDeleted &&
+				    tags.chunkId != 0) {
+					/* Data chunk in a soft deleted file, throw it away
+					 * It's a soft deleted data chunk,
+					 * No need to copy this, just forget about it and
+					 * fix up the object.
+					 */
+
+					object->nDataChunks--;
+
+					if (object->nDataChunks <= 0) {
+						/* remeber to clean up the object */
+						dev->gcCleanupList[cleanups] =
+						    tags.objectId;
+						cleanups++;
+					}
+					markNAND = 0;
+				} else if (0) {
+					/* Todo object && object->deleted && object->nDataChunks == 0 */
+					/* Deleted object header with no data chunks.
+					 * Can be discarded and the file deleted.
+					 */
+					object->hdrChunk = 0;
+					yaffs_FreeTnode(object->myDev,
+							object->variant.
+							fileVariant.top);
+					object->variant.fileVariant.top = NULL;
+					yaffs_DoGenericObjectDeletion(object);
+
+				} else if (object) {
+					/* It's either a data chunk in a live file or
+					 * an ObjectHeader, so we're interested in it.
+					 * NB Need to keep the ObjectHeaders of deleted files
+					 * until the whole file has been deleted off
+					 */
+					tags.serialNumber++;
+
+					dev->nGCCopies++;
+
+					if (tags.chunkId == 0) {
+						/* It is an object Id,
+						 * We need to nuke the shrinkheader flags first
+						 * We no longer want the shrinkHeader flag since its work is done
+						 * and if it is left in place it will mess up scanning.
+						 */
+
+						yaffs_ObjectHeader *oh;
+						oh = (yaffs_ObjectHeader *)buffer;
+						oh->isShrink = 0;
+						tags.extraIsShrinkHeader = 0;
+
+						yaffs_VerifyObjectHeader(object, oh, &tags, 1);
+					}
+
+					newChunk =
+					    yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &tags, 1);
+
+					if (newChunk < 0) {
+						retVal = YAFFS_FAIL;
+					} else {
+
+						/* Ok, now fix up the Tnodes etc. */
+
+						if (tags.chunkId == 0) {
+							/* It's a header */
+							object->hdrChunk =  newChunk;
+							object->serial =   tags.serialNumber;
+						} else {
+							/* It's a data chunk */
+							yaffs_PutChunkIntoFile
+							    (object,
+							     tags.chunkId,
+							     newChunk, 0);
+						}
+					}
+				}
+
+				if (retVal == YAFFS_OK)
+					yaffs_DeleteChunk(dev, oldChunk, markNAND, __LINE__);
+
+			}
+		}
+
+		yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+
+
+		/* Do any required cleanups */
+		for (i = 0; i < cleanups; i++) {
+			/* Time to delete the file too */
+			object =
+			    yaffs_FindObjectByNumber(dev,
+						     dev->gcCleanupList[i]);
+			if (object) {
+				yaffs_FreeTnode(dev,
+						object->variant.fileVariant.
+						top);
+				object->variant.fileVariant.top = NULL;
+				T(YAFFS_TRACE_GC,
+				  (TSTR
+				   ("yaffs: About to finally delete object %d"
+				    TENDSTR), object->objectId));
+				yaffs_DoGenericObjectDeletion(object);
+				object->myDev->nDeletedFiles--;
+			}
+
+		}
+
+	}
+
+	yaffs_VerifyCollectedBlock(dev, bi, block);
+
+	chunksAfter = yaffs_GetErasedChunks(dev);
+	if (chunksBefore >= chunksAfter) {
+		T(YAFFS_TRACE_GC,
+		  (TSTR
+		   ("gc did not increase free chunks before %d after %d"
+		    TENDSTR), chunksBefore, chunksAfter));
+	}
+
+	/* If the gc completed then clear the current gcBlock so that we find another. */
+	if (bi->blockState != YAFFS_BLOCK_STATE_COLLECTING) {
+		dev->gcBlock = -1;
+		dev->gcChunk = 0;
+	}
+
+	dev->isDoingGC = 0;
+
+	return retVal;
+}
+
+/* New garbage collector
+ * If we're very low on erased blocks then we do aggressive garbage collection
+ * otherwise we do "leasurely" garbage collection.
+ * Aggressive gc looks further (whole array) and will accept less dirty blocks.
+ * Passive gc only inspects smaller areas and will only accept more dirty blocks.
+ *
+ * The idea is to help clear out space in a more spread-out manner.
+ * Dunno if it really does anything useful.
+ */
+static int yaffs_CheckGarbageCollection(yaffs_Device *dev)
+{
+	int block;
+	int aggressive;
+	int gcOk = YAFFS_OK;
+	int maxTries = 0;
+
+	int checkpointBlockAdjust;
+
+	if (dev->isDoingGC) {
+		/* Bail out so we don't get recursive gc */
+		return YAFFS_OK;
+	}
+
+	/* This loop should pass the first time.
+	 * We'll only see looping here if the erase of the collected block fails.
+	 */
+
+	do {
+		maxTries++;
+
+		checkpointBlockAdjust = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
+		if (checkpointBlockAdjust < 0)
+			checkpointBlockAdjust = 0;
+
+		if (dev->nErasedBlocks < (dev->nReservedBlocks + checkpointBlockAdjust + 2)) {
+			/* We need a block soon...*/
+			aggressive = 1;
+		} else {
+			/* We're in no hurry */
+			aggressive = 0;
+		}
+
+		if (dev->gcBlock <= 0) {
+			dev->gcBlock = yaffs_FindBlockForGarbageCollection(dev, aggressive);
+			dev->gcChunk = 0;
+		}
+
+		block = dev->gcBlock;
+
+		if (block > 0) {
+			dev->garbageCollections++;
+			if (!aggressive)
+				dev->passiveGarbageCollections++;
+
+			T(YAFFS_TRACE_GC,
+			  (TSTR
+			   ("yaffs: GC erasedBlocks %d aggressive %d" TENDSTR),
+			   dev->nErasedBlocks, aggressive));
+
+			gcOk = yaffs_GarbageCollectBlock(dev, block, aggressive);
+		}
+
+		if (dev->nErasedBlocks < (dev->nReservedBlocks) && block > 0) {
+			T(YAFFS_TRACE_GC,
+			  (TSTR
+			   ("yaffs: GC !!!no reclaim!!! erasedBlocks %d after try %d block %d"
+			    TENDSTR), dev->nErasedBlocks, maxTries, block));
+		}
+	} while ((dev->nErasedBlocks < dev->nReservedBlocks) &&
+		 (block > 0) &&
+		 (maxTries < 2));
+
+	return aggressive ? gcOk : YAFFS_OK;
+}
+
+/*-------------------------  TAGS --------------------------------*/
+
+static int yaffs_TagsMatch(const yaffs_ExtendedTags *tags, int objectId,
+			   int chunkInObject)
+{
+	return (tags->chunkId == chunkInObject &&
+		tags->objectId == objectId && !tags->chunkDeleted) ? 1 : 0;
+
+}
+
+
+/*-------------------- Data file manipulation -----------------*/
+
+static int yaffs_FindChunkInFile(yaffs_Object *in, int chunkInInode,
+				 yaffs_ExtendedTags *tags)
+{
+	/*Get the Tnode, then get the level 0 offset chunk offset */
+	yaffs_Tnode *tn;
+	int theChunk = -1;
+	yaffs_ExtendedTags localTags;
+	int retVal = -1;
+
+	yaffs_Device *dev = in->myDev;
+
+	if (!tags) {
+		/* Passed a NULL, so use our own tags space */
+		tags = &localTags;
+	}
+
+	tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
+
+	if (tn) {
+		theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
+
+		retVal =
+		    yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
+					   chunkInInode);
+	}
+	return retVal;
+}
+
+static int yaffs_FindAndDeleteChunkInFile(yaffs_Object *in, int chunkInInode,
+					  yaffs_ExtendedTags *tags)
+{
+	/* Get the Tnode, then get the level 0 offset chunk offset */
+	yaffs_Tnode *tn;
+	int theChunk = -1;
+	yaffs_ExtendedTags localTags;
+
+	yaffs_Device *dev = in->myDev;
+	int retVal = -1;
+
+	if (!tags) {
+		/* Passed a NULL, so use our own tags space */
+		tags = &localTags;
+	}
+
+	tn = yaffs_FindLevel0Tnode(dev, &in->variant.fileVariant, chunkInInode);
+
+	if (tn) {
+
+		theChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
+
+		retVal =
+		    yaffs_FindChunkInGroup(dev, theChunk, tags, in->objectId,
+					   chunkInInode);
+
+		/* Delete the entry in the filestructure (if found) */
+		if (retVal != -1)
+			yaffs_PutLevel0Tnode(dev, tn, chunkInInode, 0);
+	}
+
+	return retVal;
+}
+
+#ifdef YAFFS_PARANOID
+
+static int yaffs_CheckFileSanity(yaffs_Object *in)
+{
+	int chunk;
+	int nChunks;
+	int fSize;
+	int failed = 0;
+	int objId;
+	yaffs_Tnode *tn;
+	yaffs_Tags localTags;
+	yaffs_Tags *tags = &localTags;
+	int theChunk;
+	int chunkDeleted;
+
+	if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
+		return YAFFS_FAIL;
+
+	objId = in->objectId;
+	fSize = in->variant.fileVariant.fileSize;
+	nChunks =
+	    (fSize + in->myDev->nDataBytesPerChunk - 1) / in->myDev->nDataBytesPerChunk;
+
+	for (chunk = 1; chunk <= nChunks; chunk++) {
+		tn = yaffs_FindLevel0Tnode(in->myDev, &in->variant.fileVariant,
+					   chunk);
+
+		if (tn) {
+
+			theChunk = yaffs_GetChunkGroupBase(dev, tn, chunk);
+
+			if (yaffs_CheckChunkBits
+			    (dev, theChunk / dev->nChunksPerBlock,
+			     theChunk % dev->nChunksPerBlock)) {
+
+				yaffs_ReadChunkTagsFromNAND(in->myDev, theChunk,
+							    tags,
+							    &chunkDeleted);
+				if (yaffs_TagsMatch
+				    (tags, in->objectId, chunk, chunkDeleted)) {
+					/* found it; */
+
+				}
+			} else {
+
+				failed = 1;
+			}
+
+		} else {
+			/* T(("No level 0 found for %d\n", chunk)); */
+		}
+	}
+
+	return failed ? YAFFS_FAIL : YAFFS_OK;
+}
+
+#endif
+
+static int yaffs_PutChunkIntoFile(yaffs_Object *in, int chunkInInode,
+				  int chunkInNAND, int inScan)
+{
+	/* NB inScan is zero unless scanning.
+	 * For forward scanning, inScan is > 0;
+	 * for backward scanning inScan is < 0
+	 */
+
+	yaffs_Tnode *tn;
+	yaffs_Device *dev = in->myDev;
+	int existingChunk;
+	yaffs_ExtendedTags existingTags;
+	yaffs_ExtendedTags newTags;
+	unsigned existingSerial, newSerial;
+
+	if (in->variantType != YAFFS_OBJECT_TYPE_FILE) {
+		/* Just ignore an attempt at putting a chunk into a non-file during scanning
+		 * If it is not during Scanning then something went wrong!
+		 */
+		if (!inScan) {
+			T(YAFFS_TRACE_ERROR,
+			  (TSTR
+			   ("yaffs tragedy:attempt to put data chunk into a non-file"
+			    TENDSTR)));
+			YBUG();
+		}
+
+		yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
+		return YAFFS_OK;
+	}
+
+	tn = yaffs_AddOrFindLevel0Tnode(dev,
+					&in->variant.fileVariant,
+					chunkInInode,
+					NULL);
+	if (!tn)
+		return YAFFS_FAIL;
+
+	existingChunk = yaffs_GetChunkGroupBase(dev, tn, chunkInInode);
+
+	if (inScan != 0) {
+		/* If we're scanning then we need to test for duplicates
+		 * NB This does not need to be efficient since it should only ever
+		 * happen when the power fails during a write, then only one
+		 * chunk should ever be affected.
+		 *
+		 * Correction for YAFFS2: This could happen quite a lot and we need to think about efficiency! TODO
+		 * Update: For backward scanning we don't need to re-read tags so this is quite cheap.
+		 */
+
+		if (existingChunk > 0) {
+			/* NB Right now existing chunk will not be real chunkId if the device >= 32MB
+			 *    thus we have to do a FindChunkInFile to get the real chunk id.
+			 *
+			 * We have a duplicate now we need to decide which one to use:
+			 *
+			 * Backwards scanning YAFFS2: The old one is what we use, dump the new one.
+			 * Forward scanning YAFFS2: The new one is what we use, dump the old one.
+			 * YAFFS1: Get both sets of tags and compare serial numbers.
+			 */
+
+			if (inScan > 0) {
+				/* Only do this for forward scanning */
+				yaffs_ReadChunkWithTagsFromNAND(dev,
+								chunkInNAND,
+								NULL, &newTags);
+
+				/* Do a proper find */
+				existingChunk =
+				    yaffs_FindChunkInFile(in, chunkInInode,
+							  &existingTags);
+			}
+
+			if (existingChunk <= 0) {
+				/*Hoosterman - how did this happen? */
+
+				T(YAFFS_TRACE_ERROR,
+				  (TSTR
+				   ("yaffs tragedy: existing chunk < 0 in scan"
+				    TENDSTR)));
+
+			}
+
+			/* NB The deleted flags should be false, otherwise the chunks will
+			 * not be loaded during a scan
+			 */
+
+			if (inScan > 0) {
+				newSerial = newTags.serialNumber;
+				existingSerial = existingTags.serialNumber;
+			}
+
+			if ((inScan > 0) &&
+			    (in->myDev->isYaffs2 ||
+			     existingChunk <= 0 ||
+			     ((existingSerial + 1) & 3) == newSerial)) {
+				/* Forward scanning.
+				 * Use new
+				 * Delete the old one and drop through to update the tnode
+				 */
+				yaffs_DeleteChunk(dev, existingChunk, 1,
+						  __LINE__);
+			} else {
+				/* Backward scanning or we want to use the existing one
+				 * Use existing.
+				 * Delete the new one and return early so that the tnode isn't changed
+				 */
+				yaffs_DeleteChunk(dev, chunkInNAND, 1,
+						  __LINE__);
+				return YAFFS_OK;
+			}
+		}
+
+	}
+
+	if (existingChunk == 0)
+		in->nDataChunks++;
+
+	yaffs_PutLevel0Tnode(dev, tn, chunkInInode, chunkInNAND);
+
+	return YAFFS_OK;
+}
+
+static int yaffs_ReadChunkDataFromObject(yaffs_Object *in, int chunkInInode,
+					__u8 *buffer)
+{
+	int chunkInNAND = yaffs_FindChunkInFile(in, chunkInInode, NULL);
+
+	if (chunkInNAND >= 0)
+		return yaffs_ReadChunkWithTagsFromNAND(in->myDev, chunkInNAND,
+						buffer, NULL);
+	else {
+		T(YAFFS_TRACE_NANDACCESS,
+		  (TSTR("Chunk %d not found zero instead" TENDSTR),
+		   chunkInNAND));
+		/* get sane (zero) data if you read a hole */
+		memset(buffer, 0, in->myDev->nDataBytesPerChunk);
+		return 0;
+	}
+
+}
+
+void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn)
+{
+	int block;
+	int page;
+	yaffs_ExtendedTags tags;
+	yaffs_BlockInfo *bi;
+
+	if (chunkId <= 0)
+		return;
+
+	dev->nDeletions++;
+	block = chunkId / dev->nChunksPerBlock;
+	page = chunkId % dev->nChunksPerBlock;
+
+
+	if (!yaffs_CheckChunkBit(dev, block, page))
+		T(YAFFS_TRACE_VERIFY,
+			(TSTR("Deleting invalid chunk %d"TENDSTR),
+			 chunkId));
+
+	bi = yaffs_GetBlockInfo(dev, block);
+
+	T(YAFFS_TRACE_DELETION,
+	  (TSTR("line %d delete of chunk %d" TENDSTR), lyn, chunkId));
+
+	if (markNAND &&
+	    bi->blockState != YAFFS_BLOCK_STATE_COLLECTING && !dev->isYaffs2) {
+
+		yaffs_InitialiseTags(&tags);
+
+		tags.chunkDeleted = 1;
+
+		yaffs_WriteChunkWithTagsToNAND(dev, chunkId, NULL, &tags);
+		yaffs_HandleUpdateChunk(dev, chunkId, &tags);
+	} else {
+		dev->nUnmarkedDeletions++;
+	}
+
+	/* Pull out of the management area.
+	 * If the whole block became dirty, this will kick off an erasure.
+	 */
+	if (bi->blockState == YAFFS_BLOCK_STATE_ALLOCATING ||
+	    bi->blockState == YAFFS_BLOCK_STATE_FULL ||
+	    bi->blockState == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+	    bi->blockState == YAFFS_BLOCK_STATE_COLLECTING) {
+		dev->nFreeChunks++;
+
+		yaffs_ClearChunkBit(dev, block, page);
+
+		bi->pagesInUse--;
+
+		if (bi->pagesInUse == 0 &&
+		    !bi->hasShrinkHeader &&
+		    bi->blockState != YAFFS_BLOCK_STATE_ALLOCATING &&
+		    bi->blockState != YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+			yaffs_BlockBecameDirty(dev, block);
+		}
+
+	}
+
+}
+
+static int yaffs_WriteChunkDataToObject(yaffs_Object *in, int chunkInInode,
+					const __u8 *buffer, int nBytes,
+					int useReserve)
+{
+	/* Find old chunk Need to do this to get serial number
+	 * Write new one and patch into tree.
+	 * Invalidate old tags.
+	 */
+
+	int prevChunkId;
+	yaffs_ExtendedTags prevTags;
+
+	int newChunkId;
+	yaffs_ExtendedTags newTags;
+
+	yaffs_Device *dev = in->myDev;
+
+	yaffs_CheckGarbageCollection(dev);
+
+	/* Get the previous chunk at this location in the file if it exists */
+	prevChunkId = yaffs_FindChunkInFile(in, chunkInInode, &prevTags);
+
+	/* Set up new tags */
+	yaffs_InitialiseTags(&newTags);
+
+	newTags.chunkId = chunkInInode;
+	newTags.objectId = in->objectId;
+	newTags.serialNumber =
+	    (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
+	newTags.byteCount = nBytes;
+
+	if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
+		T(YAFFS_TRACE_ERROR,
+		(TSTR("Writing %d bytes to chunk!!!!!!!!!" TENDSTR), nBytes));
+		YBUG();
+	}
+
+	newChunkId =
+	    yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
+					      useReserve);
+
+	if (newChunkId >= 0) {
+		yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
+
+		if (prevChunkId >= 0)
+			yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
+
+		yaffs_CheckFileSanity(in);
+	}
+	return newChunkId;
+
+}
+
+/* UpdateObjectHeader updates the header on NAND for an object.
+ * If name is not NULL, then that new name is used.
+ */
+int yaffs_UpdateObjectHeader(yaffs_Object *in, const YCHAR *name, int force,
+			     int isShrink, int shadows)
+{
+
+	yaffs_BlockInfo *bi;
+
+	yaffs_Device *dev = in->myDev;
+
+	int prevChunkId;
+	int retVal = 0;
+	int result = 0;
+
+	int newChunkId;
+	yaffs_ExtendedTags newTags;
+	yaffs_ExtendedTags oldTags;
+
+	__u8 *buffer = NULL;
+	YCHAR oldName[YAFFS_MAX_NAME_LENGTH + 1];
+
+	yaffs_ObjectHeader *oh = NULL;
+
+	yaffs_strcpy(oldName, _Y("silly old name"));
+
+
+	if (!in->fake ||
+		in == dev->rootDir || /* The rootDir should also be saved */
+		force) {
+
+		yaffs_CheckGarbageCollection(dev);
+		yaffs_CheckObjectDetailsLoaded(in);
+
+		buffer = yaffs_GetTempBuffer(in->myDev, __LINE__);
+		oh = (yaffs_ObjectHeader *) buffer;
+
+		prevChunkId = in->hdrChunk;
+
+		if (prevChunkId > 0) {
+			result = yaffs_ReadChunkWithTagsFromNAND(dev, prevChunkId,
+							buffer, &oldTags);
+
+			yaffs_VerifyObjectHeader(in, oh, &oldTags, 0);
+
+			memcpy(oldName, oh->name, sizeof(oh->name));
+		}
+
+		memset(buffer, 0xFF, dev->nDataBytesPerChunk);
+
+		oh->type = in->variantType;
+		oh->yst_mode = in->yst_mode;
+		oh->shadowsObject = oh->inbandShadowsObject = shadows;
+
+#ifdef CONFIG_YAFFS_WINCE
+		oh->win_atime[0] = in->win_atime[0];
+		oh->win_ctime[0] = in->win_ctime[0];
+		oh->win_mtime[0] = in->win_mtime[0];
+		oh->win_atime[1] = in->win_atime[1];
+		oh->win_ctime[1] = in->win_ctime[1];
+		oh->win_mtime[1] = in->win_mtime[1];
+#else
+		oh->yst_uid = in->yst_uid;
+		oh->yst_gid = in->yst_gid;
+		oh->yst_atime = in->yst_atime;
+		oh->yst_mtime = in->yst_mtime;
+		oh->yst_ctime = in->yst_ctime;
+		oh->yst_rdev = in->yst_rdev;
+#endif
+		if (in->parent)
+			oh->parentObjectId = in->parent->objectId;
+		else
+			oh->parentObjectId = 0;
+
+		if (name && *name) {
+			memset(oh->name, 0, sizeof(oh->name));
+			yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
+		} else if (prevChunkId >= 0)
+			memcpy(oh->name, oldName, sizeof(oh->name));
+		else
+			memset(oh->name, 0, sizeof(oh->name));
+
+		oh->isShrink = isShrink;
+
+		switch (in->variantType) {
+		case YAFFS_OBJECT_TYPE_UNKNOWN:
+			/* Should not happen */
+			break;
+		case YAFFS_OBJECT_TYPE_FILE:
+			oh->fileSize =
+			    (oh->parentObjectId == YAFFS_OBJECTID_DELETED
+			     || oh->parentObjectId ==
+			     YAFFS_OBJECTID_UNLINKED) ? 0 : in->variant.
+			    fileVariant.fileSize;
+			break;
+		case YAFFS_OBJECT_TYPE_HARDLINK:
+			oh->equivalentObjectId =
+			    in->variant.hardLinkVariant.equivalentObjectId;
+			break;
+		case YAFFS_OBJECT_TYPE_SPECIAL:
+			/* Do nothing */
+			break;
+		case YAFFS_OBJECT_TYPE_DIRECTORY:
+			/* Do nothing */
+			break;
+		case YAFFS_OBJECT_TYPE_SYMLINK:
+			yaffs_strncpy(oh->alias,
+				      in->variant.symLinkVariant.alias,
+				      YAFFS_MAX_ALIAS_LENGTH);
+			oh->alias[YAFFS_MAX_ALIAS_LENGTH] = 0;
+			break;
+		}
+
+		/* Tags */
+		yaffs_InitialiseTags(&newTags);
+		in->serial++;
+		newTags.chunkId = 0;
+		newTags.objectId = in->objectId;
+		newTags.serialNumber = in->serial;
+
+		/* Add extra info for file header */
+
+		newTags.extraHeaderInfoAvailable = 1;
+		newTags.extraParentObjectId = oh->parentObjectId;
+		newTags.extraFileLength = oh->fileSize;
+		newTags.extraIsShrinkHeader = oh->isShrink;
+		newTags.extraEquivalentObjectId = oh->equivalentObjectId;
+		newTags.extraShadows = (oh->shadowsObject > 0) ? 1 : 0;
+		newTags.extraObjectType = in->variantType;
+
+		yaffs_VerifyObjectHeader(in, oh, &newTags, 1);
+
+		/* Create new chunk in NAND */
+		newChunkId =
+		    yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
+						      (prevChunkId >= 0) ? 1 : 0);
+
+		if (newChunkId >= 0) {
+
+			in->hdrChunk = newChunkId;
+
+			if (prevChunkId >= 0) {
+				yaffs_DeleteChunk(dev, prevChunkId, 1,
+						  __LINE__);
+			}
+
+			if (!yaffs_ObjectHasCachedWriteData(in))
+				in->dirty = 0;
+
+			/* If this was a shrink, then mark the block that the chunk lives on */
+			if (isShrink) {
+				bi = yaffs_GetBlockInfo(in->myDev,
+					newChunkId / in->myDev->nChunksPerBlock);
+				bi->hasShrinkHeader = 1;
+			}
+
+		}
+
+		retVal = newChunkId;
+
+	}
+
+	if (buffer)
+		yaffs_ReleaseTempBuffer(dev, buffer, __LINE__);
+
+	return retVal;
+}
+
+/*------------------------ Short Operations Cache ----------------------------------------
+ *   In many situations where there is no high level buffering (eg WinCE) a lot of
+ *   reads might be short sequential reads, and a lot of writes may be short
+ *   sequential writes. eg. scanning/writing a jpeg file.
+ *   In these cases, a short read/write cache can provide a huge perfomance benefit
+ *   with dumb-as-a-rock code.
+ *   In Linux, the page cache provides read buffering aand the short op cache provides write
+ *   buffering.
+ *
+ *   There are a limited number (~10) of cache chunks per device so that we don't
+ *   need a very intelligent search.
+ */
+
+static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj)
+{
+	yaffs_Device *dev = obj->myDev;
+	int i;
+	yaffs_ChunkCache *cache;
+	int nCaches = obj->myDev->nShortOpCaches;
+
+	for (i = 0; i < nCaches; i++) {
+		cache = &dev->srCache[i];
+		if (cache->object == obj &&
+		    cache->dirty)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void yaffs_FlushFilesChunkCache(yaffs_Object *obj)
+{
+	yaffs_Device *dev = obj->myDev;
+	int lowest = -99;	/* Stop compiler whining. */
+	int i;
+	yaffs_ChunkCache *cache;
+	int chunkWritten = 0;
+	int nCaches = obj->myDev->nShortOpCaches;
+
+	if (nCaches > 0) {
+		do {
+			cache = NULL;
+
+			/* Find the dirty cache for this object with the lowest chunk id. */
+			for (i = 0; i < nCaches; i++) {
+				if (dev->srCache[i].object == obj &&
+				    dev->srCache[i].dirty) {
+					if (!cache
+					    || dev->srCache[i].chunkId <
+					    lowest) {
+						cache = &dev->srCache[i];
+						lowest = cache->chunkId;
+					}
+				}
+			}
+
+			if (cache && !cache->locked) {
+				/* Write it out and free it up */
+
+				chunkWritten =
+				    yaffs_WriteChunkDataToObject(cache->object,
+								 cache->chunkId,
+								 cache->data,
+								 cache->nBytes,
+								 1);
+				cache->dirty = 0;
+				cache->object = NULL;
+			}
+
+		} while (cache && chunkWritten > 0);
+
+		if (cache) {
+			/* Hoosterman, disk full while writing cache out. */
+			T(YAFFS_TRACE_ERROR,
+			  (TSTR("yaffs tragedy: no space during cache write" TENDSTR)));
+
+		}
+	}
+
+}
+
+/*yaffs_FlushEntireDeviceCache(dev)
+ *
+ *
+ */
+
+void yaffs_FlushEntireDeviceCache(yaffs_Device *dev)
+{
+	yaffs_Object *obj;
+	int nCaches = dev->nShortOpCaches;
+	int i;
+
+	/* Find a dirty object in the cache and flush it...
+	 * until there are no further dirty objects.
+	 */
+	do {
+		obj = NULL;
+		for (i = 0; i < nCaches && !obj; i++) {
+			if (dev->srCache[i].object &&
+			    dev->srCache[i].dirty)
+				obj = dev->srCache[i].object;
+
+		}
+		if (obj)
+			yaffs_FlushFilesChunkCache(obj);
+
+	} while (obj);
+
+}
+
+
+/* Grab us a cache chunk for use.
+ * First look for an empty one.
+ * Then look for the least recently used non-dirty one.
+ * Then look for the least recently used dirty one...., flush and look again.
+ */
+static yaffs_ChunkCache *yaffs_GrabChunkCacheWorker(yaffs_Device *dev)
+{
+	int i;
+
+	if (dev->nShortOpCaches > 0) {
+		for (i = 0; i < dev->nShortOpCaches; i++) {
+			if (!dev->srCache[i].object)
+				return &dev->srCache[i];
+		}
+	}
+
+	return NULL;
+}
+
+static yaffs_ChunkCache *yaffs_GrabChunkCache(yaffs_Device *dev)
+{
+	yaffs_ChunkCache *cache;
+	yaffs_Object *theObj;
+	int usage;
+	int i;
+	int pushout;
+
+	if (dev->nShortOpCaches > 0) {
+		/* Try find a non-dirty one... */
+
+		cache = yaffs_GrabChunkCacheWorker(dev);
+
+		if (!cache) {
+			/* They were all dirty, find the last recently used object and flush
+			 * its cache, then  find again.
+			 * NB what's here is not very accurate, we actually flush the object
+			 * the last recently used page.
+			 */
+
+			/* With locking we can't assume we can use entry zero */
+
+			theObj = NULL;
+			usage = -1;
+			cache = NULL;
+			pushout = -1;
+
+			for (i = 0; i < dev->nShortOpCaches; i++) {
+				if (dev->srCache[i].object &&
+				    !dev->srCache[i].locked &&
+				    (dev->srCache[i].lastUse < usage || !cache)) {
+					usage = dev->srCache[i].lastUse;
+					theObj = dev->srCache[i].object;
+					cache = &dev->srCache[i];
+					pushout = i;
+				}
+			}
+
+			if (!cache || cache->dirty) {
+				/* Flush and try again */
+				yaffs_FlushFilesChunkCache(theObj);
+				cache = yaffs_GrabChunkCacheWorker(dev);
+			}
+
+		}
+		return cache;
+	} else
+		return NULL;
+
+}
+
+/* Find a cached chunk */
+static yaffs_ChunkCache *yaffs_FindChunkCache(const yaffs_Object *obj,
+					      int chunkId)
+{
+	yaffs_Device *dev = obj->myDev;
+	int i;
+	if (dev->nShortOpCaches > 0) {
+		for (i = 0; i < dev->nShortOpCaches; i++) {
+			if (dev->srCache[i].object == obj &&
+			    dev->srCache[i].chunkId == chunkId) {
+				dev->cacheHits++;
+
+				return &dev->srCache[i];
+			}
+		}
+	}
+	return NULL;
+}
+
+/* Mark the chunk for the least recently used algorithym */
+static void yaffs_UseChunkCache(yaffs_Device *dev, yaffs_ChunkCache *cache,
+				int isAWrite)
+{
+
+	if (dev->nShortOpCaches > 0) {
+		if (dev->srLastUse < 0 || dev->srLastUse > 100000000) {
+			/* Reset the cache usages */
+			int i;
+			for (i = 1; i < dev->nShortOpCaches; i++)
+				dev->srCache[i].lastUse = 0;
+
+			dev->srLastUse = 0;
+		}
+
+		dev->srLastUse++;
+
+		cache->lastUse = dev->srLastUse;
+
+		if (isAWrite)
+			cache->dirty = 1;
+	}
+}
+
+/* Invalidate a single cache page.
+ * Do this when a whole page gets written,
+ * ie the short cache for this page is no longer valid.
+ */
+static void yaffs_InvalidateChunkCache(yaffs_Object *object, int chunkId)
+{
+	if (object->myDev->nShortOpCaches > 0) {
+		yaffs_ChunkCache *cache = yaffs_FindChunkCache(object, chunkId);
+
+		if (cache)
+			cache->object = NULL;
+	}
+}
+
+/* Invalidate all the cache pages associated with this object
+ * Do this whenever ther file is deleted or resized.
+ */
+static void yaffs_InvalidateWholeChunkCache(yaffs_Object *in)
+{
+	int i;
+	yaffs_Device *dev = in->myDev;
+
+	if (dev->nShortOpCaches > 0) {
+		/* Invalidate it. */
+		for (i = 0; i < dev->nShortOpCaches; i++) {
+			if (dev->srCache[i].object == in)
+				dev->srCache[i].object = NULL;
+		}
+	}
+}
+
+/*--------------------- Checkpointing --------------------*/
+
+
+static int yaffs_WriteCheckpointValidityMarker(yaffs_Device *dev, int head)
+{
+	yaffs_CheckpointValidity cp;
+
+	memset(&cp, 0, sizeof(cp));
+
+	cp.structType = sizeof(cp);
+	cp.magic = YAFFS_MAGIC;
+	cp.version = YAFFS_CHECKPOINT_VERSION;
+	cp.head = (head) ? 1 : 0;
+
+	return (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp)) ?
+		1 : 0;
+}
+
+static int yaffs_ReadCheckpointValidityMarker(yaffs_Device *dev, int head)
+{
+	yaffs_CheckpointValidity cp;
+	int ok;
+
+	ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+	if (ok)
+		ok = (cp.structType == sizeof(cp)) &&
+		     (cp.magic == YAFFS_MAGIC) &&
+		     (cp.version == YAFFS_CHECKPOINT_VERSION) &&
+		     (cp.head == ((head) ? 1 : 0));
+	return ok ? 1 : 0;
+}
+
+static void yaffs_DeviceToCheckpointDevice(yaffs_CheckpointDevice *cp,
+					   yaffs_Device *dev)
+{
+	cp->nErasedBlocks = dev->nErasedBlocks;
+	cp->allocationBlock = dev->allocationBlock;
+	cp->allocationPage = dev->allocationPage;
+	cp->nFreeChunks = dev->nFreeChunks;
+
+	cp->nDeletedFiles = dev->nDeletedFiles;
+	cp->nUnlinkedFiles = dev->nUnlinkedFiles;
+	cp->nBackgroundDeletions = dev->nBackgroundDeletions;
+	cp->sequenceNumber = dev->sequenceNumber;
+	cp->oldestDirtySequence = dev->oldestDirtySequence;
+
+}
+
+static void yaffs_CheckpointDeviceToDevice(yaffs_Device *dev,
+					   yaffs_CheckpointDevice *cp)
+{
+	dev->nErasedBlocks = cp->nErasedBlocks;
+	dev->allocationBlock = cp->allocationBlock;
+	dev->allocationPage = cp->allocationPage;
+	dev->nFreeChunks = cp->nFreeChunks;
+
+	dev->nDeletedFiles = cp->nDeletedFiles;
+	dev->nUnlinkedFiles = cp->nUnlinkedFiles;
+	dev->nBackgroundDeletions = cp->nBackgroundDeletions;
+	dev->sequenceNumber = cp->sequenceNumber;
+	dev->oldestDirtySequence = cp->oldestDirtySequence;
+}
+
+
+static int yaffs_WriteCheckpointDevice(yaffs_Device *dev)
+{
+	yaffs_CheckpointDevice cp;
+	__u32 nBytes;
+	__u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
+
+	int ok;
+
+	/* Write device runtime values*/
+	yaffs_DeviceToCheckpointDevice(&cp, dev);
+	cp.structType = sizeof(cp);
+
+	ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+	/* Write block info */
+	if (ok) {
+		nBytes = nBlocks * sizeof(yaffs_BlockInfo);
+		ok = (yaffs_CheckpointWrite(dev, dev->blockInfo, nBytes) == nBytes);
+	}
+
+	/* Write chunk bits */
+	if (ok) {
+		nBytes = nBlocks * dev->chunkBitmapStride;
+		ok = (yaffs_CheckpointWrite(dev, dev->chunkBits, nBytes) == nBytes);
+	}
+	return	 ok ? 1 : 0;
+
+}
+
+static int yaffs_ReadCheckpointDevice(yaffs_Device *dev)
+{
+	yaffs_CheckpointDevice cp;
+	__u32 nBytes;
+	__u32 nBlocks = (dev->internalEndBlock - dev->internalStartBlock + 1);
+
+	int ok;
+
+	ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
+	if (!ok)
+		return 0;
+
+	if (cp.structType != sizeof(cp))
+		return 0;
+
+
+	yaffs_CheckpointDeviceToDevice(dev, &cp);
+
+	nBytes = nBlocks * sizeof(yaffs_BlockInfo);
+
+	ok = (yaffs_CheckpointRead(dev, dev->blockInfo, nBytes) == nBytes);
+
+	if (!ok)
+		return 0;
+	nBytes = nBlocks * dev->chunkBitmapStride;
+
+	ok = (yaffs_CheckpointRead(dev, dev->chunkBits, nBytes) == nBytes);
+
+	return ok ? 1 : 0;
+}
+
+static void yaffs_ObjectToCheckpointObject(yaffs_CheckpointObject *cp,
+					   yaffs_Object *obj)
+{
+
+	cp->objectId = obj->objectId;
+	cp->parentId = (obj->parent) ? obj->parent->objectId : 0;
+	cp->hdrChunk = obj->hdrChunk;
+	cp->variantType = obj->variantType;
+	cp->deleted = obj->deleted;
+	cp->softDeleted = obj->softDeleted;
+	cp->unlinked = obj->unlinked;
+	cp->fake = obj->fake;
+	cp->renameAllowed = obj->renameAllowed;
+	cp->unlinkAllowed = obj->unlinkAllowed;
+	cp->serial = obj->serial;
+	cp->nDataChunks = obj->nDataChunks;
+
+	if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
+		cp->fileSizeOrEquivalentObjectId = obj->variant.fileVariant.fileSize;
+	else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
+		cp->fileSizeOrEquivalentObjectId = obj->variant.hardLinkVariant.equivalentObjectId;
+}
+
+static int yaffs_CheckpointObjectToObject(yaffs_Object *obj, yaffs_CheckpointObject *cp)
+{
+
+	yaffs_Object *parent;
+
+	if (obj->variantType != cp->variantType) {
+		T(YAFFS_TRACE_ERROR, (TSTR("Checkpoint read object %d type %d "
+			TCONT("chunk %d does not match existing object type %d")
+			TENDSTR), cp->objectId, cp->variantType, cp->hdrChunk,
+			obj->variantType));
+		return 0;
+	}
+
+	obj->objectId = cp->objectId;
+
+	if (cp->parentId)
+		parent = yaffs_FindOrCreateObjectByNumber(
+					obj->myDev,
+					cp->parentId,
+					YAFFS_OBJECT_TYPE_DIRECTORY);
+	else
+		parent = NULL;
+
+	if (parent) {
+		if (parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+			T(YAFFS_TRACE_ALWAYS, (TSTR("Checkpoint read object %d parent %d type %d"
+				TCONT(" chunk %d Parent type, %d, not directory")
+				TENDSTR),
+				cp->objectId, cp->parentId, cp->variantType,
+				cp->hdrChunk, parent->variantType));
+			return 0;
+		}
+		yaffs_AddObjectToDirectory(parent, obj);
+	}
+
+	obj->hdrChunk = cp->hdrChunk;
+	obj->variantType = cp->variantType;
+	obj->deleted = cp->deleted;
+	obj->softDeleted = cp->softDeleted;
+	obj->unlinked = cp->unlinked;
+	obj->fake = cp->fake;
+	obj->renameAllowed = cp->renameAllowed;
+	obj->unlinkAllowed = cp->unlinkAllowed;
+	obj->serial = cp->serial;
+	obj->nDataChunks = cp->nDataChunks;
+
+	if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
+		obj->variant.fileVariant.fileSize = cp->fileSizeOrEquivalentObjectId;
+	else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK)
+		obj->variant.hardLinkVariant.equivalentObjectId = cp->fileSizeOrEquivalentObjectId;
+
+	if (obj->hdrChunk > 0)
+		obj->lazyLoaded = 1;
+	return 1;
+}
+
+
+
+static int yaffs_CheckpointTnodeWorker(yaffs_Object *in, yaffs_Tnode *tn,
+					__u32 level, int chunkOffset)
+{
+	int i;
+	yaffs_Device *dev = in->myDev;
+	int ok = 1;
+	int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
+
+	if (tnodeSize < sizeof(yaffs_Tnode))
+		tnodeSize = sizeof(yaffs_Tnode);
+
+
+	if (tn) {
+		if (level > 0) {
+
+			for (i = 0; i < YAFFS_NTNODES_INTERNAL && ok; i++) {
+				if (tn->internal[i]) {
+					ok = yaffs_CheckpointTnodeWorker(in,
+							tn->internal[i],
+							level - 1,
+							(chunkOffset<<YAFFS_TNODES_INTERNAL_BITS) + i);
+				}
+			}
+		} else if (level == 0) {
+			__u32 baseOffset = chunkOffset <<  YAFFS_TNODES_LEVEL0_BITS;
+			ok = (yaffs_CheckpointWrite(dev, &baseOffset, sizeof(baseOffset)) == sizeof(baseOffset));
+			if (ok)
+				ok = (yaffs_CheckpointWrite(dev, tn, tnodeSize) == tnodeSize);
+		}
+	}
+
+	return ok;
+
+}
+
+static int yaffs_WriteCheckpointTnodes(yaffs_Object *obj)
+{
+	__u32 endMarker = ~0;
+	int ok = 1;
+
+	if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
+		ok = yaffs_CheckpointTnodeWorker(obj,
+					    obj->variant.fileVariant.top,
+					    obj->variant.fileVariant.topLevel,
+					    0);
+		if (ok)
+			ok = (yaffs_CheckpointWrite(obj->myDev, &endMarker, sizeof(endMarker)) ==
+				sizeof(endMarker));
+	}
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs_ReadCheckpointTnodes(yaffs_Object *obj)
+{
+	__u32 baseChunk;
+	int ok = 1;
+	yaffs_Device *dev = obj->myDev;
+	yaffs_FileStructure *fileStructPtr = &obj->variant.fileVariant;
+	yaffs_Tnode *tn;
+	int nread = 0;
+	int tnodeSize = (dev->tnodeWidth * YAFFS_NTNODES_LEVEL0)/8;
+
+	if (tnodeSize < sizeof(yaffs_Tnode))
+		tnodeSize = sizeof(yaffs_Tnode);
+
+	ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
+
+	while (ok && (~baseChunk)) {
+		nread++;
+		/* Read level 0 tnode */
+
+
+		tn = yaffs_GetTnodeRaw(dev);
+		if (tn)
+			ok = (yaffs_CheckpointRead(dev, tn, tnodeSize) == tnodeSize);
+		else
+			ok = 0;
+
+		if (tn && ok)
+			ok = yaffs_AddOrFindLevel0Tnode(dev,
+							fileStructPtr,
+							baseChunk,
+							tn) ? 1 : 0;
+
+		if (ok)
+			ok = (yaffs_CheckpointRead(dev, &baseChunk, sizeof(baseChunk)) == sizeof(baseChunk));
+
+	}
+
+	T(YAFFS_TRACE_CHECKPOINT, (
+		TSTR("Checkpoint read tnodes %d records, last %d. ok %d" TENDSTR),
+		nread, baseChunk, ok));
+
+	return ok ? 1 : 0;
+}
+
+
+static int yaffs_WriteCheckpointObjects(yaffs_Device *dev)
+{
+	yaffs_Object *obj;
+	yaffs_CheckpointObject cp;
+	int i;
+	int ok = 1;
+	struct ylist_head *lh;
+
+
+	/* Iterate through the objects in each hash entry,
+	 * dumping them to the checkpointing stream.
+	 */
+
+	for (i = 0; ok &&  i <  YAFFS_NOBJECT_BUCKETS; i++) {
+		ylist_for_each(lh, &dev->objectBucket[i].list) {
+			if (lh) {
+				obj = ylist_entry(lh, yaffs_Object, hashLink);
+				if (!obj->deferedFree) {
+					yaffs_ObjectToCheckpointObject(&cp, obj);
+					cp.structType = sizeof(cp);
+
+					T(YAFFS_TRACE_CHECKPOINT, (
+						TSTR("Checkpoint write object %d parent %d type %d chunk %d obj addr %x" TENDSTR),
+						cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk, (unsigned) obj));
+
+					ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+					if (ok && obj->variantType == YAFFS_OBJECT_TYPE_FILE)
+						ok = yaffs_WriteCheckpointTnodes(obj);
+				}
+			}
+		}
+	}
+
+	/* Dump end of list */
+	memset(&cp, 0xFF, sizeof(yaffs_CheckpointObject));
+	cp.structType = sizeof(cp);
+
+	if (ok)
+		ok = (yaffs_CheckpointWrite(dev, &cp, sizeof(cp)) == sizeof(cp));
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs_ReadCheckpointObjects(yaffs_Device *dev)
+{
+	yaffs_Object *obj;
+	yaffs_CheckpointObject cp;
+	int ok = 1;
+	int done = 0;
+	yaffs_Object *hardList = NULL;
+
+	while (ok && !done) {
+		ok = (yaffs_CheckpointRead(dev, &cp, sizeof(cp)) == sizeof(cp));
+		if (cp.structType != sizeof(cp)) {
+			T(YAFFS_TRACE_CHECKPOINT, (TSTR("struct size %d instead of %d ok %d"TENDSTR),
+				cp.structType, sizeof(cp), ok));
+			ok = 0;
+		}
+
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("Checkpoint read object %d parent %d type %d chunk %d " TENDSTR),
+			cp.objectId, cp.parentId, cp.variantType, cp.hdrChunk));
+
+		if (ok && cp.objectId == ~0)
+			done = 1;
+		else if (ok) {
+			obj = yaffs_FindOrCreateObjectByNumber(dev, cp.objectId, cp.variantType);
+			if (obj) {
+				ok = yaffs_CheckpointObjectToObject(obj, &cp);
+				if (!ok)
+					break;
+				if (obj->variantType == YAFFS_OBJECT_TYPE_FILE) {
+					ok = yaffs_ReadCheckpointTnodes(obj);
+				} else if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
+					obj->hardLinks.next =
+						(struct ylist_head *) hardList;
+					hardList = obj;
+				}
+			} else
+				ok = 0;
+		}
+	}
+
+	if (ok)
+		yaffs_HardlinkFixup(dev, hardList);
+
+	return ok ? 1 : 0;
+}
+
+static int yaffs_WriteCheckpointSum(yaffs_Device *dev)
+{
+	__u32 checkpointSum;
+	int ok;
+
+	yaffs_GetCheckpointSum(dev, &checkpointSum);
+
+	ok = (yaffs_CheckpointWrite(dev, &checkpointSum, sizeof(checkpointSum)) == sizeof(checkpointSum));
+
+	if (!ok)
+		return 0;
+
+	return 1;
+}
+
+static int yaffs_ReadCheckpointSum(yaffs_Device *dev)
+{
+	__u32 checkpointSum0;
+	__u32 checkpointSum1;
+	int ok;
+
+	yaffs_GetCheckpointSum(dev, &checkpointSum0);
+
+	ok = (yaffs_CheckpointRead(dev, &checkpointSum1, sizeof(checkpointSum1)) == sizeof(checkpointSum1));
+
+	if (!ok)
+		return 0;
+
+	if (checkpointSum0 != checkpointSum1)
+		return 0;
+
+	return 1;
+}
+
+
+static int yaffs_WriteCheckpointData(yaffs_Device *dev)
+{
+	int ok = 1;
+
+	if (dev->skipCheckpointWrite || !dev->isYaffs2) {
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint write" TENDSTR)));
+		ok = 0;
+	}
+
+	if (ok)
+		ok = yaffs_CheckpointOpen(dev, 1);
+
+	if (ok) {
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
+		ok = yaffs_WriteCheckpointValidityMarker(dev, 1);
+	}
+	if (ok) {
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint device" TENDSTR)));
+		ok = yaffs_WriteCheckpointDevice(dev);
+	}
+	if (ok) {
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint objects" TENDSTR)));
+		ok = yaffs_WriteCheckpointObjects(dev);
+	}
+	if (ok) {
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("write checkpoint validity" TENDSTR)));
+		ok = yaffs_WriteCheckpointValidityMarker(dev, 0);
+	}
+
+	if (ok)
+		ok = yaffs_WriteCheckpointSum(dev);
+
+	if (!yaffs_CheckpointClose(dev))
+		ok = 0;
+
+	if (ok)
+		dev->isCheckpointed = 1;
+	else
+		dev->isCheckpointed = 0;
+
+	return dev->isCheckpointed;
+}
+
+static int yaffs_ReadCheckpointData(yaffs_Device *dev)
+{
+	int ok = 1;
+
+	if (dev->skipCheckpointRead || !dev->isYaffs2) {
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("skipping checkpoint read" TENDSTR)));
+		ok = 0;
+	}
+
+	if (ok)
+		ok = yaffs_CheckpointOpen(dev, 0); /* open for read */
+
+	if (ok) {
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
+		ok = yaffs_ReadCheckpointValidityMarker(dev, 1);
+	}
+	if (ok) {
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint device" TENDSTR)));
+		ok = yaffs_ReadCheckpointDevice(dev);
+	}
+	if (ok) {
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint objects" TENDSTR)));
+		ok = yaffs_ReadCheckpointObjects(dev);
+	}
+	if (ok) {
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint validity" TENDSTR)));
+		ok = yaffs_ReadCheckpointValidityMarker(dev, 0);
+	}
+
+	if (ok) {
+		ok = yaffs_ReadCheckpointSum(dev);
+		T(YAFFS_TRACE_CHECKPOINT, (TSTR("read checkpoint checksum %d" TENDSTR), ok));
+	}
+
+	if (!yaffs_CheckpointClose(dev))
+		ok = 0;
+
+	if (ok)
+		dev->isCheckpointed = 1;
+	else
+		dev->isCheckpointed = 0;
+
+	return ok ? 1 : 0;
+
+}
+
+static void yaffs_InvalidateCheckpoint(yaffs_Device *dev)
+{
+	if (dev->isCheckpointed ||
+			dev->blocksInCheckpoint > 0) {
+		dev->isCheckpointed = 0;
+		yaffs_CheckpointInvalidateStream(dev);
+		if (dev->superBlock && dev->markSuperBlockDirty)
+			dev->markSuperBlockDirty(dev->superBlock);
+	}
+}
+
+
+int yaffs_CheckpointSave(yaffs_Device *dev)
+{
+
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("save entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
+
+	yaffs_VerifyObjects(dev);
+	yaffs_VerifyBlocks(dev);
+	yaffs_VerifyFreeChunks(dev);
+
+	if (!dev->isCheckpointed) {
+		yaffs_InvalidateCheckpoint(dev);
+		yaffs_WriteCheckpointData(dev);
+	}
+
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("save exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
+
+	return dev->isCheckpointed;
+}
+
+int yaffs_CheckpointRestore(yaffs_Device *dev)
+{
+	int retval;
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore entry: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
+
+	retval = yaffs_ReadCheckpointData(dev);
+
+	if (dev->isCheckpointed) {
+		yaffs_VerifyObjects(dev);
+		yaffs_VerifyBlocks(dev);
+		yaffs_VerifyFreeChunks(dev);
+	}
+
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("restore exit: isCheckpointed %d"TENDSTR), dev->isCheckpointed));
+
+	return retval;
+}
+
+/*--------------------- File read/write ------------------------
+ * Read and write have very similar structures.
+ * In general the read/write has three parts to it
+ * An incomplete chunk to start with (if the read/write is not chunk-aligned)
+ * Some complete chunks
+ * An incomplete chunk to end off with
+ *
+ * Curve-balls: the first chunk might also be the last chunk.
+ */
+
+int yaffs_ReadDataFromFile(yaffs_Object *in, __u8 *buffer, loff_t offset,
+			int nBytes)
+{
+
+	int chunk;
+	__u32 start;
+	int nToCopy;
+	int n = nBytes;
+	int nDone = 0;
+	yaffs_ChunkCache *cache;
+
+	yaffs_Device *dev;
+
+	dev = in->myDev;
+
+	while (n > 0) {
+		/* chunk = offset / dev->nDataBytesPerChunk + 1; */
+		/* start = offset % dev->nDataBytesPerChunk; */
+		yaffs_AddrToChunk(dev, offset, &chunk, &start);
+		chunk++;
+
+		/* OK now check for the curveball where the start and end are in
+		 * the same chunk.
+		 */
+		if ((start + n) < dev->nDataBytesPerChunk)
+			nToCopy = n;
+		else
+			nToCopy = dev->nDataBytesPerChunk - start;
+
+		cache = yaffs_FindChunkCache(in, chunk);
+
+		/* If the chunk is already in the cache or it is less than a whole chunk
+		 * or we're using inband tags then use the cache (if there is caching)
+		 * else bypass the cache.
+		 */
+		if (cache || nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
+			if (dev->nShortOpCaches > 0) {
+
+				/* If we can't find the data in the cache, then load it up. */
+
+				if (!cache) {
+					cache = yaffs_GrabChunkCache(in->myDev);
+					cache->object = in;
+					cache->chunkId = chunk;
+					cache->dirty = 0;
+					cache->locked = 0;
+					yaffs_ReadChunkDataFromObject(in, chunk,
+								      cache->
+								      data);
+					cache->nBytes = 0;
+				}
+
+				yaffs_UseChunkCache(dev, cache, 0);
+
+				cache->locked = 1;
+
+
+				memcpy(buffer, &cache->data[start], nToCopy);
+
+				cache->locked = 0;
+			} else {
+				/* Read into the local buffer then copy..*/
+
+				__u8 *localBuffer =
+				    yaffs_GetTempBuffer(dev, __LINE__);
+				yaffs_ReadChunkDataFromObject(in, chunk,
+							      localBuffer);
+
+				memcpy(buffer, &localBuffer[start], nToCopy);
+
+
+				yaffs_ReleaseTempBuffer(dev, localBuffer,
+							__LINE__);
+			}
+
+		} else {
+
+			/* A full chunk. Read directly into the supplied buffer. */
+			yaffs_ReadChunkDataFromObject(in, chunk, buffer);
+
+		}
+
+		n -= nToCopy;
+		offset += nToCopy;
+		buffer += nToCopy;
+		nDone += nToCopy;
+
+	}
+
+	return nDone;
+}
+
+int yaffs_WriteDataToFile(yaffs_Object *in, const __u8 *buffer, loff_t offset,
+			int nBytes, int writeThrough)
+{
+
+	int chunk;
+	__u32 start;
+	int nToCopy;
+	int n = nBytes;
+	int nDone = 0;
+	int nToWriteBack;
+	int startOfWrite = offset;
+	int chunkWritten = 0;
+	__u32 nBytesRead;
+	__u32 chunkStart;
+
+	yaffs_Device *dev;
+
+	dev = in->myDev;
+
+	while (n > 0 && chunkWritten >= 0) {
+		/* chunk = offset / dev->nDataBytesPerChunk + 1; */
+		/* start = offset % dev->nDataBytesPerChunk; */
+		yaffs_AddrToChunk(dev, offset, &chunk, &start);
+
+		if (chunk * dev->nDataBytesPerChunk + start != offset ||
+				start >= dev->nDataBytesPerChunk) {
+			T(YAFFS_TRACE_ERROR, (
+			   TSTR("AddrToChunk of offset %d gives chunk %d start %d"
+			   TENDSTR),
+			   (int)offset, chunk, start));
+		}
+		chunk++;
+
+		/* OK now check for the curveball where the start and end are in
+		 * the same chunk.
+		 */
+
+		if ((start + n) < dev->nDataBytesPerChunk) {
+			nToCopy = n;
+
+			/* Now folks, to calculate how many bytes to write back....
+			 * If we're overwriting and not writing to then end of file then
+			 * we need to write back as much as was there before.
+			 */
+
+			chunkStart = ((chunk - 1) * dev->nDataBytesPerChunk);
+
+			if (chunkStart > in->variant.fileVariant.fileSize)
+				nBytesRead = 0; /* Past end of file */
+			else
+				nBytesRead = in->variant.fileVariant.fileSize - chunkStart;
+
+			if (nBytesRead > dev->nDataBytesPerChunk)
+				nBytesRead = dev->nDataBytesPerChunk;
+
+			nToWriteBack =
+			    (nBytesRead >
+			     (start + n)) ? nBytesRead : (start + n);
+
+			if (nToWriteBack < 0 || nToWriteBack > dev->nDataBytesPerChunk)
+				YBUG();
+
+		} else {
+			nToCopy = dev->nDataBytesPerChunk - start;
+			nToWriteBack = dev->nDataBytesPerChunk;
+		}
+
+		if (nToCopy != dev->nDataBytesPerChunk || dev->inbandTags) {
+			/* An incomplete start or end chunk (or maybe both start and end chunk),
+			 * or we're using inband tags, so we want to use the cache buffers.
+			 */
+			if (dev->nShortOpCaches > 0) {
+				yaffs_ChunkCache *cache;
+				/* If we can't find the data in the cache, then load the cache */
+				cache = yaffs_FindChunkCache(in, chunk);
+
+				if (!cache
+				    && yaffs_CheckSpaceForAllocation(in->
+								     myDev)) {
+					cache = yaffs_GrabChunkCache(in->myDev);
+					cache->object = in;
+					cache->chunkId = chunk;
+					cache->dirty = 0;
+					cache->locked = 0;
+					yaffs_ReadChunkDataFromObject(in, chunk,
+								      cache->
+								      data);
+				} else if (cache &&
+					!cache->dirty &&
+					!yaffs_CheckSpaceForAllocation(in->myDev)) {
+					/* Drop the cache if it was a read cache item and
+					 * no space check has been made for it.
+					 */
+					 cache = NULL;
+				}
+
+				if (cache) {
+					yaffs_UseChunkCache(dev, cache, 1);
+					cache->locked = 1;
+
+
+					memcpy(&cache->data[start], buffer,
+					       nToCopy);
+
+
+					cache->locked = 0;
+					cache->nBytes = nToWriteBack;
+
+					if (writeThrough) {
+						chunkWritten =
+						    yaffs_WriteChunkDataToObject
+						    (cache->object,
+						     cache->chunkId,
+						     cache->data, cache->nBytes,
+						     1);
+						cache->dirty = 0;
+					}
+
+				} else {
+					chunkWritten = -1;	/* fail the write */
+				}
+			} else {
+				/* An incomplete start or end chunk (or maybe both start and end chunk)
+				 * Read into the local buffer then copy, then copy over and write back.
+				 */
+
+				__u8 *localBuffer =
+				    yaffs_GetTempBuffer(dev, __LINE__);
+
+				yaffs_ReadChunkDataFromObject(in, chunk,
+							      localBuffer);
+
+
+
+				memcpy(&localBuffer[start], buffer, nToCopy);
+
+				chunkWritten =
+				    yaffs_WriteChunkDataToObject(in, chunk,
+								 localBuffer,
+								 nToWriteBack,
+								 0);
+
+				yaffs_ReleaseTempBuffer(dev, localBuffer,
+							__LINE__);
+
+			}
+
+		} else {
+			/* A full chunk. Write directly from the supplied buffer. */
+
+
+
+			chunkWritten =
+			    yaffs_WriteChunkDataToObject(in, chunk, buffer,
+							 dev->nDataBytesPerChunk,
+							 0);
+
+			/* Since we've overwritten the cached data, we better invalidate it. */
+			yaffs_InvalidateChunkCache(in, chunk);
+		}
+
+		if (chunkWritten >= 0) {
+			n -= nToCopy;
+			offset += nToCopy;
+			buffer += nToCopy;
+			nDone += nToCopy;
+		}
+
+	}
+
+	/* Update file object */
+
+	if ((startOfWrite + nDone) > in->variant.fileVariant.fileSize)
+		in->variant.fileVariant.fileSize = (startOfWrite + nDone);
+
+	in->dirty = 1;
+
+	return nDone;
+}
+
+
+/* ---------------------- File resizing stuff ------------------ */
+
+static void yaffs_PruneResizedChunks(yaffs_Object *in, int newSize)
+{
+
+	yaffs_Device *dev = in->myDev;
+	int oldFileSize = in->variant.fileVariant.fileSize;
+
+	int lastDel = 1 + (oldFileSize - 1) / dev->nDataBytesPerChunk;
+
+	int startDel = 1 + (newSize + dev->nDataBytesPerChunk - 1) /
+	    dev->nDataBytesPerChunk;
+	int i;
+	int chunkId;
+
+	/* Delete backwards so that we don't end up with holes if
+	 * power is lost part-way through the operation.
+	 */
+	for (i = lastDel; i >= startDel; i--) {
+		/* NB this could be optimised somewhat,
+		 * eg. could retrieve the tags and write them without
+		 * using yaffs_DeleteChunk
+		 */
+
+		chunkId = yaffs_FindAndDeleteChunkInFile(in, i, NULL);
+		if (chunkId > 0) {
+			if (chunkId <
+			    (dev->internalStartBlock * dev->nChunksPerBlock)
+			    || chunkId >=
+			    ((dev->internalEndBlock +
+			      1) * dev->nChunksPerBlock)) {
+				T(YAFFS_TRACE_ALWAYS,
+				  (TSTR("Found daft chunkId %d for %d" TENDSTR),
+				   chunkId, i));
+			} else {
+				in->nDataChunks--;
+				yaffs_DeleteChunk(dev, chunkId, 1, __LINE__);
+			}
+		}
+	}
+
+}
+
+int yaffs_ResizeFile(yaffs_Object *in, loff_t newSize)
+{
+
+	int oldFileSize = in->variant.fileVariant.fileSize;
+	__u32 newSizeOfPartialChunk;
+	int newFullChunks;
+
+	yaffs_Device *dev = in->myDev;
+
+	yaffs_AddrToChunk(dev, newSize, &newFullChunks, &newSizeOfPartialChunk);
+
+	yaffs_FlushFilesChunkCache(in);
+	yaffs_InvalidateWholeChunkCache(in);
+
+	yaffs_CheckGarbageCollection(dev);
+
+	if (in->variantType != YAFFS_OBJECT_TYPE_FILE)
+		return YAFFS_FAIL;
+
+	if (newSize == oldFileSize)
+		return YAFFS_OK;
+
+	if (newSize < oldFileSize) {
+
+		yaffs_PruneResizedChunks(in, newSize);
+
+		if (newSizeOfPartialChunk != 0) {
+			int lastChunk = 1 + newFullChunks;
+
+			__u8 *localBuffer = yaffs_GetTempBuffer(dev, __LINE__);
+
+			/* Got to read and rewrite the last chunk with its new size and zero pad */
+			yaffs_ReadChunkDataFromObject(in, lastChunk,
+						      localBuffer);
+
+			memset(localBuffer + newSizeOfPartialChunk, 0,
+			       dev->nDataBytesPerChunk - newSizeOfPartialChunk);
+
+			yaffs_WriteChunkDataToObject(in, lastChunk, localBuffer,
+						     newSizeOfPartialChunk, 1);
+
+			yaffs_ReleaseTempBuffer(dev, localBuffer, __LINE__);
+		}
+
+		in->variant.fileVariant.fileSize = newSize;
+
+		yaffs_PruneFileStructure(dev, &in->variant.fileVariant);
+	} else {
+		/* newsSize > oldFileSize */
+		in->variant.fileVariant.fileSize = newSize;
+	}
+
+
+	/* Write a new object header.
+	 * show we've shrunk the file, if need be
+	 * Do this only if the file is not in the deleted directories.
+	 */
+	if (in->parent &&
+	    in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
+	    in->parent->objectId != YAFFS_OBJECTID_DELETED)
+		yaffs_UpdateObjectHeader(in, NULL, 0,
+					 (newSize < oldFileSize) ? 1 : 0, 0);
+
+	return YAFFS_OK;
+}
+
+loff_t yaffs_GetFileSize(yaffs_Object *obj)
+{
+	obj = yaffs_GetEquivalentObject(obj);
+
+	switch (obj->variantType) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		return obj->variant.fileVariant.fileSize;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		return yaffs_strlen(obj->variant.symLinkVariant.alias);
+	default:
+		return 0;
+	}
+}
+
+
+
+int yaffs_FlushFile(yaffs_Object *in, int updateTime)
+{
+	int retVal;
+	if (in->dirty) {
+		yaffs_FlushFilesChunkCache(in);
+		if (updateTime) {
+#ifdef CONFIG_YAFFS_WINCE
+			yfsd_WinFileTimeNow(in->win_mtime);
+#else
+
+			in->yst_mtime = Y_CURRENT_TIME;
+
+#endif
+		}
+
+		retVal = (yaffs_UpdateObjectHeader(in, NULL, 0, 0, 0) >=
+			0) ? YAFFS_OK : YAFFS_FAIL;
+	} else {
+		retVal = YAFFS_OK;
+	}
+
+	return retVal;
+
+}
+
+static int yaffs_DoGenericObjectDeletion(yaffs_Object *in)
+{
+
+	/* First off, invalidate the file's data in the cache, without flushing. */
+	yaffs_InvalidateWholeChunkCache(in);
+
+	if (in->myDev->isYaffs2 && (in->parent != in->myDev->deletedDir)) {
+		/* Move to the unlinked directory so we have a record that it was deleted. */
+		yaffs_ChangeObjectName(in, in->myDev->deletedDir, _Y("deleted"), 0, 0);
+
+	}
+
+	yaffs_RemoveObjectFromDirectory(in);
+	yaffs_DeleteChunk(in->myDev, in->hdrChunk, 1, __LINE__);
+	in->hdrChunk = 0;
+
+	yaffs_FreeObject(in);
+	return YAFFS_OK;
+
+}
+
+/* yaffs_DeleteFile deletes the whole file data
+ * and the inode associated with the file.
+ * It does not delete the links associated with the file.
+ */
+static int yaffs_UnlinkFileIfNeeded(yaffs_Object *in)
+{
+
+	int retVal;
+	int immediateDeletion = 0;
+
+#ifdef __KERNEL__
+	if (!in->myInode)
+		immediateDeletion = 1;
+#else
+	if (in->inUse <= 0)
+		immediateDeletion = 1;
+#endif
+
+	if (immediateDeletion) {
+		retVal =
+		    yaffs_ChangeObjectName(in, in->myDev->deletedDir,
+					   _Y("deleted"), 0, 0);
+		T(YAFFS_TRACE_TRACING,
+		  (TSTR("yaffs: immediate deletion of file %d" TENDSTR),
+		   in->objectId));
+		in->deleted = 1;
+		in->myDev->nDeletedFiles++;
+		if (1 || in->myDev->isYaffs2)
+			yaffs_ResizeFile(in, 0);
+		yaffs_SoftDeleteFile(in);
+	} else {
+		retVal =
+		    yaffs_ChangeObjectName(in, in->myDev->unlinkedDir,
+					   _Y("unlinked"), 0, 0);
+	}
+
+
+	return retVal;
+}
+
+int yaffs_DeleteFile(yaffs_Object *in)
+{
+	int retVal = YAFFS_OK;
+	int deleted = in->deleted;
+
+	yaffs_ResizeFile(in, 0);
+
+	if (in->nDataChunks > 0) {
+		/* Use soft deletion if there is data in the file.
+		 * That won't be the case if it has been resized to zero.
+		 */
+		if (!in->unlinked)
+			retVal = yaffs_UnlinkFileIfNeeded(in);
+
+		if (retVal == YAFFS_OK && in->unlinked && !in->deleted) {
+			in->deleted = 1;
+			deleted = 1;
+			in->myDev->nDeletedFiles++;
+			yaffs_SoftDeleteFile(in);
+		}
+		return deleted ? YAFFS_OK : YAFFS_FAIL;
+	} else {
+		/* The file has no data chunks so we toss it immediately */
+		yaffs_FreeTnode(in->myDev, in->variant.fileVariant.top);
+		in->variant.fileVariant.top = NULL;
+		yaffs_DoGenericObjectDeletion(in);
+
+		return YAFFS_OK;
+	}
+}
+
+static int yaffs_DeleteDirectory(yaffs_Object *in)
+{
+	/* First check that the directory is empty. */
+	if (ylist_empty(&in->variant.directoryVariant.children))
+		return yaffs_DoGenericObjectDeletion(in);
+
+	return YAFFS_FAIL;
+
+}
+
+static int yaffs_DeleteSymLink(yaffs_Object *in)
+{
+	YFREE(in->variant.symLinkVariant.alias);
+
+	return yaffs_DoGenericObjectDeletion(in);
+}
+
+static int yaffs_DeleteHardLink(yaffs_Object *in)
+{
+	/* remove this hardlink from the list assocaited with the equivalent
+	 * object
+	 */
+	ylist_del_init(&in->hardLinks);
+	return yaffs_DoGenericObjectDeletion(in);
+}
+
+int yaffs_DeleteObject(yaffs_Object *obj)
+{
+int retVal = -1;
+	switch (obj->variantType) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		retVal = yaffs_DeleteFile(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		return yaffs_DeleteDirectory(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		retVal = yaffs_DeleteSymLink(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		retVal = yaffs_DeleteHardLink(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		retVal = yaffs_DoGenericObjectDeletion(obj);
+		break;
+	case YAFFS_OBJECT_TYPE_UNKNOWN:
+		retVal = 0;
+		break;		/* should not happen. */
+	}
+
+	return retVal;
+}
+
+static int yaffs_UnlinkWorker(yaffs_Object *obj)
+{
+
+	int immediateDeletion = 0;
+
+#ifdef __KERNEL__
+	if (!obj->myInode)
+		immediateDeletion = 1;
+#else
+	if (obj->inUse <= 0)
+		immediateDeletion = 1;
+#endif
+
+	if(obj)
+		yaffs_UpdateParent(obj->parent);
+
+	if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
+		return yaffs_DeleteHardLink(obj);
+	} else if (!ylist_empty(&obj->hardLinks)) {
+		/* Curve ball: We're unlinking an object that has a hardlink.
+		 *
+		 * This problem arises because we are not strictly following
+		 * The Linux link/inode model.
+		 *
+		 * We can't really delete the object.
+		 * Instead, we do the following:
+		 * - Select a hardlink.
+		 * - Unhook it from the hard links
+		 * - Unhook it from its parent directory (so that the rename can work)
+		 * - Rename the object to the hardlink's name.
+		 * - Delete the hardlink
+		 */
+
+		yaffs_Object *hl;
+		int retVal;
+		YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+		hl = ylist_entry(obj->hardLinks.next, yaffs_Object, hardLinks);
+
+		ylist_del_init(&hl->hardLinks);
+		ylist_del_init(&hl->siblings);
+
+		yaffs_GetObjectName(hl, name, YAFFS_MAX_NAME_LENGTH + 1);
+
+		retVal = yaffs_ChangeObjectName(obj, hl->parent, name, 0, 0);
+
+		if (retVal == YAFFS_OK)
+			retVal = yaffs_DoGenericObjectDeletion(hl);
+
+		return retVal;
+
+	} else if (immediateDeletion) {
+		switch (obj->variantType) {
+		case YAFFS_OBJECT_TYPE_FILE:
+			return yaffs_DeleteFile(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_DIRECTORY:
+			return yaffs_DeleteDirectory(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_SYMLINK:
+			return yaffs_DeleteSymLink(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_SPECIAL:
+			return yaffs_DoGenericObjectDeletion(obj);
+			break;
+		case YAFFS_OBJECT_TYPE_HARDLINK:
+		case YAFFS_OBJECT_TYPE_UNKNOWN:
+		default:
+			return YAFFS_FAIL;
+		}
+	} else
+		return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
+					   _Y("unlinked"), 0, 0);
+}
+
+
+static int yaffs_UnlinkObject(yaffs_Object *obj)
+{
+
+	if (obj && obj->unlinkAllowed)
+		return yaffs_UnlinkWorker(obj);
+
+	return YAFFS_FAIL;
+
+}
+int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name)
+{
+	yaffs_Object *obj;
+
+	obj = yaffs_FindObjectByName(dir, name);
+	return yaffs_UnlinkObject(obj);
+}
+
+/*----------------------- Initialisation Scanning ---------------------- */
+
+static void yaffs_HandleShadowedObject(yaffs_Device *dev, int objId,
+				int backwardScanning)
+{
+	yaffs_Object *obj;
+
+	if (!backwardScanning) {
+		/* Handle YAFFS1 forward scanning case
+		 * For YAFFS1 we always do the deletion
+		 */
+
+	} else {
+		/* Handle YAFFS2 case (backward scanning)
+		 * If the shadowed object exists then ignore.
+		 */
+		if (yaffs_FindObjectByNumber(dev, objId))
+			return;
+	}
+
+	/* Let's create it (if it does not exist) assuming it is a file so that it can do shrinking etc.
+	 * We put it in unlinked dir to be cleaned up after the scanning
+	 */
+	obj =
+	    yaffs_FindOrCreateObjectByNumber(dev, objId,
+					     YAFFS_OBJECT_TYPE_FILE);
+	if (!obj)
+		return;
+	yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
+	obj->variant.fileVariant.shrinkSize = 0;
+	obj->valid = 1;		/* So that we don't read any other info for this file */
+
+}
+
+typedef struct {
+	int seq;
+	int block;
+} yaffs_BlockIndex;
+
+
+static void yaffs_HardlinkFixup(yaffs_Device *dev, yaffs_Object *hardList)
+{
+	yaffs_Object *hl;
+	yaffs_Object *in;
+
+	while (hardList) {
+		hl = hardList;
+		hardList = (yaffs_Object *) (hardList->hardLinks.next);
+
+		in = yaffs_FindObjectByNumber(dev,
+					      hl->variant.hardLinkVariant.
+					      equivalentObjectId);
+
+		if (in) {
+			/* Add the hardlink pointers */
+			hl->variant.hardLinkVariant.equivalentObject = in;
+			ylist_add(&hl->hardLinks, &in->hardLinks);
+		} else {
+			/* Todo Need to report/handle this better.
+			 * Got a problem... hardlink to a non-existant object
+			 */
+			hl->variant.hardLinkVariant.equivalentObject = NULL;
+			YINIT_LIST_HEAD(&hl->hardLinks);
+
+		}
+	}
+}
+
+
+
+
+
+static int ybicmp(const void *a, const void *b)
+{
+	register int aseq = ((yaffs_BlockIndex *)a)->seq;
+	register int bseq = ((yaffs_BlockIndex *)b)->seq;
+	register int ablock = ((yaffs_BlockIndex *)a)->block;
+	register int bblock = ((yaffs_BlockIndex *)b)->block;
+	if (aseq == bseq)
+		return ablock - bblock;
+	else
+		return aseq - bseq;
+}
+
+
+struct yaffs_ShadowFixerStruct {
+	int objectId;
+	int shadowedId;
+	struct yaffs_ShadowFixerStruct *next;
+};
+
+
+static void yaffs_StripDeletedObjects(yaffs_Device *dev)
+{
+	/*
+	*  Sort out state of unlinked and deleted objects after scanning.
+	*/
+	struct ylist_head *i;
+	struct ylist_head *n;
+	yaffs_Object *l;
+
+	/* Soft delete all the unlinked files */
+	ylist_for_each_safe(i, n,
+		&dev->unlinkedDir->variant.directoryVariant.children) {
+		if (i) {
+			l = ylist_entry(i, yaffs_Object, siblings);
+			yaffs_DeleteObject(l);
+		}
+	}
+
+	ylist_for_each_safe(i, n,
+		&dev->deletedDir->variant.directoryVariant.children) {
+		if (i) {
+			l = ylist_entry(i, yaffs_Object, siblings);
+			yaffs_DeleteObject(l);
+		}
+	}
+
+}
+
+static int yaffs_Scan(yaffs_Device *dev)
+{
+	yaffs_ExtendedTags tags;
+	int blk;
+	int blockIterator;
+	int startIterator;
+	int endIterator;
+	int result;
+
+	int chunk;
+	int c;
+	int deleted;
+	yaffs_BlockState state;
+	yaffs_Object *hardList = NULL;
+	yaffs_BlockInfo *bi;
+	__u32 sequenceNumber;
+	yaffs_ObjectHeader *oh;
+	yaffs_Object *in;
+	yaffs_Object *parent;
+
+	int alloc_failed = 0;
+
+	struct yaffs_ShadowFixerStruct *shadowFixerList = NULL;
+
+
+	__u8 *chunkData;
+
+
+
+	T(YAFFS_TRACE_SCAN,
+	  (TSTR("yaffs_Scan starts  intstartblk %d intendblk %d..." TENDSTR),
+	   dev->internalStartBlock, dev->internalEndBlock));
+
+	chunkData = yaffs_GetTempBuffer(dev, __LINE__);
+
+	dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+	/* Scan all the blocks to determine their state */
+	for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
+		bi = yaffs_GetBlockInfo(dev, blk);
+		yaffs_ClearChunkBits(dev, blk);
+		bi->pagesInUse = 0;
+		bi->softDeletions = 0;
+
+		yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
+
+		bi->blockState = state;
+		bi->sequenceNumber = sequenceNumber;
+
+		if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
+			bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
+
+		T(YAFFS_TRACE_SCAN_DEBUG,
+		  (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
+		   state, sequenceNumber));
+
+		if (state == YAFFS_BLOCK_STATE_DEAD) {
+			T(YAFFS_TRACE_BAD_BLOCKS,
+			  (TSTR("block %d is bad" TENDSTR), blk));
+		} else if (state == YAFFS_BLOCK_STATE_EMPTY) {
+			T(YAFFS_TRACE_SCAN_DEBUG,
+			  (TSTR("Block empty " TENDSTR)));
+			dev->nErasedBlocks++;
+			dev->nFreeChunks += dev->nChunksPerBlock;
+		}
+	}
+
+	startIterator = dev->internalStartBlock;
+	endIterator = dev->internalEndBlock;
+
+	/* For each block.... */
+	for (blockIterator = startIterator; !alloc_failed && blockIterator <= endIterator;
+	     blockIterator++) {
+
+		YYIELD();
+
+		YYIELD();
+
+		blk = blockIterator;
+
+		bi = yaffs_GetBlockInfo(dev, blk);
+		state = bi->blockState;
+
+		deleted = 0;
+
+		/* For each chunk in each block that needs scanning....*/
+		for (c = 0; !alloc_failed && c < dev->nChunksPerBlock &&
+		     state == YAFFS_BLOCK_STATE_NEEDS_SCANNING; c++) {
+			/* Read the tags and decide what to do */
+			chunk = blk * dev->nChunksPerBlock + c;
+
+			result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
+							&tags);
+
+			/* Let's have a good look at this chunk... */
+
+			if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED || tags.chunkDeleted) {
+				/* YAFFS1 only...
+				 * A deleted chunk
+				 */
+				deleted++;
+				dev->nFreeChunks++;
+				/*T((" %d %d deleted\n",blk,c)); */
+			} else if (!tags.chunkUsed) {
+				/* An unassigned chunk in the block
+				 * This means that either the block is empty or
+				 * this is the one being allocated from
+				 */
+
+				if (c == 0) {
+					/* We're looking at the first chunk in the block so the block is unused */
+					state = YAFFS_BLOCK_STATE_EMPTY;
+					dev->nErasedBlocks++;
+				} else {
+					/* this is the block being allocated from */
+					T(YAFFS_TRACE_SCAN,
+					  (TSTR
+					   (" Allocating from %d %d" TENDSTR),
+					   blk, c));
+					state = YAFFS_BLOCK_STATE_ALLOCATING;
+					dev->allocationBlock = blk;
+					dev->allocationPage = c;
+					dev->allocationBlockFinder = blk;
+					/* Set it to here to encourage the allocator to go forth from here. */
+
+				}
+
+				dev->nFreeChunks += (dev->nChunksPerBlock - c);
+			} else if (tags.chunkId > 0) {
+				/* chunkId > 0 so it is a data chunk... */
+				unsigned int endpos;
+
+				yaffs_SetChunkBit(dev, blk, c);
+				bi->pagesInUse++;
+
+				in = yaffs_FindOrCreateObjectByNumber(dev,
+								      tags.
+								      objectId,
+								      YAFFS_OBJECT_TYPE_FILE);
+				/* PutChunkIntoFile checks for a clash (two data chunks with
+				 * the same chunkId).
+				 */
+
+				if (!in)
+					alloc_failed = 1;
+
+				if (in) {
+					if (!yaffs_PutChunkIntoFile(in, tags.chunkId, chunk, 1))
+						alloc_failed = 1;
+				}
+
+				endpos =
+				    (tags.chunkId - 1) * dev->nDataBytesPerChunk +
+				    tags.byteCount;
+				if (in &&
+				    in->variantType == YAFFS_OBJECT_TYPE_FILE
+				    && in->variant.fileVariant.scannedFileSize <
+				    endpos) {
+					in->variant.fileVariant.
+					    scannedFileSize = endpos;
+					if (!dev->useHeaderFileSize) {
+						in->variant.fileVariant.
+						    fileSize =
+						    in->variant.fileVariant.
+						    scannedFileSize;
+					}
+
+				}
+				/* T((" %d %d data %d %d\n",blk,c,tags.objectId,tags.chunkId));   */
+			} else {
+				/* chunkId == 0, so it is an ObjectHeader.
+				 * Thus, we read in the object header and make the object
+				 */
+				yaffs_SetChunkBit(dev, blk, c);
+				bi->pagesInUse++;
+
+				result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk,
+								chunkData,
+								NULL);
+
+				oh = (yaffs_ObjectHeader *) chunkData;
+
+				in = yaffs_FindObjectByNumber(dev,
+							      tags.objectId);
+				if (in && in->variantType != oh->type) {
+					/* This should not happen, but somehow
+					 * Wev'e ended up with an objectId that has been reused but not yet
+					 * deleted, and worse still it has changed type. Delete the old object.
+					 */
+
+					yaffs_DeleteObject(in);
+
+					in = 0;
+				}
+
+				in = yaffs_FindOrCreateObjectByNumber(dev,
+								      tags.
+								      objectId,
+								      oh->type);
+
+				if (!in)
+					alloc_failed = 1;
+
+				if (in && oh->shadowsObject > 0) {
+
+					struct yaffs_ShadowFixerStruct *fixer;
+					fixer = YMALLOC(sizeof(struct yaffs_ShadowFixerStruct));
+					if (fixer) {
+						fixer->next = shadowFixerList;
+						shadowFixerList = fixer;
+						fixer->objectId = tags.objectId;
+						fixer->shadowedId = oh->shadowsObject;
+					}
+
+				}
+
+				if (in && in->valid) {
+					/* We have already filled this one. We have a duplicate and need to resolve it. */
+
+					unsigned existingSerial = in->serial;
+					unsigned newSerial = tags.serialNumber;
+
+					if (((existingSerial + 1) & 3) == newSerial) {
+						/* Use new one - destroy the exisiting one */
+						yaffs_DeleteChunk(dev,
+								  in->hdrChunk,
+								  1, __LINE__);
+						in->valid = 0;
+					} else {
+						/* Use existing - destroy this one. */
+						yaffs_DeleteChunk(dev, chunk, 1,
+								  __LINE__);
+					}
+				}
+
+				if (in && !in->valid &&
+				    (tags.objectId == YAFFS_OBJECTID_ROOT ||
+				     tags.objectId == YAFFS_OBJECTID_LOSTNFOUND)) {
+					/* We only load some info, don't fiddle with directory structure */
+					in->valid = 1;
+					in->variantType = oh->type;
+
+					in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+					in->win_atime[0] = oh->win_atime[0];
+					in->win_ctime[0] = oh->win_ctime[0];
+					in->win_mtime[0] = oh->win_mtime[0];
+					in->win_atime[1] = oh->win_atime[1];
+					in->win_ctime[1] = oh->win_ctime[1];
+					in->win_mtime[1] = oh->win_mtime[1];
+#else
+					in->yst_uid = oh->yst_uid;
+					in->yst_gid = oh->yst_gid;
+					in->yst_atime = oh->yst_atime;
+					in->yst_mtime = oh->yst_mtime;
+					in->yst_ctime = oh->yst_ctime;
+					in->yst_rdev = oh->yst_rdev;
+#endif
+					in->hdrChunk = chunk;
+					in->serial = tags.serialNumber;
+
+				} else if (in && !in->valid) {
+					/* we need to load this info */
+
+					in->valid = 1;
+					in->variantType = oh->type;
+
+					in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+					in->win_atime[0] = oh->win_atime[0];
+					in->win_ctime[0] = oh->win_ctime[0];
+					in->win_mtime[0] = oh->win_mtime[0];
+					in->win_atime[1] = oh->win_atime[1];
+					in->win_ctime[1] = oh->win_ctime[1];
+					in->win_mtime[1] = oh->win_mtime[1];
+#else
+					in->yst_uid = oh->yst_uid;
+					in->yst_gid = oh->yst_gid;
+					in->yst_atime = oh->yst_atime;
+					in->yst_mtime = oh->yst_mtime;
+					in->yst_ctime = oh->yst_ctime;
+					in->yst_rdev = oh->yst_rdev;
+#endif
+					in->hdrChunk = chunk;
+					in->serial = tags.serialNumber;
+
+					yaffs_SetObjectName(in, oh->name);
+					in->dirty = 0;
+
+					/* directory stuff...
+					 * hook up to parent
+					 */
+
+					parent =
+					    yaffs_FindOrCreateObjectByNumber
+					    (dev, oh->parentObjectId,
+					     YAFFS_OBJECT_TYPE_DIRECTORY);
+					if (!parent)
+						alloc_failed = 1;
+					if (parent && parent->variantType ==
+					    YAFFS_OBJECT_TYPE_UNKNOWN) {
+						/* Set up as a directory */
+						parent->variantType =
+							YAFFS_OBJECT_TYPE_DIRECTORY;
+						YINIT_LIST_HEAD(&parent->variant.
+								directoryVariant.
+								children);
+					} else if (!parent || parent->variantType !=
+						   YAFFS_OBJECT_TYPE_DIRECTORY) {
+						/* Hoosterman, another problem....
+						 * We're trying to use a non-directory as a directory
+						 */
+
+						T(YAFFS_TRACE_ERROR,
+						  (TSTR
+						   ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+						    TENDSTR)));
+						parent = dev->lostNFoundDir;
+					}
+
+					yaffs_AddObjectToDirectory(parent, in);
+
+					if (0 && (parent == dev->deletedDir ||
+						  parent == dev->unlinkedDir)) {
+						in->deleted = 1;	/* If it is unlinked at start up then it wants deleting */
+						dev->nDeletedFiles++;
+					}
+					/* Note re hardlinks.
+					 * Since we might scan a hardlink before its equivalent object is scanned
+					 * we put them all in a list.
+					 * After scanning is complete, we should have all the objects, so we run through this
+					 * list and fix up all the chains.
+					 */
+
+					switch (in->variantType) {
+					case YAFFS_OBJECT_TYPE_UNKNOWN:
+						/* Todo got a problem */
+						break;
+					case YAFFS_OBJECT_TYPE_FILE:
+						if (dev->useHeaderFileSize)
+
+							in->variant.fileVariant.
+							    fileSize =
+							    oh->fileSize;
+
+						break;
+					case YAFFS_OBJECT_TYPE_HARDLINK:
+						in->variant.hardLinkVariant.
+							equivalentObjectId =
+							oh->equivalentObjectId;
+						in->hardLinks.next =
+							(struct ylist_head *)
+							hardList;
+						hardList = in;
+						break;
+					case YAFFS_OBJECT_TYPE_DIRECTORY:
+						/* Do nothing */
+						break;
+					case YAFFS_OBJECT_TYPE_SPECIAL:
+						/* Do nothing */
+						break;
+					case YAFFS_OBJECT_TYPE_SYMLINK:
+						in->variant.symLinkVariant.alias =
+						    yaffs_CloneString(oh->alias);
+						if (!in->variant.symLinkVariant.alias)
+							alloc_failed = 1;
+						break;
+					}
+
+/*
+					if (parent == dev->deletedDir) {
+						yaffs_DestroyObject(in);
+						bi->hasShrinkHeader = 1;
+					}
+*/
+				}
+			}
+		}
+
+		if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+			/* If we got this far while scanning, then the block is fully allocated.*/
+			state = YAFFS_BLOCK_STATE_FULL;
+		}
+
+		bi->blockState = state;
+
+		/* Now let's see if it was dirty */
+		if (bi->pagesInUse == 0 &&
+		    !bi->hasShrinkHeader &&
+		    bi->blockState == YAFFS_BLOCK_STATE_FULL) {
+			yaffs_BlockBecameDirty(dev, blk);
+		}
+
+	}
+
+
+	/* Ok, we've done all the scanning.
+	 * Fix up the hard link chains.
+	 * We should now have scanned all the objects, now it's time to add these
+	 * hardlinks.
+	 */
+
+	yaffs_HardlinkFixup(dev, hardList);
+
+	/* Fix up any shadowed objects */
+	{
+		struct yaffs_ShadowFixerStruct *fixer;
+		yaffs_Object *obj;
+
+		while (shadowFixerList) {
+			fixer = shadowFixerList;
+			shadowFixerList = fixer->next;
+			/* Complete the rename transaction by deleting the shadowed object
+			 * then setting the object header to unshadowed.
+			 */
+			obj = yaffs_FindObjectByNumber(dev, fixer->shadowedId);
+			if (obj)
+				yaffs_DeleteObject(obj);
+
+			obj = yaffs_FindObjectByNumber(dev, fixer->objectId);
+
+			if (obj)
+				yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
+
+			YFREE(fixer);
+		}
+	}
+
+	yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
+
+	if (alloc_failed)
+		return YAFFS_FAIL;
+
+	T(YAFFS_TRACE_SCAN, (TSTR("yaffs_Scan ends" TENDSTR)));
+
+
+	return YAFFS_OK;
+}
+
+static void yaffs_CheckObjectDetailsLoaded(yaffs_Object *in)
+{
+	__u8 *chunkData;
+	yaffs_ObjectHeader *oh;
+	yaffs_Device *dev;
+	yaffs_ExtendedTags tags;
+	int result;
+	int alloc_failed = 0;
+
+	if (!in)
+		return;
+
+	dev = in->myDev;
+
+#if 0
+	T(YAFFS_TRACE_SCAN, (TSTR("details for object %d %s loaded" TENDSTR),
+		in->objectId,
+		in->lazyLoaded ? "not yet" : "already"));
+#endif
+
+	if (in->lazyLoaded && in->hdrChunk > 0) {
+		in->lazyLoaded = 0;
+		chunkData = yaffs_GetTempBuffer(dev, __LINE__);
+
+		result = yaffs_ReadChunkWithTagsFromNAND(dev, in->hdrChunk, chunkData, &tags);
+		oh = (yaffs_ObjectHeader *) chunkData;
+
+		in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+		in->win_atime[0] = oh->win_atime[0];
+		in->win_ctime[0] = oh->win_ctime[0];
+		in->win_mtime[0] = oh->win_mtime[0];
+		in->win_atime[1] = oh->win_atime[1];
+		in->win_ctime[1] = oh->win_ctime[1];
+		in->win_mtime[1] = oh->win_mtime[1];
+#else
+		in->yst_uid = oh->yst_uid;
+		in->yst_gid = oh->yst_gid;
+		in->yst_atime = oh->yst_atime;
+		in->yst_mtime = oh->yst_mtime;
+		in->yst_ctime = oh->yst_ctime;
+		in->yst_rdev = oh->yst_rdev;
+
+#endif
+		yaffs_SetObjectName(in, oh->name);
+
+		if (in->variantType == YAFFS_OBJECT_TYPE_SYMLINK) {
+			in->variant.symLinkVariant.alias =
+						    yaffs_CloneString(oh->alias);
+			if (!in->variant.symLinkVariant.alias)
+				alloc_failed = 1; /* Not returned to caller */
+		}
+
+		yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
+	}
+}
+
+static int yaffs_ScanBackwards(yaffs_Device *dev)
+{
+	yaffs_ExtendedTags tags;
+	int blk;
+	int blockIterator;
+	int startIterator;
+	int endIterator;
+	int nBlocksToScan = 0;
+
+	int chunk;
+	int result;
+	int c;
+	int deleted;
+	yaffs_BlockState state;
+	yaffs_Object *hardList = NULL;
+	yaffs_BlockInfo *bi;
+	__u32 sequenceNumber;
+	yaffs_ObjectHeader *oh;
+	yaffs_Object *in;
+	yaffs_Object *parent;
+	int nBlocks = dev->internalEndBlock - dev->internalStartBlock + 1;
+	int itsUnlinked;
+	__u8 *chunkData;
+
+	int fileSize;
+	int isShrink;
+	int foundChunksInBlock;
+	int equivalentObjectId;
+	int alloc_failed = 0;
+
+
+	yaffs_BlockIndex *blockIndex = NULL;
+	int altBlockIndex = 0;
+
+	if (!dev->isYaffs2) {
+		T(YAFFS_TRACE_SCAN,
+		  (TSTR("yaffs_ScanBackwards is only for YAFFS2!" TENDSTR)));
+		return YAFFS_FAIL;
+	}
+
+	T(YAFFS_TRACE_SCAN,
+	  (TSTR
+	   ("yaffs_ScanBackwards starts  intstartblk %d intendblk %d..."
+	    TENDSTR), dev->internalStartBlock, dev->internalEndBlock));
+
+
+	dev->sequenceNumber = YAFFS_LOWEST_SEQUENCE_NUMBER;
+
+	blockIndex = YMALLOC(nBlocks * sizeof(yaffs_BlockIndex));
+
+	if (!blockIndex) {
+		blockIndex = YMALLOC_ALT(nBlocks * sizeof(yaffs_BlockIndex));
+		altBlockIndex = 1;
+	}
+
+	if (!blockIndex) {
+		T(YAFFS_TRACE_SCAN,
+		  (TSTR("yaffs_Scan() could not allocate block index!" TENDSTR)));
+		return YAFFS_FAIL;
+	}
+
+	dev->blocksInCheckpoint = 0;
+
+	chunkData = yaffs_GetTempBuffer(dev, __LINE__);
+
+	/* Scan all the blocks to determine their state */
+	for (blk = dev->internalStartBlock; blk <= dev->internalEndBlock; blk++) {
+		bi = yaffs_GetBlockInfo(dev, blk);
+		yaffs_ClearChunkBits(dev, blk);
+		bi->pagesInUse = 0;
+		bi->softDeletions = 0;
+
+		yaffs_QueryInitialBlockState(dev, blk, &state, &sequenceNumber);
+
+		bi->blockState = state;
+		bi->sequenceNumber = sequenceNumber;
+
+		if (bi->sequenceNumber == YAFFS_SEQUENCE_CHECKPOINT_DATA)
+			bi->blockState = state = YAFFS_BLOCK_STATE_CHECKPOINT;
+		if (bi->sequenceNumber == YAFFS_SEQUENCE_BAD_BLOCK)
+			bi->blockState = state = YAFFS_BLOCK_STATE_DEAD;
+
+		T(YAFFS_TRACE_SCAN_DEBUG,
+		  (TSTR("Block scanning block %d state %d seq %d" TENDSTR), blk,
+		   state, sequenceNumber));
+
+
+		if (state == YAFFS_BLOCK_STATE_CHECKPOINT) {
+			dev->blocksInCheckpoint++;
+
+		} else if (state == YAFFS_BLOCK_STATE_DEAD) {
+			T(YAFFS_TRACE_BAD_BLOCKS,
+			  (TSTR("block %d is bad" TENDSTR), blk));
+		} else if (state == YAFFS_BLOCK_STATE_EMPTY) {
+			T(YAFFS_TRACE_SCAN_DEBUG,
+			  (TSTR("Block empty " TENDSTR)));
+			dev->nErasedBlocks++;
+			dev->nFreeChunks += dev->nChunksPerBlock;
+		} else if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+
+			/* Determine the highest sequence number */
+			if (sequenceNumber >= YAFFS_LOWEST_SEQUENCE_NUMBER &&
+			    sequenceNumber < YAFFS_HIGHEST_SEQUENCE_NUMBER) {
+
+				blockIndex[nBlocksToScan].seq = sequenceNumber;
+				blockIndex[nBlocksToScan].block = blk;
+
+				nBlocksToScan++;
+
+				if (sequenceNumber >= dev->sequenceNumber)
+					dev->sequenceNumber = sequenceNumber;
+			} else {
+				/* TODO: Nasty sequence number! */
+				T(YAFFS_TRACE_SCAN,
+				  (TSTR
+				   ("Block scanning block %d has bad sequence number %d"
+				    TENDSTR), blk, sequenceNumber));
+
+			}
+		}
+	}
+
+	T(YAFFS_TRACE_SCAN,
+	(TSTR("%d blocks to be sorted..." TENDSTR), nBlocksToScan));
+
+
+
+	YYIELD();
+
+	/* Sort the blocks */
+#ifndef CONFIG_YAFFS_USE_OWN_SORT
+	{
+		/* Use qsort now. */
+		yaffs_qsort(blockIndex, nBlocksToScan, sizeof(yaffs_BlockIndex), ybicmp);
+	}
+#else
+	{
+		/* Dungy old bubble sort... */
+
+		yaffs_BlockIndex temp;
+		int i;
+		int j;
+
+		for (i = 0; i < nBlocksToScan; i++)
+			for (j = i + 1; j < nBlocksToScan; j++)
+				if (blockIndex[i].seq > blockIndex[j].seq) {
+					temp = blockIndex[j];
+					blockIndex[j] = blockIndex[i];
+					blockIndex[i] = temp;
+				}
+	}
+#endif
+
+	YYIELD();
+
+	T(YAFFS_TRACE_SCAN, (TSTR("...done" TENDSTR)));
+
+	/* Now scan the blocks looking at the data. */
+	startIterator = 0;
+	endIterator = nBlocksToScan - 1;
+	T(YAFFS_TRACE_SCAN_DEBUG,
+	  (TSTR("%d blocks to be scanned" TENDSTR), nBlocksToScan));
+
+	/* For each block.... backwards */
+	for (blockIterator = endIterator; !alloc_failed && blockIterator >= startIterator;
+			blockIterator--) {
+		/* Cooperative multitasking! This loop can run for so
+		   long that watchdog timers expire. */
+		YYIELD();
+
+		/* get the block to scan in the correct order */
+		blk = blockIndex[blockIterator].block;
+
+		bi = yaffs_GetBlockInfo(dev, blk);
+
+
+		state = bi->blockState;
+
+		deleted = 0;
+
+		/* For each chunk in each block that needs scanning.... */
+		foundChunksInBlock = 0;
+		for (c = dev->nChunksPerBlock - 1;
+		     !alloc_failed && c >= 0 &&
+		     (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+		      state == YAFFS_BLOCK_STATE_ALLOCATING); c--) {
+			/* Scan backwards...
+			 * Read the tags and decide what to do
+			 */
+
+			chunk = blk * dev->nChunksPerBlock + c;
+
+			result = yaffs_ReadChunkWithTagsFromNAND(dev, chunk, NULL,
+							&tags);
+
+			/* Let's have a good look at this chunk... */
+
+			if (!tags.chunkUsed) {
+				/* An unassigned chunk in the block.
+				 * If there are used chunks after this one, then
+				 * it is a chunk that was skipped due to failing the erased
+				 * check. Just skip it so that it can be deleted.
+				 * But, more typically, We get here when this is an unallocated
+				 * chunk and his means that either the block is empty or
+				 * this is the one being allocated from
+				 */
+
+				if (foundChunksInBlock) {
+					/* This is a chunk that was skipped due to failing the erased check */
+				} else if (c == 0) {
+					/* We're looking at the first chunk in the block so the block is unused */
+					state = YAFFS_BLOCK_STATE_EMPTY;
+					dev->nErasedBlocks++;
+				} else {
+					if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING ||
+					    state == YAFFS_BLOCK_STATE_ALLOCATING) {
+						if (dev->sequenceNumber == bi->sequenceNumber) {
+							/* this is the block being allocated from */
+
+							T(YAFFS_TRACE_SCAN,
+							  (TSTR
+							   (" Allocating from %d %d"
+							    TENDSTR), blk, c));
+
+							state = YAFFS_BLOCK_STATE_ALLOCATING;
+							dev->allocationBlock = blk;
+							dev->allocationPage = c;
+							dev->allocationBlockFinder = blk;
+						} else {
+							/* This is a partially written block that is not
+							 * the current allocation block. This block must have
+							 * had a write failure, so set up for retirement.
+							 */
+
+							 /* bi->needsRetiring = 1; ??? TODO */
+							 bi->gcPrioritise = 1;
+
+							 T(YAFFS_TRACE_ALWAYS,
+							 (TSTR("Partially written block %d detected" TENDSTR),
+							 blk));
+						}
+					}
+				}
+
+				dev->nFreeChunks++;
+
+			} else if (tags.eccResult == YAFFS_ECC_RESULT_UNFIXED) {
+				T(YAFFS_TRACE_SCAN,
+				  (TSTR(" Unfixed ECC in chunk(%d:%d), chunk ignored"TENDSTR),
+				  blk, c));
+
+				  dev->nFreeChunks++;
+
+			} else if (tags.chunkId > 0) {
+				/* chunkId > 0 so it is a data chunk... */
+				unsigned int endpos;
+				__u32 chunkBase =
+				    (tags.chunkId - 1) * dev->nDataBytesPerChunk;
+
+				foundChunksInBlock = 1;
+
+
+				yaffs_SetChunkBit(dev, blk, c);
+				bi->pagesInUse++;
+
+				in = yaffs_FindOrCreateObjectByNumber(dev,
+								      tags.
+								      objectId,
+								      YAFFS_OBJECT_TYPE_FILE);
+				if (!in) {
+					/* Out of memory */
+					alloc_failed = 1;
+				}
+
+				if (in &&
+				    in->variantType == YAFFS_OBJECT_TYPE_FILE
+				    && chunkBase <
+				    in->variant.fileVariant.shrinkSize) {
+					/* This has not been invalidated by a resize */
+					if (!yaffs_PutChunkIntoFile(in, tags.chunkId,
+							       chunk, -1)) {
+						alloc_failed = 1;
+					}
+
+					/* File size is calculated by looking at the data chunks if we have not
+					 * seen an object header yet. Stop this practice once we find an object header.
+					 */
+					endpos =
+					    (tags.chunkId -
+					     1) * dev->nDataBytesPerChunk +
+					    tags.byteCount;
+
+					if (!in->valid &&	/* have not got an object header yet */
+					    in->variant.fileVariant.
+					    scannedFileSize < endpos) {
+						in->variant.fileVariant.
+						    scannedFileSize = endpos;
+						in->variant.fileVariant.
+						    fileSize =
+						    in->variant.fileVariant.
+						    scannedFileSize;
+					}
+
+				} else if (in) {
+					/* This chunk has been invalidated by a resize, so delete */
+					yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
+
+				}
+			} else {
+				/* chunkId == 0, so it is an ObjectHeader.
+				 * Thus, we read in the object header and make the object
+				 */
+				foundChunksInBlock = 1;
+
+				yaffs_SetChunkBit(dev, blk, c);
+				bi->pagesInUse++;
+
+				oh = NULL;
+				in = NULL;
+
+				if (tags.extraHeaderInfoAvailable) {
+					in = yaffs_FindOrCreateObjectByNumber
+					    (dev, tags.objectId,
+					     tags.extraObjectType);
+					if (!in)
+						alloc_failed = 1;
+				}
+
+				if (!in ||
+#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
+				    !in->valid ||
+#endif
+				    tags.extraShadows ||
+				    (!in->valid &&
+				    (tags.objectId == YAFFS_OBJECTID_ROOT ||
+				     tags.objectId == YAFFS_OBJECTID_LOSTNFOUND))) {
+
+					/* If we don't have  valid info then we need to read the chunk
+					 * TODO In future we can probably defer reading the chunk and
+					 * living with invalid data until needed.
+					 */
+
+					result = yaffs_ReadChunkWithTagsFromNAND(dev,
+									chunk,
+									chunkData,
+									NULL);
+
+					oh = (yaffs_ObjectHeader *) chunkData;
+
+					if (dev->inbandTags) {
+						/* Fix up the header if they got corrupted by inband tags */
+						oh->shadowsObject = oh->inbandShadowsObject;
+						oh->isShrink = oh->inbandIsShrink;
+					}
+
+					if (!in) {
+						in = yaffs_FindOrCreateObjectByNumber(dev, tags.objectId, oh->type);
+						if (!in)
+							alloc_failed = 1;
+					}
+
+				}
+
+				if (!in) {
+					/* TODO Hoosterman we have a problem! */
+					T(YAFFS_TRACE_ERROR,
+					  (TSTR
+					   ("yaffs tragedy: Could not make object for object  %d at chunk %d during scan"
+					    TENDSTR), tags.objectId, chunk));
+					continue;
+				}
+
+				if (in->valid) {
+					/* We have already filled this one.
+					 * We have a duplicate that will be discarded, but
+					 * we first have to suck out resize info if it is a file.
+					 */
+
+					if ((in->variantType == YAFFS_OBJECT_TYPE_FILE) &&
+					     ((oh &&
+					       oh->type == YAFFS_OBJECT_TYPE_FILE) ||
+					      (tags.extraHeaderInfoAvailable  &&
+					       tags.extraObjectType == YAFFS_OBJECT_TYPE_FILE))) {
+						__u32 thisSize =
+						    (oh) ? oh->fileSize : tags.
+						    extraFileLength;
+						__u32 parentObjectId =
+						    (oh) ? oh->
+						    parentObjectId : tags.
+						    extraParentObjectId;
+
+
+						isShrink =
+						    (oh) ? oh->isShrink : tags.
+						    extraIsShrinkHeader;
+
+						/* If it is deleted (unlinked at start also means deleted)
+						 * we treat the file size as being zeroed at this point.
+						 */
+						if (parentObjectId ==
+						    YAFFS_OBJECTID_DELETED
+						    || parentObjectId ==
+						    YAFFS_OBJECTID_UNLINKED) {
+							thisSize = 0;
+							isShrink = 1;
+						}
+
+						if (isShrink &&
+						    in->variant.fileVariant.
+						    shrinkSize > thisSize) {
+							in->variant.fileVariant.
+							    shrinkSize =
+							    thisSize;
+						}
+
+						if (isShrink)
+							bi->hasShrinkHeader = 1;
+
+					}
+					/* Use existing - destroy this one. */
+					yaffs_DeleteChunk(dev, chunk, 1, __LINE__);
+
+				}
+
+				if (!in->valid && in->variantType !=
+				    (oh ? oh->type : tags.extraObjectType))
+					T(YAFFS_TRACE_ERROR, (
+						TSTR("yaffs tragedy: Bad object type, "
+					    TCONT("%d != %d, for object %d at chunk ")
+					    TCONT("%d during scan")
+						TENDSTR), oh ?
+					    oh->type : tags.extraObjectType,
+					    in->variantType, tags.objectId,
+					    chunk));
+
+				if (!in->valid &&
+				    (tags.objectId == YAFFS_OBJECTID_ROOT ||
+				     tags.objectId ==
+				     YAFFS_OBJECTID_LOSTNFOUND)) {
+					/* We only load some info, don't fiddle with directory structure */
+					in->valid = 1;
+
+					if (oh) {
+						in->variantType = oh->type;
+
+						in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+						in->win_atime[0] = oh->win_atime[0];
+						in->win_ctime[0] = oh->win_ctime[0];
+						in->win_mtime[0] = oh->win_mtime[0];
+						in->win_atime[1] = oh->win_atime[1];
+						in->win_ctime[1] = oh->win_ctime[1];
+						in->win_mtime[1] = oh->win_mtime[1];
+#else
+						in->yst_uid = oh->yst_uid;
+						in->yst_gid = oh->yst_gid;
+						in->yst_atime = oh->yst_atime;
+						in->yst_mtime = oh->yst_mtime;
+						in->yst_ctime = oh->yst_ctime;
+						in->yst_rdev = oh->yst_rdev;
+
+#endif
+					} else {
+						in->variantType = tags.extraObjectType;
+						in->lazyLoaded = 1;
+					}
+
+					in->hdrChunk = chunk;
+
+				} else if (!in->valid) {
+					/* we need to load this info */
+
+					in->valid = 1;
+					in->hdrChunk = chunk;
+
+					if (oh) {
+						in->variantType = oh->type;
+
+						in->yst_mode = oh->yst_mode;
+#ifdef CONFIG_YAFFS_WINCE
+						in->win_atime[0] = oh->win_atime[0];
+						in->win_ctime[0] = oh->win_ctime[0];
+						in->win_mtime[0] = oh->win_mtime[0];
+						in->win_atime[1] = oh->win_atime[1];
+						in->win_ctime[1] = oh->win_ctime[1];
+						in->win_mtime[1] = oh->win_mtime[1];
+#else
+						in->yst_uid = oh->yst_uid;
+						in->yst_gid = oh->yst_gid;
+						in->yst_atime = oh->yst_atime;
+						in->yst_mtime = oh->yst_mtime;
+						in->yst_ctime = oh->yst_ctime;
+						in->yst_rdev = oh->yst_rdev;
+#endif
+
+						if (oh->shadowsObject > 0)
+							yaffs_HandleShadowedObject(dev,
+									   oh->
+									   shadowsObject,
+									   1);
+
+
+						yaffs_SetObjectName(in, oh->name);
+						parent =
+						    yaffs_FindOrCreateObjectByNumber
+							(dev, oh->parentObjectId,
+							 YAFFS_OBJECT_TYPE_DIRECTORY);
+
+						 fileSize = oh->fileSize;
+						 isShrink = oh->isShrink;
+						 equivalentObjectId = oh->equivalentObjectId;
+
+					} else {
+						in->variantType = tags.extraObjectType;
+						parent =
+						    yaffs_FindOrCreateObjectByNumber
+							(dev, tags.extraParentObjectId,
+							 YAFFS_OBJECT_TYPE_DIRECTORY);
+						 fileSize = tags.extraFileLength;
+						 isShrink = tags.extraIsShrinkHeader;
+						 equivalentObjectId = tags.extraEquivalentObjectId;
+						in->lazyLoaded = 1;
+
+					}
+					in->dirty = 0;
+
+					if (!parent)
+						alloc_failed = 1;
+
+					/* directory stuff...
+					 * hook up to parent
+					 */
+
+					if (parent && parent->variantType ==
+					    YAFFS_OBJECT_TYPE_UNKNOWN) {
+						/* Set up as a directory */
+						parent->variantType =
+							YAFFS_OBJECT_TYPE_DIRECTORY;
+						YINIT_LIST_HEAD(&parent->variant.
+							directoryVariant.
+							children);
+					} else if (!parent || parent->variantType !=
+						   YAFFS_OBJECT_TYPE_DIRECTORY) {
+						/* Hoosterman, another problem....
+						 * We're trying to use a non-directory as a directory
+						 */
+
+						T(YAFFS_TRACE_ERROR,
+						  (TSTR
+						   ("yaffs tragedy: attempting to use non-directory as a directory in scan. Put in lost+found."
+						    TENDSTR)));
+						parent = dev->lostNFoundDir;
+					}
+
+					yaffs_AddObjectToDirectory(parent, in);
+
+					itsUnlinked = (parent == dev->deletedDir) ||
+						      (parent == dev->unlinkedDir);
+
+					if (isShrink) {
+						/* Mark the block as having a shrinkHeader */
+						bi->hasShrinkHeader = 1;
+					}
+
+					/* Note re hardlinks.
+					 * Since we might scan a hardlink before its equivalent object is scanned
+					 * we put them all in a list.
+					 * After scanning is complete, we should have all the objects, so we run
+					 * through this list and fix up all the chains.
+					 */
+
+					switch (in->variantType) {
+					case YAFFS_OBJECT_TYPE_UNKNOWN:
+						/* Todo got a problem */
+						break;
+					case YAFFS_OBJECT_TYPE_FILE:
+
+						if (in->variant.fileVariant.
+						    scannedFileSize < fileSize) {
+							/* This covers the case where the file size is greater
+							 * than where the data is
+							 * This will happen if the file is resized to be larger
+							 * than its current data extents.
+							 */
+							in->variant.fileVariant.fileSize = fileSize;
+							in->variant.fileVariant.scannedFileSize =
+							    in->variant.fileVariant.fileSize;
+						}
+
+						if (isShrink &&
+						    in->variant.fileVariant.shrinkSize > fileSize) {
+							in->variant.fileVariant.shrinkSize = fileSize;
+						}
+
+						break;
+					case YAFFS_OBJECT_TYPE_HARDLINK:
+						if (!itsUnlinked) {
+							in->variant.hardLinkVariant.equivalentObjectId =
+								equivalentObjectId;
+							in->hardLinks.next =
+								(struct ylist_head *) hardList;
+							hardList = in;
+						}
+						break;
+					case YAFFS_OBJECT_TYPE_DIRECTORY:
+						/* Do nothing */
+						break;
+					case YAFFS_OBJECT_TYPE_SPECIAL:
+						/* Do nothing */
+						break;
+					case YAFFS_OBJECT_TYPE_SYMLINK:
+						if (oh) {
+							in->variant.symLinkVariant.alias =
+								yaffs_CloneString(oh->alias);
+							if (!in->variant.symLinkVariant.alias)
+								alloc_failed = 1;
+						}
+						break;
+					}
+
+				}
+
+			}
+
+		} /* End of scanning for each chunk */
+
+		if (state == YAFFS_BLOCK_STATE_NEEDS_SCANNING) {
+			/* If we got this far while scanning, then the block is fully allocated. */
+			state = YAFFS_BLOCK_STATE_FULL;
+		}
+
+		bi->blockState = state;
+
+		/* Now let's see if it was dirty */
+		if (bi->pagesInUse == 0 &&
+		    !bi->hasShrinkHeader &&
+		    bi->blockState == YAFFS_BLOCK_STATE_FULL) {
+			yaffs_BlockBecameDirty(dev, blk);
+		}
+
+	}
+
+	if (altBlockIndex)
+		YFREE_ALT(blockIndex);
+	else
+		YFREE(blockIndex);
+
+	/* Ok, we've done all the scanning.
+	 * Fix up the hard link chains.
+	 * We should now have scanned all the objects, now it's time to add these
+	 * hardlinks.
+	 */
+	yaffs_HardlinkFixup(dev, hardList);
+
+
+	yaffs_ReleaseTempBuffer(dev, chunkData, __LINE__);
+
+	if (alloc_failed)
+		return YAFFS_FAIL;
+
+	T(YAFFS_TRACE_SCAN, (TSTR("yaffs_ScanBackwards ends" TENDSTR)));
+
+	return YAFFS_OK;
+}
+
+/*------------------------------  Directory Functions ----------------------------- */
+
+static void yaffs_VerifyObjectInDirectory(yaffs_Object *obj)
+{
+	struct ylist_head *lh;
+	yaffs_Object *listObj;
+
+	int count = 0;
+
+	if (!obj) {
+		T(YAFFS_TRACE_ALWAYS, (TSTR("No object to verify" TENDSTR)));
+		YBUG();
+		return;
+	}
+
+	if (yaffs_SkipVerification(obj->myDev))
+		return;
+
+	if (!obj->parent) {
+		T(YAFFS_TRACE_ALWAYS, (TSTR("Object does not have parent" TENDSTR)));
+		YBUG();
+		return;
+	}
+
+	if (obj->parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		T(YAFFS_TRACE_ALWAYS, (TSTR("Parent is not directory" TENDSTR)));
+		YBUG();
+	}
+
+	/* Iterate through the objects in each hash entry */
+
+	ylist_for_each(lh, &obj->parent->variant.directoryVariant.children) {
+		if (lh) {
+			listObj = ylist_entry(lh, yaffs_Object, siblings);
+			yaffs_VerifyObject(listObj);
+			if (obj == listObj)
+				count++;
+		}
+	 }
+
+	if (count != 1) {
+		T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory %d times" TENDSTR), count));
+		YBUG();
+	}
+}
+
+static void yaffs_VerifyDirectory(yaffs_Object *directory)
+{
+	struct ylist_head *lh;
+	yaffs_Object *listObj;
+
+	if (!directory) {
+		YBUG();
+		return;
+	}
+
+	if (yaffs_SkipFullVerification(directory->myDev))
+		return;
+
+	if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		T(YAFFS_TRACE_ALWAYS, (TSTR("Directory has wrong type: %d" TENDSTR), directory->variantType));
+		YBUG();
+	}
+
+	/* Iterate through the objects in each hash entry */
+
+	ylist_for_each(lh, &directory->variant.directoryVariant.children) {
+		if (lh) {
+			listObj = ylist_entry(lh, yaffs_Object, siblings);
+			if (listObj->parent != directory) {
+				T(YAFFS_TRACE_ALWAYS, (TSTR("Object in directory list has wrong parent %p" TENDSTR), listObj->parent));
+				YBUG();
+			}
+			yaffs_VerifyObjectInDirectory(listObj);
+		}
+	}
+}
+
+/*
+ *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
+ * link (ie. name) is created or deleted in the directory.
+ *
+ * ie.
+ *   create dir/a : update dir's mtime/ctime
+ *   rm dir/a:   update dir's mtime/ctime
+ *   modify dir/a: don't update dir's mtimme/ctime
+ */
+ 
+static void yaffs_UpdateParent(yaffs_Object *obj)
+{
+	if(!obj)
+		return;
+
+	obj->dirty = 1;
+	obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
+
+	yaffs_UpdateObjectHeader(obj,NULL,0,0,0);
+}
+
+static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
+{
+	yaffs_Device *dev = obj->myDev;
+	yaffs_Object *parent;
+
+	yaffs_VerifyObjectInDirectory(obj);
+	parent = obj->parent;
+
+	yaffs_VerifyDirectory(parent);
+
+	if (dev && dev->removeObjectCallback)
+		dev->removeObjectCallback(obj);
+
+
+	ylist_del_init(&obj->siblings);
+	obj->parent = NULL;
+	
+	yaffs_VerifyDirectory(parent);
+}
+
+static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
+					yaffs_Object *obj)
+{
+	if (!directory) {
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR
+		   ("tragedy: Trying to add an object to a null pointer directory"
+		    TENDSTR)));
+		YBUG();
+		return;
+	}
+	if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR
+		   ("tragedy: Trying to add an object to a non-directory"
+		    TENDSTR)));
+		YBUG();
+	}
+
+	if (obj->siblings.prev == NULL) {
+		/* Not initialised */
+		YBUG();
+	}
+
+
+	yaffs_VerifyDirectory(directory);
+
+	yaffs_RemoveObjectFromDirectory(obj);
+
+
+	/* Now add it */
+	ylist_add(&obj->siblings, &directory->variant.directoryVariant.children);
+	obj->parent = directory;
+
+	if (directory == obj->myDev->unlinkedDir
+			|| directory == obj->myDev->deletedDir) {
+		obj->unlinked = 1;
+		obj->myDev->nUnlinkedFiles++;
+		obj->renameAllowed = 0;
+	}
+
+	yaffs_VerifyDirectory(directory);
+	yaffs_VerifyObjectInDirectory(obj);
+}
+
+yaffs_Object *yaffs_FindObjectByName(yaffs_Object *directory,
+				     const YCHAR *name)
+{
+	int sum;
+
+	struct ylist_head *i;
+	YCHAR buffer[YAFFS_MAX_NAME_LENGTH + 1];
+
+	yaffs_Object *l;
+
+	if (!name)
+		return NULL;
+
+	if (!directory) {
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR
+		   ("tragedy: yaffs_FindObjectByName: null pointer directory"
+		    TENDSTR)));
+		YBUG();
+		return NULL;
+	}
+	if (directory->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR
+		   ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
+		YBUG();
+	}
+
+	sum = yaffs_CalcNameSum(name);
+
+	ylist_for_each(i, &directory->variant.directoryVariant.children) {
+		if (i) {
+			l = ylist_entry(i, yaffs_Object, siblings);
+
+			if (l->parent != directory)
+				YBUG();
+
+			yaffs_CheckObjectDetailsLoaded(l);
+
+			/* Special case for lost-n-found */
+			if (l->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
+				if (yaffs_strcmp(name, YAFFS_LOSTNFOUND_NAME) == 0)
+					return l;
+			} else if (yaffs_SumCompare(l->sum, sum) || l->hdrChunk <= 0) {
+				/* LostnFound chunk called Objxxx
+				 * Do a real check
+				 */
+				yaffs_GetObjectName(l, buffer,
+						    YAFFS_MAX_NAME_LENGTH);
+				if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
+					return l;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+
+#if 0
+int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,
+					int (*fn) (yaffs_Object *))
+{
+	struct ylist_head *i;
+	yaffs_Object *l;
+
+	if (!theDir) {
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR
+		   ("tragedy: yaffs_FindObjectByName: null pointer directory"
+		    TENDSTR)));
+		YBUG();
+		return YAFFS_FAIL;
+	}
+	if (theDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY) {
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR
+		   ("tragedy: yaffs_FindObjectByName: non-directory" TENDSTR)));
+		YBUG();
+		return YAFFS_FAIL;
+	}
+
+	ylist_for_each(i, &theDir->variant.directoryVariant.children) {
+		if (i) {
+			l = ylist_entry(i, yaffs_Object, siblings);
+			if (l && !fn(l))
+				return YAFFS_FAIL;
+		}
+	}
+
+	return YAFFS_OK;
+
+}
+#endif
+
+/* GetEquivalentObject dereferences any hard links to get to the
+ * actual object.
+ */
+
+yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj)
+{
+	if (obj && obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
+		/* We want the object id of the equivalent object, not this one */
+		obj = obj->variant.hardLinkVariant.equivalentObject;
+		yaffs_CheckObjectDetailsLoaded(obj);
+	}
+	return obj;
+}
+
+int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize)
+{
+	memset(name, 0, buffSize * sizeof(YCHAR));
+
+	yaffs_CheckObjectDetailsLoaded(obj);
+
+	if (obj->objectId == YAFFS_OBJECTID_LOSTNFOUND) {
+		yaffs_strncpy(name, YAFFS_LOSTNFOUND_NAME, buffSize - 1);
+	} else if (obj->hdrChunk <= 0) {
+		YCHAR locName[20];
+		YCHAR numString[20];
+		YCHAR *x = &numString[19];
+		unsigned v = obj->objectId;
+		numString[19] = 0;
+		while (v > 0) {
+			x--;
+			*x = '0' + (v % 10);
+			v /= 10;
+		}
+		/* make up a name */
+		yaffs_strcpy(locName, YAFFS_LOSTNFOUND_PREFIX);
+		yaffs_strcat(locName, x);
+		yaffs_strncpy(name, locName, buffSize - 1);
+
+	}
+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+	else if (obj->shortName[0])
+		yaffs_strcpy(name, obj->shortName);
+#endif
+	else {
+		int result;
+		__u8 *buffer = yaffs_GetTempBuffer(obj->myDev, __LINE__);
+
+		yaffs_ObjectHeader *oh = (yaffs_ObjectHeader *) buffer;
+
+		memset(buffer, 0, obj->myDev->nDataBytesPerChunk);
+
+		if (obj->hdrChunk > 0) {
+			result = yaffs_ReadChunkWithTagsFromNAND(obj->myDev,
+							obj->hdrChunk, buffer,
+							NULL);
+		}
+		yaffs_strncpy(name, oh->name, buffSize - 1);
+
+		yaffs_ReleaseTempBuffer(obj->myDev, buffer, __LINE__);
+	}
+
+	return yaffs_strlen(name);
+}
+
+int yaffs_GetObjectFileLength(yaffs_Object *obj)
+{
+	/* Dereference any hard linking */
+	obj = yaffs_GetEquivalentObject(obj);
+
+	if (obj->variantType == YAFFS_OBJECT_TYPE_FILE)
+		return obj->variant.fileVariant.fileSize;
+	if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
+		return yaffs_strlen(obj->variant.symLinkVariant.alias);
+	else {
+		/* Only a directory should drop through to here */
+		return obj->myDev->nDataBytesPerChunk;
+	}
+}
+
+int yaffs_GetObjectLinkCount(yaffs_Object *obj)
+{
+	int count = 0;
+	struct ylist_head *i;
+
+	if (!obj->unlinked)
+		count++;		/* the object itself */
+
+	ylist_for_each(i, &obj->hardLinks)
+		count++;		/* add the hard links; */
+
+	return count;
+}
+
+int yaffs_GetObjectInode(yaffs_Object *obj)
+{
+	obj = yaffs_GetEquivalentObject(obj);
+
+	return obj->objectId;
+}
+
+unsigned yaffs_GetObjectType(yaffs_Object *obj)
+{
+	obj = yaffs_GetEquivalentObject(obj);
+
+	switch (obj->variantType) {
+	case YAFFS_OBJECT_TYPE_FILE:
+		return DT_REG;
+		break;
+	case YAFFS_OBJECT_TYPE_DIRECTORY:
+		return DT_DIR;
+		break;
+	case YAFFS_OBJECT_TYPE_SYMLINK:
+		return DT_LNK;
+		break;
+	case YAFFS_OBJECT_TYPE_HARDLINK:
+		return DT_REG;
+		break;
+	case YAFFS_OBJECT_TYPE_SPECIAL:
+		if (S_ISFIFO(obj->yst_mode))
+			return DT_FIFO;
+		if (S_ISCHR(obj->yst_mode))
+			return DT_CHR;
+		if (S_ISBLK(obj->yst_mode))
+			return DT_BLK;
+		if (S_ISSOCK(obj->yst_mode))
+			return DT_SOCK;
+	default:
+		return DT_REG;
+		break;
+	}
+}
+
+YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj)
+{
+	obj = yaffs_GetEquivalentObject(obj);
+	if (obj->variantType == YAFFS_OBJECT_TYPE_SYMLINK)
+		return yaffs_CloneString(obj->variant.symLinkVariant.alias);
+	else
+		return yaffs_CloneString(_Y(""));
+}
+
+#ifndef CONFIG_YAFFS_WINCE
+
+int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr)
+{
+	unsigned int valid = attr->ia_valid;
+
+	if (valid & ATTR_MODE)
+		obj->yst_mode = attr->ia_mode;
+	if (valid & ATTR_UID)
+		obj->yst_uid = attr->ia_uid;
+	if (valid & ATTR_GID)
+		obj->yst_gid = attr->ia_gid;
+
+	if (valid & ATTR_ATIME)
+		obj->yst_atime = Y_TIME_CONVERT(attr->ia_atime);
+	if (valid & ATTR_CTIME)
+		obj->yst_ctime = Y_TIME_CONVERT(attr->ia_ctime);
+	if (valid & ATTR_MTIME)
+		obj->yst_mtime = Y_TIME_CONVERT(attr->ia_mtime);
+
+	if (valid & ATTR_SIZE)
+		yaffs_ResizeFile(obj, attr->ia_size);
+
+	yaffs_UpdateObjectHeader(obj, NULL, 1, 0, 0);
+
+	return YAFFS_OK;
+
+}
+int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr)
+{
+	unsigned int valid = 0;
+
+	attr->ia_mode = obj->yst_mode;
+	valid |= ATTR_MODE;
+	attr->ia_uid = obj->yst_uid;
+	valid |= ATTR_UID;
+	attr->ia_gid = obj->yst_gid;
+	valid |= ATTR_GID;
+
+	Y_TIME_CONVERT(attr->ia_atime) = obj->yst_atime;
+	valid |= ATTR_ATIME;
+	Y_TIME_CONVERT(attr->ia_ctime) = obj->yst_ctime;
+	valid |= ATTR_CTIME;
+	Y_TIME_CONVERT(attr->ia_mtime) = obj->yst_mtime;
+	valid |= ATTR_MTIME;
+
+	attr->ia_size = yaffs_GetFileSize(obj);
+	valid |= ATTR_SIZE;
+
+	attr->ia_valid = valid;
+
+	return YAFFS_OK;
+}
+
+#endif
+
+#if 0
+int yaffs_DumpObject(yaffs_Object *obj)
+{
+	YCHAR name[257];
+
+	yaffs_GetObjectName(obj, name, 256);
+
+	T(YAFFS_TRACE_ALWAYS,
+	  (TSTR
+	   ("Object %d, inode %d \"%s\"\n dirty %d valid %d serial %d sum %d"
+	    " chunk %d type %d size %d\n"
+	    TENDSTR), obj->objectId, yaffs_GetObjectInode(obj), name,
+	   obj->dirty, obj->valid, obj->serial, obj->sum, obj->hdrChunk,
+	   yaffs_GetObjectType(obj), yaffs_GetObjectFileLength(obj)));
+
+	return YAFFS_OK;
+}
+#endif
+
+/*---------------------------- Initialisation code -------------------------------------- */
+
+static int yaffs_CheckDevFunctions(const yaffs_Device *dev)
+{
+
+	/* Common functions, gotta have */
+	if (!dev->eraseBlockInNAND || !dev->initialiseNAND)
+		return 0;
+
+#ifdef CONFIG_YAFFS_YAFFS2
+
+	/* Can use the "with tags" style interface for yaffs1 or yaffs2 */
+	if (dev->writeChunkWithTagsToNAND &&
+	    dev->readChunkWithTagsFromNAND &&
+	    !dev->writeChunkToNAND &&
+	    !dev->readChunkFromNAND &&
+	    dev->markNANDBlockBad && dev->queryNANDBlock)
+		return 1;
+#endif
+
+	/* Can use the "spare" style interface for yaffs1 */
+	if (!dev->isYaffs2 &&
+	    !dev->writeChunkWithTagsToNAND &&
+	    !dev->readChunkWithTagsFromNAND &&
+	    dev->writeChunkToNAND &&
+	    dev->readChunkFromNAND &&
+	    !dev->markNANDBlockBad && !dev->queryNANDBlock)
+		return 1;
+
+	return 0;		/* bad */
+}
+
+
+static int yaffs_CreateInitialDirectories(yaffs_Device *dev)
+{
+	/* Initialise the unlinked, deleted, root and lost and found directories */
+
+	dev->lostNFoundDir = dev->rootDir =  NULL;
+	dev->unlinkedDir = dev->deletedDir = NULL;
+
+	dev->unlinkedDir =
+	    yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_UNLINKED, S_IFDIR);
+
+	dev->deletedDir =
+	    yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_DELETED, S_IFDIR);
+
+	dev->rootDir =
+	    yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_ROOT,
+				      YAFFS_ROOT_MODE | S_IFDIR);
+	dev->lostNFoundDir =
+	    yaffs_CreateFakeDirectory(dev, YAFFS_OBJECTID_LOSTNFOUND,
+				      YAFFS_LOSTNFOUND_MODE | S_IFDIR);
+
+	if (dev->lostNFoundDir && dev->rootDir && dev->unlinkedDir && dev->deletedDir) {
+		yaffs_AddObjectToDirectory(dev->rootDir, dev->lostNFoundDir);
+		return YAFFS_OK;
+	}
+
+	return YAFFS_FAIL;
+}
+
+int yaffs_GutsInitialise(yaffs_Device *dev)
+{
+	int init_failed = 0;
+	unsigned x;
+	int bits;
+
+	T(YAFFS_TRACE_TRACING, (TSTR("yaffs: yaffs_GutsInitialise()" TENDSTR)));
+
+	/* Check stuff that must be set */
+
+	if (!dev) {
+		T(YAFFS_TRACE_ALWAYS, (TSTR("yaffs: Need a device" TENDSTR)));
+		return YAFFS_FAIL;
+	}
+
+	dev->internalStartBlock = dev->startBlock;
+	dev->internalEndBlock = dev->endBlock;
+	dev->blockOffset = 0;
+	dev->chunkOffset = 0;
+	dev->nFreeChunks = 0;
+
+	dev->gcBlock = -1;
+
+	if (dev->startBlock == 0) {
+		dev->internalStartBlock = dev->startBlock + 1;
+		dev->internalEndBlock = dev->endBlock + 1;
+		dev->blockOffset = 1;
+		dev->chunkOffset = dev->nChunksPerBlock;
+	}
+
+	/* Check geometry parameters. */
+
+	if ((!dev->inbandTags && dev->isYaffs2 && dev->totalBytesPerChunk < 1024) ||
+	    (!dev->isYaffs2 && dev->totalBytesPerChunk < 512) ||
+	    (dev->inbandTags && !dev->isYaffs2) ||
+	     dev->nChunksPerBlock < 2 ||
+	     dev->nReservedBlocks < 2 ||
+	     dev->internalStartBlock <= 0 ||
+	     dev->internalEndBlock <= 0 ||
+	     dev->internalEndBlock <= (dev->internalStartBlock + dev->nReservedBlocks + 2)) {	/* otherwise it is too small */
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR
+		   ("yaffs: NAND geometry problems: chunk size %d, type is yaffs%s, inbandTags %d "
+		    TENDSTR), dev->totalBytesPerChunk, dev->isYaffs2 ? "2" : "", dev->inbandTags));
+		return YAFFS_FAIL;
+	}
+
+	if (yaffs_InitialiseNAND(dev) != YAFFS_OK) {
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR("yaffs: InitialiseNAND failed" TENDSTR)));
+		return YAFFS_FAIL;
+	}
+
+	/* Sort out space for inband tags, if required */
+	if (dev->inbandTags)
+		dev->nDataBytesPerChunk = dev->totalBytesPerChunk - sizeof(yaffs_PackedTags2TagsPart);
+	else
+		dev->nDataBytesPerChunk = dev->totalBytesPerChunk;
+
+	/* Got the right mix of functions? */
+	if (!yaffs_CheckDevFunctions(dev)) {
+		/* Function missing */
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR
+		   ("yaffs: device function(s) missing or wrong\n" TENDSTR)));
+
+		return YAFFS_FAIL;
+	}
+
+	/* This is really a compilation check. */
+	if (!yaffs_CheckStructures()) {
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR("yaffs_CheckStructures failed\n" TENDSTR)));
+		return YAFFS_FAIL;
+	}
+
+	if (dev->isMounted) {
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR("yaffs: device already mounted\n" TENDSTR)));
+		return YAFFS_FAIL;
+	}
+
+	/* Finished with most checks. One or two more checks happen later on too. */
+
+	dev->isMounted = 1;
+
+	/* OK now calculate a few things for the device */
+
+	/*
+	 *  Calculate all the chunk size manipulation numbers:
+	 */
+	x = dev->nDataBytesPerChunk;
+	/* We always use dev->chunkShift and dev->chunkDiv */
+	dev->chunkShift = Shifts(x);
+	x >>= dev->chunkShift;
+	dev->chunkDiv = x;
+	/* We only use chunk mask if chunkDiv is 1 */
+	dev->chunkMask = (1<<dev->chunkShift) - 1;
+
+	/*
+	 * Calculate chunkGroupBits.
+	 * We need to find the next power of 2 > than internalEndBlock
+	 */
+
+	x = dev->nChunksPerBlock * (dev->internalEndBlock + 1);
+
+	bits = ShiftsGE(x);
+
+	/* Set up tnode width if wide tnodes are enabled. */
+	if (!dev->wideTnodesDisabled) {
+		/* bits must be even so that we end up with 32-bit words */
+		if (bits & 1)
+			bits++;
+		if (bits < 16)
+			dev->tnodeWidth = 16;
+		else
+			dev->tnodeWidth = bits;
+	} else
+		dev->tnodeWidth = 16;
+
+	dev->tnodeMask = (1<<dev->tnodeWidth)-1;
+
+	/* Level0 Tnodes are 16 bits or wider (if wide tnodes are enabled),
+	 * so if the bitwidth of the
+	 * chunk range we're using is greater than 16 we need
+	 * to figure out chunk shift and chunkGroupSize
+	 */
+
+	if (bits <= dev->tnodeWidth)
+		dev->chunkGroupBits = 0;
+	else
+		dev->chunkGroupBits = bits - dev->tnodeWidth;
+
+
+	dev->chunkGroupSize = 1 << dev->chunkGroupBits;
+
+	if (dev->nChunksPerBlock < dev->chunkGroupSize) {
+		/* We have a problem because the soft delete won't work if
+		 * the chunk group size > chunks per block.
+		 * This can be remedied by using larger "virtual blocks".
+		 */
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR("yaffs: chunk group too large\n" TENDSTR)));
+
+		return YAFFS_FAIL;
+	}
+
+	/* OK, we've finished verifying the device, lets continue with initialisation */
+
+	/* More device initialisation */
+	dev->garbageCollections = 0;
+	dev->passiveGarbageCollections = 0;
+	dev->currentDirtyChecker = 0;
+	dev->bufferedBlock = -1;
+	dev->doingBufferedBlockRewrite = 0;
+	dev->nDeletedFiles = 0;
+	dev->nBackgroundDeletions = 0;
+	dev->nUnlinkedFiles = 0;
+	dev->eccFixed = 0;
+	dev->eccUnfixed = 0;
+	dev->tagsEccFixed = 0;
+	dev->tagsEccUnfixed = 0;
+	dev->nErasureFailures = 0;
+	dev->nErasedBlocks = 0;
+	dev->isDoingGC = 0;
+	dev->hasPendingPrioritisedGCs = 1; /* Assume the worst for now, will get fixed on first GC */
+
+	/* Initialise temporary buffers and caches. */
+	if (!yaffs_InitialiseTempBuffers(dev))
+		init_failed = 1;
+
+	dev->srCache = NULL;
+	dev->gcCleanupList = NULL;
+
+
+	if (!init_failed &&
+	    dev->nShortOpCaches > 0) {
+		int i;
+		void *buf;
+		int srCacheBytes = dev->nShortOpCaches * sizeof(yaffs_ChunkCache);
+
+		if (dev->nShortOpCaches > YAFFS_MAX_SHORT_OP_CACHES)
+			dev->nShortOpCaches = YAFFS_MAX_SHORT_OP_CACHES;
+
+		dev->srCache =  YMALLOC(srCacheBytes);
+
+		buf = (__u8 *) dev->srCache;
+
+		if (dev->srCache)
+			memset(dev->srCache, 0, srCacheBytes);
+
+		for (i = 0; i < dev->nShortOpCaches && buf; i++) {
+			dev->srCache[i].object = NULL;
+			dev->srCache[i].lastUse = 0;
+			dev->srCache[i].dirty = 0;
+			dev->srCache[i].data = buf = YMALLOC_DMA(dev->totalBytesPerChunk);
+		}
+		if (!buf)
+			init_failed = 1;
+
+		dev->srLastUse = 0;
+	}
+
+	dev->cacheHits = 0;
+
+	if (!init_failed) {
+		dev->gcCleanupList = YMALLOC(dev->nChunksPerBlock * sizeof(__u32));
+		if (!dev->gcCleanupList)
+			init_failed = 1;
+	}
+
+	if (dev->isYaffs2)
+		dev->useHeaderFileSize = 1;
+
+	if (!init_failed && !yaffs_InitialiseBlocks(dev))
+		init_failed = 1;
+
+	yaffs_InitialiseTnodes(dev);
+	yaffs_InitialiseObjects(dev);
+
+	if (!init_failed && !yaffs_CreateInitialDirectories(dev))
+		init_failed = 1;
+
+
+	if (!init_failed) {
+		/* Now scan the flash. */
+		if (dev->isYaffs2) {
+			if (yaffs_CheckpointRestore(dev)) {
+				yaffs_CheckObjectDetailsLoaded(dev->rootDir);
+				T(YAFFS_TRACE_CHECKPOINT,
+				  (TSTR("yaffs: restored from checkpoint" TENDSTR)));
+			} else {
+
+				/* Clean up the mess caused by an aborted checkpoint load
+				 * and scan backwards.
+				 */
+				yaffs_DeinitialiseBlocks(dev);
+				yaffs_DeinitialiseTnodes(dev);
+				yaffs_DeinitialiseObjects(dev);
+
+
+				dev->nErasedBlocks = 0;
+				dev->nFreeChunks = 0;
+				dev->allocationBlock = -1;
+				dev->allocationPage = -1;
+				dev->nDeletedFiles = 0;
+				dev->nUnlinkedFiles = 0;
+				dev->nBackgroundDeletions = 0;
+				dev->oldestDirtySequence = 0;
+
+				if (!init_failed && !yaffs_InitialiseBlocks(dev))
+					init_failed = 1;
+
+				yaffs_InitialiseTnodes(dev);
+				yaffs_InitialiseObjects(dev);
+
+				if (!init_failed && !yaffs_CreateInitialDirectories(dev))
+					init_failed = 1;
+
+				if (!init_failed && !yaffs_ScanBackwards(dev))
+					init_failed = 1;
+			}
+		} else if (!yaffs_Scan(dev))
+				init_failed = 1;
+
+		yaffs_StripDeletedObjects(dev);
+	}
+
+	if (init_failed) {
+		/* Clean up the mess */
+		T(YAFFS_TRACE_TRACING,
+		  (TSTR("yaffs: yaffs_GutsInitialise() aborted.\n" TENDSTR)));
+
+		yaffs_Deinitialise(dev);
+		return YAFFS_FAIL;
+	}
+
+	/* Zero out stats */
+	dev->nPageReads = 0;
+	dev->nPageWrites = 0;
+	dev->nBlockErasures = 0;
+	dev->nGCCopies = 0;
+	dev->nRetriedWrites = 0;
+
+	dev->nRetiredBlocks = 0;
+
+	yaffs_VerifyFreeChunks(dev);
+	yaffs_VerifyBlocks(dev);
+
+
+	T(YAFFS_TRACE_TRACING,
+	  (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
+	return YAFFS_OK;
+
+}
+
+void yaffs_Deinitialise(yaffs_Device *dev)
+{
+	if (dev->isMounted) {
+		int i;
+
+		yaffs_DeinitialiseBlocks(dev);
+		yaffs_DeinitialiseTnodes(dev);
+		yaffs_DeinitialiseObjects(dev);
+		if (dev->nShortOpCaches > 0 &&
+		    dev->srCache) {
+
+			for (i = 0; i < dev->nShortOpCaches; i++) {
+				if (dev->srCache[i].data)
+					YFREE(dev->srCache[i].data);
+				dev->srCache[i].data = NULL;
+			}
+
+			YFREE(dev->srCache);
+			dev->srCache = NULL;
+		}
+
+		YFREE(dev->gcCleanupList);
+
+		for (i = 0; i < YAFFS_N_TEMP_BUFFERS; i++)
+			YFREE(dev->tempBuffer[i].buffer);
+
+		dev->isMounted = 0;
+
+		if (dev->deinitialiseNAND)
+			dev->deinitialiseNAND(dev);
+	}
+}
+
+static int yaffs_CountFreeChunks(yaffs_Device *dev)
+{
+	int nFree;
+	int b;
+
+	yaffs_BlockInfo *blk;
+
+	for (nFree = 0, b = dev->internalStartBlock; b <= dev->internalEndBlock;
+			b++) {
+		blk = yaffs_GetBlockInfo(dev, b);
+
+		switch (blk->blockState) {
+		case YAFFS_BLOCK_STATE_EMPTY:
+		case YAFFS_BLOCK_STATE_ALLOCATING:
+		case YAFFS_BLOCK_STATE_COLLECTING:
+		case YAFFS_BLOCK_STATE_FULL:
+			nFree +=
+			    (dev->nChunksPerBlock - blk->pagesInUse +
+			     blk->softDeletions);
+			break;
+		default:
+			break;
+		}
+	}
+
+	return nFree;
+}
+
+int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev)
+{
+	/* This is what we report to the outside world */
+
+	int nFree;
+	int nDirtyCacheChunks;
+	int blocksForCheckpoint;
+	int i;
+
+#if 1
+	nFree = dev->nFreeChunks;
+#else
+	nFree = yaffs_CountFreeChunks(dev);
+#endif
+
+	nFree += dev->nDeletedFiles;
+
+	/* Now count the number of dirty chunks in the cache and subtract those */
+
+	for (nDirtyCacheChunks = 0, i = 0; i < dev->nShortOpCaches; i++) {
+		if (dev->srCache[i].dirty)
+			nDirtyCacheChunks++;
+	}
+
+	nFree -= nDirtyCacheChunks;
+
+	nFree -= ((dev->nReservedBlocks + 1) * dev->nChunksPerBlock);
+
+	/* Now we figure out how much to reserve for the checkpoint and report that... */
+	blocksForCheckpoint = yaffs_CalcCheckpointBlocksRequired(dev) - dev->blocksInCheckpoint;
+	if (blocksForCheckpoint < 0)
+		blocksForCheckpoint = 0;
+
+	nFree -= (blocksForCheckpoint * dev->nChunksPerBlock);
+
+	if (nFree < 0)
+		nFree = 0;
+
+	return nFree;
+
+}
+
+static int yaffs_freeVerificationFailures;
+
+static void yaffs_VerifyFreeChunks(yaffs_Device *dev)
+{
+	int counted;
+	int difference;
+
+	if (yaffs_SkipVerification(dev))
+		return;
+
+	counted = yaffs_CountFreeChunks(dev);
+
+	difference = dev->nFreeChunks - counted;
+
+	if (difference) {
+		T(YAFFS_TRACE_ALWAYS,
+		  (TSTR("Freechunks verification failure %d %d %d" TENDSTR),
+		   dev->nFreeChunks, counted, difference));
+		yaffs_freeVerificationFailures++;
+	}
+}
+
+/*---------------------------------------- YAFFS test code ----------------------*/
+
+#define yaffs_CheckStruct(structure, syze, name) \
+	do { \
+		if (sizeof(structure) != syze) { \
+			T(YAFFS_TRACE_ALWAYS, (TSTR("%s should be %d but is %d\n" TENDSTR),\
+				name, syze, sizeof(structure))); \
+			return YAFFS_FAIL; \
+		} \
+	} while (0)
+
+static int yaffs_CheckStructures(void)
+{
+/*      yaffs_CheckStruct(yaffs_Tags,8,"yaffs_Tags"); */
+/*      yaffs_CheckStruct(yaffs_TagsUnion,8,"yaffs_TagsUnion"); */
+/*      yaffs_CheckStruct(yaffs_Spare,16,"yaffs_Spare"); */
+#ifndef CONFIG_YAFFS_TNODE_LIST_DEBUG
+	yaffs_CheckStruct(yaffs_Tnode, 2 * YAFFS_NTNODES_LEVEL0, "yaffs_Tnode");
+#endif
+#ifndef CONFIG_YAFFS_WINCE
+	yaffs_CheckStruct(yaffs_ObjectHeader, 512, "yaffs_ObjectHeader");
+#endif
+	return YAFFS_OK;
+}
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_guts.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_guts.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_guts.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_guts.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,904 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_GUTS_H__
+#define __YAFFS_GUTS_H__
+
+#include "devextras.h"
+#include "yportenv.h"
+
+#define YAFFS_OK	1
+#define YAFFS_FAIL  0
+
+/* Give us a  Y=0x59,
+ * Give us an A=0x41,
+ * Give us an FF=0xFF
+ * Give us an S=0x53
+ * And what have we got...
+ */
+#define YAFFS_MAGIC			0x5941FF53
+
+#define YAFFS_NTNODES_LEVEL0	  	16
+#define YAFFS_TNODES_LEVEL0_BITS	4
+#define YAFFS_TNODES_LEVEL0_MASK	0xf
+
+#define YAFFS_NTNODES_INTERNAL 		(YAFFS_NTNODES_LEVEL0 / 2)
+#define YAFFS_TNODES_INTERNAL_BITS 	(YAFFS_TNODES_LEVEL0_BITS - 1)
+#define YAFFS_TNODES_INTERNAL_MASK	0x7
+#define YAFFS_TNODES_MAX_LEVEL		6
+
+#ifndef CONFIG_YAFFS_NO_YAFFS1
+#define YAFFS_BYTES_PER_SPARE		16
+#define YAFFS_BYTES_PER_CHUNK		512
+#define YAFFS_CHUNK_SIZE_SHIFT		9
+#define YAFFS_CHUNKS_PER_BLOCK		32
+#define YAFFS_BYTES_PER_BLOCK		(YAFFS_CHUNKS_PER_BLOCK*YAFFS_BYTES_PER_CHUNK)
+#endif
+
+#define YAFFS_MIN_YAFFS2_CHUNK_SIZE 	1024
+#define YAFFS_MIN_YAFFS2_SPARE_SIZE	32
+
+#define YAFFS_MAX_CHUNK_ID		0x000FFFFF
+
+#define YAFFS_UNUSED_OBJECT_ID		0x0003FFFF
+
+#define YAFFS_ALLOCATION_NOBJECTS	100
+#define YAFFS_ALLOCATION_NTNODES	100
+#define YAFFS_ALLOCATION_NLINKS		100
+
+#define YAFFS_NOBJECT_BUCKETS		256
+
+
+#define YAFFS_OBJECT_SPACE		0x40000
+
+#define YAFFS_CHECKPOINT_VERSION 	3
+
+#ifdef CONFIG_YAFFS_UNICODE
+#define YAFFS_MAX_NAME_LENGTH		127
+#define YAFFS_MAX_ALIAS_LENGTH		79
+#else
+#define YAFFS_MAX_NAME_LENGTH		255
+#define YAFFS_MAX_ALIAS_LENGTH		159
+#endif
+
+#define YAFFS_SHORT_NAME_LENGTH		15
+
+/* Some special object ids for pseudo objects */
+#define YAFFS_OBJECTID_ROOT		1
+#define YAFFS_OBJECTID_LOSTNFOUND	2
+#define YAFFS_OBJECTID_UNLINKED		3
+#define YAFFS_OBJECTID_DELETED		4
+
+/* Sseudo object ids for checkpointing */
+#define YAFFS_OBJECTID_SB_HEADER	0x10
+#define YAFFS_OBJECTID_CHECKPOINT_DATA	0x20
+#define YAFFS_SEQUENCE_CHECKPOINT_DATA  0x21
+
+/* */
+
+#define YAFFS_MAX_SHORT_OP_CACHES	20
+
+#define YAFFS_N_TEMP_BUFFERS		6
+
+/* We limit the number attempts at sucessfully saving a chunk of data.
+ * Small-page devices have 32 pages per block; large-page devices have 64.
+ * Default to something in the order of 5 to 10 blocks worth of chunks.
+ */
+#define YAFFS_WR_ATTEMPTS		(5*64)
+
+/* Sequence numbers are used in YAFFS2 to determine block allocation order.
+ * The range is limited slightly to help distinguish bad numbers from good.
+ * This also allows us to perhaps in the future use special numbers for
+ * special purposes.
+ * EFFFFF00 allows the allocation of 8 blocks per second (~1Mbytes) for 15 years,
+ * and is a larger number than the lifetime of a 2GB device.
+ */
+#define YAFFS_LOWEST_SEQUENCE_NUMBER	0x00001000
+#define YAFFS_HIGHEST_SEQUENCE_NUMBER	0xEFFFFF00
+
+/* Special sequence number for bad block that failed to be marked bad */
+#define YAFFS_SEQUENCE_BAD_BLOCK	0xFFFF0000
+
+/* ChunkCache is used for short read/write operations.*/
+typedef struct {
+	struct yaffs_ObjectStruct *object;
+	int chunkId;
+	int lastUse;
+	int dirty;
+	int nBytes;		/* Only valid if the cache is dirty */
+	int locked;		/* Can't push out or flush while locked. */
+#ifdef CONFIG_YAFFS_YAFFS2
+	__u8 *data;
+#else
+	__u8 data[YAFFS_BYTES_PER_CHUNK];
+#endif
+} yaffs_ChunkCache;
+
+
+
+/* Tags structures in RAM
+ * NB This uses bitfield. Bitfields should not straddle a u32 boundary otherwise
+ * the structure size will get blown out.
+ */
+
+#ifndef CONFIG_YAFFS_NO_YAFFS1
+typedef struct {
+	unsigned chunkId:20;
+	unsigned serialNumber:2;
+	unsigned byteCountLSB:10;
+	unsigned objectId:18;
+	unsigned ecc:12;
+	unsigned byteCountMSB:2;
+} yaffs_Tags;
+
+typedef union {
+	yaffs_Tags asTags;
+	__u8 asBytes[8];
+} yaffs_TagsUnion;
+
+#endif
+
+/* Stuff used for extended tags in YAFFS2 */
+
+typedef enum {
+	YAFFS_ECC_RESULT_UNKNOWN,
+	YAFFS_ECC_RESULT_NO_ERROR,
+	YAFFS_ECC_RESULT_FIXED,
+	YAFFS_ECC_RESULT_UNFIXED
+} yaffs_ECCResult;
+
+typedef enum {
+	YAFFS_OBJECT_TYPE_UNKNOWN,
+	YAFFS_OBJECT_TYPE_FILE,
+	YAFFS_OBJECT_TYPE_SYMLINK,
+	YAFFS_OBJECT_TYPE_DIRECTORY,
+	YAFFS_OBJECT_TYPE_HARDLINK,
+	YAFFS_OBJECT_TYPE_SPECIAL
+} yaffs_ObjectType;
+
+#define YAFFS_OBJECT_TYPE_MAX YAFFS_OBJECT_TYPE_SPECIAL
+
+typedef struct {
+
+	unsigned validMarker0;
+	unsigned chunkUsed;	/*  Status of the chunk: used or unused */
+	unsigned objectId;	/* If 0 then this is not part of an object (unused) */
+	unsigned chunkId;	/* If 0 then this is a header, else a data chunk */
+	unsigned byteCount;	/* Only valid for data chunks */
+
+	/* The following stuff only has meaning when we read */
+	yaffs_ECCResult eccResult;
+	unsigned blockBad;
+
+	/* YAFFS 1 stuff */
+	unsigned chunkDeleted;	/* The chunk is marked deleted */
+	unsigned serialNumber;	/* Yaffs1 2-bit serial number */
+
+	/* YAFFS2 stuff */
+	unsigned sequenceNumber;	/* The sequence number of this block */
+
+	/* Extra info if this is an object header (YAFFS2 only) */
+
+	unsigned extraHeaderInfoAvailable;	/* There is extra info available if this is not zero */
+	unsigned extraParentObjectId;	/* The parent object */
+	unsigned extraIsShrinkHeader;	/* Is it a shrink header? */
+	unsigned extraShadows;		/* Does this shadow another object? */
+
+	yaffs_ObjectType extraObjectType;	/* What object type? */
+
+	unsigned extraFileLength;		/* Length if it is a file */
+	unsigned extraEquivalentObjectId;	/* Equivalent object Id if it is a hard link */
+
+	unsigned validMarker1;
+
+} yaffs_ExtendedTags;
+
+/* Spare structure for YAFFS1 */
+typedef struct {
+	__u8 tagByte0;
+	__u8 tagByte1;
+	__u8 tagByte2;
+	__u8 tagByte3;
+	__u8 pageStatus;	/* set to 0 to delete the chunk */
+	__u8 blockStatus;
+	__u8 tagByte4;
+	__u8 tagByte5;
+	__u8 ecc1[3];
+	__u8 tagByte6;
+	__u8 tagByte7;
+	__u8 ecc2[3];
+} yaffs_Spare;
+
+/*Special structure for passing through to mtd */
+struct yaffs_NANDSpare {
+	yaffs_Spare spare;
+	int eccres1;
+	int eccres2;
+};
+
+/* Block data in RAM */
+
+typedef enum {
+	YAFFS_BLOCK_STATE_UNKNOWN = 0,
+
+	YAFFS_BLOCK_STATE_SCANNING,
+	YAFFS_BLOCK_STATE_NEEDS_SCANNING,
+	/* The block might have something on it (ie it is allocating or full, perhaps empty)
+	 * but it needs to be scanned to determine its true state.
+	 * This state is only valid during yaffs_Scan.
+	 * NB We tolerate empty because the pre-scanner might be incapable of deciding
+	 * However, if this state is returned on a YAFFS2 device, then we expect a sequence number
+	 */
+
+	YAFFS_BLOCK_STATE_EMPTY,
+	/* This block is empty */
+
+	YAFFS_BLOCK_STATE_ALLOCATING,
+	/* This block is partially allocated.
+	 * At least one page holds valid data.
+	 * This is the one currently being used for page
+	 * allocation. Should never be more than one of these
+	 */
+
+	YAFFS_BLOCK_STATE_FULL,
+	/* All the pages in this block have been allocated.
+	 */
+
+	YAFFS_BLOCK_STATE_DIRTY,
+	/* All pages have been allocated and deleted.
+	 * Erase me, reuse me.
+	 */
+
+	YAFFS_BLOCK_STATE_CHECKPOINT,
+	/* This block is assigned to holding checkpoint data.
+	 */
+
+	YAFFS_BLOCK_STATE_COLLECTING,
+	/* This block is being garbage collected */
+
+	YAFFS_BLOCK_STATE_DEAD
+	/* This block has failed and is not in use */
+} yaffs_BlockState;
+
+#define	YAFFS_NUMBER_OF_BLOCK_STATES (YAFFS_BLOCK_STATE_DEAD + 1)
+
+
+typedef struct {
+
+	int softDeletions:10;	/* number of soft deleted pages */
+	int pagesInUse:10;	/* number of pages in use */
+	unsigned blockState:4;	/* One of the above block states. NB use unsigned because enum is sometimes an int */
+	__u32 needsRetiring:1;	/* Data has failed on this block, need to get valid data off */
+				/* and retire the block. */
+	__u32 skipErasedCheck:1; /* If this is set we can skip the erased check on this block */
+	__u32 gcPrioritise:1; 	/* An ECC check or blank check has failed on this block.
+				   It should be prioritised for GC */
+	__u32 chunkErrorStrikes:3; /* How many times we've had ecc etc failures on this block and tried to reuse it */
+
+#ifdef CONFIG_YAFFS_YAFFS2
+	__u32 hasShrinkHeader:1; /* This block has at least one shrink object header */
+	__u32 sequenceNumber;	 /* block sequence number for yaffs2 */
+#endif
+
+} yaffs_BlockInfo;
+
+/* -------------------------- Object structure -------------------------------*/
+/* This is the object structure as stored on NAND */
+
+typedef struct {
+	yaffs_ObjectType type;
+
+	/* Apply to everything  */
+	int parentObjectId;
+	__u16 sum__NoLongerUsed;        /* checksum of name. No longer used */
+	YCHAR name[YAFFS_MAX_NAME_LENGTH + 1];
+
+	/* The following apply to directories, files, symlinks - not hard links */
+	__u32 yst_mode;         /* protection */
+
+#ifdef CONFIG_YAFFS_WINCE
+	__u32 notForWinCE[5];
+#else
+	__u32 yst_uid;
+	__u32 yst_gid;
+	__u32 yst_atime;
+	__u32 yst_mtime;
+	__u32 yst_ctime;
+#endif
+
+	/* File size  applies to files only */
+	int fileSize;
+
+	/* Equivalent object id applies to hard links only. */
+	int equivalentObjectId;
+
+	/* Alias is for symlinks only. */
+	YCHAR alias[YAFFS_MAX_ALIAS_LENGTH + 1];
+
+	__u32 yst_rdev;		/* device stuff for block and char devices (major/min) */
+
+#ifdef CONFIG_YAFFS_WINCE
+	__u32 win_ctime[2];
+	__u32 win_atime[2];
+	__u32 win_mtime[2];
+#else
+	__u32 roomToGrow[6];
+
+#endif
+	__u32 inbandShadowsObject;
+	__u32 inbandIsShrink;
+
+	__u32 reservedSpace[2];
+	int shadowsObject;	/* This object header shadows the specified object if > 0 */
+
+	/* isShrink applies to object headers written when we shrink the file (ie resize) */
+	__u32 isShrink;
+
+} yaffs_ObjectHeader;
+
+/*--------------------------- Tnode -------------------------- */
+
+union yaffs_Tnode_union {
+#ifdef CONFIG_YAFFS_TNODE_LIST_DEBUG
+	union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL + 1];
+#else
+	union yaffs_Tnode_union *internal[YAFFS_NTNODES_INTERNAL];
+#endif
+/*	__u16 level0[YAFFS_NTNODES_LEVEL0]; */
+
+};
+
+typedef union yaffs_Tnode_union yaffs_Tnode;
+
+struct yaffs_TnodeList_struct {
+	struct yaffs_TnodeList_struct *next;
+	yaffs_Tnode *tnodes;
+};
+
+typedef struct yaffs_TnodeList_struct yaffs_TnodeList;
+
+/*------------------------  Object -----------------------------*/
+/* An object can be one of:
+ * - a directory (no data, has children links
+ * - a regular file (data.... not prunes :->).
+ * - a symlink [symbolic link] (the alias).
+ * - a hard link
+ */
+
+typedef struct {
+	__u32 fileSize;
+	__u32 scannedFileSize;
+	__u32 shrinkSize;
+	int topLevel;
+	yaffs_Tnode *top;
+} yaffs_FileStructure;
+
+typedef struct {
+	struct ylist_head children;     /* list of child links */
+} yaffs_DirectoryStructure;
+
+typedef struct {
+	YCHAR *alias;
+} yaffs_SymLinkStructure;
+
+typedef struct {
+	struct yaffs_ObjectStruct *equivalentObject;
+	__u32 equivalentObjectId;
+} yaffs_HardLinkStructure;
+
+typedef union {
+	yaffs_FileStructure fileVariant;
+	yaffs_DirectoryStructure directoryVariant;
+	yaffs_SymLinkStructure symLinkVariant;
+	yaffs_HardLinkStructure hardLinkVariant;
+} yaffs_ObjectVariant;
+
+struct yaffs_ObjectStruct {
+	__u8 deleted:1;		/* This should only apply to unlinked files. */
+	__u8 softDeleted:1;	/* it has also been soft deleted */
+	__u8 unlinked:1;	/* An unlinked file. The file should be in the unlinked directory.*/
+	__u8 fake:1;		/* A fake object has no presence on NAND. */
+	__u8 renameAllowed:1;	/* Some objects are not allowed to be renamed. */
+	__u8 unlinkAllowed:1;
+	__u8 dirty:1;		/* the object needs to be written to flash */
+	__u8 valid:1;		/* When the file system is being loaded up, this
+				 * object might be created before the data
+				 * is available (ie. file data records appear before the header).
+				 */
+	__u8 lazyLoaded:1;	/* This object has been lazy loaded and is missing some detail */
+
+	__u8 deferedFree:1;	/* For Linux kernel. Object is removed from NAND, but is
+				 * still in the inode cache. Free of object is defered.
+				 * until the inode is released.
+				 */
+	__u8 beingCreated:1;	/* This object is still being created so skip some checks. */
+
+	__u8 serial;		/* serial number of chunk in NAND. Cached here */
+	__u16 sum;		/* sum of the name to speed searching */
+
+	struct yaffs_DeviceStruct *myDev;       /* The device I'm on */
+
+	struct ylist_head hashLink;     /* list of objects in this hash bucket */
+
+	struct ylist_head hardLinks;    /* all the equivalent hard linked objects */
+
+	/* directory structure stuff */
+	/* also used for linking up the free list */
+	struct yaffs_ObjectStruct *parent;
+	struct ylist_head siblings;
+
+	/* Where's my object header in NAND? */
+	int hdrChunk;
+
+	int nDataChunks;	/* Number of data chunks attached to the file. */
+
+	__u32 objectId;		/* the object id value */
+
+	__u32 yst_mode;
+
+#ifdef CONFIG_YAFFS_SHORT_NAMES_IN_RAM
+	YCHAR shortName[YAFFS_SHORT_NAME_LENGTH + 1];
+#endif
+
+#ifndef __KERNEL__
+	__u32 inUse;
+#endif
+
+#ifdef CONFIG_YAFFS_WINCE
+	__u32 win_ctime[2];
+	__u32 win_mtime[2];
+	__u32 win_atime[2];
+#else
+	__u32 yst_uid;
+	__u32 yst_gid;
+	__u32 yst_atime;
+	__u32 yst_mtime;
+	__u32 yst_ctime;
+#endif
+
+	__u32 yst_rdev;
+
+#ifdef __KERNEL__
+	struct inode *myInode;
+
+#endif
+
+	yaffs_ObjectType variantType;
+
+	yaffs_ObjectVariant variant;
+
+};
+
+typedef struct yaffs_ObjectStruct yaffs_Object;
+
+struct yaffs_ObjectList_struct {
+	yaffs_Object *objects;
+	struct yaffs_ObjectList_struct *next;
+};
+
+typedef struct yaffs_ObjectList_struct yaffs_ObjectList;
+
+typedef struct {
+	struct ylist_head list;
+	int count;
+} yaffs_ObjectBucket;
+
+
+/* yaffs_CheckpointObject holds the definition of an object as dumped
+ * by checkpointing.
+ */
+
+typedef struct {
+	int structType;
+	__u32 objectId;
+	__u32 parentId;
+	int hdrChunk;
+	yaffs_ObjectType variantType:3;
+	__u8 deleted:1;
+	__u8 softDeleted:1;
+	__u8 unlinked:1;
+	__u8 fake:1;
+	__u8 renameAllowed:1;
+	__u8 unlinkAllowed:1;
+	__u8 serial;
+
+	int nDataChunks;
+	__u32 fileSizeOrEquivalentObjectId;
+} yaffs_CheckpointObject;
+
+/*--------------------- Temporary buffers ----------------
+ *
+ * These are chunk-sized working buffers. Each device has a few
+ */
+
+typedef struct {
+	__u8 *buffer;
+	int line;	/* track from whence this buffer was allocated */
+	int maxLine;
+} yaffs_TempBuffer;
+
+/*----------------- Device ---------------------------------*/
+
+struct yaffs_DeviceStruct {
+	struct ylist_head devList;
+	const char *name;
+
+	/* Entry parameters set up way early. Yaffs sets up the rest.*/
+	int nDataBytesPerChunk;	/* Should be a power of 2 >= 512 */
+	int nChunksPerBlock;	/* does not need to be a power of 2 */
+	int spareBytesPerChunk;	/* spare area size */
+	int startBlock;		/* Start block we're allowed to use */
+	int endBlock;		/* End block we're allowed to use */
+	int nReservedBlocks;	/* We want this tuneable so that we can reduce */
+				/* reserved blocks on NOR and RAM. */
+
+
+	/* Stuff used by the shared space checkpointing mechanism */
+	/* If this value is zero, then this mechanism is disabled */
+
+/*	int nCheckpointReservedBlocks; */ /* Blocks to reserve for checkpoint data */
+
+
+	int nShortOpCaches;	/* If <= 0, then short op caching is disabled, else
+				 * the number of short op caches (don't use too many)
+				 */
+
+	int useHeaderFileSize;	/* Flag to determine if we should use file sizes from the header */
+
+	int useNANDECC;		/* Flag to decide whether or not to use NANDECC */
+
+	void *genericDevice;	/* Pointer to device context
+				 * On an mtd this holds the mtd pointer.
+				 */
+	void *superBlock;
+
+	/* NAND access functions (Must be set before calling YAFFS)*/
+
+	int (*writeChunkToNAND) (struct yaffs_DeviceStruct *dev,
+					int chunkInNAND, const __u8 *data,
+					const yaffs_Spare *spare);
+	int (*readChunkFromNAND) (struct yaffs_DeviceStruct *dev,
+					int chunkInNAND, __u8 *data,
+					yaffs_Spare *spare);
+	int (*eraseBlockInNAND) (struct yaffs_DeviceStruct *dev,
+					int blockInNAND);
+	int (*initialiseNAND) (struct yaffs_DeviceStruct *dev);
+	int (*deinitialiseNAND) (struct yaffs_DeviceStruct *dev);
+
+#ifdef CONFIG_YAFFS_YAFFS2
+	int (*writeChunkWithTagsToNAND) (struct yaffs_DeviceStruct *dev,
+					 int chunkInNAND, const __u8 *data,
+					 const yaffs_ExtendedTags *tags);
+	int (*readChunkWithTagsFromNAND) (struct yaffs_DeviceStruct *dev,
+					  int chunkInNAND, __u8 *data,
+					  yaffs_ExtendedTags *tags);
+	int (*markNANDBlockBad) (struct yaffs_DeviceStruct *dev, int blockNo);
+	int (*queryNANDBlock) (struct yaffs_DeviceStruct *dev, int blockNo,
+			       yaffs_BlockState *state, __u32 *sequenceNumber);
+#endif
+
+	int isYaffs2;
+
+	/* The removeObjectCallback function must be supplied by OS flavours that
+	 * need it. The Linux kernel does not use this, but yaffs direct does use
+	 * it to implement the faster readdir
+	 */
+	void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
+
+	/* Callback to mark the superblock dirsty */
+	void (*markSuperBlockDirty)(void *superblock);
+
+	int wideTnodesDisabled; /* Set to disable wide tnodes */
+
+	YCHAR *pathDividers;	/* String of legal path dividers */
+
+
+	/* End of stuff that must be set before initialisation. */
+
+	/* Checkpoint control. Can be set before or after initialisation */
+	__u8 skipCheckpointRead;
+	__u8 skipCheckpointWrite;
+
+	/* Runtime parameters. Set up by YAFFS. */
+
+	__u16 chunkGroupBits;	/* 0 for devices <= 32MB. else log2(nchunks) - 16 */
+	__u16 chunkGroupSize;	/* == 2^^chunkGroupBits */
+
+	/* Stuff to support wide tnodes */
+	__u32 tnodeWidth;
+	__u32 tnodeMask;
+
+	/* Stuff for figuring out file offset to chunk conversions */
+	__u32 chunkShift; /* Shift value */
+	__u32 chunkDiv;   /* Divisor after shifting: 1 for power-of-2 sizes */
+	__u32 chunkMask;  /* Mask to use for power-of-2 case */
+
+	/* Stuff to handle inband tags */
+	int inbandTags;
+	__u32 totalBytesPerChunk;
+
+#ifdef __KERNEL__
+
+	struct semaphore sem;	/* Semaphore for waiting on erasure.*/
+	struct semaphore grossLock;	/* Gross locking semaphore */
+	__u8 *spareBuffer;	/* For mtdif2 use. Don't know the size of the buffer
+				 * at compile time so we have to allocate it.
+				 */
+	void (*putSuperFunc) (struct super_block *sb);
+#endif
+
+	int isMounted;
+
+	int isCheckpointed;
+
+
+	/* Stuff to support block offsetting to support start block zero */
+	int internalStartBlock;
+	int internalEndBlock;
+	int blockOffset;
+	int chunkOffset;
+
+
+	/* Runtime checkpointing stuff */
+	int checkpointPageSequence;   /* running sequence number of checkpoint pages */
+	int checkpointByteCount;
+	int checkpointByteOffset;
+	__u8 *checkpointBuffer;
+	int checkpointOpenForWrite;
+	int blocksInCheckpoint;
+	int checkpointCurrentChunk;
+	int checkpointCurrentBlock;
+	int checkpointNextBlock;
+	int *checkpointBlockList;
+	int checkpointMaxBlocks;
+	__u32 checkpointSum;
+	__u32 checkpointXor;
+
+	int nCheckpointBlocksRequired; /* Number of blocks needed to store current checkpoint set */
+
+	/* Block Info */
+	yaffs_BlockInfo *blockInfo;
+	__u8 *chunkBits;	/* bitmap of chunks in use */
+	unsigned blockInfoAlt:1;	/* was allocated using alternative strategy */
+	unsigned chunkBitsAlt:1;	/* was allocated using alternative strategy */
+	int chunkBitmapStride;	/* Number of bytes of chunkBits per block.
+				 * Must be consistent with nChunksPerBlock.
+				 */
+
+	int nErasedBlocks;
+	int allocationBlock;	/* Current block being allocated off */
+	__u32 allocationPage;
+	int allocationBlockFinder;	/* Used to search for next allocation block */
+
+	/* Runtime state */
+	int nTnodesCreated;
+	yaffs_Tnode *freeTnodes;
+	int nFreeTnodes;
+	yaffs_TnodeList *allocatedTnodeList;
+
+	int isDoingGC;
+	int gcBlock;
+	int gcChunk;
+
+	int nObjectsCreated;
+	yaffs_Object *freeObjects;
+	int nFreeObjects;
+
+	int nHardLinks;
+
+	yaffs_ObjectList *allocatedObjectList;
+
+	yaffs_ObjectBucket objectBucket[YAFFS_NOBJECT_BUCKETS];
+
+	int nFreeChunks;
+
+	int currentDirtyChecker;	/* Used to find current dirtiest block */
+
+	__u32 *gcCleanupList;	/* objects to delete at the end of a GC. */
+	int nonAggressiveSkip;	/* GC state/mode */
+
+	/* Statistcs */
+	int nPageWrites;
+	int nPageReads;
+	int nBlockErasures;
+	int nErasureFailures;
+	int nGCCopies;
+	int garbageCollections;
+	int passiveGarbageCollections;
+	int nRetriedWrites;
+	int nRetiredBlocks;
+	int eccFixed;
+	int eccUnfixed;
+	int tagsEccFixed;
+	int tagsEccUnfixed;
+	int nDeletions;
+	int nUnmarkedDeletions;
+
+	int hasPendingPrioritisedGCs; /* We think this device might have pending prioritised gcs */
+
+	/* Special directories */
+	yaffs_Object *rootDir;
+	yaffs_Object *lostNFoundDir;
+
+	/* Buffer areas for storing data to recover from write failures TODO
+	 *      __u8            bufferedData[YAFFS_CHUNKS_PER_BLOCK][YAFFS_BYTES_PER_CHUNK];
+	 *      yaffs_Spare bufferedSpare[YAFFS_CHUNKS_PER_BLOCK];
+	 */
+
+	int bufferedBlock;	/* Which block is buffered here? */
+	int doingBufferedBlockRewrite;
+
+	yaffs_ChunkCache *srCache;
+	int srLastUse;
+
+	int cacheHits;
+
+	/* Stuff for background deletion and unlinked files.*/
+	yaffs_Object *unlinkedDir;	/* Directory where unlinked and deleted files live. */
+	yaffs_Object *deletedDir;	/* Directory where deleted objects are sent to disappear. */
+	yaffs_Object *unlinkedDeletion;	/* Current file being background deleted.*/
+	int nDeletedFiles;		/* Count of files awaiting deletion;*/
+	int nUnlinkedFiles;		/* Count of unlinked files. */
+	int nBackgroundDeletions;	/* Count of background deletions. */
+
+
+	/* Temporary buffer management */
+	yaffs_TempBuffer tempBuffer[YAFFS_N_TEMP_BUFFERS];
+	int maxTemp;
+	int tempInUse;
+	int unmanagedTempAllocations;
+	int unmanagedTempDeallocations;
+
+	/* yaffs2 runtime stuff */
+	unsigned sequenceNumber;	/* Sequence number of currently allocating block */
+	unsigned oldestDirtySequence;
+
+};
+
+typedef struct yaffs_DeviceStruct yaffs_Device;
+
+/* The static layout of block usage etc is stored in the super block header */
+typedef struct {
+	int StructType;
+	int version;
+	int checkpointStartBlock;
+	int checkpointEndBlock;
+	int startBlock;
+	int endBlock;
+	int rfu[100];
+} yaffs_SuperBlockHeader;
+
+/* The CheckpointDevice structure holds the device information that changes at runtime and
+ * must be preserved over unmount/mount cycles.
+ */
+typedef struct {
+	int structType;
+	int nErasedBlocks;
+	int allocationBlock;	/* Current block being allocated off */
+	__u32 allocationPage;
+	int nFreeChunks;
+
+	int nDeletedFiles;		/* Count of files awaiting deletion;*/
+	int nUnlinkedFiles;		/* Count of unlinked files. */
+	int nBackgroundDeletions;	/* Count of background deletions. */
+
+	/* yaffs2 runtime stuff */
+	unsigned sequenceNumber;	/* Sequence number of currently allocating block */
+	unsigned oldestDirtySequence;
+
+} yaffs_CheckpointDevice;
+
+
+typedef struct {
+	int structType;
+	__u32 magic;
+	__u32 version;
+	__u32 head;
+} yaffs_CheckpointValidity;
+
+
+/*----------------------- YAFFS Functions -----------------------*/
+
+int yaffs_GutsInitialise(yaffs_Device *dev);
+void yaffs_Deinitialise(yaffs_Device *dev);
+
+int yaffs_GetNumberOfFreeChunks(yaffs_Device *dev);
+
+int yaffs_RenameObject(yaffs_Object *oldDir, const YCHAR *oldName,
+		       yaffs_Object *newDir, const YCHAR *newName);
+
+int yaffs_Unlink(yaffs_Object *dir, const YCHAR *name);
+int yaffs_DeleteObject(yaffs_Object *obj);
+
+int yaffs_GetObjectName(yaffs_Object *obj, YCHAR *name, int buffSize);
+int yaffs_GetObjectFileLength(yaffs_Object *obj);
+int yaffs_GetObjectInode(yaffs_Object *obj);
+unsigned yaffs_GetObjectType(yaffs_Object *obj);
+int yaffs_GetObjectLinkCount(yaffs_Object *obj);
+
+int yaffs_SetAttributes(yaffs_Object *obj, struct iattr *attr);
+int yaffs_GetAttributes(yaffs_Object *obj, struct iattr *attr);
+
+/* File operations */
+int yaffs_ReadDataFromFile(yaffs_Object *obj, __u8 *buffer, loff_t offset,
+				int nBytes);
+int yaffs_WriteDataToFile(yaffs_Object *obj, const __u8 *buffer, loff_t offset,
+				int nBytes, int writeThrough);
+int yaffs_ResizeFile(yaffs_Object *obj, loff_t newSize);
+
+yaffs_Object *yaffs_MknodFile(yaffs_Object *parent, const YCHAR *name,
+				__u32 mode, __u32 uid, __u32 gid);
+int yaffs_FlushFile(yaffs_Object *obj, int updateTime);
+
+/* Flushing and checkpointing */
+void yaffs_FlushEntireDeviceCache(yaffs_Device *dev);
+
+int yaffs_CheckpointSave(yaffs_Device *dev);
+int yaffs_CheckpointRestore(yaffs_Device *dev);
+
+/* Directory operations */
+yaffs_Object *yaffs_MknodDirectory(yaffs_Object *parent, const YCHAR *name,
+				__u32 mode, __u32 uid, __u32 gid);
+yaffs_Object *yaffs_FindObjectByName(yaffs_Object *theDir, const YCHAR *name);
+int yaffs_ApplyToDirectoryChildren(yaffs_Object *theDir,
+				   int (*fn) (yaffs_Object *));
+
+yaffs_Object *yaffs_FindObjectByNumber(yaffs_Device *dev, __u32 number);
+
+/* Link operations */
+yaffs_Object *yaffs_Link(yaffs_Object *parent, const YCHAR *name,
+			 yaffs_Object *equivalentObject);
+
+yaffs_Object *yaffs_GetEquivalentObject(yaffs_Object *obj);
+
+/* Symlink operations */
+yaffs_Object *yaffs_MknodSymLink(yaffs_Object *parent, const YCHAR *name,
+				 __u32 mode, __u32 uid, __u32 gid,
+				 const YCHAR *alias);
+YCHAR *yaffs_GetSymlinkAlias(yaffs_Object *obj);
+
+/* Special inodes (fifos, sockets and devices) */
+yaffs_Object *yaffs_MknodSpecial(yaffs_Object *parent, const YCHAR *name,
+				 __u32 mode, __u32 uid, __u32 gid, __u32 rdev);
+
+/* Special directories */
+yaffs_Object *yaffs_Root(yaffs_Device *dev);
+yaffs_Object *yaffs_LostNFound(yaffs_Device *dev);
+
+#ifdef CONFIG_YAFFS_WINCE
+/* CONFIG_YAFFS_WINCE special stuff */
+void yfsd_WinFileTimeNow(__u32 target[2]);
+#endif
+
+#ifdef __KERNEL__
+
+void yaffs_HandleDeferedFree(yaffs_Object *obj);
+#endif
+
+/* Debug dump  */
+int yaffs_DumpObject(yaffs_Object *obj);
+
+void yaffs_GutsTest(yaffs_Device *dev);
+
+/* A few useful functions */
+void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
+void yaffs_DeleteChunk(yaffs_Device *dev, int chunkId, int markNAND, int lyn);
+int yaffs_CheckFF(__u8 *buffer, int nBytes);
+void yaffs_HandleChunkError(yaffs_Device *dev, yaffs_BlockInfo *bi);
+
+__u8 *yaffs_GetTempBuffer(yaffs_Device *dev, int lineNo);
+void yaffs_ReleaseTempBuffer(yaffs_Device *dev, __u8 *buffer, int lineNo);
+
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffsinterface.h linux-2.6.29.6.mod/fs/yaffs2/yaffsinterface.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffsinterface.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffsinterface.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,21 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFSINTERFACE_H__
+#define __YAFFSINTERFACE_H__
+
+int yaffs_Initialise(unsigned nBlocks);
+
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif1.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif1.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif1.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif1.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,365 @@
+/*
+ * YAFFS: Yet another FFS. A NAND-flash specific file system.
+ * yaffs_mtdif1.c  NAND mtd interface functions for small-page NAND.
+ *
+ * Copyright (C) 2002 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * 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 module provides the interface between yaffs_nand.c and the
+ * MTD API.  This version is used when the MTD interface supports the
+ * 'mtd_oob_ops' style calls to read_oob and write_oob, circa 2.6.17,
+ * and we have small-page NAND device.
+ *
+ * These functions are invoked via function pointers in yaffs_nand.c.
+ * This replaces functionality provided by functions in yaffs_mtdif.c
+ * and the yaffs_TagsCompatability functions in yaffs_tagscompat.c that are
+ * called in yaffs_mtdif.c when the function pointers are NULL.
+ * We assume the MTD layer is performing ECC (useNANDECC is true).
+ */
+
+#include "yportenv.h"
+#include "yaffs_guts.h"
+#include "yaffs_packedtags1.h"
+#include "yaffs_tagscompat.h"	/* for yaffs_CalcTagsECC */
+
+#include "linux/kernel.h"
+#include "linux/version.h"
+#include "linux/types.h"
+#include "linux/mtd/mtd.h"
+
+/* Don't compile this module if we don't have MTD's mtd_oob_ops interface */
+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
+
+const char *yaffs_mtdif1_c_version = "$Id: yaffs_mtdif1.c,v 1.10 2009-03-09 07:41:10 charles Exp $";
+
+#ifndef CONFIG_YAFFS_9BYTE_TAGS
+# define YTAG1_SIZE 8
+#else
+# define YTAG1_SIZE 9
+#endif
+
+#if 0
+/* Use the following nand_ecclayout with MTD when using
+ * CONFIG_YAFFS_9BYTE_TAGS and the older on-NAND tags layout.
+ * If you have existing Yaffs images and the byte order differs from this,
+ * adjust 'oobfree' to match your existing Yaffs data.
+ *
+ * This nand_ecclayout scatters/gathers to/from the old-yaffs layout with the
+ * pageStatus byte (at NAND spare offset 4) scattered/gathered from/to
+ * the 9th byte.
+ *
+ * Old-style on-NAND format: T0,T1,T2,T3,P,B,T4,T5,E0,E1,E2,T6,T7,E3,E4,E5
+ * We have/need PackedTags1 plus pageStatus: T0,T1,T2,T3,T4,T5,T6,T7,P
+ * where Tn are the tag bytes, En are MTD's ECC bytes, P is the pageStatus
+ * byte and B is the small-page bad-block indicator byte.
+ */
+static struct nand_ecclayout nand_oob_16 = {
+	.eccbytes = 6,
+	.eccpos = { 8, 9, 10, 13, 14, 15 },
+	.oobavail = 9,
+	.oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
+};
+#endif
+
+/* Write a chunk (page) of data to NAND.
+ *
+ * Caller always provides ExtendedTags data which are converted to a more
+ * compact (packed) form for storage in NAND.  A mini-ECC runs over the
+ * contents of the tags meta-data; used to valid the tags when read.
+ *
+ *  - Pack ExtendedTags to PackedTags1 form
+ *  - Compute mini-ECC for PackedTags1
+ *  - Write data and packed tags to NAND.
+ *
+ * Note: Due to the use of the PackedTags1 meta-data which does not include
+ * a full sequence number (as found in the larger PackedTags2 form) it is
+ * necessary for Yaffs to re-write a chunk/page (just once) to mark it as
+ * discarded and dirty.  This is not ideal: newer NAND parts are supposed
+ * to be written just once.  When Yaffs performs this operation, this
+ * function is called with a NULL data pointer -- calling MTD write_oob
+ * without data is valid usage (2.6.17).
+ *
+ * Any underlying MTD error results in YAFFS_FAIL.
+ * Returns YAFFS_OK or YAFFS_FAIL.
+ */
+int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev,
+	int chunkInNAND, const __u8 *data, const yaffs_ExtendedTags *etags)
+{
+	struct mtd_info *mtd = dev->genericDevice;
+	int chunkBytes = dev->nDataBytesPerChunk;
+	loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
+	struct mtd_oob_ops ops;
+	yaffs_PackedTags1 pt1;
+	int retval;
+
+	/* we assume that PackedTags1 and yaffs_Tags are compatible */
+	compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
+	compile_time_assertion(sizeof(yaffs_Tags) == 8);
+
+	dev->nPageWrites++;
+
+	yaffs_PackTags1(&pt1, etags);
+	yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
+
+	/* When deleting a chunk, the upper layer provides only skeletal
+	 * etags, one with chunkDeleted set.  However, we need to update the
+	 * tags, not erase them completely.  So we use the NAND write property
+	 * that only zeroed-bits stick and set tag bytes to all-ones and
+	 * zero just the (not) deleted bit.
+	 */
+#ifndef CONFIG_YAFFS_9BYTE_TAGS
+	if (etags->chunkDeleted) {
+		memset(&pt1, 0xff, 8);
+		/* clear delete status bit to indicate deleted */
+		pt1.deleted = 0;
+	}
+#else
+	((__u8 *)&pt1)[8] = 0xff;
+	if (etags->chunkDeleted) {
+		memset(&pt1, 0xff, 8);
+		/* zero pageStatus byte to indicate deleted */
+		((__u8 *)&pt1)[8] = 0;
+	}
+#endif
+
+	memset(&ops, 0, sizeof(ops));
+	ops.mode = MTD_OOB_AUTO;
+	ops.len = (data) ? chunkBytes : 0;
+	ops.ooblen = YTAG1_SIZE;
+	ops.datbuf = (__u8 *)data;
+	ops.oobbuf = (__u8 *)&pt1;
+
+	retval = mtd->write_oob(mtd, addr, &ops);
+	if (retval) {
+		yaffs_trace(YAFFS_TRACE_MTD,
+			"write_oob failed, chunk %d, mtd error %d\n",
+			chunkInNAND, retval);
+	}
+	return retval ? YAFFS_FAIL : YAFFS_OK;
+}
+
+/* Return with empty ExtendedTags but add eccResult.
+ */
+static int rettags(yaffs_ExtendedTags *etags, int eccResult, int retval)
+{
+	if (etags) {
+		memset(etags, 0, sizeof(*etags));
+		etags->eccResult = eccResult;
+	}
+	return retval;
+}
+
+/* Read a chunk (page) from NAND.
+ *
+ * Caller expects ExtendedTags data to be usable even on error; that is,
+ * all members except eccResult and blockBad are zeroed.
+ *
+ *  - Check ECC results for data (if applicable)
+ *  - Check for blank/erased block (return empty ExtendedTags if blank)
+ *  - Check the PackedTags1 mini-ECC (correct if necessary/possible)
+ *  - Convert PackedTags1 to ExtendedTags
+ *  - Update eccResult and blockBad members to refect state.
+ *
+ * Returns YAFFS_OK or YAFFS_FAIL.
+ */
+int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev,
+	int chunkInNAND, __u8 *data, yaffs_ExtendedTags *etags)
+{
+	struct mtd_info *mtd = dev->genericDevice;
+	int chunkBytes = dev->nDataBytesPerChunk;
+	loff_t addr = ((loff_t)chunkInNAND) * chunkBytes;
+	int eccres = YAFFS_ECC_RESULT_NO_ERROR;
+	struct mtd_oob_ops ops;
+	yaffs_PackedTags1 pt1;
+	int retval;
+	int deleted;
+
+	dev->nPageReads++;
+
+	memset(&ops, 0, sizeof(ops));
+	ops.mode = MTD_OOB_AUTO;
+	ops.len = (data) ? chunkBytes : 0;
+	ops.ooblen = YTAG1_SIZE;
+	ops.datbuf = data;
+	ops.oobbuf = (__u8 *)&pt1;
+
+#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 20))
+	/* In MTD 2.6.18 to 2.6.19 nand_base.c:nand_do_read_oob() has a bug;
+	 * help it out with ops.len = ops.ooblen when ops.datbuf == NULL.
+	 */
+	ops.len = (ops.datbuf) ? ops.len : ops.ooblen;
+#endif
+	/* Read page and oob using MTD.
+	 * Check status and determine ECC result.
+	 */
+	retval = mtd->read_oob(mtd, addr, &ops);
+	if (retval) {
+		yaffs_trace(YAFFS_TRACE_MTD,
+			"read_oob failed, chunk %d, mtd error %d\n",
+			chunkInNAND, retval);
+	}
+
+	switch (retval) {
+	case 0:
+		/* no error */
+		break;
+
+	case -EUCLEAN:
+		/* MTD's ECC fixed the data */
+		eccres = YAFFS_ECC_RESULT_FIXED;
+		dev->eccFixed++;
+		break;
+
+	case -EBADMSG:
+		/* MTD's ECC could not fix the data */
+		dev->eccUnfixed++;
+		/* fall into... */
+	default:
+		rettags(etags, YAFFS_ECC_RESULT_UNFIXED, 0);
+		etags->blockBad = (mtd->block_isbad)(mtd, addr);
+		return YAFFS_FAIL;
+	}
+
+	/* Check for a blank/erased chunk.
+	 */
+	if (yaffs_CheckFF((__u8 *)&pt1, 8)) {
+		/* when blank, upper layers want eccResult to be <= NO_ERROR */
+		return rettags(etags, YAFFS_ECC_RESULT_NO_ERROR, YAFFS_OK);
+	}
+
+#ifndef CONFIG_YAFFS_9BYTE_TAGS
+	/* Read deleted status (bit) then return it to it's non-deleted
+	 * state before performing tags mini-ECC check. pt1.deleted is
+	 * inverted.
+	 */
+	deleted = !pt1.deleted;
+	pt1.deleted = 1;
+#else
+	deleted = (yaffs_CountBits(((__u8 *)&pt1)[8]) < 7);
+#endif
+
+	/* Check the packed tags mini-ECC and correct if necessary/possible.
+	 */
+	retval = yaffs_CheckECCOnTags((yaffs_Tags *)&pt1);
+	switch (retval) {
+	case 0:
+		/* no tags error, use MTD result */
+		break;
+	case 1:
+		/* recovered tags-ECC error */
+		dev->tagsEccFixed++;
+		if (eccres == YAFFS_ECC_RESULT_NO_ERROR)
+			eccres = YAFFS_ECC_RESULT_FIXED;
+		break;
+	default:
+		/* unrecovered tags-ECC error */
+		dev->tagsEccUnfixed++;
+		return rettags(etags, YAFFS_ECC_RESULT_UNFIXED, YAFFS_FAIL);
+	}
+
+	/* Unpack the tags to extended form and set ECC result.
+	 * [set shouldBeFF just to keep yaffs_UnpackTags1 happy]
+	 */
+	pt1.shouldBeFF = 0xFFFFFFFF;
+	yaffs_UnpackTags1(etags, &pt1);
+	etags->eccResult = eccres;
+
+	/* Set deleted state */
+	etags->chunkDeleted = deleted;
+	return YAFFS_OK;
+}
+
+/* Mark a block bad.
+ *
+ * This is a persistant state.
+ * Use of this function should be rare.
+ *
+ * Returns YAFFS_OK or YAFFS_FAIL.
+ */
+int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
+{
+	struct mtd_info *mtd = dev->genericDevice;
+	int blocksize = dev->nChunksPerBlock * dev->nDataBytesPerChunk;
+	int retval;
+
+	yaffs_trace(YAFFS_TRACE_BAD_BLOCKS, "marking block %d bad\n", blockNo);
+
+	retval = mtd->block_markbad(mtd, (loff_t)blocksize * blockNo);
+	return (retval) ? YAFFS_FAIL : YAFFS_OK;
+}
+
+/* Check any MTD prerequists.
+ *
+ * Returns YAFFS_OK or YAFFS_FAIL.
+ */
+static int nandmtd1_TestPrerequists(struct mtd_info *mtd)
+{
+	/* 2.6.18 has mtd->ecclayout->oobavail */
+	/* 2.6.21 has mtd->ecclayout->oobavail and mtd->oobavail */
+	int oobavail = mtd->ecclayout->oobavail;
+
+	if (oobavail < YTAG1_SIZE) {
+		yaffs_trace(YAFFS_TRACE_ERROR,
+			"mtd device has only %d bytes for tags, need %d\n",
+			oobavail, YTAG1_SIZE);
+		return YAFFS_FAIL;
+	}
+	return YAFFS_OK;
+}
+
+/* Query for the current state of a specific block.
+ *
+ * Examine the tags of the first chunk of the block and return the state:
+ *  - YAFFS_BLOCK_STATE_DEAD, the block is marked bad
+ *  - YAFFS_BLOCK_STATE_NEEDS_SCANNING, the block is in use
+ *  - YAFFS_BLOCK_STATE_EMPTY, the block is clean
+ *
+ * Always returns YAFFS_OK.
+ */
+int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
+	yaffs_BlockState *pState, __u32 *pSequenceNumber)
+{
+	struct mtd_info *mtd = dev->genericDevice;
+	int chunkNo = blockNo * dev->nChunksPerBlock;
+	loff_t addr = (loff_t)chunkNo * dev->nDataBytesPerChunk;
+	yaffs_ExtendedTags etags;
+	int state = YAFFS_BLOCK_STATE_DEAD;
+	int seqnum = 0;
+	int retval;
+
+	/* We don't yet have a good place to test for MTD config prerequists.
+	 * Do it here as we are called during the initial scan.
+	 */
+	if (nandmtd1_TestPrerequists(mtd) != YAFFS_OK)
+		return YAFFS_FAIL;
+
+	retval = nandmtd1_ReadChunkWithTagsFromNAND(dev, chunkNo, NULL, &etags);
+	etags.blockBad = (mtd->block_isbad)(mtd, addr);
+	if (etags.blockBad) {
+		yaffs_trace(YAFFS_TRACE_BAD_BLOCKS,
+			"block %d is marked bad\n", blockNo);
+		state = YAFFS_BLOCK_STATE_DEAD;
+	} else if (etags.eccResult != YAFFS_ECC_RESULT_NO_ERROR) {
+		/* bad tags, need to look more closely */
+		state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
+	} else if (etags.chunkUsed) {
+		state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
+		seqnum = etags.sequenceNumber;
+	} else {
+		state = YAFFS_BLOCK_STATE_EMPTY;
+	}
+
+	*pState = state;
+	*pSequenceNumber = seqnum;
+
+	/* query always succeeds */
+	return YAFFS_OK;
+}
+
+#endif /*MTD_VERSION*/
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif1.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif1.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif1.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif1.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,28 @@
+/*
+ * YAFFS: Yet another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_MTDIF1_H__
+#define __YAFFS_MTDIF1_H__
+
+int nandmtd1_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
+	const __u8 *data, const yaffs_ExtendedTags *tags);
+
+int nandmtd1_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
+	__u8 *data, yaffs_ExtendedTags *tags);
+
+int nandmtd1_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
+
+int nandmtd1_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
+	yaffs_BlockState *state, __u32 *sequenceNumber);
+
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif2.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif2.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif2.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif2.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,246 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+/* mtd interface for YAFFS2 */
+
+const char *yaffs_mtdif2_c_version =
+	"$Id: yaffs_mtdif2.c,v 1.23 2009-03-06 17:20:53 wookey Exp $";
+
+#include "yportenv.h"
+
+
+#include "yaffs_mtdif2.h"
+
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+
+#include "yaffs_packedtags2.h"
+
+/* NB For use with inband tags....
+ * We assume that the data buffer is of size totalBytersPerChunk so that we can also
+ * use it to load the tags.
+ */
+int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
+				      const __u8 *data,
+				      const yaffs_ExtendedTags *tags)
+{
+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
+	struct mtd_oob_ops ops;
+#else
+	size_t dummy;
+#endif
+	int retval = 0;
+
+	loff_t addr;
+
+	yaffs_PackedTags2 pt;
+
+	T(YAFFS_TRACE_MTD,
+	  (TSTR
+	   ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
+	    TENDSTR), chunkInNAND, data, tags));
+
+
+	addr  = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
+
+	/* For yaffs2 writing there must be both data and tags.
+	 * If we're using inband tags, then the tags are stuffed into
+	 * the end of the data buffer.
+	 */
+	if (!data || !tags)
+		BUG();
+	else if (dev->inbandTags) {
+		yaffs_PackedTags2TagsPart *pt2tp;
+		pt2tp = (yaffs_PackedTags2TagsPart *)(data + dev->nDataBytesPerChunk);
+		yaffs_PackTags2TagsPart(pt2tp, tags);
+	} else
+		yaffs_PackTags2(&pt, tags);
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+	ops.mode = MTD_OOB_AUTO;
+	ops.ooblen = (dev->inbandTags) ? 0 : sizeof(pt);
+	ops.len = dev->totalBytesPerChunk;
+	ops.ooboffs = 0;
+	ops.datbuf = (__u8 *)data;
+	ops.oobbuf = (dev->inbandTags) ? NULL : (void *)&pt;
+	retval = mtd->write_oob(mtd, addr, &ops);
+
+#else
+	if (!dev->inbandTags) {
+		retval =
+		    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
+				   &dummy, data, (__u8 *) &pt, NULL);
+	} else {
+		retval =
+		    mtd->write(mtd, addr, dev->totalBytesPerChunk, &dummy,
+			       data);
+	}
+#endif
+
+	if (retval == 0)
+		return YAFFS_OK;
+	else
+		return YAFFS_FAIL;
+}
+
+int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
+				       __u8 *data, yaffs_ExtendedTags *tags)
+{
+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
+	struct mtd_oob_ops ops;
+#endif
+	size_t dummy;
+	int retval = 0;
+	int localData = 0;
+
+	loff_t addr = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
+
+	yaffs_PackedTags2 pt;
+
+	T(YAFFS_TRACE_MTD,
+	  (TSTR
+	   ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
+	    TENDSTR), chunkInNAND, data, tags));
+
+	if (dev->inbandTags) {
+
+		if (!data) {
+			localData = 1;
+			data = yaffs_GetTempBuffer(dev, __LINE__);
+		}
+
+
+	}
+
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
+	if (dev->inbandTags || (data && !tags))
+		retval = mtd->read(mtd, addr, dev->totalBytesPerChunk,
+				&dummy, data);
+	else if (tags) {
+		ops.mode = MTD_OOB_AUTO;
+		ops.ooblen = sizeof(pt);
+		ops.len = data ? dev->nDataBytesPerChunk : sizeof(pt);
+		ops.ooboffs = 0;
+		ops.datbuf = data;
+		ops.oobbuf = dev->spareBuffer;
+		retval = mtd->read_oob(mtd, addr, &ops);
+	}
+#else
+	if (!dev->inbandTags && data && tags) {
+
+		retval = mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
+					  &dummy, data, dev->spareBuffer,
+					  NULL);
+	} else {
+		if (data)
+			retval =
+			    mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
+				      data);
+		if (!dev->inbandTags && tags)
+			retval =
+			    mtd->read_oob(mtd, addr, mtd->oobsize, &dummy,
+					  dev->spareBuffer);
+	}
+#endif
+
+
+	if (dev->inbandTags) {
+		if (tags) {
+			yaffs_PackedTags2TagsPart *pt2tp;
+			pt2tp = (yaffs_PackedTags2TagsPart *)&data[dev->nDataBytesPerChunk];
+			yaffs_UnpackTags2TagsPart(tags, pt2tp);
+		}
+	} else {
+		if (tags) {
+			memcpy(&pt, dev->spareBuffer, sizeof(pt));
+			yaffs_UnpackTags2(tags, &pt);
+		}
+	}
+
+	if (localData)
+		yaffs_ReleaseTempBuffer(dev, data, __LINE__);
+
+	if (tags && retval == -EBADMSG && tags->eccResult == YAFFS_ECC_RESULT_NO_ERROR)
+		tags->eccResult = YAFFS_ECC_RESULT_UNFIXED;
+	if (retval == 0)
+		return YAFFS_OK;
+	else
+		return YAFFS_FAIL;
+}
+
+int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo)
+{
+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+	int retval;
+	T(YAFFS_TRACE_MTD,
+	  (TSTR("nandmtd2_MarkNANDBlockBad %d" TENDSTR), blockNo));
+
+	retval =
+	    mtd->block_markbad(mtd,
+			       blockNo * dev->nChunksPerBlock *
+			       dev->totalBytesPerChunk);
+
+	if (retval == 0)
+		return YAFFS_OK;
+	else
+		return YAFFS_FAIL;
+
+}
+
+int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
+			    yaffs_BlockState *state, __u32 *sequenceNumber)
+{
+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+	int retval;
+
+	T(YAFFS_TRACE_MTD,
+	  (TSTR("nandmtd2_QueryNANDBlock %d" TENDSTR), blockNo));
+	retval =
+	    mtd->block_isbad(mtd,
+			     blockNo * dev->nChunksPerBlock *
+			     dev->totalBytesPerChunk);
+
+	if (retval) {
+		T(YAFFS_TRACE_MTD, (TSTR("block is bad" TENDSTR)));
+
+		*state = YAFFS_BLOCK_STATE_DEAD;
+		*sequenceNumber = 0;
+	} else {
+		yaffs_ExtendedTags t;
+		nandmtd2_ReadChunkWithTagsFromNAND(dev,
+						   blockNo *
+						   dev->nChunksPerBlock, NULL,
+						   &t);
+
+		if (t.chunkUsed) {
+			*sequenceNumber = t.sequenceNumber;
+			*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
+		} else {
+			*sequenceNumber = 0;
+			*state = YAFFS_BLOCK_STATE_EMPTY;
+		}
+	}
+	T(YAFFS_TRACE_MTD,
+	  (TSTR("block is bad seq %d state %d" TENDSTR), *sequenceNumber,
+	   *state));
+
+	if (retval == 0)
+		return YAFFS_OK;
+	else
+		return YAFFS_FAIL;
+}
+
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif2.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif2.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif2.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif2.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,29 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_MTDIF2_H__
+#define __YAFFS_MTDIF2_H__
+
+#include "yaffs_guts.h"
+int nandmtd2_WriteChunkWithTagsToNAND(yaffs_Device *dev, int chunkInNAND,
+				const __u8 *data,
+				const yaffs_ExtendedTags *tags);
+int nandmtd2_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
+				__u8 *data, yaffs_ExtendedTags *tags);
+int nandmtd2_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
+int nandmtd2_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
+			yaffs_BlockState *state, __u32 *sequenceNumber);
+
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,241 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+const char *yaffs_mtdif_c_version =
+	"$Id: yaffs_mtdif.c,v 1.22 2009-03-06 17:20:51 wookey Exp $";
+
+#include "yportenv.h"
+
+
+#include "yaffs_mtdif.h"
+
+#include "linux/mtd/mtd.h"
+#include "linux/types.h"
+#include "linux/time.h"
+#include "linux/mtd/nand.h"
+
+#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
+static struct nand_oobinfo yaffs_oobinfo = {
+	.useecc = 1,
+	.eccbytes = 6,
+	.eccpos = {8, 9, 10, 13, 14, 15}
+};
+
+static struct nand_oobinfo yaffs_noeccinfo = {
+	.useecc = 0,
+};
+#endif
+
+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
+static inline void translate_spare2oob(const yaffs_Spare *spare, __u8 *oob)
+{
+	oob[0] = spare->tagByte0;
+	oob[1] = spare->tagByte1;
+	oob[2] = spare->tagByte2;
+	oob[3] = spare->tagByte3;
+	oob[4] = spare->tagByte4;
+	oob[5] = spare->tagByte5 & 0x3f;
+	oob[5] |= spare->blockStatus == 'Y' ? 0 : 0x80;
+	oob[5] |= spare->pageStatus == 0 ? 0 : 0x40;
+	oob[6] = spare->tagByte6;
+	oob[7] = spare->tagByte7;
+}
+
+static inline void translate_oob2spare(yaffs_Spare *spare, __u8 *oob)
+{
+	struct yaffs_NANDSpare *nspare = (struct yaffs_NANDSpare *)spare;
+	spare->tagByte0 = oob[0];
+	spare->tagByte1 = oob[1];
+	spare->tagByte2 = oob[2];
+	spare->tagByte3 = oob[3];
+	spare->tagByte4 = oob[4];
+	spare->tagByte5 = oob[5] == 0xff ? 0xff : oob[5] & 0x3f;
+	spare->blockStatus = oob[5] & 0x80 ? 0xff : 'Y';
+	spare->pageStatus = oob[5] & 0x40 ? 0xff : 0;
+	spare->ecc1[0] = spare->ecc1[1] = spare->ecc1[2] = 0xff;
+	spare->tagByte6 = oob[6];
+	spare->tagByte7 = oob[7];
+	spare->ecc2[0] = spare->ecc2[1] = spare->ecc2[2] = 0xff;
+
+	nspare->eccres1 = nspare->eccres2 = 0; /* FIXME */
+}
+#endif
+
+int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
+			     const __u8 *data, const yaffs_Spare *spare)
+{
+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
+	struct mtd_oob_ops ops;
+#endif
+	size_t dummy;
+	int retval = 0;
+
+	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
+	__u8 spareAsBytes[8]; /* OOB */
+
+	if (data && !spare)
+		retval = mtd->write(mtd, addr, dev->nDataBytesPerChunk,
+				&dummy, data);
+	else if (spare) {
+		if (dev->useNANDECC) {
+			translate_spare2oob(spare, spareAsBytes);
+			ops.mode = MTD_OOB_AUTO;
+			ops.ooblen = 8; /* temp hack */
+		} else {
+			ops.mode = MTD_OOB_RAW;
+			ops.ooblen = YAFFS_BYTES_PER_SPARE;
+		}
+		ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
+		ops.datbuf = (u8 *)data;
+		ops.ooboffs = 0;
+		ops.oobbuf = spareAsBytes;
+		retval = mtd->write_oob(mtd, addr, &ops);
+	}
+#else
+	__u8 *spareAsBytes = (__u8 *) spare;
+
+	if (data && spare) {
+		if (dev->useNANDECC)
+			retval =
+			    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
+					   &dummy, data, spareAsBytes,
+					   &yaffs_oobinfo);
+		else
+			retval =
+			    mtd->write_ecc(mtd, addr, dev->nDataBytesPerChunk,
+					   &dummy, data, spareAsBytes,
+					   &yaffs_noeccinfo);
+	} else {
+		if (data)
+			retval =
+			    mtd->write(mtd, addr, dev->nDataBytesPerChunk, &dummy,
+				       data);
+		if (spare)
+			retval =
+			    mtd->write_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
+					   &dummy, spareAsBytes);
+	}
+#endif
+
+	if (retval == 0)
+		return YAFFS_OK;
+	else
+		return YAFFS_FAIL;
+}
+
+int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
+			      yaffs_Spare *spare)
+{
+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
+	struct mtd_oob_ops ops;
+#endif
+	size_t dummy;
+	int retval = 0;
+
+	loff_t addr = ((loff_t) chunkInNAND) * dev->nDataBytesPerChunk;
+#if (MTD_VERSION_CODE > MTD_VERSION(2, 6, 17))
+	__u8 spareAsBytes[8]; /* OOB */
+
+	if (data && !spare)
+		retval = mtd->read(mtd, addr, dev->nDataBytesPerChunk,
+				&dummy, data);
+	else if (spare) {
+		if (dev->useNANDECC) {
+			ops.mode = MTD_OOB_AUTO;
+			ops.ooblen = 8; /* temp hack */
+		} else {
+			ops.mode = MTD_OOB_RAW;
+			ops.ooblen = YAFFS_BYTES_PER_SPARE;
+		}
+		ops.len = data ? dev->nDataBytesPerChunk : ops.ooblen;
+		ops.datbuf = data;
+		ops.ooboffs = 0;
+		ops.oobbuf = spareAsBytes;
+		retval = mtd->read_oob(mtd, addr, &ops);
+		if (dev->useNANDECC)
+			translate_oob2spare(spare, spareAsBytes);
+	}
+#else
+	__u8 *spareAsBytes = (__u8 *) spare;
+
+	if (data && spare) {
+		if (dev->useNANDECC) {
+			/* Careful, this call adds 2 ints */
+			/* to the end of the spare data.  Calling function */
+			/* should allocate enough memory for spare, */
+			/* i.e. [YAFFS_BYTES_PER_SPARE+2*sizeof(int)]. */
+			retval =
+			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
+					  &dummy, data, spareAsBytes,
+					  &yaffs_oobinfo);
+		} else {
+			retval =
+			    mtd->read_ecc(mtd, addr, dev->nDataBytesPerChunk,
+					  &dummy, data, spareAsBytes,
+					  &yaffs_noeccinfo);
+		}
+	} else {
+		if (data)
+			retval =
+			    mtd->read(mtd, addr, dev->nDataBytesPerChunk, &dummy,
+				      data);
+		if (spare)
+			retval =
+			    mtd->read_oob(mtd, addr, YAFFS_BYTES_PER_SPARE,
+					  &dummy, spareAsBytes);
+	}
+#endif
+
+	if (retval == 0)
+		return YAFFS_OK;
+	else
+		return YAFFS_FAIL;
+}
+
+int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber)
+{
+	struct mtd_info *mtd = (struct mtd_info *)(dev->genericDevice);
+	__u32 addr =
+	    ((loff_t) blockNumber) * dev->nDataBytesPerChunk
+		* dev->nChunksPerBlock;
+	struct erase_info ei;
+	int retval = 0;
+
+	ei.mtd = mtd;
+	ei.addr = addr;
+	ei.len = dev->nDataBytesPerChunk * dev->nChunksPerBlock;
+	ei.time = 1000;
+	ei.retries = 2;
+	ei.callback = NULL;
+	ei.priv = (u_long) dev;
+
+	/* Todo finish off the ei if required */
+
+	sema_init(&dev->sem, 0);
+
+	retval = mtd->erase(mtd, &ei);
+
+	if (retval == 0)
+		return YAFFS_OK;
+	else
+		return YAFFS_FAIL;
+}
+
+int nandmtd_InitialiseNAND(yaffs_Device *dev)
+{
+	return YAFFS_OK;
+}
+
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_mtdif.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_mtdif.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,32 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_MTDIF_H__
+#define __YAFFS_MTDIF_H__
+
+#include "yaffs_guts.h"
+
+#if (MTD_VERSION_CODE < MTD_VERSION(2, 6, 18))
+extern struct nand_oobinfo yaffs_oobinfo;
+extern struct nand_oobinfo yaffs_noeccinfo;
+#endif
+
+int nandmtd_WriteChunkToNAND(yaffs_Device *dev, int chunkInNAND,
+			const __u8 *data, const yaffs_Spare *spare);
+int nandmtd_ReadChunkFromNAND(yaffs_Device *dev, int chunkInNAND, __u8 *data,
+			yaffs_Spare *spare);
+int nandmtd_EraseBlockInNAND(yaffs_Device *dev, int blockNumber);
+int nandmtd_InitialiseNAND(yaffs_Device *dev);
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_nand.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_nand.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_nand.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_nand.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,135 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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.
+ */
+
+const char *yaffs_nand_c_version =
+	"$Id: yaffs_nand.c,v 1.10 2009-03-06 17:20:54 wookey Exp $";
+
+#include "yaffs_nand.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_tagsvalidity.h"
+
+#include "yaffs_getblockinfo.h"
+
+int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
+					   __u8 *buffer,
+					   yaffs_ExtendedTags *tags)
+{
+	int result;
+	yaffs_ExtendedTags localTags;
+
+	int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
+
+	/* If there are no tags provided, use local tags to get prioritised gc working */
+	if (!tags)
+		tags = &localTags;
+
+	if (dev->readChunkWithTagsFromNAND)
+		result = dev->readChunkWithTagsFromNAND(dev, realignedChunkInNAND, buffer,
+						      tags);
+	else
+		result = yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(dev,
+									realignedChunkInNAND,
+									buffer,
+									tags);
+	if (tags &&
+	   tags->eccResult > YAFFS_ECC_RESULT_NO_ERROR) {
+
+		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, chunkInNAND/dev->nChunksPerBlock);
+		yaffs_HandleChunkError(dev, bi);
+	}
+
+	return result;
+}
+
+int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
+						   int chunkInNAND,
+						   const __u8 *buffer,
+						   yaffs_ExtendedTags *tags)
+{
+	chunkInNAND -= dev->chunkOffset;
+
+
+	if (tags) {
+		tags->sequenceNumber = dev->sequenceNumber;
+		tags->chunkUsed = 1;
+		if (!yaffs_ValidateTags(tags)) {
+			T(YAFFS_TRACE_ERROR,
+			  (TSTR("Writing uninitialised tags" TENDSTR)));
+			YBUG();
+		}
+		T(YAFFS_TRACE_WRITE,
+		  (TSTR("Writing chunk %d tags %d %d" TENDSTR), chunkInNAND,
+		   tags->objectId, tags->chunkId));
+	} else {
+		T(YAFFS_TRACE_ERROR, (TSTR("Writing with no tags" TENDSTR)));
+		YBUG();
+	}
+
+	if (dev->writeChunkWithTagsToNAND)
+		return dev->writeChunkWithTagsToNAND(dev, chunkInNAND, buffer,
+						     tags);
+	else
+		return yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(dev,
+								       chunkInNAND,
+								       buffer,
+								       tags);
+}
+
+int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo)
+{
+	blockNo -= dev->blockOffset;
+
+;
+	if (dev->markNANDBlockBad)
+		return dev->markNANDBlockBad(dev, blockNo);
+	else
+		return yaffs_TagsCompatabilityMarkNANDBlockBad(dev, blockNo);
+}
+
+int yaffs_QueryInitialBlockState(yaffs_Device *dev,
+						 int blockNo,
+						 yaffs_BlockState *state,
+						 __u32 *sequenceNumber)
+{
+	blockNo -= dev->blockOffset;
+
+	if (dev->queryNANDBlock)
+		return dev->queryNANDBlock(dev, blockNo, state, sequenceNumber);
+	else
+		return yaffs_TagsCompatabilityQueryNANDBlock(dev, blockNo,
+							     state,
+							     sequenceNumber);
+}
+
+
+int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
+				  int blockInNAND)
+{
+	int result;
+
+	blockInNAND -= dev->blockOffset;
+
+
+	dev->nBlockErasures++;
+	result = dev->eraseBlockInNAND(dev, blockInNAND);
+
+	return result;
+}
+
+int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev)
+{
+	return dev->initialiseNAND(dev);
+}
+
+
+
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_nandemul2k.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_nandemul2k.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_nandemul2k.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_nandemul2k.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,39 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* Interface to emulated NAND functions (2k page size) */
+
+#ifndef __YAFFS_NANDEMUL2K_H__
+#define __YAFFS_NANDEMUL2K_H__
+
+#include "yaffs_guts.h"
+
+int nandemul2k_WriteChunkWithTagsToNAND(struct yaffs_DeviceStruct *dev,
+					int chunkInNAND, const __u8 *data,
+					const yaffs_ExtendedTags *tags);
+int nandemul2k_ReadChunkWithTagsFromNAND(struct yaffs_DeviceStruct *dev,
+					 int chunkInNAND, __u8 *data,
+					 yaffs_ExtendedTags *tags);
+int nandemul2k_MarkNANDBlockBad(struct yaffs_DeviceStruct *dev, int blockNo);
+int nandemul2k_QueryNANDBlock(struct yaffs_DeviceStruct *dev, int blockNo,
+			      yaffs_BlockState *state, __u32 *sequenceNumber);
+int nandemul2k_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
+				int blockInNAND);
+int nandemul2k_InitialiseNAND(struct yaffs_DeviceStruct *dev);
+int nandemul2k_GetBytesPerChunk(void);
+int nandemul2k_GetChunksPerBlock(void);
+int nandemul2k_GetNumberOfBlocks(void);
+
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_nand.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_nand.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_nand.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_nand.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,44 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_NAND_H__
+#define __YAFFS_NAND_H__
+#include "yaffs_guts.h"
+
+
+
+int yaffs_ReadChunkWithTagsFromNAND(yaffs_Device *dev, int chunkInNAND,
+					__u8 *buffer,
+					yaffs_ExtendedTags *tags);
+
+int yaffs_WriteChunkWithTagsToNAND(yaffs_Device *dev,
+						int chunkInNAND,
+						const __u8 *buffer,
+						yaffs_ExtendedTags *tags);
+
+int yaffs_MarkBlockBad(yaffs_Device *dev, int blockNo);
+
+int yaffs_QueryInitialBlockState(yaffs_Device *dev,
+						int blockNo,
+						yaffs_BlockState *state,
+						unsigned *sequenceNumber);
+
+int yaffs_EraseBlockInNAND(struct yaffs_DeviceStruct *dev,
+				  int blockInNAND);
+
+int yaffs_InitialiseNAND(struct yaffs_DeviceStruct *dev);
+
+#endif
+
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_packedtags1.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_packedtags1.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_packedtags1.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_packedtags1.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,50 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_packedtags1.h"
+#include "yportenv.h"
+
+void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t)
+{
+	pt->chunkId = t->chunkId;
+	pt->serialNumber = t->serialNumber;
+	pt->byteCount = t->byteCount;
+	pt->objectId = t->objectId;
+	pt->ecc = 0;
+	pt->deleted = (t->chunkDeleted) ? 0 : 1;
+	pt->unusedStuff = 0;
+	pt->shouldBeFF = 0xFFFFFFFF;
+
+}
+
+void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt)
+{
+	static const __u8 allFF[] =
+	    { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+0xff };
+
+	if (memcmp(allFF, pt, sizeof(yaffs_PackedTags1))) {
+		t->blockBad = 0;
+		if (pt->shouldBeFF != 0xFFFFFFFF)
+			t->blockBad = 1;
+		t->chunkUsed = 1;
+		t->objectId = pt->objectId;
+		t->chunkId = pt->chunkId;
+		t->byteCount = pt->byteCount;
+		t->eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+		t->chunkDeleted = (pt->deleted) ? 0 : 1;
+		t->serialNumber = pt->serialNumber;
+	} else {
+		memset(t, 0, sizeof(yaffs_ExtendedTags));
+	}
+}
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_packedtags1.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_packedtags1.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_packedtags1.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_packedtags1.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,37 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* This is used to pack YAFFS1 tags, not YAFFS2 tags. */
+
+#ifndef __YAFFS_PACKEDTAGS1_H__
+#define __YAFFS_PACKEDTAGS1_H__
+
+#include "yaffs_guts.h"
+
+typedef struct {
+	unsigned chunkId:20;
+	unsigned serialNumber:2;
+	unsigned byteCount:10;
+	unsigned objectId:18;
+	unsigned ecc:12;
+	unsigned deleted:1;
+	unsigned unusedStuff:1;
+	unsigned shouldBeFF;
+
+} yaffs_PackedTags1;
+
+void yaffs_PackTags1(yaffs_PackedTags1 *pt, const yaffs_ExtendedTags *t);
+void yaffs_UnpackTags1(yaffs_ExtendedTags *t, const yaffs_PackedTags1 *pt);
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_packedtags2.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_packedtags2.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_packedtags2.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_packedtags2.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,206 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_packedtags2.h"
+#include "yportenv.h"
+#include "yaffs_tagsvalidity.h"
+
+/* This code packs a set of extended tags into a binary structure for
+ * NAND storage
+ */
+
+/* Some of the information is "extra" struff which can be packed in to
+ * speed scanning
+ * This is defined by having the EXTRA_HEADER_INFO_FLAG set.
+ */
+
+/* Extra flags applied to chunkId */
+
+#define EXTRA_HEADER_INFO_FLAG	0x80000000
+#define EXTRA_SHRINK_FLAG	0x40000000
+#define EXTRA_SHADOWS_FLAG	0x20000000
+#define EXTRA_SPARE_FLAGS	0x10000000
+
+#define ALL_EXTRA_FLAGS		0xF0000000
+
+/* Also, the top 4 bits of the object Id are set to the object type. */
+#define EXTRA_OBJECT_TYPE_SHIFT (28)
+#define EXTRA_OBJECT_TYPE_MASK  ((0x0F) << EXTRA_OBJECT_TYPE_SHIFT)
+
+
+static void yaffs_DumpPackedTags2TagsPart(const yaffs_PackedTags2TagsPart *ptt)
+{
+	T(YAFFS_TRACE_MTD,
+	  (TSTR("packed tags obj %d chunk %d byte %d seq %d" TENDSTR),
+	   ptt->objectId, ptt->chunkId, ptt->byteCount,
+	   ptt->sequenceNumber));
+}
+static void yaffs_DumpPackedTags2(const yaffs_PackedTags2 *pt)
+{
+	yaffs_DumpPackedTags2TagsPart(&pt->t);
+}
+
+static void yaffs_DumpTags2(const yaffs_ExtendedTags *t)
+{
+	T(YAFFS_TRACE_MTD,
+	  (TSTR
+	   ("ext.tags eccres %d blkbad %d chused %d obj %d chunk%d byte %d del %d ser %d seq %d"
+	    TENDSTR), t->eccResult, t->blockBad, t->chunkUsed, t->objectId,
+	   t->chunkId, t->byteCount, t->chunkDeleted, t->serialNumber,
+	   t->sequenceNumber));
+
+}
+
+void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *ptt,
+		const yaffs_ExtendedTags *t)
+{
+	ptt->chunkId = t->chunkId;
+	ptt->sequenceNumber = t->sequenceNumber;
+	ptt->byteCount = t->byteCount;
+	ptt->objectId = t->objectId;
+
+	if (t->chunkId == 0 && t->extraHeaderInfoAvailable) {
+		/* Store the extra header info instead */
+		/* We save the parent object in the chunkId */
+		ptt->chunkId = EXTRA_HEADER_INFO_FLAG
+			| t->extraParentObjectId;
+		if (t->extraIsShrinkHeader)
+			ptt->chunkId |= EXTRA_SHRINK_FLAG;
+		if (t->extraShadows)
+			ptt->chunkId |= EXTRA_SHADOWS_FLAG;
+
+		ptt->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
+		ptt->objectId |=
+		    (t->extraObjectType << EXTRA_OBJECT_TYPE_SHIFT);
+
+		if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
+			ptt->byteCount = t->extraEquivalentObjectId;
+		else if (t->extraObjectType == YAFFS_OBJECT_TYPE_FILE)
+			ptt->byteCount = t->extraFileLength;
+		else
+			ptt->byteCount = 0;
+	}
+
+	yaffs_DumpPackedTags2TagsPart(ptt);
+	yaffs_DumpTags2(t);
+}
+
+
+void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t)
+{
+	yaffs_PackTags2TagsPart(&pt->t, t);
+
+#ifndef YAFFS_IGNORE_TAGS_ECC
+	{
+		yaffs_ECCCalculateOther((unsigned char *)&pt->t,
+					sizeof(yaffs_PackedTags2TagsPart),
+					&pt->ecc);
+	}
+#endif
+}
+
+
+void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t,
+		yaffs_PackedTags2TagsPart *ptt)
+{
+
+	memset(t, 0, sizeof(yaffs_ExtendedTags));
+
+	yaffs_InitialiseTags(t);
+
+	if (ptt->sequenceNumber != 0xFFFFFFFF) {
+		t->blockBad = 0;
+		t->chunkUsed = 1;
+		t->objectId = ptt->objectId;
+		t->chunkId = ptt->chunkId;
+		t->byteCount = ptt->byteCount;
+		t->chunkDeleted = 0;
+		t->serialNumber = 0;
+		t->sequenceNumber = ptt->sequenceNumber;
+
+		/* Do extra header info stuff */
+
+		if (ptt->chunkId & EXTRA_HEADER_INFO_FLAG) {
+			t->chunkId = 0;
+			t->byteCount = 0;
+
+			t->extraHeaderInfoAvailable = 1;
+			t->extraParentObjectId =
+			    ptt->chunkId & (~(ALL_EXTRA_FLAGS));
+			t->extraIsShrinkHeader =
+			    (ptt->chunkId & EXTRA_SHRINK_FLAG) ? 1 : 0;
+			t->extraShadows =
+			    (ptt->chunkId & EXTRA_SHADOWS_FLAG) ? 1 : 0;
+			t->extraObjectType =
+			    ptt->objectId >> EXTRA_OBJECT_TYPE_SHIFT;
+			t->objectId &= ~EXTRA_OBJECT_TYPE_MASK;
+
+			if (t->extraObjectType == YAFFS_OBJECT_TYPE_HARDLINK)
+				t->extraEquivalentObjectId = ptt->byteCount;
+			else
+				t->extraFileLength = ptt->byteCount;
+		}
+	}
+
+	yaffs_DumpPackedTags2TagsPart(ptt);
+	yaffs_DumpTags2(t);
+
+}
+
+
+void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt)
+{
+
+	yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+
+	if (pt->t.sequenceNumber != 0xFFFFFFFF) {
+		/* Page is in use */
+#ifndef YAFFS_IGNORE_TAGS_ECC
+		{
+			yaffs_ECCOther ecc;
+			int result;
+			yaffs_ECCCalculateOther((unsigned char *)&pt->t,
+						sizeof
+						(yaffs_PackedTags2TagsPart),
+						&ecc);
+			result =
+			    yaffs_ECCCorrectOther((unsigned char *)&pt->t,
+						  sizeof
+						  (yaffs_PackedTags2TagsPart),
+						  &pt->ecc, &ecc);
+			switch (result) {
+			case 0:
+				eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+				break;
+			case 1:
+				eccResult = YAFFS_ECC_RESULT_FIXED;
+				break;
+			case -1:
+				eccResult = YAFFS_ECC_RESULT_UNFIXED;
+				break;
+			default:
+				eccResult = YAFFS_ECC_RESULT_UNKNOWN;
+			}
+		}
+#endif
+	}
+
+	yaffs_UnpackTags2TagsPart(t, &pt->t);
+
+	t->eccResult = eccResult;
+
+	yaffs_DumpPackedTags2(pt);
+	yaffs_DumpTags2(t);
+
+}
+
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_packedtags2.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_packedtags2.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_packedtags2.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_packedtags2.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,43 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+/* This is used to pack YAFFS2 tags, not YAFFS1tags. */
+
+#ifndef __YAFFS_PACKEDTAGS2_H__
+#define __YAFFS_PACKEDTAGS2_H__
+
+#include "yaffs_guts.h"
+#include "yaffs_ecc.h"
+
+typedef struct {
+	unsigned sequenceNumber;
+	unsigned objectId;
+	unsigned chunkId;
+	unsigned byteCount;
+} yaffs_PackedTags2TagsPart;
+
+typedef struct {
+	yaffs_PackedTags2TagsPart t;
+	yaffs_ECCOther ecc;
+} yaffs_PackedTags2;
+
+/* Full packed tags with ECC, used for oob tags */
+void yaffs_PackTags2(yaffs_PackedTags2 *pt, const yaffs_ExtendedTags *t);
+void yaffs_UnpackTags2(yaffs_ExtendedTags *t, yaffs_PackedTags2 *pt);
+
+/* Only the tags part (no ECC for use with inband tags */
+void yaffs_PackTags2TagsPart(yaffs_PackedTags2TagsPart *pt, const yaffs_ExtendedTags *t);
+void yaffs_UnpackTags2TagsPart(yaffs_ExtendedTags *t, yaffs_PackedTags2TagsPart *pt);
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_qsort.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_qsort.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_qsort.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_qsort.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,163 @@
+/*
+ * Copyright (c) 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "yportenv.h"
+/* #include <linux/string.h> */
+
+/*
+ * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
+ */
+#define swapcode(TYPE, parmi, parmj, n) do { 		\
+	long i = (n) / sizeof (TYPE); 			\
+	register TYPE *pi = (TYPE *) (parmi); 		\
+	register TYPE *pj = (TYPE *) (parmj); 		\
+	do { 						\
+		register TYPE	t = *pi;		\
+		*pi++ = *pj;				\
+		*pj++ = t;				\
+	} while (--i > 0);				\
+} while (0)
+
+#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
+	es % sizeof(long) ? 2 : es == sizeof(long) ? 0 : 1;
+
+static __inline void
+swapfunc(char *a, char *b, int n, int swaptype)
+{
+	if (swaptype <= 1)
+		swapcode(long, a, b, n);
+	else
+		swapcode(char, a, b, n);
+}
+
+#define yswap(a, b) do {					\
+	if (swaptype == 0) {				\
+		long t = *(long *)(a);			\
+		*(long *)(a) = *(long *)(b);		\
+		*(long *)(b) = t;			\
+	} else						\
+		swapfunc(a, b, es, swaptype);		\
+} while (0)
+
+#define vecswap(a, b, n) 	if ((n) > 0) swapfunc(a, b, n, swaptype)
+
+static __inline char *
+med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
+{
+	return cmp(a, b) < 0 ?
+		(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a))
+		: (cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c));
+}
+
+#ifndef min
+#define min(a, b) (((a) < (b)) ? (a) : (b))
+#endif
+
+void
+yaffs_qsort(void *aa, size_t n, size_t es,
+	int (*cmp)(const void *, const void *))
+{
+	char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
+	int d, r, swaptype, swap_cnt;
+	register char *a = aa;
+
+loop:	SWAPINIT(a, es);
+	swap_cnt = 0;
+	if (n < 7) {
+		for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
+			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+			     pl -= es)
+				yswap(pl, pl - es);
+		return;
+	}
+	pm = (char *)a + (n / 2) * es;
+	if (n > 7) {
+		pl = (char *)a;
+		pn = (char *)a + (n - 1) * es;
+		if (n > 40) {
+			d = (n / 8) * es;
+			pl = med3(pl, pl + d, pl + 2 * d, cmp);
+			pm = med3(pm - d, pm, pm + d, cmp);
+			pn = med3(pn - 2 * d, pn - d, pn, cmp);
+		}
+		pm = med3(pl, pm, pn, cmp);
+	}
+	yswap(a, pm);
+	pa = pb = (char *)a + es;
+
+	pc = pd = (char *)a + (n - 1) * es;
+	for (;;) {
+		while (pb <= pc && (r = cmp(pb, a)) <= 0) {
+			if (r == 0) {
+				swap_cnt = 1;
+				yswap(pa, pb);
+				pa += es;
+			}
+			pb += es;
+		}
+		while (pb <= pc && (r = cmp(pc, a)) >= 0) {
+			if (r == 0) {
+				swap_cnt = 1;
+				yswap(pc, pd);
+				pd -= es;
+			}
+			pc -= es;
+		}
+		if (pb > pc)
+			break;
+		yswap(pb, pc);
+		swap_cnt = 1;
+		pb += es;
+		pc -= es;
+	}
+	if (swap_cnt == 0) {  /* Switch to insertion sort */
+		for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
+			for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
+			     pl -= es)
+				yswap(pl, pl - es);
+		return;
+	}
+
+	pn = (char *)a + n * es;
+	r = min(pa - (char *)a, pb - pa);
+	vecswap(a, pb - r, r);
+	r = min((long)(pd - pc), (long)(pn - pd - es));
+	vecswap(pb, pn - r, r);
+	r = pb - pa;
+	if (r > es)
+		yaffs_qsort(a, r / es, es, cmp);
+	r = pd - pc;
+	if (r > es) {
+		/* Iterate rather than recurse to save stack space */
+		a = pn - r;
+		n = r / es;
+		goto loop;
+	}
+/*		yaffs_qsort(pn - r, r / es, es, cmp);*/
+}
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_qsort.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_qsort.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_qsort.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_qsort.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,23 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YAFFS_QSORT_H__
+#define __YAFFS_QSORT_H__
+
+extern void yaffs_qsort(void *const base, size_t total_elems, size_t size,
+			int (*cmp)(const void *, const void *));
+
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_tagscompat.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_tagscompat.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_tagscompat.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_tagscompat.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,541 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_guts.h"
+#include "yaffs_tagscompat.h"
+#include "yaffs_ecc.h"
+#include "yaffs_getblockinfo.h"
+
+static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND);
+#ifdef NOTYET
+static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND);
+static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
+				     const __u8 *data,
+				     const yaffs_Spare *spare);
+static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
+				    const yaffs_Spare *spare);
+static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND);
+#endif
+
+static const char yaffs_countBitsTable[256] = {
+	0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7,
+	4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8
+};
+
+int yaffs_CountBits(__u8 x)
+{
+	int retVal;
+	retVal = yaffs_countBitsTable[x];
+	return retVal;
+}
+
+/********** Tags ECC calculations  *********/
+
+void yaffs_CalcECC(const __u8 *data, yaffs_Spare *spare)
+{
+	yaffs_ECCCalculate(data, spare->ecc1);
+	yaffs_ECCCalculate(&data[256], spare->ecc2);
+}
+
+void yaffs_CalcTagsECC(yaffs_Tags *tags)
+{
+	/* Calculate an ecc */
+
+	unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
+	unsigned i, j;
+	unsigned ecc = 0;
+	unsigned bit = 0;
+
+	tags->ecc = 0;
+
+	for (i = 0; i < 8; i++) {
+		for (j = 1; j & 0xff; j <<= 1) {
+			bit++;
+			if (b[i] & j)
+				ecc ^= bit;
+		}
+	}
+
+	tags->ecc = ecc;
+
+}
+
+int yaffs_CheckECCOnTags(yaffs_Tags *tags)
+{
+	unsigned ecc = tags->ecc;
+
+	yaffs_CalcTagsECC(tags);
+
+	ecc ^= tags->ecc;
+
+	if (ecc && ecc <= 64) {
+		/* TODO: Handle the failure better. Retire? */
+		unsigned char *b = ((yaffs_TagsUnion *) tags)->asBytes;
+
+		ecc--;
+
+		b[ecc / 8] ^= (1 << (ecc & 7));
+
+		/* Now recvalc the ecc */
+		yaffs_CalcTagsECC(tags);
+
+		return 1;	/* recovered error */
+	} else if (ecc) {
+		/* Wierd ecc failure value */
+		/* TODO Need to do somethiong here */
+		return -1;	/* unrecovered error */
+	}
+
+	return 0;
+}
+
+/********** Tags **********/
+
+static void yaffs_LoadTagsIntoSpare(yaffs_Spare *sparePtr,
+				yaffs_Tags *tagsPtr)
+{
+	yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
+
+	yaffs_CalcTagsECC(tagsPtr);
+
+	sparePtr->tagByte0 = tu->asBytes[0];
+	sparePtr->tagByte1 = tu->asBytes[1];
+	sparePtr->tagByte2 = tu->asBytes[2];
+	sparePtr->tagByte3 = tu->asBytes[3];
+	sparePtr->tagByte4 = tu->asBytes[4];
+	sparePtr->tagByte5 = tu->asBytes[5];
+	sparePtr->tagByte6 = tu->asBytes[6];
+	sparePtr->tagByte7 = tu->asBytes[7];
+}
+
+static void yaffs_GetTagsFromSpare(yaffs_Device *dev, yaffs_Spare *sparePtr,
+				yaffs_Tags *tagsPtr)
+{
+	yaffs_TagsUnion *tu = (yaffs_TagsUnion *) tagsPtr;
+	int result;
+
+	tu->asBytes[0] = sparePtr->tagByte0;
+	tu->asBytes[1] = sparePtr->tagByte1;
+	tu->asBytes[2] = sparePtr->tagByte2;
+	tu->asBytes[3] = sparePtr->tagByte3;
+	tu->asBytes[4] = sparePtr->tagByte4;
+	tu->asBytes[5] = sparePtr->tagByte5;
+	tu->asBytes[6] = sparePtr->tagByte6;
+	tu->asBytes[7] = sparePtr->tagByte7;
+
+	result = yaffs_CheckECCOnTags(tagsPtr);
+	if (result > 0)
+		dev->tagsEccFixed++;
+	else if (result < 0)
+		dev->tagsEccUnfixed++;
+}
+
+static void yaffs_SpareInitialise(yaffs_Spare *spare)
+{
+	memset(spare, 0xFF, sizeof(yaffs_Spare));
+}
+
+static int yaffs_WriteChunkToNAND(struct yaffs_DeviceStruct *dev,
+				int chunkInNAND, const __u8 *data,
+				yaffs_Spare *spare)
+{
+	if (chunkInNAND < dev->startBlock * dev->nChunksPerBlock) {
+		T(YAFFS_TRACE_ERROR,
+		  (TSTR("**>> yaffs chunk %d is not valid" TENDSTR),
+		   chunkInNAND));
+		return YAFFS_FAIL;
+	}
+
+	dev->nPageWrites++;
+	return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
+}
+
+static int yaffs_ReadChunkFromNAND(struct yaffs_DeviceStruct *dev,
+				   int chunkInNAND,
+				   __u8 *data,
+				   yaffs_Spare *spare,
+				   yaffs_ECCResult *eccResult,
+				   int doErrorCorrection)
+{
+	int retVal;
+	yaffs_Spare localSpare;
+
+	dev->nPageReads++;
+
+	if (!spare && data) {
+		/* If we don't have a real spare, then we use a local one. */
+		/* Need this for the calculation of the ecc */
+		spare = &localSpare;
+	}
+
+	if (!dev->useNANDECC) {
+		retVal = dev->readChunkFromNAND(dev, chunkInNAND, data, spare);
+		if (data && doErrorCorrection) {
+			/* Do ECC correction */
+			/* Todo handle any errors */
+			int eccResult1, eccResult2;
+			__u8 calcEcc[3];
+
+			yaffs_ECCCalculate(data, calcEcc);
+			eccResult1 =
+			    yaffs_ECCCorrect(data, spare->ecc1, calcEcc);
+			yaffs_ECCCalculate(&data[256], calcEcc);
+			eccResult2 =
+			    yaffs_ECCCorrect(&data[256], spare->ecc2, calcEcc);
+
+			if (eccResult1 > 0) {
+				T(YAFFS_TRACE_ERROR,
+				  (TSTR
+				   ("**>>yaffs ecc error fix performed on chunk %d:0"
+				    TENDSTR), chunkInNAND));
+				dev->eccFixed++;
+			} else if (eccResult1 < 0) {
+				T(YAFFS_TRACE_ERROR,
+				  (TSTR
+				   ("**>>yaffs ecc error unfixed on chunk %d:0"
+				    TENDSTR), chunkInNAND));
+				dev->eccUnfixed++;
+			}
+
+			if (eccResult2 > 0) {
+				T(YAFFS_TRACE_ERROR,
+				  (TSTR
+				   ("**>>yaffs ecc error fix performed on chunk %d:1"
+				    TENDSTR), chunkInNAND));
+				dev->eccFixed++;
+			} else if (eccResult2 < 0) {
+				T(YAFFS_TRACE_ERROR,
+				  (TSTR
+				   ("**>>yaffs ecc error unfixed on chunk %d:1"
+				    TENDSTR), chunkInNAND));
+				dev->eccUnfixed++;
+			}
+
+			if (eccResult1 || eccResult2) {
+				/* We had a data problem on this page */
+				yaffs_HandleReadDataError(dev, chunkInNAND);
+			}
+
+			if (eccResult1 < 0 || eccResult2 < 0)
+				*eccResult = YAFFS_ECC_RESULT_UNFIXED;
+			else if (eccResult1 > 0 || eccResult2 > 0)
+				*eccResult = YAFFS_ECC_RESULT_FIXED;
+			else
+				*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+		}
+	} else {
+		/* Must allocate enough memory for spare+2*sizeof(int) */
+		/* for ecc results from device. */
+		struct yaffs_NANDSpare nspare;
+
+		memset(&nspare, 0, sizeof(nspare));
+
+		retVal = dev->readChunkFromNAND(dev, chunkInNAND, data,
+					(yaffs_Spare *) &nspare);
+		memcpy(spare, &nspare, sizeof(yaffs_Spare));
+		if (data && doErrorCorrection) {
+			if (nspare.eccres1 > 0) {
+				T(YAFFS_TRACE_ERROR,
+				  (TSTR
+				   ("**>>mtd ecc error fix performed on chunk %d:0"
+				    TENDSTR), chunkInNAND));
+			} else if (nspare.eccres1 < 0) {
+				T(YAFFS_TRACE_ERROR,
+				  (TSTR
+				   ("**>>mtd ecc error unfixed on chunk %d:0"
+				    TENDSTR), chunkInNAND));
+			}
+
+			if (nspare.eccres2 > 0) {
+				T(YAFFS_TRACE_ERROR,
+				  (TSTR
+				   ("**>>mtd ecc error fix performed on chunk %d:1"
+				    TENDSTR), chunkInNAND));
+			} else if (nspare.eccres2 < 0) {
+				T(YAFFS_TRACE_ERROR,
+				  (TSTR
+				   ("**>>mtd ecc error unfixed on chunk %d:1"
+				    TENDSTR), chunkInNAND));
+			}
+
+			if (nspare.eccres1 || nspare.eccres2) {
+				/* We had a data problem on this page */
+				yaffs_HandleReadDataError(dev, chunkInNAND);
+			}
+
+			if (nspare.eccres1 < 0 || nspare.eccres2 < 0)
+				*eccResult = YAFFS_ECC_RESULT_UNFIXED;
+			else if (nspare.eccres1 > 0 || nspare.eccres2 > 0)
+				*eccResult = YAFFS_ECC_RESULT_FIXED;
+			else
+				*eccResult = YAFFS_ECC_RESULT_NO_ERROR;
+
+		}
+	}
+	return retVal;
+}
+
+#ifdef NOTYET
+static int yaffs_CheckChunkErased(struct yaffs_DeviceStruct *dev,
+				  int chunkInNAND)
+{
+	static int init;
+	static __u8 cmpbuf[YAFFS_BYTES_PER_CHUNK];
+	static __u8 data[YAFFS_BYTES_PER_CHUNK];
+	/* Might as well always allocate the larger size for */
+	/* dev->useNANDECC == true; */
+	static __u8 spare[sizeof(struct yaffs_NANDSpare)];
+
+	dev->readChunkFromNAND(dev, chunkInNAND, data, (yaffs_Spare *) spare);
+
+	if (!init) {
+		memset(cmpbuf, 0xff, YAFFS_BYTES_PER_CHUNK);
+		init = 1;
+	}
+
+	if (memcmp(cmpbuf, data, YAFFS_BYTES_PER_CHUNK))
+		return YAFFS_FAIL;
+	if (memcmp(cmpbuf, spare, 16))
+		return YAFFS_FAIL;
+
+	return YAFFS_OK;
+
+}
+#endif
+
+/*
+ * Functions for robustisizing
+ */
+
+static void yaffs_HandleReadDataError(yaffs_Device *dev, int chunkInNAND)
+{
+	int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
+
+	/* Mark the block for retirement */
+	yaffs_GetBlockInfo(dev, blockInNAND + dev->blockOffset)->needsRetiring = 1;
+	T(YAFFS_TRACE_ERROR | YAFFS_TRACE_BAD_BLOCKS,
+	  (TSTR("**>>Block %d marked for retirement" TENDSTR), blockInNAND));
+
+	/* TODO:
+	 * Just do a garbage collection on the affected block
+	 * then retire the block
+	 * NB recursion
+	 */
+}
+
+#ifdef NOTYET
+static void yaffs_CheckWrittenBlock(yaffs_Device *dev, int chunkInNAND)
+{
+}
+
+static void yaffs_HandleWriteChunkOk(yaffs_Device *dev, int chunkInNAND,
+				     const __u8 *data,
+				     const yaffs_Spare *spare)
+{
+}
+
+static void yaffs_HandleUpdateChunk(yaffs_Device *dev, int chunkInNAND,
+				    const yaffs_Spare *spare)
+{
+}
+
+static void yaffs_HandleWriteChunkError(yaffs_Device *dev, int chunkInNAND)
+{
+	int blockInNAND = chunkInNAND / dev->nChunksPerBlock;
+
+	/* Mark the block for retirement */
+	yaffs_GetBlockInfo(dev, blockInNAND)->needsRetiring = 1;
+	/* Delete the chunk */
+	yaffs_DeleteChunk(dev, chunkInNAND, 1, __LINE__);
+}
+
+static int yaffs_VerifyCompare(const __u8 *d0, const __u8 *d1,
+			       const yaffs_Spare *s0, const yaffs_Spare *s1)
+{
+
+	if (memcmp(d0, d1, YAFFS_BYTES_PER_CHUNK) != 0 ||
+	    s0->tagByte0 != s1->tagByte0 ||
+	    s0->tagByte1 != s1->tagByte1 ||
+	    s0->tagByte2 != s1->tagByte2 ||
+	    s0->tagByte3 != s1->tagByte3 ||
+	    s0->tagByte4 != s1->tagByte4 ||
+	    s0->tagByte5 != s1->tagByte5 ||
+	    s0->tagByte6 != s1->tagByte6 ||
+	    s0->tagByte7 != s1->tagByte7 ||
+	    s0->ecc1[0] != s1->ecc1[0] ||
+	    s0->ecc1[1] != s1->ecc1[1] ||
+	    s0->ecc1[2] != s1->ecc1[2] ||
+	    s0->ecc2[0] != s1->ecc2[0] ||
+	    s0->ecc2[1] != s1->ecc2[1] || s0->ecc2[2] != s1->ecc2[2]) {
+		return 0;
+	}
+
+	return 1;
+}
+#endif				/* NOTYET */
+
+int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
+						int chunkInNAND,
+						const __u8 *data,
+						const yaffs_ExtendedTags *eTags)
+{
+	yaffs_Spare spare;
+	yaffs_Tags tags;
+
+	yaffs_SpareInitialise(&spare);
+
+	if (eTags->chunkDeleted)
+		spare.pageStatus = 0;
+	else {
+		tags.objectId = eTags->objectId;
+		tags.chunkId = eTags->chunkId;
+
+		tags.byteCountLSB = eTags->byteCount & 0x3ff;
+
+		if (dev->nDataBytesPerChunk >= 1024)
+			tags.byteCountMSB = (eTags->byteCount >> 10) & 3;
+		else
+			tags.byteCountMSB = 3;
+
+
+		tags.serialNumber = eTags->serialNumber;
+
+		if (!dev->useNANDECC && data)
+			yaffs_CalcECC(data, &spare);
+
+		yaffs_LoadTagsIntoSpare(&spare, &tags);
+
+	}
+
+	return yaffs_WriteChunkToNAND(dev, chunkInNAND, data, &spare);
+}
+
+int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
+						     int chunkInNAND,
+						     __u8 *data,
+						     yaffs_ExtendedTags *eTags)
+{
+
+	yaffs_Spare spare;
+	yaffs_Tags tags;
+	yaffs_ECCResult eccResult = YAFFS_ECC_RESULT_UNKNOWN;
+
+	static yaffs_Spare spareFF;
+	static int init;
+
+	if (!init) {
+		memset(&spareFF, 0xFF, sizeof(spareFF));
+		init = 1;
+	}
+
+	if (yaffs_ReadChunkFromNAND
+	    (dev, chunkInNAND, data, &spare, &eccResult, 1)) {
+		/* eTags may be NULL */
+		if (eTags) {
+
+			int deleted =
+			    (yaffs_CountBits(spare.pageStatus) < 7) ? 1 : 0;
+
+			eTags->chunkDeleted = deleted;
+			eTags->eccResult = eccResult;
+			eTags->blockBad = 0;	/* We're reading it */
+			/* therefore it is not a bad block */
+			eTags->chunkUsed =
+			    (memcmp(&spareFF, &spare, sizeof(spareFF)) !=
+			     0) ? 1 : 0;
+
+			if (eTags->chunkUsed) {
+				yaffs_GetTagsFromSpare(dev, &spare, &tags);
+
+				eTags->objectId = tags.objectId;
+				eTags->chunkId = tags.chunkId;
+				eTags->byteCount = tags.byteCountLSB;
+
+				if (dev->nDataBytesPerChunk >= 1024)
+					eTags->byteCount |= (((unsigned) tags.byteCountMSB) << 10);
+
+				eTags->serialNumber = tags.serialNumber;
+			}
+		}
+
+		return YAFFS_OK;
+	} else {
+		return YAFFS_FAIL;
+	}
+}
+
+int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
+					    int blockInNAND)
+{
+
+	yaffs_Spare spare;
+
+	memset(&spare, 0xff, sizeof(yaffs_Spare));
+
+	spare.blockStatus = 'Y';
+
+	yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock, NULL,
+			       &spare);
+	yaffs_WriteChunkToNAND(dev, blockInNAND * dev->nChunksPerBlock + 1,
+			       NULL, &spare);
+
+	return YAFFS_OK;
+
+}
+
+int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
+					  int blockNo,
+					  yaffs_BlockState *state,
+					  __u32 *sequenceNumber)
+{
+
+	yaffs_Spare spare0, spare1;
+	static yaffs_Spare spareFF;
+	static int init;
+	yaffs_ECCResult dummy;
+
+	if (!init) {
+		memset(&spareFF, 0xFF, sizeof(spareFF));
+		init = 1;
+	}
+
+	*sequenceNumber = 0;
+
+	yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock, NULL,
+				&spare0, &dummy, 1);
+	yaffs_ReadChunkFromNAND(dev, blockNo * dev->nChunksPerBlock + 1, NULL,
+				&spare1, &dummy, 1);
+
+	if (yaffs_CountBits(spare0.blockStatus & spare1.blockStatus) < 7)
+		*state = YAFFS_BLOCK_STATE_DEAD;
+	else if (memcmp(&spareFF, &spare0, sizeof(spareFF)) == 0)
+		*state = YAFFS_BLOCK_STATE_EMPTY;
+	else
+		*state = YAFFS_BLOCK_STATE_NEEDS_SCANNING;
+
+	return YAFFS_OK;
+}
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_tagscompat.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_tagscompat.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_tagscompat.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_tagscompat.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,39 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+#ifndef __YAFFS_TAGSCOMPAT_H__
+#define __YAFFS_TAGSCOMPAT_H__
+
+#include "yaffs_guts.h"
+int yaffs_TagsCompatabilityWriteChunkWithTagsToNAND(yaffs_Device *dev,
+						int chunkInNAND,
+						const __u8 *data,
+						const yaffs_ExtendedTags *tags);
+int yaffs_TagsCompatabilityReadChunkWithTagsFromNAND(yaffs_Device *dev,
+						int chunkInNAND,
+						__u8 *data,
+						yaffs_ExtendedTags *tags);
+int yaffs_TagsCompatabilityMarkNANDBlockBad(struct yaffs_DeviceStruct *dev,
+					    int blockNo);
+int yaffs_TagsCompatabilityQueryNANDBlock(struct yaffs_DeviceStruct *dev,
+					  int blockNo,
+					  yaffs_BlockState *state,
+					  __u32 *sequenceNumber);
+
+void yaffs_CalcTagsECC(yaffs_Tags *tags);
+int yaffs_CheckECCOnTags(yaffs_Tags *tags);
+int yaffs_CountBits(__u8 byte);
+
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_tagsvalidity.c linux-2.6.29.6.mod/fs/yaffs2/yaffs_tagsvalidity.c
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_tagsvalidity.c	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_tagsvalidity.c	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,28 @@
+/*
+ * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * 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 "yaffs_tagsvalidity.h"
+
+void yaffs_InitialiseTags(yaffs_ExtendedTags *tags)
+{
+	memset(tags, 0, sizeof(yaffs_ExtendedTags));
+	tags->validMarker0 = 0xAAAAAAAA;
+	tags->validMarker1 = 0x55555555;
+}
+
+int yaffs_ValidateTags(yaffs_ExtendedTags *tags)
+{
+	return (tags->validMarker0 == 0xAAAAAAAA &&
+		tags->validMarker1 == 0x55555555);
+
+}
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yaffs_tagsvalidity.h linux-2.6.29.6.mod/fs/yaffs2/yaffs_tagsvalidity.h
--- linux-2.6.29.6.orig/fs/yaffs2/yaffs_tagsvalidity.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yaffs_tagsvalidity.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,24 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YAFFS_TAGS_VALIDITY_H__
+#define __YAFFS_TAGS_VALIDITY_H__
+
+#include "yaffs_guts.h"
+
+void yaffs_InitialiseTags(yaffs_ExtendedTags *tags);
+int yaffs_ValidateTags(yaffs_ExtendedTags *tags);
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/fs/yaffs2/yportenv.h linux-2.6.29.6.mod/fs/yaffs2/yportenv.h
--- linux-2.6.29.6.orig/fs/yaffs2/yportenv.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/fs/yaffs2/yportenv.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,203 @@
+/*
+ * YAFFS: Yet another Flash File System . A NAND-flash specific file system.
+ *
+ * Copyright (C) 2002-2007 Aleph One Ltd.
+ *   for Toby Churchill Ltd and Brightstar Engineering
+ *
+ * Created by Charles Manning <charles@aleph1.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 2.1 as
+ * published by the Free Software Foundation.
+ *
+ * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL.
+ */
+
+
+#ifndef __YPORTENV_H__
+#define __YPORTENV_H__
+
+/*
+ * Define the MTD version in terms of Linux Kernel versions
+ * This allows yaffs to be used independantly of the kernel
+ * as well as with it.
+ */
+
+#define MTD_VERSION(a, b, c) (((a) << 16) + ((b) << 8) + (c))
+
+#if defined CONFIG_YAFFS_WINCE
+
+#include "ywinceenv.h"
+
+#elif defined __KERNEL__
+
+#include "moduleconfig.h"
+
+/* Linux kernel */
+
+#include <linux/version.h>
+#define MTD_VERSION_CODE LINUX_VERSION_CODE
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
+#include <linux/config.h>
+#endif
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+
+#define YCHAR char
+#define YUCHAR unsigned char
+#define _Y(x)     x
+#define yaffs_strcat(a, b)     strcat(a, b)
+#define yaffs_strcpy(a, b)     strcpy(a, b)
+#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
+#define yaffs_strncmp(a, b, c) strncmp(a, b, c)
+#define yaffs_strlen(s)	       strlen(s)
+#define yaffs_sprintf	       sprintf
+#define yaffs_toupper(a)       toupper(a)
+
+#define Y_INLINE inline
+
+#define YAFFS_LOSTNFOUND_NAME		"lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX		"obj"
+
+/* #define YPRINTF(x) printk x */
+#define YMALLOC(x) kmalloc(x, GFP_NOFS)
+#define YFREE(x)   kfree(x)
+#define YMALLOC_ALT(x) vmalloc(x)
+#define YFREE_ALT(x)   vfree(x)
+#define YMALLOC_DMA(x) YMALLOC(x)
+
+/* KR - added for use in scan so processes aren't blocked indefinitely. */
+#define YYIELD() schedule()
+
+#define YAFFS_ROOT_MODE			0666
+#define YAFFS_LOSTNFOUND_MODE		0666
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
+#define Y_CURRENT_TIME CURRENT_TIME.tv_sec
+#define Y_TIME_CONVERT(x) (x).tv_sec
+#else
+#define Y_CURRENT_TIME CURRENT_TIME
+#define Y_TIME_CONVERT(x) (x)
+#endif
+
+#define yaffs_SumCompare(x, y) ((x) == (y))
+#define yaffs_strcmp(a, b) strcmp(a, b)
+
+#define TENDSTR "\n"
+#define TSTR(x) KERN_WARNING x
+#define TCONT(x) x
+#define TOUT(p) printk p
+
+#define yaffs_trace(mask, fmt, args...) \
+	do { if ((mask) & (yaffs_traceMask|YAFFS_TRACE_ERROR)) \
+		printk(KERN_WARNING "yaffs: " fmt, ## args); \
+	} while (0)
+
+#define compile_time_assertion(assertion) \
+	({ int x = __builtin_choose_expr(assertion, 0, (void)0); (void) x; })
+
+#elif defined CONFIG_YAFFS_DIRECT
+
+#define MTD_VERSION_CODE MTD_VERSION(2, 6, 22)
+
+/* Direct interface */
+#include "ydirectenv.h"
+
+#elif defined CONFIG_YAFFS_UTIL
+
+/* Stuff for YAFFS utilities */
+
+#include "stdlib.h"
+#include "stdio.h"
+#include "string.h"
+
+#include "devextras.h"
+
+#define YMALLOC(x) malloc(x)
+#define YFREE(x)   free(x)
+#define YMALLOC_ALT(x) malloc(x)
+#define YFREE_ALT(x) free(x)
+
+#define YCHAR char
+#define YUCHAR unsigned char
+#define _Y(x)     x
+#define yaffs_strcat(a, b)     strcat(a, b)
+#define yaffs_strcpy(a, b)     strcpy(a, b)
+#define yaffs_strncpy(a, b, c) strncpy(a, b, c)
+#define yaffs_strlen(s)	       strlen(s)
+#define yaffs_sprintf	       sprintf
+#define yaffs_toupper(a)       toupper(a)
+
+#define Y_INLINE inline
+
+/* #define YINFO(s) YPRINTF(( __FILE__ " %d %s\n",__LINE__,s)) */
+/* #define YALERT(s) YINFO(s) */
+
+#define TENDSTR "\n"
+#define TSTR(x) x
+#define TOUT(p) printf p
+
+#define YAFFS_LOSTNFOUND_NAME		"lost+found"
+#define YAFFS_LOSTNFOUND_PREFIX		"obj"
+/* #define YPRINTF(x) printf x */
+
+#define YAFFS_ROOT_MODE				0666
+#define YAFFS_LOSTNFOUND_MODE		0666
+
+#define yaffs_SumCompare(x, y) ((x) == (y))
+#define yaffs_strcmp(a, b) strcmp(a, b)
+
+#else
+/* Should have specified a configuration type */
+#error Unknown configuration
+
+#endif
+
+/* see yaffs_fs.c */
+extern unsigned int yaffs_traceMask;
+extern unsigned int yaffs_wr_attempts;
+
+/*
+ * Tracing flags.
+ * The flags masked in YAFFS_TRACE_ALWAYS are always traced.
+ */
+
+#define YAFFS_TRACE_OS			0x00000002
+#define YAFFS_TRACE_ALLOCATE		0x00000004
+#define YAFFS_TRACE_SCAN		0x00000008
+#define YAFFS_TRACE_BAD_BLOCKS		0x00000010
+#define YAFFS_TRACE_ERASE		0x00000020
+#define YAFFS_TRACE_GC			0x00000040
+#define YAFFS_TRACE_WRITE		0x00000080
+#define YAFFS_TRACE_TRACING		0x00000100
+#define YAFFS_TRACE_DELETION		0x00000200
+#define YAFFS_TRACE_BUFFERS		0x00000400
+#define YAFFS_TRACE_NANDACCESS		0x00000800
+#define YAFFS_TRACE_GC_DETAIL		0x00001000
+#define YAFFS_TRACE_SCAN_DEBUG		0x00002000
+#define YAFFS_TRACE_MTD			0x00004000
+#define YAFFS_TRACE_CHECKPOINT		0x00008000
+
+#define YAFFS_TRACE_VERIFY		0x00010000
+#define YAFFS_TRACE_VERIFY_NAND		0x00020000
+#define YAFFS_TRACE_VERIFY_FULL		0x00040000
+#define YAFFS_TRACE_VERIFY_ALL		0x000F0000
+
+
+#define YAFFS_TRACE_ERROR		0x40000000
+#define YAFFS_TRACE_BUG			0x80000000
+#define YAFFS_TRACE_ALWAYS		0xF0000000
+
+
+#define T(mask, p) do { if ((mask) & (yaffs_traceMask | YAFFS_TRACE_ALWAYS)) TOUT(p); } while (0)
+
+#ifndef YBUG
+#define YBUG() do {T(YAFFS_TRACE_BUG, (TSTR("==>> yaffs bug: " __FILE__ " %d" TENDSTR), __LINE__)); } while (0)
+#endif
+
+#endif
diff -u --new-file --recursive linux-2.6.29.6.orig/include/linux/i2c.h linux-2.6.29.6.mod/include/linux/i2c.h
--- linux-2.6.29.6.orig/include/linux/i2c.h	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/include/linux/i2c.h	2009-07-21 11:28:18.000000000 -0700
@@ -34,8 +34,13 @@
 #include <linux/device.h>	/* for struct device */
 #include <linux/sched.h>	/* for completion */
 #include <linux/mutex.h>
+#include <linux/kref.h>
+#include <linux/list.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <asm/atomic.h>
 
-extern struct bus_type i2c_bus_type;
+// extern struct bus_type i2c_bus_type;
 
 /* --- General options ------------------------------------------------	*/
 
@@ -46,6 +51,7 @@
 struct i2c_driver;
 union i2c_smbus_data;
 struct i2c_board_info;
+struct i2c_op_q_entry;
 
 /*
  * The master routines are the ones normally used to transmit data to devices
@@ -94,6 +100,24 @@
 					  u8 command, u8 length,
 					  const u8 *values);
 
+/*
+ * Non-blocking interface.  The user should fill out the public
+ * portions of the entry structure.  All data in the entry structure
+ * should be guaranteed to be available until the handler callback is
+ * called with the entry.
+ */
+extern int i2c_non_blocking_op(struct i2c_client *client,
+			       struct i2c_op_q_entry *entry);
+
+/*
+ * Poll the i2c interface.  This should only be called in a situation
+ * where scheduling and interrupts are off.  You should put the amount
+ * of microseconds between calls in us_since_last_call.
+ */
+extern void i2c_poll(struct i2c_client *client,
+		     unsigned int us_since_last_call);
+
+
 /**
  * struct i2c_driver - represent an I2C device driver
  * @id: Unique driver ID (optional)
@@ -319,6 +343,37 @@
 #endif
 
 /*
+ * About locking and the non-blocking interface.
+ *
+ * The poll operations are called single-threaded (along with the
+ * xxx_start operations), so if the driver is only polled then there
+ * is no need to do any locking.  If you are using interrupts, then
+ * the timer operations and interrupts can race and you need to lock
+ * appropriately.
+ *
+ * i2c_op_done() can be called multiple times on the same entry (as
+ * long as each one has a get operation).  This handles poll and
+ * interrupt races calling i2c_op_done().  It will do the right thing.
+ */
+
+/*
+ * Called from an non-blocking interface to get the current working
+ * entry.  Returns NULL if there is none.  This is primarily for
+ * interrupt handlers to determine what they should be working on.
+ * Note that if you call i2c_entry_get() and get a non-null entry, you
+ * must call i2c_entry_put() on it.
+ */
+struct i2c_op_q_entry *i2c_entry_get(struct i2c_adapter *adap);
+void i2c_entry_put(struct i2c_adapter *adap,
+		   struct i2c_op_q_entry *entry);
+
+/*
+ * Called from an non-blocking interface to report that an operation
+ * has completed.  Can be called from interrupt context.
+ */
+void i2c_op_done(struct i2c_adapter *adap, struct i2c_op_q_entry *entry);
+
+/*
  * The following structs are for those who like to implement new bus drivers:
  * i2c_algorithm is the interface to a class of hardware solutions which can
  * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584
@@ -337,11 +392,54 @@
 			   unsigned short flags, char read_write,
 			   u8 command, int size, union i2c_smbus_data *data);
 
+	/*
+	 * These are like the previous calls, but they will only start
+	 * the operation.  The poll call will be called periodically
+	 * to drive the operation of the bus.  Each of these calls
+	 * should set the result on an error, and set the timeout as
+	 * necessary.  Note that even interrupt driven drivers need to
+	 * poll so they can time out operations.  Note that all the
+	 * data structures passed in are guaranteed to be kept around
+	 * until the operation completes.  These may be called from
+	 * interrupt context.  If the start operation fails, these
+	 * should return an error.  They are called with the queue lock
+	 * held, so they should not call i2c_op_done().
+	 */
+	int (*master_start)(struct i2c_adapter    *adap,
+			    struct i2c_op_q_entry *entry);
+	int (*smbus_start)(struct i2c_adapter    *adap,
+			   struct i2c_op_q_entry *entry);
+	/*
+	 * us_since_last_poll is the amount of time since the last
+	 * time poll was called. Note that this may be *less* than the
+	 * time you requested, so always use this number and don't
+	 * assume it's the one you gave it.  This time is approximate
+	 * and is only guaranteed to be >= the time since the last
+	 * poll.  The value may be zero.
+	 */
+	void (*poll)(struct i2c_adapter *adap,
+		     struct i2c_op_q_entry *entry,
+		     unsigned int us_since_last_poll);
+
 	/* To determine what the adapter supports */
 	u32 (*functionality) (struct i2c_adapter *);
 };
 
 /*
+ * The timer has it's own separately allocated data structure because
+ * it needs to be able to exist even if the adapter is deleted (due to
+ * timer cancellation races).
+ */
+struct i2c_timer {
+	spinlock_t lock;
+	char deleted;
+	char running;
+	struct timer_list timer;
+	unsigned int next_call_time;
+	struct i2c_adapter *adapter;
+};
+
+/*
  * i2c_adapter is the structure used to identify a physical i2c bus along
  * with the access algorithms necessary to access it.
  */
@@ -361,6 +459,14 @@
 	struct mutex bus_lock;
 	struct mutex clist_lock;
 
+	struct list_head q;
+ 	spinlock_t q_lock;
+
+ 	/*
+ 	 * Used to time non-blocking operations.
+ 	 */
+ 	struct i2c_timer *timer;
+
 	int timeout;			/* in jiffies */
 	int retries;
 	struct device dev;		/* the adapter device */
@@ -471,6 +577,11 @@
 {
 	return adap->nr;
 }
+
+static inline int i2c_non_blocking_capable(struct i2c_adapter *adap)
+{
+	return adap->algo->poll != NULL;
+}
 #endif /* __KERNEL__ */
 
 /**
@@ -542,6 +653,8 @@
 #define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000
 #define I2C_FUNC_SMBUS_READ_I2C_BLOCK	0x04000000 /* I2C-like block xfer  */
 #define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK	0x08000000 /* w/ 1-byte reg. addr. */
+#define I2C_FUNC_SMBUS_READ_I2C_BLOCK_2  0x10000000 /* I2C-like block xfer  */
+#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK_2 0x20000000 /* w/ 2-byte reg. addr. */
 
 #define I2C_FUNC_SMBUS_BYTE		(I2C_FUNC_SMBUS_READ_BYTE | \
 					 I2C_FUNC_SMBUS_WRITE_BYTE)
@@ -593,6 +706,117 @@
 
 #ifdef __KERNEL__
 
+/*
+ * Hold an I2C operation to perform, and used to pass data around.
+ */
+#define I2C_OP_I2C	0
+#define I2C_OP_SMBUS	1
+typedef void (*i2c_op_done_cb)(struct i2c_op_q_entry *entry);
+struct i2c_op_q_entry {
+	/*
+	 * The result will be set to the result of the operation when
+	 * it completes.
+	 */
+	s32 result;
+
+	/**************************************************************/
+	/*
+	 * Public interface.  The user should set these up (and the
+	 * proper structure below).
+	 */
+
+	/*
+	 * Set to I2C_OP_I2C or I2C_OP_SMBUS depending on the transfer type.
+	 */
+	int            xfer_type;
+
+	/*
+	 * Handler may be called from interrupt context, so be
+	 * careful.
+	 */
+	i2c_op_done_cb handler;
+	void           *handler_data;
+
+	/*
+	 * Set up the i2c or smbus structure, depending on the transfer
+	 * type.
+	 *
+	 * Note that i2c and smbus are not in a union because an smbus
+	 * operation may be converted into an i2c operation (thus both
+	 * structures will be used).  The data in these may be changed
+	 * by the driver.
+	 */
+	struct {
+		struct i2c_msg *msgs;
+		int num;
+	} i2c;
+	struct {
+		/*
+		 * Addr and flags are filled in by the non-blocking
+		 * send routine that takes a client.
+		 */
+		u16 addr;
+		unsigned short flags;
+
+		char read_write;
+		u8 command;
+
+		/*
+		 * Note that the size is *not* the length of the data.
+		 * It is the transaction type, like I2C_SMBUS_QUICK
+		 * and the ones after that below.  If this is a block
+		 * transaction, the length of the rest of the data is
+		 * in the first byte of the data, for both transmit
+		 * and receive.
+		 */
+		int size;
+		union i2c_smbus_data *data;
+	} smbus;
+
+	/**************************************************************/
+	/* Bus Interface */
+	/*
+	 * The bus interface must set call_again_us to the time in
+	 * microseconds until the next poll operation should be
+	 * called.  This *must* be set in the start operation
+	 * function.  The value may be changed in poll calls if the
+	 * bus interface needs different timeouts at different times.
+	 * The time_left and data can be used for anything the bus
+	 * interface likes.  data will be set to NULL before being
+	 * started; the bus interface must use that to tell if the
+	 * entry has been set up.  It should ignore poll operations on
+	 * entries that are not yet set up.
+	 */
+	unsigned int  call_again_us;
+	long          time_left;
+	void	      *data;
+
+	/**************************************************************/
+	/* Internals */
+	struct completion *start;
+	unsigned char     use_timer;
+#define I2C_OP_QUEUED		0
+#define I2C_OP_INITIALIZED	1
+#define I2C_OP_FINISHED		2
+	unsigned char	  state;
+	u8                pec;
+	u8                partial_pec;
+	void (*complete)(struct i2c_adapter    *adap,
+			 struct i2c_op_q_entry *entry);
+
+	struct list_head link;
+	struct kref usecount;
+
+	/*
+	 * These are here for SMBus emulation over I2C.  I don't like
+	 * them taking this much room in the data structure, but they
+	 * need to be available in this case.
+	 */
+	unsigned char msgbuf0[I2C_SMBUS_BLOCK_MAX + 3];
+	unsigned char msgbuf1[I2C_SMBUS_BLOCK_MAX + 2];
+	struct i2c_msg msg[2];
+};
+
 /* These defines are used for probing i2c client addresses */
 /* The length of the option lists */
 #define I2C_CLIENT_MAX_OPTS 48
diff -u --new-file --recursive linux-2.6.29.6.orig/include/linux/ipmi.h linux-2.6.29.6.mod/include/linux/ipmi.h
--- linux-2.6.29.6.orig/include/linux/ipmi.h	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/include/linux/ipmi.h	2009-07-21 11:28:18.000000000 -0700
@@ -198,6 +198,8 @@
 					      response.  When you send a
 					      response message, this will
 					      be returned. */
+#define IPMI_OEM_RECV_TYPE		5 /* The response for OEM Channels */
+
 /* Note that async events and received commands do not have a completion
    code as the first byte of the incoming data, unlike a response. */
 
@@ -262,6 +264,7 @@
 };
 
 /* Allocate and free the receive message. */
+struct ipmi_recv_msg *ipmi_alloc_recv_msg(void);
 void ipmi_free_recv_msg(struct ipmi_recv_msg *msg);
 
 struct ipmi_user_hndl {
@@ -357,6 +360,18 @@
 			     int                  priority);
 
 /*
+ * Like ipmi_request, but lets you specify the slave return address.
+ */
+int ipmi_request_with_source(ipmi_user_t      user,
+			     struct ipmi_addr *addr,
+			     long             msgid,
+			     struct kernel_ipmi_msg  *msg,
+			     void             *user_msg_data,
+			     int              priority,
+			     unsigned char    source_address,
+			     unsigned char    source_lun);
+
+/*
  * Poll the IPMI interface for the user.  This causes the IPMI code to
  * do an immediate check for information from the driver and handle
  * anything that is immediately pending.  This will not block in any
@@ -366,6 +381,16 @@
 void ipmi_poll_interface(ipmi_user_t user);
 
 /*
+ * Register the given user to handle all received IPMI commands.  This
+ * will fail if anyone is registered as a command receiver or if
+ * another is already registered to receive all commands.  NOTE THAT
+ * THIS IS FOR EMULATION USERS ONLY, DO NOT USER THIS FOR NORMAL
+ * STUFF.
+ */
+int ipmi_register_all_cmd_rcvr(ipmi_user_t user);
+int ipmi_unregister_all_cmd_rcvr(ipmi_user_t user);
+
+/*
  * When commands come in to the SMS, the user can register to receive
  * them.  Only one user can be listening on a specific netfn/cmd/chan tuple
  * at a time, you will get an EBUSY error if the command is already
@@ -452,6 +477,9 @@
 /* Validate that the given IPMI address is valid. */
 int ipmi_validate_addr(struct ipmi_addr *addr, int len);
 
+/* Return 1 if the given addresses are equal, 0 if not. */
+int ipmi_addr_equal(struct ipmi_addr *addr1, struct ipmi_addr *addr2);
+
 #endif /* __KERNEL__ */
 
 
diff -u --new-file --recursive linux-2.6.29.6.orig/include/linux/ipmi_imb.h linux-2.6.29.6.mod/include/linux/ipmi_imb.h
--- linux-2.6.29.6.orig/include/linux/ipmi_imb.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/include/linux/ipmi_imb.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,146 @@
+/*
+ * ipmi_imb.h
+ *
+ * Intels IMB emulation on the MontaVista IPMI interface
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#ifndef __LINUX_IPMI_IMB_H
+#define __LINUX_IPMI_IMB_H
+
+typedef struct overlapped_s {
+    unsigned long Internal;
+    unsigned long InternalHigh;
+    unsigned long Offset;
+    unsigned long OffsetHigh;
+} overlapped_t;
+
+struct smi {
+    unsigned long smi_VersionNo;
+    unsigned long smi_Reserved1;
+    unsigned long smi_Reserved2;
+    void          *ntstatus;	      /* address of NT status block*/
+    void          *lpvInBuffer;       /* address of buffer for input data*/
+    unsigned long cbInBuffer;         /* size of input buffer*/
+    void          *lpvOutBuffer;      /* address of output buffer*/
+    unsigned long cbOutBuffer;        /* size of output buffer*/
+    unsigned long *lpcbBytesReturned; /* address of actual bytes of output*/
+    overlapped_t  *lpoOverlapped;     /* address of overlapped structure*/
+};
+
+
+#define MAX_IMB_PACKET_SIZE	33
+
+typedef struct {
+	unsigned char rsSa;
+	unsigned char cmd;
+	unsigned char netFn;
+	unsigned char rsLun;
+	unsigned char dataLength;
+	unsigned char data[1];
+} ImbRequest;
+
+typedef struct {
+	unsigned long flags;
+#define	      		NO_RESPONSE_EXPECTED	0x01
+
+	unsigned long timeOut;
+	ImbRequest    req;
+} ImbRequestBuffer;
+
+#define MIN_IMB_REQ_BUF_SIZE	13
+
+
+typedef struct {
+	unsigned char cCode;
+	unsigned char data[1];
+} ImbResponseBuffer;
+
+#define ASYNC_SEQ_START		0	// starting sequence number
+
+#define MIN_IMB_RESP_BUF_SIZE	1	// a buffer without any request data
+#define MAX_IMB_RESP_SIZE		(MIN_IMB_RESP_BUF_SIZE + MAX_IMB_RESPONSE_SIZE)
+
+#define MIN_IMB_RESPONSE_SIZE	7
+#define MAX_IMB_RESPONSE_SIZE	MAX_IMB_PACKET_SIZE
+
+typedef struct {
+	unsigned long timeOut;
+	unsigned long lastSeq;
+} ImbAsyncRequest;
+
+typedef struct {
+	unsigned long thisSeq;
+	unsigned char data[1];
+} ImbAsyncResponse;
+
+#define MIN_ASYNC_RESP_SIZE		sizeof(unsigned long)
+#define MAX_ASYNC_RESP_SIZE		(MIN_ASYNC_RESP_SIZE + MAX_IMB_PACKET_SIZE)
+
+#define STATUS_SUCCESS                  (0x00000000U)
+#define IMB_NO_ASYNC_MSG		((unsigned long)0xE0070012L)
+#define IMB_SEND_REQUEST_FAILED		((unsigned long)0xE0070013L)
+#define INVALID_ARGUMENTS		((unsigned long)0xE0070002L)
+
+
+#define FILE_DEVICE_IMB			0x00008010
+#define IOCTL_IMB_BASE			0x00000880
+
+#define CTL_CODE(DeviceType, Function, Method, Access)\
+		_IO(DeviceType & 0x00FF, Function & 0x00FF)
+
+#define FILE_DEVICE_IMB			0x00008010
+#define IOCTL_IMB_BASE			0x00000880
+#define METHOD_BUFFERED                 0
+#define FILE_ANY_ACCESS                 0
+
+
+typedef struct {
+	int	code;
+#define		SD_NO_ACTION				0
+#define		SD_RESET				1
+#define		SD_POWER_OFF				2
+
+	int	delayTime;  /* in units of 100 millisecond */
+} ShutdownCmdBuffer;
+
+
+/* BMC added parentheses around IOCTL_IMB_BASE + 2 */
+#define IOCTL_IMB_SEND_MESSAGE		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 2), METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_IMB_GET_ASYNC_MSG		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 8), METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_IMB_MAP_MEMORY		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 14),METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_IMB_UNMAP_MEMORY		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 16),METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_IMB_SHUTDOWN_CODE		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 18),METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_IMB_REGISTER_ASYNC_OBJ	CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 24),METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_IMB_DEREGISTER_ASYNC_OBJ	CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 26),METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_IMB_CHECK_EVENT		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 28),METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define IOCTL_IMB_POLL_ASYNC		CTL_CODE(FILE_DEVICE_IMB, (IOCTL_IMB_BASE + 20),METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+
+#endif /* __LINUX_IPMI_IMB_H */
diff -u --new-file --recursive linux-2.6.29.6.orig/include/linux/ipmi_msgdefs.h linux-2.6.29.6.mod/include/linux/ipmi_msgdefs.h
--- linux-2.6.29.6.orig/include/linux/ipmi_msgdefs.h	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/include/linux/ipmi_msgdefs.h	2009-07-21 11:28:18.000000000 -0700
@@ -58,6 +58,12 @@
 #define IPMI_READ_EVENT_MSG_BUFFER_CMD	0x35
 #define IPMI_GET_CHANNEL_INFO_CMD	0x42
 
+/* Bit for BMC global enables. */
+#define IPMI_BMC_RCV_MSG_INTR     0x01
+#define IPMI_BMC_EVT_MSG_INTR     0x02
+#define IPMI_BMC_EVT_MSG_BUFF     0x04
+#define IPMI_BMC_SYS_LOG          0x08
+
 #define IPMI_NETFN_STORAGE_REQUEST		0x0a
 #define IPMI_NETFN_STORAGE_RESPONSE		0x0b
 #define IPMI_ADD_SEL_ENTRY_CMD		0x44
@@ -65,6 +71,9 @@
 #define IPMI_NETFN_FIRMWARE_REQUEST		0x08
 #define IPMI_NETFN_FIRMWARE_RESPONSE		0x09
 
+#define IPMI_NETFN_OEM_REQUEST			0x2e
+#define IPMI_NETFN_OEM_RESPONSE			0x2f
+
 /* The default slave address */
 #define IPMI_BMC_SLAVE_ADDR	0x20
 
@@ -109,5 +118,7 @@
 #define IPMI_CHANNEL_MEDIUM_USB1	10
 #define IPMI_CHANNEL_MEDIUM_USB2	11
 #define IPMI_CHANNEL_MEDIUM_SYSINTF	12
+#define IPMI_CHANNEL_MEDIUM_OEM_MIN	0x60
+#define IPMI_CHANNEL_MEDIUM_OEM_MAX	0x7f
 
 #endif /* __LINUX_IPMI_MSGDEFS_H */
diff -u --new-file --recursive linux-2.6.29.6.orig/include/linux/ipmi_radisys.h linux-2.6.29.6.mod/include/linux/ipmi_radisys.h
--- linux-2.6.29.6.orig/include/linux/ipmi_radisys.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/include/linux/ipmi_radisys.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,128 @@
+/*
+ * ipmi_radisys.h
+ *
+ * An emulation of the Radisys IPMI interface on top of the MontaVista
+ * interface.
+ *
+ * Author: MontaVista Software, Inc.
+ *         Corey Minyard <minyard@mvista.com>
+ *         source@mvista.com
+ *
+ * Copyright 2002 MontaVista Software Inc.
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#ifndef __LINUX_IPMI_RADISYS_H
+#define __LINUX_IPMI_RADISYS_H
+
+/******************************************************************************
+ * This is the old IPMI interface defined by Radisys.  We are
+ * compliant with that.  Don't use it for new designs, though.
+ */
+#define IOCTL_IPMI_RCV          ( IPMI_IOC_MAGIC<<8 | 1 )
+#define IOCTL_IPMI_SEND         ( IPMI_IOC_MAGIC<<8 | 2 )
+#define IOCTL_IPMI_EVENT        ( IPMI_IOC_MAGIC<<8 | 3 )
+#define IOCTL_IPMI_REGISTER     ( IPMI_IOC_MAGIC<<8 | 4 )
+#define IOCTL_IPMI_UNREGISTER   ( IPMI_IOC_MAGIC<<8 | 5 )
+#define IOCTL_IPMI_CLEAR        ( IPMI_IOC_MAGIC<<8 | 9 )
+
+/* These don't seem to be implemented in the Radisys driver.
+#define IOCTL_IPMI_RESET_BMC    ( IPMI_IOC_MAGIC<<8 | 6 )
+#define IOCTL_IPMI_GET_BMC_ADDR ( IPMI_IOC_MAGIC<<8 | 7 )
+#define IOCTL_IPMI_SET_BMC_ADDR ( IPMI_IOC_MAGIC<<8 | 8 )
+*/
+
+/*
+ * Network Function Codes
+ */
+#define IPMI_NETFN_CHASSIS          0x00    /* Chassis - 0x00 << 2 */
+#define IPMI_NETFN_CHASSIS_RESP     0x04    /* Chassis - 0x01 << 2 */
+
+#define IPMI_NETFN_BRIDGE           0x08    /* Bridge - 0x02 << 2 */
+#define IPMI_NETFN_BRIDGE_RESP      0x0c    /* Bridge - 0x03 << 2 */
+
+#define IPMI_NETFN_SENSOR_EVT       0x10    /* Sensor/Event - 0x04 << 2 */
+#define IPMI_NETFN_SENSOR_EVT_RESP  0x14    /* Sensor/Event - 0x05 << 2 */
+
+#define IPMI_NETFN_APP              0x18    /* Application - 0x06 << 2 */
+#define IPMI_NETFN_APP_RESP         0x1c    /* Application - 0x07 << 2 */
+
+#define IPMI_NETFN_FIRMWARE         0x20    /* Firmware - 0x08 << 2 */
+#define IPMI_NETFN_FIRMWARE_RESP    0x24    /* Firmware - 0x09 << 2 */
+
+#define IPMI_NETFN_STORAGE          0x28    /* Storage - 0x0a << 2 */
+#define IPMI_NETFN_STORAGE_RESP     0x2c    /* Storage - 0x0b << 2 */
+
+#define IPMI_NETFN_OEM_1            0xC0    /* Storage - 0x30 << 2 */
+#define IPMI_NETFN_OEM_1_RESP       0xC4    /* Storage - 0x31 << 2 */
+
+/* there are 15 other OEM netfn pairs (OEM - 0x30-0x3f) */
+
+typedef struct _IPMI_LIST_ENTRY {
+   struct _IPMI_LIST_ENTRY * volatile Flink;
+   struct _IPMI_LIST_ENTRY * volatile Blink;
+} IPMI_LIST_ENTRY, *PIPMI_LIST_ENTRY;
+
+typedef struct IPMI_semaphore   IPMI_KSEMAPHORE;
+typedef struct IPMI_semaphore * IPMI_PKSEMAPHORE;
+
+/* IPMI Address structure */
+typedef struct _IPMI_ADDR {
+    unsigned char uchSlave;                /* Slave Address */
+    unsigned char uchLun;                  /* Logical Unit Number */
+} IPMI_ADDR, *PIPMI_ADDR;
+
+#define IPMI_MAX_MSG_SIZE	36
+
+/* IPMI Message Descriptor structure */
+typedef struct _IPMI_MSGDESC {
+                                         /************************************/
+                                         /* Device Driver Specific Elements  */
+                                         /************************************/
+    IPMI_LIST_ENTRY  Entry;                  /* Linked list element */
+    void             *pIRPacket;             /* Pointer to IRP object */
+    IPMI_PKSEMAPHORE pSema;                  /* Semaphore Object */
+    long             lTimeout;               /* Timeout value */
+                                         /************************************/
+                                         /* Shared elements                  */
+                                         /************************************/
+    unsigned char   auchBuffer[IPMI_MAX_MSG_SIZE]; /* Message buffer */
+    unsigned long   ulLength;               /* Length of message in bytes */
+    int             fDefer;                 /* TRUE - Defer I/O
+					       operation, doesn't seem
+					       to be used in the
+					       Radisys driver. */
+    IPMI_ADDR       Dest;                   /* Destination IPM Address */
+    unsigned char   uchNetFn;               /* Network Function */
+    unsigned char   uchCmd;                 /* Command */
+    unsigned char   uchSeq;                 /* Sequence Number */
+    unsigned char   uchComplete;            /* Completion Code */
+} IPMI_MSGDESC, *PIPMI_MSGDESC;
+
+/* Byte return codes for some things. */
+#define LOWLRC_SUCCESS              0x00 /* routine completed successfully */
+#define LOWLRC_ERROR                0xff /* routine did not complete */
+#define LOWLRC_INVALID_PARAMETERS   0xfe /* invalid parameters */
+#define LOWLRC_INVALID_REQUEST_DATA 0xfd /* invalid request data */
+
+#endif /* __LINUX_IPMI_RADISYS_H */
diff -u --new-file --recursive linux-2.6.29.6.orig/include/linux/ipmi_serial_sm.h linux-2.6.29.6.mod/include/linux/ipmi_serial_sm.h
--- linux-2.6.29.6.orig/include/linux/ipmi_serial_sm.h	1969-12-31 17:00:00.000000000 -0700
+++ linux-2.6.29.6.mod/include/linux/ipmi_serial_sm.h	2009-07-21 11:28:18.000000000 -0700
@@ -0,0 +1,306 @@
+/*
+ * ipmi_serial_sm.h
+ *
+ * State machine interface for low-level IPMI serial interface driver
+ * state machines.  This code is the interface between
+ * the ipmi_serial code and the supported codec(s)
+ *
+ * Author: MontaVista Software, Inc.
+ *         dgriego@mvista.com
+ *         cminyard@mvista.com
+ *         source@mvista.com
+ *
+ * Copyright 2006 MontaVista Software Inc.
+ *
+ *  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 SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
+ *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.
+ */
+
+#ifndef _IPMI_SERIAL_SM_H
+#define _IPMI_SERIAL_SM_H
+
+#include <linux/termios.h>
+#include <linux/ipmi_smi.h>
+
+/*
+ * This is the interface between the IPMI serial code and the codecs
+ * themselves.
+ *
+ * The IPMI serial code handles the interface to the IPMI message
+ * handler, the queuing of messages to transmit, the configuration of
+ * the serial port, and dealing directly with the serial port.  It also
+ * requests and handles interface flags.
+ *
+ * The lower layer is concerned with transmission of one message at a
+ * time, the handling of received bytes to assemble into full received
+ * messages.
+ *
+ * All messages are formatted in the same manner as a standard KCS
+ * command:
+ *   send: [(netfn << 2) | lun] [command] [data1] ...
+ *   recv: [(netfn << 2) | lun] [command] [completion code] [data1] ...
+ *
+ * Note that some commands may have a special meaning:
+ *   IPMI_GET_MSG_FLAGS_CMD - If the BMC does not handle this and transfers
+ *     this information via a different mechanism, the lower layer may
+ *     return -ENOTSUP for a send of this command.
+ *   IPMI_READ_EVENT_MSG_BUFFER_CMD - Used to report a received event.
+ *     The lower layer may send these asynchronously to the upper layer
+ *     if it has a different mechanism to receive these.
+ *   IPMI_GET_MSG_CMD - Used to report a received command.
+ *     The lower layer may send these asynchronously to the upper layer
+ *     if it has a different mechanism to receive these.
+ * The lower layer may not asynchronously send anything else with
+ * the async function except what is allowed above.
+ *
+ * See the end of this file for expected call flows.
+ */
+
+/*
+ * This is defined by the codecs themselves, it is an opaque
+ * data type for them to use.
+ */
+struct ipmi_serial_codec_data;
+
+/*
+ * Opaque data used in the serial interface that the state machines
+ * must supply to the serial interface in callbacks.
+ */
+struct ipmi_serial_info;
+
+/*
+ * Handlers for the IPMI serial state machine.
+ */
+struct ipmi_serial_codec {
+	struct module *owner;
+	char          *name;
+
+#define IPMI_SERIAL_NEEDS_GET_FLAGS_POLLING	0x00000001
+#define IPMI_SERIAL_SUPPORTS_GET_FLAGS		0x00000002
+#define IPMI_SERIAL_SUPPORTS_EVENT_BUFFER	0x00000004
+#define IPMI_SERIAL_HAS_ATTN			0x00000008
+	unsigned int (*capabilities)(struct ipmi_serial_codec_data *data);
+
+	/*
+	 * Set up the basic termios for the serial port for this
+	 * interface type.  The upper layer will call this when
+	 * setting up the serial port.  The upper layer will change
+	 * some of these values based upon information from the user,
+	 * primarily baud, number of bits/char, stop bits, and parity.
+	 */
+	int (*setup_termios)(struct ktermios *t);
+
+	/*
+	 * Initialize the data structure for the codec.  The info must
+	 * be supplied to callbacks.  Note that this shouldn't send or
+	 * receive anything, it should just initialize.  The user may
+	 * pass options in on the serial configuration command line,
+	 * these will be passed to this function.
+	 */
+	int (*init)(struct ipmi_serial_codec_data *data,
+		    struct ipmi_serial_info *info,
+		    const char *options);
+
+	/*
+	 * Start processing.  When this is done,
+	 * ipmi_serial_ll_init_complete() must be called by the codec.
+	 * This function may send and receive data.  If this is NULL,
+	 * the codec is assumed to already be fully operational after
+	 * the init call.
+	 */
+	 int (*start)(struct ipmi_serial_codec_data *data);
+
+	/*
+	 * Cleanup anything that needs to be cleaned up before the codec
+	 * is freed.
+	 */
+	void (*cleanup)(struct ipmi_serial_codec_data *data);
+
+	/*
+	 * Return the size of the ipmi_serial_codec_data structure in
+	 * bytes.  The upper layer will use this to allocate the data
+	 * structure for the codec.
+	 */
+	int (*size)(void);
+
+	/*
+	 * Send a message.  Only one message send at a time is
+	 * allowed.  When the send is complete the lower layer must
+	 * call ipmi_serial_ll_send_complete().  May return an error
+	 * code if there is already a message in progress.  The response
+	 * that comes back will have the given seq value in the receive
+	 * call.
+	 */
+	int (*send_msg)(struct ipmi_serial_codec_data *data,
+			const unsigned char *msg, unsigned int msg_len,
+			unsigned int seq);
+
+	/*
+	 * Handle a single received character from the serial port.
+	 * Note that this is called without the serial code claiming a
+	 * lock, but will be single-threaded.
+	 */
+	void (*handle_char)(struct ipmi_serial_codec_data *data,
+			    unsigned char ch);
+
+	/*
+	 * Called when the transmitter has space to take more
+	 * characters.  If ipmi_serial_xmit_data returns less queued
+	 * characters than asked to transmit, the lower layer should
+	 * wait for this call and then send more data.
+	 */
+	void (*tx_ready)(struct ipmi_serial_codec_data *data);
+
+
+	/*
+	 * If not-NULL, this will be called periodically.  The time
+	 * since the last call will be passed, time is in microseconds.
+	 */
+	void (*timer_tick)(struct ipmi_serial_codec_data *data,
+			   unsigned int time_since_last);
+
+	/*
+	 * Once the device id is fetched by the main serial code, this
+	 * will be called if it is not NULL.  This allows the codec to
+	 * enable certain hacks for certain machines.
+	 */
+	void (*check_dev_id)(struct ipmi_serial_codec_data *data,
+			     struct ipmi_device_id *dev_id);
+
+	/*
+	 * Print the current options in use by the codec.  If there are
+	 * options printed, the codec should prepend a ','.
+	 */
+	int (*add_options)(struct ipmi_serial_codec_data *data, char *out);
+
+	/*
+	 * Used by the serial interface, the codec shouldn't touch
+	 * anything below.
+	 */
+	struct list_head link;
+};
+
+/*
+ * Called by the lower layer when initialization is complete.  Pass
+ * in zero as the slave_addr if you are unable to compute it.
+ */
+extern void ipmi_serial_ll_init_complete(struct ipmi_serial_info *info,
+					 unsigned char slave_addr,
+					 int err);
+
+/*
+ * Called by the lower layer when it needs to send some data.  Returns the
+ * actual number of bytes queued for transmit.
+ */
+extern unsigned int ipmi_serial_ll_xmit(struct ipmi_serial_info *info,
+					const unsigned char *data,
+					unsigned int len);
+
+/*
+ * Called by the lower layer when it detects that message flags are
+ * available.
+ */
+extern void ipmi_serial_ll_attn(struct ipmi_serial_info *info);
+
+/*
+ * Called by the lower layer when a full message response is received.
+ * The seq will be set to the value supplied to the state machine
+ * at send time.
+ */
+extern void ipmi_serial_ll_recv(struct ipmi_serial_info *info,
+				const unsigned char *data,
+				unsigned int len,
+				unsigned int seq);
+
+/*
+ * Called when the lower layer receives an async message (assuming it
+ * has a different way to do this than normal flag handling) These may
+ * be received commands or events based upon the rules specified
+ * above.
+ */
+extern void ipmi_serial_ll_async(struct ipmi_serial_info *info,
+				 const unsigned char *data,
+				 unsigned int len);
+
+/*
+ * Used to report various low-level errors.
+ */
+extern void ipmi_serial_ll_protocol_violation(struct ipmi_serial_info *info);
+extern void ipmi_serial_ll_checksum_error(struct ipmi_serial_info *info);
+
+/*
+ * These functions allow codecs to register and unregister with the serial
+ * system interface layer.
+ */
+extern int ipmi_serial_codec_register(struct ipmi_serial_codec *codec);
+extern void ipmi_serial_codec_unregister(struct ipmi_serial_codec *codec);
+
+/*
+ * Expected flow how how things happen on this interface:
+ *
+ *     Upper Layer                                  Lower Layer
+ *     	   |   	       	       	       			|
+ * 	   |----------------init----------------------->|
+ * 	   |			       			|
+ *     	   |<---------------xmit------------------------|
+ * 	   |			       			|
+ *     	   |-----------handle_char--------------------->|
+ *     	   |-----------handle_char--------------------->|
+ *     	   |-----------handle_char--------------------->|
+ *     	   |   	       		       			|
+ *     	   |<------------init_complete------------------|
+ * 	   |			       			|
+ *     	   |--------------send_msg--------------------->|
+ * 	   |			       			|
+ *     	   |<-----------xmit (return less)--------------|
+ * 	   |			       	  		|
+ *     	   |------------tx_ready----------------------->|
+ * 	   |			       			|
+ *     	   |<---------------xmit------------------------|
+ * 	   |			       	     		|
+ *     	   |<-------------send_complete-----------------|
+ * 	   |			       	     		|
+ *     	   |-----------handle_char--------------------->|
+ *     	   |-----------handle_char--------------------->|
+ *     	   |-----------handle_char--------------------->|
+ * 	   |			       	     		|
+ *     	   |<---------------recv------------------------|
+ * 	   |			       	     		|
+ *     	   |-----------handle_char--------------------->|
+ * 	   |			       	     		|
+ *     	   |<---------------attn------------------------|
+ * 	   |			       	     		|
+ *     	   |--------------send_msg(GET_FLAGS)---------->|
+ * 	   |			       	     		|
+ *     	   |<---------------xmit------------------------|
+ * 	   |			       	     		|
+ *     	   |<-------------send_complete-----------------|
+ * 	   |			       	     		|
+ *     	   |-----------handle_char--------------------->|
+ *     	   |-----------handle_char--------------------->|
+ *     	   |-----------handle_char--------------------->|
+ * 	   |			       	     		|
+ *     	   |<---------------recv------------------------|
+ * 	   |			       			|
+ *     	   |--------------cleanup---------------------->|
+ * 	   |			       			|
+ */
+#endif /* _IPMI_SERIAL_SM_H */
diff -u --new-file --recursive linux-2.6.29.6.orig/include/linux/pci_ids.h linux-2.6.29.6.mod/include/linux/pci_ids.h
--- linux-2.6.29.6.orig/include/linux/pci_ids.h	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/include/linux/pci_ids.h	2009-07-21 11:28:18.000000000 -0700
@@ -1259,6 +1259,9 @@
 #define PCI_DEVICE_ID_IMS_TT128		0x9128
 #define PCI_DEVICE_ID_IMS_TT3D		0x9135
 
+#define PCI_VENDOR_ID_TUNDRA            0x10e3
+#define PCI_DEVICE_ID_TUNDRA_CA91C042   0x0000
+
 #define PCI_VENDOR_ID_INTERG		0x10ea
 #define PCI_DEVICE_ID_INTERG_1682	0x1682
 #define PCI_DEVICE_ID_INTERG_2000	0x2000
diff -u --new-file --recursive linux-2.6.29.6.orig/init/do_mounts.c linux-2.6.29.6.mod/init/do_mounts.c
--- linux-2.6.29.6.orig/init/do_mounts.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/init/do_mounts.c	2009-07-21 11:28:18.000000000 -0700
@@ -237,6 +237,7 @@
 #else
 	const char *b = name;
 #endif
+	int retries = 0;
 
 	get_fs_names(fs_names);
 retry:
@@ -259,16 +260,30 @@
 #ifdef CONFIG_BLOCK
 		__bdevname(ROOT_DEV, b);
 #endif
-		printk("VFS: Cannot open root device \"%s\" or %s\n",
+		printk("VFS: Cannot open root device \"%s\" or %s, retrying in 1 second\n",
 				root_device_name, b);
-		printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
+		retries++;
+		if (retries < 10) {
+			/* wait 1 second and try again */
+			current->state = TASK_INTERRUPTIBLE;
+			schedule_timeout(HZ);
+			root_device_name = saved_root_name;
+			ROOT_DEV = name_to_dev_t(root_device_name);
+			if (strncmp(root_device_name, "/dev/", 5) == 0)
+				root_device_name += 5;
+			create_dev("/dev/root", ROOT_DEV);
+			get_fs_names(fs_names);
+			goto retry;
+		} else {
+			printk("Please append a correct \"root=\" boot option; here are the available partitions:\n");
 
-		printk_all_partitions();
+			printk_all_partitions();
 #ifdef CONFIG_DEBUG_BLOCK_EXT_DEVT
-		printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify "
+			printk("DEBUG_BLOCK_EXT_DEVT is enabled, you need to specify "
 		       "explicit textual name for \"root=\" boot option.\n");
 #endif
-		panic("VFS: Unable to mount root fs on %s", b);
+			panic("VFS: Unable to mount root fs on %s", b);
+		}
 	}
 
 	printk("List of all partitions:\n");
diff -u --new-file --recursive linux-2.6.29.6.orig/kernel/resource.c linux-2.6.29.6.mod/kernel/resource.c
--- linux-2.6.29.6.orig/kernel/resource.c	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/kernel/resource.c	2009-07-21 11:28:18.000000000 -0700
@@ -381,8 +381,8 @@
 
 		if ((first->start > new->start) || (first->end < new->end))
 			break;
-		if ((first->start == new->start) && (first->end == new->end))
-			break;
+//		if ((first->start == new->start) && (first->end == new->end))
+//			break;
 	}
 
 	for (next = first; ; next = next->sibling) {
diff -u --new-file --recursive linux-2.6.29.6.orig/Makefile linux-2.6.29.6.mod/Makefile
--- linux-2.6.29.6.orig/Makefile	2009-07-02 16:41:20.000000000 -0700
+++ linux-2.6.29.6.mod/Makefile	2009-07-21 11:28:18.000000000 -0700
@@ -190,8 +190,19 @@
 # Default value for CROSS_COMPILE is not to prefix executables
 # Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile
 export KBUILD_BUILDHOST := $(SUBARCH)
-ARCH		?= $(SUBARCH)
-CROSS_COMPILE	?=
+#ARCH		?= $(SUBARCH)
+#CROSS_COMPILE	?=
+
+#ARCH           ?= powerpc
+
+# use ppc_85xx- for MVME3100
+# use ppc_85xxDP- for MVME4100, CPCI6200
+# use ppc_6xx- for MCP750
+# use ppc_74xx- for MVME5500, MVME6100, MVME7100, MCP820, MCP905
+#CROSS_COMPILE  ?= ppc_85xx-
+#CROSS_COMPILE  ?= ppc_85xxDP-
+#CROSS_COMPILE  ?= ppc_74xx-
+#CROSS_COMPILE  ?= ppc_6xx-
 
 # Architecture as present in compile.h
 UTS_MACHINE 	:= $(ARCH)

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-08 13:39     ` Philippe Gerum
  2011-04-08 13:47       ` Jesper Christensen
@ 2011-04-08 14:33       ` Jesper Christensen
  1 sibling, 0 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-08 14:33 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai


With the risk of jinx'ing it the 2.5.6 version seems to have done the
trick. Huge thanks to you Philippe, you have saved my head from
decapitation :)

/Jesper


On 2011-04-08 15:39, Philippe Gerum wrote:
> On Fri, 2011-04-08 at 15:20 +0200, Jesper Christensen wrote:
>   
>> Thanks i'll give 2.5.6 a shot.
>>
>> Also it has come to my attention that there is some source files
>> (arch/powerpc/platforms/85xx/cpci6200.c,
>> arch/powerpc/platforms/85xx/cpci6200.h,
>> arch/powerpc/platforms/85xx/cpci6200_timer.c) that are probably not
>> covered by the adeos patch. Am i correct in assuming these need some
>> work to support i-pipe?
>>
>>     
> I can't tell since I have no access to them, this is probably not a
> mainline port.
>
> In any case, if any of those files implements the support for the
> programmable interrupt controller, hw timer, gpios and/or any form of
> cascaded interrupt handling, this is correct: they should be made I-pipe
> aware.
>
>   
>> /Jesper
>>
>>
>> On 2011-04-08 15:12, Philippe Gerum wrote:
>>     
>>> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
>>>   
>>>       
>>>> Hi
>>>>
>>>> I'm trying to implement some gateway functionality in the kernel on a
>>>> emerson CPCI6200 board, but have run into some strange errors. The
>>>> kernel module is made up of two threads that run every 1 ms. I have also
>>>> made use of the rtpc dispatcher in rtnet to dispatch control messages
>>>> from a netlink socket to the RT part of my kernel module.
>>>>
>>>> The problem is that when loaded the threads get suspended due to exceptions:
>>>>
>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
>>>> after exception #1792
>>>>
>>>> or
>>>>
>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
>>>> exception #1025
>>>>
>>>> or
>>>>
>>>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
>>>> after exception #1792
>>>>
>>>>
>>>> I have ported the "gianfar" driver from linux to rtnet.
>>>>
>>>> The versions and hardware are listed below. The errors are most likely
>>>> due to faulty software on my part, but i would like to ask if there are
>>>> any known issues with the versions or hardware i'm using. I would also
>>>> like to ask if there are any ways of further debugging the errors as i
>>>> am not getting very far with the above messages.
>>>>     
>>>>         
>>> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
>>> which would cause exactly the kind of weird behavior you are seeing
>>> right now. The bug triggered random code execution due to stack memory
>>> pollution at init on powerpc for Xenomai kthreads:
>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
>>>
>>> You need at the very least those three patches (from the top of my
>>> head), but it would be much better to upgrade to 2.5.6.
>>>
>>>   
>>>       
>>>>
>>>> System info:
>>>>
>>>> Linux kernel: 2.6.29.6
>>>> i-pipe version: 2.7-04
>>>> processor: powerpc mpc8572
>>>> xenomai version: 2.5.3
>>>> rtnet version: 0.9.12
>>>>
>>>>     
>>>>         
>>>   
>>>       
>>     
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-08 12:58 [Xenomai-core] kernel threads crash Jesper Christensen
  2011-04-08 13:12 ` Philippe Gerum
@ 2011-04-08 19:15 ` Richard Cochran
  2011-04-11  6:52   ` Jesper Christensen
  1 sibling, 1 reply; 42+ messages in thread
From: Richard Cochran @ 2011-04-08 19:15 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On Fri, Apr 08, 2011 at 02:58:33PM +0200, Jesper Christensen wrote:

> I have ported the "gianfar" driver from linux to rtnet.

Can you publish this driver? I have been wanting to make a rtnet
gianfar myself.

Thanks,

Richard


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-08 19:15 ` Richard Cochran
@ 2011-04-11  6:52   ` Jesper Christensen
  2011-04-11  6:55     ` Richard Cochran
  0 siblings, 1 reply; 42+ messages in thread
From: Jesper Christensen @ 2011-04-11  6:52 UTC (permalink / raw)
  To: Richard Cochran; +Cc: xenomai

I have made a number of changes to rtnet (scatter gather support, icmp
fixes etc.) so maybe i could send you a tar ball of the entire directory?

/Jesper


On 2011-04-08 21:15, Richard Cochran wrote:
> On Fri, Apr 08, 2011 at 02:58:33PM +0200, Jesper Christensen wrote:
>
>   
>> I have ported the "gianfar" driver from linux to rtnet.
>>     
> Can you publish this driver? I have been wanting to make a rtnet
> gianfar myself.
>
> Thanks,
>
> Richard
>
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11  6:52   ` Jesper Christensen
@ 2011-04-11  6:55     ` Richard Cochran
  2011-04-11  6:59       ` Jesper Christensen
  0 siblings, 1 reply; 42+ messages in thread
From: Richard Cochran @ 2011-04-11  6:55 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On Mon, Apr 11, 2011 at 08:52:04AM +0200, Jesper Christensen wrote:
> I have made a number of changes to rtnet (scatter gather support, icmp
> fixes etc.) so maybe i could send you a tar ball of the entire directory?

Yes, please do.

thanks,
Richard

> On 2011-04-08 21:15, Richard Cochran wrote:
> > On Fri, Apr 08, 2011 at 02:58:33PM +0200, Jesper Christensen wrote:
> >
> >   
> >> I have ported the "gianfar" driver from linux to rtnet.
> >>     
> > Can you publish this driver? I have been wanting to make a rtnet
> > gianfar myself.
> >
> > Thanks,
> >
> > Richard
> >
> >   
> 


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11  6:55     ` Richard Cochran
@ 2011-04-11  6:59       ` Jesper Christensen
  2011-04-11  9:18         ` Jan Kiszka
  0 siblings, 1 reply; 42+ messages in thread
From: Jesper Christensen @ 2011-04-11  6:59 UTC (permalink / raw)
  To: Richard Cochran; +Cc: xenomai

[-- Attachment #1: Type: text/plain, Size: 740 bytes --]

There you go.

/Jesper


On 2011-04-11 08:55, Richard Cochran wrote:
> On Mon, Apr 11, 2011 at 08:52:04AM +0200, Jesper Christensen wrote:
>   
>> I have made a number of changes to rtnet (scatter gather support, icmp
>> fixes etc.) so maybe i could send you a tar ball of the entire directory?
>>     
> Yes, please do.
>
> thanks,
> Richard
>
>   
>> On 2011-04-08 21:15, Richard Cochran wrote:
>>     
>>> On Fri, Apr 08, 2011 at 02:58:33PM +0200, Jesper Christensen wrote:
>>>
>>>   
>>>       
>>>> I have ported the "gianfar" driver from linux to rtnet.
>>>>     
>>>>         
>>> Can you publish this driver? I have been wanting to make a rtnet
>>> gianfar myself.
>>>
>>> Thanks,
>>>
>>> Richard
>>>
>>>   
>>>       
>>     
>   

[-- Attachment #2: rtnet-0.9.12.tar.gz --]
[-- Type: application/x-gzip, Size: 1595371 bytes --]

^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11  6:59       ` Jesper Christensen
@ 2011-04-11  9:18         ` Jan Kiszka
  2011-04-11  9:26           ` Jesper Christensen
  0 siblings, 1 reply; 42+ messages in thread
From: Jan Kiszka @ 2011-04-11  9:18 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On 2011-04-11 08:59, Jesper Christensen wrote:
> There you go.
> 

Even better would be individual patches (one for each topic) so that we
can more easily review/merge your improvements into RTnet. If you are
not familiar with this process, maybe you can convince Richard to do the
break-up... :)

Also, please follow up on RTnet-list(s) about RTnet topics.

TIA,
Jan

> 
> On 2011-04-11 08:55, Richard Cochran wrote:
>> On Mon, Apr 11, 2011 at 08:52:04AM +0200, Jesper Christensen wrote:
>>   
>>> I have made a number of changes to rtnet (scatter gather support, icmp
>>> fixes etc.) so maybe i could send you a tar ball of the entire directory?
>>>     
>> Yes, please do.
>>
>> thanks,
>> Richard
>>
>>   
>>> On 2011-04-08 21:15, Richard Cochran wrote:
>>>     
>>>> On Fri, Apr 08, 2011 at 02:58:33PM +0200, Jesper Christensen wrote:
>>>>
>>>>   
>>>>       
>>>>> I have ported the "gianfar" driver from linux to rtnet.
>>>>>     
>>>>>         
>>>> Can you publish this driver? I have been wanting to make a rtnet
>>>> gianfar myself.
>>>>
>>>> Thanks,
>>>>
>>>> Richard
>>>>
>>>>   
>>>>       

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11  9:18         ` Jan Kiszka
@ 2011-04-11  9:26           ` Jesper Christensen
  0 siblings, 0 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-11  9:26 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: xenomai

Yeah we've been stupid enough not to use the version from the git
repository, but i'll see what i can do over the next few days (snowed
under at work :(  ). I should be able to do some diffs against the git
repository.

/Jesper


On 2011-04-11 11:18, Jan Kiszka wrote:
> On 2011-04-11 08:59, Jesper Christensen wrote:
>   
>> There you go.
>>
>>     
> Even better would be individual patches (one for each topic) so that we
> can more easily review/merge your improvements into RTnet. If you are
> not familiar with this process, maybe you can convince Richard to do the
> break-up... :)
>
> Also, please follow up on RTnet-list(s) about RTnet topics.
>
> TIA,
> Jan
>
>   
>> On 2011-04-11 08:55, Richard Cochran wrote:
>>     
>>> On Mon, Apr 11, 2011 at 08:52:04AM +0200, Jesper Christensen wrote:
>>>   
>>>       
>>>> I have made a number of changes to rtnet (scatter gather support, icmp
>>>> fixes etc.) so maybe i could send you a tar ball of the entire directory?
>>>>     
>>>>         
>>> Yes, please do.
>>>
>>> thanks,
>>> Richard
>>>
>>>   
>>>       
>>>> On 2011-04-08 21:15, Richard Cochran wrote:
>>>>     
>>>>         
>>>>> On Fri, Apr 08, 2011 at 02:58:33PM +0200, Jesper Christensen wrote:
>>>>>
>>>>>   
>>>>>       
>>>>>           
>>>>>> I have ported the "gianfar" driver from linux to rtnet.
>>>>>>     
>>>>>>         
>>>>>>             
>>>>> Can you publish this driver? I have been wanting to make a rtnet
>>>>> gianfar myself.
>>>>>
>>>>> Thanks,
>>>>>
>>>>> Richard
>>>>>
>>>>>   
>>>>>       
>>>>>           
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-08 13:12 ` Philippe Gerum
  2011-04-08 13:20   ` Jesper Christensen
@ 2011-04-11 14:13   ` Jesper Christensen
  2011-04-11 14:18     ` Philippe Gerum
  2011-04-11 14:36     ` Gilles Chanteperdrix
  1 sibling, 2 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-11 14:13 UTC (permalink / raw)
  To: xenomai

I have updated to xenomai 2.5.6, but i'm still seeing exceptions
(considerably less often though):

Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
after exception #1792

/Jesper


On 2011-04-08 15:12, Philippe Gerum wrote:
> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
>   
>> Hi
>>
>> I'm trying to implement some gateway functionality in the kernel on a
>> emerson CPCI6200 board, but have run into some strange errors. The
>> kernel module is made up of two threads that run every 1 ms. I have also
>> made use of the rtpc dispatcher in rtnet to dispatch control messages
>> from a netlink socket to the RT part of my kernel module.
>>
>> The problem is that when loaded the threads get suspended due to exceptions:
>>
>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
>> after exception #1792
>>
>> or
>>
>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
>> exception #1025
>>
>> or
>>
>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
>> after exception #1792
>>
>>
>> I have ported the "gianfar" driver from linux to rtnet.
>>
>> The versions and hardware are listed below. The errors are most likely
>> due to faulty software on my part, but i would like to ask if there are
>> any known issues with the versions or hardware i'm using. I would also
>> like to ask if there are any ways of further debugging the errors as i
>> am not getting very far with the above messages.
>>     
> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
> which would cause exactly the kind of weird behavior you are seeing
> right now. The bug triggered random code execution due to stack memory
> pollution at init on powerpc for Xenomai kthreads:
> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
>
> You need at the very least those three patches (from the top of my
> head), but it would be much better to upgrade to 2.5.6.
>
>   
>>
>>
>> System info:
>>
>> Linux kernel: 2.6.29.6
>> i-pipe version: 2.7-04
>> processor: powerpc mpc8572
>> xenomai version: 2.5.3
>> rtnet version: 0.9.12
>>
>>     
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 14:13   ` Jesper Christensen
@ 2011-04-11 14:18     ` Philippe Gerum
  2011-04-11 14:20       ` Jesper Christensen
  2011-04-11 14:23       ` Philippe Gerum
  2011-04-11 14:36     ` Gilles Chanteperdrix
  1 sibling, 2 replies; 42+ messages in thread
From: Philippe Gerum @ 2011-04-11 14:18 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On Mon, 2011-04-11 at 16:13 +0200, Jesper Christensen wrote:
> I have updated to xenomai 2.5.6, but i'm still seeing exceptions
> (considerably less often though):
> 
> Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
> after exception #1792

You should build your code statically into the kernel, not as a module,
and find out which code raises the MCE.

CONFIG_DEBUG_INFO=y, then objdump -dl vmlinux, looking for the NIP
mentioned.

> 
> /Jesper
> 
> 
> On 2011-04-08 15:12, Philippe Gerum wrote:
> > On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
> >   
> >> Hi
> >>
> >> I'm trying to implement some gateway functionality in the kernel on a
> >> emerson CPCI6200 board, but have run into some strange errors. The
> >> kernel module is made up of two threads that run every 1 ms. I have also
> >> made use of the rtpc dispatcher in rtnet to dispatch control messages
> >> from a netlink socket to the RT part of my kernel module.
> >>
> >> The problem is that when loaded the threads get suspended due to exceptions:
> >>
> >> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
> >> after exception #1792
> >>
> >> or
> >>
> >> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
> >> exception #1025
> >>
> >> or
> >>
> >> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
> >> after exception #1792
> >>
> >>
> >> I have ported the "gianfar" driver from linux to rtnet.
> >>
> >> The versions and hardware are listed below. The errors are most likely
> >> due to faulty software on my part, but i would like to ask if there are
> >> any known issues with the versions or hardware i'm using. I would also
> >> like to ask if there are any ways of further debugging the errors as i
> >> am not getting very far with the above messages.
> >>     
> > A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
> > which would cause exactly the kind of weird behavior you are seeing
> > right now. The bug triggered random code execution due to stack memory
> > pollution at init on powerpc for Xenomai kthreads:
> > http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
> > http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
> > http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
> >
> > You need at the very least those three patches (from the top of my
> > head), but it would be much better to upgrade to 2.5.6.
> >
> >   
> >>
> >>
> >> System info:
> >>
> >> Linux kernel: 2.6.29.6
> >> i-pipe version: 2.7-04
> >> processor: powerpc mpc8572
> >> xenomai version: 2.5.3
> >> rtnet version: 0.9.12
> >>
> >>     
> >   
> 
> 
> _______________________________________________
> Xenomai-core mailing list
> Xenomai-core@domain.hid
> https://mail.gna.org/listinfo/xenomai-core

-- 
Philippe.




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 14:18     ` Philippe Gerum
@ 2011-04-11 14:20       ` Jesper Christensen
  2011-04-11 14:27         ` Philippe Gerum
  2011-04-11 14:34         ` Philippe Gerum
  2011-04-11 14:23       ` Philippe Gerum
  1 sibling, 2 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-11 14:20 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai

Problem is the NIP in question is the address of the thread structure as
seen in the error message.

/Jesper


On 2011-04-11 16:18, Philippe Gerum wrote:
> On Mon, 2011-04-11 at 16:13 +0200, Jesper Christensen wrote:
>   
>> I have updated to xenomai 2.5.6, but i'm still seeing exceptions
>> (considerably less often though):
>>
>> Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
>> after exception #1792
>>     
> You should build your code statically into the kernel, not as a module,
> and find out which code raises the MCE.
>
> CONFIG_DEBUG_INFO=y, then objdump -dl vmlinux, looking for the NIP
> mentioned.
>
>   
>> /Jesper
>>
>>
>> On 2011-04-08 15:12, Philippe Gerum wrote:
>>     
>>> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
>>>   
>>>       
>>>> Hi
>>>>
>>>> I'm trying to implement some gateway functionality in the kernel on a
>>>> emerson CPCI6200 board, but have run into some strange errors. The
>>>> kernel module is made up of two threads that run every 1 ms. I have also
>>>> made use of the rtpc dispatcher in rtnet to dispatch control messages
>>>> from a netlink socket to the RT part of my kernel module.
>>>>
>>>> The problem is that when loaded the threads get suspended due to exceptions:
>>>>
>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
>>>> after exception #1792
>>>>
>>>> or
>>>>
>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
>>>> exception #1025
>>>>
>>>> or
>>>>
>>>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
>>>> after exception #1792
>>>>
>>>>
>>>> I have ported the "gianfar" driver from linux to rtnet.
>>>>
>>>> The versions and hardware are listed below. The errors are most likely
>>>> due to faulty software on my part, but i would like to ask if there are
>>>> any known issues with the versions or hardware i'm using. I would also
>>>> like to ask if there are any ways of further debugging the errors as i
>>>> am not getting very far with the above messages.
>>>>     
>>>>         
>>> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
>>> which would cause exactly the kind of weird behavior you are seeing
>>> right now. The bug triggered random code execution due to stack memory
>>> pollution at init on powerpc for Xenomai kthreads:
>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
>>>
>>> You need at the very least those three patches (from the top of my
>>> head), but it would be much better to upgrade to 2.5.6.
>>>
>>>   
>>>       
>>>>
>>>> System info:
>>>>
>>>> Linux kernel: 2.6.29.6
>>>> i-pipe version: 2.7-04
>>>> processor: powerpc mpc8572
>>>> xenomai version: 2.5.3
>>>> rtnet version: 0.9.12
>>>>
>>>>     
>>>>         
>>>   
>>>       
>>
>> _______________________________________________
>> Xenomai-core mailing list
>> Xenomai-core@domain.hid
>> https://mail.gna.org/listinfo/xenomai-core
>>     
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 14:18     ` Philippe Gerum
  2011-04-11 14:20       ` Jesper Christensen
@ 2011-04-11 14:23       ` Philippe Gerum
  1 sibling, 0 replies; 42+ messages in thread
From: Philippe Gerum @ 2011-04-11 14:23 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On Mon, 2011-04-11 at 16:18 +0200, Philippe Gerum wrote:
> On Mon, 2011-04-11 at 16:13 +0200, Jesper Christensen wrote:
> > I have updated to xenomai 2.5.6, but i'm still seeing exceptions
> > (considerably less often though):
> > 
> > Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
> > after exception #1792
> 
> You should build your code statically into the kernel, not as a module,
> and find out which code raises the MCE.

It's a program check exception, not a machine check, but the rest
remains applicable.

> 
> CONFIG_DEBUG_INFO=y, then objdump -dl vmlinux, looking for the NIP
> mentioned.
> 
> > 
> > /Jesper
> > 
> > 
> > On 2011-04-08 15:12, Philippe Gerum wrote:
> > > On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
> > >   
> > >> Hi
> > >>
> > >> I'm trying to implement some gateway functionality in the kernel on a
> > >> emerson CPCI6200 board, but have run into some strange errors. The
> > >> kernel module is made up of two threads that run every 1 ms. I have also
> > >> made use of the rtpc dispatcher in rtnet to dispatch control messages
> > >> from a netlink socket to the RT part of my kernel module.
> > >>
> > >> The problem is that when loaded the threads get suspended due to exceptions:
> > >>
> > >> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
> > >> after exception #1792
> > >>
> > >> or
> > >>
> > >> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
> > >> exception #1025
> > >>
> > >> or
> > >>
> > >> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
> > >> after exception #1792
> > >>
> > >>
> > >> I have ported the "gianfar" driver from linux to rtnet.
> > >>
> > >> The versions and hardware are listed below. The errors are most likely
> > >> due to faulty software on my part, but i would like to ask if there are
> > >> any known issues with the versions or hardware i'm using. I would also
> > >> like to ask if there are any ways of further debugging the errors as i
> > >> am not getting very far with the above messages.
> > >>     
> > > A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
> > > which would cause exactly the kind of weird behavior you are seeing
> > > right now. The bug triggered random code execution due to stack memory
> > > pollution at init on powerpc for Xenomai kthreads:
> > > http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
> > > http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
> > > http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
> > >
> > > You need at the very least those three patches (from the top of my
> > > head), but it would be much better to upgrade to 2.5.6.
> > >
> > >   
> > >>
> > >>
> > >> System info:
> > >>
> > >> Linux kernel: 2.6.29.6
> > >> i-pipe version: 2.7-04
> > >> processor: powerpc mpc8572
> > >> xenomai version: 2.5.3
> > >> rtnet version: 0.9.12
> > >>
> > >>     
> > >   
> > 
> > 
> > _______________________________________________
> > Xenomai-core mailing list
> > Xenomai-core@domain.hid
> > https://mail.gna.org/listinfo/xenomai-core
> 

-- 
Philippe.




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 14:20       ` Jesper Christensen
@ 2011-04-11 14:27         ` Philippe Gerum
  2011-04-11 14:32           ` Jesper Christensen
  2011-04-11 14:34         ` Philippe Gerum
  1 sibling, 1 reply; 42+ messages in thread
From: Philippe Gerum @ 2011-04-11 14:27 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On Mon, 2011-04-11 at 16:20 +0200, Jesper Christensen wrote:
> Problem is the NIP in question is the address of the thread structure as
> seen in the error message.

LR?

> 
> /Jesper
> 
> 
> On 2011-04-11 16:18, Philippe Gerum wrote:
> > On Mon, 2011-04-11 at 16:13 +0200, Jesper Christensen wrote:
> >   
> >> I have updated to xenomai 2.5.6, but i'm still seeing exceptions
> >> (considerably less often though):
> >>
> >> Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
> >> after exception #1792
> >>     
> > You should build your code statically into the kernel, not as a module,
> > and find out which code raises the MCE.
> >
> > CONFIG_DEBUG_INFO=y, then objdump -dl vmlinux, looking for the NIP
> > mentioned.
> >
> >   
> >> /Jesper
> >>
> >>
> >> On 2011-04-08 15:12, Philippe Gerum wrote:
> >>     
> >>> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
> >>>   
> >>>       
> >>>> Hi
> >>>>
> >>>> I'm trying to implement some gateway functionality in the kernel on a
> >>>> emerson CPCI6200 board, but have run into some strange errors. The
> >>>> kernel module is made up of two threads that run every 1 ms. I have also
> >>>> made use of the rtpc dispatcher in rtnet to dispatch control messages
> >>>> from a netlink socket to the RT part of my kernel module.
> >>>>
> >>>> The problem is that when loaded the threads get suspended due to exceptions:
> >>>>
> >>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
> >>>> after exception #1792
> >>>>
> >>>> or
> >>>>
> >>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
> >>>> exception #1025
> >>>>
> >>>> or
> >>>>
> >>>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
> >>>> after exception #1792
> >>>>
> >>>>
> >>>> I have ported the "gianfar" driver from linux to rtnet.
> >>>>
> >>>> The versions and hardware are listed below. The errors are most likely
> >>>> due to faulty software on my part, but i would like to ask if there are
> >>>> any known issues with the versions or hardware i'm using. I would also
> >>>> like to ask if there are any ways of further debugging the errors as i
> >>>> am not getting very far with the above messages.
> >>>>     
> >>>>         
> >>> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
> >>> which would cause exactly the kind of weird behavior you are seeing
> >>> right now. The bug triggered random code execution due to stack memory
> >>> pollution at init on powerpc for Xenomai kthreads:
> >>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
> >>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
> >>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
> >>>
> >>> You need at the very least those three patches (from the top of my
> >>> head), but it would be much better to upgrade to 2.5.6.
> >>>
> >>>   
> >>>       
> >>>>
> >>>> System info:
> >>>>
> >>>> Linux kernel: 2.6.29.6
> >>>> i-pipe version: 2.7-04
> >>>> processor: powerpc mpc8572
> >>>> xenomai version: 2.5.3
> >>>> rtnet version: 0.9.12
> >>>>
> >>>>     
> >>>>         
> >>>   
> >>>       
> >>
> >> _______________________________________________
> >> Xenomai-core mailing list
> >> Xenomai-core@domain.hid
> >> https://mail.gna.org/listinfo/xenomai-core
> >>     
> >   
> 

-- 
Philippe.




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 14:27         ` Philippe Gerum
@ 2011-04-11 14:32           ` Jesper Christensen
  2011-04-11 14:39             ` Philippe Gerum
  0 siblings, 1 reply; 42+ messages in thread
From: Jesper Christensen @ 2011-04-11 14:32 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai

How do i see that?

/Jesper


On 2011-04-11 16:27, Philippe Gerum wrote:
> On Mon, 2011-04-11 at 16:20 +0200, Jesper Christensen wrote:
>   
>> Problem is the NIP in question is the address of the thread structure as
>> seen in the error message.
>>     
> LR?
>
>   
>> /Jesper
>>
>>
>> On 2011-04-11 16:18, Philippe Gerum wrote:
>>     
>>> On Mon, 2011-04-11 at 16:13 +0200, Jesper Christensen wrote:
>>>   
>>>       
>>>> I have updated to xenomai 2.5.6, but i'm still seeing exceptions
>>>> (considerably less often though):
>>>>
>>>> Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
>>>> after exception #1792
>>>>     
>>>>         
>>> You should build your code statically into the kernel, not as a module,
>>> and find out which code raises the MCE.
>>>
>>> CONFIG_DEBUG_INFO=y, then objdump -dl vmlinux, looking for the NIP
>>> mentioned.
>>>
>>>   
>>>       
>>>> /Jesper
>>>>
>>>>
>>>> On 2011-04-08 15:12, Philippe Gerum wrote:
>>>>     
>>>>         
>>>>> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
>>>>>   
>>>>>       
>>>>>           
>>>>>> Hi
>>>>>>
>>>>>> I'm trying to implement some gateway functionality in the kernel on a
>>>>>> emerson CPCI6200 board, but have run into some strange errors. The
>>>>>> kernel module is made up of two threads that run every 1 ms. I have also
>>>>>> made use of the rtpc dispatcher in rtnet to dispatch control messages
>>>>>> from a netlink socket to the RT part of my kernel module.
>>>>>>
>>>>>> The problem is that when loaded the threads get suspended due to exceptions:
>>>>>>
>>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
>>>>>> after exception #1792
>>>>>>
>>>>>> or
>>>>>>
>>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
>>>>>> exception #1025
>>>>>>
>>>>>> or
>>>>>>
>>>>>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
>>>>>> after exception #1792
>>>>>>
>>>>>>
>>>>>> I have ported the "gianfar" driver from linux to rtnet.
>>>>>>
>>>>>> The versions and hardware are listed below. The errors are most likely
>>>>>> due to faulty software on my part, but i would like to ask if there are
>>>>>> any known issues with the versions or hardware i'm using. I would also
>>>>>> like to ask if there are any ways of further debugging the errors as i
>>>>>> am not getting very far with the above messages.
>>>>>>     
>>>>>>         
>>>>>>             
>>>>> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
>>>>> which would cause exactly the kind of weird behavior you are seeing
>>>>> right now. The bug triggered random code execution due to stack memory
>>>>> pollution at init on powerpc for Xenomai kthreads:
>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
>>>>>
>>>>> You need at the very least those three patches (from the top of my
>>>>> head), but it would be much better to upgrade to 2.5.6.
>>>>>
>>>>>   
>>>>>       
>>>>>           
>>>>>> System info:
>>>>>>
>>>>>> Linux kernel: 2.6.29.6
>>>>>> i-pipe version: 2.7-04
>>>>>> processor: powerpc mpc8572
>>>>>> xenomai version: 2.5.3
>>>>>> rtnet version: 0.9.12
>>>>>>
>>>>>>     
>>>>>>         
>>>>>>             
>>>>>   
>>>>>       
>>>>>           
>>>> _______________________________________________
>>>> Xenomai-core mailing list
>>>> Xenomai-core@domain.hid
>>>> https://mail.gna.org/listinfo/xenomai-core
>>>>     
>>>>         
>>>   
>>>       
>>     
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 14:20       ` Jesper Christensen
  2011-04-11 14:27         ` Philippe Gerum
@ 2011-04-11 14:34         ` Philippe Gerum
  2011-04-11 14:35           ` Jesper Christensen
  1 sibling, 1 reply; 42+ messages in thread
From: Philippe Gerum @ 2011-04-11 14:34 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On Mon, 2011-04-11 at 16:20 +0200, Jesper Christensen wrote:
> Problem is the NIP in question is the address of the thread structure as
> seen in the error message.
> 

Is your code spawning -rt kernel threads frequently/periodically, or
only when the application initializes?

> /Jesper
> 
> 
> On 2011-04-11 16:18, Philippe Gerum wrote:
> > On Mon, 2011-04-11 at 16:13 +0200, Jesper Christensen wrote:
> >   
> >> I have updated to xenomai 2.5.6, but i'm still seeing exceptions
> >> (considerably less often though):
> >>
> >> Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
> >> after exception #1792
> >>     
> > You should build your code statically into the kernel, not as a module,
> > and find out which code raises the MCE.
> >
> > CONFIG_DEBUG_INFO=y, then objdump -dl vmlinux, looking for the NIP
> > mentioned.
> >
> >   
> >> /Jesper
> >>
> >>
> >> On 2011-04-08 15:12, Philippe Gerum wrote:
> >>     
> >>> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
> >>>   
> >>>       
> >>>> Hi
> >>>>
> >>>> I'm trying to implement some gateway functionality in the kernel on a
> >>>> emerson CPCI6200 board, but have run into some strange errors. The
> >>>> kernel module is made up of two threads that run every 1 ms. I have also
> >>>> made use of the rtpc dispatcher in rtnet to dispatch control messages
> >>>> from a netlink socket to the RT part of my kernel module.
> >>>>
> >>>> The problem is that when loaded the threads get suspended due to exceptions:
> >>>>
> >>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
> >>>> after exception #1792
> >>>>
> >>>> or
> >>>>
> >>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
> >>>> exception #1025
> >>>>
> >>>> or
> >>>>
> >>>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
> >>>> after exception #1792
> >>>>
> >>>>
> >>>> I have ported the "gianfar" driver from linux to rtnet.
> >>>>
> >>>> The versions and hardware are listed below. The errors are most likely
> >>>> due to faulty software on my part, but i would like to ask if there are
> >>>> any known issues with the versions or hardware i'm using. I would also
> >>>> like to ask if there are any ways of further debugging the errors as i
> >>>> am not getting very far with the above messages.
> >>>>     
> >>>>         
> >>> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
> >>> which would cause exactly the kind of weird behavior you are seeing
> >>> right now. The bug triggered random code execution due to stack memory
> >>> pollution at init on powerpc for Xenomai kthreads:
> >>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
> >>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
> >>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
> >>>
> >>> You need at the very least those three patches (from the top of my
> >>> head), but it would be much better to upgrade to 2.5.6.
> >>>
> >>>   
> >>>       
> >>>>
> >>>> System info:
> >>>>
> >>>> Linux kernel: 2.6.29.6
> >>>> i-pipe version: 2.7-04
> >>>> processor: powerpc mpc8572
> >>>> xenomai version: 2.5.3
> >>>> rtnet version: 0.9.12
> >>>>
> >>>>     
> >>>>         
> >>>   
> >>>       
> >>
> >> _______________________________________________
> >> Xenomai-core mailing list
> >> Xenomai-core@domain.hid
> >> https://mail.gna.org/listinfo/xenomai-core
> >>     
> >   
> 

-- 
Philippe.




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 14:34         ` Philippe Gerum
@ 2011-04-11 14:35           ` Jesper Christensen
  0 siblings, 0 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-11 14:35 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai

Only during init:

# cat /proc/xenomai/sched
CPU  PID    CLASS  PRI      TIMEOUT   TIMEBASE   STAT       NAME
  0  0      idle    -1      -         master     R          ROOT/0
  1  0      idle    -1      -         master     R          ROOT/1
  0  0      rt      98      -         master     W          rtnet-stack
  0  0      rt       0      -         master     W          rtnet-rtpc
  0  0      rt      99      -         master     S          tt_upgw_0
  1  0      rt      99      27us      master     D          tt_upgw_1
  0  720    rt       0      -         master     X          upgmu
  0  724    rt       0      979ms599us  master     D          upgmu

/Jesper


On 2011-04-11 16:34, Philippe Gerum wrote:
> On Mon, 2011-04-11 at 16:20 +0200, Jesper Christensen wrote:
>   
>> Problem is the NIP in question is the address of the thread structure as
>> seen in the error message.
>>
>>     
> Is your code spawning -rt kernel threads frequently/periodically, or
> only when the application initializes?
>
>   
>> /Jesper
>>
>>
>> On 2011-04-11 16:18, Philippe Gerum wrote:
>>     
>>> On Mon, 2011-04-11 at 16:13 +0200, Jesper Christensen wrote:
>>>   
>>>       
>>>> I have updated to xenomai 2.5.6, but i'm still seeing exceptions
>>>> (considerably less often though):
>>>>
>>>> Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
>>>> after exception #1792
>>>>     
>>>>         
>>> You should build your code statically into the kernel, not as a module,
>>> and find out which code raises the MCE.
>>>
>>> CONFIG_DEBUG_INFO=y, then objdump -dl vmlinux, looking for the NIP
>>> mentioned.
>>>
>>>   
>>>       
>>>> /Jesper
>>>>
>>>>
>>>> On 2011-04-08 15:12, Philippe Gerum wrote:
>>>>     
>>>>         
>>>>> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
>>>>>   
>>>>>       
>>>>>           
>>>>>> Hi
>>>>>>
>>>>>> I'm trying to implement some gateway functionality in the kernel on a
>>>>>> emerson CPCI6200 board, but have run into some strange errors. The
>>>>>> kernel module is made up of two threads that run every 1 ms. I have also
>>>>>> made use of the rtpc dispatcher in rtnet to dispatch control messages
>>>>>> from a netlink socket to the RT part of my kernel module.
>>>>>>
>>>>>> The problem is that when loaded the threads get suspended due to exceptions:
>>>>>>
>>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
>>>>>> after exception #1792
>>>>>>
>>>>>> or
>>>>>>
>>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
>>>>>> exception #1025
>>>>>>
>>>>>> or
>>>>>>
>>>>>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
>>>>>> after exception #1792
>>>>>>
>>>>>>
>>>>>> I have ported the "gianfar" driver from linux to rtnet.
>>>>>>
>>>>>> The versions and hardware are listed below. The errors are most likely
>>>>>> due to faulty software on my part, but i would like to ask if there are
>>>>>> any known issues with the versions or hardware i'm using. I would also
>>>>>> like to ask if there are any ways of further debugging the errors as i
>>>>>> am not getting very far with the above messages.
>>>>>>     
>>>>>>         
>>>>>>             
>>>>> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
>>>>> which would cause exactly the kind of weird behavior you are seeing
>>>>> right now. The bug triggered random code execution due to stack memory
>>>>> pollution at init on powerpc for Xenomai kthreads:
>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
>>>>>
>>>>> You need at the very least those three patches (from the top of my
>>>>> head), but it would be much better to upgrade to 2.5.6.
>>>>>
>>>>>   
>>>>>       
>>>>>           
>>>>>> System info:
>>>>>>
>>>>>> Linux kernel: 2.6.29.6
>>>>>> i-pipe version: 2.7-04
>>>>>> processor: powerpc mpc8572
>>>>>> xenomai version: 2.5.3
>>>>>> rtnet version: 0.9.12
>>>>>>
>>>>>>     
>>>>>>         
>>>>>>             
>>>>>   
>>>>>       
>>>>>           
>>>> _______________________________________________
>>>> Xenomai-core mailing list
>>>> Xenomai-core@domain.hid
>>>> https://mail.gna.org/listinfo/xenomai-core
>>>>     
>>>>         
>>>   
>>>       
>>     
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 14:13   ` Jesper Christensen
  2011-04-11 14:18     ` Philippe Gerum
@ 2011-04-11 14:36     ` Gilles Chanteperdrix
  1 sibling, 0 replies; 42+ messages in thread
From: Gilles Chanteperdrix @ 2011-04-11 14:36 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

Jesper Christensen wrote:
> I have updated to xenomai 2.5.6, but i'm still seeing exceptions
> (considerably less often though):
> 
> Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
> after exception #1792

There was an alignment issue with rtnet on ARM some time ago, which was
solved by the following patch:
http://rtnet.git.sourceforge.net/git/gitweb.cgi?p=rtnet/rtnet;a=commit;h=1b38434c6137d3b4a708e00d8fef6a4b422c6593

Maybe it is related?

Regards.

-- 
					    Gilles.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 14:32           ` Jesper Christensen
@ 2011-04-11 14:39             ` Philippe Gerum
  2011-04-11 14:49               ` Jesper Christensen
  0 siblings, 1 reply; 42+ messages in thread
From: Philippe Gerum @ 2011-04-11 14:39 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On Mon, 2011-04-11 at 16:32 +0200, Jesper Christensen wrote:
> How do i see that?
> 

diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
index 5cc4a23..8dbc537 100644
--- a/include/asm-powerpc/system.h
+++ b/include/asm-powerpc/system.h
@@ -104,7 +104,7 @@ typedef struct xnarch_fltinfo {
 #define xnarch_fault_trap(fi)   ((unsigned int)(fi)->regs->trap)
 #define xnarch_fault_code(fi)   ((fi)->regs->dar)
 #define xnarch_fault_pc(fi)     ((fi)->regs->nip)
-#define xnarch_fault_pc(fi)     ((fi)->regs->nip)
+#define xnarch_fault_lr(fi)     ((fi)->regs->link)
 /* FIXME: FPU faults ignored by the nanokernel on PPC. */
 #define xnarch_fault_fpu_p(fi)  (0)
 /* The following predicates are only usable over a regular Linux stack
diff --git a/ksrc/nucleus/pod.c b/ksrc/nucleus/pod.c
index b5ddbaa..c1722e7 100644
--- a/ksrc/nucleus/pod.c
+++ b/ksrc/nucleus/pod.c
@@ -2591,8 +2591,8 @@ int xnpod_trap_fault(xnarch_fltinfo_t *fltinfo)
 
 	if (!xnpod_userspace_p()) {
 		xnprintf
-		    ("suspending kernel thread %p ('%s') at 0x%lx after exception #%u\n",
-		     thread, thread->name, xnarch_fault_pc(fltinfo),
+		    ("suspending kernel thread %p ('%s') at nip=0x%lx, lr=0x%lx after exception #%u\n",
+		     thread, thread->name, xnarch_fault_pc(fltinfo), xnarch_fault_lr(fltinfo),
 		     xnarch_fault_trap(fltinfo));
 
 		xnpod_suspend_thread(thread, XNSUSP, XN_INFINITE, XN_RELATIVE, NULL);
> /Jesper
> 
> 
> On 2011-04-11 16:27, Philippe Gerum wrote:
> > On Mon, 2011-04-11 at 16:20 +0200, Jesper Christensen wrote:
> >   
> >> Problem is the NIP in question is the address of the thread structure as
> >> seen in the error message.
> >>     
> > LR?
> >
> >   
> >> /Jesper
> >>
> >>
> >> On 2011-04-11 16:18, Philippe Gerum wrote:
> >>     
> >>> On Mon, 2011-04-11 at 16:13 +0200, Jesper Christensen wrote:
> >>>   
> >>>       
> >>>> I have updated to xenomai 2.5.6, but i'm still seeing exceptions
> >>>> (considerably less often though):
> >>>>
> >>>> Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
> >>>> after exception #1792
> >>>>     
> >>>>         
> >>> You should build your code statically into the kernel, not as a module,
> >>> and find out which code raises the MCE.
> >>>
> >>> CONFIG_DEBUG_INFO=y, then objdump -dl vmlinux, looking for the NIP
> >>> mentioned.
> >>>
> >>>   
> >>>       
> >>>> /Jesper
> >>>>
> >>>>
> >>>> On 2011-04-08 15:12, Philippe Gerum wrote:
> >>>>     
> >>>>         
> >>>>> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
> >>>>>   
> >>>>>       
> >>>>>           
> >>>>>> Hi
> >>>>>>
> >>>>>> I'm trying to implement some gateway functionality in the kernel on a
> >>>>>> emerson CPCI6200 board, but have run into some strange errors. The
> >>>>>> kernel module is made up of two threads that run every 1 ms. I have also
> >>>>>> made use of the rtpc dispatcher in rtnet to dispatch control messages
> >>>>>> from a netlink socket to the RT part of my kernel module.
> >>>>>>
> >>>>>> The problem is that when loaded the threads get suspended due to exceptions:
> >>>>>>
> >>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
> >>>>>> after exception #1792
> >>>>>>
> >>>>>> or
> >>>>>>
> >>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
> >>>>>> exception #1025
> >>>>>>
> >>>>>> or
> >>>>>>
> >>>>>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
> >>>>>> after exception #1792
> >>>>>>
> >>>>>>
> >>>>>> I have ported the "gianfar" driver from linux to rtnet.
> >>>>>>
> >>>>>> The versions and hardware are listed below. The errors are most likely
> >>>>>> due to faulty software on my part, but i would like to ask if there are
> >>>>>> any known issues with the versions or hardware i'm using. I would also
> >>>>>> like to ask if there are any ways of further debugging the errors as i
> >>>>>> am not getting very far with the above messages.
> >>>>>>     
> >>>>>>         
> >>>>>>             
> >>>>> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
> >>>>> which would cause exactly the kind of weird behavior you are seeing
> >>>>> right now. The bug triggered random code execution due to stack memory
> >>>>> pollution at init on powerpc for Xenomai kthreads:
> >>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
> >>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
> >>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
> >>>>>
> >>>>> You need at the very least those three patches (from the top of my
> >>>>> head), but it would be much better to upgrade to 2.5.6.
> >>>>>
> >>>>>   
> >>>>>       
> >>>>>           
> >>>>>> System info:
> >>>>>>
> >>>>>> Linux kernel: 2.6.29.6
> >>>>>> i-pipe version: 2.7-04
> >>>>>> processor: powerpc mpc8572
> >>>>>> xenomai version: 2.5.3
> >>>>>> rtnet version: 0.9.12
> >>>>>>
> >>>>>>     
> >>>>>>         
> >>>>>>             
> >>>>>   
> >>>>>       
> >>>>>           
> >>>> _______________________________________________
> >>>> Xenomai-core mailing list
> >>>> Xenomai-core@domain.hid
> >>>> https://mail.gna.org/listinfo/xenomai-core
> >>>>     
> >>>>         
> >>>   
> >>>       
> >>     
> >   
> 

-- 
Philippe.




^ permalink raw reply related	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 14:39             ` Philippe Gerum
@ 2011-04-11 14:49               ` Jesper Christensen
  2011-04-11 15:31                 ` Jesper Christensen
  0 siblings, 1 reply; 42+ messages in thread
From: Jesper Christensen @ 2011-04-11 14:49 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai


I'll just give them a run and see, thanks!

/Jesper


On 2011-04-11 16:39, Philippe Gerum wrote:
> On Mon, 2011-04-11 at 16:32 +0200, Jesper Christensen wrote:
>   
>> How do i see that?
>>
>>     
> diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
> index 5cc4a23..8dbc537 100644
> --- a/include/asm-powerpc/system.h
> +++ b/include/asm-powerpc/system.h
> @@ -104,7 +104,7 @@ typedef struct xnarch_fltinfo {
>  #define xnarch_fault_trap(fi)   ((unsigned int)(fi)->regs->trap)
>  #define xnarch_fault_code(fi)   ((fi)->regs->dar)
>  #define xnarch_fault_pc(fi)     ((fi)->regs->nip)
> -#define xnarch_fault_pc(fi)     ((fi)->regs->nip)
> +#define xnarch_fault_lr(fi)     ((fi)->regs->link)
>  /* FIXME: FPU faults ignored by the nanokernel on PPC. */
>  #define xnarch_fault_fpu_p(fi)  (0)
>  /* The following predicates are only usable over a regular Linux stack
> diff --git a/ksrc/nucleus/pod.c b/ksrc/nucleus/pod.c
> index b5ddbaa..c1722e7 100644
> --- a/ksrc/nucleus/pod.c
> +++ b/ksrc/nucleus/pod.c
> @@ -2591,8 +2591,8 @@ int xnpod_trap_fault(xnarch_fltinfo_t *fltinfo)
>  
>  	if (!xnpod_userspace_p()) {
>  		xnprintf
> -		    ("suspending kernel thread %p ('%s') at 0x%lx after exception #%u\n",
> -		     thread, thread->name, xnarch_fault_pc(fltinfo),
> +		    ("suspending kernel thread %p ('%s') at nip=0x%lx, lr=0x%lx after exception #%u\n",
> +		     thread, thread->name, xnarch_fault_pc(fltinfo), xnarch_fault_lr(fltinfo),
>  		     xnarch_fault_trap(fltinfo));
>  
>  		xnpod_suspend_thread(thread, XNSUSP, XN_INFINITE, XN_RELATIVE, NULL);
>   
>> /Jesper
>>
>>
>> On 2011-04-11 16:27, Philippe Gerum wrote:
>>     
>>> On Mon, 2011-04-11 at 16:20 +0200, Jesper Christensen wrote:
>>>   
>>>       
>>>> Problem is the NIP in question is the address of the thread structure as
>>>> seen in the error message.
>>>>     
>>>>         
>>> LR?
>>>
>>>   
>>>       
>>>> /Jesper
>>>>
>>>>
>>>> On 2011-04-11 16:18, Philippe Gerum wrote:
>>>>     
>>>>         
>>>>> On Mon, 2011-04-11 at 16:13 +0200, Jesper Christensen wrote:
>>>>>   
>>>>>       
>>>>>           
>>>>>> I have updated to xenomai 2.5.6, but i'm still seeing exceptions
>>>>>> (considerably less often though):
>>>>>>
>>>>>> Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
>>>>>> after exception #1792
>>>>>>     
>>>>>>         
>>>>>>             
>>>>> You should build your code statically into the kernel, not as a module,
>>>>> and find out which code raises the MCE.
>>>>>
>>>>> CONFIG_DEBUG_INFO=y, then objdump -dl vmlinux, looking for the NIP
>>>>> mentioned.
>>>>>
>>>>>   
>>>>>       
>>>>>           
>>>>>> /Jesper
>>>>>>
>>>>>>
>>>>>> On 2011-04-08 15:12, Philippe Gerum wrote:
>>>>>>     
>>>>>>         
>>>>>>             
>>>>>>> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
>>>>>>>   
>>>>>>>       
>>>>>>>           
>>>>>>>               
>>>>>>>> Hi
>>>>>>>>
>>>>>>>> I'm trying to implement some gateway functionality in the kernel on a
>>>>>>>> emerson CPCI6200 board, but have run into some strange errors. The
>>>>>>>> kernel module is made up of two threads that run every 1 ms. I have also
>>>>>>>> made use of the rtpc dispatcher in rtnet to dispatch control messages
>>>>>>>> from a netlink socket to the RT part of my kernel module.
>>>>>>>>
>>>>>>>> The problem is that when loaded the threads get suspended due to exceptions:
>>>>>>>>
>>>>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
>>>>>>>> after exception #1792
>>>>>>>>
>>>>>>>> or
>>>>>>>>
>>>>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
>>>>>>>> exception #1025
>>>>>>>>
>>>>>>>> or
>>>>>>>>
>>>>>>>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
>>>>>>>> after exception #1792
>>>>>>>>
>>>>>>>>
>>>>>>>> I have ported the "gianfar" driver from linux to rtnet.
>>>>>>>>
>>>>>>>> The versions and hardware are listed below. The errors are most likely
>>>>>>>> due to faulty software on my part, but i would like to ask if there are
>>>>>>>> any known issues with the versions or hardware i'm using. I would also
>>>>>>>> like to ask if there are any ways of further debugging the errors as i
>>>>>>>> am not getting very far with the above messages.
>>>>>>>>     
>>>>>>>>         
>>>>>>>>             
>>>>>>>>                 
>>>>>>> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
>>>>>>> which would cause exactly the kind of weird behavior you are seeing
>>>>>>> right now. The bug triggered random code execution due to stack memory
>>>>>>> pollution at init on powerpc for Xenomai kthreads:
>>>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
>>>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
>>>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
>>>>>>>
>>>>>>> You need at the very least those three patches (from the top of my
>>>>>>> head), but it would be much better to upgrade to 2.5.6.
>>>>>>>
>>>>>>>   
>>>>>>>       
>>>>>>>           
>>>>>>>               
>>>>>>>> System info:
>>>>>>>>
>>>>>>>> Linux kernel: 2.6.29.6
>>>>>>>> i-pipe version: 2.7-04
>>>>>>>> processor: powerpc mpc8572
>>>>>>>> xenomai version: 2.5.3
>>>>>>>> rtnet version: 0.9.12
>>>>>>>>
>>>>>>>>     
>>>>>>>>         
>>>>>>>>             
>>>>>>>>                 
>>>>>>>   
>>>>>>>       
>>>>>>>           
>>>>>>>               
>>>>>> _______________________________________________
>>>>>> Xenomai-core mailing list
>>>>>> Xenomai-core@domain.hid
>>>>>> https://mail.gna.org/listinfo/xenomai-core
>>>>>>     
>>>>>>         
>>>>>>             
>>>>>   
>>>>>       
>>>>>           
>>>>     
>>>>         
>>>   
>>>       
>>     
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 14:49               ` Jesper Christensen
@ 2011-04-11 15:31                 ` Jesper Christensen
  2011-04-12 13:31                   ` Jesper Christensen
  0 siblings, 1 reply; 42+ messages in thread
From: Jesper Christensen @ 2011-04-11 15:31 UTC (permalink / raw)
  To: xenomai

hmm...

Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at
nip=0x1088860, lr=0x1088862 after exception #1025

LR points to nowhere...Maybe i should do a hexdump of the stack and
manually decode it.

/Jesper


On 2011-04-11 16:49, Jesper Christensen wrote:
> I'll just give them a run and see, thanks!
>
> /Jesper
>
>
> On 2011-04-11 16:39, Philippe Gerum wrote:
>   
>> On Mon, 2011-04-11 at 16:32 +0200, Jesper Christensen wrote:
>>   
>>     
>>> How do i see that?
>>>
>>>     
>>>       
>> diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
>> index 5cc4a23..8dbc537 100644
>> --- a/include/asm-powerpc/system.h
>> +++ b/include/asm-powerpc/system.h
>> @@ -104,7 +104,7 @@ typedef struct xnarch_fltinfo {
>>  #define xnarch_fault_trap(fi)   ((unsigned int)(fi)->regs->trap)
>>  #define xnarch_fault_code(fi)   ((fi)->regs->dar)
>>  #define xnarch_fault_pc(fi)     ((fi)->regs->nip)
>> -#define xnarch_fault_pc(fi)     ((fi)->regs->nip)
>> +#define xnarch_fault_lr(fi)     ((fi)->regs->link)
>>  /* FIXME: FPU faults ignored by the nanokernel on PPC. */
>>  #define xnarch_fault_fpu_p(fi)  (0)
>>  /* The following predicates are only usable over a regular Linux stack
>> diff --git a/ksrc/nucleus/pod.c b/ksrc/nucleus/pod.c
>> index b5ddbaa..c1722e7 100644
>> --- a/ksrc/nucleus/pod.c
>> +++ b/ksrc/nucleus/pod.c
>> @@ -2591,8 +2591,8 @@ int xnpod_trap_fault(xnarch_fltinfo_t *fltinfo)
>>  
>>  	if (!xnpod_userspace_p()) {
>>  		xnprintf
>> -		    ("suspending kernel thread %p ('%s') at 0x%lx after exception #%u\n",
>> -		     thread, thread->name, xnarch_fault_pc(fltinfo),
>> +		    ("suspending kernel thread %p ('%s') at nip=0x%lx, lr=0x%lx after exception #%u\n",
>> +		     thread, thread->name, xnarch_fault_pc(fltinfo), xnarch_fault_lr(fltinfo),
>>  		     xnarch_fault_trap(fltinfo));
>>  
>>  		xnpod_suspend_thread(thread, XNSUSP, XN_INFINITE, XN_RELATIVE, NULL);
>>   
>>     
>>> /Jesper
>>>
>>>
>>> On 2011-04-11 16:27, Philippe Gerum wrote:
>>>     
>>>       
>>>> On Mon, 2011-04-11 at 16:20 +0200, Jesper Christensen wrote:
>>>>   
>>>>       
>>>>         
>>>>> Problem is the NIP in question is the address of the thread structure as
>>>>> seen in the error message.
>>>>>     
>>>>>         
>>>>>           
>>>> LR?
>>>>
>>>>   
>>>>       
>>>>         
>>>>> /Jesper
>>>>>
>>>>>
>>>>> On 2011-04-11 16:18, Philippe Gerum wrote:
>>>>>     
>>>>>         
>>>>>           
>>>>>> On Mon, 2011-04-11 at 16:13 +0200, Jesper Christensen wrote:
>>>>>>   
>>>>>>       
>>>>>>           
>>>>>>             
>>>>>>> I have updated to xenomai 2.5.6, but i'm still seeing exceptions
>>>>>>> (considerably less often though):
>>>>>>>
>>>>>>> Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
>>>>>>> after exception #1792
>>>>>>>     
>>>>>>>         
>>>>>>>             
>>>>>>>               
>>>>>> You should build your code statically into the kernel, not as a module,
>>>>>> and find out which code raises the MCE.
>>>>>>
>>>>>> CONFIG_DEBUG_INFO=y, then objdump -dl vmlinux, looking for the NIP
>>>>>> mentioned.
>>>>>>
>>>>>>   
>>>>>>       
>>>>>>           
>>>>>>             
>>>>>>> /Jesper
>>>>>>>
>>>>>>>
>>>>>>> On 2011-04-08 15:12, Philippe Gerum wrote:
>>>>>>>     
>>>>>>>         
>>>>>>>             
>>>>>>>               
>>>>>>>> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
>>>>>>>>   
>>>>>>>>       
>>>>>>>>           
>>>>>>>>               
>>>>>>>>                 
>>>>>>>>> Hi
>>>>>>>>>
>>>>>>>>> I'm trying to implement some gateway functionality in the kernel on a
>>>>>>>>> emerson CPCI6200 board, but have run into some strange errors. The
>>>>>>>>> kernel module is made up of two threads that run every 1 ms. I have also
>>>>>>>>> made use of the rtpc dispatcher in rtnet to dispatch control messages
>>>>>>>>> from a netlink socket to the RT part of my kernel module.
>>>>>>>>>
>>>>>>>>> The problem is that when loaded the threads get suspended due to exceptions:
>>>>>>>>>
>>>>>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
>>>>>>>>> after exception #1792
>>>>>>>>>
>>>>>>>>> or
>>>>>>>>>
>>>>>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
>>>>>>>>> exception #1025
>>>>>>>>>
>>>>>>>>> or
>>>>>>>>>
>>>>>>>>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
>>>>>>>>> after exception #1792
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> I have ported the "gianfar" driver from linux to rtnet.
>>>>>>>>>
>>>>>>>>> The versions and hardware are listed below. The errors are most likely
>>>>>>>>> due to faulty software on my part, but i would like to ask if there are
>>>>>>>>> any known issues with the versions or hardware i'm using. I would also
>>>>>>>>> like to ask if there are any ways of further debugging the errors as i
>>>>>>>>> am not getting very far with the above messages.
>>>>>>>>>     
>>>>>>>>>         
>>>>>>>>>             
>>>>>>>>>                 
>>>>>>>>>                   
>>>>>>>> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
>>>>>>>> which would cause exactly the kind of weird behavior you are seeing
>>>>>>>> right now. The bug triggered random code execution due to stack memory
>>>>>>>> pollution at init on powerpc for Xenomai kthreads:
>>>>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
>>>>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
>>>>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
>>>>>>>>
>>>>>>>> You need at the very least those three patches (from the top of my
>>>>>>>> head), but it would be much better to upgrade to 2.5.6.
>>>>>>>>
>>>>>>>>   
>>>>>>>>       
>>>>>>>>           
>>>>>>>>               
>>>>>>>>                 
>>>>>>>>> System info:
>>>>>>>>>
>>>>>>>>> Linux kernel: 2.6.29.6
>>>>>>>>> i-pipe version: 2.7-04
>>>>>>>>> processor: powerpc mpc8572
>>>>>>>>> xenomai version: 2.5.3
>>>>>>>>> rtnet version: 0.9.12
>>>>>>>>>
>>>>>>>>>     
>>>>>>>>>         
>>>>>>>>>             
>>>>>>>>>                 
>>>>>>>>>                   
>>>>>>>>   
>>>>>>>>       
>>>>>>>>           
>>>>>>>>               
>>>>>>>>                 
>>>>>>> _______________________________________________
>>>>>>> Xenomai-core mailing list
>>>>>>> Xenomai-core@domain.hid
>>>>>>> https://mail.gna.org/listinfo/xenomai-core
>>>>>>>     
>>>>>>>         
>>>>>>>             
>>>>>>>               
>>>>>>   
>>>>>>       
>>>>>>           
>>>>>>             
>>>>>     
>>>>>         
>>>>>           
>>>>   
>>>>       
>>>>         
>>>     
>>>       
>>   
>>     
>
> _______________________________________________
> Xenomai-core mailing list
> Xenomai-core@domain.hid
> https://mail.gna.org/listinfo/xenomai-core
>
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-11 15:31                 ` Jesper Christensen
@ 2011-04-12 13:31                   ` Jesper Christensen
  2011-04-12 13:39                     ` Gilles Chanteperdrix
  2011-04-12 13:40                     ` Jan Kiszka
  0 siblings, 2 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-12 13:31 UTC (permalink / raw)
  To: xenomai

 

I have managed to print the stack of a faulting thread:

Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at
nip=0xb911f940, lr=0xb911f940, r1=0xaf2c4580 after exception #1792

Xenomai: dumping stack at af2c4600
Xenomai: 0xaf2c45ec - 0xaf2c45fc:       00000000 af2c4600 8009a334
00000000 00000000
Xenomai: 0xaf2c45d8 - 0xaf2c45e8:       00000000  0 00000000 00000000
00000000
Xenomai: 0xaf2c45c4 - 0xaf2c45d4:       b911f518  0 00000000 af2c45f0
8009a364
Xenomai: 0xaf2c45b0 - 0xaf2c45c0:       00000000  0 00000000 00000000
00000000
Xenomai: 0xaf2c459c - 0xaf2c45ac:       00000000  0 00000000 b911f518
8009a334
Xenomai: 0xaf2c4588 - 0xaf2c4598:       00000000 b911f4e0 af2c45d0
b911649c 00000000
Xenomai: 0xaf2c4574 - 0xaf2c4584:       805e3988 8000000 805a89f0
00000001 b911f940
Xenomai: 0xaf2c4560 - 0xaf2c4570:       b911f940 20000000 22000022
b911ebb8 00000700
Xenomai: 0xaf2c454c - 0xaf2c455c:       805a89f0 b911f940 00029000
ffffffff 8009b2e4
Xenomai: 0xaf2c4538 - 0xaf2c4548:       00000000 b911ebb8 805e50c4
805e3988 805a89f0
Xenomai: 0xaf2c4524 - 0xaf2c4534:       00100100 ffffffff 00000000
af2c4580 8000bf48
Xenomai: 0xaf2c4510 - 0xaf2c4520:       00000000  0 00000000 00000000
00200200
Xenomai: 0xaf2c44fc - 0xaf2c450c:       805e3988 22000022 00000000
00000000 00000000

Manually decoded link register words:
---------------------------------------------------------------------------------------------------------
8009a334:
$ powerpc-linux-gnu-addr2line -e vmlinux 0x8009a334
linux-2.6.29.6/arch/powerpc/include/asm/xenomai/bits/pod.h:168

8009a364:
$ powerpc-linux-gnu-addr2line -e vmlinux 0x8009a364
linux-2.6.29.6/arch/powerpc/include/asm/xenomai/bits/pod.h:172

b911649c:
$ powerpc-linux-gnu-addr2line -e
../3rd_party/XM-Linux/rtnet_build/stack/rtnet.ko 0x249c
rtnet_build/stack/rtnet_rtpc.c:201

8000bf48:
$ powerpc-linux-gnu-addr2line -e vmlinux 0x8000bf48
linux-2.6.29.6/arch/powerpc/kernel/ipipe.c:429  
(ipipe_trigger_irq(unsigned irq) at local_irq_restore_hw(flags);)

---------------------------------------------------------------------------------------------------------

Notice the "r1" register in the first line i assume should point to a
back chain word, but the value is 00000001 and the "link register" word
immediately after is b911f940 which points to:
# grep b911f940 /proc/kallsyms
b911f940 b pending_calls_lock   [rtnet]


I'm not sure of the significance of the stack frame after that one.




/Jesper


On 2011-04-11 17:31, Jesper Christensen wrote:
> hmm...
>
> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at
> nip=0x1088860, lr=0x1088862 after exception #1025
>
> LR points to nowhere...Maybe i should do a hexdump of the stack and
> manually decode it.
>
> /Jesper
>
>
> On 2011-04-11 16:49, Jesper Christensen wrote:
>   
>> I'll just give them a run and see, thanks!
>>
>> /Jesper
>>
>>
>> On 2011-04-11 16:39, Philippe Gerum wrote:
>>   
>>     
>>> On Mon, 2011-04-11 at 16:32 +0200, Jesper Christensen wrote:
>>>   
>>>     
>>>       
>>>> How do i see that?
>>>>
>>>>     
>>>>       
>>>>         
>>> diff --git a/include/asm-powerpc/system.h b/include/asm-powerpc/system.h
>>> index 5cc4a23..8dbc537 100644
>>> --- a/include/asm-powerpc/system.h
>>> +++ b/include/asm-powerpc/system.h
>>> @@ -104,7 +104,7 @@ typedef struct xnarch_fltinfo {
>>>  #define xnarch_fault_trap(fi)   ((unsigned int)(fi)->regs->trap)
>>>  #define xnarch_fault_code(fi)   ((fi)->regs->dar)
>>>  #define xnarch_fault_pc(fi)     ((fi)->regs->nip)
>>> -#define xnarch_fault_pc(fi)     ((fi)->regs->nip)
>>> +#define xnarch_fault_lr(fi)     ((fi)->regs->link)
>>>  /* FIXME: FPU faults ignored by the nanokernel on PPC. */
>>>  #define xnarch_fault_fpu_p(fi)  (0)
>>>  /* The following predicates are only usable over a regular Linux stack
>>> diff --git a/ksrc/nucleus/pod.c b/ksrc/nucleus/pod.c
>>> index b5ddbaa..c1722e7 100644
>>> --- a/ksrc/nucleus/pod.c
>>> +++ b/ksrc/nucleus/pod.c
>>> @@ -2591,8 +2591,8 @@ int xnpod_trap_fault(xnarch_fltinfo_t *fltinfo)
>>>  
>>>  	if (!xnpod_userspace_p()) {
>>>  		xnprintf
>>> -		    ("suspending kernel thread %p ('%s') at 0x%lx after exception #%u\n",
>>> -		     thread, thread->name, xnarch_fault_pc(fltinfo),
>>> +		    ("suspending kernel thread %p ('%s') at nip=0x%lx, lr=0x%lx after exception #%u\n",
>>> +		     thread, thread->name, xnarch_fault_pc(fltinfo), xnarch_fault_lr(fltinfo),
>>>  		     xnarch_fault_trap(fltinfo));
>>>  
>>>  		xnpod_suspend_thread(thread, XNSUSP, XN_INFINITE, XN_RELATIVE, NULL);
>>>   
>>>     
>>>       
>>>> /Jesper
>>>>
>>>>
>>>> On 2011-04-11 16:27, Philippe Gerum wrote:
>>>>     
>>>>       
>>>>         
>>>>> On Mon, 2011-04-11 at 16:20 +0200, Jesper Christensen wrote:
>>>>>   
>>>>>       
>>>>>         
>>>>>           
>>>>>> Problem is the NIP in question is the address of the thread structure as
>>>>>> seen in the error message.
>>>>>>     
>>>>>>         
>>>>>>           
>>>>>>             
>>>>> LR?
>>>>>
>>>>>   
>>>>>       
>>>>>         
>>>>>           
>>>>>> /Jesper
>>>>>>
>>>>>>
>>>>>> On 2011-04-11 16:18, Philippe Gerum wrote:
>>>>>>     
>>>>>>         
>>>>>>           
>>>>>>             
>>>>>>> On Mon, 2011-04-11 at 16:13 +0200, Jesper Christensen wrote:
>>>>>>>   
>>>>>>>       
>>>>>>>           
>>>>>>>             
>>>>>>>               
>>>>>>>> I have updated to xenomai 2.5.6, but i'm still seeing exceptions
>>>>>>>> (considerably less often though):
>>>>>>>>
>>>>>>>> Xenomai: suspending kernel thread b92a39d0 ('tt_upgw_0') at 0xb92a39d0
>>>>>>>> after exception #1792
>>>>>>>>     
>>>>>>>>         
>>>>>>>>             
>>>>>>>>               
>>>>>>>>                 
>>>>>>> You should build your code statically into the kernel, not as a module,
>>>>>>> and find out which code raises the MCE.
>>>>>>>
>>>>>>> CONFIG_DEBUG_INFO=y, then objdump -dl vmlinux, looking for the NIP
>>>>>>> mentioned.
>>>>>>>
>>>>>>>   
>>>>>>>       
>>>>>>>           
>>>>>>>             
>>>>>>>               
>>>>>>>> /Jesper
>>>>>>>>
>>>>>>>>
>>>>>>>> On 2011-04-08 15:12, Philippe Gerum wrote:
>>>>>>>>     
>>>>>>>>         
>>>>>>>>             
>>>>>>>>               
>>>>>>>>                 
>>>>>>>>> On Fri, 2011-04-08 at 14:58 +0200, Jesper Christensen wrote:
>>>>>>>>>   
>>>>>>>>>       
>>>>>>>>>           
>>>>>>>>>               
>>>>>>>>>                 
>>>>>>>>>                   
>>>>>>>>>> Hi
>>>>>>>>>>
>>>>>>>>>> I'm trying to implement some gateway functionality in the kernel on a
>>>>>>>>>> emerson CPCI6200 board, but have run into some strange errors. The
>>>>>>>>>> kernel module is made up of two threads that run every 1 ms. I have also
>>>>>>>>>> made use of the rtpc dispatcher in rtnet to dispatch control messages
>>>>>>>>>> from a netlink socket to the RT part of my kernel module.
>>>>>>>>>>
>>>>>>>>>> The problem is that when loaded the threads get suspended due to exceptions:
>>>>>>>>>>
>>>>>>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0xb929cbc0
>>>>>>>>>> after exception #1792
>>>>>>>>>>
>>>>>>>>>> or
>>>>>>>>>>
>>>>>>>>>> Xenomai: suspending kernel thread b929cbc0 ('tt_upgw_0') at 0x0 after
>>>>>>>>>> exception #1025
>>>>>>>>>>
>>>>>>>>>> or
>>>>>>>>>>
>>>>>>>>>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at 0xb911f940
>>>>>>>>>> after exception #1792
>>>>>>>>>>
>>>>>>>>>>
>>>>>>>>>> I have ported the "gianfar" driver from linux to rtnet.
>>>>>>>>>>
>>>>>>>>>> The versions and hardware are listed below. The errors are most likely
>>>>>>>>>> due to faulty software on my part, but i would like to ask if there are
>>>>>>>>>> any known issues with the versions or hardware i'm using. I would also
>>>>>>>>>> like to ask if there are any ways of further debugging the errors as i
>>>>>>>>>> am not getting very far with the above messages.
>>>>>>>>>>     
>>>>>>>>>>         
>>>>>>>>>>             
>>>>>>>>>>                 
>>>>>>>>>>                   
>>>>>>>>>>                     
>>>>>>>>> A severe bug at kthread init was fixed in the 2.5.5.2 - 2.5.6 timeframe,
>>>>>>>>> which would cause exactly the kind of weird behavior you are seeing
>>>>>>>>> right now. The bug triggered random code execution due to stack memory
>>>>>>>>> pollution at init on powerpc for Xenomai kthreads:
>>>>>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=90699565cbce41f2cec193d57857bb5817efc19a
>>>>>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=da20c20d4b4d892d40c657ad1d32ddb6d0ceb47c
>>>>>>>>> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=a5886b354dc18f054b187b58cfbacfb60bccaf47
>>>>>>>>>
>>>>>>>>> You need at the very least those three patches (from the top of my
>>>>>>>>> head), but it would be much better to upgrade to 2.5.6.
>>>>>>>>>
>>>>>>>>>   
>>>>>>>>>       
>>>>>>>>>           
>>>>>>>>>               
>>>>>>>>>                 
>>>>>>>>>                   
>>>>>>>>>> System info:
>>>>>>>>>>
>>>>>>>>>> Linux kernel: 2.6.29.6
>>>>>>>>>> i-pipe version: 2.7-04
>>>>>>>>>> processor: powerpc mpc8572
>>>>>>>>>> xenomai version: 2.5.3
>>>>>>>>>> rtnet version: 0.9.12
>>>>>>>>>>
>>>>>>>>>>     
>>>>>>>>>>         
>>>>>>>>>>             
>>>>>>>>>>                 
>>>>>>>>>>                   
>>>>>>>>>>                     
>>>>>>>>>   
>>>>>>>>>       
>>>>>>>>>           
>>>>>>>>>               
>>>>>>>>>                 
>>>>>>>>>                   
>>>>>>>> _______________________________________________
>>>>>>>> Xenomai-core mailing list
>>>>>>>> Xenomai-core@domain.hid
>>>>>>>> https://mail.gna.org/listinfo/xenomai-core
>>>>>>>>     
>>>>>>>>         
>>>>>>>>             
>>>>>>>>               
>>>>>>>>                 
>>>>>>>   
>>>>>>>       
>>>>>>>           
>>>>>>>             
>>>>>>>               
>>>>>>     
>>>>>>         
>>>>>>           
>>>>>>             
>>>>>   
>>>>>       
>>>>>         
>>>>>           
>>>>     
>>>>       
>>>>         
>>>   
>>>     
>>>       
>> _______________________________________________
>> Xenomai-core mailing list
>> Xenomai-core@domain.hid
>> https://mail.gna.org/listinfo/xenomai-core
>>
>>   
>>     
>
> _______________________________________________
> Xenomai-core mailing list
> Xenomai-core@domain.hid
> https://mail.gna.org/listinfo/xenomai-core
>
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-12 13:31                   ` Jesper Christensen
@ 2011-04-12 13:39                     ` Gilles Chanteperdrix
  2011-04-12 13:40                       ` Jesper Christensen
  2011-04-12 13:40                     ` Jan Kiszka
  1 sibling, 1 reply; 42+ messages in thread
From: Gilles Chanteperdrix @ 2011-04-12 13:39 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

Jesper Christensen wrote:
>  
> 
> I have managed to print the stack of a faulting thread:

Did you test the patch I directed you to? We may be chasing an already
known issue here...

-- 
					    Gilles.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-12 13:31                   ` Jesper Christensen
  2011-04-12 13:39                     ` Gilles Chanteperdrix
@ 2011-04-12 13:40                     ` Jan Kiszka
  2011-04-12 13:45                       ` Jesper Christensen
  2011-04-12 14:09                       ` Jesper Christensen
  1 sibling, 2 replies; 42+ messages in thread
From: Jan Kiszka @ 2011-04-12 13:40 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On 2011-04-12 15:31, Jesper Christensen wrote:
>  
> 
> I have managed to print the stack of a faulting thread:
> 
> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at
> nip=0xb911f940, lr=0xb911f940, r1=0xaf2c4580 after exception #1792
> 
> Xenomai: dumping stack at af2c4600
> Xenomai: 0xaf2c45ec - 0xaf2c45fc:       00000000 af2c4600 8009a334
> 00000000 00000000
> Xenomai: 0xaf2c45d8 - 0xaf2c45e8:       00000000  0 00000000 00000000
> 00000000
> Xenomai: 0xaf2c45c4 - 0xaf2c45d4:       b911f518  0 00000000 af2c45f0
> 8009a364
> Xenomai: 0xaf2c45b0 - 0xaf2c45c0:       00000000  0 00000000 00000000
> 00000000
> Xenomai: 0xaf2c459c - 0xaf2c45ac:       00000000  0 00000000 b911f518
> 8009a334
> Xenomai: 0xaf2c4588 - 0xaf2c4598:       00000000 b911f4e0 af2c45d0
> b911649c 00000000
> Xenomai: 0xaf2c4574 - 0xaf2c4584:       805e3988 8000000 805a89f0
> 00000001 b911f940
> Xenomai: 0xaf2c4560 - 0xaf2c4570:       b911f940 20000000 22000022
> b911ebb8 00000700
> Xenomai: 0xaf2c454c - 0xaf2c455c:       805a89f0 b911f940 00029000
> ffffffff 8009b2e4
> Xenomai: 0xaf2c4538 - 0xaf2c4548:       00000000 b911ebb8 805e50c4
> 805e3988 805a89f0
> Xenomai: 0xaf2c4524 - 0xaf2c4534:       00100100 ffffffff 00000000
> af2c4580 8000bf48
> Xenomai: 0xaf2c4510 - 0xaf2c4520:       00000000  0 00000000 00000000
> 00200200
> Xenomai: 0xaf2c44fc - 0xaf2c450c:       805e3988 22000022 00000000
> 00000000 00000000
> 
> Manually decoded link register words:
> ---------------------------------------------------------------------------------------------------------
> 8009a334:
> $ powerpc-linux-gnu-addr2line -e vmlinux 0x8009a334
> linux-2.6.29.6/arch/powerpc/include/asm/xenomai/bits/pod.h:168
> 
> 8009a364:
> $ powerpc-linux-gnu-addr2line -e vmlinux 0x8009a364
> linux-2.6.29.6/arch/powerpc/include/asm/xenomai/bits/pod.h:172
> 
> b911649c:
> $ powerpc-linux-gnu-addr2line -e
> ../3rd_party/XM-Linux/rtnet_build/stack/rtnet.ko 0x249c
> rtnet_build/stack/rtnet_rtpc.c:201
> 
> 8000bf48:
> $ powerpc-linux-gnu-addr2line -e vmlinux 0x8000bf48
> linux-2.6.29.6/arch/powerpc/kernel/ipipe.c:429  
> (ipipe_trigger_irq(unsigned irq) at local_irq_restore_hw(flags);)
> 
> ---------------------------------------------------------------------------------------------------------
> 
> Notice the "r1" register in the first line i assume should point to a
> back chain word, but the value is 00000001 and the "link register" word
> immediately after is b911f940 which points to:
> # grep b911f940 /proc/kallsyms
> b911f940 b pending_calls_lock   [rtnet]
> 
> 
> I'm not sure of the significance of the stack frame after that one.
> 

IIRC, you said that you are using rtnet-rtpc for a special use case.
Given the fact that this interface very well documented and highly
intuitive to use ;), I wouldn't be too surprised if you ran into a race
or an invalid use case.

Is the rtpc-using code part of your tarball? If so, can you break it out
and explain on it how you use rtpc?

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-12 13:39                     ` Gilles Chanteperdrix
@ 2011-04-12 13:40                       ` Jesper Christensen
  0 siblings, 0 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-12 13:40 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: xenomai

Sorry about that, yes i merged that in right away.

/Jesper


On 2011-04-12 15:39, Gilles Chanteperdrix wrote:
> Jesper Christensen wrote:
>   
>>  
>>
>> I have managed to print the stack of a faulting thread:
>>     
> Did you test the patch I directed you to? We may be chasing an already
> known issue here...
>
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-12 13:40                     ` Jan Kiszka
@ 2011-04-12 13:45                       ` Jesper Christensen
  2011-04-12 14:09                       ` Jesper Christensen
  1 sibling, 0 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-12 13:45 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: xenomai

Unfortunately it's not part of the tar ball, but i might be able to post
a source file that sums it up pretty well.

/Jesper


On 2011-04-12 15:40, Jan Kiszka wrote:
> On 2011-04-12 15:31, Jesper Christensen wrote:
>   
>>  
>>
>> I have managed to print the stack of a faulting thread:
>>
>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at
>> nip=0xb911f940, lr=0xb911f940, r1=0xaf2c4580 after exception #1792
>>
>> Xenomai: dumping stack at af2c4600
>> Xenomai: 0xaf2c45ec - 0xaf2c45fc:       00000000 af2c4600 8009a334
>> 00000000 00000000
>> Xenomai: 0xaf2c45d8 - 0xaf2c45e8:       00000000  0 00000000 00000000
>> 00000000
>> Xenomai: 0xaf2c45c4 - 0xaf2c45d4:       b911f518  0 00000000 af2c45f0
>> 8009a364
>> Xenomai: 0xaf2c45b0 - 0xaf2c45c0:       00000000  0 00000000 00000000
>> 00000000
>> Xenomai: 0xaf2c459c - 0xaf2c45ac:       00000000  0 00000000 b911f518
>> 8009a334
>> Xenomai: 0xaf2c4588 - 0xaf2c4598:       00000000 b911f4e0 af2c45d0
>> b911649c 00000000
>> Xenomai: 0xaf2c4574 - 0xaf2c4584:       805e3988 8000000 805a89f0
>> 00000001 b911f940
>> Xenomai: 0xaf2c4560 - 0xaf2c4570:       b911f940 20000000 22000022
>> b911ebb8 00000700
>> Xenomai: 0xaf2c454c - 0xaf2c455c:       805a89f0 b911f940 00029000
>> ffffffff 8009b2e4
>> Xenomai: 0xaf2c4538 - 0xaf2c4548:       00000000 b911ebb8 805e50c4
>> 805e3988 805a89f0
>> Xenomai: 0xaf2c4524 - 0xaf2c4534:       00100100 ffffffff 00000000
>> af2c4580 8000bf48
>> Xenomai: 0xaf2c4510 - 0xaf2c4520:       00000000  0 00000000 00000000
>> 00200200
>> Xenomai: 0xaf2c44fc - 0xaf2c450c:       805e3988 22000022 00000000
>> 00000000 00000000
>>
>> Manually decoded link register words:
>> ---------------------------------------------------------------------------------------------------------
>> 8009a334:
>> $ powerpc-linux-gnu-addr2line -e vmlinux 0x8009a334
>> linux-2.6.29.6/arch/powerpc/include/asm/xenomai/bits/pod.h:168
>>
>> 8009a364:
>> $ powerpc-linux-gnu-addr2line -e vmlinux 0x8009a364
>> linux-2.6.29.6/arch/powerpc/include/asm/xenomai/bits/pod.h:172
>>
>> b911649c:
>> $ powerpc-linux-gnu-addr2line -e
>> ../3rd_party/XM-Linux/rtnet_build/stack/rtnet.ko 0x249c
>> rtnet_build/stack/rtnet_rtpc.c:201
>>
>> 8000bf48:
>> $ powerpc-linux-gnu-addr2line -e vmlinux 0x8000bf48
>> linux-2.6.29.6/arch/powerpc/kernel/ipipe.c:429  
>> (ipipe_trigger_irq(unsigned irq) at local_irq_restore_hw(flags);)
>>
>> ---------------------------------------------------------------------------------------------------------
>>
>> Notice the "r1" register in the first line i assume should point to a
>> back chain word, but the value is 00000001 and the "link register" word
>> immediately after is b911f940 which points to:
>> # grep b911f940 /proc/kallsyms
>> b911f940 b pending_calls_lock   [rtnet]
>>
>>
>> I'm not sure of the significance of the stack frame after that one.
>>
>>     
> IIRC, you said that you are using rtnet-rtpc for a special use case.
> Given the fact that this interface very well documented and highly
> intuitive to use ;), I wouldn't be too surprised if you ran into a race
> or an invalid use case.
>
> Is the rtpc-using code part of your tarball? If so, can you break it out
> and explain on it how you use rtpc?
>
> Jan
>
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-12 13:40                     ` Jan Kiszka
  2011-04-12 13:45                       ` Jesper Christensen
@ 2011-04-12 14:09                       ` Jesper Christensen
  2011-04-12 14:14                         ` Jan Kiszka
  1 sibling, 1 reply; 42+ messages in thread
From: Jesper Christensen @ 2011-04-12 14:09 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: xenomai

Speaking of rtpc, could there be a race condition when using a
rtdm_lock_t to synchronize between a linux thread and a xenomai thread?

/Jesper


On 2011-04-12 15:40, Jan Kiszka wrote:
> On 2011-04-12 15:31, Jesper Christensen wrote:
>   
>>  
>>
>> I have managed to print the stack of a faulting thread:
>>
>> Xenomai: suspending kernel thread b911f518 ('rtnet-rtpc') at
>> nip=0xb911f940, lr=0xb911f940, r1=0xaf2c4580 after exception #1792
>>
>> Xenomai: dumping stack at af2c4600
>> Xenomai: 0xaf2c45ec - 0xaf2c45fc:       00000000 af2c4600 8009a334
>> 00000000 00000000
>> Xenomai: 0xaf2c45d8 - 0xaf2c45e8:       00000000  0 00000000 00000000
>> 00000000
>> Xenomai: 0xaf2c45c4 - 0xaf2c45d4:       b911f518  0 00000000 af2c45f0
>> 8009a364
>> Xenomai: 0xaf2c45b0 - 0xaf2c45c0:       00000000  0 00000000 00000000
>> 00000000
>> Xenomai: 0xaf2c459c - 0xaf2c45ac:       00000000  0 00000000 b911f518
>> 8009a334
>> Xenomai: 0xaf2c4588 - 0xaf2c4598:       00000000 b911f4e0 af2c45d0
>> b911649c 00000000
>> Xenomai: 0xaf2c4574 - 0xaf2c4584:       805e3988 8000000 805a89f0
>> 00000001 b911f940
>> Xenomai: 0xaf2c4560 - 0xaf2c4570:       b911f940 20000000 22000022
>> b911ebb8 00000700
>> Xenomai: 0xaf2c454c - 0xaf2c455c:       805a89f0 b911f940 00029000
>> ffffffff 8009b2e4
>> Xenomai: 0xaf2c4538 - 0xaf2c4548:       00000000 b911ebb8 805e50c4
>> 805e3988 805a89f0
>> Xenomai: 0xaf2c4524 - 0xaf2c4534:       00100100 ffffffff 00000000
>> af2c4580 8000bf48
>> Xenomai: 0xaf2c4510 - 0xaf2c4520:       00000000  0 00000000 00000000
>> 00200200
>> Xenomai: 0xaf2c44fc - 0xaf2c450c:       805e3988 22000022 00000000
>> 00000000 00000000
>>
>> Manually decoded link register words:
>> ---------------------------------------------------------------------------------------------------------
>> 8009a334:
>> $ powerpc-linux-gnu-addr2line -e vmlinux 0x8009a334
>> linux-2.6.29.6/arch/powerpc/include/asm/xenomai/bits/pod.h:168
>>
>> 8009a364:
>> $ powerpc-linux-gnu-addr2line -e vmlinux 0x8009a364
>> linux-2.6.29.6/arch/powerpc/include/asm/xenomai/bits/pod.h:172
>>
>> b911649c:
>> $ powerpc-linux-gnu-addr2line -e
>> ../3rd_party/XM-Linux/rtnet_build/stack/rtnet.ko 0x249c
>> rtnet_build/stack/rtnet_rtpc.c:201
>>
>> 8000bf48:
>> $ powerpc-linux-gnu-addr2line -e vmlinux 0x8000bf48
>> linux-2.6.29.6/arch/powerpc/kernel/ipipe.c:429  
>> (ipipe_trigger_irq(unsigned irq) at local_irq_restore_hw(flags);)
>>
>> ---------------------------------------------------------------------------------------------------------
>>
>> Notice the "r1" register in the first line i assume should point to a
>> back chain word, but the value is 00000001 and the "link register" word
>> immediately after is b911f940 which points to:
>> # grep b911f940 /proc/kallsyms
>> b911f940 b pending_calls_lock   [rtnet]
>>
>>
>> I'm not sure of the significance of the stack frame after that one.
>>
>>     
> IIRC, you said that you are using rtnet-rtpc for a special use case.
> Given the fact that this interface very well documented and highly
> intuitive to use ;), I wouldn't be too surprised if you ran into a race
> or an invalid use case.
>
> Is the rtpc-using code part of your tarball? If so, can you break it out
> and explain on it how you use rtpc?
>
> Jan
>
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-12 14:09                       ` Jesper Christensen
@ 2011-04-12 14:14                         ` Jan Kiszka
  2011-04-12 14:21                           ` Jesper Christensen
  0 siblings, 1 reply; 42+ messages in thread
From: Jan Kiszka @ 2011-04-12 14:14 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai@xenomai.org

On 2011-04-12 16:09, Jesper Christensen wrote:
> Speaking of rtpc, could there be a race condition when using a
> rtdm_lock_t to synchronize between a linux thread and a xenomai thread?

Without seeing at some code, I can't comment on this meaningfully.

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-12 14:14                         ` Jan Kiszka
@ 2011-04-12 14:21                           ` Jesper Christensen
  2011-04-12 15:24                             ` Jan Kiszka
  2011-04-19  7:26                             ` Jesper Christensen
  0 siblings, 2 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-12 14:21 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: xenomai@xenomai.org

There you go:


-----------------------------------------------------------------------------------

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/workqueue.h>

#include <rtnet_rtpc.h>
#include <up.h>



static rtdm_lock_t      umsg_list_lock = RTDM_LOCK_UNLOCKED;
static rtdm_nrtsig_t    up_nrt_signal;
LIST_HEAD(umsg_list);


static void up_work_queue_handler(struct work_struct *work);
DECLARE_WORK(wq, up_work_queue_handler);

u32 up_user_pid = 0;

struct up_msg_buf *up_alloc_msg_buf(int cmd, size_t psize, struct
genl_info *info,
                                          up_msg_finalize fin)
{
   
    struct up_msg_buf *ret;
   
    ret = kmalloc(sizeof(struct up_msg_buf) + psize, GFP_KERNEL);
    if(!ret)
        return ret;
   
    memset(ret, 0, sizeof(struct up_msg_buf));
   
    /* Initialize some fields */
    if(info) {
        ret->pid = info->snd_pid;
        ret->seq = info->snd_seq;
    }
    ret->cmd = cmd;
    ret->finalize = fin;
   
   
    return ret;
   
   
}

void up_queue_umsg(struct up_msg_buf *umsg, int op, int len, U8 upid)
{
   
    rtdm_lockctx_t context;
   
    umsg->hdr.opcode = op;
    umsg->hdr.plen = len;
    umsg->hdr.up_id = upid;
   
    rtdm_lock_get_irqsave(&umsg_list_lock, context);
    list_add_tail(&umsg->list_entry, &umsg_list);
    rtdm_lock_put_irqrestore(&umsg_list_lock, context);
   
    rtdm_nrtsig_pend(&up_nrt_signal);
   
   
}


static int up_handle_cmd_msg_rt(struct rt_proc_call *call)
{
   
    struct up_cmd_param *params;
    struct up_msg_buf *resp;
   
    params = rtpc_get_priv(call, struct up_cmd_param);
    resp = params->resp_buf;
   
    if(resp)
        resp->cmd = UP_NL_C_CMD;
   
    switch(params->hdr.opcode) {
       
        case UP_CMD_INIT:
            break;

        case UP_CMD_CREATE_REQ:
        {
            struct up_config *c = (struct up_config *)&params->msg.config;
            int *res = (int *)resp->payload;
            *res = up_create(params->hdr.up_id, c);
            if(*res < 0)
                rtdm_printk("Error creating UP\n");

            up_queue_umsg(resp, UP_CMD_CREATE_RES, sizeof(int), 0);
            break;
        }

        default:
            rtdm_printk("Unknown cmd message: op=%d\n", params->hdr.opcode);
            return -ENOTSUPP;
       
    }
   
    return 0;
}

static int up_handle_cmd_msg_nrt(struct sk_buff *skb, struct genl_info
*info)
{
   
    int ret;
    struct up_cmd_param params;
    struct up_user_hdr *uhdr = (struct up_user_hdr *)info->userhdr;
   
    //TODO: Allocate response buffer based on message type
    switch(uhdr->opcode) {
       
        case UP_CMD_INIT:
            up_user_pid = info->snd_pid;
            params.resp_buf = NULL;
            break;
           
        default:
            params.resp_buf = up_alloc_msg_buf(UP_NL_C_CMD,
sizeof(cmdMsg_t),
                                                    info, NULL);
            break;
    };
   
    memcpy(&params.hdr, info->userhdr, sizeof(struct up_user_hdr));
   
    if(params.hdr.plen > sizeof(cmdMsg_t))
        printk("up_handle_cmd_msg_nrt(): ERROR plen=%u >
sizeof(cmdMsg_t)=%u\n", params.hdr.plen, sizeof(cmdMsg_t));
   
    if(params.hdr.plen)
        nla_memcpy(&params.msg, info->attrs[UP_NL_A_MSG], params.hdr.plen);
   
    ret = rtpc_dispatch_call(up_handle_cmd_msg_rt, 0, &params,
sizeof(params),
                             NULL, NULL, NULL);
   
    if(ret < 0)
        kfree(params.resp_buf);

    return ret;

}

/* netlink attribute policy */
static const struct nla_policy up_genl_policy[UP_NL_A_MAX + 1] = {
    [UP_NL_A_MSG] = { .type = NLA_BINARY }
};

/* Generic netlink event operation definition */
static struct genl_ops up_genl_ops_cmd = {
    .cmd = UP_NL_C_CMD,
    .flags = 0,
    .policy = up_genl_policy,
    .doit = up_handle_cmd_msg_nrt,
    .dumpit = NULL
};

/* Generic netlink family */
static struct genl_family up_genl_family = {
    .id = GENL_ID_GENERATE,
    .hdrsize = UP_GENL_HDRLEN,
    .name = "up",
    .version = UP_NL_VERSION,
    .maxattr = UP_NL_A_MAX
};

static void up_work_queue_handler(struct work_struct *work)
{
   
    struct up_msg_buf *msg;
    struct sk_buff *skb;
    struct up_user_hdr *uhdr;
    rtdm_lockctx_t context;
    int rc;
   
    rtdm_lock_get_irqsave(&umsg_list_lock, context);
   
    while(!list_empty(&umsg_list)) {
        msg = (struct up_msg_buf *)umsg_list.next;
        list_del(&msg->list_entry);
        rtdm_lock_put_irqrestore(&umsg_list_lock, context);
       
        /* construct netlink message and send */
        skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
        if(!skb)
            goto failure;
       
        uhdr = genlmsg_put(skb, msg->pid, msg->seq, &up_genl_family,
                               0, msg->cmd);
        if(!uhdr)
            goto skb_failure;
       
        memcpy(uhdr, &msg->hdr, sizeof(struct up_user_hdr));
       
        rc = nla_put(skb, UP_NL_A_MSG, msg->hdr.plen, &msg->payload);
        if(rc != 0)
            goto skb_failure;
       
        genlmsg_end(skb, uhdr);
       
        rc = genlmsg_unicast(skb, msg->pid);
       
        if(msg->finalize)
            msg->finalize(msg);
        else
            kfree(msg);
       
        if(rc < 0)
            goto skb_failure;
       
        rtdm_lock_get_irqsave(&umsg_list_lock, context);
    }
   
    rtdm_lock_put_irqrestore(&umsg_list_lock, context);
   
    return;

skb_failure:
    nlmsg_free(skb);
failure:
    printk("Response failure\n");
   
}

static void up_signal_handler(rtdm_nrtsig_t nrt_sig, void *arg)
{
    /* Schedule work to be done in process context */
    schedule_work(&wq);
}

static int __init up_init(void)
{
   
    int rc = 0;
    printk("UP module loading\n");
   
    rc = genl_register_family(&up_genl_family);
    if(rc != 0)
        return rc;
   
    rc = genl_register_ops(&up_genl_family, &up_genl_ops_cmd);
    if(rc != 0)
        goto failure;
   
    rc = rtdm_nrtsig_init(&up_nrt_signal, up_signal_handler, NULL);
    if(rc < 0)
        goto failure;

    rc = up_init();
   
    if(rc < 0)
        goto failure;

   
    return 0;

failure:
    printk("UP module loading failed\n");
    genl_unregister_family(&up_genl_family);
    return rc;
}


static void __exit up_release(void)
{
   
    printk("UP module unloading\n");
    rtdm_nrtsig_destroy(&up_nrt_signal);

    genl_unregister_family(&up_genl_family);
   
    up_release();
   
}

module_init(up_init);
module_exit(up_release);


-----------------------------------------------------------------------------------

/Jesper


On 2011-04-12 16:14, Jan Kiszka wrote:
> On 2011-04-12 16:09, Jesper Christensen wrote:
>   
>> Speaking of rtpc, could there be a race condition when using a
>> rtdm_lock_t to synchronize between a linux thread and a xenomai thread?
>>     
> Without seeing at some code, I can't comment on this meaningfully.
>
> Jan
>
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-12 14:21                           ` Jesper Christensen
@ 2011-04-12 15:24                             ` Jan Kiszka
  2011-04-12 15:50                               ` Jesper Christensen
  2011-04-19  7:26                             ` Jesper Christensen
  1 sibling, 1 reply; 42+ messages in thread
From: Jan Kiszka @ 2011-04-12 15:24 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai@xenomai.org

On 2011-04-12 16:21, Jesper Christensen wrote:
> There you go:
> 
> 
> -----------------------------------------------------------------------------------
> 
> #include <linux/module.h>
> #include <linux/kernel.h>
> #include <linux/list.h>
> #include <linux/workqueue.h>
> 
> #include <rtnet_rtpc.h>
> #include <up.h>
> 
> 
> 
> static rtdm_lock_t      umsg_list_lock = RTDM_LOCK_UNLOCKED;
> static rtdm_nrtsig_t    up_nrt_signal;
> LIST_HEAD(umsg_list);
> 
> 
> static void up_work_queue_handler(struct work_struct *work);
> DECLARE_WORK(wq, up_work_queue_handler);
> 
> u32 up_user_pid = 0;
> 
> struct up_msg_buf *up_alloc_msg_buf(int cmd, size_t psize, struct
> genl_info *info,
>                                           up_msg_finalize fin)
> {
>    
>     struct up_msg_buf *ret;
>    
>     ret = kmalloc(sizeof(struct up_msg_buf) + psize, GFP_KERNEL);
>     if(!ret)
>         return ret;
>    
>     memset(ret, 0, sizeof(struct up_msg_buf));

[ kzalloc = kmalloc + memset ]

>    
>     /* Initialize some fields */
>     if(info) {
>         ret->pid = info->snd_pid;
>         ret->seq = info->snd_seq;
>     }
>     ret->cmd = cmd;
>     ret->finalize = fin;
>    
>    
>     return ret;
>    
>    
> }
> 
> void up_queue_umsg(struct up_msg_buf *umsg, int op, int len, U8 upid)
> {
>    
>     rtdm_lockctx_t context;
>    
>     umsg->hdr.opcode = op;
>     umsg->hdr.plen = len;
>     umsg->hdr.up_id = upid;
>    
>     rtdm_lock_get_irqsave(&umsg_list_lock, context);
>     list_add_tail(&umsg->list_entry, &umsg_list);
>     rtdm_lock_put_irqrestore(&umsg_list_lock, context);
>    
>     rtdm_nrtsig_pend(&up_nrt_signal);
>    

Why this signaling here? Either the message is processed synchronously
(/wrt dispatch_call) so that you can release it after return from the
dispatcher, or it's handled asynchronously, but then this signal comes
too early as the RT work is potentially still ongoing.

>    
> }
> 
> 
> static int up_handle_cmd_msg_rt(struct rt_proc_call *call)
> {
>    
>     struct up_cmd_param *params;
>     struct up_msg_buf *resp;
>    
>     params = rtpc_get_priv(call, struct up_cmd_param);
>     resp = params->resp_buf;
>    
>     if(resp)
>         resp->cmd = UP_NL_C_CMD;
>    
>     switch(params->hdr.opcode) {
>        
>         case UP_CMD_INIT:
>             break;
> 
>         case UP_CMD_CREATE_REQ:
>         {
>             struct up_config *c = (struct up_config *)&params->msg.config;
>             int *res = (int *)resp->payload;
>             *res = up_create(params->hdr.up_id, c);

I can only assume this function doesn't do anything crazy.

>             if(*res < 0)
>                 rtdm_printk("Error creating UP\n");
> 
>             up_queue_umsg(resp, UP_CMD_CREATE_RES, sizeof(int), 0);
>             break;
>         }
> 
>         default:
>             rtdm_printk("Unknown cmd message: op=%d\n", params->hdr.opcode);
>             return -ENOTSUPP;
>        
>     }
>    
>     return 0;
> }
> 
> static int up_handle_cmd_msg_nrt(struct sk_buff *skb, struct genl_info
> *info)
> {
>    
>     int ret;
>     struct up_cmd_param params;
>     struct up_user_hdr *uhdr = (struct up_user_hdr *)info->userhdr;
>    
>     //TODO: Allocate response buffer based on message type
>     switch(uhdr->opcode) {
>        
>         case UP_CMD_INIT:
>             up_user_pid = info->snd_pid;
>             params.resp_buf = NULL;
>             break;
>            
>         default:
>             params.resp_buf = up_alloc_msg_buf(UP_NL_C_CMD,
> sizeof(cmdMsg_t),
>                                                     info, NULL);
>             break;
>     };
>    
>     memcpy(&params.hdr, info->userhdr, sizeof(struct up_user_hdr));
>    
>     if(params.hdr.plen > sizeof(cmdMsg_t))
>         printk("up_handle_cmd_msg_nrt(): ERROR plen=%u >
> sizeof(cmdMsg_t)=%u\n", params.hdr.plen, sizeof(cmdMsg_t));
>    
>     if(params.hdr.plen)
>         nla_memcpy(&params.msg, info->attrs[UP_NL_A_MSG], params.hdr.plen);
>    
>     ret = rtpc_dispatch_call(up_handle_cmd_msg_rt, 0, &params,
> sizeof(params),
>                              NULL, NULL, NULL);

That shouldn't build (too many arguments).

>    
>     if(ret < 0)
>         kfree(params.resp_buf);
> 
>     return ret;
> 
> }
> 
> /* netlink attribute policy */
> static const struct nla_policy up_genl_policy[UP_NL_A_MAX + 1] = {
>     [UP_NL_A_MSG] = { .type = NLA_BINARY }
> };
> 
> /* Generic netlink event operation definition */
> static struct genl_ops up_genl_ops_cmd = {
>     .cmd = UP_NL_C_CMD,
>     .flags = 0,
>     .policy = up_genl_policy,
>     .doit = up_handle_cmd_msg_nrt,
>     .dumpit = NULL
> };
> 
> /* Generic netlink family */
> static struct genl_family up_genl_family = {
>     .id = GENL_ID_GENERATE,
>     .hdrsize = UP_GENL_HDRLEN,
>     .name = "up",
>     .version = UP_NL_VERSION,
>     .maxattr = UP_NL_A_MAX
> };
> 
> static void up_work_queue_handler(struct work_struct *work)
> {
>    
>     struct up_msg_buf *msg;
>     struct sk_buff *skb;
>     struct up_user_hdr *uhdr;
>     rtdm_lockctx_t context;
>     int rc;
>    
>     rtdm_lock_get_irqsave(&umsg_list_lock, context);
>    
>     while(!list_empty(&umsg_list)) {
>         msg = (struct up_msg_buf *)umsg_list.next;
>         list_del(&msg->list_entry);
>         rtdm_lock_put_irqrestore(&umsg_list_lock, context);
>        
>         /* construct netlink message and send */
>         skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
>         if(!skb)
>             goto failure;
>        
>         uhdr = genlmsg_put(skb, msg->pid, msg->seq, &up_genl_family,
>                                0, msg->cmd);
>         if(!uhdr)
>             goto skb_failure;
>        
>         memcpy(uhdr, &msg->hdr, sizeof(struct up_user_hdr));
>        
>         rc = nla_put(skb, UP_NL_A_MSG, msg->hdr.plen, &msg->payload);
>         if(rc != 0)
>             goto skb_failure;
>        
>         genlmsg_end(skb, uhdr);
>        
>         rc = genlmsg_unicast(skb, msg->pid);
>        
>         if(msg->finalize)
>             msg->finalize(msg);
>         else
>             kfree(msg);
>        
>         if(rc < 0)
>             goto skb_failure;
>        
>         rtdm_lock_get_irqsave(&umsg_list_lock, context);
>     }
>    
>     rtdm_lock_put_irqrestore(&umsg_list_lock, context);
>    
>     return;
> 
> skb_failure:
>     nlmsg_free(skb);
> failure:
>     printk("Response failure\n");
>    
> }
> 
> static void up_signal_handler(rtdm_nrtsig_t nrt_sig, void *arg)
> {
>     /* Schedule work to be done in process context */
>     schedule_work(&wq);
> }
> 
> static int __init up_init(void)
> {
>    
>     int rc = 0;
>     printk("UP module loading\n");
>    
>     rc = genl_register_family(&up_genl_family);
>     if(rc != 0)
>         return rc;
>    
>     rc = genl_register_ops(&up_genl_family, &up_genl_ops_cmd);
>     if(rc != 0)
>         goto failure;
>    
>     rc = rtdm_nrtsig_init(&up_nrt_signal, up_signal_handler, NULL);
>     if(rc < 0)
>         goto failure;
> 
>     rc = up_init();

Endless recursion???

>    
>     if(rc < 0)
>         goto failure;
> 
>    
>     return 0;
> 
> failure:
>     printk("UP module loading failed\n");
>     genl_unregister_family(&up_genl_family);
>     return rc;
> }
> 
> 
> static void __exit up_release(void)
> {
>    
>     printk("UP module unloading\n");
>     rtdm_nrtsig_destroy(&up_nrt_signal);
> 
>     genl_unregister_family(&up_genl_family);
>    
>     up_release();
>    
> }
> 
> module_init(up_init);
> module_exit(up_release);
> 

The way you use rtpc itself looks correct on first glance. But the two
fishy spots and that signaling inconsistency I found make me wonder if
this code corresponds to what crashes your box.

Can you describe again what service rtpc needs to execute in the RT
domain, and what data is exchanged between both worlds?

Jan

-- 
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-12 15:24                             ` Jan Kiszka
@ 2011-04-12 15:50                               ` Jesper Christensen
  0 siblings, 0 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-12 15:50 UTC (permalink / raw)
  To: Jan Kiszka; +Cc: xenomai@xenomai.org


On 2011-04-12 17:24, Jan Kiszka wrote:
> On 2011-04-12 16:21, Jesper Christensen wrote:
>   
>> There you go:
>>
>>
>> -----------------------------------------------------------------------------------
>>
>> #include <linux/module.h>
>> #include <linux/kernel.h>
>> #include <linux/list.h>
>> #include <linux/workqueue.h>
>>
>> #include <rtnet_rtpc.h>
>> #include <up.h>
>>
>>
>>
>> static rtdm_lock_t      umsg_list_lock = RTDM_LOCK_UNLOCKED;
>> static rtdm_nrtsig_t    up_nrt_signal;
>> LIST_HEAD(umsg_list);
>>
>>
>> static void up_work_queue_handler(struct work_struct *work);
>> DECLARE_WORK(wq, up_work_queue_handler);
>>
>> u32 up_user_pid = 0;
>>
>> struct up_msg_buf *up_alloc_msg_buf(int cmd, size_t psize, struct
>> genl_info *info,
>>                                           up_msg_finalize fin)
>> {
>>    
>>     struct up_msg_buf *ret;
>>    
>>     ret = kmalloc(sizeof(struct up_msg_buf) + psize, GFP_KERNEL);
>>     if(!ret)
>>         return ret;
>>    
>>     memset(ret, 0, sizeof(struct up_msg_buf));
>>     
> [ kzalloc = kmalloc + memset ]
>
>   
Got it.
>>    
>>     /* Initialize some fields */
>>     if(info) {
>>         ret->pid = info->snd_pid;
>>         ret->seq = info->snd_seq;
>>     }
>>     ret->cmd = cmd;
>>     ret->finalize = fin;
>>    
>>    
>>     return ret;
>>    
>>    
>> }
>>
>> void up_queue_umsg(struct up_msg_buf *umsg, int op, int len, U8 upid)
>> {
>>    
>>     rtdm_lockctx_t context;
>>    
>>     umsg->hdr.opcode = op;
>>     umsg->hdr.plen = len;
>>     umsg->hdr.up_id = upid;
>>    
>>     rtdm_lock_get_irqsave(&umsg_list_lock, context);
>>     list_add_tail(&umsg->list_entry, &umsg_list);
>>     rtdm_lock_put_irqrestore(&umsg_list_lock, context);
>>    
>>     rtdm_nrtsig_pend(&up_nrt_signal);
>>    
>>     
> Why this signaling here? Either the message is processed synchronously
> (/wrt dispatch_call) so that you can release it after return from the
> dispatcher, or it's handled asynchronously, but then this signal comes
> too early as the RT work is potentially still ongoing.
>
>   
Well this is for dispatching messages the other way (via the
work_queue). The rt part will (by design) not modify the umsg buffer
after this call. This mechanism is also needed to pass unsolicited
messages from rt to userland.
>>    
>> }
>>
>>
>> static int up_handle_cmd_msg_rt(struct rt_proc_call *call)
>> {
>>    
>>     struct up_cmd_param *params;
>>     struct up_msg_buf *resp;
>>    
>>     params = rtpc_get_priv(call, struct up_cmd_param);
>>     resp = params->resp_buf;
>>    
>>     if(resp)
>>         resp->cmd = UP_NL_C_CMD;
>>    
>>     switch(params->hdr.opcode) {
>>        
>>         case UP_CMD_INIT:
>>             break;
>>
>>         case UP_CMD_CREATE_REQ:
>>         {
>>             struct up_config *c = (struct up_config *)&params->msg.config;
>>             int *res = (int *)resp->payload;
>>             *res = up_create(params->hdr.up_id, c);
>>     
> I can only assume this function doesn't do anything crazy.
>   
You are correct. It is only called once during startup.
>   
>>             if(*res < 0)
>>                 rtdm_printk("Error creating UP\n");
>>
>>             up_queue_umsg(resp, UP_CMD_CREATE_RES, sizeof(int), 0);
>>             break;
>>         }
>>
>>         default:
>>             rtdm_printk("Unknown cmd message: op=%d\n", params->hdr.opcode);
>>             return -ENOTSUPP;
>>        
>>     }
>>    
>>     return 0;
>> }
>>
>> static int up_handle_cmd_msg_nrt(struct sk_buff *skb, struct genl_info
>> *info)
>> {
>>    
>>     int ret;
>>     struct up_cmd_param params;
>>     struct up_user_hdr *uhdr = (struct up_user_hdr *)info->userhdr;
>>    
>>     //TODO: Allocate response buffer based on message type
>>     switch(uhdr->opcode) {
>>        
>>         case UP_CMD_INIT:
>>             up_user_pid = info->snd_pid;
>>             params.resp_buf = NULL;
>>             break;
>>            
>>         default:
>>             params.resp_buf = up_alloc_msg_buf(UP_NL_C_CMD,
>> sizeof(cmdMsg_t),
>>                                                     info, NULL);
>>             break;
>>     };
>>    
>>     memcpy(&params.hdr, info->userhdr, sizeof(struct up_user_hdr));
>>    
>>     if(params.hdr.plen > sizeof(cmdMsg_t))
>>         printk("up_handle_cmd_msg_nrt(): ERROR plen=%u >
>> sizeof(cmdMsg_t)=%u\n", params.hdr.plen, sizeof(cmdMsg_t));
>>    
>>     if(params.hdr.plen)
>>         nla_memcpy(&params.msg, info->attrs[UP_NL_A_MSG], params.hdr.plen);
>>    
>>     ret = rtpc_dispatch_call(up_handle_cmd_msg_rt, 0, &params,
>> sizeof(params),
>>                              NULL, NULL, NULL);
>>     
> That shouldn't build (too many arguments).
>   
That is actually a concurrency bug fix i made in rtnet (in the tar file
:) that prevented multiple userland threads from sending rt pings at the
same time.
>   
>>    
>>     if(ret < 0)
>>         kfree(params.resp_buf);
>>
>>     return ret;
>>
>> }
>>
>> /* netlink attribute policy */
>> static const struct nla_policy up_genl_policy[UP_NL_A_MAX + 1] = {
>>     [UP_NL_A_MSG] = { .type = NLA_BINARY }
>> };
>>
>> /* Generic netlink event operation definition */
>> static struct genl_ops up_genl_ops_cmd = {
>>     .cmd = UP_NL_C_CMD,
>>     .flags = 0,
>>     .policy = up_genl_policy,
>>     .doit = up_handle_cmd_msg_nrt,
>>     .dumpit = NULL
>> };
>>
>> /* Generic netlink family */
>> static struct genl_family up_genl_family = {
>>     .id = GENL_ID_GENERATE,
>>     .hdrsize = UP_GENL_HDRLEN,
>>     .name = "up",
>>     .version = UP_NL_VERSION,
>>     .maxattr = UP_NL_A_MAX
>> };
>>
>> static void up_work_queue_handler(struct work_struct *work)
>> {
>>    
>>     struct up_msg_buf *msg;
>>     struct sk_buff *skb;
>>     struct up_user_hdr *uhdr;
>>     rtdm_lockctx_t context;
>>     int rc;
>>    
>>     rtdm_lock_get_irqsave(&umsg_list_lock, context);
>>    
>>     while(!list_empty(&umsg_list)) {
>>         msg = (struct up_msg_buf *)umsg_list.next;
>>         list_del(&msg->list_entry);
>>         rtdm_lock_put_irqrestore(&umsg_list_lock, context);
>>        
>>         /* construct netlink message and send */
>>         skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
>>         if(!skb)
>>             goto failure;
>>        
>>         uhdr = genlmsg_put(skb, msg->pid, msg->seq, &up_genl_family,
>>                                0, msg->cmd);
>>         if(!uhdr)
>>             goto skb_failure;
>>        
>>         memcpy(uhdr, &msg->hdr, sizeof(struct up_user_hdr));
>>        
>>         rc = nla_put(skb, UP_NL_A_MSG, msg->hdr.plen, &msg->payload);
>>         if(rc != 0)
>>             goto skb_failure;
>>        
>>         genlmsg_end(skb, uhdr);
>>        
>>         rc = genlmsg_unicast(skb, msg->pid);
>>        
>>         if(msg->finalize)
>>             msg->finalize(msg);
>>         else
>>             kfree(msg);
>>        
>>         if(rc < 0)
>>             goto skb_failure;
>>        
>>         rtdm_lock_get_irqsave(&umsg_list_lock, context);
>>     }
>>    
>>     rtdm_lock_put_irqrestore(&umsg_list_lock, context);
>>    
>>     return;
>>
>> skb_failure:
>>     nlmsg_free(skb);
>> failure:
>>     printk("Response failure\n");
>>    
>> }
>>
>> static void up_signal_handler(rtdm_nrtsig_t nrt_sig, void *arg)
>> {
>>     /* Schedule work to be done in process context */
>>     schedule_work(&wq);
>> }
>>
>> static int __init up_init(void)
>> {
>>    
>>     int rc = 0;
>>     printk("UP module loading\n");
>>    
>>     rc = genl_register_family(&up_genl_family);
>>     if(rc != 0)
>>         return rc;
>>    
>>     rc = genl_register_ops(&up_genl_family, &up_genl_ops_cmd);
>>     if(rc != 0)
>>         goto failure;
>>    
>>     rc = rtdm_nrtsig_init(&up_nrt_signal, up_signal_handler, NULL);
>>     if(rc < 0)
>>         goto failure;
>>
>>     rc = up_init();
>>     
> Endless recursion???
>   
Woops, typo, sorry
>   
>>    
>>     if(rc < 0)
>>         goto failure;
>>
>>    
>>     return 0;
>>
>> failure:
>>     printk("UP module loading failed\n");
>>     genl_unregister_family(&up_genl_family);
>>     return rc;
>> }
>>
>>
>> static void __exit up_release(void)
>> {
>>    
>>     printk("UP module unloading\n");
>>     rtdm_nrtsig_destroy(&up_nrt_signal);
>>
>>     genl_unregister_family(&up_genl_family);
>>    
>>     up_release();
>>    
>> }
>>
>> module_init(up_init);
>> module_exit(up_release);
>>
>>     
> The way you use rtpc itself looks correct on first glance. But the two
> fishy spots and that signaling inconsistency I found make me wonder if
> this code corresponds to what crashes your box.
>
> Can you describe again what service rtpc needs to execute in the RT
> domain, and what data is exchanged between both worlds?
>
> Jan
>
>   

Thank you very much for your observations. To answer your question, the
data exchanged is basically session information which is used by two
threads on the rt side (session setup, release and modification). The
two threads receive udp packet from a ethernet interface, manipulates
some headers and forwards them on another interface (if the session
exists).
Now obviously i can not fully guarantee that there are no race
conditions there, but even then i cannot se how it should lead to a 
stack corruption.


/jesper



^ permalink raw reply	[flat|nested] 42+ messages in thread

* [Xenomai-core] kernel threads crash
  2011-04-12 14:21                           ` Jesper Christensen
  2011-04-12 15:24                             ` Jan Kiszka
@ 2011-04-19  7:26                             ` Jesper Christensen
  2011-04-19  7:39                               ` Philippe Gerum
  1 sibling, 1 reply; 42+ messages in thread
From: Jesper Christensen @ 2011-04-19  7:26 UTC (permalink / raw)
  To: xenomai


If i run switchtest i get the following output:

[root@domain.hid /bin]# switchtest
== Testing FPU check routines...
r0: 1 != 2
r1: 1 != 2
r2: 1 != 2
r3: 1 != 2
r4: 1 != 2
r5: 1 != 2
r6: 1 != 2
r7: 1 != 2
r8: 1 != 2
r9: 1 != 2
r10: 1 != 2
r11: 1 != 2
r12: 1 != 2
r13: 1 != 2
r14: 1 != 2
r15: 1 != 2
r16: 1 != 2
r17: 1 != 2
r18: 1 != 2
r19: 1 != 2
r20: 1 != 2
r21: 1 != 2
r22: 1 != 2
r23: 1 != 2
r24: 1 != 2
r25: 1 != 2
r26: 1 != 2
r27: 1 != 2
r28: 1 != 2
r29: 1 != 2
r30: 1 != 2
r31: 1 != 2
== FPU check routines: OK.
== Threads: sleeper_ufps0-0 rtk0-1 rtk0-2 rtk_fp0-3 rtk_fp0-4
rtk_fp_ufpp0-5 rtk_fp_ufpp0-6 rtup0-7 rtup0-8 rtup_ufpp0-9 rtup_ufpp0-10
rtus0-11 rtus0-12 rtus_ufps0-13 rtus_ufps0-14 rtuo0-15 rtuo0-16
rtuo_ufpp0-17 rtuo_ufpp0-18 rtuo_ufps0-19 rtuo_ufps0-20
rtuo_ufpp_ufps0-21 rtuo_ufpp_ufps0-22



And then it halts. dmesg shows:

Xenomai: suspending kernel thread ae819678 ('rtk5/0') at nip=0x80319aa0,
lr=0x80319a70, r1=0xafa90510 after exception #1792


switchtest -n runs normally, should i use some sort of soft float flag
in my compilations?

/Jesper





^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-19  7:26                             ` Jesper Christensen
@ 2011-04-19  7:39                               ` Philippe Gerum
  2011-04-19  7:58                                 ` Jesper Christensen
  0 siblings, 1 reply; 42+ messages in thread
From: Philippe Gerum @ 2011-04-19  7:39 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On Tue, 2011-04-19 at 09:26 +0200, Jesper Christensen wrote:
> If i run switchtest i get the following output:
> 


If still talking about the cpci6200, this patch should apply:
http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=3d6fa118ef282c60dfeb0e690a579e8357bb7d13

> [root@domain.hid /bin]# switchtest
> == Testing FPU check routines...
> r0: 1 != 2
> r1: 1 != 2
> r2: 1 != 2
> r3: 1 != 2
> r4: 1 != 2
> r5: 1 != 2
> r6: 1 != 2
> r7: 1 != 2
> r8: 1 != 2
> r9: 1 != 2
> r10: 1 != 2
> r11: 1 != 2
> r12: 1 != 2
> r13: 1 != 2
> r14: 1 != 2
> r15: 1 != 2
> r16: 1 != 2
> r17: 1 != 2
> r18: 1 != 2
> r19: 1 != 2
> r20: 1 != 2
> r21: 1 != 2
> r22: 1 != 2
> r23: 1 != 2
> r24: 1 != 2
> r25: 1 != 2
> r26: 1 != 2
> r27: 1 != 2
> r28: 1 != 2
> r29: 1 != 2
> r30: 1 != 2
> r31: 1 != 2
> == FPU check routines: OK.
> == Threads: sleeper_ufps0-0 rtk0-1 rtk0-2 rtk_fp0-3 rtk_fp0-4
> rtk_fp_ufpp0-5 rtk_fp_ufpp0-6 rtup0-7 rtup0-8 rtup_ufpp0-9 rtup_ufpp0-10
> rtus0-11 rtus0-12 rtus_ufps0-13 rtus_ufps0-14 rtuo0-15 rtuo0-16
> rtuo_ufpp0-17 rtuo_ufpp0-18 rtuo_ufps0-19 rtuo_ufps0-20
> rtuo_ufpp_ufps0-21 rtuo_ufpp_ufps0-22
> 
> 
> 
> And then it halts. dmesg shows:
> 
> Xenomai: suspending kernel thread ae819678 ('rtk5/0') at nip=0x80319aa0,
> lr=0x80319a70, r1=0xafa90510 after exception #1792
> 
> 
> switchtest -n runs normally, should i use some sort of soft float flag
> in my compilations?
> 
> /Jesper
> 
> 
> 
> 
> _______________________________________________
> Xenomai-core mailing list
> Xenomai-core@domain.hid
> https://mail.gna.org/listinfo/xenomai-core

-- 
Philippe.




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-19  7:39                               ` Philippe Gerum
@ 2011-04-19  7:58                                 ` Jesper Christensen
  2011-04-19  8:02                                   ` Philippe Gerum
  0 siblings, 1 reply; 42+ messages in thread
From: Jesper Christensen @ 2011-04-19  7:58 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai

Great thanks, but i can't help wondering if the problems i'm seeing are
related to some of my userspace programs using fp.

/Jesper


On 2011-04-19 09:39, Philippe Gerum wrote:
> On Tue, 2011-04-19 at 09:26 +0200, Jesper Christensen wrote:
>   
>> If i run switchtest i get the following output:
>>
>>     
>
> If still talking about the cpci6200, this patch should apply:
> http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=3d6fa118ef282c60dfeb0e690a579e8357bb7d13
>
>   
>> [root@domain.hid /bin]# switchtest
>> == Testing FPU check routines...
>> r0: 1 != 2
>> r1: 1 != 2
>> r2: 1 != 2
>> r3: 1 != 2
>> r4: 1 != 2
>> r5: 1 != 2
>> r6: 1 != 2
>> r7: 1 != 2
>> r8: 1 != 2
>> r9: 1 != 2
>> r10: 1 != 2
>> r11: 1 != 2
>> r12: 1 != 2
>> r13: 1 != 2
>> r14: 1 != 2
>> r15: 1 != 2
>> r16: 1 != 2
>> r17: 1 != 2
>> r18: 1 != 2
>> r19: 1 != 2
>> r20: 1 != 2
>> r21: 1 != 2
>> r22: 1 != 2
>> r23: 1 != 2
>> r24: 1 != 2
>> r25: 1 != 2
>> r26: 1 != 2
>> r27: 1 != 2
>> r28: 1 != 2
>> r29: 1 != 2
>> r30: 1 != 2
>> r31: 1 != 2
>> == FPU check routines: OK.
>> == Threads: sleeper_ufps0-0 rtk0-1 rtk0-2 rtk_fp0-3 rtk_fp0-4
>> rtk_fp_ufpp0-5 rtk_fp_ufpp0-6 rtup0-7 rtup0-8 rtup_ufpp0-9 rtup_ufpp0-10
>> rtus0-11 rtus0-12 rtus_ufps0-13 rtus_ufps0-14 rtuo0-15 rtuo0-16
>> rtuo_ufpp0-17 rtuo_ufpp0-18 rtuo_ufps0-19 rtuo_ufps0-20
>> rtuo_ufpp_ufps0-21 rtuo_ufpp_ufps0-22
>>
>>
>>
>> And then it halts. dmesg shows:
>>
>> Xenomai: suspending kernel thread ae819678 ('rtk5/0') at nip=0x80319aa0,
>> lr=0x80319a70, r1=0xafa90510 after exception #1792
>>
>>
>> switchtest -n runs normally, should i use some sort of soft float flag
>> in my compilations?
>>
>> /Jesper
>>
>>
>>
>>
>> _______________________________________________
>> Xenomai-core mailing list
>> Xenomai-core@domain.hid
>> https://mail.gna.org/listinfo/xenomai-core
>>     
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-19  7:58                                 ` Jesper Christensen
@ 2011-04-19  8:02                                   ` Philippe Gerum
  2011-04-19  8:42                                     ` Gilles Chanteperdrix
  0 siblings, 1 reply; 42+ messages in thread
From: Philippe Gerum @ 2011-04-19  8:02 UTC (permalink / raw)
  To: Jesper Christensen; +Cc: xenomai

On Tue, 2011-04-19 at 09:58 +0200, Jesper Christensen wrote:
> Great thanks, but i can't help wondering if the problems i'm seeing are
> related to some of my userspace programs using fp.

I don't think so. The switchtest programs exercises the FPU hardware in
a certain way to make sure it is available in real-time mode from kernel
space (which is an utterly crappy legacy, but we will have to deal with
it until Xenomai 3.x). As far as I can see from your .config, you can't
have such support, so switchtest was basically trying to test an
inexistent feature.

> 
> /Jesper
> 
> 
> On 2011-04-19 09:39, Philippe Gerum wrote:
> > On Tue, 2011-04-19 at 09:26 +0200, Jesper Christensen wrote:
> >   
> >> If i run switchtest i get the following output:
> >>
> >>     
> >
> > If still talking about the cpci6200, this patch should apply:
> > http://git.xenomai.org/?p=xenomai-rpm.git;a=commit;h=3d6fa118ef282c60dfeb0e690a579e8357bb7d13
> >
> >   
> >> [root@domain.hid /bin]# switchtest
> >> == Testing FPU check routines...
> >> r0: 1 != 2
> >> r1: 1 != 2
> >> r2: 1 != 2
> >> r3: 1 != 2
> >> r4: 1 != 2
> >> r5: 1 != 2
> >> r6: 1 != 2
> >> r7: 1 != 2
> >> r8: 1 != 2
> >> r9: 1 != 2
> >> r10: 1 != 2
> >> r11: 1 != 2
> >> r12: 1 != 2
> >> r13: 1 != 2
> >> r14: 1 != 2
> >> r15: 1 != 2
> >> r16: 1 != 2
> >> r17: 1 != 2
> >> r18: 1 != 2
> >> r19: 1 != 2
> >> r20: 1 != 2
> >> r21: 1 != 2
> >> r22: 1 != 2
> >> r23: 1 != 2
> >> r24: 1 != 2
> >> r25: 1 != 2
> >> r26: 1 != 2
> >> r27: 1 != 2
> >> r28: 1 != 2
> >> r29: 1 != 2
> >> r30: 1 != 2
> >> r31: 1 != 2
> >> == FPU check routines: OK.
> >> == Threads: sleeper_ufps0-0 rtk0-1 rtk0-2 rtk_fp0-3 rtk_fp0-4
> >> rtk_fp_ufpp0-5 rtk_fp_ufpp0-6 rtup0-7 rtup0-8 rtup_ufpp0-9 rtup_ufpp0-10
> >> rtus0-11 rtus0-12 rtus_ufps0-13 rtus_ufps0-14 rtuo0-15 rtuo0-16
> >> rtuo_ufpp0-17 rtuo_ufpp0-18 rtuo_ufps0-19 rtuo_ufps0-20
> >> rtuo_ufpp_ufps0-21 rtuo_ufpp_ufps0-22
> >>
> >>
> >>
> >> And then it halts. dmesg shows:
> >>
> >> Xenomai: suspending kernel thread ae819678 ('rtk5/0') at nip=0x80319aa0,
> >> lr=0x80319a70, r1=0xafa90510 after exception #1792
> >>
> >>
> >> switchtest -n runs normally, should i use some sort of soft float flag
> >> in my compilations?
> >>
> >> /Jesper
> >>
> >>
> >>
> >>
> >> _______________________________________________
> >> Xenomai-core mailing list
> >> Xenomai-core@domain.hid
> >> https://mail.gna.org/listinfo/xenomai-core
> >>     
> >   
> 

-- 
Philippe.




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-19  8:02                                   ` Philippe Gerum
@ 2011-04-19  8:42                                     ` Gilles Chanteperdrix
  2011-04-19  9:29                                       ` Philippe Gerum
  0 siblings, 1 reply; 42+ messages in thread
From: Gilles Chanteperdrix @ 2011-04-19  8:42 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai

Philippe Gerum wrote:
> On Tue, 2011-04-19 at 09:58 +0200, Jesper Christensen wrote:
>> Great thanks, but i can't help wondering if the problems i'm seeing are
>> related to some of my userspace programs using fp.
> 
> I don't think so. The switchtest programs exercises the FPU hardware in
> a certain way to make sure it is available in real-time mode from kernel
> space (which is an utterly crappy legacy, but we will have to deal with
> it until Xenomai 3.x). As far as I can see from your .config, you can't
> have such support, so switchtest was basically trying to test an
> inexistent feature.

In fact, switchtest whether Xenomai FPU switch routines work when the
Linux kernel itself uses FPU in kernel-space. Currently, the only place
when this happens is in the RAID code: x86 uses mmx/sse, and some power
pcs use altivec. Some powerpc also fix unaligned accesses to floating
point data in kernel-space, I do not know if this may interfere, which
is why the powerpc code is compiled even without RAID.


-- 
					    Gilles.


^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-19  8:42                                     ` Gilles Chanteperdrix
@ 2011-04-19  9:29                                       ` Philippe Gerum
  2011-04-19  9:30                                         ` Philippe Gerum
  0 siblings, 1 reply; 42+ messages in thread
From: Philippe Gerum @ 2011-04-19  9:29 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: xenomai

On Tue, 2011-04-19 at 10:42 +0200, Gilles Chanteperdrix wrote:
> Philippe Gerum wrote:
> > On Tue, 2011-04-19 at 09:58 +0200, Jesper Christensen wrote:
> >> Great thanks, but i can't help wondering if the problems i'm seeing are
> >> related to some of my userspace programs using fp.
> > 
> > I don't think so. The switchtest programs exercises the FPU hardware in
> > a certain way to make sure it is available in real-time mode from kernel
> > space (which is an utterly crappy legacy, but we will have to deal with
> > it until Xenomai 3.x). As far as I can see from your .config, you can't
> > have such support, so switchtest was basically trying to test an
> > inexistent feature.
> 
> In fact, switchtest whether Xenomai FPU switch routines work when the
> Linux kernel itself uses FPU in kernel-space. Currently, the only place
> when this happens is in the RAID code: x86 uses mmx/sse, and some power
> pcs use altivec. Some powerpc also fix unaligned accesses to floating
> point data in kernel-space, I do not know if this may interfere, which
> is why the powerpc code is compiled even without RAID.
> 
> 

AFAICS, fp_regs_set() on ppc is issuing a load float instruction in
kernel space which could be unaligned, and therefore trap. Looking at
the .config for the target system, hw FPU support is disabled in the
alignment code, so basically, this would beget a nop.

-- 
Philippe.




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-19  9:29                                       ` Philippe Gerum
@ 2011-04-19  9:30                                         ` Philippe Gerum
  2011-04-19  9:34                                           ` Jesper Christensen
  0 siblings, 1 reply; 42+ messages in thread
From: Philippe Gerum @ 2011-04-19  9:30 UTC (permalink / raw)
  To: Gilles Chanteperdrix; +Cc: xenomai

On Tue, 2011-04-19 at 11:29 +0200, Philippe Gerum wrote:
> On Tue, 2011-04-19 at 10:42 +0200, Gilles Chanteperdrix wrote:
> > Philippe Gerum wrote:
> > > On Tue, 2011-04-19 at 09:58 +0200, Jesper Christensen wrote:
> > >> Great thanks, but i can't help wondering if the problems i'm seeing are
> > >> related to some of my userspace programs using fp.
> > > 
> > > I don't think so. The switchtest programs exercises the FPU hardware in
> > > a certain way to make sure it is available in real-time mode from kernel
> > > space (which is an utterly crappy legacy, but we will have to deal with
> > > it until Xenomai 3.x). As far as I can see from your .config, you can't
> > > have such support, so switchtest was basically trying to test an
> > > inexistent feature.
> > 
> > In fact, switchtest whether Xenomai FPU switch routines work when the
> > Linux kernel itself uses FPU in kernel-space. Currently, the only place
> > when this happens is in the RAID code: x86 uses mmx/sse, and some power
> > pcs use altivec. Some powerpc also fix unaligned accesses to floating
> > point data in kernel-space, I do not know if this may interfere, which
> > is why the powerpc code is compiled even without RAID.
> > 
> > 
> 
> AFAICS, fp_regs_set() on ppc is issuing a load float instruction in
> kernel space which could be unaligned, and therefore trap. Looking at
> the .config for the target system, hw FPU support is disabled in the
> alignment code, so basically, this would beget a nop.

A nop in fixing the issue, I mean.

-- 
Philippe.




^ permalink raw reply	[flat|nested] 42+ messages in thread

* Re: [Xenomai-core] kernel threads crash
  2011-04-19  9:30                                         ` Philippe Gerum
@ 2011-04-19  9:34                                           ` Jesper Christensen
  0 siblings, 0 replies; 42+ messages in thread
From: Jesper Christensen @ 2011-04-19  9:34 UTC (permalink / raw)
  To: Philippe Gerum; +Cc: xenomai

Okay

/Jesper


On 2011-04-19 11:30, Philippe Gerum wrote:
> On Tue, 2011-04-19 at 11:29 +0200, Philippe Gerum wrote:
>   
>> On Tue, 2011-04-19 at 10:42 +0200, Gilles Chanteperdrix wrote:
>>     
>>> Philippe Gerum wrote:
>>>       
>>>> On Tue, 2011-04-19 at 09:58 +0200, Jesper Christensen wrote:
>>>>         
>>>>> Great thanks, but i can't help wondering if the problems i'm seeing are
>>>>> related to some of my userspace programs using fp.
>>>>>           
>>>> I don't think so. The switchtest programs exercises the FPU hardware in
>>>> a certain way to make sure it is available in real-time mode from kernel
>>>> space (which is an utterly crappy legacy, but we will have to deal with
>>>> it until Xenomai 3.x). As far as I can see from your .config, you can't
>>>> have such support, so switchtest was basically trying to test an
>>>> inexistent feature.
>>>>         
>>> In fact, switchtest whether Xenomai FPU switch routines work when the
>>> Linux kernel itself uses FPU in kernel-space. Currently, the only place
>>> when this happens is in the RAID code: x86 uses mmx/sse, and some power
>>> pcs use altivec. Some powerpc also fix unaligned accesses to floating
>>> point data in kernel-space, I do not know if this may interfere, which
>>> is why the powerpc code is compiled even without RAID.
>>>
>>>
>>>       
>> AFAICS, fp_regs_set() on ppc is issuing a load float instruction in
>> kernel space which could be unaligned, and therefore trap. Looking at
>> the .config for the target system, hw FPU support is disabled in the
>> alignment code, so basically, this would beget a nop.
>>     
> A nop in fixing the issue, I mean.
>
>   



^ permalink raw reply	[flat|nested] 42+ messages in thread

end of thread, other threads:[~2011-04-19  9:34 UTC | newest]

Thread overview: 42+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-04-08 12:58 [Xenomai-core] kernel threads crash Jesper Christensen
2011-04-08 13:12 ` Philippe Gerum
2011-04-08 13:20   ` Jesper Christensen
2011-04-08 13:39     ` Philippe Gerum
2011-04-08 13:47       ` Jesper Christensen
2011-04-08 14:33       ` Jesper Christensen
2011-04-11 14:13   ` Jesper Christensen
2011-04-11 14:18     ` Philippe Gerum
2011-04-11 14:20       ` Jesper Christensen
2011-04-11 14:27         ` Philippe Gerum
2011-04-11 14:32           ` Jesper Christensen
2011-04-11 14:39             ` Philippe Gerum
2011-04-11 14:49               ` Jesper Christensen
2011-04-11 15:31                 ` Jesper Christensen
2011-04-12 13:31                   ` Jesper Christensen
2011-04-12 13:39                     ` Gilles Chanteperdrix
2011-04-12 13:40                       ` Jesper Christensen
2011-04-12 13:40                     ` Jan Kiszka
2011-04-12 13:45                       ` Jesper Christensen
2011-04-12 14:09                       ` Jesper Christensen
2011-04-12 14:14                         ` Jan Kiszka
2011-04-12 14:21                           ` Jesper Christensen
2011-04-12 15:24                             ` Jan Kiszka
2011-04-12 15:50                               ` Jesper Christensen
2011-04-19  7:26                             ` Jesper Christensen
2011-04-19  7:39                               ` Philippe Gerum
2011-04-19  7:58                                 ` Jesper Christensen
2011-04-19  8:02                                   ` Philippe Gerum
2011-04-19  8:42                                     ` Gilles Chanteperdrix
2011-04-19  9:29                                       ` Philippe Gerum
2011-04-19  9:30                                         ` Philippe Gerum
2011-04-19  9:34                                           ` Jesper Christensen
2011-04-11 14:34         ` Philippe Gerum
2011-04-11 14:35           ` Jesper Christensen
2011-04-11 14:23       ` Philippe Gerum
2011-04-11 14:36     ` Gilles Chanteperdrix
2011-04-08 19:15 ` Richard Cochran
2011-04-11  6:52   ` Jesper Christensen
2011-04-11  6:55     ` Richard Cochran
2011-04-11  6:59       ` Jesper Christensen
2011-04-11  9:18         ` Jan Kiszka
2011-04-11  9:26           ` Jesper Christensen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.