* 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, ®ion,
+ 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, ®ion,
+ 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, ®ion,
+ 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, ®ion, 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, ®ion, 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, ®);
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, ¤tLL->dva);
+ writel(vmeCur->dstAddr, ¤tLL->dlv);
+ } else {
+ writel(vmeCur->srcAddr, ¤tLL->dlv);
+ writel(vmeCur->dstAddr, ¤tLL->dva);
+ }
+ uniSetupDctlReg(vmeCur, &dctlreg);
+ writel(dctlreg, ¤tLL->dctl);
+ writel(vmeCur->byteCount, ¤tLL->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, ¤tLL->dcpp);
+ } else {
+ writel((unsigned int)virt_to_bus(nextLL),
+ ¤tLL->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(¤tLL->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